jetpytools 1.6.5__tar.gz → 1.7.1__tar.gz

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.

Files changed (34) hide show
  1. {jetpytools-1.6.5 → jetpytools-1.7.1}/PKG-INFO +1 -1
  2. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/_metadata.py +1 -1
  3. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/types/utils.py +136 -60
  4. {jetpytools-1.6.5 → jetpytools-1.7.1}/.gitignore +0 -0
  5. {jetpytools-1.6.5 → jetpytools-1.7.1}/LICENSE +0 -0
  6. {jetpytools-1.6.5 → jetpytools-1.7.1}/README.md +0 -0
  7. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/__init__.py +0 -0
  8. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/enums/__init__.py +0 -0
  9. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/enums/base.py +0 -0
  10. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/enums/other.py +0 -0
  11. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/exceptions/__init__.py +0 -0
  12. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/exceptions/base.py +0 -0
  13. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/exceptions/enum.py +0 -0
  14. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/exceptions/file.py +0 -0
  15. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/exceptions/generic.py +0 -0
  16. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/exceptions/module.py +0 -0
  17. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/functions/__init__.py +0 -0
  18. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/functions/funcs.py +0 -0
  19. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/functions/normalize.py +0 -0
  20. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/functions/other.py +0 -0
  21. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/py.typed +0 -0
  22. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/types/__init__.py +0 -0
  23. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/types/builtins.py +0 -0
  24. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/types/check.py +0 -0
  25. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/types/file.py +0 -0
  26. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/types/funcs.py +0 -0
  27. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/types/generic.py +0 -0
  28. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/types/supports.py +0 -0
  29. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/utils/__init__.py +0 -0
  30. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/utils/file.py +0 -0
  31. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/utils/funcs.py +0 -0
  32. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/utils/math.py +0 -0
  33. {jetpytools-1.6.5 → jetpytools-1.7.1}/jetpytools/utils/ranges.py +0 -0
  34. {jetpytools-1.6.5 → jetpytools-1.7.1}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jetpytools
3
- Version: 1.6.5
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,6 +1,6 @@
1
1
  """Collection of stuff that's useful in general python programming"""
2
2
 
3
- __version__ = "1.6.5"
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__
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
- from functools import partial, wraps
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, T1, T2, KwargsT, P, R, R0_co, R1_co, R_co, T, T0_co, T1_co, T_co
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 classproperty(Generic[T, R]):
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]], R] | classmethod[T, ..., R],
413
- fset: Callable[[type[T], R], None] | classmethod[T, Concatenate[R, ...], None] | None = None,
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 __get__(self, obj: T | None, type_: type | None = None) -> R:
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
- return self.fget.__get__(obj, type_)()
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
- self.fset.__get__(None, type(obj))(value)
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
- self.fdel.__get__(None, type(obj))()
474
+ type_ = type(obj)
450
475
 
451
- @property
452
- def __name__(self) -> str:
453
- return self.fget.__name__
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 cachedproperty(property, Generic[P, R_co, T, T0, P0]):
482
+ class classproperty(classproperty_base[T, R_co]):
457
483
  """
458
- Wrapper for a one-time get property, that will be cached.
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
- Keep in mind two things:
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
- * The cache is per-object. Don't hold a reference to itself or it will never get garbage collected.
463
- * Your class has to either manually set __dict__[cachedproperty.cache_key]
464
- or inherit from cachedproperty.baseclass.
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[P, R_co],
489
- fset: Callable[[T, T0], None] | None = None,
490
- fdel: Callable[P0, None] | None = None,
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[P1, R0_co]) -> cachedproperty[P1, R0_co, T, T0, P0]: ...
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
- def setter(self, fset: Callable[[T1, T2], None]) -> cachedproperty[P, R_co, T1, T2, P0]: ...
553
+ if sys.version_info < (3, 13):
497
554
 
498
- def deleter(self, fdel: Callable[P1, None]) -> cachedproperty[P, R_co, T, T0, P1]: ...
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, obj: None, type_: type | None = None) -> Self: ...
560
+ def __get__(self, instance: None, owner: type | None = None) -> Self: ...
502
561
 
503
562
  @overload
504
- def __get__(self, obj: object, type_: type | None = None) -> R_co: ...
563
+ def __get__(self, instance: Any, owner: type | None = None) -> R_co: ...
505
564
 
506
- def __get__(self, obj: Any, type_: type | None = None) -> Any:
507
- if isinstance(self.fget, classproperty):
508
- function = partial(self.fget.__get__, obj, type_) # type: ignore
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
- if not hasattr(obj, cachedproperty.cache_key):
512
- setattr(obj, cachedproperty.cache_key, dict[str, Any]())
569
+ if self.__name__ in (cache := instance.__dict__.setdefault(self.cache_key, {})):
570
+ return cache[self.__name__]
513
571
 
514
- cache = getattr(obj, cachedproperty.cache_key)
515
- name = self.fget.__name__
516
- else:
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
- if name not in cache:
523
- cache[name] = function()
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 cache[name]
580
+ return super().__set__(instance, value)
526
581
 
527
- if TYPE_CHECKING:
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
- def __set__(self, obj: Any, value: R_co, /) -> None: # type: ignore[misc]
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):
File without changes
File without changes
File without changes
File without changes