dycw-utilities 0.166.30__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 (45) hide show
  1. dycw_utilities-0.175.17.dist-info/METADATA +34 -0
  2. {dycw_utilities-0.166.30.dist-info → dycw_utilities-0.175.17.dist-info}/RECORD +43 -38
  3. dycw_utilities-0.175.17.dist-info/WHEEL +4 -0
  4. {dycw_utilities-0.166.30.dist-info → dycw_utilities-0.175.17.dist-info}/entry_points.txt +1 -0
  5. utilities/__init__.py +1 -1
  6. utilities/altair.py +9 -4
  7. utilities/asyncio.py +10 -16
  8. utilities/cachetools.py +9 -6
  9. utilities/click.py +76 -20
  10. utilities/docker.py +293 -0
  11. utilities/functions.py +1 -1
  12. utilities/grp.py +28 -0
  13. utilities/hypothesis.py +38 -6
  14. utilities/importlib.py +17 -1
  15. utilities/jinja2.py +148 -0
  16. utilities/logging.py +7 -9
  17. utilities/orjson.py +18 -18
  18. utilities/os.py +38 -0
  19. utilities/parse.py +2 -2
  20. utilities/pathlib.py +18 -1
  21. utilities/permissions.py +298 -0
  22. utilities/platform.py +1 -1
  23. utilities/polars.py +4 -1
  24. utilities/postgres.py +28 -29
  25. utilities/pwd.py +28 -0
  26. utilities/pydantic.py +11 -0
  27. utilities/pydantic_settings.py +81 -8
  28. utilities/pydantic_settings_sops.py +13 -0
  29. utilities/pytest.py +60 -30
  30. utilities/pytest_regressions.py +26 -7
  31. utilities/shutil.py +25 -0
  32. utilities/sqlalchemy.py +15 -0
  33. utilities/subprocess.py +1572 -0
  34. utilities/tempfile.py +60 -1
  35. utilities/text.py +48 -32
  36. utilities/timer.py +2 -2
  37. utilities/traceback.py +1 -1
  38. utilities/types.py +5 -0
  39. utilities/typing.py +8 -2
  40. utilities/whenever.py +36 -5
  41. dycw_utilities-0.166.30.dist-info/METADATA +0 -41
  42. dycw_utilities-0.166.30.dist-info/WHEEL +0 -4
  43. dycw_utilities-0.166.30.dist-info/licenses/LICENSE +0 -21
  44. utilities/aeventkit.py +0 -388
  45. utilities/typed_settings.py +0 -152
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.3
2
+ Name: dycw-utilities
3
+ Version: 0.175.17
4
+ Summary: Miscellaneous Python utilities
5
+ Author: Derek Wan
6
+ Author-email: Derek Wan <d.wan@icloud.com>
7
+ Requires-Dist: atomicwrites>=1.4.1,<1.5
8
+ Requires-Dist: typing-extensions>=4.15.0,<4.16
9
+ Requires-Dist: tzlocal>=5.3.1,<5.4
10
+ Requires-Dist: whenever>=0.9.4,<0.10
11
+ Requires-Dist: coloredlogs>=15.0.1,<15.1 ; extra == 'logging'
12
+ Requires-Dist: dycw-pytest-only>=2.1.1,<2.2 ; extra == 'test'
13
+ Requires-Dist: hypothesis>=6.148.8,<6.149 ; extra == 'test'
14
+ Requires-Dist: pytest>=9.0.2,<9.1 ; extra == 'test'
15
+ Requires-Dist: pytest-asyncio>=1.3.0,<1.4 ; extra == 'test'
16
+ Requires-Dist: pytest-cov>=7.0.0,<7.1 ; extra == 'test'
17
+ Requires-Dist: pytest-instafail>=0.5.0,<0.6 ; extra == 'test'
18
+ Requires-Dist: pytest-lazy-fixtures>=1.4.0,<1.5 ; extra == 'test'
19
+ Requires-Dist: pytest-randomly>=4.0.1,<4.1 ; extra == 'test'
20
+ Requires-Dist: pytest-regressions>=2.8.3,<2.9 ; extra == 'test'
21
+ Requires-Dist: pytest-repeat>=0.9.4,<0.10 ; extra == 'test'
22
+ Requires-Dist: pytest-rerunfailures>=16.1,<16.2 ; extra == 'test'
23
+ Requires-Dist: pytest-rng>=1.0.0,<1.1 ; extra == 'test'
24
+ Requires-Dist: pytest-timeout>=2.4.0,<2.5 ; extra == 'test'
25
+ Requires-Dist: pytest-xdist>=3.8.0,<3.9 ; extra == 'test'
26
+ Requires-Dist: testbook>=0.4.2,<0.5 ; extra == 'test'
27
+ Requires-Python: >=3.12
28
+ Provides-Extra: logging
29
+ Provides-Extra: test
30
+ Description-Content-Type: text/markdown
31
+
32
+ # `python-utilities`
33
+
34
+ Miscellaneous Python utilities
@@ -1,38 +1,40 @@
1
- utilities/__init__.py,sha256=1ZO_cavh1o4bHb63EXlMpG07TU7njs0GEuTie2-NSEo,61
2
- utilities/aeventkit.py,sha256=ddoleSwW9zdc2tjX5Ge0pMKtYwV_JMxhHYOxnWX2AGM,12609
3
- utilities/altair.py,sha256=nHdpWt8ZwdUwRQN970MvHd5bRWokNqzHcZQEdSHKRuE,9033
4
- utilities/asyncio.py,sha256=60l1IwjnRGeaVphAFiwDIHyfKoZYKY-XGpptUxGiU-M,17034
1
+ utilities/__init__.py,sha256=8_tM295sqZUhpgJO-NkFFdbuntYma_XUNSt0IM3-C_0,61
2
+ utilities/altair.py,sha256=TLfRFbG9HwG7SLXoJ-v0r-t49ZaGgTQZD82cpjVi4vs,9085
3
+ utilities/asyncio.py,sha256=aJySVxBY0gqsIYnoNmH7-1r8djKuf4vSsU69VCD08t8,16772
5
4
  utilities/atomicwrites.py,sha256=tPo6r-Rypd9u99u66B9z86YBPpnLrlHtwox_8Z7T34Y,5790
