dycw-utilities 0.125.11__tar.gz → 0.125.13__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 (223) hide show
  1. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/PKG-INFO +5 -5
  2. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/pyproject.toml +10 -10
  3. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_asyncio.py +428 -2
  4. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/__init__.py +1 -1
  5. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/asyncio.py +473 -9
  6. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/.gitignore +0 -0
  7. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/LICENSE +0 -0
  8. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/README.md +0 -0
  9. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/__init__.py +0 -0
  10. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/conftest.py +0 -0
  11. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/__init__.py +0 -0
  12. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_missing/__init__.py +0 -0
  13. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_missing/module.py +0 -0
  14. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_with/__init__.py +0 -0
  15. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_with/outer_1.py +0 -0
  16. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_with/outer_2.py +0 -0
  17. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  18. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  19. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  20. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  21. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_without/__init__.py +0 -0
  22. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_without/module_1.py +0 -0
  23. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/package_without/module_2.py +0 -0
  24. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/standalone.py +0 -0
  25. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/modules/with_imports.py +0 -0
  26. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  27. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  28. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  29. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  30. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  31. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  32. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  33. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  34. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_altair.py +0 -0
  35. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_atomicwrites.py +0 -0
  36. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_atools.py +0 -0
  37. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_cachetools.py +0 -0
  38. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_click.py +0 -0
  39. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_concurrent.py +0 -0
  40. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_contextlib.py +0 -0
  41. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_contextvars.py +0 -0
  42. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_cryptography.py +0 -0
  43. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_cvxpy.py +0 -0
  44. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_dataclasses.py +0 -0
  45. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_datetime.py +0 -0
  46. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_enum.py +0 -0
  47. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_errors.py +0 -0
  48. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_eventkit.py +0 -0
  49. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_fastapi.py +0 -0
  50. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_fpdf2.py +0 -0
  51. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_functions.py +0 -0
  52. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_functools.py +0 -0
  53. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_getpass.py +0 -0
  54. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_git.py +0 -0
  55. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_hashlib.py +0 -0
  56. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_http.py +0 -0
  57. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_hypothesis.py +0 -0
  58. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_importlib.py +0 -0
  59. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_ipython.py +0 -0
  60. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_iterables.py +0 -0
  61. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_jupyter.py +0 -0
  62. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_libcst.py +0 -0
  63. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_lightweight_charts.py +0 -0
  64. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_logging.py +0 -0
  65. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_loguru.py +0 -0
  66. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_luigi.py +0 -0
  67. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_math.py +0 -0
  68. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_memory_profiler.py +0 -0
  69. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_modules.py +0 -0
  70. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_more_itertools.py +0 -0
  71. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_numpy.py +0 -0
  72. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_operator.py +0 -0
  73. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_optuna.py +0 -0
  74. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_orjson.py +0 -0
  75. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_os.py +0 -0
  76. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_parse.py +0 -0
  77. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_pathlib.py +0 -0
  78. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_period.py +0 -0
  79. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_pickle.py +0 -0
  80. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_platform.py +0 -0
  81. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_polars.py +0 -0
  82. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_polars_ols.py +0 -0
  83. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_pqdm.py +0 -0
  84. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_pydantic.py +0 -0
  85. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_pyinstrument.py +0 -0
  86. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_pyrsistent.py +0 -0
  87. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_pytest.py +0 -0
  88. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_pytest_regressions.py +0 -0
  89. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_python_dotenv.py +0 -0
  90. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_random.py +0 -0
  91. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_re.py +0 -0
  92. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_redis.py +0 -0
  93. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_reprlib.py +0 -0
  94. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_rich.py +0 -0
  95. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_scipy.py +0 -0
  96. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_sentinel.py +0 -0
  97. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_shelve.py +0 -0
  98. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_slack_sdk.py +0 -0
  99. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_socket.py +0 -0
  100. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_sqlalchemy.py +0 -0
  101. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_sqlalchemy_polars.py +0 -0
  102. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_statsmodel.py +0 -0
  103. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_streamlit.py +0 -0
  104. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_sys.py +0 -0
  105. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_tempfile.py +0 -0
  106. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_tenacity.py +0 -0
  107. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_text.py +0 -0
  108. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_threading.py +0 -0
  109. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_timer.py +0 -0
  110. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback.py +0 -0
  111. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/__init__.py +0 -0
  112. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/chain.py +0 -0
  113. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  114. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  115. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  116. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/many.py +0 -0
  117. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/one.py +0 -0
  118. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/recursive.py +0 -0
  119. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  120. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  121. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/two.py +0 -0
  122. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_traceback_funcs/untraced.py +0 -0
  123. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_types.py +0 -0
  124. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_typing.py +0 -0
  125. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_typing_funcs/__init__.py +0 -0
  126. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_typing_funcs/no_future.py +0 -0
  127. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_typing_funcs/with_future.py +0 -0
  128. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_tzdata.py +0 -0
  129. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_tzlocal.py +0 -0
  130. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_uuid.py +0 -0
  131. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_version.py +0 -0
  132. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_warnings.py +0 -0
  133. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_whenever.py +0 -0
  134. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_zipfile.py +0 -0
  135. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/tests/test_zoneinfo.py +0 -0
  136. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/altair.py +0 -0
  137. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/atomicwrites.py +0 -0
  138. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/atools.py +0 -0
  139. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/cachetools.py +0 -0
  140. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/click.py +0 -0
  141. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/concurrent.py +0 -0
  142. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/contextlib.py +0 -0
  143. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/contextvars.py +0 -0
  144. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/cryptography.py +0 -0
  145. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/cvxpy.py +0 -0
  146. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/dataclasses.py +0 -0
  147. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/datetime.py +0 -0
  148. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/enum.py +0 -0
  149. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/errors.py +0 -0
  150. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/eventkit.py +0 -0
  151. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/fastapi.py +0 -0
  152. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/fpdf2.py +0 -0
  153. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/functions.py +0 -0
  154. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/functools.py +0 -0
  155. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/getpass.py +0 -0
  156. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/git.py +0 -0
  157. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/hashlib.py +0 -0
  158. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/http.py +0 -0
  159. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/hypothesis.py +0 -0
  160. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/importlib.py +0 -0
  161. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/ipython.py +0 -0
  162. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/iterables.py +0 -0
  163. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/jupyter.py +0 -0
  164. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/libcst.py +0 -0
  165. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/lightweight_charts.py +0 -0
  166. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/logging.py +0 -0
  167. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/loguru.py +0 -0
  168. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/luigi.py +0 -0
  169. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/math.py +0 -0
  170. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/memory_profiler.py +0 -0
  171. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/modules.py +0 -0
  172. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/more_itertools.py +0 -0
  173. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/numpy.py +0 -0
  174. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/operator.py +0 -0
  175. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/optuna.py +0 -0
  176. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/orjson.py +0 -0
  177. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/os.py +0 -0
  178. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/parse.py +0 -0
  179. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/pathlib.py +0 -0
  180. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/period.py +0 -0
  181. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/pickle.py +0 -0
  182. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/platform.py +0 -0
  183. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/polars.py +0 -0
  184. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/polars_ols.py +0 -0
  185. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/pqdm.py +0 -0
  186. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/py.typed +0 -0
  187. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/pydantic.py +0 -0
  188. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/pyinstrument.py +0 -0
  189. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/pyrsistent.py +0 -0
  190. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/pytest.py +0 -0
  191. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/pytest_regressions.py +0 -0
  192. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/python_dotenv.py +0 -0
  193. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/random.py +0 -0
  194. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/re.py +0 -0
  195. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/redis.py +0 -0
  196. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/reprlib.py +0 -0
  197. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/rich.py +0 -0
  198. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/scipy.py +0 -0
  199. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/sentinel.py +0 -0
  200. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/shelve.py +0 -0
  201. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/slack_sdk.py +0 -0
  202. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/socket.py +0 -0
  203. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/sqlalchemy.py +0 -0
  204. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/sqlalchemy_polars.py +0 -0
  205. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/statsmodels.py +0 -0
  206. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/streamlit.py +0 -0
  207. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/sys.py +0 -0
  208. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/tempfile.py +0 -0
  209. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/tenacity.py +0 -0
  210. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/text.py +0 -0
  211. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/threading.py +0 -0
  212. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/timer.py +0 -0
  213. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/traceback.py +0 -0
  214. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/types.py +0 -0
  215. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/typing.py +0 -0
  216. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/tzdata.py +0 -0
  217. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/tzlocal.py +0 -0
  218. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/uuid.py +0 -0
  219. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/version.py +0 -0
  220. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/warnings.py +0 -0
  221. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/whenever.py +0 -0
  222. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/zipfile.py +0 -0
  223. {dycw_utilities-0.125.11 → dycw_utilities-0.125.13}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.125.11
