jetpytools 1.6.5__py3-none-any.whl → 1.7.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jetpytools might be problematic. Click here for more details.
- jetpytools/_metadata.py +1 -1
- jetpytools/types/utils.py +136 -60
- {jetpytools-1.6.5.dist-info → jetpytools-1.7.1.dist-info}/METADATA +1 -1
- {jetpytools-1.6.5.dist-info → jetpytools-1.7.1.dist-info}/RECORD +6 -6
- {jetpytools-1.6.5.dist-info → jetpytools-1.7.1.dist-info}/WHEEL +0 -0
- {jetpytools-1.6.5.dist-info → jetpytools-1.7.1.dist-info}/licenses/LICENSE +0 -0
jetpytools/_metadata.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Collection of stuff that's useful in general python programming"""
|
|
2
2
|
|
|
3
|
-
__version__ = "1.
|
|
3
|
+
__version__ = "1.7.1"
|
|
4
4
|
|
|
5
5
|
__author_name__, __author_email__ = "Jaded Encoding Thaumaturgy", "jaded.encoding.thaumaturgy@gmail.com"
|
|
6
6
|
__maintainer_name__, __maintainer_email__ = __author_name__, __author_email__
|
jetpytools/types/utils.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import sys
|
|
4
|
+
from contextlib import suppress
|
|
5
|
+
from functools import wraps
|
|
4
6
|
from inspect import Signature
|
|
5
7
|
from inspect import _empty as empty_param
|
|
6
8
|
from typing import (
|
|
@@ -21,9 +23,9 @@ from typing import (
|
|
|
21
23
|
overload,
|
|
22
24
|
)
|
|
23
25
|
|
|
24
|
-
from typing_extensions import Self
|
|
26
|
+
from typing_extensions import Self, deprecated
|
|
25
27
|
|
|
26
|
-
from .builtins import F0, F1, P0, P1, R0, R1, T0,
|
|
28
|
+
from .builtins import F0, F1, P0, P1, R0, R1, T0, KwargsT, P, R, R0_co, R1_co, R_co, T, T0_co, T1_co, T_co
|
|
27
29
|
|
|
28
30
|
__all__ = [
|
|
29
31
|
"KwargsNotNone",
|
|
@@ -400,17 +402,15 @@ def get_subclasses(family: type[T], exclude: Sequence[type[T]] = []) -> list[typ
|
|
|
400
402
|
return list(set(_subclasses(family)))
|
|
401
403
|
|
|
402
404
|
|
|
403
|
-
class
|
|
404
|
-
"""
|
|
405
|
-
Make a class property. A combination between classmethod and property.
|
|
406
|
-
"""
|
|
407
|
-
|
|
405
|
+
class classproperty_base(Generic[T, R_co]):
|
|
408
406
|
__isabstractmethod__: bool = False
|
|
409
407
|
|
|
410
408
|
def __init__(
|
|
411
409
|
self,
|
|
412
|
-
fget: Callable[[type[T]],
|
|
413
|
-
fset: Callable[[type[T],
|
|
410
|
+
fget: Callable[[type[T]], R_co] | classmethod[T, ..., R_co],
|
|
411
|
+
fset: Callable[Concatenate[type[T], Any, ...], None]
|
|
412
|
+
| classmethod[T, Concatenate[Any, ...], None]
|
|
413
|
+
| None = None,
|
|
414
414
|
fdel: Callable[[type[T]], None] | classmethod[T, ..., None] | None = None,
|
|
415
415
|
doc: str | None = None,
|
|
416
416
|
) -> None:
|
|
@@ -419,6 +419,7 @@ class classproperty(Generic[T, R]):
|
|
|
419
419
|
self.fdel = self._wrap(fdel) if fdel is not None else fdel
|
|
420
420
|
|
|
421
421
|
self.__doc__ = doc
|
|
422
|
+
self.__name__ = self.fget.__name__
|
|
422
423
|
|
|
423
424
|
def _wrap(self, func: Callable[..., R1] | classmethod[T, P1, R1]) -> classmethod[T, P1, R1]:
|
|
424
425
|
if not isinstance(func, classmethod):
|
|
@@ -426,11 +427,30 @@ class classproperty(Generic[T, R]):
|
|
|
426
427
|
|
|
427
428
|
return func
|
|
428
429
|
|
|
429
|
-
def
|
|
430
|
+
def __set_name__(self, owner: object, name: str) -> None:
|
|
431
|
+
self.__name__ = name
|
|
432
|
+
|
|
433
|
+
def _get_cache(self, type_: type) -> dict[str, Any]:
|
|
434
|
+
cache_key = getattr(self, "cache_key")
|
|
435
|
+
|
|
436
|
+
if not hasattr(type_, cache_key):
|
|
437
|
+
setattr(type_, cache_key, {})
|
|
438
|
+
|
|
439
|
+
return getattr(type_, cache_key)
|
|
440
|
+
|
|
441
|
+
def __get__(self, obj: T | None, type_: type | None = None) -> R_co:
|
|
430
442
|
if type_ is None:
|
|
431
443
|
type_ = type(obj)
|
|
432
444
|
|
|
433
|
-
|
|
445
|
+
if not isinstance(self, classproperty.cached):
|
|
446
|
+
return self.fget.__get__(obj, type_)()
|
|
447
|
+
|
|
448
|
+
if self.__name__ in (cache := self._get_cache(type_)):
|
|
449
|
+
return cache[self.__name__]
|
|
450
|
+
|
|
451
|
+
value = self.fget.__get__(obj, type_)()
|
|
452
|
+
cache[self.__name__] = value
|
|
453
|
+
return value
|
|
434
454
|
|
|
435
455
|
def __set__(self, obj: T, value: Any) -> None:
|
|
436
456
|
if not self.fset:
|
|
@@ -438,7 +458,12 @@ class classproperty(Generic[T, R]):
|
|
|
438
458
|
f'classproperty with getter "{self.__name__}" of "{obj.__class__.__name__}" object has no setter.'
|
|
439
459
|
)
|
|
440
460
|
|
|
441
|
-
|
|
461
|
+
type_ = type(obj)
|
|
462
|
+
|
|
463
|
+
if self.__name__ in (cache := self._get_cache(type_)):
|
|
464
|
+
del cache[self.__name__]
|
|
465
|
+
|
|
466
|
+
self.fset.__get__(None, type_)(value)
|
|
442
467
|
|
|
443
468
|
def __delete__(self, obj: T) -> None:
|
|
444
469
|
if not self.fdel:
|
|
@@ -446,88 +471,139 @@ class classproperty(Generic[T, R]):
|
|
|
446
471
|
f'classproperty with getter "{self.__name__}" of "{obj.__class__.__name__}" object has no deleter.'
|
|
447
472
|
)
|
|
448
473
|
|
|
449
|
-
|
|
474
|
+
type_ = type(obj)
|
|
450
475
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
476
|
+
if self.__name__ in (cache := self._get_cache(type_)):
|
|
477
|
+
del cache[self.__name__]
|
|
478
|
+
|
|
479
|
+
self.fdel.__get__(None, type_)()
|
|
454
480
|
|
|
455
481
|
|
|
456
|
-
class
|
|
482
|
+
class classproperty(classproperty_base[T, R_co]):
|
|
457
483
|
"""
|
|
458
|
-
|
|
484
|
+
A combination of `classmethod` and `property`.
|
|
485
|
+
"""
|
|
486
|
+
|
|
487
|
+
class cached(classproperty_base[T0, R0_co]):
|
|
488
|
+
"""
|
|
489
|
+
A combination of `classmethod` and `property`.
|
|
490
|
+
|
|
491
|
+
The value is computed once and then cached in a dictionary (under `cache_key`)
|
|
492
|
+
attached to the class type. If a setter or deleter is defined and invoked,
|
|
493
|
+
the cache is cleared.
|
|
494
|
+
"""
|
|
495
|
+
|
|
496
|
+
cache_key = "_jetpt_classproperty_cached"
|
|
497
|
+
|
|
498
|
+
@classmethod
|
|
499
|
+
def clear_cache(cls, type_: type, names: str | Iterable[str] | None = None) -> None:
|
|
500
|
+
"""
|
|
501
|
+
Clear cached properties of an type instance.
|
|
459
502
|
|
|
460
|
-
|
|
503
|
+
:param type_: The type whose cache should be cleared.
|
|
504
|
+
:param names: Specific property names to clear. If None, all cached properties are cleared.
|
|
505
|
+
"""
|
|
506
|
+
if names is None:
|
|
507
|
+
with suppress(AttributeError):
|
|
508
|
+
getattr(type_, cls.cache_key).clear()
|
|
509
|
+
return None
|
|
461
510
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
511
|
+
from ..functions import to_arr
|
|
512
|
+
|
|
513
|
+
cache = getattr(type_, cls.cache_key, {})
|
|
514
|
+
|
|
515
|
+
for name in to_arr(names):
|
|
516
|
+
with suppress(KeyError):
|
|
517
|
+
del cache[name]
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
class cachedproperty(property, Generic[R_co]):
|
|
521
|
+
"""
|
|
522
|
+
Wrapper for a one-time get property, that will be cached.
|
|
523
|
+
|
|
524
|
+
You shouldn't hold a reference to itself or it will never get garbage collected.
|
|
465
525
|
"""
|
|
466
526
|
|
|
467
527
|
__isabstractmethod__: bool = False
|
|
468
528
|
|
|
469
529
|
cache_key = "_jetpt_cachedproperty_cache"
|
|
470
530
|
|
|
531
|
+
@deprecated(
|
|
532
|
+
"The cache dict is now set automatically. You no longer need to inherit from it", category=DeprecationWarning
|
|
533
|
+
)
|
|
471
534
|
class baseclass:
|
|
472
535
|
"""Inherit from this class to automatically set the cache dict."""
|
|
473
536
|
|
|
474
|
-
if not TYPE_CHECKING:
|
|
475
|
-
|
|
476
|
-
def __new__(cls, *args: Any, **kwargs: Any) -> None:
|
|
477
|
-
try:
|
|
478
|
-
self = super().__new__(cls, *args, **kwargs)
|
|
479
|
-
except TypeError:
|
|
480
|
-
self = super().__new__(cls)
|
|
481
|
-
self.__dict__.__setitem__(cachedproperty.cache_key, dict[str, Any]())
|
|
482
|
-
return self
|
|
483
|
-
|
|
484
537
|
if TYPE_CHECKING:
|
|
485
538
|
|
|
486
539
|
def __init__(
|
|
487
540
|
self,
|
|
488
|
-
fget: Callable[
|
|
489
|
-
fset: Callable[[
|
|
490
|
-
fdel: Callable[
|
|
541
|
+
fget: Callable[[Any], R_co],
|
|
542
|
+
fset: Callable[[Any, Any], None] | None = None,
|
|
543
|
+
fdel: Callable[[Any], None] | None = None,
|
|
491
544
|
doc: str | None = None,
|
|
492
545
|
) -> None: ...
|
|
493
546
|
|
|
494
|
-
def getter(self, fget: Callable[
|
|
547
|
+
def getter(self, fget: Callable[..., R_co]) -> cachedproperty[R_co]: ...
|
|
548
|
+
|
|
549
|
+
def setter(self, fset: Callable[[Any, Any], None]) -> cachedproperty[R_co]: ...
|
|
550
|
+
|
|
551
|
+
def deleter(self, fdel: Callable[..., None]) -> cachedproperty[R_co]: ...
|
|
495
552
|
|
|
496
|
-
|
|
553
|
+
if sys.version_info < (3, 13):
|
|
497
554
|
|
|
498
|
-
def
|
|
555
|
+
def __init__(self, fget: Any, fset: Any | None = None, fdel: Any | None = None, doc: str | None = None) -> None:
|
|
556
|
+
self.__name__ = fget.__name__
|
|
557
|
+
super().__init__(fget, fset, fdel, doc)
|
|
499
558
|
|
|
500
559
|
@overload
|
|
501
|
-
def __get__(self,
|
|
560
|
+
def __get__(self, instance: None, owner: type | None = None) -> Self: ...
|
|
502
561
|
|
|
503
562
|
@overload
|
|
504
|
-
def __get__(self,
|
|
563
|
+
def __get__(self, instance: Any, owner: type | None = None) -> R_co: ...
|
|
505
564
|
|
|
506
|
-
def __get__(self,
|
|
507
|
-
if
|
|
508
|
-
|
|
509
|
-
obj = type_
|
|
565
|
+
def __get__(self, instance: Any, owner: type | None = None) -> Any:
|
|
566
|
+
if instance is None:
|
|
567
|
+
return self
|
|
510
568
|
|
|
511
|
-
|
|
512
|
-
|
|
569
|
+
if self.__name__ in (cache := instance.__dict__.setdefault(self.cache_key, {})):
|
|
570
|
+
return cache[self.__name__]
|
|
513
571
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
assert self.fget
|
|
518
|
-
function = self.fget.__get__(obj, type_)
|
|
519
|
-
cache = obj.__dict__.get(cachedproperty.cache_key)
|
|
520
|
-
name = function.__name__
|
|
572
|
+
value = super().__get__(instance, owner)
|
|
573
|
+
cache[self.__name__] = value
|
|
574
|
+
return value
|
|
521
575
|
|
|
522
|
-
|
|
523
|
-
|
|
576
|
+
def __set__(self, instance: Any, value: Any) -> None:
|
|
577
|
+
if self.__name__ in (cache := instance.__dict__.setdefault(self.cache_key, {})):
|
|
578
|
+
del cache[self.__name__]
|
|
524
579
|
|
|
525
|
-
return
|
|
580
|
+
return super().__set__(instance, value)
|
|
526
581
|
|
|
527
|
-
|
|
582
|
+
def __delete__(self, instance: Any) -> None:
|
|
583
|
+
if self.__name__ in (cache := instance.__dict__.setdefault(self.cache_key, {})):
|
|
584
|
+
del cache[self.__name__]
|
|
585
|
+
|
|
586
|
+
return super().__delete__(instance)
|
|
587
|
+
|
|
588
|
+
@classmethod
|
|
589
|
+
def clear_cache(cls, obj: object, names: str | Iterable[str] | None = None) -> None:
|
|
590
|
+
"""
|
|
591
|
+
Clear cached properties of an object instance.
|
|
592
|
+
|
|
593
|
+
:param obj: The object whose cache should be cleared.
|
|
594
|
+
:param names: Specific property names to clear. If None, all cached properties are cleared.
|
|
595
|
+
"""
|
|
596
|
+
if names is None:
|
|
597
|
+
obj.__dict__.get(cls.cache_key, {}).clear()
|
|
598
|
+
return None
|
|
599
|
+
|
|
600
|
+
from ..functions import to_arr
|
|
601
|
+
|
|
602
|
+
cache = obj.__dict__.get(cls.cache_key, {})
|
|
528
603
|
|
|
529
|
-
|
|
530
|
-
|
|
604
|
+
for name in to_arr(names):
|
|
605
|
+
with suppress(KeyError):
|
|
606
|
+
del cache[name]
|
|
531
607
|
|
|
532
608
|
|
|
533
609
|
class KwargsNotNone(KwargsT):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jetpytools
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.1
|
|
4
4
|
Summary: Collection of stuff that's useful in general python programming
|
|
5
5
|
Project-URL: Source Code, https://github.com/Jaded-Encoding-Thaumaturgy/jetpytools
|
|
6
6
|
Project-URL: Contact, https://discord.gg/XTpc6Fa9eB
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
jetpytools/__init__.py,sha256=ha_pCOMqfeIbipDRrtqKOqH3NQEpX4KwN2SskpsCGb4,114
|
|
2
|
-
jetpytools/_metadata.py,sha256=
|
|
2
|
+
jetpytools/_metadata.py,sha256=lqi2SmD1Kr0aXukbAQaNUyoWqdq00iRpW-gpGQ3gJjw,414
|
|
3
3
|
jetpytools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
jetpytools/enums/__init__.py,sha256=TvEt3TWmnzf2TWS_Gd6llyyXAGDKxdhdJsDgSvT7xys,41
|
|
5
5
|
jetpytools/enums/base.py,sha256=L5dk6UAsQ3V6GVj0vulKaiJsholnh0Ftyh1FZFM9zwI,2034
|
|
@@ -21,13 +21,13 @@ jetpytools/types/file.py,sha256=LbOwMAwDALWxAZZ2i7ZNexoN3GHWD-uUoIhVvUy95Vo,6539
|
|
|
21
21
|
jetpytools/types/funcs.py,sha256=U5tBmTtLS5CLp3ZtOiA5101PQiCWQOBsmf0bj1pRwgY,2778
|
|
22
22
|
jetpytools/types/generic.py,sha256=SFnUqDAVehKZ36HmLrs9PN4Ze0BLcabPjwC7hJsGp4w,1102
|
|
23
23
|
jetpytools/types/supports.py,sha256=woMTv62HpcRiC5TG18U8NU5v2Q6iqcrHzQgXl7QYEws,3516
|
|
24
|
-
jetpytools/types/utils.py,sha256=
|
|
24
|
+
jetpytools/types/utils.py,sha256=tIN6OdjrwHxb8XyQeptWh4YbOKdABPOZkKpONZ7eAv8,22877
|
|
25
25
|
jetpytools/utils/__init__.py,sha256=_rJ-mY5PsGjBfy8Fihx_FYJfAIGSrYAYzI6Td9oFh9A,83
|
|
26
26
|
jetpytools/utils/file.py,sha256=um4ow7_UEH1UxOV74w6F1u4s0wC4zh98LrcwBYjed50,10578
|
|
27
27
|
jetpytools/utils/funcs.py,sha256=2qhFyLD0OLvenjzOu2wu1ZWoZGzQ8aPmvbkAI1i9Gvk,914
|
|
28
28
|
jetpytools/utils/math.py,sha256=I56OeHDDJl3X8EFXMWVEiXGAD16AKcn8KVnFuP5fFes,3445
|
|
29
29
|
jetpytools/utils/ranges.py,sha256=glxypgmuzauV6KCSNujNHOdWkNEUNylOUAPS618jnIg,2559
|
|
30
|
-
jetpytools-1.
|
|
31
|
-
jetpytools-1.
|
|
32
|
-
jetpytools-1.
|
|
33
|
-
jetpytools-1.
|
|
30
|
+
jetpytools-1.7.1.dist-info/METADATA,sha256=HmlHVWQzTOvcGcFVN1BM-ljNSMWe8sXJnIzRRzOA8vg,1198
|
|
31
|
+
jetpytools-1.7.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
32
|
+
jetpytools-1.7.1.dist-info/licenses/LICENSE,sha256=l0PN-qDtXcgOB5aXP_nSUsvCK5V3o9pQCGsTzyZhKL0,1071
|
|
33
|
+
jetpytools-1.7.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|