dycw-utilities 0.129.10__py3-none-any.whl → 0.175.17__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.
Files changed (103) hide show
  1. dycw_utilities-0.175.17.dist-info/METADATA +34 -0
  2. dycw_utilities-0.175.17.dist-info/RECORD +103 -0
  3. dycw_utilities-0.175.17.dist-info/WHEEL +4 -0
  4. dycw_utilities-0.175.17.dist-info/entry_points.txt +4 -0
  5. utilities/__init__.py +1 -1
  6. utilities/altair.py +14 -14
  7. utilities/asyncio.py +350 -819
  8. utilities/atomicwrites.py +18 -6
  9. utilities/atools.py +77 -22
  10. utilities/cachetools.py +24 -29
  11. utilities/click.py +393 -237
  12. utilities/concurrent.py +8 -11
  13. utilities/contextlib.py +216 -17
  14. utilities/contextvars.py +20 -1
  15. utilities/cryptography.py +3 -3
  16. utilities/dataclasses.py +83 -118
  17. utilities/docker.py +293 -0
  18. utilities/enum.py +26 -23
  19. utilities/errors.py +17 -3
  20. utilities/fastapi.py +29 -65
  21. utilities/fpdf2.py +3 -3
  22. utilities/functions.py +169 -416
  23. utilities/functools.py +18 -19
  24. utilities/git.py +9 -30
  25. utilities/grp.py +28 -0
  26. utilities/gzip.py +31 -0
  27. utilities/http.py +3 -2
  28. utilities/hypothesis.py +738 -589
  29. utilities/importlib.py +17 -1
  30. utilities/inflect.py +25 -0
  31. utilities/iterables.py +194 -262
  32. utilities/jinja2.py +148 -0
  33. utilities/json.py +70 -0
  34. utilities/libcst.py +38 -17
  35. utilities/lightweight_charts.py +5 -9
  36. utilities/logging.py +345 -543
  37. utilities/math.py +18 -13
  38. utilities/memory_profiler.py +11 -15
  39. utilities/more_itertools.py +200 -131
  40. utilities/operator.py +33 -29
  41. utilities/optuna.py +6 -6
  42. utilities/orjson.py +272 -137
  43. utilities/os.py +61 -4
  44. utilities/parse.py +59 -61
  45. utilities/pathlib.py +281 -40
  46. utilities/permissions.py +298 -0
  47. utilities/pickle.py +2 -2
  48. utilities/platform.py +24 -5
  49. utilities/polars.py +1214 -430
  50. utilities/polars_ols.py +1 -1
  51. utilities/postgres.py +408 -0
  52. utilities/pottery.py +113 -26
  53. utilities/pqdm.py +10 -11
  54. utilities/psutil.py +6 -57
  55. utilities/pwd.py +28 -0
  56. utilities/pydantic.py +4 -54
  57. utilities/pydantic_settings.py +240 -0
  58. utilities/pydantic_settings_sops.py +76 -0
  59. utilities/pyinstrument.py +8 -10
  60. utilities/pytest.py +227 -121
  61. utilities/pytest_plugins/__init__.py +1 -0
  62. utilities/pytest_plugins/pytest_randomly.py +23 -0
  63. utilities/pytest_plugins/pytest_regressions.py +56 -0
  64. utilities/pytest_regressions.py +26 -46
  65. utilities/random.py +13 -9
  66. utilities/re.py +58 -28
  67. utilities/redis.py +401 -550
  68. utilities/scipy.py +1 -1
  69. utilities/sentinel.py +10 -0
  70. utilities/shelve.py +4 -1
  71. utilities/shutil.py +25 -0
  72. utilities/slack_sdk.py +36 -106
  73. utilities/sqlalchemy.py +502 -473
  74. utilities/sqlalchemy_polars.py +38 -94
  75. utilities/string.py +2 -3
  76. utilities/subprocess.py +1572 -0
  77. utilities/tempfile.py +86 -4
  78. utilities/testbook.py +50 -0
  79. utilities/text.py +165 -42
  80. utilities/timer.py +37 -65
  81. utilities/traceback.py +158 -929
  82. utilities/types.py +146 -116
  83. utilities/typing.py +531 -71
  84. utilities/tzdata.py +1 -53
  85. utilities/tzlocal.py +6 -23
  86. utilities/uuid.py +43 -5
  87. utilities/version.py +27 -26
  88. utilities/whenever.py +1776 -386
  89. utilities/zoneinfo.py +84 -22
  90. dycw_utilities-0.129.10.dist-info/METADATA +0 -241
  91. dycw_utilities-0.129.10.dist-info/RECORD +0 -96
  92. dycw_utilities-0.129.10.dist-info/WHEEL +0 -4
  93. dycw_utilities-0.129.10.dist-info/licenses/LICENSE +0 -21
  94. utilities/datetime.py +0 -1409
  95. utilities/eventkit.py +0 -402
  96. utilities/loguru.py +0 -144
  97. utilities/luigi.py +0 -228
  98. utilities/period.py +0 -324
  99. utilities/pyrsistent.py +0 -89
  100. utilities/python_dotenv.py +0 -105
  101. utilities/streamlit.py +0 -105
  102. utilities/sys.py +0 -87
  103. utilities/tenacity.py +0 -145
