dycw-utilities 0.131.16__tar.gz → 0.131.17__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 (222) hide show
  1. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/PKG-INFO +1 -1
  2. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/pyproject.toml +2 -3
  3. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio.py +95 -96
  4. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio_classes/loopers.py +13 -12
  5. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio_classes/redis.py +7 -7
  6. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_atools.py +3 -3
  7. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_cachetools.py +2 -2
  8. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_fastapi.py +2 -1
  9. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pottery.py +33 -26
  10. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_psutil.py +3 -3
  11. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_redis.py +40 -35
  12. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_slack_sdk.py +17 -8
  13. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_sqlalchemy.py +11 -9
  14. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_timer.py +17 -35
  15. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/__init__.py +1 -1
  16. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/asyncio.py +47 -60
  17. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pottery.py +16 -19
  18. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/psutil.py +8 -7
  19. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/redis.py +108 -116
  20. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/slack_sdk.py +17 -18
  21. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/sqlalchemy.py +36 -30
  22. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/sqlalchemy_polars.py +12 -27
  23. dycw_utilities-0.131.16/src/tests/test_tenacity.py +0 -113
  24. dycw_utilities-0.131.16/src/utilities/tenacity.py +0 -145
  25. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/.gitignore +0 -0
  26. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/LICENSE +0 -0
  27. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/README.md +0 -0
  28. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/__init__.py +0 -0
  29. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/conftest.py +0 -0
  30. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/__init__.py +0 -0
  31. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_missing/__init__.py +0 -0
  32. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_missing/module.py +0 -0
  33. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/__init__.py +0 -0
  34. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/outer_1.py +0 -0
  35. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/outer_2.py +0 -0
  36. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  37. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  38. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  39. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  40. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_without/__init__.py +0 -0
  41. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_without/module_1.py +0 -0
  42. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_without/module_2.py +0 -0
  43. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/standalone.py +0 -0
  44. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/with_imports.py +0 -0
  45. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  46. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  47. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  48. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  49. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  50. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  51. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  52. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  53. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_aiolimiter.py +0 -0
  54. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_altair.py +0 -0
  55. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio_classes/__init__.py +0 -0
  56. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_atomicwrites.py +0 -0
  57. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_click.py +0 -0
  58. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_concurrent.py +0 -0
  59. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_contextlib.py +0 -0
  60. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_contextvars.py +0 -0
  61. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_cryptography.py +0 -0
  62. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_cvxpy.py +0 -0
  63. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_dataclasses.py +0 -0
  64. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_datetime.py +0 -0
  65. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_enum.py +0 -0
  66. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_errors.py +0 -0
  67. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_eventkit.py +0 -0
  68. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_fpdf2.py +0 -0
  69. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_functions.py +0 -0
  70. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_functools.py +0 -0
  71. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_getpass.py +0 -0
  72. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_git.py +0 -0
  73. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_hashlib.py +0 -0
  74. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_http.py +0 -0
  75. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_hypothesis.py +0 -0
  76. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_importlib.py +0 -0
  77. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_inflect.py +0 -0
  78. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_ipython.py +0 -0
  79. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_iterables.py +0 -0
  80. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_jupyter.py +0 -0
  81. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_libcst.py +0 -0
  82. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_lightweight_charts.py +0 -0
  83. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_logging.py +0 -0
  84. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_luigi.py +0 -0
  85. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_math.py +0 -0
  86. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_memory_profiler.py +0 -0
  87. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_modules.py +0 -0
  88. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_more_itertools.py +0 -0
  89. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_numpy.py +0 -0
  90. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_operator.py +0 -0
  91. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_optuna.py +0 -0
  92. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_orjson.py +0 -0
  93. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_os.py +0 -0
  94. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_parse.py +0 -0
  95. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pathlib.py +0 -0
  96. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_period.py +0 -0
  97. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pickle.py +0 -0
  98. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_platform.py +0 -0
  99. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_polars.py +0 -0
  100. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_polars_ols.py +0 -0
  101. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pqdm.py +0 -0
  102. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pydantic.py +0 -0
  103. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pyinstrument.py +0 -0
  104. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pyrsistent.py +0 -0
  105. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pytest.py +0 -0
  106. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pytest_regressions.py +0 -0
  107. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_python_dotenv.py +0 -0
  108. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_random.py +0 -0
  109. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_re.py +0 -0
  110. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_reprlib.py +0 -0
  111. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_scipy.py +0 -0
  112. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_sentinel.py +0 -0
  113. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_shelve.py +0 -0
  114. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_socket.py +0 -0
  115. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_sqlalchemy_polars.py +0 -0
  116. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_statsmodel.py +0 -0
  117. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_streamlit.py +0 -0
  118. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_string.py +0 -0
  119. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_tempfile.py +0 -0
  120. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_text.py +0 -0
  121. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_threading.py +0 -0
  122. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_traceback.py +0 -0
  123. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typed_settings.py +0 -0
  124. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_types.py +0 -0
  125. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typing.py +0 -0
  126. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typing_funcs/__init__.py +0 -0
  127. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typing_funcs/no_future.py +0 -0
  128. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typing_funcs/with_future.py +0 -0
  129. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_tzdata.py +0 -0
  130. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_tzlocal.py +0 -0
  131. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_uuid.py +0 -0
  132. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_version.py +0 -0
  133. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_warnings.py +0 -0
  134. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_whenever.py +0 -0
  135. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_whenever2.py +0 -0
  136. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_zipfile.py +0 -0
  137. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_zoneinfo.py +0 -0
  138. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/aiolimiter.py +0 -0
  139. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/altair.py +0 -0
  140. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/atomicwrites.py +0 -0
  141. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/atools.py +0 -0
  142. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/cachetools.py +0 -0
  143. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/click.py +0 -0
  144. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/concurrent.py +0 -0
  145. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/contextlib.py +0 -0
  146. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/contextvars.py +0 -0
  147. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/cryptography.py +0 -0
  148. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/cvxpy.py +0 -0
  149. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/dataclasses.py +0 -0
  150. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/datetime.py +0 -0
  151. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/enum.py +0 -0
  152. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/errors.py +0 -0
  153. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/eventkit.py +0 -0
  154. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/fastapi.py +0 -0
  155. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/fpdf2.py +0 -0
  156. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/functions.py +0 -0
  157. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/functools.py +0 -0
  158. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/getpass.py +0 -0
  159. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/git.py +0 -0
  160. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/hashlib.py +0 -0
  161. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/http.py +0 -0
  162. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/hypothesis.py +0 -0
  163. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/importlib.py +0 -0
  164. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/inflect.py +0 -0
  165. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/ipython.py +0 -0
  166. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/iterables.py +0 -0
  167. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/jupyter.py +0 -0
  168. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/libcst.py +0 -0
  169. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/lightweight_charts.py +0 -0
  170. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/logging.py +0 -0
  171. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/luigi.py +0 -0
  172. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/math.py +0 -0
  173. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/memory_profiler.py +0 -0
  174. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/modules.py +0 -0
  175. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/more_itertools.py +0 -0
  176. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/numpy.py +0 -0
  177. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/operator.py +0 -0
  178. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/optuna.py +0 -0
  179. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/orjson.py +0 -0
  180. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/os.py +0 -0
  181. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/parse.py +0 -0
  182. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pathlib.py +0 -0
  183. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/period.py +0 -0
  184. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pickle.py +0 -0
  185. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/platform.py +0 -0
  186. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/polars.py +0 -0
  187. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/polars_ols.py +0 -0
  188. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pqdm.py +0 -0
  189. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/py.typed +0 -0
  190. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pydantic.py +0 -0
  191. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pyinstrument.py +0 -0
  192. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pyrsistent.py +0 -0
  193. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pytest.py +0 -0
  194. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pytest_regressions.py +0 -0
  195. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/python_dotenv.py +0 -0
  196. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/random.py +0 -0
  197. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/re.py +0 -0
  198. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/reprlib.py +0 -0
  199. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/scipy.py +0 -0
  200. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/sentinel.py +0 -0
  201. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/shelve.py +0 -0
  202. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/socket.py +0 -0
  203. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/statsmodels.py +0 -0
  204. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/streamlit.py +0 -0
  205. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/string.py +0 -0
  206. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/tempfile.py +0 -0
  207. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/text.py +0 -0
  208. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/threading.py +0 -0
  209. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/timer.py +0 -0
  210. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/traceback.py +0 -0
  211. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/typed_settings.py +0 -0
  212. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/types.py +0 -0
  213. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/typing.py +0 -0
  214. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/tzdata.py +0 -0
  215. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/tzlocal.py +0 -0
  216. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/uuid.py +0 -0
  217. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/version.py +0 -0
  218. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/warnings.py +0 -0
  219. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/whenever.py +0 -0
  220. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/whenever2.py +0 -0
  221. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/zipfile.py +0 -0
  222. {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.131.16
3
+ Version: 0.131.17
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -59,7 +59,6 @@ dev = [
59
59
  "sqlalchemy >= 2.0.41, < 2.1",
60
60
  "statsmodels >= 0.14.4, < 0.15",
61
61
  "streamlit >= 1.45.0, < 1.46",
62
- "tenacity >= 8.5.0, < 9.0", # limited by luigi
63
62
  "tomlkit >= 0.13.2, < 0.14",
64
63
  "typed-settings >= 24.6.0, < 24.7",
65
64
  "tzdata >= 2025.2, < 2025.3",
@@ -95,7 +94,7 @@ dependencies = [
95
94
  name = "dycw-utilities"
96
95
  readme = "README.md"
97
96
  requires-python = ">= 3.12"
98
- version = "0.131.16"
97
+ version = "0.131.17"
99
98
 
100
99
  [project.optional-dependencies]
101
100
  logging = [
@@ -122,7 +121,7 @@ test = [
122
121
  # bump-my-version
123
122
  [tool.bumpversion]
124
123
  allow_dirty = true
125
- current_version = "0.131.16"
124
+ current_version = "0.131.17"
126
125
 
127
126
  [[tool.bumpversion.files]]
128
127
  filename = "src/utilities/__init__.py"
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from asyncio import Event, Queue, run, sleep, timeout
3
+ from asyncio import Event, Queue, run
4
4
  from collections import deque
5
5
  from contextlib import asynccontextmanager
6
6
  from dataclasses import dataclass, field
@@ -8,7 +8,7 @@ from itertools import chain
8
8
  from re import search
9
9
  from typing import TYPE_CHECKING, Any, ClassVar, Self, override
10
10
 
11
- from hypothesis import Phase, assume, given, settings
11
+ from hypothesis import assume, given
12
12
  from hypothesis.strategies import (
13
13
  DataObject,
14
14
  booleans,
@@ -49,27 +49,28 @@ from utilities.asyncio import (
49
49
  get_items_nowait,
50
50
  put_items,
51
51
  put_items_nowait,
52
- sleep_dur,
53
- sleep_max_dur,
52
+ sleep_max,
53
+ sleep_rounded,
54
+ sleep_td,
54
55
  sleep_until,
55
- sleep_until_rounded,
56
56
  stream_command,
57
- timeout_dur,
57
+ timeout_td,
58
58
  )
59
59
  from utilities.dataclasses import replace_non_sentinel
60
- from utilities.datetime import MILLISECOND, datetime_duration_to_timedelta, get_now
61
60
  from utilities.functions import get_class_name
62
61
  from utilities.hypothesis import sentinels, text_ascii
63
62
  from utilities.iterables import one, unique_everseen
64
63
  from utilities.pytest import skipif_windows
65
64
  from utilities.sentinel import Sentinel, sentinel
66
65
  from utilities.timer import Timer
66
+ from utilities.whenever2 import SECOND, get_now
67
67
 
68
68
  if TYPE_CHECKING:
69
- import datetime as dt
70
69
  from collections.abc import AsyncIterator
71
70
 
72
- from utilities.types import Duration, MaybeCallableEvent
71
+ from whenever import TimeDelta
72
+
73
+ from utilities.types import MaybeCallableEvent
73
74
 
74
75
 
75
76
  class TestEnhancedQueue:
@@ -144,6 +145,8 @@ class TestEnhancedQueue:
144
145
 
145
146
 
146
147
  class TestEnhancedTaskGroup:
148
+ delta: ClassVar[TimeDelta] = 0.05 * SECOND
149
+
147
150
  async def test_create_task_context_coroutine(self) -> None:
148
151
  flag: bool = False
149
152
 
@@ -157,43 +160,43 @@ class TestEnhancedTaskGroup:
157
160
  flag = False
158
161
 
159
162
  assert not flag
160
- async with EnhancedTaskGroup(timeout=0.1) as tg:
163
+ async with EnhancedTaskGroup(timeout=2 * self.delta) as tg:
161
164
  _ = tg.create_task_context(yield_true())
162
- await sleep(0.05)
165
+ await sleep_td(self.delta)
163
166
  assert flag
164
167
  assert not flag
165
168
 
166
169
  async def test_create_task_context_looper(self) -> None:
167
- looper = CountingLooper().replace(timeout=1.0)
170
+ looper = CountingLooper().replace(timeout=10 * self.delta)
168
171
  assert looper._core_attempts == 0
169
- async with EnhancedTaskGroup(timeout=0.1) as tg:
172
+ async with EnhancedTaskGroup(timeout=2 * self.delta) as tg:
170
173
  assert looper._core_attempts == 0
171
174
  _ = tg.create_task_context(looper)
172
- await sleep(0.05)
175
+ await sleep_td(self.delta)
173
176
  assert looper._core_attempts >= 1
174
177
 
175
178
  async def test_max_tasks_disabled(self) -> None:
176
179
  with Timer() as timer:
177
180
  async with EnhancedTaskGroup() as tg:
178
181
  for _ in range(10):
179
- _ = tg.create_task(sleep(0.01))
180
- assert timer.timedelta.in_seconds() <= 0.05
182
+ _ = tg.create_task(sleep_td(self.delta))
183
+ assert timer <= 2 * self.delta
181
184
 
182
185
  async def test_max_tasks_enabled(self) -> None:
183
186
  with Timer() as timer:
184
187
  async with EnhancedTaskGroup(max_tasks=2) as tg:
185
188
  for _ in range(10):
186
- _ = tg.create_task(sleep(0.01))
187
- assert timer.timedelta.in_seconds() >= 0.05
189
+ _ = tg.create_task(sleep_td(self.delta))
190
+ assert timer >= self.delta
188
191
 
189
192
  async def test_timeout_pass(self) -> None:
190
- async with EnhancedTaskGroup(timeout=0.2) as tg:
191
- _ = tg.create_task(sleep(0.1))
193
+ async with EnhancedTaskGroup(timeout=2 * self.delta) as tg:
194
+ _ = tg.create_task(sleep_td(self.delta))
192
195
 
193
196
  async def test_timeout_fail(self) -> None:
194
197
  with raises(ExceptionGroup) as exc_info:
195
- async with EnhancedTaskGroup(timeout=0.05) as tg:
196
- _ = tg.create_task(sleep(0.1))
198
+ async with EnhancedTaskGroup(timeout=self.delta) as tg:
199
+ _ = tg.create_task(sleep_td(2 * self.delta))
197
200
  assert len(exc_info.value.exceptions) == 1
198
201
  error = one(exc_info.value.exceptions)
199
202
  assert isinstance(error, TimeoutError)
@@ -202,8 +205,8 @@ class TestEnhancedTaskGroup:
202
205
  class CustomError(Exception): ...
203
206
 
204
207
  with raises(ExceptionGroup) as exc_info:
205
- async with EnhancedTaskGroup(timeout=0.05, error=CustomError) as tg:
206
- _ = tg.create_task(sleep(0.1))
208
+ async with EnhancedTaskGroup(timeout=self.delta, error=CustomError) as tg:
209
+ _ = tg.create_task(sleep_td(2 * self.delta))
207
210
  assert len(exc_info.value.exceptions) == 1
208
211
  error = one(exc_info.value.exceptions)
209
212
  assert isinstance(error, CustomError)
@@ -259,12 +262,8 @@ class TestGetItems:
259
262
 
260
263
 
261
264
  class TestLooper:
262
- _restart_min_elapsed: ClassVar[dt.timedelta] = datetime_duration_to_timedelta(
263
- (0.8 if IS_CI else 1.0) * _BACKOFF
264
- )
265
- _restart_max_elapsed: ClassVar[dt.timedelta] = datetime_duration_to_timedelta(
266
- (1.2 if IS_CI else 1.0) * _FREQ
267
- )
265
+ _restart_min_elapsed: ClassVar[TimeDelta] = (0.8 if IS_CI else 1.0) * _BACKOFF
266
+ _restart_max_elapsed: ClassVar[TimeDelta] = (1.2 if IS_CI else 1.0) * _FREQ
268
267
  skip_sleep_if_failure_cases: ClassVar[list[Any]] = [
269
268
  param(True, ""),
270
269
  param(False, "; sleeping for .*"),
@@ -279,12 +278,12 @@ class TestLooper:
279
278
  async def test_auto_start(self) -> None:
280
279
  looper = CountingLooper(auto_start=True)
281
280
  with raises(TimeoutError):
282
- async with timeout(1.0), looper:
281
+ async with timeout_td(SECOND), looper:
283
282
  ...
284
283
  self._assert_stats_full(looper)
285
284
 
286
285
  async def test_auto_start_and_timeout(self) -> None:
287
- looper = CountingLooper(auto_start=True, timeout=1.0)
286
+ looper = CountingLooper(auto_start=True, timeout=SECOND)
288
287
  async with looper:
289
288
  ...
290
289
  self._assert_stats_full(looper, stops=1)
@@ -298,7 +297,7 @@ class TestLooper:
298
297
  async def test_context_manager_already_entered(
299
298
  self, *, caplog: LogCaptureFixture
300
299
  ) -> None:
301
- looper = CountingLooper(timeout=1.0)
300
+ looper = CountingLooper(timeout=SECOND)
302
301
  async with looper, looper:
303
302
  ...
304
303
  _ = one(m for m in caplog.messages if search(": already entered$", m))
@@ -311,10 +310,10 @@ class TestLooper:
311
310
  assert not looper.empty()
312
311
 
313
312
  async def test_empty_upon_exit(self) -> None:
314
- looper = QueueLooper(freq=0.05, empty_upon_exit=True)
313
+ looper = QueueLooper(freq=0.05 * SECOND, empty_upon_exit=True)
315
314
  looper.put_right_nowait(0)
316
315
  assert not looper.empty()
317
- async with timeout(1.0), looper:
316
+ async with timeout_td(SECOND), looper:
318
317
  ...
319
318
  self._assert_stats_no_runs(looper, entries=1, stops=1)
320
319
  assert looper.empty()
@@ -322,7 +321,7 @@ class TestLooper:
322
321
  async def test_explicit_start(self) -> None:
323
322
  looper = CountingLooper()
324
323
  with raises(TimeoutError):
325
- async with timeout(1.0), looper:
324
+ async with timeout_td(SECOND), looper:
326
325
  await looper
327
326
  self._assert_stats_full(looper, stops=1)
328
327
 
@@ -373,11 +372,11 @@ class TestLooper:
373
372
  @mark.parametrize("counter_auto_start", [param(True), param(False)])
374
373
  async def test_mixin(self, *, counter_auto_start: bool) -> None:
375
374
  looper = LooperWithCounterMixin(
376
- auto_start=True, timeout=1.0, counter_auto_start=counter_auto_start
375
+ auto_start=True, timeout=SECOND, counter_auto_start=counter_auto_start
377
376
  )
378
377
  if counter_auto_start:
379
378
  with raises(TimeoutError):
380
- async with timeout(1.0), looper:
379
+ async with timeout_td(SECOND), looper:
381
380
  ...
382
381
  self._assert_stats_half(looper._counter)
383
382
  else:
@@ -388,7 +387,7 @@ class TestLooper:
388
387
  @mark.parametrize("counter_auto_start", [param(True), param(False)])
389
388
  async def test_mixin_in_task_group(self, *, counter_auto_start: bool) -> None:
390
389
  looper = LooperWithCounterMixin(
391
- auto_start=True, timeout=1.0, counter_auto_start=counter_auto_start
390
+ auto_start=True, timeout=SECOND, counter_auto_start=counter_auto_start
392
391
  )
393
392
  with raises(ExceptionGroup) as exc_info:
394
393
  async with EnhancedTaskGroup(timeout=looper.timeout) as tg:
@@ -404,21 +403,21 @@ class TestLooper:
404
403
  ) -> None:
405
404
  looper = LooperWithCounterMixins(
406
405
  auto_start=True,
407
- timeout=1.0,
406
+ timeout=SECOND,
408
407
  counter1_auto_start=counter1_auto_start,
409
408
  counter2_auto_start=counter2_auto_start,
410
409
  )
411
410
  match counter1_auto_start, counter2_auto_start:
412
411
  case _, True:
413
412
  with raises(TimeoutError):
414
- async with timeout(1.0), looper:
413
+ async with timeout_td(SECOND), looper:
415
414
  ...
416
415
  assert_looper_full(looper)
417
416
  self._assert_stats_no_runs(looper._counter1)
418
417
  self._assert_stats_third(looper._counter2)
419
418
  case True, False:
420
419
  with raises(TimeoutError):
421
- async with timeout(1.0), looper:
420
+ async with timeout_td(SECOND), looper:
422
421
  ...
423
422
  assert_looper_full(looper)
424
423
  self._assert_stats_half(looper._counter1)
@@ -433,13 +432,13 @@ class TestLooper:
433
432
  @mark.parametrize("counter_auto_start", [param(True), param(False)])
434
433
  async def test_mixins_in_task_group(self, *, counter_auto_start: bool) -> None:
435
434
  looper1 = LooperWithCounterMixin(
436
- auto_start=True, timeout=1.0, counter_auto_start=counter_auto_start
435
+ auto_start=True, timeout=SECOND, counter_auto_start=counter_auto_start
437
436
  )
438
437
  looper2 = LooperWithCounterMixin(
439
- auto_start=True, timeout=1.0, counter_auto_start=counter_auto_start
438
+ auto_start=True, timeout=SECOND, counter_auto_start=counter_auto_start
440
439
  )
441
440
  with raises(ExceptionGroup) as exc_info: # noqa: PT012
442
- async with EnhancedTaskGroup(timeout=1.0) as tg:
441
+ async with EnhancedTaskGroup(timeout=SECOND) as tg:
443
442
  _ = tg.create_task_context(looper1)
444
443
  _ = tg.create_task_context(looper2)
445
444
  errors = exc_info.value.exceptions
@@ -450,8 +449,8 @@ class TestLooper:
450
449
  self._assert_stats_half(looper2._counter)
451
450
 
452
451
  def test_replace(self) -> None:
453
- looper = CountingLooper().replace(freq=10.0)
454
- assert looper.freq == 10.0
452
+ looper = CountingLooper().replace(freq=10 * SECOND)
453
+ assert looper.freq == 10 * SECOND
455
454
 
456
455
  async def test_request_back_off(self) -> None:
457
456
  class Example(CountingLooper):
@@ -463,7 +462,7 @@ class TestLooper:
463
462
  ):
464
463
  self.request_back_off()
465
464
 
466
- looper = Example(auto_start=True, timeout=1.0)
465
+ looper = Example(auto_start=True, timeout=SECOND)
467
466
  async with looper:
468
467
  ...
469
468
  assert_looper_stats(
@@ -497,7 +496,7 @@ class TestLooper:
497
496
  ):
498
497
  self.request_restart()
499
498
 
500
- looper = Example(auto_start=True, timeout=1.0)
499
+ looper = Example(auto_start=True, timeout=SECOND)
501
500
  async with looper:
502
501
  ...
503
502
  assert_looper_stats(
@@ -531,7 +530,7 @@ class TestLooper:
531
530
  ):
532
531
  self.request_stop()
533
532
 
534
- looper = Example(auto_start=True, timeout=1.0)
533
+ looper = Example(auto_start=True, timeout=SECOND)
535
534
  async with looper:
536
535
  ...
537
536
  assert_looper_stats(
@@ -565,7 +564,7 @@ class TestLooper:
565
564
  _ = self.get_right_nowait()
566
565
  self.request_stop_when_empty()
567
566
 
568
- looper = Example(auto_start=True, timeout=1.0)
567
+ looper = Example(auto_start=True, timeout=SECOND)
569
568
  for i in range(25):
570
569
  match i % 2 == 0:
571
570
  case True:
@@ -610,7 +609,7 @@ class TestLooper:
610
609
  looper = Example()
611
610
  with Timer() as timer:
612
611
  await looper.restart()
613
- assert timer.timedelta.py_timedelta() >= self._restart_min_elapsed
612
+ assert timer >= self._restart_min_elapsed
614
613
  pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) whilst restarting \(initialize\); sleeping for .*\.\.\.$"
615
614
  _ = one(m for m in caplog.messages if search(pattern, m))
616
615
 
@@ -627,7 +626,7 @@ class TestLooper:
627
626
  looper = Example()
628
627
  with Timer() as timer:
629
628
  await looper.restart()
630
- assert timer.timedelta.py_timedelta() >= self._restart_min_elapsed
629
+ assert timer >= self._restart_min_elapsed
631
630
  pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) whilst restarting \(tear down\); sleeping for .*\.\.\.$"
632
631
  _ = one(m for m in caplog.messages if search(pattern, m))
633
632
 
@@ -650,7 +649,7 @@ class TestLooper:
650
649
  looper = Example()
651
650
  with Timer() as timer:
652
651
  await looper.restart()
653
- assert timer.timedelta.py_timedelta() >= self._restart_min_elapsed
652
+ assert timer >= self._restart_min_elapsed
654
653
  pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) \(tear down\) and then {get_class_name(CountingLooperError)}\(\) \(initialization\) whilst restarting; sleeping for .*\.\.\.$"
655
654
  _ = one(m for m in caplog.messages if search(pattern, m))
656
655
 
@@ -658,26 +657,26 @@ class TestLooper:
658
657
  looper = CountingLooper()
659
658
  with Timer() as timer:
660
659
  await looper.restart()
661
- assert timer.timedelta.py_timedelta() <= self._restart_max_elapsed
660
+ assert timer <= self._restart_max_elapsed
662
661
  pattern = r": finished restarting$"
663
662
  _ = one(m for m in caplog.messages if search(pattern, m))
664
663
 
665
664
  @mark.parametrize("n", [param(0), param(1), param(2)])
666
665
  async def test_run_until_empty(self, *, n: int) -> None:
667
- looper = QueueLooper(freq=0.05)
666
+ looper = QueueLooper(freq=0.05 * SECOND)
668
667
  looper.put_right_nowait(*range(n))
669
- async with timeout(1.0), looper:
668
+ async with timeout_td(SECOND), looper:
670
669
  await looper.run_until_empty()
671
670
  assert looper.empty()
672
671
 
673
672
  @mark.parametrize("inner_auto_start", [param(True), param(False)])
674
673
  async def test_sub_looper_one(self, *, inner_auto_start: bool) -> None:
675
674
  looper = OuterCountingLooper(
676
- auto_start=True, timeout=1.0, inner_auto_start=inner_auto_start
675
+ auto_start=True, timeout=SECOND, inner_auto_start=inner_auto_start
677
676
  )
678
677
  if inner_auto_start:
679
678
  with raises(TimeoutError):
680
- async with timeout(1.0), looper:
679
+ async with timeout_td(SECOND), looper:
681
680
  ...
682
681
  self._assert_stats_full(looper)
683
682
  self._assert_stats_half(looper.inner)
@@ -694,21 +693,21 @@ class TestLooper:
694
693
  ) -> None:
695
694
  looper = MultipleSubLoopers(
696
695
  auto_start=True,
697
- timeout=1.0,
696
+ timeout=SECOND,
698
697
  inner1_auto_start=inner1_auto_start,
699
698
  inner2_auto_start=inner2_auto_start,
700
699
  )
701
700
  match inner1_auto_start, inner2_auto_start:
702
701
  case True, _:
703
702
  with raises(TimeoutError):
704
- async with timeout(1.0), looper:
703
+ async with timeout_td(SECOND), looper:
705
704
  ...
706
705
  self._assert_stats_full(looper)
707
706
  self._assert_stats_half(looper.inner1)
708
707
  self._assert_stats_no_runs(looper.inner2)
709
708
  case False, True:
710
709
  with raises(TimeoutError):
711
- async with timeout(1.0), looper:
710
+ async with timeout_td(SECOND), looper:
712
711
  ...
713
712
  self._assert_stats_full(looper)
714
713
  self._assert_stats_half(looper.inner1)
@@ -727,7 +726,7 @@ class TestLooper:
727
726
  ) -> None:
728
727
  looper = Outer2CountingLooper(
729
728
  auto_start=True,
730
- timeout=1.0,
729
+ timeout=SECOND,
731
730
  middle_auto_start=middle_auto_start,
732
731
  inner_auto_start=inner_auto_start,
733
732
  )
@@ -740,7 +739,7 @@ class TestLooper:
740
739
  self._assert_stats_quarter(looper.middle.inner, stops=1)
741
740
  case _, _:
742
741
  with raises(TimeoutError):
743
- async with timeout(1.0), looper:
742
+ async with timeout_td(SECOND), looper:
744
743
  ...
745
744
  self._assert_stats_full(looper)
746
745
  self._assert_stats_half(looper.middle)
@@ -777,7 +776,7 @@ class TestLooper:
777
776
  _ = one(m for m in caplog.messages if search(pattern, m))
778
777
 
779
778
  async def test_timeout(self) -> None:
780
- looper = CountingLooper(timeout=1.0)
779
+ looper = CountingLooper(timeout=SECOND)
781
780
  with Timer() as timer:
782
781
  async with looper:
783
782
  await looper
@@ -905,55 +904,53 @@ class TestUniqueQueue:
905
904
  assert queue._set == set()
906
905
 
907
906
 
908
- class TestSleepDur:
909
- @given(duration=sampled_from([0.1, 10 * MILLISECOND]))
910
- @settings(phases={Phase.generate})
911
- async def test_main(self, *, duration: Duration) -> None:
907
+ class TestSleepMaxDur:
908
+ delta: ClassVar[TimeDelta] = 0.05 * SECOND
909
+
910
+ async def test_main(self) -> None:
912
911
  with Timer() as timer:
913
- await sleep_dur(duration=duration)
914
- assert timer.timedelta.py_timedelta() <= datetime_duration_to_timedelta(
915
- 2 * duration
916
- )
912
+ await sleep_max(self.delta)
913
+ assert timer <= 2 * self.delta
917
914
 
918
915
  async def test_none(self) -> None:
919
916
  with Timer() as timer:
920
- await sleep_dur()
921
- assert timer.timedelta.in_seconds() <= 0.01
917
+ await sleep_max()
918
+ assert timer <= self.delta
922
919
 
923
920
 
924
- class TestSleepMaxDur:
925
- @given(duration=sampled_from([0.1, 10 * MILLISECOND]))
926
- @settings(phases={Phase.generate})
927
- async def test_main(self, *, duration: Duration) -> None:
921
+ class TestSleepTD:
922
+ delta: ClassVar[TimeDelta] = 0.05 * SECOND
923
+
924
+ async def test_main(self) -> None:
928
925
  with Timer() as timer:
929
- await sleep_max_dur(duration=duration)
930
- assert timer.timedelta.py_timedelta() <= datetime_duration_to_timedelta(
931
- 2 * duration
932
- )
926
+ await sleep_td(self.delta)
927
+ assert timer <= 2 * self.delta
933
928
 
934
929
  async def test_none(self) -> None:
935
930
  with Timer() as timer:
936
- await sleep_max_dur()
937
- assert timer.timedelta.in_seconds() <= 0.01
931
+ await sleep_td()
932
+ assert timer <= self.delta
938
933
 
939
934
 
940
935
  class TestSleepUntil:
941
936
  async def test_main(self) -> None:
942
- await sleep_until(get_now() + 10 * MILLISECOND)
937
+ await sleep_until(get_now() + 0.05 * SECOND)
943
938
 
944
939
 
945
940
  class TestSleepUntilRounded:
946
941
  async def test_main(self) -> None:
947
- await sleep_until_rounded(10 * MILLISECOND)
942
+ await sleep_rounded(unit="millisecond", increment=10)
948
943
 
949
944
 
950
945
  class TestStreamCommand:
946
+ delta: ClassVar[TimeDelta] = 0.05 * SECOND
947
+
951
948
  @skipif_windows
952
949
  async def test_main(self) -> None:
953
950
  output = await stream_command(
954
951
  'echo "stdout message" && sleep 0.1 && echo "stderr message" >&2'
955
952
  )
956
- await sleep(0.01)
953
+ await sleep_td(self.delta)
957
954
  assert output.return_code == 0
958
955
  assert output.stdout == "stdout message\n"
959
956
  assert output.stderr == "stderr message\n"
@@ -961,7 +958,7 @@ class TestStreamCommand:
961
958
  @skipif_windows
962
959
  async def test_error(self) -> None:
963
960
  output = await stream_command("this-is-an-error")
964
- await sleep(0.01)
961
+ await sleep_td(self.delta)
965
962
  assert output.return_code == 127
966
963
  assert output.stdout == ""
967
964
  assert search(
@@ -969,22 +966,24 @@ class TestStreamCommand:
969
966
  )
970
967
 
971
968
 
972
- class TestTimeoutDur:
969
+ class TestTimeoutTD:
970
+ delta: ClassVar[TimeDelta] = 0.05 * SECOND
971
+
973
972
  async def test_pass(self) -> None:
974
- async with timeout_dur(duration=0.2):
975
- await sleep(0.1)
973
+ async with timeout_td(2 * self.delta):
974
+ await sleep_td(self.delta)
976
975
 
977
976
  async def test_fail(self) -> None:
978
977
  with raises(TimeoutError):
979
- async with timeout_dur(duration=0.05):
980
- await sleep(0.1)
978
+ async with timeout_td(self.delta):
979
+ await sleep_td(2 * self.delta)
981
980
 
982
981
  async def test_custom_error(self) -> None:
983
982
  class CustomError(Exception): ...
984
983
 
985
984
  with raises(CustomError):
986
- async with timeout_dur(duration=0.05, error=CustomError):
987
- await sleep(0.1)
985
+ async with timeout_td(self.delta, error=CustomError):
986
+ await sleep_td(2 * self.delta)
988
987
 
989
988
 
990
989
  if __name__ == "__main__":
@@ -8,15 +8,16 @@ from pytest import approx
8
8
  from tests.conftest import IS_CI
9
9
  from utilities.asyncio import Looper
10
10
  from utilities.contextlib import suppress_super_object_attribute_error
11
- from utilities.datetime import MILLISECOND
11
+ from utilities.whenever2 import SECOND
12
12
 
13
13
  if TYPE_CHECKING:
14
14
  from collections.abc import Iterator
15
15
 
16
- from utilities.types import Duration
16
+ from whenever import TimeDelta
17
17
 
18
- _FREQ: Duration = 10 * MILLISECOND
19
- _BACKOFF: Duration = 100 * MILLISECOND
18
+
19
+ _FREQ: TimeDelta = 0.01 * SECOND
20
+ _BACKOFF: TimeDelta = 0.1 * SECOND
20
21
  _REL: float = 2.0 if IS_CI else 0.25
21
22
 
22
23
 
@@ -102,8 +103,8 @@ def assert_looper_full(
102
103
 
103
104
  @dataclass(kw_only=True)
104
105
  class CountingLooper(Looper[Any]):
105
- freq: Duration = field(default=_FREQ, repr=False)
106
- backoff: Duration = field(default=_BACKOFF, repr=False)
106
+ freq: TimeDelta = field(default=_FREQ, repr=False)
107
+ backoff: TimeDelta = field(default=_BACKOFF, repr=False)
107
108
  _debug: bool = field(default=True, repr=False)
108
109
  count: int = 0
109
110
  max_count: int = 10
@@ -212,8 +213,8 @@ class Outer2CountingLooper(CountingLooper):
212
213
 
213
214
  @dataclass(kw_only=True)
214
215
  class CounterMixin:
215
- freq: Duration = field(default=_FREQ, repr=False)
216
- backoff: Duration = field(default=_BACKOFF, repr=False)
216
+ freq: TimeDelta = field(default=_FREQ, repr=False)
217
+ backoff: TimeDelta = field(default=_BACKOFF, repr=False)
217
218
  _debug: bool = field(default=True, repr=False)
218
219
  count: int = 0
219
220
  max_count: int = 10
@@ -245,8 +246,8 @@ class LooperWithCounterMixin(CounterMixin, Looper): ...
245
246
 
246
247
  @dataclass(kw_only=True)
247
248
  class CounterMixin1:
248
- freq: Duration = field(default=_FREQ, repr=False)
249
- backoff: Duration = field(default=_BACKOFF, repr=False)
249
+ freq: TimeDelta = field(default=_FREQ, repr=False)
250
+ backoff: TimeDelta = field(default=_BACKOFF, repr=False)
250
251
  _debug: bool = field(default=True, repr=False)
251
252
  count: int = 0
252
253
  max_count: int = 10
@@ -271,8 +272,8 @@ class CounterMixin1:
271
272
 
272
273
  @dataclass(kw_only=True)
273
274
  class CounterMixin2:
274
- freq: Duration = field(default=_FREQ, repr=False)
275
- backoff: Duration = field(default=_BACKOFF, repr=False)
275
+ freq: TimeDelta = field(default=_FREQ, repr=False)
276
+ backoff: TimeDelta = field(default=_BACKOFF, repr=False)
276
277
  _debug: bool = field(default=True, repr=False)
277
278
  count: int = 0
278
279
  max_count: int = 10
@@ -9,20 +9,20 @@ from utilities.redis import PublishServiceMixin, SubscribeServiceMixin
9
9
  from utilities.text import unique_str
10
10
 
11
11
  if TYPE_CHECKING:
12
- from utilities.types import Duration
12
+ from whenever import TimeDelta
13
13
 
14
14
 
15
15
  @dataclass(kw_only=True)
16
16
  class LooperWithPublishAndSubscribeMixins(
17
17
  PublishServiceMixin[Any], SubscribeServiceMixin[Any], Looper[Any]
18
18
  ):
19
- freq: Duration = field(default=_FREQ, repr=False)
20
- backoff: Duration = field(default=_BACKOFF, repr=False)
19
+ freq: TimeDelta = field(default=_FREQ, repr=False)
20
+ backoff: TimeDelta = field(default=_BACKOFF, repr=False)
21
21
  _debug: bool = field(default=True, repr=False)
22
- publish_service_freq: Duration = field(default=_FREQ, repr=False)
23
- publish_service_backoff: Duration = field(default=_BACKOFF, repr=False)
22
+ publish_service_freq: TimeDelta = field(default=_FREQ, repr=False)
23
+ publish_service_backoff: TimeDelta = field(default=_BACKOFF, repr=False)
24
24
  publish_service_debug: bool = field(default=True, repr=False)
25
- subscribe_service_freq: Duration = field(default=_FREQ, repr=False)
26
- subscribe_service_backoff: Duration = field(default=_BACKOFF, repr=False)
25
+ subscribe_service_freq: TimeDelta = field(default=_FREQ, repr=False)
26
+ subscribe_service_backoff: TimeDelta = field(default=_BACKOFF, repr=False)
27
27
  subscribe_service_debug: bool = field(default=True, repr=False)
28
28
  subscribe_service_channel: str = field(default_factory=unique_str)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from utilities.asyncio import sleep_dur
3
+ from utilities.asyncio import sleep_td
4
4
  from utilities.atools import call_memoized
5
5
  from utilities.whenever2 import SECOND
6
6
 
@@ -20,7 +20,7 @@ class TestCallMemoized:
20
20
 
21
21
  async def test_refresh(self) -> None:
22
22
  counter = 0
23
- delta = 0.05 * SECOND
23
+ delta = 0.1 * SECOND
24
24
 
25
25
  async def increment() -> int:
26
26
  nonlocal counter
@@ -30,7 +30,7 @@ class TestCallMemoized:
30
30
  for _ in range(2):
31
31
  assert (await call_memoized(increment, delta)) == 1
32
32
  assert counter == 1
33
- await sleep_dur(duration=2 * delta)
33
+ await sleep_td(2 * delta)
34
34
  for _ in range(2):
35
35
  assert (await call_memoized(increment, delta)) == 2
36
36
  assert counter == 2