6
5
  utilities/atools.py,sha256=6neeCcgXxK2dlsc0xp15Za7nSucbCgFtAJepGI_-WXU,2549
7
- utilities/cachetools.py,sha256=v1-9sXHLdOLiwmkq6NB0OUbxeKBuVVN6wmAWefWoaHI,2744
8
- utilities/click.py,sha256=RPdpxVt3cE2Ahbw0-ziMhvnsR05YSKNJxnmmjRD2zWQ,17449
6
+ utilities/cachetools.py,sha256=2S9LMHIunDYMIu8JGI7OLN04sQ7-xZGdEdP1Li0vksA,2775
7
+ utilities/click.py,sha256=ScLzBLoBp8Si5YjgB18A0IVMAR-r4sGUnVfJbAaru98,19191
9
8
  utilities/concurrent.py,sha256=fHeW2SZ_TEMfFY0C8pyQI6aPlnecvx9x6SuUwBWj_JY,2853
10
9
  utilities/contextlib.py,sha256=iP7R2tIm6ZsbfLD5ks6UKBYwj50e9gBI8AkpLN-chro,7476
11
10
  utilities/contextvars.py,sha256=J8OhC7jqozAGYOCe2KUWysbPXNGe5JYz3HfaY_mIs08,883
12
11
  utilities/cryptography.py,sha256=5PFrzsNUGHay91dFgYnDKwYprXxahrBqztmUqViRzBk,956
13
12
  utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
14
13
  utilities/dataclasses.py,sha256=xbU3QN1GFy7RC6hIJRZIeUZm7YRlodrgEWmahWG6k2g,32465
14
+ utilities/docker.py,sha256=N__PKd3cnSRsXNEMHMLdLneLdyzfbr2ESkElcwrovvQ,7940
15
15
  utilities/enum.py,sha256=5l6pwZD1cjSlVW4ss-zBPspWvrbrYrdtJWcg6f5_J5w,5781
16
16
  utilities/errors.py,sha256=mFlDGSM0LI1jZ1pbqwLAH3ttLZ2JVIxyZLojw8tGVZU,1479
17
17
  utilities/fastapi.py,sha256=TqyKvBjiMS594sXPjrz-KRTLMb3l3D3rZ1zAYV7GfOk,1454
18
18
  utilities/fpdf2.py,sha256=dSiYz0FJTD2sQuxpxqFWwwIe2-p6Y7oTB9Tv0Jajit0,1866
19
- utilities/functions.py,sha256=82qCAaPIB0JmZ5wsQurA3MTYl7fh8LHcoBFkxPs7Zeg,21478
19
+ utilities/functions.py,sha256=18Zda7nTloARdcEudH8YJ4e13xAdWShAGhPNN4w2Gyc,21498
20
20
  utilities/functools.py,sha256=I00ru2gQPakZw2SHVeKIKXfTv741655s6HI0lUoE0D4,1552
21
21
  utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
22
22
  utilities/git.py,sha256=U1RFvCTANGENgx9wVBDvllioqBQZM2ns12ivKhOsaO4,414
23
+ utilities/grp.py,sha256=1vV3gNR9dQsl1vtUtvC_2qgVdQzm7O8lLMSh56cTbeg,694
23
24
  utilities/gzip.py,sha256=fkGP3KdsBfXlstodT4wtlp-PwNyUsogpbDCVVVGdsm4,781
24
25
  utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
25
26
  utilities/http.py,sha256=TsavEfHlRtlLaeV21Z6KZh0qbPw-kvD1zsQdZ7Kep5Q,977
