diff --git a/kaitaistruct.py b/kaitaistruct.py index 73c1e12..865ac42 100644 --- a/kaitaistruct.py +++ b/kaitaistruct.py @@ -1,5 +1,5 @@ import itertools -import sys +import sys, threading import struct from struct import unpack from io import BytesIO # noqa @@ -15,6 +15,48 @@ # __version__ = '0.8' +# https://github.com/KOLANICH/RecursionSafe.py inlined +from functools import wraps +class RecursionSafe: + __slots__=("visiting") + class Lock: + __slots__=("obj", "safe") + def __init__(self, safe, obj): + self.safe=safe + self.obj=obj + def __enter__(self): + i=id(self.obj) + if i not in self.safe.visiting: + self.safe.visiting.add(i) + return self.obj + else: + return ... + def __exit__(self, *args, **kwargs): + i=id(self.obj) + if i in self.safe.visiting: + self.safe.visiting.remove(i) + def __init__(self): + self.visiting=set() + def __call__(self, obj): + return self.__class__.Lock(self, obj) + def wrap(self, f): + @wraps(f) + def wrapped(firstArg, *args, **kwargs): + with self(firstArg) as firstArg: + return f(firstArg, *args, **kwargs) + return wrapped + +thread_local=threading.local() +thread_local.rec_safe=RecursionSafe() + +@thread_local.rec_safe.wrap +def repr_generator_for_all_props(self): + """Generator to use in own __repr__ functions.""" + return ( + "".join(( str(k), "=", repr(getattr(self, k)) )) + for k in dir(self) + if k[0] != "_" and not hasattr(KaitaiStruct, k) and not isinstance(getattr(self, k), type) + ) class KaitaiStruct(object): def __init__(self, stream): @@ -26,6 +68,16 @@ def __enter__(self): def __exit__(self, *args, **kwargs): self.close() + def __repr__(self): + return "".join( + ( + self.__class__.__name__, + "(", + ", ".join( repr_generator_for_all_props(self) ), + ")" + ) + ) + def close(self): self._io.close()