99 lines
1.9 KiB
Python
99 lines
1.9 KiB
Python
|
# Copyright 2019 Ram Rachum and collaborators.
|
||
|
# This program is distributed under the MIT license.
|
||
|
|
||
|
import abc
|
||
|
import re
|
||
|
|
||
|
import sys
|
||
|
from .pycompat import ABC, string_types, collections_abc
|
||
|
|
||
|
def _check_methods(C, *methods):
|
||
|
mro = C.__mro__
|
||
|
for method in methods:
|
||
|
for B in mro:
|
||
|
if method in B.__dict__:
|
||
|
if B.__dict__[method] is None:
|
||
|
return NotImplemented
|
||
|
break
|
||
|
else:
|
||
|
return NotImplemented
|
||
|
return True
|
||
|
|
||
|
|
||
|
class WritableStream(ABC):
|
||
|
@abc.abstractmethod
|
||
|
def write(self, s):
|
||
|
pass
|
||
|
|
||
|
@classmethod
|
||
|
def __subclasshook__(cls, C):
|
||
|
if cls is WritableStream:
|
||
|
return _check_methods(C, 'write')
|
||
|
return NotImplemented
|
||
|
|
||
|
|
||
|
|
||
|
file_reading_errors = (
|
||
|
IOError,
|
||
|
OSError,
|
||
|
ValueError # IronPython weirdness.
|
||
|
)
|
||
|
|
||
|
|
||
|
|
||
|
def shitcode(s):
|
||
|
return ''.join(
|
||
|
(c if (0 < ord(c) < 256) else '?') for c in s
|
||
|
)
|
||
|
|
||
|
|
||
|
def get_repr_function(item, custom_repr):
|
||
|
for condition, action in custom_repr:
|
||
|
if isinstance(condition, type):
|
||
|
condition = lambda x, y=condition: isinstance(x, y)
|
||
|
if condition(item):
|
||
|
return action
|
||
|
return repr
|
||
|
|
||
|
|
||
|
DEFAULT_REPR_RE = re.compile(r' at 0x[a-f0-9A-F]{4,}')
|
||
|
|
||
|
|
||
|
def normalize_repr(item_repr):
|
||
|
"""Remove memory address (0x...) from a default python repr"""
|
||
|
return DEFAULT_REPR_RE.sub('', item_repr)
|
||
|
|
||
|
|
||
|
def get_shortish_repr(item, custom_repr=(), max_length=None, normalize=False):
|
||
|
repr_function = get_repr_function(item, custom_repr)
|
||
|
try:
|
||
|
r = repr_function(item)
|
||
|
except Exception:
|
||
|
r = 'REPR FAILED'
|
||
|
r = r.replace('\r', '').replace('\n', '')
|
||
|
if normalize:
|
||
|
r = normalize_repr(r)
|
||
|
if max_length:
|
||
|
r = truncate(r, max_length)
|
||
|
return r
|
||
|
|
||
|
|
||
|
def truncate(string, max_length):
|
||
|
if (max_length is None) or (len(string) <= max_length):
|
||
|
return string
|
||
|
else:
|
||
|
left = (max_length - 3) // 2
|
||
|
right = max_length - 3 - left
|
||
|
return u'{}...{}'.format(string[:left], string[-right:])
|
||
|
|
||
|
|
||
|
def ensure_tuple(x):
|
||
|
if isinstance(x, collections_abc.Iterable) and \
|
||
|
not isinstance(x, string_types):
|
||
|
return tuple(x)
|
||
|
else:
|
||
|
return (x,)
|
||
|
|
||
|
|
||
|
|