utilities/dataclasses.py CHANGED
@@ -3,23 +3,10 @@ from __future__ import annotations
3
3
  from collections.abc import Mapping
4
4
  from contextlib import suppress
5
5
  from dataclasses import MISSING, dataclass, field, fields, replace
6
- from typing import (
7
- TYPE_CHECKING,
8
- Any,
9
- Generic,
10
- Literal,
11
- TypeVar,
12
- assert_never,
13
- overload,
14
- override,
15
- )
6
+ from typing import TYPE_CHECKING, Any, Literal, assert_never, overload, override
16
7
 
17
8
  from utilities.errors import ImpossibleCaseError
18
- from utilities.functions import (
19
- get_class_name,
20
- is_dataclass_class,
21
- is_dataclass_instance,
22
- )
9
+ from utilities.functions import get_class_name
23
10
  from utilities.iterables import (
24
11
  OneStrEmptyError,
25
12
  OneStrNonUniqueError,
@@ -34,7 +21,7 @@ from utilities.parse import (
34
21
  serialize_object,
35
22
  )
36
23
  from utilities.re import ExtractGroupError, extract_group
37
- from utilities.sentinel import Sentinel, sentinel
24
+ from utilities.sentinel import Sentinel, is_sentinel, sentinel
38
25
  from utilities.text import (
39
26
  BRACKETS,
40
27
  LIST_SEPARATOR,
@@ -43,30 +30,23 @@ from utilities.text import (
43
30
  _SplitKeyValuePairsSplitError,
44
31
  split_key_value_pairs,
45
32
  )
46
- from utilities.types import (
47
- ParseObjectExtra,
48
- SerializeObjectExtra,
49
- StrStrMapping,
50
- TDataclass,
51
- TSupportsLT,
52
- )
53
- from utilities.typing import get_type_hints
33
+ from utilities.types import MaybeType, SupportsLT
34
+ from utilities.typing import get_type_hints, is_dataclass_class, is_dataclass_instance
54
35
 
55
36
  if TYPE_CHECKING:
56
37
  from collections.abc import Callable, Iterable, Iterator
57
38
  from collections.abc import Set as AbstractSet
58
39
 
59
- from utilities.types import Dataclass, StrMapping
60
-
61
-
62
- _T = TypeVar("_T")
63
- _U = TypeVar("_U")
64
-
65
-
66
- ##
40
+ from utilities.types import (
41
+ Dataclass,
42
+ ParseObjectExtra,
43
+ SerializeObjectExtra,
44
+ StrMapping,
45
+ StrStrMapping,
46
+ )
67
47
 
68
48
 
69
- def dataclass_repr(
49
+ def dataclass_repr[T](
70
50
  obj: Dataclass,
71
51
  /,
72
52
  *,
@@ -77,7 +57,7 @@ def dataclass_repr(
77
57
  exclude: Iterable[str] | None = None,
78
58
  rel_tol: float | None = None,
79
59
  abs_tol: float | None = None,
80
- extra: Mapping[type[_T], Callable[[_T, _T], bool]] | None = None,
60
+ extra: Mapping[type[T], Callable[[T, T], bool]] | None = None,
81
61
  defaults: bool = False,
82
62
  recursive: bool = False,
83
63
  ) -> str:
@@ -145,7 +125,7 @@ def dataclass_repr(
145
125
  ##
146
126
 
147
127
 
148
- def dataclass_to_dict(
128
+ def dataclass_to_dict[T](
149
129
  obj: Dataclass,
150
130
  /,
151
131
  *,
@@ -156,7 +136,7 @@ def dataclass_to_dict(
156
136
  exclude: Iterable[str] | None = None,
157
137
  rel_tol: float | None = None,
158
138
  abs_tol: float | None = None,
159
- extra: Mapping[type[_T], Callable[[_T, _T], bool]] | None = None,
139
+ extra: Mapping[type[T], Callable[[T, T], bool]] | None = None,
160
140
  defaults: bool = False,
161
141
  final: Callable[[type[Dataclass], StrMapping], StrMapping] | None = None,
162
142
  recursive: bool = False,
@@ -221,7 +201,7 @@ def dataclass_to_dict(
221
201
  ##
222
202
 
223
203
 
224
- def is_nullable_lt(x: TSupportsLT | None, y: TSupportsLT | None, /) -> bool | None:
204
+ def is_nullable_lt[T: SupportsLT](x: T | None, y: T | None, /) -> bool | None:
225
205
  """Compare two nullable fields."""
226
206
  match cmp_nullable(x, y):
227
207
  case 1:
@@ -230,15 +210,15 @@ def is_nullable_lt(x: TSupportsLT | None, y: TSupportsLT | None, /) -> bool | No
230
210
  return True
231
211
  case 0:
232
212
  return None
233
- case _ as never:
213
+ case never:
234
214
  assert_never(never)
235
215
 
236
216
 
237
217
  ##
238
218
 
239
219
 
240
- def mapping_to_dataclass(
241
- cls: type[TDataclass],
220
+ def mapping_to_dataclass[T: Dataclass](
221
+ cls: type[T],
242
222
  mapping: StrMapping,
243
223
  /,
244
224
  *,
@@ -249,7 +229,7 @@ def mapping_to_dataclass(
249
229
  head: bool = False,
250
230
  case_sensitive: bool = False,
251
231
  allow_extra: bool = False,
252
- ) -> TDataclass:
232
+ ) -> T:
253
233
  """Construct a dataclass from a mapping."""
254
234
  if fields is None:
255
235
  fields_use = list(
@@ -291,8 +271,7 @@ def mapping_to_dataclass(
291
271
  default = {
292
272
  f.name
293
273
  for f in fields_use
294
- if (not isinstance(f.default, Sentinel))
295
- or (not isinstance(f.default_factory, Sentinel))
274
+ if (not is_sentinel(f.default)) or (not is_sentinel(f.default_factory))
296
275
  }
297
276
  have = set(field_names_to_values) | default
298
277
  missing = {f.name for f in fields_use} - have
@@ -302,12 +281,12 @@ def mapping_to_dataclass(
302
281
 
303
282
 
304
283
  @dataclass(kw_only=True, slots=True)
305
- class MappingToDataclassError(Exception, Generic[TDataclass]):
306
- cls: type[TDataclass]
284
+ class MappingToDataclassError[T: Dataclass](Exception):
285
+ cls: type[T]
307
286
 
308
287
 
309
288
  @dataclass(kw_only=True, slots=True)
310
- class _MappingToDataClassEmptyError(MappingToDataclassError[TDataclass]):
289
+ class _MappingToDataClassEmptyError(MappingToDataclassError):
311
290
  key: str
312
291
  head: bool = False
313
292
  case_sensitive: bool = False
@@ -320,7 +299,7 @@ class _MappingToDataClassEmptyError(MappingToDataclassError[TDataclass]):
320
299
 
321
300
 
322
301
  @dataclass(kw_only=True, slots=True)
323
- class _MappingToDataClassNonUniqueError(MappingToDataclassError[TDataclass]):
302
+ class _MappingToDataClassNonUniqueError(MappingToDataclassError):
324
303
  key: str
325
304
  head: bool = False
326
305
  case_sensitive: bool = False
@@ -340,7 +319,7 @@ class _MappingToDataClassNonUniqueError(MappingToDataclassError[TDataclass]):
340
319
 
341
320
 
342
321
  @dataclass(kw_only=True, slots=True)
343
- class _MappingToDataClassMissingValuesError(MappingToDataclassError[TDataclass]):
322
+ class _MappingToDataClassMissingValuesError(MappingToDataclassError):
344
323
  fields: AbstractSet[str]
345
324
 
346
325
  @override
@@ -396,15 +375,15 @@ def one_field(
396
375
 
397
376
 
398
377
  @dataclass(kw_only=True, slots=True)
399
- class OneFieldError(Exception, Generic[TDataclass]):
400
- cls: type[TDataclass]
378
+ class OneFieldError[T: Dataclass](Exception):
379
+ cls: type[T]
401
380
  key: str
402
381
  head: bool = False
403
382
  case_sensitive: bool = False
404
383
 
405
384
 
406
385
  @dataclass(kw_only=True, slots=True)
407
- class _OneFieldEmptyError(OneFieldError[TDataclass]):
386
+ class _OneFieldEmptyError(OneFieldError):
408
387
  @override
409
388
  def __str__(self) -> str:
410
389
  return _empty_error_str(
@@ -413,7 +392,7 @@ class _OneFieldEmptyError(OneFieldError[TDataclass]):
413
392
 
414
393
 
415
394
  @dataclass(kw_only=True, slots=True)
416
- class _OneFieldNonUniqueError(OneFieldError[TDataclass]):
395
+ class _OneFieldNonUniqueError(OneFieldError):
417
396
  first: str
418
397
  second: str
419
398
 
@@ -434,34 +413,32 @@ class _OneFieldNonUniqueError(OneFieldError[TDataclass]):
434
413
 
435
414
  @overload
436
415
  def replace_non_sentinel(
437
- obj: Any, /, *, in_place: Literal[True], **kwargs: Any
416
+ obj: Dataclass, /, *, in_place: Literal[True], **kwargs: Any
438
417
  ) -> None: ...
439
418
  @overload
440
- def replace_non_sentinel(
441
- obj: TDataclass, /, *, in_place: Literal[False] = False, **kwargs: Any
442
- ) -> TDataclass: ...
419
+ def replace_non_sentinel[T: Dataclass](
420
+ obj: T, /, *, in_place: Literal[False] = False, **kwargs: Any
421
+ ) -> T: ...
443
422
  @overload
444
- def replace_non_sentinel(
445
- obj: TDataclass, /, *, in_place: bool = False, **kwargs: Any
446
- ) -> TDataclass | None: ...
447
- def replace_non_sentinel(
448
- obj: TDataclass, /, *, in_place: bool = False, **kwargs: Any
449
- ) -> TDataclass | None:
423
+ def replace_non_sentinel[T: Dataclass](
424
+ obj: T, /, *, in_place: bool = False, **kwargs: Any
425
+ ) -> T | None: ...
426
+ def replace_non_sentinel[T: Dataclass](
427
+ obj: T, /, *, in_place: bool = False, **kwargs: Any
428
+ ) -> T | None:
450
429
  """Replace attributes on a dataclass, filtering out sentinel values."""
451
430
  if in_place:
452
431
  for k, v in kwargs.items():
453
- if not isinstance(v, Sentinel):
432
+ if not is_sentinel(v):
454
433
  setattr(obj, k, v)
455
434
  return None
456
- return replace(
457
- obj, **{k: v for k, v in kwargs.items() if not isinstance(v, Sentinel)}
458
- )
435
+ return replace(obj, **{k: v for k, v in kwargs.items() if not is_sentinel(v)})
459
436
 
460
437
 
461
438
  ##
462
439
 
463
440
 
464
- def serialize_dataclass(
441
+ def serialize_dataclass[T](
465
442
  obj: Dataclass,
466
443
  /,
467
444
  *,
@@ -472,7 +449,7 @@ def serialize_dataclass(
472
449
  exclude: Iterable[str] | None = None,
473
450
  rel_tol: float | None = None,
474
451
  abs_tol: float | None = None,
475
- extra_equal: Mapping[type[_U], Callable[[_U, _U], bool]] | None = None,
452
+ extra_equal: Mapping[type[T], Callable[[T, T], bool]] | None = None,
476
453
  defaults: bool = False,
477
454
  list_separator: str = LIST_SEPARATOR,
478
455
  pair_separator: str = PAIR_SEPARATOR,
@@ -508,9 +485,9 @@ def serialize_dataclass(
508
485
  )
509
486
 
510
487
 
511
- def parse_dataclass(
488
+ def parse_dataclass[T: Dataclass](
512
489
  text_or_mapping: str | StrStrMapping,
513
- cls: type[TDataclass],
490
+ cls: type[T],
514
491
  /,
515
492
  *,
516
493
  list_separator: str = LIST_SEPARATOR,
@@ -523,7 +500,7 @@ def parse_dataclass(
523
500
  case_sensitive: bool = False,
524
501
  allow_extra_keys: bool = False,
525
502
  extra_parsers: ParseObjectExtra | None = None,
526
- ) -> TDataclass:
503
+ ) -> T:
527
504
  """Construct a dataclass from a string or a mapping or strings."""
528
505
  match text_or_mapping:
529
506
  case str() as text:
@@ -536,7 +513,7 @@ def parse_dataclass(
536
513
  )
537
514
  case Mapping() as keys_to_serializes:
538
515
  ...
539
- case _ as never:
516
+ case never:
540
517
  assert_never(never)
541
518
  fields = list(
542
519
  yield_fields(
@@ -597,9 +574,9 @@ def parse_dataclass(
597
574
  raise _ParseDataClassMissingValuesError(cls=cls, fields=error.fields) from None
598
575
 
599
576
 
600
- def _parse_dataclass_split_key_value_pairs(
577
+ def _parse_dataclass_split_key_value_pairs[T: Dataclass](
601
578
  text: str,
602
- cls: type[TDataclass],
579
+ cls: type[T],
603
580
  /,
604
581
  *,
605
582
  list_separator: str = LIST_SEPARATOR,
@@ -657,12 +634,12 @@ def _parse_dataclass_parse_text(
657
634
 
658
635
 
659
636
  @dataclass(kw_only=True, slots=True)
660
- class ParseDataClassError(Exception, Generic[TDataclass]):
661
- cls: type[TDataclass]
637
+ class ParseDataClassError[T: Dataclass](Exception):
638
+ cls: type[T]
662
639
 
663
640
 
664
641
  @dataclass(kw_only=True, slots=True)
665
- class _ParseDataClassSplitKeyValuePairsSplitError(ParseDataClassError[TDataclass]):
642
+ class _ParseDataClassSplitKeyValuePairsSplitError(ParseDataClassError):
666
643
  text: str
667
644
 
668
645
  @override
@@ -671,9 +648,7 @@ class _ParseDataClassSplitKeyValuePairsSplitError(ParseDataClassError[TDataclass
671
648
 
672
649
 
673
650
  @dataclass(kw_only=True, slots=True)
674
- class _ParseDataClassSplitKeyValuePairsDuplicateKeysError(
675
- ParseDataClassError[TDataclass]
676
- ):
651
+ class _ParseDataClassSplitKeyValuePairsDuplicateKeysError(ParseDataClassError):
677
652
  counts: Mapping[str, int]
678
653
 
679
654
  @override
@@ -682,7 +657,7 @@ class _ParseDataClassSplitKeyValuePairsDuplicateKeysError(
682
657
 
683
658
 
684
659
  @dataclass(kw_only=True, slots=True)
685
- class _ParseDataClassTextParseError(ParseDataClassError[TDataclass]):
660
+ class _ParseDataClassTextParseError(ParseDataClassError):
686
661
  field: _YieldFieldsClass[Any]
687
662
  text: str
688
663
 
@@ -692,7 +667,7 @@ class _ParseDataClassTextParseError(ParseDataClassError[TDataclass]):
692
667
 
693
668
 
694
669
  @dataclass(kw_only=True, slots=True)
695
- class _ParseDataClassTextExtraNonUniqueError(ParseDataClassError[TDataclass]):
670
+ class _ParseDataClassTextExtraNonUniqueError(ParseDataClassError):
696
671
  field: _YieldFieldsClass[Any]
697
672
  first: type[Any]
698
673
  second: type[Any]
@@ -703,9 +678,7 @@ class _ParseDataClassTextExtraNonUniqueError(ParseDataClassError[TDataclass]):
703
678
 
704
679
 
705
680
  @dataclass(kw_only=True, slots=True)
706
- class _ParseDataClassStrMappingToFieldMappingEmptyError(
707
- ParseDataClassError[TDataclass]
708
- ):
681
+ class _ParseDataClassStrMappingToFieldMappingEmptyError(ParseDataClassError):
709
682
  key: str
710
683
  head: bool = False
711
684
  case_sensitive: bool = False
@@ -720,9 +693,7 @@ class _ParseDataClassStrMappingToFieldMappingEmptyError(
720
693
 
721
694
 
722
695
  @dataclass(kw_only=True, slots=True)
723
- class _ParseDataClassStrMappingToFieldMappingNonUniqueError(
724
- ParseDataClassError[TDataclass]
725
- ):
696
+ class _ParseDataClassStrMappingToFieldMappingNonUniqueError(ParseDataClassError):
726
697
  key: str
727
698
  head: bool = False
728
699
  case_sensitive: bool = False
@@ -743,7 +714,7 @@ class _ParseDataClassStrMappingToFieldMappingNonUniqueError(
743
714
 
744
715
 
745
716
  @dataclass(kw_only=True, slots=True)
746
- class _ParseDataClassMissingValuesError(ParseDataClassError[TDataclass]):
717
+ class _ParseDataClassMissingValuesError(ParseDataClassError):
747
718
  fields: AbstractSet[str]
748
719
 
749
720
  @override
@@ -755,9 +726,9 @@ class _ParseDataClassMissingValuesError(ParseDataClassError[TDataclass]):
755
726
  ##
756
727
 
757
728
 
758
- def str_mapping_to_field_mapping(
759
- cls: type[TDataclass],
760
- mapping: Mapping[str, _T],
729
+ def str_mapping_to_field_mapping[T: Dataclass, U](
730
+ cls: type[T],
731
+ mapping: Mapping[str, U],
761
732
  /,
762
733
  *,
763
734
  fields: Iterable[_YieldFieldsClass[Any]] | None = None,
@@ -767,7 +738,7 @@ def str_mapping_to_field_mapping(
767
738
  head: bool = False,
768
739
  case_sensitive: bool = False,
769
740
  allow_extra: bool = False,
770
- ) -> Mapping[_YieldFieldsClass[Any], _T]:
741
+ ) -> Mapping[_YieldFieldsClass[Any], U]:
771
742
  """Convert a string-mapping into a field-mapping."""
772
743
  keys_to_fields: Mapping[str, _YieldFieldsClass[Any]] = {}
773
744
  for key in mapping:
@@ -800,8 +771,8 @@ def str_mapping_to_field_mapping(
800
771
 
801
772
 
802
773
  @dataclass(kw_only=True, slots=True)
803
- class StrMappingToFieldMappingError(Exception, Generic[TDataclass]):
804
- cls: type[TDataclass]
774
+ class StrMappingToFieldMappingError[T: Dataclass](Exception):
775
+ cls: type[T]
805
776
  key: str
806
777
  head: bool = False
807
778
  case_sensitive: bool = False
@@ -855,7 +826,7 @@ def yield_fields(
855
826
  warn_name_errors: bool = False,
856
827
  ) -> Iterator[_YieldFieldsClass[Any]]: ...
857
828
  def yield_fields(
858
- obj: Dataclass | type[Dataclass],
829
+ obj: MaybeType[Dataclass],
859
830
  /,
860
831
  *,
861
832
  globalns: StrMapping | None = None,
@@ -913,12 +884,12 @@ def yield_fields(
913
884
 
914
885
 
915
886
  @dataclass(order=True, unsafe_hash=True, kw_only=True, slots=True)
916
- class _YieldFieldsInstance(Generic[_T]):
887
+ class _YieldFieldsInstance[T]:
917
888
  name: str
918
- value: _T = field(hash=False)
889
+ value: T = field(hash=False)
919
890
  type_: Any = field(hash=False)
920
- default: _T | Sentinel = field(default=sentinel, hash=False)
921
- default_factory: Callable[[], _T] | Sentinel = field(default=sentinel, hash=False)
891
+ default: T | Sentinel = field(default=sentinel, hash=False)
892
+ default_factory: Callable[[], T] | Sentinel = field(default=sentinel, hash=False)
922
893
  repr: bool = True
923
894
  hash_: bool | None = None
924
895
  init: bool = True
@@ -926,25 +897,19 @@ class _YieldFieldsInstance(Generic[_T]):
926
897
  metadata: StrMapping = field(default_factory=dict, hash=False)
927
898
  kw_only: bool | Sentinel = sentinel
928
899
 
929
- def equals_default(
900
+ def equals_default[U](
930
901
  self,
931
902
  *,
932
903
  rel_tol: float | None = None,
933
904
  abs_tol: float | None = None,
934
- extra: Mapping[type[_U], Callable[[_U, _U], bool]] | None = None,
905
+ extra: Mapping[type[U], Callable[[U, U], bool]] | None = None,
935
906
  ) -> bool:
936
907
  """Check if the field value equals its default."""
937
- if isinstance(self.default, Sentinel) and isinstance(
938
- self.default_factory, Sentinel
939
- ):
908
+ if is_sentinel(self.default) and is_sentinel(self.default_factory):
940
909
  return False
941
- if (not isinstance(self.default, Sentinel)) and isinstance(
942
- self.default_factory, Sentinel
943
- ):
910
+ if (not is_sentinel(self.default)) and is_sentinel(self.default_factory):
944
911
  expected = self.default
945
- elif isinstance(self.default, Sentinel) and (
946
- not isinstance(self.default_factory, Sentinel)
947
- ):
912
+ elif is_sentinel(self.default) and (not is_sentinel(self.default_factory)):
948
913
  expected = self.default_factory()
949
914
  else: # pragma: no cover
950
915
  raise ImpossibleCaseError(
@@ -954,14 +919,14 @@ class _YieldFieldsInstance(Generic[_T]):
954
919
  self.value, expected, rel_tol=rel_tol, abs_tol=abs_tol, extra=extra
955
920
  )
956
921
 
957
- def keep(
922
+ def keep[U](
958
923
  self,
959
924
  *,
960
925
  include: Iterable[str] | None = None,
961
926
  exclude: Iterable[str] | None = None,
962
927
  rel_tol: float | None = None,
963
928
  abs_tol: float | None = None,
964
- extra: Mapping[type[_U], Callable[[_U, _U], bool]] | None = None,
929
+ extra: Mapping[type[U], Callable[[U, U], bool]] | None = None,
965
930
  defaults: bool = False,
966
931
  ) -> bool:
967
932
  """Whether to include a field."""
@@ -974,11 +939,11 @@ class _YieldFieldsInstance(Generic[_T]):
974
939
 
975
940
 
976
941
  @dataclass(order=True, unsafe_hash=True, kw_only=True, slots=True)
977
- class _YieldFieldsClass(Generic[_T]):
942
+ class _YieldFieldsClass[T]:
978
943
  name: str
979
944
  type_: Any = field(hash=False)
980
- default: _T | Sentinel = field(default=sentinel, hash=False)
981
- default_factory: Callable[[], _T] | Sentinel = field(default=sentinel, hash=False)
945
+ default: T | Sentinel = field(default=sentinel, hash=False)
946
+ default_factory: Callable[[], T] | Sentinel = field(default=sentinel, hash=False)
982
947
  repr: bool = True
983
948
  hash_: bool | None = None
984
949
  init: bool = True
@@ -1024,7 +989,7 @@ def _empty_error_str_core(
1024
989
  return f"any field starting with {key!r}"
1025
990
  case True, False:
1026
991
  return f"any field starting with {key!r} (modulo case)"
1027
- case _ as never:
992
+ case never:
1028
993
  assert_never(never)
1029
994
 
1030
995
 
@@ -1065,7 +1030,7 @@ def _non_unique_error_str_core(
1065
1030
  head_msg = f"exactly one field starting with {key!r}"
1066
1031
  case True, False:
1067
1032
  head_msg = f"exactly one field starting with {key!r} (modulo case)"
1068
- case _ as never:
1033
+ case never:
1069
1034
  assert_never(never)
1070
1035
  return f"{head_msg}; got {first!r}, {second!r} and perhaps more"
1071
1036