26
- utilities/hypothesis.py,sha256=CSCJFek07g71iSND7PCty7gyaOT_49QSbnTHn1wWidQ,45535
27
- utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
27
+ utilities/hypothesis.py,sha256=NUu30pl5kjL3tzo-m8SMRwTqLAmTWK-_Sau2NemJcQo,46773
28
+ utilities/importlib.py,sha256=SkVVtIjVC7bjJ36doXnmnmFiYe5tLbip4YAfYJj8Ycg,892
28
29
  utilities/inflect.py,sha256=v7YkOWSu8NAmVghPcf4F3YBZQoJCS47_DLf9jbfWIs0,581
29
30
  utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
30
31
  utilities/iterables.py,sha256=t2TsW-K3rVlS6y4_tqcc1fk9RwJV-bi7G_VwduMABK0,42558
32
+ utilities/jinja2.py,sha256=JpNHMcyMJDguX8rBN4wEz-v4En7w6WHXvYJr4Xw-F0o,4691
31
33
  utilities/json.py,sha256=-WcGtSsCr9Y42wHZzAMnfvU6ihAfVftylFfRUORaDFo,2102
32
34
  utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
33
35
  utilities/libcst.py,sha256=ngD4wxnR3Kh-RBVmU5l5ST7cuZLhMZwyMDjHZe5mhTs,5581
34
36
  utilities/lightweight_charts.py,sha256=YM3ojBvJxuCSUBu_KrhFBmaMCvRPvupKC3qkm-UVZq4,2751
35
- utilities/logging.py,sha256=W3d8Vby0mmqGWvTNlGtcfrmORDTt7abCuqjkIyCPIg8,18914
37
+ utilities/logging.py,sha256=mckcX_0Q5njVgnhtIoePcDHjYjTVELw7ExutiiDnzsU,18724
36
38
  utilities/math.py,sha256=cevB-YyEYAzJTWtkAr7qeeu-hbxorDI3gMznXlmNQkw,26897
37
39
  utilities/memory_profiler.py,sha256=XzN56jDCa5aqXS_DxEjb_K4L6aIWh_5zyKi6OhcIxw0,853
38
40
  utilities/modules.py,sha256=iuvLluJya-hvl1Q25-Jk3dLgx2Es3ck4SjJiEkAlVTs,3195
@@ -40,24 +42,30 @@ utilities/more_itertools.py,sha256=syfIPhQF_WS-YiicdGe2h5F1G-Ld12Q2XsVduL2hA40,1
40
42
  utilities/numpy.py,sha256=Xn23sA2ZbVNqwUYEgNJD3XBYH6IbCri_WkHSNhg3NkY,26122
41
43
  utilities/operator.py,sha256=C3NylZWGTVWRpwYHOPVhaLgRhw0DfpS4_XQ8KfPhBLQ,3613
42
44
  utilities/optuna.py,sha256=C-fhWYiXHVPo1l8QctYkFJ4DyhbSrGorzP1dJb_qvd8,1933
43
- utilities/orjson.py,sha256=rII_rINPcH9X0CfL_WeFjwHgKNkKAF-TVS5rnpLHjzc,41998
44
- utilities/os.py,sha256=MQxP4yVsV0sg8nPQyC8rctnimJdys_PvzxqDZfVzMMs,3935
45
- utilities/parse.py,sha256=JcJn5yXKhIWXBCwgBdPsyu7Hvcuw6kyEdqvaebCaI9k,17951
46
- utilities/pathlib.py,sha256=X6pHmfT3hnBGysdTr73uHsNaBEgKviZhk7aGWvEXDXo,8912
45
+ utilities/orjson.py,sha256=T_0SlK811ysg46d3orvIPY3JpBa4FRMpP2wlPQo7-gU,41854
46
+ utilities/os.py,sha256=kjKKSQfnRqFTTZ315iavaaGd3gGuYNoSWlxVLCJjyQs,4852
47
+ utilities/parse.py,sha256=g7Qm9eBOIeDId2tGA021CIaeF6jp1TI8rx4srdvlyoo,17937
48
+ utilities/pathlib.py,sha256=N4Ip8R9eCM-6GfvxUJ3T9oQIle2C2P52F-13BCFRdTg,9345
49
+ utilities/permissions.py,sha256=vLXlWztSVYffbrxptne7ksj6dU1HLekm4fEvS4ny_4Q,8944
47
50
  utilities/pickle.py,sha256=MBT2xZCsv0pH868IXLGKnlcqNx2IRVKYNpRcqiQQqxw,653
48
- utilities/platform.py,sha256=pTn7gw6N4T6LdKrf0virwarof_mze9WtoQlrGMzhGVI,2798
49
- utilities/polars.py,sha256=qsiYY9p_41fORGnc7HNkA4zhlsycK7sgD74xuigMDAc,87466
51
+ utilities/platform.py,sha256=R3ldt2-DlI7la9ng6Rxt1CThd2lL0Ai2tC0TbabtCC0,2800
52
+ utilities/polars.py,sha256=JPzN4UqQDC7R4IXsIuXEIXRiwHSrkiSZcD8UOfwGPuE,87535
50
53
  utilities/polars_ols.py,sha256=LNTFNLPuYW7fcAHymlbnams_DhitToblYvib3mhKbwI,5615
