1# ty: ignore[unresolved-attribute,unresolved-reference]
2from asyncutils import exceptions as E
3from asyncutils._internal import patch as P
4from asyncutils._internal.submodules import version_all as __all__
5def p(I, /, f=0 .__gt__, e=E.VersionValueError):
6 a, i = (r := []).append, 0
7 for i, j in enumerate(I):
8 a(int(j, 0) if isinstance(j, str) else int(j))
9 if i == 2: break
10 else: r += (0 for _ in range(2-i))
11 if any(map(f, r)): raise e('asyncutils.version.normalize: major, minor and patch should all be positive')
12 return tuple(r)
13def r(c, /, _='cannot subclass asyncutils.version.%s'): raise TypeError(_%c.__name__)
14def a(c, /, t=tuple(property(lambda o, _=i: o[_]) for i in range(3)), _=classmethod(r), f=('major', 'minor', 'patch')): c._fields, c._asdict = f, lambda self, _=f: dict(zip(_, self)); c.major, c.minor, c.patch = t; c.__floor__ = c.__trunc__ = t[0].fget; c._replace = c.__replace__ = lambda self, **k: c(**self._asdict(), **k); c.__init_subclass__ = _; return c
15N, t, _ = {}, lambda o, /: o if isinstance(o, type) else type(o), 0xFF
16def b(z): z <<= 1; return ~z if z < 0 else z
17def c(key, _=_, f=b): return (key := f(key))&_, (key>>9)&_, key>>17, key>>8&1
[docs]
18@a
19class VersionDelta(tuple):
20 __slots__ = (); _make = classmethod(tuple.__new__)
21 def __new__(cls, major=0, minor=0, patch=0): return cls._make((major, minor, patch))
[docs]
22 def __neg__(self): return __class__(*map(int.__neg__, self))
[docs]
23@a
24class VersionInfo(str): # noqa: FURB189
25 __slots__ = 'parts',
26 def __new__(cls, /, *a, p=p): object.__setattr__(s := super().__new__(cls, '.'.join(map(str, a := normalize(a[0]) if len(a) == 1 else p(a)))), 'parts', a); return s
27 def _hash(self, _=lambda x, y, /: y*y+x if x < y else x*x+x+y, f=lambda n: (~n if n&1 else n)>>1): return f(_(_(*self[:2]), self[2]))
[docs]
28 def __hash__(self): return (x := self._hash())+(x > -2)
[docs]
29 def shelve(self, path, /, key=0x659db, _=_, g=c):
30 x, h, y, l = g(key); y ^= self._hash()
31 with open(path, 'wb') as f: (w := f.write)(bytes((h,))); w(bytes((i-x)&_ for i in y.to_bytes((y.bit_length()>>3)+1, 'little' if l else 'big', signed=True)))
[docs]
32 @classmethod
33 def unshelve(cls, path, /, key=0x659db, _=_, g=c):
34 x, h, y, l = g(key)
35 with open(path, 'rb') as f:
36 if (r := f.read)(1)[0] != h: raise ValueError('asyncutils.version.VersionInfo.unshelve: bad key')
37 return cls._unhash(int.from_bytes(((i+x)&_ for i in r()), 'little' if l else 'big', signed=True)^y)
[docs]
38 @classmethod
39 def from_hash(cls, hashed, _=E.VersionValueError('hash cannot be -1')):
40 if hashed == -1: raise _
41 return cls._unhash(hashed-(hashed > -1))
42 @classmethod
43 def _unhash(cls, c, /, _=b, f=lambda z, f=__import__('math').isqrt: (x, y) if (x := z-(y := f(z))*y) < y else (y, x-y)): b, c = f(_(c)); return cls(*f(b), c)
[docs]
44 @classmethod
45 def from_rep(cls, rep): return cls(rep.removeprefix('asyncutils v'))
[docs]
46 @classmethod
47 def get_current_version(cls, _=E.StateCorrupted('module-internal', 'asyncutils.__version__ is inconsistent with expectations')):
48 from asyncutils import __version__ as V
49 if isinstance(V, cls): V.assert_valid(); return V
50 raise _
[docs]
51 def is_current_version(self): return __class__.get_current_version().parts == self.parts
[docs]
52 def __round__(self, n=None, /): return __class__(self[:n])
53 def __repr__(self): return f'VersionInfo{self:t}'
[docs]
54 def __ceil__(self): return self[0]+any(self[1:])
[docs]
55 def __len__(self): return 3
[docs]
56 def to_complex(self): return complex(*self[:2])
[docs]
57 def __float__(self, _=.01): return sum((j*_**i for i, j in enumerate(self)), start=.0)
[docs]
58 def __reduce__(self): return __class__, self.parts
[docs]
59 def __iter__(self): return self.parts.__iter__()
[docs]
60 def __getitem__(self, i, /): return tuple.__getitem__(self.parts, i)
[docs]
61 def assert_valid(self, _=E.VersionCorrupted):
62 try:
63 if isinstance(p := self.parts, tuple) and len(p) == 3 and all(isinstance(i, int) and i == j >= 0 for i, j in zip(map(int, self.split('.')), p, strict=True)): return # ty: ignore[unsupported-operator]
64 except (ValueError, TypeError, AttributeError): ...
65 raise _(self) # ty: ignore[invalid-argument-type]
[docs]
66 def replace_parts(self, *, _=('major', 'minor', 'patch'), **k): return __class__(*(getattr(self, _) if (v := k.pop(_, None)) is None else v for _ in _))
[docs]
79 def __add__(self, o, /): return __class__(*self[:2], self[2]+o) if isinstance(o, int) else __class__(*map(int.__add__, self, o)) if isinstance(o, VersionDelta) else NotImplemented
[docs]
80 def __sub__(self, o, /, f=lambda x, y: max(0, x-y)): return __class__(*self[:2], f(self[2], o)) if isinstance(o, int) else T[1-T.index(t)](*map(f, self, o)) if (t := type(o)) in (T := (VersionDelta, __class__)) else NotImplemented
[docs]
81 def next_patch(self): return self.replace_parts(patch=self[2]+1)
[docs]
82 def next_minor(self): return __class__(self[0], self[1]+1)
[docs]
83 def next_major(self): return __class__(self[0]+1, 0)
[docs]
84 def change_sep(self, sep): return self.replace('.', sep)
[docs]
85 def __setattr__(self, name, value, /): raise AttributeError(f'asyncutils.version.VersionInfo: immutable attribute: {name!r}')
[docs]
86 def __int__(self, _=0x100):
87 M, m, p = self
88 if not 0 <= p < _ > m >= 0: raise OverflowError(f'asyncutils.version.VersionInfo: cannot pack version {self} into an integer')
89 return p|m<<8|M<<16
90 @property
91 def is_api_unstable(self): return self[0] == 0
[docs]
92 def compatible(self, o, /, majtol=0, mintol=None): return majtol is None or (abs(self[0]-o[0]) <= majtol and (mintol is None or abs(self[1]-o[1]) <= mintol))
93 representation, __index__, __radd__ = property('asyncutils v'.__add__), __int__, __add__; P.patch_classmethod_signatures((__new__, '/, *args'), (get_current_version, ''), (from_hash, 'hashed'), (unshelve, _ := 'path, /, key=5')); P.patch_method_signatures((shelve, _), (__format__, 'format_spec, /'), (_hash, ''), (__sub__, 'other, /'), (replace_parts, '*, major=None, minor=None, patch=None')); del _
[docs]
94def normalize_allow_unimplemented(o, /, E=E, p=p, c=lambda o, /, t=tuple(map(type, (p.__get__(True), True.__init__, ''.lower))), a='__iter__': isinstance(getattr(o, a, None), t), s=frozenset(('inf', '-inf', 'nan')), m=0xFF):
95 if (T := type(o)) is VersionInfo: return o.parts
96 if T is str: o = o.split('.')
97 elif T is complex: o = o.real, o.imag, 0
98 if T is int: o = o>>16, (o>>8)&m, o&m # ty: ignore[unsupported-operator]
99 elif T is float:
100 if (o := format(o, '.4f')) in s: return
101 o, _ = o.split('.', 1); o = map(int, (o, _[:2], _[2:]))
102 elif f := dispatch_normalizer(o, type):
103 try:
104 if (o := f(o)) is None: return
105 except E.CRITICAL: raise E.Critical
106 except BaseException as e: unregister_normalizer(o, type); raise E.VersionNormalizerFault(f, o, e) from None # noqa: BLE001
107 else:
108 if not c(o): raise E.VersionNormalizerTypeError(f, o)
109 elif not c(o): return
110 with E.IgnoreErrors(TypeError, ValueError): return p(o)
[docs]
111def normalize(o, /, _=E.VersionNormalizerMissing):
112 if (r := normalize_allow_unimplemented(o)): return r
113 raise _(o)
[docs]
114def register_normalizer(o, n, /, _=t, f=N.setdefault): return f(_(o), n) is n
[docs]
115def unregister_normalizer(o, /, _=t, f=N.pop): return f(_(o), None)
[docs]
116def dispatch_normalizer(o, /, _=t, f=N.get): return f(_(o))
[docs]
117def autogenerate_normalizers(): return register_normalizer(__import__('_decimal').Decimal, lambda d, /: map(int, ((d := format(d, '.4f'))[:-4], d[-4:-2], d[-2:])))®ister_normalizer(F := __import__('fractions').Fraction, F.as_integer_ratio)
118P.patch_function_signatures((normalize_allow_unimplemented, t := 'o, /'), (unregister_normalizer, t), (dispatch_normalizer, t), (register_normalizer, 'o, f, /'))
119for _ in ('__lt__', '__le__', '__gt__', '__ge__', '__eq__', '__ne__'): setattr(VersionInfo, _, lambda self, other, /, _=getattr(tuple, _): NotImplemented if (other := normalize_allow_unimplemented(other)) is None else _(self.parts, other))
120del _, N, t, P, p, E, a, b, c, r