dycw-utilities 0.112.1__py3-none-any.whl → 0.112.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.112.1
3
+ Version: 0.112.2
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=hV5Btasavyruats4m9DGhq8YssGlUGNVeNJRvxXPIiM,60
1
+ utilities/__init__.py,sha256=YIZTcfeQmna9ccW7NIqZzcDB03vFiy0xoZl-xVKVNg4,60
2
2
  utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
3
3
  utilities/astor.py,sha256=xuDUkjq0-b6fhtwjhbnebzbqQZAjMSHR1IIS5uOodVg,777
4
4
  utilities/asyncio.py,sha256=41oQUurWMvadFK5gFnaG21hMM0Vmfn2WS6OpC0R9mas,14757
@@ -46,7 +46,7 @@ utilities/pathlib.py,sha256=31WPMXdLIyXgYOMMl_HOI2wlo66MGSE-cgeelk-Lias,1410
46
46
  utilities/period.py,sha256=RWfcNVoNlW07RNdU47g_zuLZMKbtgfK4bE6G-9tVjY8,11024
47
47
  utilities/pickle.py,sha256=Bhvd7cZl-zQKQDFjUerqGuSKlHvnW1K2QXeU5UZibtg,657
48
48
  utilities/platform.py,sha256=NU7ycTvAXAG-fdYmDXaM1m4EOml2cGiaYwaUzfzSqyU,1767
49
- utilities/polars.py,sha256=lr0l3JE2d5Rj1UbbFtagcv1z3Vw5YXjSfAwzVa9cFXw,58374
49
+ utilities/polars.py,sha256=q8a2hTX9tyPxtxUarIm2BxlnckIwF1RCpcJz03OoIoY,58458
50
50
  utilities/polars_ols.py,sha256=efhXf0gjrHUpQrvS6a7g8yJQJWf_ATKtJnqqF2inCOU,5680
51
51
  utilities/pqdm.py,sha256=foRytQybmOQ05pjt5LF7ANyzrIa--4ScDE3T2wd31a4,3118
52
52
  utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -62,7 +62,7 @@ utilities/redis.py,sha256=fAUbfOlCmxcxhh47PXQX63w0CU5iOFKfdUJ7jDn9ntM,22096
62
62
  utilities/reprlib.py,sha256=Re9bk3n-kC__9DxQmRlevqFA86pE6TtVfWjUgpbVOv0,1849
63
63
  utilities/rich.py,sha256=t50MwwVBsoOLxzmeVFSVpjno4OW6Ufum32skXbV8-Bs,1911
64
64
  utilities/scipy.py,sha256=X6ROnHwiUhAmPhM0jkfEh0-Fd9iRvwiqtCQMOLmOQF8,945
65
- utilities/sentinel.py,sha256=0X1GWWcnPxGCo7wDgVTOfhU5iKlXdvVZudlMM0iezDw,1246
65
+ utilities/sentinel.py,sha256=3jIwgpMekWgDAxPDA_hXMP2St43cPhciKN3LWiZ7kv0,1248
66
66
  utilities/shelve.py,sha256=HZsMwK4tcIfg3sh0gApx4-yjQnrY4o3V3ZRimvRhoW0,738
67
67
  utilities/slack_sdk.py,sha256=SeDNMh24IPiEBWoGMdgvrflUaFa9TGlTS03H9-NKaQw,4132
68
68
  utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
@@ -73,12 +73,12 @@ utilities/streamlit.py,sha256=U9PJBaKP1IdSykKhPZhIzSPTZsmLsnwbEPZWzNhJPKk,2955
73
73
  utilities/sys.py,sha256=h0Xr7Vj86wNalvwJVP1wj5Y0kD_VWm1vzuXZ_jw94mE,2743
74
74
  utilities/tempfile.py,sha256=VqmZJAhTJ1OaVywFzk5eqROV8iJbW9XQ_QYAV0bpdRo,1384
75
75
  utilities/tenacity.py,sha256=1PUvODiBVgeqIh7G5TRt5WWMSqjLYkEqP53itT97WQc,4914
