jetpytools 1.2.5__py3-none-any.whl → 1.2.7__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 CHANGED
@@ -1,6 +1,6 @@
1
1
  """Collection of stuff that's useful in general python programming"""
2
2
 
3
- __version__ = '1.2.5'
3
+ __version__ = '1.2.7'
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/enums/base.py CHANGED
@@ -3,6 +3,8 @@ from __future__ import annotations
3
3
  from enum import Enum
4
4
  from typing import Any, TypeVar
5
5
 
6
+ from typing_extensions import Self
7
+
6
8
  from ..exceptions import CustomValueError, NotFoundEnumValue
7
9
  from ..types import FuncExceptT
8
10
 
@@ -16,11 +18,11 @@ class CustomEnum(Enum):
16
18
  """Base class for custom enums."""
17
19
 
18
20
  @classmethod
19
- def _missing_(cls: type[SelfEnum], value: Any) -> SelfEnum | None:
21
+ def _missing_(cls, value: Any) -> Self | None:
20
22
  return cls.from_param(value)
21
23
 
22
24
  @classmethod
23
- def from_param(cls: type[SelfEnum], value: Any, func_except: FuncExceptT | None = None) -> SelfEnum | None:
25
+ def from_param(cls, value: Any, func_except: FuncExceptT | None = None) -> Self | None:
24
26
  """
25
27
  Return the enum value from a parameter.
26
28
 
jetpytools/enums/other.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TypeVar, overload
3
+ from typing import overload
4
+ from typing_extensions import Self
4
5
 
5
6
  __all__ = [
6
7
  'Coordinate',
@@ -23,14 +24,14 @@ class Coordinate:
23
24
  """Vertical coordinate."""
24
25
 
25
26
  @overload
26
- def __init__(self: SelfCoord, other: tuple[int, int] | SelfCoord, /) -> None:
27
+ def __init__(self, other: tuple[int, int] | Self, /) -> None:
27
28
  ...
28
29
 
29
30
  @overload
30
- def __init__(self: SelfCoord, x: int, y: int, /) -> None:
31
+ def __init__(self, x: int, y: int, /) -> None:
31
32
  ...
32
33
 
33
- def __init__(self: SelfCoord, x_or_self: int | tuple[int, int] | SelfCoord, y: int | None = None, /) -> None:
34
+ def __init__(self, x_or_self: int | tuple[int, int] | Self, y: int | None = None, /) -> None:
34
35
  from ..exceptions import CustomValueError
35
36
 
36
37
  if isinstance(x_or_self, int):
@@ -48,9 +49,6 @@ class Coordinate:
48
49
  self.y = y
49
50
 
50
51
 
51
- SelfCoord = TypeVar('SelfCoord', bound=Coordinate)
52
-
53
-
54
52
  class Position(Coordinate):
55
53
  """Positive set of an (x,y) offset relative to the top left corner of an area."""
56
54
 
@@ -1,10 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import sys
4
+
4
5
  from copy import deepcopy
5
6
  from typing import TYPE_CHECKING, Any, TypeVar
6
7
 
7
- from ..types import MISSING, FuncExceptT, SupportsString
8
+ from typing_extensions import Self
9
+
10
+ from ..types import MISSING, FuncExceptT, SupportsString, MissingT
8
11
 
9
12
  __all__ = [
10
13
  'CustomError',
@@ -112,10 +115,12 @@ class CustomError(ExceptionT, metaclass=CustomErrorMeta):
112
115
  return CustomErrorMeta.setup_exception(inner_exception, exception) # type: ignore
113
116
 
114
117
  def __call__(
115
- self: SelfError, message: SupportsString | None = MISSING,
116
- func: FuncExceptT | None = MISSING, reason: SupportsString | FuncExceptT | None = MISSING, # type: ignore
118
+ self,
119
+ message: SupportsString | None | MissingT = MISSING,
120
+ func: FuncExceptT | None | MissingT = MISSING,
121
+ reason: SupportsString | FuncExceptT | None | MissingT = MISSING,
117
122
  **kwargs: Any
118
- ) -> SelfError:
123
+ ) -> Self:
119
124
  """
120
125
  Copy an existing exception with defaults and instantiate a new one.
121
126
 
@@ -129,7 +134,7 @@ class CustomError(ExceptionT, metaclass=CustomErrorMeta):
129
134
  if message is not MISSING:
130
135
  err.message = message
131
136
 
132
- if func is not MISSING: # type: ignore[comparison-overlap]
137
+ if func is not MISSING:
133
138
  err.func = func
134
139
 