3
+ Version: 0.125.13
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -25,7 +25,7 @@ Requires-Dist: altair<5.6,>=5.5.0; extra == 'zzz-test-altair'
25
25
  Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-altair'
26
26
  Requires-Dist: img2pdf<0.7,>=0.6.0; extra == 'zzz-test-altair'
27
27
  Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-altair'
28
- Requires-Dist: vl-convert-python<1.8,>=1.7.0; extra == 'zzz-test-altair'
28
+ Requires-Dist: vl-convert-python<1.9,>=1.8.0; extra == 'zzz-test-altair'
29
29
  Requires-Dist: whenever<0.9,>=0.8.4; extra == 'zzz-test-altair'
30
30
  Provides-Extra: zzz-test-asyncio
31
31
  Provides-Extra: zzz-test-atomicwrites
@@ -82,7 +82,7 @@ Requires-Dist: hypothesis<6.132,>=6.131.30; extra == 'zzz-test-hypothesis'
82
82
  Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-hypothesis'
83
83
  Requires-Dist: numpy<2.3,>=2.2.6; extra == 'zzz-test-hypothesis'
84
84
  Requires-Dist: pathvalidate<3.3,>=3.2.3; extra == 'zzz-test-hypothesis'
85
- Requires-Dist: redis<6.2,>=6.1.0; extra == 'zzz-test-hypothesis'
85
+ Requires-Dist: redis<6.3,>=6.2.0; extra == 'zzz-test-hypothesis'
86
86
  Requires-Dist: sqlalchemy<2.1,>=2.0.41; extra == 'zzz-test-hypothesis'