51
- utilities/postgres.py,sha256=ynCTTaF-bVEOSW-KEAR-dlLh_hYjeVVjm__-4pEU8Zk,12269
54
+ utilities/postgres.py,sha256=g3tEwTI8TdmiCbRME61ffQ0xaibdpXPu8mJOOHvjPKc,12532
52
55
  utilities/pottery.py,sha256=nA0SsF9irvfC0tk68YAr08tuL9lGRSlBKihSx7Ibk84,3963
53
56
  utilities/pqdm.py,sha256=idv2seRVP2f6NeSfpeEnT5A-tQezaHZKDyeu16g2-0E,3091
54
57
  utilities/psutil.py,sha256=KUlu4lrUw9Zg1V7ZGetpWpGb9DB8l_SSDWGbANFNCPU,2104
58
+ utilities/pwd.py,sha256=pzlLkBfSTZsCVkMrAxEmuEoNmm-6goklfAygVmOEZqs,707
55
59
  utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
- utilities/pydantic_settings.py,sha256=bFr9UDrVhdqTl7O_TPutCLdsQ5rUp--nO76-_F8z0bs,5102
57
- utilities/pydantic_settings_sops.py,sha256=m2uB9wDw1PU2CiSL7KwxulDXT0STjOZTu3Ctc2q7jc0,1943
60
+ utilities/pydantic.py,sha256=z_PnYXN_UNNLQwo_XF7cr4GDcf5wicvscD6aFYVOEvA,238
61
+ utilities/pydantic_settings.py,sha256=53tQTpHFtA6UIuzHKzauZtW_bSRwL5lQnNwTWeO4Fjw,7608
62
+ utilities/pydantic_settings_sops.py,sha256=9Ou6Cx6PiYOU49vtkKqqW1Sdp_i3WlVyg8KkUUKNliM,2310
58
63
  utilities/pyinstrument.py,sha256=hnXaL-4HE7wWBI5JKaPfYTpsrXe68YiuZKahHV0VJn8,841
59
- utilities/pytest.py,sha256=4KzMZYg5Zzfyjxrw8VlnZNYCD2S0Uee1JIFMIPyIkO8,10076
60
- utilities/pytest_regressions.py,sha256=ocjHTtfOeiGfQAKIei8pKNd61sxN9dawrJJ9gPt2wzA,4097
64
+ utilities/pytest.py,sha256=9HHwYgZQe6CRF0ekHQEFH05gmoP4Ne0V54RrtUNDfi4,10524
65
+ utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
66
+ utilities/pytest_plugins/pytest_randomly.py,sha256=B1qYVlExGOxTywq2r1SMi5o7btHLk2PNdY_b1p98dkE,409
67
+ utilities/pytest_plugins/pytest_regressions.py,sha256=mnHYBfdprz50UGVkVzV1bZERZN5CFfoF8YbokGxdFwU,1639
68
+ utilities/pytest_regressions.py,sha256=tJxW38u-zpoyjW1N4zogBx4V_07r-ibDInddcEUyXmc,4763
61
69
  utilities/random.py,sha256=hZlH4gnAtoaofWswuJYjcygejrY8db4CzP-z_adO2Mo,4165
62
70
  utilities/re.py,sha256=S4h-DLL6ScMPqjboZ_uQ1BVTJajrqV06r_81D--_HCE,4573
63
71
  utilities/redis.py,sha256=gybjqKea33Jy50n4dHTS14JdquqHaJqHF2dixQljYWQ,30172
@@ -65,34 +73,31 @@ utilities/reprlib.py,sha256=ssYTcBW-TeRh3fhCJv57sopTZHF5FrPyyUg9yp5XBlo,3953
65
73
  utilities/scipy.py,sha256=wZJM7fEgBAkLSYYvSmsg5ac-QuwAI0BGqHVetw1_Hb0,947
66
74
  utilities/sentinel.py,sha256=A_p5jX2K0Yc5XBfoYHyBLqHsEWzE1ByOdDuzzA2pZnE,1434
67
75
  utilities/shelve.py,sha256=4OzjQI6kGuUbJciqf535rwnao-_IBv66gsT6tRGiUt0,759
76
+ utilities/shutil.py,sha256=knJ7hx42FtIfGByxQZMcOSgQCDlaSony325g505ps3A,480
68
77
  utilities/slack_sdk.py,sha256=76-DYtcGiUhEvl-voMamc5OjfF7Y7nCq54Bys1arqzw,2233
69
78
  utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
70
- utilities/sqlalchemy.py,sha256=X_F4Vq3t0ftgmhYdrs1DOMrI4ls5Tw_ddcW7dmhQaPY,36407
79
+ utilities/sqlalchemy.py,sha256=HQYpd7LFxdTF5WYVWYtCJeEBI71EJm7ytvCGyAH9B-U,37163
71
80
  utilities/sqlalchemy_polars.py,sha256=JCGhB37raSR7fqeWV5dTsciRTMVzIdVT9YSqKT0piT0,13370