135
140
  if reason is not MISSING:
@@ -18,8 +18,8 @@ class MismatchError(CustomValueError):
18
18
  return str(item)
19
19
 
20
20
  @classmethod
21
- def _reduce(cls, items: Iterable[Any]) -> tuple[str]:
22
- return tuple[str](dict.fromkeys(map(cls._item_to_name, items)).keys()) # type: ignore
21
+ def _reduce(cls, items: Iterable[Any]) -> tuple[str, ...]:
22
+ return tuple(dict.fromkeys(map(cls._item_to_name, items)).keys())
23
23
 
24
24
  def __init__(
25
25
  self, func: FuncExceptT, items: Iterable[Any], message: SupportsString = 'All items must be equal!',
@@ -28,7 +28,7 @@ class MismatchError(CustomValueError):
28
28
  super().__init__(message, func, reason, **kwargs, reduced_items=iter(self._reduce(items)))
29
29
 
30
30
  @classmethod
31
- def check(cls, func: FuncExceptT, *items: Any, **kwargs: Any) -> None:
31
+ def check(cls, func: FuncExceptT, /, *items: Any, **kwargs: Any) -> None:
32
32
  if len(cls._reduce(items)) != 1:
33
33
  raise cls(func, items, **kwargs)
34
34
 
@@ -40,6 +40,6 @@ class MismatchRefError(MismatchError):
40
40
  super().__init__(func, [base, ref], message, **kwargs)
41
41
 
42
42
  @classmethod
43
- def check(cls, func: FuncExceptT, *items: Any, **kwargs: Any) -> None:
43
+ def check(cls, func: FuncExceptT, /, *items: Any, **kwargs: Any) -> None:
44
44
  if len(cls._reduce(items)) != 1:
45
45
  raise cls(func, *items, **kwargs)
@@ -1,9 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from fractions import Fraction
4
- from typing import Any, Iterable, Iterator, Sequence, overload
4
+ from typing import Any, Callable, Iterable, Iterator, Sequence, overload
5
5
 
6
- from ..types import F, SupportsString, T, SoftRange, SoftRangeN, SoftRangesN, StrictRange
6
+ from ..types import SoftRange, SoftRangeN, SoftRangesN, StrictRange, SupportsString, T, is_soft_range_n
7
7
 
8
8
  __all__ = [
9
9
  'normalize_seq',
@@ -19,12 +19,12 @@ __all__ = [
19
19
 
20
20
 
21
21
  @overload
22
- def normalize_seq(val: Sequence[T], length: int) -> list[T]:
22
+ def normalize_seq(val: T | Sequence[T], length: int) -> list[T]:
23
23
  ...
24
24
 
25
25
 
26
26
  @overload
27
- def normalize_seq(val: T | Sequence[T], length: int) -> list[T]:
27
+ def normalize_seq(val: Any, length: int) -> list[Any]:
28
28
  ...
29
29
 
30
30
 
@@ -47,45 +47,43 @@ def normalize_seq(val: T | Sequence[T], length: int) -> list[T]:
47
47
  return val[:length]
48
48
 
49
49
 
50
- _iterables_t = (list, tuple, range, zip, set, map, enumerate)
51
-
52
-
53
50
  @overload
54
- def to_arr(val: list[T], *, sub: bool = False) -> list[T]:
51
+ def to_arr(val: T | Iterable[T]) -> list[T]:
55
52
  ...
56
53
 
57
54
 
58
55
  @overload
59
- def to_arr(val: T | Sequence[T], *, sub: bool = False) -> list[T]:
56
+ def to_arr(val: Any) -> list[Any]:
60
57
  ...
61
58
 
62
59
 
63
- def to_arr(val: T | Sequence[T], *, sub: bool = False) -> list[T]:
64
- """Normalize any value into an iterable."""
65
-
60
+ def to_arr(val: Any, *, sub: Any = []) -> list[Any]:
61
+ """
62
+ Normalize any value to a list.
63
+ Bytes and str are not considered iterable and will not be flattened.
64
+ """
66
65
  if sub:
67
- return list(val) if any(isinstance(val, x) for x in _iterables_t) else [val] # type: ignore
66
+ import warnings
67
+ warnings.warn("sub is deprecated.", DeprecationWarning)
68
68
 
69
- return list(val) if type(val) in _iterables_t else [val] # type: ignore
69
+ return list(val) if (isinstance(val, Iterable) and not isinstance(val, (str, bytes))) else [val]
70
70
 
71
71
 
72
72
  @overload
73
- def flatten(items: T | Iterable[T | Iterable[T | Iterable[T]]]) -> Iterable[T]:
73
+ def flatten(items: Iterable[Iterable[T]]) -> Iterator[T]:
74
74
  ...
75
75
 
76
76
 
77
77
  @overload
78
- def flatten(items: T | Iterable[T | Iterable[T]]) -> Iterable[T]: # type: ignore
78
+ def flatten(items: Iterable[Any]) -> Iterator[Any]:
79
79
  ...
80
80
 
81
81
 
82
- @overload
83
- def flatten(items: T | Iterable[T]) -> Iterable[T]: # type: ignore
84
- ...
85
-
86
-
87
- def flatten(items: Any) -> Any:
88
- """Flatten an array of values."""
82
+ def flatten(items: Any) -> Iterator[Any]:
83
+ """
84
+ Flatten an array of values.
85
+ Bytes and str are not considered iterable and will not be flattened..
86
+ """
89
87
 
90
88
  for val in items:
91
89
  if isinstance(val, Iterable) and not isinstance(val, (str, bytes)):
@@ -170,13 +168,13 @@ def normalize_ranges(ranges: SoftRangeN | SoftRangesN, end: int) -> list[StrictR
170
168
  [(24, 150)]
171
169
 
172
170
 
173
- :param clip: Input clip.
174
171
  :param franges: Frame range or list of frame ranges.
172
+ :param end: End number.
175
173
 
176
174
  :return: List of positive frame ranges.
177
175
  """
178
176
 
179
- ranges = ranges if isinstance(ranges, list) else [ranges] # type:ignore
177
+ ranges = [ranges] if is_soft_range_n(ranges) else ranges
180
178
 
181
179
  out = []
182
180
 
@@ -215,7 +213,7 @@ def invert_ranges(ranges: SoftRangeN | SoftRangesN, enda: int, endb: int | None)
215
213
  return normalize_list_to_ranges({*range(enda)} - b_frames)
216
214
 
217
215
 
218
- def norm_func_name(func_name: SupportsString | F) -> str:
216
+ def norm_func_name(func_name: SupportsString | Callable[..., Any]) -> str:
219
217
  """Normalize a class, function, or other object to obtain its name"""
220
218
 
221
219
  if isinstance(func_name, str):
@@ -1,4 +1,5 @@
1
1
  from .builtins import * # noqa: F401, F403
2
+ from .check import * # noqa: F401, F403
2
3
  from .file import * # noqa: F401, F403
3
4
  from .funcs import * # noqa: F401, F403
4
5
  from .generic import * # noqa: F401, F403
@@ -1,8 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import (
4
- TYPE_CHECKING, Any, Callable, ParamSpec, Sequence, SupportsFloat, SupportsIndex, TypeAlias, TypeVar, Union
5
- )
3
+ from typing import Any, Callable, ParamSpec, Sequence, SupportsFloat, SupportsIndex, TypeAlias, TypeVar, Union
6
4
 
7
5
  __all__ = [
8
6
  'T', 'T0', 'T1', 'T2', 'T_contra',
@@ -10,14 +8,12 @@ __all__ = [
10
8
  'F', 'F0', 'F1', 'F2',
11
9
 
12
10
  'P', 'P0', 'P1', 'P2',
13
- 'R', 'R0', 'R1', 'R2', 'R_contra',
11
+ 'R', 'R0', 'R1', 'R2', 'R_co', 'R0_co', 'R_contra',
14
12
 
15
13
  'Nb',
16
14
 
17
15
  'StrictRange', 'SoftRange', 'SoftRangeN', 'SoftRangesN',
18
16
 
19
- 'Self',
20
-
21
17
  'SingleOrArr', 'SingleOrArrOpt',
22
18
  'SingleOrSeq', 'SingleOrSeqOpt',
23
19
 
@@ -49,20 +45,18 @@ R0 = TypeVar('R0')
49
45
  R1 = TypeVar('R1')
50
46
  R2 = TypeVar('R2')
51
47
 
48
+ R_co = TypeVar('R_co', covariant=True)
49
+ R0_co = TypeVar('R0_co', covariant=True)
50
+
52
51
  T_contra = TypeVar('T_contra', contravariant=True)
53
52
  R_contra = TypeVar('R_contra', contravariant=True)
54
53
 
55
- Self = TypeVar('Self')
56
-
57
54
  StrictRange: TypeAlias = tuple[int, int]
58
55
  SoftRange: TypeAlias = int | StrictRange | Sequence[int]
59
56
 
60
57
  SoftRangeN: TypeAlias = int | tuple[int | None, int | None] | None
61
58
 
62
- if TYPE_CHECKING:
63
- SoftRangesN: TypeAlias = Sequence[SoftRangeN]
64
- else:
65
- SoftRangesN: TypeAlias = list[SoftRangeN]
59
+ SoftRangesN: TypeAlias = Sequence[SoftRangeN]
66
60
 
67
61
  SingleOrArr = Union[T, list[T]]
68
62
  SingleOrSeq = Union[T, Sequence[T]]
@@ -0,0 +1,34 @@
1
+ from typing import Any, Sequence
2
+
3
+ from typing_extensions import TypeIs
4
+
5
+ from .builtins import SoftRange, SoftRangeN, SoftRangesN, StrictRange
6
+
7
+ __all__ = [
8
+ "is_strict_range", "is_soft_range", "is_soft_range_n", "is_soft_ranges_n"
9
+ ]
10
+
11
+
12
+ def is_strict_range(val: Any) -> TypeIs[StrictRange]:
13
+ return isinstance(val, tuple) and len(val) == 2 and all(isinstance(x, int) for x in val)
14
+
15
+
16
+ def is_soft_range(val: Any) -> TypeIs[SoftRange]:
17
+ return isinstance(val, int) or is_strict_range(val) or (
18
+ isinstance(val, Sequence) and all(isinstance(x, int) for x in val)
19
+ )
20
+
21
+
22
+ def is_soft_range_n(val: Any) -> TypeIs[SoftRangeN]:
23
+ return (
24
+ isinstance(val, int)
25
+ or (isinstance(val, tuple) and len(val) == 2 and all(isinstance(x, int) or x is None for x in val))
26
+ or val is None
27
+ )
28
+
29
+
30
+ def is_soft_ranges_n(val: Any) -> TypeIs[SoftRangesN]:
31
+ return (
32
+ isinstance(val, Sequence)
33
+ and all(is_soft_range_n(x) for x in val)
34
+ )
jetpytools/types/file.py CHANGED
@@ -121,7 +121,7 @@ class SPath(Path):
121
121
 
122
122
  from ..functions import to_arr
123
123
 
124
- return self.with_stem(sep.join([self.stem, *to_arr(suffixes)])) # type:ignore[list-item]
124
+ return self.with_stem(sep.join([self.stem, *to_arr(suffixes)]))
125
125
 
126
126
  def is_empty_dir(self) -> bool:
127
127
  """Check if the directory is empty."""
@@ -176,10 +176,12 @@ class SPath(Path):
176
176
 
177
177
  matching_files = self.get_folder().glob(pattern)
178
178
 
179
- if not matching_files:
179
+ try:
180
+ next(matching_files)
181
+ except StopIteration:
180
182
  return None
181
183
 
182
- return max(matching_files, key=lambda p: p.stat().st_mtime, default=None) # type:ignore
184
+ return max(matching_files, key=lambda p: p.stat().st_mtime)
183
185
 
184
186
  def get_size(self) -> int:
185
187
  """Get the size of the file or directory in bytes."""
@@ -194,4 +196,4 @@ class SPath(Path):
194
196
  return sum(f.stat().st_size for f in self.rglob('*') if f.is_file())
195
197
 
196
198
 
197
- SPathLike = Union[str, Path, SPath]
199
+ SPathLike = Union[str, PathLike[str], Path, SPath]
jetpytools/types/funcs.py CHANGED
@@ -1,9 +1,11 @@
1
1
  from __future__ import annotations
2
+
2
3
  from functools import wraps
4
+ from typing import TYPE_CHECKING, Any, Callable, Iterable, Iterator, SupportsIndex, TypeAlias, overload
3
5
 
4
- from typing import TYPE_CHECKING, Any, Callable, Iterable, List, SupportsIndex, TypeAlias, TypeVar, overload
6
+ from typing_extensions import Self, TypeIs
5
7
 
6
- from .builtins import T, P
8
+ from .builtins import P, T
7
9
  from .supports import SupportsString
8
10
 
9
11
  __all__ = [
@@ -13,7 +15,7 @@ __all__ = [
13
15
  ]
14
16
 
15
17
 
16
- class StrList(List[SupportsString]):
18
+ class StrList(list[SupportsString]):
17
19
  """Custom class for representing a recursively "stringable" list."""
18
20
 
19
21
  if TYPE_CHECKING:
@@ -41,7 +43,7 @@ class StrList(List[SupportsString]):
41
43
  return ' '.join(
42
44
  filter(
43
45
  None,
44
- (str(x).strip() for x in flatten(self) if x is not None) # type: ignore[var-annotated,arg-type]
46
+ (str(x).strip() for x in flatten(self) if x is not None)
45
47
  )
46
48
  )
47
49
 
@@ -74,20 +76,22 @@ class SentinelDispatcher:
74
76
 
75
77
  return _wrap
76
78
 
77
- def filter(self: SelfSentinel, items: Iterable[T | SelfSentinel]) -> Iterable[T]:
79
+ def filter(self, items: Iterable[T | Self]) -> Iterator[T]:
78
80
  for item in items:
79
- if item is self:
81
+ if isinstance(item, SentinelDispatcher):
80
82
  continue
81
-
82
- yield item # type: ignore
83
+ yield item
83
84
 
84
85
  @classmethod
85
- def filter_multi(cls, items: Iterable[T | SelfSentinel], *sentinels: SelfSentinel) -> Iterable[T]:
86
+ def filter_multi(cls, items: Iterable[T | Self], *sentinels: Self) -> Iterator[T]:
87
+ def _in_sentinels(it: Any) -> TypeIs[SentinelDispatcher]:
88
+ return it in sentinels
89
+
86
90
  for item in items:
87
- if item in sentinels:
91
+ if _in_sentinels(item):
88
92
  continue
89
93
 
90
- yield item # type: ignore
94
+ yield item
91
95
 
92
96
  def __getattr__(self, name: str) -> SentinelDispatcher:
93
97
  if name not in _sentinels:
@@ -105,5 +109,3 @@ Sentinel = SentinelDispatcher()
105
109
  SentinelT: TypeAlias = SentinelDispatcher
106
110
 
107
111
  _sentinels = dict[str, SentinelDispatcher]()
108
-
109
- SelfSentinel = TypeVar('SelfSentinel', bound=SentinelDispatcher)
jetpytools/types/utils.py CHANGED
@@ -8,8 +8,9 @@ from typing import (
8
8
  TYPE_CHECKING, Any, Callable, Concatenate, Generator, Generic, Iterable, Iterator, Mapping,
9
9
  NoReturn, Protocol, Sequence, TypeVar, cast, overload
10
10
  )
11
+ from typing_extensions import Self
11
12
 
12
- from .builtins import F0, F1, P0, P1, R0, R1, T0, T1, T2, KwargsT, P, R, T
13
+ from .builtins import F0, F1, P0, P1, R0, R1, T0, T1, T2, KwargsT, P, R, R_co, R0_co, T
13
14
 
14
15
  __all__ = [
15
16
  'copy_signature',
@@ -97,10 +98,15 @@ class injected_self_func(Generic[T, P, R], Protocol): # type: ignore[misc]
97
98
  ...
98
99
 
99
100
 
100
- self_objects_cache = dict[type[T], T]() # type: ignore
101
+ self_objects_cache = dict[type, Any]()
101
102
 
102
103
 
103
104
  class inject_self_base(Generic[T, P, R]):
105
+ cache: bool | None
106
+ signature: Signature | None
107
+ init_kwargs: list[str] | None
108
+ first_key: str | None
109
+
104
110
  def __init__(self, function: Callable[Concatenate[T, P], R], /, *, cache: bool = False) -> None:
105
111
  """
106
112
  Wrap ``function`` to always have a self provided to it.
@@ -126,20 +132,20 @@ class inject_self_base(Generic[T, P, R]):
126
132
  def __get__(
127
133
  self, class_obj: type[T] | T | None, class_type: type[T] | type[type[T]] # type: ignore
128
134
  ) -> injected_self_func[T, P, R]:
129
- if not self.signature or not self.first_key: # type: ignore
130
- self.signature = Signature.from_callable(self.function, eval_str=True) # type: ignore
131
- self.first_key = next(iter(list(self.signature.parameters.keys())), None) # type: ignore
135
+ if not self.signature or not self.first_key:
136
+ self.signature = Signature.from_callable(self.function, eval_str=True)
137
+ self.first_key = next(iter(list(self.signature.parameters.keys())), None)
132
138
 
133
139
  if isinstance(self, inject_self.init_kwargs):
134
140
  from ..exceptions import CustomValueError
135
141
 
136
- if 4 not in {x.kind for x in self.signature.parameters.values()}: # type: ignore
142
+ if 4 not in {x.kind for x in self.signature.parameters.values()}:
137
143
  raise CustomValueError(
138
144
  'This function hasn\'t got any kwargs!', 'inject_self.init_kwargs', self.function
139
145
  )
140
146
 
141
- self.init_kwargs = list[str]( # type: ignore
142
- k for k, x in self.signature.parameters.items() if x.kind != 4 # type: ignore
147
+ self.init_kwargs = list[str](
148
+ k for k, x in self.signature.parameters.items() if x.kind != 4
143
149
  )
144
150
 
145
151
  @wraps(self.function)
@@ -151,15 +157,15 @@ class inject_self_base(Generic[T, P, R]):
151
157
  if (
152
158
  first_arg and (
153
159
  (is_obj := isinstance(first_arg, class_type))
154
- or isinstance(first_arg, type(class_type)) # noqa
155
- or first_arg is class_type # noqa
160
+ or isinstance(first_arg, type(class_type))
161
+ or first_arg is class_type
156
162
  )
157
163
  ):
158
164
  obj = first_arg if is_obj else first_arg()
159
165
  if args:
160
166
  args = args[1:]
161
167
  elif kwargs and self.first_key:
162
- kwargs.pop(self.first_key) # type: ignore
168
+ kwargs.pop(self.first_key)
163
169
  elif class_obj is None:
164
170
  if self.cache:
165
171
  if class_type not in self_objects_cache:
@@ -167,7 +173,7 @@ class inject_self_base(Generic[T, P, R]):
167
173
  else:
168
174
  obj = self_objects_cache[class_type]
169
175
  elif self.init_kwargs:
170
- obj = class_type( # type: ignore
176
+ obj = class_type(
171
177
  *self.args, **(self.kwargs | {k: v for k, v in kwargs.items() if k not in self.init_kwargs})
172
178
  )
173
179
  if self.clean_kwargs:
@@ -473,7 +479,7 @@ class classproperty(Generic[P, R, T, T0, P0]):
473
479
 
474
480
  return self.fget.__get__(__obj, __type)() # type: ignore
475
481
 
476
- def __set__(self, __obj: Any, __value: T1) -> None:
482
+ def __set__(self, __obj: Any, __value: Any) -> None:
477
483
  from ..exceptions import CustomError
478
484
 
479
485
  if not self.fset:
@@ -503,7 +509,7 @@ class classproperty(Generic[P, R, T, T0, P0]):
503
509
  return self.fget.__name__
504
510
 
505
511
 
506
- class cachedproperty(property, Generic[P, R, T, T0, P0]):
512
+ class cachedproperty(property, Generic[P, R_co, T, T0, P0]):
507
513
  """
508
514
  Wrapper for a one-time get property, that will be cached.
509
515
 
@@ -532,21 +538,29 @@ class cachedproperty(property, Generic[P, R, T, T0, P0]):
532
538
 
533
539
  if TYPE_CHECKING:
534
540
  def __init__(
535
- self, fget: Callable[P, R], fset: Callable[[T, T0], None] | None = None,
541
+ self, fget: Callable[P, R_co], fset: Callable[[T, T0], None] | None = None,
536
542
  fdel: Callable[P0, None] | None = None, doc: str | None = None,
537
543
  ) -> None:
538
544
  ...
539
545
 
540
- def getter(self, __fget: Callable[P1, R1]) -> cachedproperty[P1, R1, T, T0, P0]:
546
+ def getter(self, __fget: Callable[P1, R0_co]) -> cachedproperty[P1, R0_co, T, T0, P0]:
541
547
  ...
542
548
 
543
- def setter(self, __fset: Callable[[T1, T2], None]) -> cachedproperty[P, R, T1, T2, P0]:
549
+ def setter(self, __fset: Callable[[T1, T2], None]) -> cachedproperty[P, R_co, T1, T2, P0]:
544
550
  ...
545
551
 
546
- def deleter(self, __fdel: Callable[P1, None]) -> cachedproperty[P, R, T, T0, P1]:
552
+ def deleter(self, __fdel: Callable[P1, None]) -> cachedproperty[P, R_co, T, T0, P1]:
547
553
  ...
548
554
 
549
- def __get__(self, __obj: Any, __type: type | None = None) -> R:
555
+ @overload
556
+ def __get__(self, __obj: None, __type: type | None = None) -> Self:
557
+ ...
558
+
559
+ @overload
560
+ def __get__(self, __obj: object, __type: type | None = None) -> R_co:
561
+ ...
562
+
563
+ def __get__(self, __obj: Any, __type: type | None = None) -> Any:
550
564
  if isinstance(self.fget, classproperty):
551
565
  function = partial(self.fget.__get__, __obj, __type) # type: ignore
552
566
  __obj = __type
@@ -557,14 +571,19 @@ class cachedproperty(property, Generic[P, R, T, T0, P0]):
557
571
  cache = getattr(__obj, cachedproperty.cache_key)
558
572
  name = self.fget.__name__
559
573
  else:
560
- function = self.fget.__get__(__obj, __type) # type: ignore
574
+ assert self.fget
575
+ function = self.fget.__get__(__obj, __type)
561
576
  cache = __obj.__dict__.get(cachedproperty.cache_key)
562
577
  name = function.__name__
563
578
 
564
579
  if name not in cache:
565
580
  cache[name] = function()
566
581
 
567
- return cache[name] # type: ignore
582
+ return cache[name]
583
+
584
+ if TYPE_CHECKING:
585
+ def __set__(self, obj: Any, value: R_co, /) -> None: # type: ignore[misc]
586
+ ...
568
587
 
569
588
 
570
589
  class KwargsNotNone(KwargsT):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: jetpytools
3
- Version: 1.2.5
3
+ Version: 1.2.7
4
4
  Summary: Collection of stuff that's useful in general python programming
5
5
  Author: Jaded Encoding Thaumaturgy
6
6
  Author-email: jaded.encoding.thaumaturgy@gmail.com
@@ -1,33 +1,34 @@
1
1
  jetpytools/__init__.py,sha256=FSVZdj69oy4mBXd6OXiRHrUhaSc4Exo1pQHBlXycV98,214
2
- jetpytools/_metadata.py,sha256=EF2prSeiktlzSwZCzFXhHgnZPWOi41ij--oy_a9-7nk,414
2
+ jetpytools/_metadata.py,sha256=y_dN8-DDeLCacriLV91BnQjH9vA5oZyzrnDV73-0YaU,414
3
3
  jetpytools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  jetpytools/enums/__init__.py,sha256=5n6Cu8Yb9N6hIa_YTsyy_s0cCgCnh0vDb-NyXK2RwV0,81
5
- jetpytools/enums/base.py,sha256=q0HUCl8NN66b4VXYNjP_AMrYqjlcLVlRs0GQHXt17zU,2083
6
- jetpytools/enums/other.py,sha256=vQIouUJWRa039t8E1RQYc61MYS3uhe-o-5SBRlXs9x4,1416
5
+ jetpytools/enums/base.py,sha256=BbePlmj__Vqc7gzhrbZBFnrQcC9WNBjtiBYoXpgVNOA,2079
6
+ jetpytools/enums/other.py,sha256=DerFtmdjNK41ZxSYt601vHV5yzvZHPfTKNDlj-FjHm8,1346
7
7
  jetpytools/exceptions/__init__.py,sha256=g8GT0XqcNuHFHgQGSRj6a_X1kBiBQGP05soYNbEIN_Q,205
8
- jetpytools/exceptions/base.py,sha256=S3sqhT6yQSbPshmcy3XyVgfjDXic_xbpb8799TfD-cI,6342
8
+ jetpytools/exceptions/base.py,sha256=ESwC7H8iCQW9DGMGmaoFwIiid98tE1e6sATjOH_7Duc,6370
9
9
  jetpytools/exceptions/enum.py,sha256=9YoWwEfyd9k7NwanAqtXbhJaJQAnjRKqsAO73cDvcpA,223
10
10
  jetpytools/exceptions/file.py,sha256=QwhUFAoG3NsFFYuPe5O_I6K969CzlrTCv3RTrfzx8B0,1107
11
- jetpytools/exceptions/generic.py,sha256=jWCJ6ato12rJBXLmZx4ReMVWG0iMuStR5Tz9CJlVevI,1492
11
+ jetpytools/exceptions/generic.py,sha256=kMj5lR3ifHk3uNhpxN6Lu4Am0vi7E6TfQezkZulqhaQ,1482
12
12
  jetpytools/exceptions/module.py,sha256=drkcpa8hcE7Ee20N15j3qsX_grl8a3Jjv10XJ3xtDmE,1207
13
13
  jetpytools/functions/__init__.py,sha256=CeDfQrPCYqjiXyCoZ6jcbfM2d7KmRM11lBSxUK2wl4g,127
14
14
  jetpytools/functions/funcs.py,sha256=EMoJ_h2tl8Cgr1PXAsmRvgaOY5YL7AiEnGGo3-H76tk,3797
15
- jetpytools/functions/normalize.py,sha256=dyEuLVOZ2WSR_qDgyVGILn-0MURizCn5Nk1KuppgbG8,6381
15
+ jetpytools/functions/normalize.py,sha256=2BACok7TAN5ldANyYrbGhUpOkj84siApAYy6ndlhUfI,6316
16
16
  jetpytools/functions/other.py,sha256=TRz91spvdYJUh9vKe3Kuw6xZfSEJvrQs1mZVg7SyYmY,413
17
- jetpytools/types/__init__.py,sha256=0veUJC8ioXsx1g3Nx-YQSKTnkenfyaD5y91qBDkyM8Q,253
18
- jetpytools/types/builtins.py,sha256=moET0CgjQnUkis2V1RViL53OMCVAIV4zBDcClsaKn5g,1807
19
- jetpytools/types/file.py,sha256=H9EJlb6K0cC634GqoaPtUJ2WoAhtP4WwS37egS0S3Ss,6200
20
- jetpytools/types/funcs.py,sha256=epmw4EVmZph2hOso9WxE9SL5RWm9oYtHICkTGSwDyv0,3129
17
+ jetpytools/types/__init__.py,sha256=yDT-PYTTzH6DyHsQcKvOy1jrCPmUQRKrjCM3apd0kNw,294
18
+ jetpytools/types/builtins.py,sha256=Em8vybY4wCxtK-6KkeKLVP55X1N9Z8OXji3_7W3wEH8,1771
19
+ jetpytools/types/check.py,sha256=Ivf_JkVLG9OgiKXYjq-8azoROLjJvhNNqPq_KDIiOkI,971
20
+ jetpytools/types/file.py,sha256=j46SCbdhus2wtxddAGSCn6V4nJdWWwpnAfW1K3P3ewg,6205
21
+ jetpytools/types/funcs.py,sha256=9qONnDWdpqvRj7vL3W9BLwWeGyQipXQgxOaPjqpQ1M4,3119
21
22
  jetpytools/types/generic.py,sha256=sAyBwGVG5FZ-6HVpfRuczov_6zQ_Uyoi0QWnR2iMm9Q,1128
22
23
  jetpytools/types/supports.py,sha256=--VZ-iCUiv-a6K8n-H8-6hSxHjrvdYg9mCLhr_lRplo,3051
23
- jetpytools/types/utils.py,sha256=Bi-AKe40IVxK-eSMZC1y_32w3XfeeGj-o4ZmwX3WXEI,22227
24
+ jetpytools/types/utils.py,sha256=3MaUnjezgTy4VjCstD4jNRMOoZX2Q_T1G6L55su5VhU,22570
24
25
  jetpytools/utils/__init__.py,sha256=v5Bkl43-OBWlXx9OWpZoGH-QMaYNsPIi4vfuhC13ZLI,163
25
26
  jetpytools/utils/file.py,sha256=9GhMGJ5D7CpvUFnvnwPFMloYTeIX-AJ7aKYKdoJQ374,10455
26
27
  jetpytools/utils/funcs.py,sha256=ZuLz63kveBY1CLlBexEqmrQiGC67dY4gaXdNU3CeBMw,898
27
28
  jetpytools/utils/math.py,sha256=lNTriLtTXgqN82DVSXJ5KUbhsWgxXoJ5eNGIZ0-_r_c,3335
28
29
  jetpytools/utils/ranges.py,sha256=dL3WG235Pz9sk5su8A0VdwVf_oSt6obR7R_JNwLyCjQ,2572
29
- jetpytools-1.2.5.dist-info/LICENSE,sha256=l0PN-qDtXcgOB5aXP_nSUsvCK5V3o9pQCGsTzyZhKL0,1071
30
- jetpytools-1.2.5.dist-info/METADATA,sha256=YfuNYSyncP1LrQ38qZNDP_d9qy9gyyqL2IzctrhxF5M,1399
31
- jetpytools-1.2.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
32
- jetpytools-1.2.5.dist-info/top_level.txt,sha256=Iy4HjIta33ADJxN9Nyt5t5jRIfotEkZkQcOSw4eG8Cs,11
33
- jetpytools-1.2.5.dist-info/RECORD,,
30
+ jetpytools-1.2.7.dist-info/LICENSE,sha256=l0PN-qDtXcgOB5aXP_nSUsvCK5V3o9pQCGsTzyZhKL0,1071
31
+ jetpytools-1.2.7.dist-info/METADATA,sha256=FU7Mfh5s7nnARJMWSshl18-SoTcYYruA-fVy27y1p94,1399
32
+ jetpytools-1.2.7.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
33
+ jetpytools-1.2.7.dist-info/top_level.txt,sha256=Iy4HjIta33ADJxN9Nyt5t5jRIfotEkZkQcOSw4eG8Cs,11
34
+ jetpytools-1.2.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5