76
- utilities/text.py,sha256=hfcBKF22fKT6s_U-ZdP-g5TjFQ0-NrIrQdvIwERWT80,10971
76
+ utilities/text.py,sha256=c65sonE-vMJtBR8-LIntXUqku7wDQC6p4z69DOSur7o,10947
77
77
  utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
78
78
  utilities/timer.py,sha256=Rkc49KSpHuC8s7vUxGO9DU55U9I6yDKnchsQqrUCVBs,4075
79
79
  utilities/traceback.py,sha256=secexUnBsecfWV4ZuqP1W4pGF3prOeO1CRyJK-8zQDU,27402
80
80
  utilities/types.py,sha256=kVY71hZkcnyYNIlYSse0mLm8yeP3OBkzhDPMME6jXxo,18126
81
- utilities/typing.py,sha256=jtc6EiGZGG0E745jo3NeLqo_HdHt7Zdaco3kCAEWIYU,11177
81
+ utilities/typing.py,sha256=i_Ajb8UAOplnhrezb2zk4JaXtUyE0nUyaPR5o9j4YNc,12869
82
82
  utilities/tzdata.py,sha256=yCf70NICwAeazN3_JcXhWvRqCy06XJNQ42j7r6gw3HY,1217
83
83
  utilities/tzlocal.py,sha256=3upDNFBvGh1l9njmLR2z2S6K6VxQSb7QizYGUbAH3JU,960
84
84
  utilities/uuid.py,sha256=jJTFxz-CWgltqNuzmythB7iEQ-Q1mCwPevUfKthZT3c,611
@@ -87,7 +87,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
87
87
  utilities/whenever.py,sha256=iLRP_-8CZtBpHKbGZGu-kjSMg1ZubJ-VSmgSy7Eudxw,17787
88
88
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
89
89
  utilities/zoneinfo.py,sha256=-Xm57PMMwDTYpxJdkiJG13wnbwK--I7XItBh5WVhD-o,1874