87
87
  Requires-Dist: tenacity<9.0,>=8.5.0; extra == 'zzz-test-hypothesis'
88
88
  Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-hypothesis'
@@ -162,7 +162,7 @@ Provides-Extra: zzz-test-re
162
162
  Provides-Extra: zzz-test-redis
163
163
  Requires-Dist: orjson<3.11,>=3.10.15; extra == 'zzz-test-redis'
164
164
  Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-redis'
165
- Requires-Dist: redis<6.2,>=6.1.0; extra == 'zzz-test-redis'
165
+ Requires-Dist: redis<6.3,>=6.2.0; extra == 'zzz-test-redis'
166
166
  Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-redis'
167
167
  Requires-Dist: tenacity<9.0,>=8.5.0; extra == 'zzz-test-redis'
168
168
  Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-redis'
@@ -174,7 +174,7 @@ Requires-Dist: scipy<1.16,>=1.15.3; extra == 'zzz-test-scipy'
174
174
  Provides-Extra: zzz-test-sentinel
175
175
  Provides-Extra: zzz-test-shelve
176
176
  Provides-Extra: zzz-test-slack-sdk
177
- Requires-Dist: aiohttp<3.12.3,>=3.12.2; extra == 'zzz-test-slack-sdk'
177
+ Requires-Dist: aiohttp<3.12.5,>=3.12.4; extra == 'zzz-test-slack-sdk'
178
178
  Requires-Dist: slack-sdk<3.36,>=3.35.0; extra == 'zzz-test-slack-sdk'
179
179
  Provides-Extra: zzz-test-socket
180
180
  Provides-Extra: zzz-test-sqlalchemy
@@ -8,7 +8,7 @@ requires = ["hatchling"]
8
8
  # dependency groups
9
9
  [dependency-groups]
