dycw-utilities 0.148.4__py3-none-any.whl → 0.174.12__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 dycw-utilities might be problematic. Click here for more details.
- dycw_utilities-0.174.12.dist-info/METADATA +41 -0
- dycw_utilities-0.174.12.dist-info/RECORD +104 -0
- dycw_utilities-0.174.12.dist-info/WHEEL +4 -0
- {dycw_utilities-0.148.4.dist-info → dycw_utilities-0.174.12.dist-info}/entry_points.txt +3 -0
- utilities/__init__.py +1 -1
- utilities/{eventkit.py → aeventkit.py} +12 -11
- utilities/altair.py +7 -6
- utilities/asyncio.py +113 -64
- utilities/atomicwrites.py +1 -1
- utilities/atools.py +64 -4
- utilities/cachetools.py +9 -6
- utilities/click.py +145 -49
- utilities/concurrent.py +1 -1
- utilities/contextlib.py +4 -2
- utilities/contextvars.py +20 -1
- utilities/cryptography.py +3 -3
- utilities/dataclasses.py +15 -28
- utilities/docker.py +292 -0
- utilities/enum.py +2 -2
- utilities/errors.py +1 -1
- utilities/fastapi.py +8 -3
- utilities/fpdf2.py +2 -2
- utilities/functions.py +20 -297
- utilities/git.py +19 -0
- utilities/grp.py +28 -0
- utilities/hypothesis.py +360 -78
- utilities/inflect.py +1 -1
- utilities/iterables.py +12 -58
- utilities/jinja2.py +148 -0
- utilities/json.py +1 -1
- utilities/libcst.py +7 -7
- utilities/logging.py +74 -85
- utilities/math.py +8 -4
- utilities/more_itertools.py +4 -6
- utilities/operator.py +1 -1
- utilities/orjson.py +86 -34
- utilities/os.py +49 -2
- utilities/parse.py +2 -2
- utilities/pathlib.py +66 -34
- utilities/permissions.py +297 -0
- utilities/platform.py +5 -5
- utilities/polars.py +932 -420
- utilities/polars_ols.py +1 -1
- utilities/postgres.py +299 -174
- utilities/pottery.py +8 -73
- utilities/pqdm.py +3 -3
- utilities/pwd.py +28 -0
- utilities/pydantic.py +11 -0
- utilities/pydantic_settings.py +240 -0
- utilities/pydantic_settings_sops.py +76 -0
- utilities/pyinstrument.py +5 -5
- utilities/pytest.py +155 -46
- utilities/pytest_plugins/pytest_randomly.py +1 -1
- utilities/pytest_plugins/pytest_regressions.py +7 -3
- utilities/pytest_regressions.py +2 -3
- utilities/random.py +11 -6
- utilities/re.py +1 -1
- utilities/redis.py +101 -64
- utilities/sentinel.py +10 -0
- utilities/shelve.py +4 -1
- utilities/shutil.py +25 -0
- utilities/slack_sdk.py +8 -3
- utilities/sqlalchemy.py +422 -352
- utilities/sqlalchemy_polars.py +28 -52
- utilities/string.py +1 -1
- utilities/subprocess.py +864 -0
- utilities/tempfile.py +62 -4
- utilities/testbook.py +50 -0
- utilities/text.py +165 -42
- utilities/timer.py +2 -2
- utilities/traceback.py +46 -36
- utilities/types.py +62 -23
- utilities/typing.py +479 -19
- utilities/uuid.py +42 -5
- utilities/version.py +27 -26
- utilities/whenever.py +661 -151
- utilities/zoneinfo.py +80 -22
- dycw_utilities-0.148.4.dist-info/METADATA +0 -41
- dycw_utilities-0.148.4.dist-info/RECORD +0 -95
- dycw_utilities-0.148.4.dist-info/WHEEL +0 -4
- dycw_utilities-0.148.4.dist-info/licenses/LICENSE +0 -21
- utilities/period.py +0 -237
- utilities/typed_settings.py +0 -144
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: dycw-utilities
|
|
3
|
+
Version: 0.174.12
|
|
4
|
+
Author: Derek Wan
|
|
5
|
+
Author-email: Derek Wan <d.wan@icloud.com>
|
|
6
|
+
Requires-Dist: atomicwrites>=1.4.1,<1.5
|
|
7
|
+
Requires-Dist: typing-extensions>=4.15.0,<4.16
|
|
8
|
+
Requires-Dist: tzlocal>=5.3.1,<5.4
|
|
9
|
+
Requires-Dist: whenever>=0.9.4,<0.10
|
|
10
|
+
Requires-Dist: coloredlogs>=15.0.1,<15.1 ; extra == 'logging'
|
|
11
|
+
Requires-Dist: dycw-pytest-only>=2.1.1,<2.2 ; extra == 'test'
|
|
12
|
+
Requires-Dist: hypothesis>=6.148.8,<6.149 ; extra == 'test'
|
|
13
|
+
Requires-Dist: pytest>=9.0.2,<9.1 ; extra == 'test'
|
|
14
|
+
Requires-Dist: pytest-asyncio>=1.3.0,<1.4 ; extra == 'test'
|
|
15
|
+
Requires-Dist: pytest-cov>=7.0.0,<7.1 ; extra == 'test'
|
|
16
|
+
Requires-Dist: pytest-instafail>=0.5.0,<0.6 ; extra == 'test'
|
|
17
|
+
Requires-Dist: pytest-lazy-fixtures>=1.4.0,<1.5 ; extra == 'test'
|
|
18
|
+
Requires-Dist: pytest-randomly>=4.0.1,<4.1 ; extra == 'test'
|
|
19
|
+
Requires-Dist: pytest-regressions>=2.8.3,<2.9 ; extra == 'test'
|
|
20
|
+
Requires-Dist: pytest-repeat>=0.9.4,<0.10 ; extra == 'test'
|
|
21
|
+
Requires-Dist: pytest-rerunfailures>=16.1,<16.2 ; extra == 'test'
|
|
22
|
+
Requires-Dist: pytest-rng>=1.0.0,<1.1 ; extra == 'test'
|
|
23
|
+
Requires-Dist: pytest-timeout>=2.4.0,<2.5 ; extra == 'test'
|
|
24
|
+
Requires-Dist: pytest-xdist>=3.8.0,<3.9 ; extra == 'test'
|
|
25
|
+
Requires-Dist: testbook>=0.4.2,<0.5 ; extra == 'test'
|
|
26
|
+
Requires-Python: >=3.12
|
|
27
|
+
Provides-Extra: logging
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
[](https://badge.fury.io/py/dycw-utilities)
|
|
32
|
+
|
|
33
|
+
# `dycw-utilities`
|
|
34
|
+
|
|
35
|
+
[All the Python functions I don't want to write twice.](https://github.com/nvim-lua/plenary.nvim)
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
- `pip install dycw-utilities`
|
|
40
|
+
|
|
41
|
+
or with [extras](https://github.com/dycw/python-utilities/blob/master/pyproject.toml).
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
utilities/__init__.py,sha256=VFU3kmpNxjyAnXuMdW-ygHCxl3CNmUA0rP-wy1y_uzg,61
|
|
2
|
+
utilities/aeventkit.py,sha256=OmDBhYGgbsKrB7cdC5FFpJHUatX9O76eTeKVVTksp2Y,12673
|
|
3
|
+
utilities/altair.py,sha256=rUK99g9x6CYDDfiZrf-aTx5fSRbL1Q8ctgKORowzXHg,9060
|
|
4
|
+
utilities/asyncio.py,sha256=aJySVxBY0gqsIYnoNmH7-1r8djKuf4vSsU69VCD08t8,16772
|
|
5
|
+
utilities/atomicwrites.py,sha256=tPo6r-Rypd9u99u66B9z86YBPpnLrlHtwox_8Z7T34Y,5790
|
|
6
|
+
utilities/atools.py,sha256=6neeCcgXxK2dlsc0xp15Za7nSucbCgFtAJepGI_-WXU,2549
|
|
7
|
+
utilities/cachetools.py,sha256=2S9LMHIunDYMIu8JGI7OLN04sQ7-xZGdEdP1Li0vksA,2775
|
|
8
|
+
utilities/click.py,sha256=-_B7V5arQopuVJA6emnwBlZGQvcnq7nq6IYc3cPX5FA,19204
|
|
9
|
+
utilities/concurrent.py,sha256=fHeW2SZ_TEMfFY0C8pyQI6aPlnecvx9x6SuUwBWj_JY,2853
|
|
10
|
+
utilities/contextlib.py,sha256=iP7R2tIm6ZsbfLD5ks6UKBYwj50e9gBI8AkpLN-chro,7476
|
|
11
|
+
utilities/contextvars.py,sha256=J8OhC7jqozAGYOCe2KUWysbPXNGe5JYz3HfaY_mIs08,883
|
|
12
|
+
utilities/cryptography.py,sha256=5PFrzsNUGHay91dFgYnDKwYprXxahrBqztmUqViRzBk,956
|
|
13
|
+
utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
|
|
14
|
+
utilities/dataclasses.py,sha256=xbU3QN1GFy7RC6hIJRZIeUZm7YRlodrgEWmahWG6k2g,32465
|
|
15
|
+
utilities/docker.py,sha256=DBgSz-UPBDHk_XJLPNaNMkNym1kKK8l3Os8IqMwEyW8,7866
|
|
16
|
+
utilities/enum.py,sha256=5l6pwZD1cjSlVW4ss-zBPspWvrbrYrdtJWcg6f5_J5w,5781
|
|
17
|
+
utilities/errors.py,sha256=mFlDGSM0LI1jZ1pbqwLAH3ttLZ2JVIxyZLojw8tGVZU,1479
|
|
18
|
+
utilities/fastapi.py,sha256=TqyKvBjiMS594sXPjrz-KRTLMb3l3D3rZ1zAYV7GfOk,1454
|
|
19
|
+
utilities/fpdf2.py,sha256=dSiYz0FJTD2sQuxpxqFWwwIe2-p6Y7oTB9Tv0Jajit0,1866
|
|
20
|
+
utilities/functions.py,sha256=82qCAaPIB0JmZ5wsQurA3MTYl7fh8LHcoBFkxPs7Zeg,21478
|
|
21
|
+
utilities/functools.py,sha256=I00ru2gQPakZw2SHVeKIKXfTv741655s6HI0lUoE0D4,1552
|
|
22
|
+
utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
|
|
23
|
+
utilities/git.py,sha256=U1RFvCTANGENgx9wVBDvllioqBQZM2ns12ivKhOsaO4,414
|
|
24
|
+
utilities/grp.py,sha256=1vV3gNR9dQsl1vtUtvC_2qgVdQzm7O8lLMSh56cTbeg,694
|
|
25
|
+
utilities/gzip.py,sha256=fkGP3KdsBfXlstodT4wtlp-PwNyUsogpbDCVVVGdsm4,781
|
|
26
|
+
utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
|
|
27
|
+
utilities/http.py,sha256=TsavEfHlRtlLaeV21Z6KZh0qbPw-kvD1zsQdZ7Kep5Q,977
|
|
28
|
+
utilities/hypothesis.py,sha256=wk1HiNdBg7tGPEKLZ5uiNVbtlSZl58QJjlediYoSHkA,46753
|
|
29
|
+
utilities/importlib.py,sha256=mV1xT_O_zt_GnZZ36tl3xOmMaN_3jErDWY54fX39F6Y,429
|
|
30
|
+
utilities/inflect.py,sha256=v7YkOWSu8NAmVghPcf4F3YBZQoJCS47_DLf9jbfWIs0,581
|
|
31
|
+
utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
|
|
32
|
+
utilities/iterables.py,sha256=t2TsW-K3rVlS6y4_tqcc1fk9RwJV-bi7G_VwduMABK0,42558
|
|
33
|
+
utilities/jinja2.py,sha256=JpNHMcyMJDguX8rBN4wEz-v4En7w6WHXvYJr4Xw-F0o,4691
|
|
34
|
+
utilities/json.py,sha256=-WcGtSsCr9Y42wHZzAMnfvU6ihAfVftylFfRUORaDFo,2102
|
|
35
|
+
utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
|
|
36
|
+
utilities/libcst.py,sha256=ngD4wxnR3Kh-RBVmU5l5ST7cuZLhMZwyMDjHZe5mhTs,5581
|
|
37
|
+
utilities/lightweight_charts.py,sha256=YM3ojBvJxuCSUBu_KrhFBmaMCvRPvupKC3qkm-UVZq4,2751
|
|
38
|
+
utilities/logging.py,sha256=mckcX_0Q5njVgnhtIoePcDHjYjTVELw7ExutiiDnzsU,18724
|
|
39
|
+
utilities/math.py,sha256=cevB-YyEYAzJTWtkAr7qeeu-hbxorDI3gMznXlmNQkw,26897
|
|
40
|
+
utilities/memory_profiler.py,sha256=XzN56jDCa5aqXS_DxEjb_K4L6aIWh_5zyKi6OhcIxw0,853
|
|
41
|
+
utilities/modules.py,sha256=iuvLluJya-hvl1Q25-Jk3dLgx2Es3ck4SjJiEkAlVTs,3195
|
|
42
|
+
utilities/more_itertools.py,sha256=syfIPhQF_WS-YiicdGe2h5F1G-Ld12Q2XsVduL2hA40,10908
|
|
43
|
+
utilities/numpy.py,sha256=Xn23sA2ZbVNqwUYEgNJD3XBYH6IbCri_WkHSNhg3NkY,26122
|
|
44
|
+
utilities/operator.py,sha256=C3NylZWGTVWRpwYHOPVhaLgRhw0DfpS4_XQ8KfPhBLQ,3613
|
|
45
|
+
utilities/optuna.py,sha256=C-fhWYiXHVPo1l8QctYkFJ4DyhbSrGorzP1dJb_qvd8,1933
|
|
46
|
+
utilities/orjson.py,sha256=T_0SlK811ysg46d3orvIPY3JpBa4FRMpP2wlPQo7-gU,41854
|
|
47
|
+
utilities/os.py,sha256=kjKKSQfnRqFTTZ315iavaaGd3gGuYNoSWlxVLCJjyQs,4852
|
|
48
|
+
utilities/parse.py,sha256=g7Qm9eBOIeDId2tGA021CIaeF6jp1TI8rx4srdvlyoo,17937
|
|
49
|
+
utilities/pathlib.py,sha256=EKZn-wWxH7MEWFrQGqHIoB-GJzyXeiEj8iDIgvkr8Wk,9325
|
|
50
|
+
utilities/permissions.py,sha256=u-1PMJGC8PDbZltR4SozBuKKX5yIubmXPuiKrBx3IKU,8943
|
|
51
|
+
utilities/pickle.py,sha256=MBT2xZCsv0pH868IXLGKnlcqNx2IRVKYNpRcqiQQqxw,653
|
|
52
|
+
utilities/platform.py,sha256=0pYO5v7L2sU5UN87zHhEEhTKsZ9NIEM8N6UCr0F7bLY,2778
|
|
53
|
+
utilities/polars.py,sha256=cNFBLWgOMUAp_Sz4xtlto17uZswZRrcfQYC95QKyaY4,87483
|
|
54
|
+
utilities/polars_ols.py,sha256=LNTFNLPuYW7fcAHymlbnams_DhitToblYvib3mhKbwI,5615
|
|
55
|
+
utilities/postgres.py,sha256=g3tEwTI8TdmiCbRME61ffQ0xaibdpXPu8mJOOHvjPKc,12532
|
|
56
|
+
utilities/pottery.py,sha256=nA0SsF9irvfC0tk68YAr08tuL9lGRSlBKihSx7Ibk84,3963
|
|
57
|
+
utilities/pqdm.py,sha256=idv2seRVP2f6NeSfpeEnT5A-tQezaHZKDyeu16g2-0E,3091
|
|
58
|
+
utilities/psutil.py,sha256=KUlu4lrUw9Zg1V7ZGetpWpGb9DB8l_SSDWGbANFNCPU,2104
|
|
59
|
+
utilities/pwd.py,sha256=pzlLkBfSTZsCVkMrAxEmuEoNmm-6goklfAygVmOEZqs,707
|
|
60
|
+
utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
61
|
+
utilities/pydantic.py,sha256=z_PnYXN_UNNLQwo_XF7cr4GDcf5wicvscD6aFYVOEvA,238
|
|
62
|
+
utilities/pydantic_settings.py,sha256=53tQTpHFtA6UIuzHKzauZtW_bSRwL5lQnNwTWeO4Fjw,7608
|
|
63
|
+
utilities/pydantic_settings_sops.py,sha256=9Ou6Cx6PiYOU49vtkKqqW1Sdp_i3WlVyg8KkUUKNliM,2310
|
|
64
|
+
utilities/pyinstrument.py,sha256=hnXaL-4HE7wWBI5JKaPfYTpsrXe68YiuZKahHV0VJn8,841
|
|
65
|
+
utilities/pytest.py,sha256=9HHwYgZQe6CRF0ekHQEFH05gmoP4Ne0V54RrtUNDfi4,10524
|
|
66
|
+
utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
67
|
+
utilities/pytest_plugins/pytest_randomly.py,sha256=B1qYVlExGOxTywq2r1SMi5o7btHLk2PNdY_b1p98dkE,409
|
|
68
|
+
utilities/pytest_plugins/pytest_regressions.py,sha256=mnHYBfdprz50UGVkVzV1bZERZN5CFfoF8YbokGxdFwU,1639
|
|
69
|
+
utilities/pytest_regressions.py,sha256=nKdVZAa88_aMo1a8V-EIHg_smZYdk1iDQBm50R3FlO4,4044
|
|
70
|
+
utilities/random.py,sha256=hZlH4gnAtoaofWswuJYjcygejrY8db4CzP-z_adO2Mo,4165
|
|
71
|
+
utilities/re.py,sha256=S4h-DLL6ScMPqjboZ_uQ1BVTJajrqV06r_81D--_HCE,4573
|
|
72
|
+
utilities/redis.py,sha256=gybjqKea33Jy50n4dHTS14JdquqHaJqHF2dixQljYWQ,30172
|
|
73
|
+
utilities/reprlib.py,sha256=ssYTcBW-TeRh3fhCJv57sopTZHF5FrPyyUg9yp5XBlo,3953
|
|
74
|
+
utilities/scipy.py,sha256=wZJM7fEgBAkLSYYvSmsg5ac-QuwAI0BGqHVetw1_Hb0,947
|
|
75
|
+
utilities/sentinel.py,sha256=A_p5jX2K0Yc5XBfoYHyBLqHsEWzE1ByOdDuzzA2pZnE,1434
|
|
76
|
+
utilities/shelve.py,sha256=4OzjQI6kGuUbJciqf535rwnao-_IBv66gsT6tRGiUt0,759
|
|
77
|
+
utilities/shutil.py,sha256=knJ7hx42FtIfGByxQZMcOSgQCDlaSony325g505ps3A,480
|
|
78
|
+
utilities/slack_sdk.py,sha256=76-DYtcGiUhEvl-voMamc5OjfF7Y7nCq54Bys1arqzw,2233
|
|
79
|
+
utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
|
|
80
|
+
utilities/sqlalchemy.py,sha256=HQYpd7LFxdTF5WYVWYtCJeEBI71EJm7ytvCGyAH9B-U,37163
|
|
81
|
+
utilities/sqlalchemy_polars.py,sha256=JCGhB37raSR7fqeWV5dTsciRTMVzIdVT9YSqKT0piT0,13370
|
|
82
|
+
utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
|
|
83
|
+
utilities/string.py,sha256=shmBK87zZwzGyixuNuXCiUbqzfeZ9xlrFwz6JTaRvDk,582
|
|
84
|
+
utilities/subprocess.py,sha256=dIBguvLB0WepJKqgBxlzF6r8z9HW5JiGKLg-eslpuec,22549
|
|
85
|
+
utilities/tempfile.py,sha256=Lx6qa16lL1XVH6WdmD_G9vlN6gLI8nrIurxmsFkPKvg,3022
|
|
86
|
+
utilities/testbook.py,sha256=j1KmaVbrX9VrbeMgtPh5gk55myAsn3dyRUn7jGbPbRk,1294
|
|
87
|
+
utilities/text.py,sha256=7SvwcSR2l_5cOrm1samGnR4C-ZI6qyFLHLzSpO1zeHQ,13958
|
|
88
|
+
utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
|
|
89
|
+
utilities/timer.py,sha256=BGlwEVznx67scuLOUohyWJ4d5rTnwtk-IR4yLXFiNfo,2574
|
|
90
|
+
utilities/traceback.py,sha256=B_sc0TRUv-mGDnF-ek05nbqjmBiHr3-wvxliAqIF5hI,9608
|
|
91
|
+
utilities/types.py,sha256=UwxYajRnupKTCnzReaYWYqtKdpIPeSO-d97Wu4bLEq8,18878
|
|
92
|
+
utilities/typing.py,sha256=xuR8LxzjD-XlSftTM3TNvGVdQyV1mzpdwWdDMzWwCPE,25310
|
|
93
|
+
utilities/tzdata.py,sha256=fgNVj66yUbCSI_-vrRVzSD3gtf-L_8IEJEPjP_Jel5Y,266
|
|
94
|
+
utilities/tzlocal.py,sha256=KyCXEgCTjqGFx-389JdTuhMRUaT06U1RCMdWoED-qro,728
|
|
95
|
+
utilities/uuid.py,sha256=nQZs6tFX4mqtc2Ku3KqjloYCqwpTKeTj8eKwQwh3FQI,1572
|
|
96
|
+
utilities/version.py,sha256=ipBj5-WYY_nelp2uwFlApfWWCzTLzPwpovUi9x_OBMs,5085
|
|
97
|
+
utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
98
|
+
utilities/whenever.py,sha256=F4ek0-OBWxHYrZdmoZt76N2RnNyKY5KrEHt7rqO4AQE,60183
|
|
99
|
+
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
|
100
|
+
utilities/zoneinfo.py,sha256=tdIScrTB2-B-LH0ukb1HUXKooLknOfJNwHk10MuMYvA,3619
|
|
101
|
+
dycw_utilities-0.174.12.dist-info/WHEEL,sha256=ZyFSCYkV2BrxH6-HRVRg3R9Fo7MALzer9KiPYqNxSbo,79
|
|
102
|
+
dycw_utilities-0.174.12.dist-info/entry_points.txt,sha256=ykGI1ArwOPHqm2g5Cqh3ENdMxEej_a_FcOUov5EM5Oc,155
|
|
103
|
+
dycw_utilities-0.174.12.dist-info/METADATA,sha256=Cf8kQqLOY8YDH8nG9Y7WcGf6xJFGxfDIMC1Amw13isc,1710
|
|
104
|
+
dycw_utilities-0.174.12.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
|
@@ -29,12 +29,12 @@ from eventkit import (
|
|
|
29
29
|
|
|
30
30
|
from utilities.functions import apply_decorators
|
|
31
31
|
from utilities.iterables import always_iterable
|
|
32
|
-
from utilities.logging import
|
|
32
|
+
from utilities.logging import to_logger
|
|
33
33
|
|
|
34
34
|
if TYPE_CHECKING:
|
|
35
35
|
from collections.abc import Callable
|
|
36
36
|
|
|
37
|
-
from utilities.types import Coro,
|
|
37
|
+
from utilities.types import Coro, LoggerLike, MaybeCoro, MaybeIterable, TypeLike
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
##
|
|
@@ -47,7 +47,7 @@ def add_listener[E: Event, F: Callable](
|
|
|
47
47
|
*,
|
|
48
48
|
error: Callable[[Event, BaseException], MaybeCoro[None]] | None = None,
|
|
49
49
|
ignore: TypeLike[BaseException] | None = None,
|
|
50
|
-
logger:
|
|
50
|
+
logger: LoggerLike | None = None,
|
|
51
51
|
decorators: MaybeIterable[Callable[[F], F]] | None = None,
|
|
52
52
|
done: Callable[..., MaybeCoro[None]] | None = None,
|
|
53
53
|
keep_ref: bool = False,
|
|
@@ -92,7 +92,7 @@ class LiftedEvent[F: Callable[..., MaybeCoro[None]]]:
|
|
|
92
92
|
*,
|
|
93
93
|
error: Callable[[Event, BaseException], MaybeCoro[None]] | None = None,
|
|
94
94
|
ignore: TypeLike[BaseException] | None = None,
|
|
95
|
-
logger:
|
|
95
|
+
logger: LoggerLike | None = None,
|
|
96
96
|
decorators: MaybeIterable[Callable[[F2], F2]] | None = None,
|
|
97
97
|
done: Callable[..., MaybeCoro[None]] | None = None,
|
|
98
98
|
keep_ref: bool = False,
|
|
@@ -169,7 +169,8 @@ class LiftedEvent[F: Callable[..., MaybeCoro[None]]]:
|
|
|
169
169
|
def __await__(self) -> Any:
|
|
170
170
|
return self.event.__await__() # pragma: no cover
|
|
171
171
|
|
|
172
|
-
__aiter__
|
|
172
|
+
def __aiter__(self) -> Any:
|
|
173
|
+
return self.event.aiter() # pragma: no cover
|
|
173
174
|
|
|
174
175
|
def __contains__(self, c: Any, /) -> bool:
|
|
175
176
|
return self.event.__contains__(c) # pragma: no cover
|
|
@@ -255,7 +256,7 @@ class TypedEvent[F: Callable[..., MaybeCoro[None]]](Event):
|
|
|
255
256
|
keep_ref: bool = False,
|
|
256
257
|
*,
|
|
257
258
|
ignore: TypeLike[BaseException] | None = None,
|
|
258
|
-
logger:
|
|
259
|
+
logger: LoggerLike | None = None,
|
|
259
260
|
decorators: MaybeIterable[Callable[[F2], F2]] | None = None,
|
|
260
261
|
) -> Self:
|
|
261
262
|
lifted = lift_listener(
|
|
@@ -283,7 +284,7 @@ def lift_listener[F1: Callable[..., MaybeCoro[None]], F2: Callable](
|
|
|
283
284
|
*,
|
|
284
285
|
error: Callable[[Event, BaseException], MaybeCoro[None]] | None = None,
|
|
285
286
|
ignore: TypeLike[BaseException] | None = None,
|
|
286
|
-
logger:
|
|
287
|
+
logger: LoggerLike | None = None,
|
|
287
288
|
decorators: MaybeIterable[Callable[[F2], F2]] | None = None,
|
|
288
289
|
) -> F1:
|
|
289
290
|
match error, bool(iscoroutinefunction(listener)):
|
|
@@ -297,7 +298,7 @@ def lift_listener[F1: Callable[..., MaybeCoro[None]], F2: Callable](
|
|
|
297
298
|
except Exception as exc: # noqa: BLE001
|
|
298
299
|
if (ignore is not None) and isinstance(exc, ignore):
|
|
299
300
|
return
|
|
300
|
-
|
|
301
|
+
to_logger(logger).exception("")
|
|
301
302
|
|
|
302
303
|
lifted = listener_no_error_sync
|
|
303
304
|
|
|
@@ -311,7 +312,7 @@ def lift_listener[F1: Callable[..., MaybeCoro[None]], F2: Callable](
|
|
|
311
312
|
except Exception as exc: # noqa: BLE001
|
|
312
313
|
if (ignore is not None) and isinstance(exc, ignore):
|
|
313
314
|
return
|
|
314
|
-
|
|
315
|
+
to_logger(logger).exception("")
|
|
315
316
|
|
|
316
317
|
lifted = listener_no_error_async
|
|
317
318
|
case _, _:
|
|
@@ -359,9 +360,9 @@ def lift_listener[F1: Callable[..., MaybeCoro[None]], F2: Callable](
|
|
|
359
360
|
error_typed(event, exc)
|
|
360
361
|
|
|
361
362
|
lifted = listener_have_error_async
|
|
362
|
-
case
|
|
363
|
+
case never:
|
|
363
364
|
assert_never(never)
|
|
364
|
-
case
|
|
365
|
+
case never:
|
|
365
366
|
assert_never(never)
|
|
366
367
|
|
|
367
368
|
if decorators is not None:
|
utilities/altair.py
CHANGED
|
@@ -29,8 +29,6 @@ from utilities.iterables import always_iterable
|
|
|
29
29
|
from utilities.tempfile import TemporaryDirectory
|
|
30
30
|
|
|
31
31
|
if TYPE_CHECKING:
|
|
32
|
-
from collections.abc import Sequence
|
|
33
|
-
|
|
34
32
|
from polars import DataFrame
|
|
35
33
|
|
|
36
34
|
from utilities.types import PathLike
|
|
@@ -43,7 +41,7 @@ _WIDTH = 800
|
|
|
43
41
|
|
|
44
42
|
@dataclass(kw_only=True, slots=True)
|
|
45
43
|
class _PlotDataFramesSpec:
|
|
46
|
-
y:
|
|
44
|
+
y: list[str]
|
|
47
45
|
height: int = _HEIGHT
|
|
48
46
|
|
|
49
47
|
|
|
@@ -96,7 +94,8 @@ def plot_dataframes(
|
|
|
96
94
|
# lines
|
|
97
95
|
selection = selection_point(bind="legend", fields=[var_name], nearest=False)
|
|
98
96
|
lines = [
|
|
99
|
-
chart
|
|
97
|
+
chart
|
|
98
|
+
.mark_line(interpolate=interpolate)
|
|
100
99
|
.encode(
|
|
101
100
|
x=x_use,
|
|
102
101
|
y=Y(value_name).scale(zero=False),
|
|
@@ -126,7 +125,8 @@ def plot_dataframes(
|
|
|
126
125
|
else:
|
|
127
126
|
tooltip_format_use = Undefined
|
|
128
127
|
rules = [
|
|
129
|
-
chart
|
|
128
|
+
chart
|
|
129
|
+
.transform_pivot(var_name, value=value_name, groupby=[x_use])
|
|
130
130
|
.mark_rule(color="gray")
|
|
131
131
|
.encode(
|
|
132
132
|
x=x_use,
|
|
@@ -229,7 +229,8 @@ def plot_intraday_dataframe(
|
|
|
229
229
|
)
|
|
230
230
|
|
|
231
231
|
data4 = (
|
|
232
|
-
data3
|
|
232
|
+
data3
|
|
233
|
+
.group_by("_date_index")
|
|
233
234
|
.agg(
|
|
234
235
|
col(f"_{datetime}_index").min().alias(f"{datetime}_index_min"),
|
|
235
236
|
(col(f"_{datetime}_index").max() + 1).alias(f"{datetime}_index_max"),
|
utilities/asyncio.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
import sys
|
|
5
4
|
from asyncio import (
|
|
6
5
|
Lock,
|
|
7
6
|
Queue,
|
|
@@ -22,6 +21,7 @@ from contextlib import (
|
|
|
22
21
|
)
|
|
23
22
|
from dataclasses import dataclass
|
|
24
23
|
from io import StringIO
|
|
24
|
+
from pathlib import Path
|
|
25
25
|
from subprocess import PIPE
|
|
26
26
|
from sys import stderr, stdout
|
|
27
27
|
from typing import (
|
|
@@ -31,15 +31,18 @@ from typing import (
|
|
|
31
31
|
Self,
|
|
32
32
|
TextIO,
|
|
33
33
|
assert_never,
|
|
34
|
+
cast,
|
|
34
35
|
overload,
|
|
35
36
|
override,
|
|
36
37
|
)
|
|
37
38
|
|
|
38
|
-
from utilities.
|
|
39
|
-
from utilities.
|
|
40
|
-
from utilities.logging import get_logger
|
|
39
|
+
from utilities.functions import ensure_int, ensure_not_none
|
|
40
|
+
from utilities.os import is_pytest
|
|
41
41
|
from utilities.random import SYSTEM_RANDOM
|
|
42
|
+
from utilities.reprlib import get_repr
|
|
42
43
|
from utilities.sentinel import Sentinel, sentinel
|
|
44
|
+
from utilities.shelve import yield_shelf
|
|
45
|
+
from utilities.text import to_bool
|
|
43
46
|
from utilities.warnings import suppress_warnings
|
|
44
47
|
from utilities.whenever import get_now, round_date_or_date_time, to_nanoseconds
|
|
45
48
|
|
|
@@ -47,6 +50,7 @@ if TYPE_CHECKING:
|
|
|
47
50
|
from asyncio import _CoroutineLike
|
|
48
51
|
from asyncio.subprocess import Process
|
|
49
52
|
from collections.abc import (
|
|
53
|
+
AsyncIterable,
|
|
50
54
|
AsyncIterator,
|
|
51
55
|
Callable,
|
|
52
56
|
ItemsView,
|
|
@@ -58,17 +62,18 @@ if TYPE_CHECKING:
|
|
|
58
62
|
)
|
|
59
63
|
from contextvars import Context
|
|
60
64
|
from random import Random
|
|
65
|
+
from shelve import Shelf
|
|
61
66
|
from types import TracebackType
|
|
62
67
|
|
|
63
68
|
from whenever import ZonedDateTime
|
|
64
69
|
|
|
70
|
+
from utilities.shelve import _Flag
|
|
65
71
|
from utilities.types import (
|
|
66
72
|
Coro,
|
|
67
73
|
Delta,
|
|
68
|
-
|
|
69
|
-
LoggerOrName,
|
|
70
|
-
MaybeCallableBool,
|
|
74
|
+
MaybeCallableBoolLike,
|
|
71
75
|
MaybeType,
|
|
76
|
+
PathLike,
|
|
72
77
|
SupportsKeysAndGetItem,
|
|
73
78
|
)
|
|
74
79
|
|
|
@@ -226,7 +231,7 @@ class EnhancedTaskGroup(TaskGroup):
|
|
|
226
231
|
_semaphore: Semaphore | None
|
|
227
232
|
_timeout: Delta | None
|
|
228
233
|
_error: MaybeType[BaseException]
|
|
229
|
-
_debug:
|
|
234
|
+
_debug: MaybeCallableBoolLike
|
|
230
235
|
_stack: AsyncExitStack
|
|
231
236
|
_timeout_cm: _AsyncGeneratorContextManager[None] | None
|
|
232
237
|
|
|
@@ -237,7 +242,7 @@ class EnhancedTaskGroup(TaskGroup):
|
|
|
237
242
|
max_tasks: int | None = None,
|
|
238
243
|
timeout: Delta | None = None,
|
|
239
244
|
error: MaybeType[BaseException] = TimeoutError,
|
|
240
|
-
debug:
|
|
245
|
+
debug: MaybeCallableBoolLike = False,
|
|
241
246
|
) -> None:
|
|
242
247
|
super().__init__()
|
|
243
248
|
self._max_tasks = max_tasks
|
|
@@ -270,7 +275,7 @@ class EnhancedTaskGroup(TaskGroup):
|
|
|
270
275
|
_ = await super().__aexit__(et, exc, tb)
|
|
271
276
|
case False:
|
|
272
277
|
_ = await super().__aexit__(et, exc, tb)
|
|
273
|
-
case
|
|
278
|
+
case never:
|
|
274
279
|
assert_never(never)
|
|
275
280
|
|
|
276
281
|
@override
|
|
@@ -307,7 +312,7 @@ class EnhancedTaskGroup(TaskGroup):
|
|
|
307
312
|
self.create_task(make_coro(*args, **kwargs))
|
|
308
313
|
for _ in range(self._max_tasks)
|
|
309
314
|
]
|
|
310
|
-
case
|
|
315
|
+
case never:
|
|
311
316
|
assert_never(never)
|
|
312
317
|
|
|
313
318
|
async def run_or_create_task[T](
|
|
@@ -322,11 +327,11 @@ class EnhancedTaskGroup(TaskGroup):
|
|
|
322
327
|
return await coro
|
|
323
328
|
case False:
|
|
324
329
|
return self.create_task(coro, name=name, context=context)
|
|
325
|
-
case
|
|
330
|
+
case never:
|
|
326
331
|
assert_never(never)
|
|
327
332
|
|
|
328
333
|
def _is_debug(self) -> bool:
|
|
329
|
-
return to_bool(
|
|
334
|
+
return to_bool(self._debug) or (
|
|
330
335
|
(self._max_tasks is not None) and (self._max_tasks <= 0)
|
|
331
336
|
)
|
|
332
337
|
|
|
@@ -344,6 +349,24 @@ class EnhancedTaskGroup(TaskGroup):
|
|
|
344
349
|
##
|
|
345
350
|
|
|
346
351
|
|
|
352
|
+
def chain_async[T](*iterables: Iterable[T] | AsyncIterable[T]) -> AsyncIterator[T]:
|
|
353
|
+
"""Asynchronous version of `chain`."""
|
|
354
|
+
|
|
355
|
+
async def iterator() -> AsyncIterator[T]:
|
|
356
|
+
for it in iterables:
|
|
357
|
+
try:
|
|
358
|
+
async for item in cast("AsyncIterable[T]", it):
|
|
359
|
+
yield item
|
|
360
|
+
except TypeError:
|
|
361
|
+
for item in cast("Iterable[T]", it):
|
|
362
|
+
yield item
|
|
363
|
+
|
|
364
|
+
return iterator()
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
##
|
|
368
|
+
|
|
369
|
+
|
|
347
370
|
def get_coroutine_name(func: Callable[[], Coro[Any]], /) -> str:
|
|
348
371
|
"""Get the name of a coroutine, and then dispose of it gracefully."""
|
|
349
372
|
coro = func()
|
|
@@ -363,8 +386,6 @@ async def get_items[T](queue: Queue[T], /, *, max_size: int | None = None) -> li
|
|
|
363
386
|
try:
|
|
364
387
|
items = [await queue.get()]
|
|
365
388
|
except RuntimeError as error: # pragma: no cover
|
|
366
|
-
from utilities.pytest import is_pytest
|
|
367
|
-
|
|
368
389
|
if (not is_pytest()) or (error.args[0] != "Event loop is closed"):
|
|
369
390
|
raise
|
|
370
391
|
return []
|
|
@@ -394,38 +415,38 @@ def get_items_nowait[T](queue: Queue[T], /, *, max_size: int | None = None) -> l
|
|
|
394
415
|
##
|
|
395
416
|
|
|
396
417
|
|
|
397
|
-
async def
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
418
|
+
async def one_async[T](*iterables: Iterable[T] | AsyncIterable[T]) -> T:
|
|
419
|
+
"""Asynchronous version of `one`."""
|
|
420
|
+
result: T | Sentinel = sentinel
|
|
421
|
+
async for item in chain_async(*iterables):
|
|
422
|
+
if not isinstance(result, Sentinel):
|
|
423
|
+
raise OneAsyncNonUniqueError(iterables=iterables, first=result, second=item)
|
|
424
|
+
result = item
|
|
425
|
+
if isinstance(result, Sentinel):
|
|
426
|
+
raise OneAsyncEmptyError(iterables=iterables)
|
|
427
|
+
return result
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
@dataclass(kw_only=True, slots=True)
|
|
431
|
+
class OneAsyncError[T](Exception):
|
|
432
|
+
iterables: tuple[Iterable[T] | AsyncIterable[T], ...]
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@dataclass(kw_only=True, slots=True)
|
|
436
|
+
class OneAsyncEmptyError[T](OneAsyncError[T]):
|
|
437
|
+
@override
|
|
438
|
+
def __str__(self) -> str:
|
|
439
|
+
return f"Iterable(s) {get_repr(self.iterables)} must not be empty"
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
@dataclass(kw_only=True, slots=True)
|
|
443
|
+
class OneAsyncNonUniqueError[T](OneAsyncError):
|
|
444
|
+
first: T
|
|
445
|
+
second: T
|
|
446
|
+
|
|
447
|
+
@override
|
|
448
|
+
def __str__(self) -> str:
|
|
449
|
+
return f"Iterable(s) {get_repr(self.iterables)} must contain exactly one item; got {self.first}, {self.second} and perhaps more"
|
|
429
450
|
|
|
430
451
|
|
|
431
452
|
##
|
|
@@ -492,27 +513,21 @@ class StreamCommandOutput:
|
|
|
492
513
|
|
|
493
514
|
@property
|
|
494
515
|
def return_code(self) -> int:
|
|
495
|
-
return ensure_int(self.process.returncode)
|
|
516
|
+
return ensure_int(self.process.returncode)
|
|
496
517
|
|
|
497
518
|
|
|
498
519
|
async def stream_command(cmd: str, /) -> StreamCommandOutput:
|
|
499
520
|
"""Run a shell command asynchronously and stream its output in real time."""
|
|
500
|
-
process = await create_subprocess_shell(
|
|
501
|
-
|
|
502
|
-
)
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
)
|
|
506
|
-
proc_stderr = ensure_not_none( # skipif-not-windows
|
|
507
|
-
process.stderr, desc="process.stderr"
|
|
508
|
-
)
|
|
509
|
-
ret_stdout = StringIO() # skipif-not-windows
|
|
510
|
-
ret_stderr = StringIO() # skipif-not-windows
|
|
511
|
-
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:
|
|
512
527
|
_ = tg.create_task(_stream_one(proc_stdout, stdout, ret_stdout))
|
|
513
528
|
_ = tg.create_task(_stream_one(proc_stderr, stderr, ret_stderr))
|
|
514
|
-
_ = await process.wait()
|
|
515
|
-
return StreamCommandOutput(
|
|
529
|
+
_ = await process.wait()
|
|
530
|
+
return StreamCommandOutput(
|
|
516
531
|
process=process, stdout=ret_stdout.getvalue(), stderr=ret_stderr.getvalue()
|
|
517
532
|
)
|
|
518
533
|
|
|
@@ -521,7 +536,7 @@ async def _stream_one(
|
|
|
521
536
|
input_: StreamReader, out_stream: TextIO, ret_stream: StringIO, /
|
|
522
537
|
) -> None:
|
|
523
538
|
"""Asynchronously read from a stream and write to the target output stream."""
|
|
524
|
-
while True:
|
|
539
|
+
while True:
|
|
525
540
|
line = await input_.readline()
|
|
526
541
|
if not line:
|
|
527
542
|
break
|
|
@@ -547,14 +562,47 @@ async def timeout_td(
|
|
|
547
562
|
raise error from None
|
|
548
563
|
|
|
549
564
|
|
|
565
|
+
##
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
_LOCKS: AsyncDict[Path, Lock] = AsyncDict()
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
@asynccontextmanager
|
|
572
|
+
async def yield_locked_shelf(
|
|
573
|
+
path: PathLike,
|
|
574
|
+
/,
|
|
575
|
+
*,
|
|
576
|
+
flag: _Flag = "c",
|
|
577
|
+
protocol: int | None = None,
|
|
578
|
+
writeback: bool = False,
|
|
579
|
+
) -> AsyncIterator[Shelf[Any]]:
|
|
580
|
+
"""Yield a shelf, behind a lock."""
|
|
581
|
+
path = Path(path)
|
|
582
|
+
try:
|
|
583
|
+
lock = _LOCKS[path]
|
|
584
|
+
except KeyError:
|
|
585
|
+
lock = Lock()
|
|
586
|
+
await _LOCKS.set(path, lock)
|
|
587
|
+
async with lock:
|
|
588
|
+
with yield_shelf(
|
|
589
|
+
path, flag=flag, protocol=protocol, writeback=writeback
|
|
590
|
+
) as shelf:
|
|
591
|
+
yield shelf
|
|
592
|
+
|
|
593
|
+
|
|
550
594
|
__all__ = [
|
|
551
595
|
"AsyncDict",
|
|
552
596
|
"EnhancedTaskGroup",
|
|
597
|
+
"OneAsyncEmptyError",
|
|
598
|
+
"OneAsyncError",
|
|
599
|
+
"OneAsyncNonUniqueError",
|
|
553
600
|
"StreamCommandOutput",
|
|
601
|
+
"chain_async",
|
|
554
602
|
"get_coroutine_name",
|
|
555
603
|
"get_items",
|
|
556
604
|
"get_items_nowait",
|
|
557
|
-
"
|
|
605
|
+
"one_async",
|
|
558
606
|
"put_items",
|
|
559
607
|
"put_items_nowait",
|
|
560
608
|
"sleep_max",
|
|
@@ -563,4 +611,5 @@ __all__ = [
|
|
|
563
611
|
"sleep_until",
|
|
564
612
|
"stream_command",
|
|
565
613
|
"timeout_td",
|
|
614
|
+
"yield_locked_shelf",
|
|
566
615
|
]
|