72
81
  utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
73
82
  utilities/string.py,sha256=shmBK87zZwzGyixuNuXCiUbqzfeZ9xlrFwz6JTaRvDk,582
74
- utilities/tempfile.py,sha256=HxB2BF28CcecDJLQ3Bx2Ej-Pb6RJc6W9ngSpB9CnP4k,2018
83
+ utilities/subprocess.py,sha256=nFPIXVzXomI_Oby8PYF9HNWrsWtcSsCtgFnj_22QYlI,43753
84
+ utilities/tempfile.py,sha256=QyvIdfV4r4YZ0NeNYsg0tCijThLKa7Z32u5Kxy6ZsGo,3619
75
85
  utilities/testbook.py,sha256=j1KmaVbrX9VrbeMgtPh5gk55myAsn3dyRUn7jGbPbRk,1294
76
- utilities/text.py,sha256=GkjXhJk1UbKEoh2VnMR6UfmunuCwCL4pa-2AmgKE2pU,13666
86
+ utilities/text.py,sha256=7SvwcSR2l_5cOrm1samGnR4C-ZI6qyFLHLzSpO1zeHQ,13958
77
87
  utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
78
- utilities/timer.py,sha256=oXfTii6ymu57niP0BDGZjFD55LEHi2a19kqZKiTgaFQ,2588
79
- utilities/traceback.py,sha256=-tgTUnryG7Bu2tOXjURIIpC4ohIVBzVAxIj6Kf3xxCM,9615
80
- utilities/typed_settings.py,sha256=bCGybctbjNDEbUBCvQFhKitRFrk9ixImpvbIpshgbtA,4644
81
- utilities/types.py,sha256=IlRrCtPdLkGYVfpe-QIg2qNUgBr8OJNN7BhTKxnhh-M,18817
82
- utilities/typing.py,sha256=QYoCIc71e_u5W-kBeiNzrD-GXxpLtMOGc9PqgZjMXeE,25274
88
+ utilities/timer.py,sha256=BGlwEVznx67scuLOUohyWJ4d5rTnwtk-IR4yLXFiNfo,2574
89
+ utilities/traceback.py,sha256=B_sc0TRUv-mGDnF-ek05nbqjmBiHr3-wvxliAqIF5hI,9608
90
+ utilities/types.py,sha256=UwxYajRnupKTCnzReaYWYqtKdpIPeSO-d97Wu4bLEq8,18878
91
+ utilities/typing.py,sha256=xuR8LxzjD-XlSftTM3TNvGVdQyV1mzpdwWdDMzWwCPE,25310
83
92
  utilities/tzdata.py,sha256=fgNVj66yUbCSI_-vrRVzSD3gtf-L_8IEJEPjP_Jel5Y,266
84
93
  utilities/tzlocal.py,sha256=KyCXEgCTjqGFx-389JdTuhMRUaT06U1RCMdWoED-qro,728
85
94
  utilities/uuid.py,sha256=nQZs6tFX4mqtc2Ku3KqjloYCqwpTKeTj8eKwQwh3FQI,1572
86
95
  utilities/version.py,sha256=ipBj5-WYY_nelp2uwFlApfWWCzTLzPwpovUi9x_OBMs,5085
87
96
  utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
88
- utilities/whenever.py,sha256=0N5JcZU9cPyIrkTN3wqdcR86PsmIKVlLI1yU1aEbIgk,59198
97
+ utilities/whenever.py,sha256=F4ek0-OBWxHYrZdmoZt76N2RnNyKY5KrEHt7rqO4AQE,60183
89
98
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
90
99
  utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
91
- utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
92
- utilities/pytest_plugins/pytest_randomly.py,sha256=B1qYVlExGOxTywq2r1SMi5o7btHLk2PNdY_b1p98dkE,409
93
- utilities/pytest_plugins/pytest_regressions.py,sha256=mnHYBfdprz50UGVkVzV1bZERZN5CFfoF8YbokGxdFwU,1639
94
- dycw_utilities-0.166.30.dist-info/METADATA,sha256=lYac7uqJTy4ACG9-MmZeajuG8tiZBsBMh5kU0irWduQ,1700
95
- dycw_utilities-0.166.30.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
96
- dycw_utilities-0.166.30.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
97
- dycw_utilities-0.166.30.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
98
- dycw_utilities-0.166.30.dist-info/RECORD,,
100
+ dycw_utilities-0.175.17.dist-info/WHEEL,sha256=RRVLqVugUmFOqBedBFAmA4bsgFcROUBiSUKlERi0Hcg,79
101
+ dycw_utilities-0.175.17.dist-info/entry_points.txt,sha256=cOGtKeJI0KXLSV7MJ8Dhc2G8jPgDcBDm53MVNJU4ycI,136
102
+ dycw_utilities-0.175.17.dist-info/METADATA,sha256=obLY4pbYFf5oCFvSPuNf1mXsv1VC5nCC7sGJtizR-AA,1443
103
+ dycw_utilities-0.175.17.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.21
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -1,3 +1,4 @@
1
1
  [pytest11]