90
- dycw_utilities-0.112.1.dist-info/METADATA,sha256=0K3rDMRdIWtMVqAXUo7sXWuZjUFz7brciAZ2SbsYANg,13004
91
- dycw_utilities-0.112.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
92
- dycw_utilities-0.112.1.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
93
- dycw_utilities-0.112.1.dist-info/RECORD,,
90
+ dycw_utilities-0.112.2.dist-info/METADATA,sha256=QmNVwMJdLQtljfZmV0Mg0zLgFYogVdVymaaF1QuOxrc,13004
91
+ dycw_utilities-0.112.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
92
+ dycw_utilities-0.112.2.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
93
+ dycw_utilities-0.112.2.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.112.1"
3
+ __version__ = "0.112.2"
utilities/polars.py CHANGED
@@ -941,10 +941,9 @@ def dataclass_to_schema(
941
941
  dtype = struct_dtype(**dtypes)
942
942
  elif field.type_ is dt.datetime:
943
943
  dtype = _dataclass_to_schema_datetime(field)
944
- elif is_union_type(field.type_) and set(get_args(field.type_)) == {
945
- dt.date,
946
- dt.datetime,
947
- }:
944
+ elif is_union_type(field.type_) and set(
945
+ get_args(field.type_, optional_drop_none=True)
946
+ ) == {dt.date, dt.datetime}:
948
947
  if is_instance_gen(field.value, dt.date):
949
948
  dtype = Date
950
949
  else:
@@ -1002,7 +1001,7 @@ def _dataclass_to_schema_one(
1002
1001
  if is_literal_type(obj):
1003
1002
  return pl.Enum(get_args(obj))
1004
1003
  if is_optional_type(obj):
1005
- inner_type = one(get_args(obj))
1004
+ inner_type = one(get_args(obj, optional_drop_none=True))
1006
1005
  return _dataclass_to_schema_one(inner_type, globalns=globalns, localns=localns)
1007
1006
  msg = f"{obj=}"
1008
1007
  raise NotImplementedError(msg)
@@ -1732,7 +1731,9 @@ def _struct_from_dataclass_one(
1732
1731
  ):
1733
1732
  return String
1734
1733
  if is_optional_type(ann):
1735
- return _struct_from_dataclass_one(one(get_args(ann)), time_zone=time_zone)
1734
+ return _struct_from_dataclass_one(
1735
+ one(get_args(ann, optional_drop_none=True)), time_zone=time_zone
1736
+ )
1736
1737
  if is_frozenset_type(ann) or is_list_type(ann) or is_set_type(ann):
1737
1738
  return List(_struct_from_dataclass_one(one(get_args(ann)), time_zone=time_zone))
1738
1739
  raise _StructFromDataClassTypeError(ann=ann)
utilities/sentinel.py CHANGED
@@ -40,7 +40,7 @@ sentinel = Sentinel()
40
40
 
41
41
  def parse_sentinel(text: str, /) -> Sentinel:
42
42
  """Parse text into the Sentinel value."""
43
- if text == "" or search("Sentinel", text, flags=IGNORECASE):
43
+ if search("^(|sentinel|<sentinel>)$", text, flags=IGNORECASE):
44
44
  return sentinel
45
45
  raise ParseSentinelError(text=text)
46
46
 
utilities/text.py CHANGED
@@ -25,9 +25,9 @@ DEFAULT_SEPARATOR = ","
25
25
 
26
26
  def parse_bool(text: str, /) -> bool:
27
27
  """Parse text into a boolean value."""
28
- if text == "0" or search("false", text, flags=IGNORECASE):
28
+ if search(r"^(0|False)$", text, flags=IGNORECASE):
29
29
  return False
30
- if text == "1" or search("true", text, flags=IGNORECASE):
30
+ if search(r"^(1|True)$", text, flags=IGNORECASE):
31
31
  return True
32
32
  raise ParseBoolError(text=text)
33
33
 
@@ -46,7 +46,7 @@ class ParseBoolError(Exception):
46
46
 
47
47
  def parse_none(text: str, /) -> None:
48
48
  """Parse text into the None value."""
49
- if text == "" or search("None", text, flags=IGNORECASE):
49
+ if search(r"^(|None)$", text, flags=IGNORECASE):
50
50
  return
51
51
  raise ParseNoneError(text=text)
52
52
 
utilities/typing.py CHANGED
@@ -48,14 +48,14 @@ def contains_self(obj: Any, /) -> bool:
48
48
  ##
49
49
 
50
50
 
51
- def get_args(obj: Any, /) -> tuple[Any, ...]:
51
+ def get_args(obj: Any, /, *, optional_drop_none: bool = False) -> tuple[Any, ...]:
52
52
  """Get the arguments of an annotation."""
53
53
  if isinstance(obj, TypeAliasType):
54
54
  return get_args(obj.__value__)
55
- if is_optional_type(obj):
56
- args = _get_args(obj)
57
- return tuple(a for a in args if a is not NoneType)
58
- return _get_args(obj)
55
+ args = _get_args(obj)
56
+ if is_optional_type(obj) and optional_drop_none:
57
+ args = tuple(a for a in args if a is not NoneType)
58
+ return args
59
59
 
60
60
 
61
61
  ##
@@ -230,10 +230,24 @@ def is_instance_gen(
230
230
  def is_instance_gen(obj: Any, type_: Any, /) -> bool: ...
231
231
  def is_instance_gen(obj: Any, type_: Any, /) -> bool:
232
232
  """Check if an instance relationship holds, except bool<int."""
233
- return any(_is_instance_gen_one(obj, t) for t in get_type_classes(type_))
233
+ if isinstance(obj, tuple) and isinstance(type_, tuple):
234
+ return _is_instance_gen_tuple(obj, type_)
235
+ if is_literal_type(type_):
236
+ return _is_instance_gen_literal(obj, type_)
237
+ return any(_is_instance_gen_type(obj, t) for t in get_type_classes(type_))
234
238
 
235
239
 
236
- def _is_instance_gen_one(obj: Any, type_: type[_T], /) -> TypeGuard[_T]:
240
+ def _is_instance_gen_tuple(obj: tuple[Any, ...], type_: tuple[Any, ...], /) -> bool:
241
+ return (len(obj) == len(type_)) and all(
242
+ is_instance_gen(o, t) for o, t in zip(obj, type_, strict=True)
243
+ )
244
+
245
+
246
+ def _is_instance_gen_literal(obj: Any, type_: type[_T], /) -> TypeGuard[_T]:
247
+ return obj in get_args(type_)
248
+
249
+
250
+ def _is_instance_gen_type(obj: Any, type_: type[_T], /) -> TypeGuard[_T]:
237
251
  return (
238
252
  isinstance(obj, type_)
239
253
  and not (
@@ -350,13 +364,23 @@ def is_subclass_gen(
350
364
  /,
351
365
  ) -> TypeGuard[type[_T1 | _T2 | _T3 | _T4 | _T5]]: ...
352
366
  @overload
353
- def is_subclass_gen(cls: type[Any], parent: Any, /) -> bool: ...
354
- def is_subclass_gen(cls: type[Any], parent: Any, /) -> bool:
367
+ def is_subclass_gen(cls: Any, parent: Any, /) -> bool: ...
368
+ def is_subclass_gen(cls: Any, parent: Any, /) -> bool:
355
369
  """Generalized `issubclass`."""
356
- return any(_is_subclass_gen_one(cls, p) for p in get_type_classes(parent))
370
+ if isinstance(cls, tuple) and isinstance(parent, tuple):
371
+ return _is_subclass_gen_tuple(cls, parent)
372
+ if is_literal_type(cls) and is_literal_type(parent):
373
+ return _is_subclass_gen_literal(cls, parent)
374
+ if is_literal_type(cls) is not is_literal_type(parent):
375
+ return False
376
+ if is_union_type(cls):
377
+ return _is_subclass_gen_union(cls, parent)
378
+ if isinstance(cls, type):
379
+ return any(_is_subclass_gen_type(cls, p) for p in get_type_classes(parent))
380
+ raise IsSubclassGenError(cls=cls)
357
381
 
358
382
 
359
- def _is_subclass_gen_one(cls: type[Any], parent: type[_T], /) -> TypeGuard[type[_T]]:
383
+ def _is_subclass_gen_type(cls: type[Any], parent: type[_T], /) -> TypeGuard[type[_T]]:
360
384
  return (
361
385
  issubclass(cls, parent)
362
386
  and not (
@@ -372,6 +396,29 @@ def _is_subclass_gen_one(cls: type[Any], parent: type[_T], /) -> TypeGuard[type[
372
396
  )
373
397
 
374
398
 
399
+ def _is_subclass_gen_tuple(cls: tuple[Any, ...], parent: tuple[Any, ...], /) -> bool:
400
+ return (len(cls) == len(parent)) and all(
401
+ is_subclass_gen(c, p) for c, p in zip(cls, parent, strict=True)
402
+ )
403
+
404
+
405
+ def _is_subclass_gen_literal(cls: Any, parent: Any, /) -> bool:
406
+ return set(get_args(cls)).issubset(get_args(parent))
407
+
408
+
409
+ def _is_subclass_gen_union(cls: Any, parent: Any, /) -> bool:
410
+ return all(is_subclass_gen(a, parent) for a in get_args(cls))
411
+
412
+
413
+ @dataclass(kw_only=True, slots=True)
414
+ class IsSubclassGenError(Exception):
415
+ cls: Any
416
+
417
+ @override
418
+ def __str__(self) -> str:
419
+ return f"Argument must be a class; got {self.cls!r}"
420
+
421
+
375
422
  ##
376
423
 
377
424
 
@@ -402,6 +449,7 @@ def _is_annotation_of_type(obj: Any, origin: Any, /) -> bool:
402
449
  __all__ = [
403
450
  "GetTypeClassesError",
404
451
  "GetUnionTypeClassesError",
452
+ "IsSubclassGenError",
405
453
  "contains_self",
406
454
  "get_literal_elements",
407
455
  "get_type_classes",