Last active
March 22, 2018 02:57
-
-
Save badocelot/26b4a7e994ccffd39e396c9d6cc1936e to your computer and use it in GitHub Desktop.
Class for weakly-typed objects that obfuscate the wrapped object's type
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import operator | |
__all__ = ['weak'] | |
def apply_operator(op, a, b): | |
types = lambda x: x, float, int, complex | |
for a_type in types: | |
for b_type in types: | |
try: | |
return op(a_type(a), b_type(b)) | |
except (TypeError, ValueError): | |
pass | |
return str(a) + str(b) | |
def try_conversion(cls, value): | |
try: | |
return cls(value) | |
except (TypeError, ValueError): | |
return cls() | |
class weak: | |
__slots__ = () | |
def __new__(cls, value): | |
# don't telescope weak wrappers | |
if isinstance(value, weak): | |
return value | |
obj = value | |
class inner(cls): | |
__slots__ = () | |
def __call__(self, *args, **kwargs): | |
try: | |
return weak(obj(*args, **kwargs)) | |
except TypeError: | |
return self if len(args) == 0 and len(kwargs) == 0 else None | |
def __repr__(self): | |
return '<weakly-typed object>' | |
# attribute operations | |
def __delattr__(self, name): | |
try: | |
obj.__delattr__(name) | |
except AttributeError: | |
return | |
def __getattribute__(self, name): | |
try: | |
return weak(obj.__getattribute__(name)) | |
except AttributeError: | |
return None | |
def __setattr__(self, name, value): | |
try: | |
obj.__setattr__(name, value) | |
except AttributeError: | |
return | |
def __dir__(self): | |
return () | |
# iterator operations | |
def __iter__(self): | |
try: | |
return iter(weak(x) for x in obj) | |
except TypeError: | |
return iter((self,)) | |
def __next__(self): | |
try: | |
return weak(next(obj)) | |
except TypeError: | |
return self | |
# container operations | |
def __delitem__(self, key): | |
try: | |
del obj[key] | |
except TypeError: | |
return | |
def __getitem__(self, key): | |
try: | |
return weak(obj[key]) | |
except TypeError: | |
return self if key == 0 else None | |
def __len__(self): | |
try: | |
return len(obj) | |
except TypeError: | |
return 1 | |
def __setitem__(self, key, value): | |
try: | |
obj[key] = value | |
except TypeError: | |
return | |
# conversion operations | |
def __bool__(self): | |
return try_conversion(bool, obj) | |
def __complex__(self): | |
return try_conversion(complex, obj) | |
def __float__(self): | |
return try_conversion(float, obj) | |
def __int__(self): | |
return try_conversion(int, obj) | |
def __round__(self, ndigits = None): | |
try: | |
return round(obj, ndigits) | |
except TypeError: | |
return 0 | |
def __str__(self): | |
return try_conversion(str, obj) | |
# comparison operations | |
def __eq__(self, other): | |
return weak(apply_operator(operator.eq, obj, other)) | |
def __ge__(self, other): | |
return weak(apply_operator(operator.ge, obj, other)) | |
def __gt__(self, other): | |
return weak(apply_operator(operator.gt, obj, other)) | |
def __le__(self, other): | |
return weak(apply_operator(operator.le, obj, other)) | |
def __lt__(self, other): | |
return weak(apply_operator(operator.le, obj, other)) | |
def __ne__(self, other): | |
return weak(apply_operator(operator.ne, obj, other)) | |
# arithmetic operations | |
def __add__(self, other): | |
return weak(apply_operator(operator.add, obj, other)) | |
def __divmod__(self, other): | |
return weak(apply_operator(divmod, obj, other)) | |
def __floordiv__(self, other): | |
return weak(apply_operator(operator.floordiv, obj, other)) | |
def __lshift__(self, other): | |
return weak(apply_operator(operator.lshift, obj, other)) | |
def __matmul__(self, other): | |
return weak(apply_operator(operator.mathmul, obj, other)) | |
def __mod__(self, other): | |
return weak(apply_operator(operator.mod, obj, other)) | |
def __mul__(self, other): | |
return weak(apply_operator(operator.mul, obj, other)) | |
def __pow__(self, other): | |
return weak(apply_operator(operator.pow, obj, other)) | |
def __rshift__(self, other): | |
return weak(apply_operator(operator.rshift, obj, other)) | |
def __sub__(self, other): | |
return weak(apply_operator(operator.sub, obj, other)) | |
def __truediv__(self, other): | |
return weak(apply_operator(operator.truediv, obj, other)) | |
# right-hand arithmetic operations | |
def __radd__(self, other): | |
return weak(apply_operator(operator.add, other, obj)) | |
def __rdivmod__(self, other): | |
return weak(apply_operator(divmod, other, obj)) | |
def __rfloordiv__(self, other): | |
return weak(apply_operator(operator.floordiv, other, obj)) | |
def __rlshift__(self, other): | |
return weak(apply_operator(operator.lshift, other, obj)) | |
def __rmatmul__(self, other): | |
return weak(apply_operator(operator.matmul, other, obj)) | |
def __rmod__(self, other): | |
return weak(apply_operator(operator.mod, other, obj)) | |
def __rmul__(self, other): | |
return weak(apply_operator(operator.mul, other, obj)) | |
def __rpow__(self, other): | |
return weak(apply_operator(operator.pow, other, obj)) | |
def __rrshift__(self, other): | |
return weak(apply_operator(operator.rshift, other, obj)) | |
def __rsub__(self, other): | |
return weak(apply_operator(operator.sub, other, obj)) | |
def __rtruediv__(self, other): | |
return weak(apply_operator(operator.truediv, other, obj)) | |
# bitwise operations | |
def __and__(self, other): | |
return weak(apply_operator(operator.and_, obj, other)) | |
def __or__(self, other): | |
return weak(apply_operator(operator.or_, obj, other)) | |
def __xor__(self, other): | |
return weak(apply_operator(operator.xor, obj, other)) | |
# right-hand bitwise operations | |
def __rand__(self, other): | |
return weak(apply_operator(operator.and_, other, obj)) | |
def __ror__(self, other): | |
return weak(apply_operator(operator.or_, other, obj)) | |
def __rxor__(self, other): | |
return weak(apply_operator(operator.xor, other, obj)) | |
# unary arithmetic operations | |
def __abs__(self): | |
try: | |
return weak(abs(obj)) | |
except TypeError: | |
return self | |
def __invert__(self): | |
try: | |
return weak(~obj) | |
except TypeError: | |
return self | |
def __neg__(self): | |
try: | |
return weak(-obj) | |
except TypeError: | |
return self | |
def __pos__(self): | |
try: | |
return weak(+obj) | |
except TypeError: | |
return self | |
return object.__new__(inner) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment