dycw-utilities 0.133.6__tar.gz → 0.134.0__tar.gz

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 (218) hide show
  1. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/PKG-INFO +1 -1
  2. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/pyproject.toml +3 -2
  3. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_arq.py +3 -3
  4. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_click.py +200 -110
  5. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_eventkit.py +3 -7
  6. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_functions.py +8 -13
  7. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_timer.py +4 -0
  8. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_typed_settings.py +4 -8
  9. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_types.py +2 -2
  10. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/__init__.py +1 -1
  11. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/arq.py +13 -20
  12. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/asyncio.py +59 -74
  13. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/atools.py +10 -13
  14. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/cachetools.py +11 -17
  15. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/click.py +61 -55
  16. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/concurrent.py +7 -10
  17. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/dataclasses.py +69 -91
  18. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/enum.py +24 -21
  19. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/eventkit.py +34 -48
  20. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/functions.py +133 -168
  21. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/functools.py +14 -18
  22. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/hypothesis.py +34 -44
  23. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/iterables.py +165 -179
  24. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/luigi.py +3 -15
  25. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/memory_profiler.py +11 -15
  26. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/more_itertools.py +85 -94
  27. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/operator.py +5 -7
  28. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/optuna.py +6 -6
  29. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/pathlib.py +1 -0
  30. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/period.py +7 -9
  31. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/polars.py +5 -16
  32. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/pqdm.py +7 -8
  33. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/pydantic.py +2 -4
  34. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/pytest.py +14 -23
  35. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/python_dotenv.py +5 -9
  36. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/random.py +2 -3
  37. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/redis.py +163 -181
  38. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/slack_sdk.py +2 -2
  39. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/sqlalchemy.py +4 -14
  40. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/timer.py +6 -0
  41. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/typed_settings.py +7 -10
  42. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/types.py +10 -94
  43. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/typing.py +32 -43
  44. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/uuid.py +1 -0
  45. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/.gitignore +0 -0
  46. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/LICENSE +0 -0
  47. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/README.md +0 -0
  48. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/__init__.py +0 -0
  49. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/conftest.py +0 -0
  50. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/__init__.py +0 -0
  51. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_missing/__init__.py +0 -0
  52. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_missing/module.py +0 -0
  53. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_with/__init__.py +0 -0
  54. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_with/outer_1.py +0 -0
  55. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_with/outer_2.py +0 -0
  56. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  57. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  58. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  59. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  60. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_without/__init__.py +0 -0
  61. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_without/module_1.py +0 -0
  62. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/package_without/module_2.py +0 -0
  63. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/standalone.py +0 -0
  64. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/modules/with_imports.py +0 -0
  65. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  66. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  67. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  68. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  69. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  70. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  71. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  72. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  73. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_aiolimiter.py +0 -0
  74. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_altair.py +0 -0
  75. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_asyncio.py +0 -0
  76. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_asyncio_classes/__init__.py +0 -0
  77. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_asyncio_classes/loopers.py +0 -0
  78. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_asyncio_classes/redis.py +0 -0
  79. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_atomicwrites.py +0 -0
  80. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_atools.py +0 -0
  81. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_cachetools.py +0 -0
  82. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_concurrent.py +0 -0
  83. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_contextlib.py +0 -0
  84. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_contextvars.py +0 -0
  85. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_cryptography.py +0 -0
  86. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_cvxpy.py +0 -0
  87. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_dataclasses.py +0 -0
  88. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_enum.py +0 -0
  89. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_errors.py +0 -0
  90. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_fastapi.py +0 -0
  91. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_fpdf2.py +0 -0
  92. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_functools.py +0 -0
  93. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_getpass.py +0 -0
  94. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_git.py +0 -0
  95. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_hashlib.py +0 -0
  96. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_http.py +0 -0
  97. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_hypothesis.py +0 -0
  98. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_importlib.py +0 -0
  99. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_inflect.py +0 -0
  100. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_ipython.py +0 -0
  101. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_iterables.py +0 -0
  102. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_jupyter.py +0 -0
  103. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_libcst.py +0 -0
  104. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_lightweight_charts.py +0 -0
  105. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_logging.py +0 -0
  106. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_luigi.py +0 -0
  107. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_math.py +0 -0
  108. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_memory_profiler.py +0 -0
  109. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_modules.py +0 -0
  110. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_more_itertools.py +0 -0
  111. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_numpy.py +0 -0
  112. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_objects/__init__.py +0 -0
  113. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_objects/objects.py +0 -0
  114. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_operator.py +0 -0
  115. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_optuna.py +0 -0
  116. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_orjson.py +0 -0
  117. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_os.py +0 -0
  118. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_parse.py +0 -0
  119. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_pathlib.py +0 -0
  120. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_period.py +0 -0
  121. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_pickle.py +0 -0
  122. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_platform.py +0 -0
  123. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_polars.py +0 -0
  124. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_polars_ols.py +0 -0
  125. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_pottery.py +0 -0
  126. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_pqdm.py +0 -0
  127. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_psutil.py +0 -0
  128. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_pydantic.py +0 -0
  129. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_pyinstrument.py +0 -0
  130. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_pytest.py +0 -0
  131. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_pytest_regressions.py +0 -0
  132. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_python_dotenv.py +0 -0
  133. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_random.py +0 -0
  134. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_re.py +0 -0
  135. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_redis.py +0 -0
  136. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_reprlib.py +0 -0
  137. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_scipy.py +0 -0
  138. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_sentinel.py +0 -0
  139. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_shelve.py +0 -0
  140. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_slack_sdk.py +0 -0
  141. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_socket.py +0 -0
  142. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_sqlalchemy.py +0 -0
  143. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_sqlalchemy_polars.py +0 -0
  144. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_statsmodels.py +0 -0
  145. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_streamlit.py +0 -0
  146. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_string.py +0 -0
  147. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_tempfile.py +0 -0
  148. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_text.py +0 -0
  149. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_threading.py +0 -0
  150. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_traceback.py +0 -0
  151. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_typing.py +0 -0
  152. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_typing_funcs/__init__.py +0 -0
  153. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_typing_funcs/no_future.py +0 -0
  154. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_typing_funcs/with_future.py +0 -0
  155. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_tzdata.py +0 -0
  156. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_tzlocal.py +0 -0
  157. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_uuid.py +0 -0
  158. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_version.py +0 -0
  159. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_warnings.py +0 -0
  160. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_whenever.py +0 -0
  161. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_zipfile.py +0 -0
  162. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/tests/test_zoneinfo.py +0 -0
  163. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/aiolimiter.py +0 -0
  164. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/altair.py +0 -0
  165. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/atomicwrites.py +0 -0
  166. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/contextlib.py +0 -0
  167. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/contextvars.py +0 -0
  168. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/cryptography.py +0 -0
  169. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/cvxpy.py +0 -0
  170. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/errors.py +0 -0
  171. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/fastapi.py +0 -0
  172. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/fpdf2.py +0 -0
  173. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/getpass.py +0 -0
  174. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/git.py +0 -0
  175. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/hashlib.py +0 -0
  176. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/http.py +0 -0
  177. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/importlib.py +0 -0
  178. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/inflect.py +0 -0
  179. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/ipython.py +0 -0
  180. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/jupyter.py +0 -0
  181. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/libcst.py +0 -0
  182. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/lightweight_charts.py +0 -0
  183. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/logging.py +0 -0
  184. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/math.py +0 -0
  185. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/modules.py +0 -0
  186. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/numpy.py +0 -0
  187. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/orjson.py +0 -0
  188. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/os.py +0 -0
  189. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/parse.py +0 -0
  190. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/pickle.py +0 -0
  191. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/platform.py +0 -0
  192. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/polars_ols.py +0 -0
  193. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/pottery.py +0 -0
  194. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/psutil.py +0 -0
  195. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/py.typed +0 -0
  196. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/pyinstrument.py +0 -0
  197. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/pytest_regressions.py +0 -0
  198. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/re.py +0 -0
  199. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/reprlib.py +0 -0
  200. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/scipy.py +0 -0
  201. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/sentinel.py +0 -0
  202. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/shelve.py +0 -0
  203. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/socket.py +0 -0
  204. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/sqlalchemy_polars.py +0 -0
  205. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/statsmodels.py +0 -0
  206. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/streamlit.py +0 -0
  207. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/string.py +0 -0
  208. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/tempfile.py +0 -0
  209. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/text.py +0 -0
  210. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/threading.py +0 -0
  211. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/traceback.py +0 -0
  212. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/tzdata.py +0 -0
  213. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/tzlocal.py +0 -0
  214. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/version.py +0 -0
  215. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/warnings.py +0 -0
  216. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/whenever.py +0 -0
  217. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/zipfile.py +0 -0
  218. {dycw_utilities-0.133.6 → dycw_utilities-0.134.0}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.133.6
3
+ Version: 0.134.0
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -104,7 +104,7 @@ dependencies = [
104
104
  name = "dycw-utilities"
105
105
  readme = "README.md"
106
106
  requires-python = ">= 3.12"
107
- version = "0.133.6"
107
+ version = "0.134.0"
108
108
 
109
109
  [project.optional-dependencies]
110
110
  logging = [
@@ -131,7 +131,7 @@ test = [
131
131
  # bump-my-version
132
132
  [tool.bumpversion]
133
133
  allow_dirty = true
134
- current_version = "0.133.6"
134
+ current_version = "0.134.0"
135
135
 
136
136
  [[tool.bumpversion.files]]
137
137
  filename = "src/utilities/__init__.py"
@@ -292,6 +292,7 @@ ignore = [
292
292
  "E501", # line-too-long
293
293
  "PD", # pandas-vet
294
294
  "PERF203", # try-except-in-loop
295
+ "PLC0415", # import-outside-top-level
295
296
  "PLR0911", # too-many-return-statements
296
297
  "PLR0912", # too-many-branches
297
298
  "PLR0913", # too-many-arguments
@@ -12,11 +12,11 @@ from utilities.arq import Worker, cron_raw, job_enqueuer
12
12
  from utilities.iterables import one
13
13
 
14
14
  if TYPE_CHECKING:
15
- from collections.abc import Sequence
15
+ from collections.abc import Callable, Sequence
16
16
 
17
17
  from arq.typing import WorkerCoroutine
18
18
 
19
- from utilities.types import CallableCoroutine1
19
+ from utilities.types import Coro
20
20
 
21
21
 
22
22
  class TestCronRaw:
@@ -51,7 +51,7 @@ class TestWorker:
51
51
  return x + y
52
52
 
53
53
  class Example(Worker):
54
- functions_raw: Sequence[CallableCoroutine1[Any]] = [func]
54
+ functions_raw: Sequence[Callable[..., Coro[Any]]] = [func]
55
55
 
56
56
  func_use = cast("WorkerCoroutine", one(Example.functions))
57
57
  result = await func_use({}, x, y)
@@ -1,10 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import enum
4
+ from dataclasses import dataclass
4
5
  from enum import auto
5
6
  from operator import attrgetter
6
7
  from re import search
7
- from typing import TYPE_CHECKING, Any, TypeVar
8
+ from typing import TYPE_CHECKING, Any, ClassVar
8
9
 
9
10
  import whenever
10
11
  from click import ParamType, argument, command, echo, option
@@ -13,7 +14,6 @@ from hypothesis import given
13
14
  from hypothesis.strategies import (
14
15
  DataObject,
15
16
  SearchStrategy,
16
- booleans,
17
17
  data,
18
18
  frozensets,
19
19
  ip_addresses,
@@ -40,6 +40,7 @@ from utilities.click import (
40
40
  FrozenSetStrs,
41
41
  IPv4Address,
42
42
  IPv6Address,
43
+ ListChoices,
43
44
  ListEnums,
44
45
  ListStrs,
45
46
  Month,
@@ -54,7 +55,6 @@ from utilities.hypothesis import (
54
55
  dates,
55
56
  freqs,
56
57
  months,
57
- pairs,
58
58
  plain_datetimes,
59
59
  text_ascii,
60
60
  time_deltas,
@@ -68,9 +68,6 @@ if TYPE_CHECKING:
68
68
  from pathlib import Path
69
69
 
70
70
 
71
- _T = TypeVar("_T")
72
-
73
-
74
71
  class TestContextSettingsHelpOptionNames:
75
72
  @given(help_=sampled_from(["-h", "--help"]))
76
73
  def test_main(self, *, help_: str) -> None:
@@ -175,133 +172,226 @@ class _ExampleEnum(enum.Enum):
175
172
  c = auto()
176
173
 
177
174
 
178
- def _lift_serializer(
179
- serializer: Callable[[_T], str], /, *, sort: bool = False
180
- ) -> Callable[[Iterable[_T]], str]:
181
- def wrapped(values: Iterable[_T], /) -> str:
175
+ def _lift_serializer[T](
176
+ serializer: Callable[[T], str], /, *, sort: bool = False
177
+ ) -> Callable[[Iterable[T]], str]:
178
+ def wrapped(values: Iterable[T], /) -> str:
182
179
  return join_strs(map(serializer, values), sort=sort)
183
180
 
184
181
  return wrapped
185
182
 
186
183
 
184
+ @dataclass(kw_only=True, slots=True)
185
+ class _Case[T]:
186
+ param: ParamType
187
+ name: str
188
+ repr: str | None = None
189
+ strategy: SearchStrategy[T]
190
+ serialize: Callable[[T], str]
191
+ failable: bool = False
192
+
193
+
187
194
  class TestParameters:
188
- @given(data=data(), use_value=booleans())
195
+ cases: ClassVar[list[_Case]] = [
196
+ _Case(
197
+ param=Date(),
198
+ name="date",
199
+ strategy=dates(),
200
+ serialize=whenever.Date.format_common_iso,
201
+ failable=True,
202
+ ),
203
+ _Case(
204
+ param=DateDelta(),
205
+ name="date delta",
206
+ strategy=date_deltas(parsable=True),
207
+ serialize=whenever.DateDelta.format_common_iso,
208
+ failable=True,
209
+ ),
210
+ _Case(
211
+ param=DateTimeDelta(),
212
+ name="date-time delta",
213
+ strategy=date_time_deltas(parsable=True),
214
+ serialize=whenever.DateTimeDelta.format_common_iso,
215
+ failable=True,
216
+ ),
217
+ _Case(
218
+ param=Enum(_ExampleEnum),
219
+ name="enum[_ExampleEnum]",
220
+ repr="ENUM[_ExampleEnum]",
221
+ strategy=sampled_from(_ExampleEnum),
222
+ serialize=attrgetter("name"),
223
+ failable=True,
224
+ ),
225
+ _Case(
226
+ param=Freq(),
227
+ name="freq",
228
+ strategy=freqs(),
229
+ serialize=utilities.whenever.Freq.serialize,
230
+ failable=True,
231
+ ),
232
+ _Case(
233
+ param=FrozenSetChoices(["a", "b", "c"]),
234
+ name="frozenset[choice]",
235
+ repr="FROZENSET[Choice(['a', 'b', 'c'])]",
236
+ strategy=frozensets(sampled_from(["a", "b", "c"])),
237
+ serialize=_lift_serializer(str, sort=True),
238
+ failable=True,
239
+ ),
240
+ _Case(
241
+ param=FrozenSetEnums(_ExampleEnum),
242
+ name="frozenset[enum[_ExampleEnum]]",
243
+ repr="FROZENSET[ENUM[_ExampleEnum]]",
244
+ strategy=frozensets(sampled_from(_ExampleEnum)),
245
+ serialize=_lift_serializer(attrgetter("name"), sort=True),
246
+ failable=True,
247
+ ),
248
+ _Case(
249
+ param=FrozenSetStrs(),
250
+ name="frozenset[text]",
251
+ repr="FROZENSET[STRING]",
252
+ strategy=frozensets(text_ascii()),
253
+ serialize=_lift_serializer(str, sort=True),
254
+ ),
255
+ _Case(
256
+ param=IPv4Address(),
257
+ name="ipv4 address",
258
+ strategy=ip_addresses(v=4),
259
+ serialize=str,
260
+ failable=True,
261
+ ),
262
+ _Case(
263
+ param=IPv6Address(),
264
+ name="ipv6 address",
265
+ strategy=ip_addresses(v=6),
266
+ serialize=str,
267
+ failable=True,
268
+ ),
269
+ _Case(
270
+ param=ListChoices(["a", "b", "c"]),
271
+ name="list[choice]",
272
+ repr="LIST[Choice(['a', 'b', 'c'])]",
273
+ strategy=frozensets(sampled_from(["a", "b", "c"])),
274
+ serialize=_lift_serializer(str, sort=True),
275
+ failable=True,
276
+ ),
277
+ _Case(
278
+ param=ListEnums(_ExampleEnum),
279
+ name="list[enum[_ExampleEnum]]",
280
+ repr="LIST[ENUM[_ExampleEnum]]",
281
+ strategy=lists(sampled_from(_ExampleEnum)),
282
+ serialize=_lift_serializer(attrgetter("name")),
283
+ failable=True,
284
+ ),
285
+ _Case(
286
+ param=Month(),
287
+ name="month",
288
+ strategy=months(),
289
+ serialize=utilities.whenever.Month.format_common_iso,
290
+ failable=True,
291
+ ),
292
+ _Case(
293
+ param=PlainDateTime(),
294
+ name="plain date-time",
295
+ strategy=plain_datetimes(),
296
+ serialize=whenever.PlainDateTime.format_common_iso,
297
+ failable=True,
298
+ ),
299
+ _Case(
300
+ param=Time(),
301
+ name="time",
302
+ strategy=times(),
303
+ serialize=whenever.Time.format_common_iso,
304
+ failable=True,
305
+ ),
306
+ _Case(
307
+ param=TimeDelta(),
308
+ name="time-delta",
309
+ strategy=time_deltas(),
310
+ serialize=whenever.TimeDelta.format_common_iso,
311
+ failable=True,
312
+ ),
313
+ _Case(
314
+ param=ZonedDateTime(),
315
+ name="zoned date-time",
316
+ strategy=zoned_datetimes(),
317
+ serialize=whenever.ZonedDateTime.format_common_iso,
318
+ failable=True,
319
+ ),
320
+ ]
321
+
322
+ @given(data=data())
189
323
  @mark.parametrize(
190
- ("param", "exp_repr", "strategy", "serialize", "failable"),
191
- [
192
- param(Date(), "DATE", dates(), whenever.Date.format_common_iso, True),
193
- param(
194
- DateDelta(),
195
- "DATE DELTA",
196
- date_deltas(parsable=True),
197
- whenever.DateDelta.format_common_iso,
198
- True,
199
- ),
200
- param(
201
- DateTimeDelta(),
202
- "DATE-TIME DELTA",
203
- date_time_deltas(parsable=True),
204
- whenever.DateTimeDelta.format_common_iso,
205
- True,
206
- ),
207
- param(
208
- Enum(_ExampleEnum),
209
- "ENUM[_ExampleEnum]",
210
- sampled_from(_ExampleEnum),
211
- attrgetter("name"),
212
- True,
213
- ),
214
- param(Freq(), "FREQ", freqs(), utilities.whenever.Freq.serialize, True),
215
- param(
216
- FrozenSetChoices(["a", "b", "c"]),
217
- "FROZENSET[Choice(['a', 'b', 'c'])]",
218
- frozensets(sampled_from(["a", "b", "c"])),
219
- _lift_serializer(str, sort=True),
220
- True,
221
- ),
222
- param(
223
- FrozenSetEnums(_ExampleEnum),
224
- "FROZENSET[ENUM[_ExampleEnum]]",
225
- frozensets(sampled_from(_ExampleEnum)),
226
- _lift_serializer(attrgetter("name"), sort=True),
227
- True,
228
- ),
229
- param(
230
- FrozenSetStrs(),
231
- "FROZENSET[STRING]",
232
- frozensets(text_ascii()),
233
- _lift_serializer(str, sort=True),
234
- False,
235
- ),
236
- param(IPv4Address(), "IPV4 ADDRESS", ip_addresses(v=4), str, True),
237
- param(IPv6Address(), "IPV6 ADDRESS", ip_addresses(v=6), str, True),
238
- param(
239
- ListEnums(_ExampleEnum),
240
- "LIST[ENUM[_ExampleEnum]]",
241
- lists(sampled_from(_ExampleEnum)),
242
- _lift_serializer(attrgetter("name")),
243
- True,
244
- ),
245
- param(
246
- Month(),
247
- "MONTH",
248
- months(),
249
- utilities.whenever.Month.format_common_iso,
250
- True,
251
- ),
252
- param(
253
- PlainDateTime(),
254
- "PLAIN DATE-TIME",
255
- plain_datetimes(),
256
- whenever.PlainDateTime.format_common_iso,
257
- True,
258
- ),
259
- param(Time(), "TIME", times(), whenever.Time.format_common_iso, True),
260
- param(
261
- TimeDelta(),
262
- "TIME-DELTA",
263
- time_deltas(),
264
- whenever.TimeDelta.format_common_iso,
265
- True,
266
- ),
267
- param(
268
- ZonedDateTime(),
269
- "ZONED DATE-TIME",
270
- zoned_datetimes(),
271
- whenever.ZonedDateTime.format_common_iso,
272
- True,
273
- ),
274
- ],
324
+ ("param", "strategy", "serialize"),
325
+ [param(c.param, c.strategy, c.serialize) for c in cases],
275
326
  )
276
- def test_main(
327
+ def test_default(
277
328
  self,
278
329
  *,
279
330
  data: DataObject,
280
331
  param: ParamType,
281
- exp_repr: str,
282
332
  strategy: SearchStrategy[Any],
283
333
  serialize: Callable[[Any], str],
284
- use_value: bool,
285
- failable: bool,
286
334
  ) -> None:
287
- assert repr(param) == exp_repr
288
-
289
- default, value = data.draw(pairs(strategy))
335
+ default = data.draw(strategy)
290
336
 
291
337
  @command()
292
338
  @option("--value", type=param, default=default)
293
339
  def cli(*, value: Any) -> None:
294
340
  echo(f"value = {serialize(value)}")
295
341
 
296
- args = [f"--value={serialize(value)}"] if use_value else None
297
- result = CliRunner().invoke(cli, args=args)
342
+ result = CliRunner().invoke(cli, args=[])
298
343
  assert result.exit_code == 0
299
- expected_str = serialize(value if use_value else default)
300
- assert result.stdout == f"value = {expected_str}\n"
344
+ assert result.stdout == f"value = {serialize(default)}\n"
345
+
346
+ @given(data=data())
347
+ @mark.parametrize(
348
+ ("param", "strategy", "serialize"),
349
+ [param(c.param, c.strategy, c.serialize) for c in cases],
350
+ )
351
+ def test_cli_value(
352
+ self,
353
+ *,
354
+ data: DataObject,
355
+ param: ParamType,
356
+ strategy: SearchStrategy[Any],
357
+ serialize: Callable[[Any], str],
358
+ ) -> None:
359
+ @command()
360
+ @option("--value", type=param)
361
+ def cli(*, value: Any) -> None:
362
+ echo(f"value = {serialize(value)}")
301
363
 
302
- result = CliRunner().invoke(cli, ["--value=error"])
303
- expected = 2 if failable else 0
304
- assert result.exit_code == expected
364
+ value = data.draw(strategy)
365
+ ser = serialize(value)
366
+ result = CliRunner().invoke(cli, args=[f"--value={ser}"])
367
+ assert result.exit_code == 0
368
+ assert result.stdout == f"value = {ser}\n"
369
+
370
+ @mark.parametrize(
371
+ ("param", "serialize"),
372
+ [param(c.param, c.serialize) for c in cases if c.failable],
373
+ )
374
+ def test_cli_fail(
375
+ self, *, param: ParamType, serialize: Callable[[Any], str]
376
+ ) -> None:
377
+ @command()
378
+ @option("--value", type=param)
379
+ def cli(*, value: Any) -> None:
380
+ echo(f"value = {serialize(value)}")
381
+
382
+ result = CliRunner().invoke(cli, args=["--value=invalid"])
383
+ assert result.exit_code == 2
384
+
385
+ @mark.parametrize(("param", "name"), [param(c.param, c.name) for c in cases])
386
+ def test_name(self, *, param: ParamType, name: str) -> None:
387
+ assert param.name == name
388
+
389
+ @mark.parametrize(
390
+ ("param", "repr_", "name"), [param(c.param, c.repr, c.name) for c in cases]
391
+ )
392
+ def test_repr(self, *, param: ParamType, repr_: str | None, name: str) -> None:
393
+ expected = name.upper() if repr_ is None else repr_
394
+ assert repr(param) == expected
305
395
 
306
396
  @mark.parametrize(
307
397
  "param",
@@ -6,7 +6,7 @@ from functools import wraps
6
6
  from io import StringIO
7
7
  from logging import StreamHandler, getLogger
8
8
  from re import search
9
- from typing import TYPE_CHECKING, Literal, ParamSpec, TypeVar
9
+ from typing import TYPE_CHECKING, Literal
10
10
 
11
11
  from eventkit import Event
12
12
  from hypothesis import given
@@ -26,10 +26,6 @@ if TYPE_CHECKING:
26
26
  from pathlib import Path
27
27
 
28
28
 
29
- _P = ParamSpec("_P")
30
- _R = TypeVar("_R")
31
-
32
-
33
29
  class TestAddListener:
34
30
  @given(sync_or_async=sampled_from(["sync", "async"]))
35
31
  async def test_main(self, *, sync_or_async: Literal["sync", "async"]) -> None:
@@ -210,9 +206,9 @@ class TestAddListener:
210
206
  nonlocal counter
211
207
  counter += 1
212
208
 
213
- def increment(func: Callable[_P, _R], /) -> Callable[_P, _R]:
209
+ def increment[**P, R](func: Callable[P, R], /) -> Callable[P, R]:
214
210
  @wraps(func)
215
- def wrapped(*args: _P.args, **kwargs: _P.kwargs) -> _R:
211
+ def wrapped(*args: P.args, **kwargs: P.kwargs) -> R:
216
212
  nonlocal counter
217
213
  counter += 1
218
214
  return func(*args, **kwargs)
@@ -7,7 +7,7 @@ from itertools import chain
7
7
  from operator import neg
8
8
  from pathlib import Path
9
9
  from types import NoneType
10
- from typing import TYPE_CHECKING, Any, ClassVar, ParamSpec, TypeVar, cast
10
+ from typing import TYPE_CHECKING, Any, ClassVar, cast
11
11
 
12
12
  from hypothesis import given
13
13
  from hypothesis.strategies import (
@@ -106,11 +106,6 @@ if TYPE_CHECKING:
106
106
  from utilities.types import Number
107
107
 
108
108
 
109
- _P = ParamSpec("_P")
110
- _R = TypeVar("_R")
111
- _T = TypeVar("_T")
112
-
113
-
114
109
  class TestApplyDecorators:
115
110
  @given(n=integers())
116
111
  def test_main(self, *, n: int) -> None:
@@ -119,9 +114,9 @@ class TestApplyDecorators:
119
114
  def negate(x: int, /) -> int:
120
115
  return -x
121
116
 
122
- def increment(func: Callable[_P, _R], /) -> Callable[_P, _R]:
117
+ def increment[**P, T](func: Callable[P, T], /) -> Callable[P, T]:
123
118
  @wraps(func)
124
- def wrapped(*args: _P.args, **kwargs: _P.kwargs) -> _R:
119
+ def wrapped(*args: P.args, **kwargs: P.kwargs) -> T:
125
120
  nonlocal counter
126
121
  counter += 1
127
122
  return func(*args, **kwargs)
@@ -538,7 +533,7 @@ class TestGetFuncNameAndGetFuncQualName:
538
533
 
539
534
  def test_decorated(self) -> None:
540
535
  @wraps(identity)
541
- def wrapped(x: _T, /) -> _T:
536
+ def wrapped[T](x: T, /) -> T:
542
537
  return identity(x)
543
538
 
544
539
  assert get_func_name(wrapped) == "identity"
@@ -557,7 +552,7 @@ class TestGetFuncNameAndGetFuncQualName:
557
552
 
558
553
  def test_object(self) -> None:
559
554
  class Example:
560
- def __call__(self, x: _T, /) -> _T:
555
+ def __call__[T](self, x: T, /) -> T:
561
556
  return identity(x)
562
557
 
563
558
  obj = Example()
@@ -566,7 +561,7 @@ class TestGetFuncNameAndGetFuncQualName:
566
561
 
567
562
  def test_obj_method(self) -> None:
568
563
  class Example:
569
- def obj_method(self, x: _T) -> _T:
564
+ def obj_method[T](self, x: T) -> T:
570
565
  return identity(x)
571
566
 
572
567
  obj = Example()
@@ -579,7 +574,7 @@ class TestGetFuncNameAndGetFuncQualName:
579
574
  def test_obj_classmethod(self) -> None:
580
575
  class Example:
581
576
  @classmethod
582
- def obj_classmethod(cls: _T) -> _T:
577
+ def obj_classmethod[T](cls: T) -> T:
583
578
  return identity(cls)
584
579
 
585
580
  assert get_func_name(Example.obj_classmethod) == "Example.obj_classmethod"
@@ -591,7 +586,7 @@ class TestGetFuncNameAndGetFuncQualName:
591
586
  def test_obj_staticmethod(self) -> None:
592
587
  class Example:
593
588
  @staticmethod
594
- def obj_staticmethod(x: _T) -> _T:
589
+ def obj_staticmethod[T](x: T) -> T:
595
590
  return identity(x)
596
591
 
597
592
  assert get_func_name(Example.obj_staticmethod) == "Example.obj_staticmethod"
@@ -101,6 +101,10 @@ class TestTimer:
101
101
  await sleep_td(2 * delta)
102
102
  assert timer >= delta
103
103
 
104
+ def test_hashable(self) -> None:
105
+ timer = Timer()
106
+ _ = hash(timer)
107
+
104
108
  @mark.parametrize("func", [param(repr), param(str)])
105
109
  async def test_repr_and_str(self, *, func: Callable[[Timer], str]) -> None:
106
110
  with Timer() as timer:
@@ -2,7 +2,6 @@ from collections.abc import Callable
2
2
  from dataclasses import dataclass
3
3
  from ipaddress import IPv4Address, IPv6Address
4
4
  from pathlib import Path
5
- from typing import TypeVar
6
5
 
7
6
  import typed_settings
8
7
  from hypothesis import given
@@ -43,9 +42,6 @@ from utilities.whenever import Freq
43
42
  app_names = text_ascii(min_size=1).map(str.lower)
44
43
 
45
44
 
46
- _T = TypeVar("_T")
47
-
48
-
49
45
  class TestExtendedTSConverter:
50
46
  @given(data=data(), root=temp_paths(), app_name=app_names)
51
47
  @mark.parametrize(
@@ -67,15 +63,15 @@ class TestExtendedTSConverter:
67
63
  param(ZonedDateTime, zoned_datetimes(), ZonedDateTime.format_common_iso),
68
64
  ],
69
65
  )
70
- def test_main(
66
+ def test_main[T](
71
67
  self,
72
68
  *,
73
69
  data: DataObject,
74
70
  root: Path,
75
71
  app_name: str,
76
- test_cls: type[_T],
77
- strategy: SearchStrategy[_T],
78
- serialize: Callable[[_T], str],
72
+ test_cls: type[T],
73
+ strategy: SearchStrategy[T],
74
+ serialize: Callable[[T], str],
79
75
  ) -> None:
80
76
  default, value = data.draw(tuples(strategy, strategy))
81
77
 
@@ -9,13 +9,13 @@ from hypothesis.strategies import sampled_from
9
9
  from pytest import mark, param
10
10
 
11
11
  from utilities.platform import SYSTEM
12
- from utilities.types import Number, PathLike, TDataclass, TimeZone
12
+ from utilities.types import Dataclass, Number, PathLike, TimeZone
13
13
  from utilities.typing import get_literal_elements
14
14
 
15
15
 
16
16
  class TestDataClassProtocol:
17
17
  def test_main(self) -> None:
18
- def identity(x: TDataclass, /) -> TDataclass:
18
+ def identity[T: Dataclass](x: T, /) -> T:
19
19
  return x
20
20
 
21
21
  @dataclass(kw_only=True, slots=True)
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.133.6"
3
+ __version__ = "0.134.0"