10
10
  dev = [
11
- "aiohttp >= 3.12.2, < 3.12.3", # for slack
11
+ "aiohttp >= 3.12.4, < 3.12.5", # for slack
12
12
  "aiosqlite >= 0.21.0, < 0.22",
13
13
  "altair >= 5.5.0, < 5.6",
14
14
  "asyncpg >= 0.30.0, < 0.31", # for sqlalchemy async
@@ -35,7 +35,7 @@ dev = [
35
35
  "nest-asyncio >= 1.6.0, < 1.7", # for sqlalchemy async
36
36
  "nox >= 2025.2.9, < 2025.3",
37
37
  "numpy >= 2.2.6, < 2.3",
38
- "libcst >= 1.7.0, < 1.8",
38
+ "libcst >= 1.8.0, < 1.9",
39
39
  "optuna >= 4.3.0, < 4.4",
40
40
  "orjson >= 3.10.18, < 3.11",
41
41
  "pathvalidate >= 3.2.3, < 3.3",
@@ -50,7 +50,7 @@ dev = [
50
50
  "pytest >= 8.3.5, < 8.4",
51
51
  "pytest-regressions >= 2.7.0, < 2.8",
52
52
  "python-dotenv >= 1.1.0, < 1.2",
53
- "redis >= 6.1.0, < 6.2",
53
+ "redis >= 6.2.0, < 6.3",
54
54
  "rich >= 14.0.0, < 14.1",
55
55
  "scikit-learn >= 1.6.1, < 1.7",
56
56
  "scipy >= 1.15.3, < 1.16",
@@ -65,7 +65,7 @@ dev = [
65
65
  "uvicorn >= 0.34.1, < 0.35",
66
66
  "vegafusion >= 2.0.2, < 2.1",
67
67
  "vegafusion-python-embed >= 1.6.9, < 1.7",
68
- "vl-convert-python >= 1.7.0, < 1.8",
68
+ "vl-convert-python >= 1.8.0, < 1.9",
69
69
  "whenever >= 0.8.4, < 0.9",
70
70
  # test
71
71
  "coverage-conditional-plugin >= 0.9.0, < 0.10",
@@ -93,7 +93,7 @@ dependencies = [
93
93
  name = "dycw-utilities"
94
94
  readme = "README.md"
95
95
  requires-python = ">= 3.12"
96
- version = "0.125.11"
96
+ version = "0.125.13"
97
97
 
98
98
  [project.optional-dependencies]
99
99
  test = [
@@ -117,7 +117,7 @@ zzz-test-altair = [
117
117
  "atomicwrites >= 1.4.1, < 1.5",
118
118
  "img2pdf >= 0.6.0, < 0.7",
119
119
  "polars-lts-cpu >= 1.30.0, < 1.31",
120
- "vl-convert-python >= 1.7.0, < 1.8",
120
+ "vl-convert-python >= 1.8.0, < 1.9",
121
121
  "whenever >= 0.8.4, < 0.9",
122
122
  ]
123
123
  zzz-test-asyncio = []
@@ -178,7 +178,7 @@ zzz-test-hypothesis = [
178
178
  "luigi >= 3.6.0, < 3.7",
179
179
  "numpy >= 2.2.6, < 2.3",
180
180
  "pathvalidate >= 3.2.3, < 3.3",
181
- "redis >= 6.1.0, < 6.2",
181
+ "redis >= 6.2.0, < 6.3",
182
182
  "sqlalchemy >= 2.0.41, < 2.1",
183
183
  "tenacity >= 8.5.0, < 9.0", # limited by luigi
184
184
  "tzlocal >= 5.3.1, < 5.4",
@@ -259,7 +259,7 @@ zzz-test-re = []
259
259
  zzz-test-redis = [
260
260
  "orjson >= 3.10.15, < 3.11",
261
261
  "polars-lts-cpu >= 1.30.0, < 1.31",
262
- "redis >= 6.1.0, < 6.2",
262
+ "redis >= 6.2.0, < 6.3",
263
263
  "rich >= 14.0.0, < 14.1",
264
264
  "tenacity >= 8.5.0, < 9.0", # limited by luigi
265
265
  "tzlocal >= 5.3.1, < 5.4",
@@ -270,7 +270,7 @@ zzz-test-scipy = ["scipy >= 1.15.3, < 1.16"]
270
270
  zzz-test-sentinel = []
271
271
  zzz-test-shelve = []
272
272
  zzz-test-slack-sdk = [
273
- "aiohttp >= 3.12.2, < 3.12.3", # for slack
273
+ "aiohttp >= 3.12.4, < 3.12.5", # for slack
274
274
  "slack-sdk >= 3.35.0, < 3.36",
275
275
  ]
276
276
  zzz-test-socket = []
@@ -334,7 +334,7 @@ zzz-test-zoneinfo = [
334
334
  # bump-my-version
335
335
  [tool.bumpversion]
336
336
  allow_dirty = true
337
- current_version = "0.125.11"
337
+ current_version = "0.125.13"
338
338
 
339
339
  [[tool.bumpversion.files]]
340
340
  filename = "src/utilities/__init__.py"
@@ -21,17 +21,21 @@ from hypothesis.strategies import (
21
21
  permutations,
22
22
  sampled_from,
23
23
  )
24
- from pytest import LogCaptureFixture, mark, param, raises
24
+ from pytest import LogCaptureFixture, approx, mark, param, raises
25
25
 
26
26
  from utilities.asyncio import (
27
27
  EnhancedQueue,
28
28
  EnhancedTaskGroup,
29
29
  InfiniteLooper,
30
30
  InfiniteQueueLooper,
31
+ Looper,
32
+ LooperTimeoutError,
31
33
  UniquePriorityQueue,
32
34
  UniqueQueue,
33
35
  _InfiniteLooperDefaultEventError,
34
36
  _InfiniteLooperNoSuchEventError,
37
+ _LooperNoTaskError,
38
+ _LooperStats,
35
39
  get_event,
36
40
  get_items,
37
41
  get_items_nowait,
@@ -47,6 +51,7 @@ from utilities.dataclasses import replace_non_sentinel
47
51
  from utilities.datetime import (
48
52
  MILLISECOND,
49
53
  MINUTE,
54
+ SECOND,
50
55
  datetime_duration_to_timedelta,
51
56
  get_now,
52
57
  )
@@ -817,7 +822,7 @@ class TestInfiniteQueueLooper:
817
822
  assert len(looper) == 0
818
823
  assert looper.empty()
819
824
  looper.put_right_nowait(*range(n))
820
- assert len(looper) == n
825
+ assert len(looper) == looper.qsize() == n
821
826
  assert not looper.empty()
822
827
 
823
828
  async def test_run_until_empty_no_stop(self) -> None:
@@ -872,6 +877,427 @@ class TestInfiniteQueueLooper:
872
877
  assert message == expected
873
878
 
874
879
 
880
+ class _ExampleLooperError(Exception): ...
881
+
882
+
883
+ @dataclass(kw_only=True)
884
+ class _ExampleLooper(Looper[Any]):
885
+ freq: Duration = field(default=10 * MILLISECOND, repr=False)
886
+ backoff: Duration = field(default=100 * MILLISECOND, repr=False)
887
+ _debug: bool = field(default=True, repr=False)
888
+ count: int = 0
889
+ max_count: int = 10
890
+
891
+ @override
892
+ async def _initialize_core(self) -> None:
893
+ self.count = 0
894
+
895
+ @override
896
+ async def core(self) -> None:
897
+ self.count += 1
898
+ if self.count >= self.max_count:
899
+ raise _ExampleLooperError
900
+
901
+
902
+ @dataclass(kw_only=True)
903
+ class _ExampleOuterLooper(_ExampleLooper):
904
+ inner: _ExampleLooper = field(init=False, repr=False)
905
+
906
+ @override
907
+ def __post_init__(self) -> None:
908
+ super().__post_init__()
909
+ self.inner = _ExampleLooper(
910
+ freq=self.freq / 2,
911
+ backoff=self.backoff / 2,
912
+ logger=self.logger,
913
+ timeout=self.timeout,
914
+ timeout_error=self.timeout_error,
915
+ max_count=round(self.max_count / 2),
916
+ )
917
+
918
+ @override
919
+ def _yield_sub_loopers(self) -> Iterator[Looper]:
920
+ yield self.inner
921
+
922
+
923
+ class TestLooper:
924
+ async def test_main_with_nothing(self) -> None:
925
+ looper = _ExampleLooper()
926
+ async with looper:
927
+ ...
928
+ assert looper.stats == _LooperStats(entries=1, stops=1)
929
+
930
+ @mark.flaky
931
+ async def test_main_with_explicit_start(self) -> None:
932
+ looper = _ExampleLooper()
933
+ with raises(TimeoutError):
934
+ async with timeout(1.0), looper:
935
+ await looper
936
+ self._assert_stats(looper, stops=1)
937
+
938
+ async def test_main_with_auto_start(self) -> None:
939
+ looper = _ExampleLooper(auto_start=True)
940
+ with raises(TimeoutError):
941
+ async with timeout(1.0), looper:
942
+ ...
943
+ self._assert_stats(looper)
944
+
945
+ @mark.flaky
946
+ async def test_main_with_timeout(self) -> None:
947
+ looper = _ExampleLooper(timeout=SECOND)
948
+ async with looper:
949
+ with raises(LooperTimeoutError, match="Timeout"):
950
+ await looper
951
+ self._assert_stats(looper, stops=1)
952
+
953
+ async def test_main_with_auto_start_and_timeout(self) -> None:
954
+ looper = _ExampleLooper(auto_start=True, timeout=SECOND)
955
+ async with looper:
956
+ ...
957
+ self._assert_stats(looper, stops=1)
958
+
959
+ async def test_await_without_task(self) -> None:
960
+ looper = _ExampleLooper()
961
+ with raises(_LooperNoTaskError, match=".* has no running task"):
962
+ await looper
963
+
964
+ async def test_context_manager_already_entered(
965
+ self, *, caplog: LogCaptureFixture
966
+ ) -> None:
967
+ looper = _ExampleLooper(auto_start=True, timeout=SECOND)
968
+ async with looper, looper:
969
+ ...
970
+ _ = one(m for m in caplog.messages if search(": already entered$", m))
971
+
972
+ def test_empty(self) -> None:
973
+ looper = _ExampleLooper()
974
+ assert looper.empty()
975
+ looper.put_left_nowait(None)
976
+ assert not looper.empty()
977
+
978
+ def test_get_all_nowait(self) -> None:
979
+ looper = _ExampleLooper()
980
+ looper.put_left_nowait(None)
981
+ items = looper.get_all_nowait()
982
+ assert items == [None]
983
+
984
+ async def test_initialize_already_initializing(
985
+ self, *, caplog: LogCaptureFixture
986
+ ) -> None:
987
+ class Example(_ExampleLooper):
988
+ @override
989
+ async def _initialize_core(self) -> None:
990
+ if self._initialization_attempts == 1:
991
+ _ = await super().initialize()
992
+ await super()._initialize_core()
993
+
994
+ looper = Example()
995
+ _ = await looper.initialize()
996
+ _ = one(m for m in caplog.messages if search(": already initializing$", m))
997
+
998
+ async def test_initialize_failure(self, *, caplog: LogCaptureFixture) -> None:
999
+ class Example(_ExampleLooper):
1000
+ @override
1001
+ async def _initialize_core(self) -> None:
1002
+ if self._initialization_attempts == 1:
1003
+ raise _ExampleLooperError
1004
+ await super()._initialize_core()
1005
+
1006
+ looper = Example()
1007
+ _ = await looper.initialize()
1008
+ _ = one(
1009
+ m
1010
+ for m in caplog.messages
1011
+ if search(r": encountered _ExampleLooperError\(\) whilst initializing$", m)
1012
+ )
1013
+
1014
+ def test_len_and_qsize(self) -> None:
1015
+ looper = _ExampleLooper()
1016
+ assert len(looper) == looper.qsize() == 0
1017
+ looper.put_left_nowait(None)
1018
+ assert len(looper) == looper.qsize() == 1
1019
+
1020
+ def test_replace(self) -> None:
1021
+ looper = _ExampleLooper().replace(freq=SECOND)
1022
+ assert looper.freq == SECOND
1023
+
1024
+ async def test_request_restart(self) -> None:
1025
+ class Example(_ExampleLooper):
1026
+ @override
1027
+ async def core(self) -> None:
1028
+ await super().core()
1029
+ if (self._initialization_attempts >= 2) and (
1030
+ self.count >= (self.max_count / 2)
1031
+ ):
1032
+ self.request_restart()
1033
+
1034
+ looper = Example(auto_start=True, timeout=SECOND)
1035
+ async with looper:
1036
+ ...
1037
+ self._assert_stats(
1038
+ looper,
1039
+ core_successes=79,
1040
+ core_failures=1,
1041
+ initialization_successes=16,
1042
+ tear_down_successes=15,
1043
+ restart_successes=15,
1044
+ stops=1,
1045
+ )
1046
+
1047
+ def test_request_restart_already_requested(
1048
+ self, *, caplog: LogCaptureFixture
1049
+ ) -> None:
1050
+ looper = _ExampleLooper()
1051
+ for _ in range(2):
1052
+ looper.request_restart()
1053
+ _ = one(
1054
+ m for m in caplog.messages if search(r": already requested restart$", m)
1055
+ )
1056
+
1057
+ async def test_request_stop(self) -> None:
1058
+ class Example(_ExampleLooper):
1059
+ @override
1060
+ async def core(self) -> None:
1061
+ await super().core()
1062
+ if (self._initialization_attempts >= 2) and (
1063
+ self.count >= (self.max_count / 2)
1064
+ ):
1065
+ self.request_stop()
1066
+
1067
+ looper = Example(auto_start=True, timeout=SECOND)
1068
+ async with looper:
1069
+ ...
1070
+ self._assert_stats(
1071
+ looper,
1072
+ core_successes=14,
1073
+ core_failures=1,
1074
+ initialization_successes=2,
1075
+ tear_down_successes=1,
1076
+ restart_successes=1,
1077
+ stops=1,
1078
+ )
1079
+
1080
+ def test_request_stop_already_requested(self, *, caplog: LogCaptureFixture) -> None:
1081
+ looper = _ExampleLooper()
1082
+ for _ in range(2):
1083
+ looper.request_stop()
1084
+ _ = one(m for m in caplog.messages if search(r": already requested stop$", m))
1085
+
1086
+ async def test_request_stop_when_empty(self) -> None:
1087
+ class Example(_ExampleLooper):
1088
+ @override
1089
+ async def core(self) -> None:
1090
+ await super().core()
1091
+ if self.empty():
1092
+ await self.stop()
1093
+ match self.qsize() % 2 == 0:
1094
+ case True:
1095
+ _ = self.get_left_nowait()
1096
+ case False:
1097
+ _ = self.get_right_nowait()
1098
+ self.request_stop_when_empty()
1099
+
1100
+ looper = Example(auto_start=True, timeout=SECOND)
1101
+ for i in range(25):
1102
+ match i % 2 == 0:
1103
+ case True:
1104
+ looper.put_left_nowait(i)
1105
+ case False:
1106
+ looper.put_right_nowait(i)
1107
+ async with looper:
1108
+ ...
1109
+ self._assert_stats(
1110
+ looper,
1111
+ core_successes=25,
1112
+ core_failures=2,
1113
+ initialization_successes=3,
1114
+ tear_down_successes=2,
1115
+ restart_successes=2,
1116
+ stops=1,
1117
+ )
1118
+
1119
+ def test_request_stop_when_empty_already_requested(
1120
+ self, *, caplog: LogCaptureFixture
1121
+ ) -> None:
1122
+ looper = _ExampleLooper()
1123
+ for _ in range(2):
1124
+ looper.request_stop_when_empty()
1125
+ _ = one(
1126
+ m
1127
+ for m in caplog.messages
1128
+ if search(r": already requested stop when empty$", m)
1129
+ )
1130
+
1131
+ async def test_restart_failure_during_initialization(
1132
+ self, *, caplog: LogCaptureFixture
1133
+ ) -> None:
1134
+ class Example(_ExampleLooper):
1135
+ @override
1136
+ async def _initialize_core(self) -> None:
1137
+ if self._initialization_attempts == 1:
1138
+ raise _ExampleLooperError
1139
+ await super()._initialize_core()
1140
+
1141
+ looper = Example()
1142
+ await looper.restart()
1143
+ _ = one(
1144
+ m
1145
+ for m in caplog.messages
1146
+ if search(
1147
+ r": encountered _ExampleLooperError\(\) whilst restarting, during initialization$",
1148
+ m,
1149
+ )
1150
+ )
1151
+
1152
+ async def test_restart_failure_during_tear_down(
1153
+ self, *, caplog: LogCaptureFixture
1154
+ ) -> None:
1155
+ class Example(_ExampleLooper):
1156
+ @override
1157
+ async def _tear_down_core(self) -> None:
1158
+ if self._tear_down_attempts == 1:
1159
+ raise _ExampleLooperError
1160
+ await super()._tear_down_core()
1161
+
1162
+ looper = Example()
1163
+ await looper.restart()
1164
+ _ = one(
1165
+ m
1166
+ for m in caplog.messages
1167
+ if search(
1168
+ r": encountered _ExampleLooperError\(\) whilst restarting, during tear down$",
1169
+ m,
1170
+ )
1171
+ )
1172
+
1173
+ async def test_restart_failure_during_tear_down_and_initialization(
1174
+ self, *, caplog: LogCaptureFixture
1175
+ ) -> None:
1176
+ class Example(_ExampleLooper):
1177
+ @override
1178
+ async def _initialize_core(self) -> None:
1179
+ if self._initialization_attempts == 1:
1180
+ raise _ExampleLooperError
1181
+ await super()._initialize_core()
1182
+
1183
+ @override
1184
+ async def _tear_down_core(self) -> None:
1185
+ if self._tear_down_attempts == 1:
1186
+ raise _ExampleLooperError
1187
+ await super()._tear_down_core()
1188
+
1189
+ looper = Example()
1190
+ await looper.restart()
1191
+ _ = one(
1192
+ m
1193
+ for m in caplog.messages
1194
+ if search(
1195
+ r": encountered _ExampleLooperError\(\) \(tear down\) and then _ExampleLooperError\(\) \(initialization\) whilst restarting$",
1196
+ m,
1197
+ )
1198
+ )
1199
+
1200
+ async def test_sub_looper(self) -> None:
1201
+ looper = _ExampleOuterLooper(auto_start=True, timeout=SECOND)
1202
+ looper.inner.auto_start = True
1203
+ async with looper:
1204
+ ...
1205
+ self._assert_stats(looper, stops=1)
1206
+ self._assert_stats(
1207
+ looper.inner,
1208
+ core_successes=56,
1209
+ core_failures=13,
1210
+ initialization_successes=14,
1211
+ tear_down_successes=13,
1212
+ restart_successes=13,
1213
+ stops=1,
1214
+ )
1215
+
1216
+ async def test_sub_looper_changing_to_auto_start(
1217
+ self, *, caplog: LogCaptureFixture
1218
+ ) -> None:
1219
+ looper = _ExampleOuterLooper(auto_start=True, timeout=SECOND)
1220
+ async with looper:
1221
+ ...
1222
+ _ = one(
1223
+ m
1224
+ for m in caplog.messages
1225
+ if search(
1226
+ r": changing sub-looper _ExampleLooper\(.*?\) to auto-start...$", m
1227
+ )
1228
+ )
1229
+
1230
+ async def test_tear_down_already_initializing(
1231
+ self, *, caplog: LogCaptureFixture
1232
+ ) -> None:
1233
+ class Example(_ExampleLooper):
1234
+ @override
1235
+ async def _tear_down_core(self) -> None:
1236
+ if self._tear_down_attempts == 1:
1237
+ _ = await super().tear_down()
1238
+ await super()._tear_down_core()
1239
+
1240
+ looper = Example()
1241
+ _ = await looper.tear_down()
1242
+ _ = one(m for m in caplog.messages if search(": already tearing down$", m))
1243
+
1244
+ async def test_tear_down_failure(self, *, caplog: LogCaptureFixture) -> None:
1245
+ class Example(_ExampleLooper):
1246
+ @override
1247
+ async def _tear_down_core(self) -> None:
1248
+ if self._tear_down_attempts == 1:
1249
+ raise _ExampleLooperError
1250
+ await super()._tear_down_core()
1251
+
1252
+ looper = Example()
1253
+ _ = await looper.tear_down()
1254
+ _ = one(
1255
+ m
1256
+ for m in caplog.messages
1257
+ if search(r": encountered _ExampleLooperError\(\) whilst tearing down$", m)
1258
+ )
1259
+
1260
+ def _assert_stats(
1261
+ self,
1262
+ looper: _ExampleLooper,
1263
+ /,
1264
+ *,
1265
+ entries: int = 1,
1266
+ core_successes: int = 45,
1267
+ core_failures: int = 5,
1268
+ initialization_successes: int = 6,
1269
+ initialization_failures: int = 0,
1270
+ tear_down_successes: int = 5,
1271
+ tear_down_failures: int = 0,
1272
+ restart_successes: int = 5,
1273
+ restart_failures: int = 0,
1274
+ stops: int = 0,
1275
+ ) -> None:
1276
+ stats = looper.stats
1277
+ assert stats.entries == entries
1278
+ assert stats.core_attempts == (stats.core_successes + stats.core_failures)
1279
+ assert stats.core_successes == approx(core_successes, rel=0.5)
1280
+ assert stats.core_failures == approx(core_failures, rel=0.5)
1281
+ assert stats.initialization_attempts == (
1282
+ stats.initialization_successes + stats.initialization_failures
1283
+ )
1284
+ assert stats.initialization_successes == approx(
1285
+ initialization_successes, rel=0.5
1286
+ )
1287
+ assert stats.initialization_failures == approx(initialization_failures, rel=0.5)
1288
+ assert stats.tear_down_attempts == (
1289
+ stats.tear_down_successes + stats.tear_down_failures
1290
+ )
1291
+ assert stats.tear_down_successes == approx(tear_down_successes, rel=0.5)
1292
+ assert stats.tear_down_failures == approx(tear_down_failures, rel=0.5)
1293
+ assert stats.restart_attempts == (
1294
+ stats.restart_successes + stats.restart_failures
1295
+ )
1296
+ assert stats.restart_successes == approx(restart_successes, rel=0.5)
1297
+ assert stats.restart_failures == approx(restart_failures, rel=0.5)
1298
+ assert stats.stops == stops
1299
+
1300
+
875
1301
  class TestPutItems:
876
1302
  @given(xs=lists(integers(), min_size=1), wait=booleans())
877
1303
  async def test_main(self, *, xs: list[int], wait: bool) -> None:
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.125.11"
3
+ __version__ = "0.125.13"