Source code for asyncutils.version

  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] 67 def __format__(self, s, /, a=dict(x='hex', b='bin', o='oct', dec='d', major='0', minor='1', patch='2', maj='0', min='1', short='s', long='l', ascii='a', chars='c', tuple='t', hash='h', majmin='n').get): # noqa: C408,PLR0911 68 match s := a(s := s.lower(), s): 69 case '0'|'1'|'2': return str(self[int(s)]) 70 case 's': return 'v'+'.'.join(map(str, self if self[2] else self[:2 if self[1] else 1])) 71 case 'l': return f'asyncutils version {self}' 72 case 'a'|'c': return bytes(self).decode('ascii' if s == 'a' else 'latin-1') 73 case 't': return str(self.parts) 74 case 'd': return repr(int(self)) 75 case 'h': return repr(hash(self)) 76 case 'n': return self.rpartition('.')[0] 77 case 'bin'|'hex'|'oct': return __builtins__[s](int(self)) 78 return str(self)
[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:])))&register_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