2
2
  pytest-randomly = utilities.pytest_plugins.pytest_randomly
3
3
  pytest-regressions = utilities.pytest_plugins.pytest_regressions
4
+
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.166.30"
3
+ __version__ = "0.175.17"
utilities/altair.py CHANGED
@@ -94,7 +94,8 @@ def plot_dataframes(
94
94
  # lines
95
95
  selection = selection_point(bind="legend", fields=[var_name], nearest=False)
96
96
  lines = [
97
- chart.mark_line(interpolate=interpolate)
97
+ chart
98
+ .mark_line(interpolate=interpolate)
98
99
  .encode(
99
100
  x=x_use,
100
101
  y=Y(value_name).scale(zero=False),
@@ -124,7 +125,8 @@ def plot_dataframes(
124
125
  else:
125
126
  tooltip_format_use = Undefined
126
127
  rules = [
127
- chart.transform_pivot(var_name, value=value_name, groupby=[x_use])
128
+ chart
129
+ .transform_pivot(var_name, value=value_name, groupby=[x_use])
128
130
  .mark_rule(color="gray")
129
131
  .encode(
130
132
  x=x_use,
@@ -143,7 +145,9 @@ def plot_dataframes(
143
145
  ]
144
146
  zoom = selection_interval(bind="scales", encodings=["x"])
145
147
  chart = (
146
- vconcat(*layers).add_params(zoom).resolve_scale(color="independent", x="shared")
148
+ vconcat_charts(*layers)
149
+ .add_params(zoom)
150
+ .resolve_scale(color="independent", x="shared")
147
151
  )
148
152
  if title is not None:
149
153
  chart = chart.properties(title=title)
@@ -227,7 +231,8 @@ def plot_intraday_dataframe(
227
231
  )
228
232
 
229
233
  data4 = (
230
- data3.group_by("_date_index")
234
+ data3
235
+ .group_by("_date_index")
231
236
  .agg(
232
237
  col(f"_{datetime}_index").min().alias(f"{datetime}_index_min"),
233
238
  (col(f"_{datetime}_index").max() + 1).alias(f"{datetime}_index_max"),
utilities/asyncio.py CHANGED
@@ -513,27 +513,21 @@ class StreamCommandOutput:
513
513
 
514
514
  @property
515
515
  def return_code(self) -> int:
516
- return ensure_int(self.process.returncode) # skipif-not-windows
516
+ return ensure_int(self.process.returncode)
517
517
 
518
518
 
519
519
  async def stream_command(cmd: str, /) -> StreamCommandOutput:
520
520
  """Run a shell command asynchronously and stream its output in real time."""
521
- process = await create_subprocess_shell( # skipif-not-windows
522
- cmd, stdout=PIPE, stderr=PIPE
523
- )
524
- proc_stdout = ensure_not_none( # skipif-not-windows
525
- process.stdout, desc="process.stdout"
526
- )
527
- proc_stderr = ensure_not_none( # skipif-not-windows
528
- process.stderr, desc="process.stderr"
529
- )
530
- ret_stdout = StringIO() # skipif-not-windows
531
- ret_stderr = StringIO() # skipif-not-windows
532
- async with TaskGroup() as tg: # skipif-not-windows
521
+ process = await create_subprocess_shell(cmd, stdout=PIPE, stderr=PIPE)
522
+ proc_stdout = ensure_not_none(process.stdout, desc="process.stdout")
523
+ proc_stderr = ensure_not_none(process.stderr, desc="process.stderr")
524
+ ret_stdout = StringIO()
525
+ ret_stderr = StringIO()
526
+ async with TaskGroup() as tg:
533
527
  _ = tg.create_task(_stream_one(proc_stdout, stdout, ret_stdout))
534
528
  _ = tg.create_task(_stream_one(proc_stderr, stderr, ret_stderr))
535
- _ = await process.wait() # skipif-not-windows
536
- return StreamCommandOutput( # skipif-not-windows
529
+ _ = await process.wait()
530
+ return StreamCommandOutput(
537
531
  process=process, stdout=ret_stdout.getvalue(), stderr=ret_stderr.getvalue()
538
532
  )
539
533
 
@@ -542,7 +536,7 @@ async def _stream_one(
542
536
  input_: StreamReader, out_stream: TextIO, ret_stream: StringIO, /
543
537
  ) -> None:
544
538
  """Asynchronously read from a stream and write to the target output stream."""
545
- while True: # skipif-not-windows
539
+ while True:
546
540
  line = await input_.readline()
547
541
  if not line:
548
542
  break
utilities/cachetools.py CHANGED
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from collections.abc import Callable, Hashable, Iterable, Iterator, MutableSet
4
4
  from math import inf
5
5
  from time import monotonic
6
- from typing import TYPE_CHECKING, Any, override
6
+ from typing import TYPE_CHECKING, Any, cast, override
7
7
 
8
8
  import cachetools
9
9
  from cachetools.func import ttl_cache
@@ -100,11 +100,14 @@ def cache[F: Callable](
100
100
  typed_: bool = False,
101
101
  ) -> Callable[[F], F]:
102
102
  """Decorate a function with `max_size` and/or `ttl` settings."""
103
- return ttl_cache(
104
- maxsize=inf if max_size is None else max_size,
105
- ttl=inf if max_duration is None else max_duration.in_seconds(),
106
- timer=timer,
107
- typed=typed_,
103
+ return cast(
104
+ "F",
105
+ ttl_cache(
106
+ maxsize=max_size,
107
+ ttl=inf if max_duration is None else max_duration.in_seconds(),
108
+ timer=timer,
109
+ typed=typed_,
110
+ ),
108
111
  )
109
112
 
110
113
 
utilities/click.py CHANGED
@@ -4,6 +4,7 @@ import enum
4
4
  import ipaddress
5
5
  import pathlib
6
6
  import uuid
7
+ from enum import StrEnum
7
8
  from typing import TYPE_CHECKING, TypedDict, assert_never, override
8
9
 
9
10
  import whenever
@@ -11,8 +12,8 @@ from click import Choice, Context, Parameter, ParamType
11
12
  from click.types import IntParamType, StringParamType
12
13
 
13
14
  from utilities.enum import EnsureEnumError, ensure_enum
14
- from utilities.functions import EnsureStrError, ensure_str, get_class_name
15
- from utilities.iterables import is_iterable_not_str
15
+ from utilities.functions import EnsureStrError, ensure_str, get_class, get_class_name
16
+ from utilities.iterables import is_iterable_not_str, one_unique
16
17
  from utilities.parse import ParseObjectError, parse_object
17
18
  from utilities.text import split_str
18
19
 
@@ -37,17 +38,23 @@ if TYPE_CHECKING:
37
38
  )
38
39
 
39
40
 
40
- class _HelpOptionNames(TypedDict):
41
- help_option_names: list[str]
41
+ class _ContextSettings(TypedDict):
42
+ context_settings: _ContextSettingsInner
42
43
 
43
44
 
44
- class _ContextSettings(TypedDict):
45
- context_settings: _HelpOptionNames
45
+ class _ContextSettingsInner(TypedDict):
46
+ max_content_width: int
47
+ help_option_names: list[str]
48
+ show_default: bool
46
49
 
47
50
 
48
- CONTEXT_SETTINGS_HELP_OPTION_NAMES = _ContextSettings(
49
- context_settings=_HelpOptionNames(help_option_names=["-h", "--help"])
51
+ _MAX_CONTENT_WIDTH = 120
52
+ _CONTEXT_SETTINGS_INNER = _ContextSettingsInner(
53
+ max_content_width=_MAX_CONTENT_WIDTH,
54
+ help_option_names=["-h", "--help"],
55
+ show_default=True,
50
56
  )
57
+ CONTEXT_SETTINGS = _ContextSettings(context_settings=_CONTEXT_SETTINGS_INNER)
51
58
 
52
59
 
53
60
  # parameters
@@ -72,7 +79,7 @@ class Date(ParamType):
72
79
  return value
73
80
  case str():
74
81
  try:
75
- return whenever.Date.parse_common_iso(value)
82
+ return whenever.Date.parse_iso(value)
76
83
  except ValueError as error:
77
84
  self.fail(str(error), param, ctx)
78
85
  case never:
@@ -98,7 +105,7 @@ class DateDelta(ParamType):
98
105
  return value
99
106
  case str():
100
107
  try:
101
- return whenever.DateDelta.parse_common_iso(value)
108
+ return whenever.DateDelta.parse_iso(value)
102
109
  except ValueError as error:
103
110
  self.fail(str(error), param, ctx)
104
111
  case never:
@@ -124,7 +131,7 @@ class DateTimeDelta(ParamType):
124
131
  return value
125
132
  case str():
126
133
  try:
127
- return whenever.DateTimeDelta.parse_common_iso(value)
134
+ return whenever.DateTimeDelta.parse_iso(value)
128
135
  except ValueError as error:
129
136
  self.fail(str(error), param, ctx)
130
137
  case never:
@@ -135,10 +142,13 @@ class Enum[E: enum.Enum](ParamType):
135
142
  """An enum-valued parameter."""
136
143
 
137
144
  @override
138
- def __init__(self, enum: type[E], /, *, case_sensitive: bool = False) -> None:
145
+ def __init__(
146
+ self, enum: type[E], /, *, value: bool = False, case_sensitive: bool = False
147
+ ) -> None:
139
148
  cls = get_class_name(enum)
140
149
  self.name = f"enum[{cls}]"
141
150
  self._enum = enum
151
+ self._value = issubclass(self._enum, StrEnum) or value
142
152
  self._case_sensitive = case_sensitive
143
153
  super().__init__()
144
154
 
@@ -160,7 +170,52 @@ class Enum[E: enum.Enum](ParamType):
160
170
  @override
161
171
  def get_metavar(self, param: Parameter, ctx: Context) -> str | None:
162
172
  _ = ctx
163
- desc = ",".join(e.name for e in self._enum)
173
+ desc = ",".join(str(e.value) if self._value else e.name for e in self._enum)
174
+ return _make_metavar(param, desc)
175
+
176
+
177
+ class EnumPartial[E: enum.Enum](ParamType):
178
+ """An enum-valued parameter."""
179
+
180
+ @override
181
+ def __init__(
182
+ self,
183
+ members: Iterable[E],
184
+ /,
185
+ *,
186
+ value: bool = False,
187
+ case_sensitive: bool = False,
188
+ ) -> None:
189
+ self._members = list(members)
190
+ self._enum = one_unique(get_class(e) for e in self._members)
191
+ cls = get_class_name(self._enum)
192
+ self.name = f"enum-partial[{cls}]"
193
+ self._value = issubclass(self._enum, StrEnum) or value
194
+ self._case_sensitive = case_sensitive
195
+ super().__init__()
196
+
197
+ @override
198
+ def __repr__(self) -> str:
199
+ cls = get_class_name(self._enum)
200
+ return f"ENUMPARTIAL[{cls}]"
201
+
202
+ @override
203
+ def convert(
204
+ self, value: EnumLike[E], param: Parameter | None, ctx: Context | None
205
+ ) -> E:
206
+ """Convert a value into the `Enum` type."""
207
+ try:
208
+ enum = ensure_enum(value, self._enum, case_sensitive=self._case_sensitive)
209
+ except EnsureEnumError as error:
210
+ self.fail(str(error), param, ctx)
211
+ if enum in self._members:
212
+ return enum
213
+ return self.fail(f"{enum.value!r} is not a selected member")
214
+
215
+ @override
216
+ def get_metavar(self, param: Parameter, ctx: Context) -> str | None:
217
+ _ = ctx
218
+ desc = ",".join(str(e.value) if self._value else e.name for e in self._members)
164
219
  return _make_metavar(param, desc)
165
220
 
166
221
 
@@ -235,7 +290,7 @@ class MonthDay(ParamType):
235
290
  return value
236
291
  case str():
237
292
  try:
238
- return whenever.MonthDay.parse_common_iso(value)
293
+ return whenever.MonthDay.parse_iso(value)
239
294
  except ValueError as error:
240
295
  self.fail(str(error), param, ctx)
241
296
  case never:
@@ -284,7 +339,7 @@ class PlainDateTime(ParamType):
284
339
  return value
285
340
  case str():
286
341
  try:
287
- return whenever.PlainDateTime.parse_common_iso(value)
342
+ return whenever.PlainDateTime.parse_iso(value)
288
343
  except ValueError as error:
289
344
  self.fail(str(error), param, ctx)
290
345
  case never:
@@ -310,7 +365,7 @@ class Time(ParamType):
310
365
  return value
311
366
  case str():
312
367
  try:
313
- return whenever.Time.parse_common_iso(value)
368
+ return whenever.Time.parse_iso(value)
314
369
  except ValueError as error:
315
370
  self.fail(str(error), param, ctx)
316
371
  case never:
@@ -336,7 +391,7 @@ class TimeDelta(ParamType):
336
391
  return value
337
392
  case str():
338
393
  try:
339
- return whenever.TimeDelta.parse_common_iso(value)
394
+ return whenever.TimeDelta.parse_iso(value)
340
395
  except ValueError as error:
341
396
  self.fail(str(error), param, ctx)
342
397
  case never:
@@ -388,7 +443,7 @@ class YearMonth(ParamType):
388
443
  return value
389
444
  case str():
390
445
  try:
391
- return whenever.YearMonth.parse_common_iso(value)
446
+ return whenever.YearMonth.parse_iso(value)
392
447
  except ValueError as error:
393
448
  self.fail(str(error), param, ctx)
394
449
  case never:
@@ -414,7 +469,7 @@ class ZonedDateTime(ParamType):
414
469
  return value
415
470
  case str():
416
471
  try:
417
- return whenever.ZonedDateTime.parse_common_iso(value)
472
+ return whenever.ZonedDateTime.parse_iso(value)
418
473
  except ValueError as error:
419
474
  self.fail(str(error), param, ctx)
420
475
  case never:
@@ -600,12 +655,13 @@ def _make_metavar(param: Parameter, desc: str, /) -> str:
600
655
 
601
656
 
602
657
  __all__ = [
603
- "CONTEXT_SETTINGS_HELP_OPTION_NAMES",
658
+ "CONTEXT_SETTINGS",
604
659
  "UUID",
605
660
  "Date",
606
661
  "DateDelta",
607
662
  "DateTimeDelta",
608
663
  "Enum",
664
+ "EnumPartial",
609
665
  "FrozenSetChoices",
610
666
  "FrozenSetEnums",
611
667
  "FrozenSetParameter",