dycw-utilities 0.114.0__tar.gz → 0.114.1__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 (228) hide show
  1. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/PKG-INFO +1 -1
  2. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/pyproject.toml +2 -2
  3. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_asyncio.py +157 -30
  4. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/__init__.py +1 -1
  5. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/asyncio.py +117 -22
  6. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/.gitignore +0 -0
  7. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/LICENSE +0 -0
  8. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/README.md +0 -0
  9. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/__init__.py +0 -0
  10. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/conftest.py +0 -0
  11. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/__init__.py +0 -0
  12. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_missing/__init__.py +0 -0
  13. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_missing/module.py +0 -0
  14. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_with/__init__.py +0 -0
  15. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_with/outer_1.py +0 -0
  16. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_with/outer_2.py +0 -0
  17. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  18. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  19. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  20. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  21. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_without/__init__.py +0 -0
  22. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_without/module_1.py +0 -0
  23. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/package_without/module_2.py +0 -0
  24. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/standalone.py +0 -0
  25. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/modules/with_imports.py +0 -0
  26. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  27. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  28. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  29. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  30. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  31. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  32. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  33. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  34. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/scripts/__init__.py +0 -0
  35. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/scripts/test_async_service/__init__.py +0 -0
  36. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/scripts/test_async_service/__main__.py +0 -0
  37. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/scripts/test_async_service/run.sh +0 -0
  38. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  39. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  40. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  41. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_altair.py +0 -0
  42. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_astor.py +0 -0
  43. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_atomicwrites.py +0 -0
  44. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_atools.py +0 -0
  45. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_cachetools.py +0 -0
  46. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_click.py +0 -0
  47. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_concurrent.py +0 -0
  48. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_contextlib.py +0 -0
  49. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_contextvars.py +0 -0
  50. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_cryptography.py +0 -0
  51. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_cvxpy.py +0 -0
  52. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_dataclasses.py +0 -0
  53. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_datetime.py +0 -0
  54. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_enum.py +0 -0
  55. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_errors.py +0 -0
  56. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_eventkit.py +0 -0
  57. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_fastapi.py +0 -0
  58. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_fpdf2.py +0 -0
  59. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_functions.py +0 -0
  60. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_functools.py +0 -0
  61. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_getpass.py +0 -0
  62. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_git.py +0 -0
  63. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_hashlib.py +0 -0
  64. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_http.py +0 -0
  65. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_hypothesis.py +0 -0
  66. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_ipython.py +0 -0
  67. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_iterables.py +0 -0
  68. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_jupyter.py +0 -0
  69. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_lightweight_charts.py +0 -0
  70. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_logging.py +0 -0
  71. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_loguru.py +0 -0
  72. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_luigi.py +0 -0
  73. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_math.py +0 -0
  74. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_memory_profiler.py +0 -0
  75. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_modules.py +0 -0
  76. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_more_itertools.py +0 -0
  77. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_numpy.py +0 -0
  78. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_operator.py +0 -0
  79. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_optuna.py +0 -0
  80. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_orjson.py +0 -0
  81. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_os.py +0 -0
  82. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_parse.py +0 -0
  83. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_pathlib.py +0 -0
  84. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_period.py +0 -0
  85. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_pickle.py +0 -0
  86. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_platform.py +0 -0
  87. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_polars.py +0 -0
  88. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_polars_ols.py +0 -0
  89. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_pqdm.py +0 -0
  90. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_pydantic.py +0 -0
  91. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_pyinstrument.py +0 -0
  92. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_pyrsistent.py +0 -0
  93. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_pytest.py +0 -0
  94. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_pytest_regressions.py +0 -0
  95. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_python_dotenv.py +0 -0
  96. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_random.py +0 -0
  97. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_re.py +0 -0
  98. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_redis.py +0 -0
  99. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_reprlib.py +0 -0
  100. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_rich.py +0 -0
  101. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_scipy.py +0 -0
  102. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_sentinel.py +0 -0
  103. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_shelve.py +0 -0
  104. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_slack_sdk.py +0 -0
  105. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_socket.py +0 -0
  106. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_sqlalchemy.py +0 -0
  107. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_sqlalchemy_polars.py +0 -0
  108. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_statsmodel.py +0 -0
  109. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_streamlit.py +0 -0
  110. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_sys.py +0 -0
  111. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_tempfile.py +0 -0
  112. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_tenacity.py +0 -0
  113. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_text.py +0 -0
  114. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_threading.py +0 -0
  115. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_timer.py +0 -0
  116. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback.py +0 -0
  117. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/__init__.py +0 -0
  118. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/chain.py +0 -0
  119. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  120. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  121. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  122. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/many.py +0 -0
  123. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/one.py +0 -0
  124. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/recursive.py +0 -0
  125. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  126. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  127. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/two.py +0 -0
  128. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_traceback_funcs/untraced.py +0 -0
  129. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_types.py +0 -0
  130. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_typing.py +0 -0
  131. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_typing_funcs/__init__.py +0 -0
  132. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_typing_funcs/no_future.py +0 -0
  133. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_typing_funcs/with_future.py +0 -0
  134. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_tzdata.py +0 -0
  135. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_tzlocal.py +0 -0
  136. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_uuid.py +0 -0
  137. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_version.py +0 -0
  138. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_warnings.py +0 -0
  139. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_whenever.py +0 -0
  140. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_zipfile.py +0 -0
  141. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/tests/test_zoneinfo.py +0 -0
  142. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/altair.py +0 -0
  143. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/astor.py +0 -0
  144. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/atomicwrites.py +0 -0
  145. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/atools.py +0 -0
  146. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/cachetools.py +0 -0
  147. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/click.py +0 -0
  148. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/concurrent.py +0 -0
  149. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/contextlib.py +0 -0
  150. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/contextvars.py +0 -0
  151. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/cryptography.py +0 -0
  152. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/cvxpy.py +0 -0
  153. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/dataclasses.py +0 -0
  154. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/datetime.py +0 -0
  155. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/enum.py +0 -0
  156. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/errors.py +0 -0
  157. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/eventkit.py +0 -0
  158. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/fastapi.py +0 -0
  159. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/fpdf2.py +0 -0
  160. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/functions.py +0 -0
  161. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/functools.py +0 -0
  162. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/getpass.py +0 -0
  163. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/git.py +0 -0
  164. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/hashlib.py +0 -0
  165. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/http.py +0 -0
  166. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/hypothesis.py +0 -0
  167. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/ipython.py +0 -0
  168. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/iterables.py +0 -0
  169. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/jupyter.py +0 -0
  170. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/lightweight_charts.py +0 -0
  171. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/logging.py +0 -0
  172. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/loguru.py +0 -0
  173. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/luigi.py +0 -0
  174. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/math.py +0 -0
  175. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/memory_profiler.py +0 -0
  176. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/modules.py +0 -0
  177. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/more_itertools.py +0 -0
  178. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/numpy.py +0 -0
  179. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/operator.py +0 -0
  180. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/optuna.py +0 -0
  181. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/orjson.py +0 -0
  182. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/os.py +0 -0
  183. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/parse.py +0 -0
  184. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/pathlib.py +0 -0
  185. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/period.py +0 -0
  186. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/pickle.py +0 -0
  187. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/platform.py +0 -0
  188. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/polars.py +0 -0
  189. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/polars_ols.py +0 -0
  190. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/pqdm.py +0 -0
  191. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/py.typed +0 -0
  192. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/pydantic.py +0 -0
  193. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/pyinstrument.py +0 -0
  194. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/pyrsistent.py +0 -0
  195. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/pytest.py +0 -0
  196. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/pytest_regressions.py +0 -0
  197. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/python_dotenv.py +0 -0
  198. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/random.py +0 -0
  199. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/re.py +0 -0
  200. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/redis.py +0 -0
  201. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/reprlib.py +0 -0
  202. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/rich.py +0 -0
  203. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/scipy.py +0 -0
  204. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/sentinel.py +0 -0
  205. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/shelve.py +0 -0
  206. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/slack_sdk.py +0 -0
  207. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/socket.py +0 -0
  208. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/sqlalchemy.py +0 -0
  209. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/sqlalchemy_polars.py +0 -0
  210. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/statsmodels.py +0 -0
  211. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/streamlit.py +0 -0
  212. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/sys.py +0 -0
  213. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/tempfile.py +0 -0
  214. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/tenacity.py +0 -0
  215. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/text.py +0 -0
  216. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/threading.py +0 -0
  217. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/timer.py +0 -0
  218. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/traceback.py +0 -0
  219. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/types.py +0 -0
  220. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/typing.py +0 -0
  221. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/tzdata.py +0 -0
  222. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/tzlocal.py +0 -0
  223. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/uuid.py +0 -0
  224. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/version.py +0 -0
  225. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/warnings.py +0 -0
  226. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/whenever.py +0 -0
  227. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/zipfile.py +0 -0
  228. {dycw_utilities-0.114.0 → dycw_utilities-0.114.1}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.114.0
3
+ Version: 0.114.1
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -92,7 +92,7 @@ dependencies = [
92
92
  name = "dycw-utilities"
93
93
  readme = "README.md"
94
94
  requires-python = ">= 3.12"
95
- version = "0.114.0"
95
+ version = "0.114.1"
96
96
 
97
97
  [project.optional-dependencies]
98
98
  test = [
@@ -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.114.0"
337
+ current_version = "0.114.1"
338
338
 
339
339
  [[tool.bumpversion.files]]
340
340
  filename = "src/utilities/__init__.py"
@@ -12,7 +12,7 @@ from asyncio import (
12
12
  )
13
13
  from collections import Counter
14
14
  from dataclasses import dataclass, field
15
- from itertools import chain
15
+ from itertools import chain, count
16
16
  from re import search
17
17
  from typing import TYPE_CHECKING, Self, override
18
18
 
@@ -34,6 +34,8 @@ from utilities.asyncio import (
34
34
  EnhancedTaskGroup,
35
35
  ExceptionProcessor,
36
36
  InfiniteLooper,
37
+ InfiniteLooperError,
38
+ InfiniteQueueLooper,
37
39
  QueueProcessor,
38
40
  UniquePriorityQueue,
39
41
  UniqueQueue,
@@ -55,7 +57,7 @@ from utilities.sentinel import Sentinel, sentinel
55
57
  from utilities.timer import Timer
56
58
 
57
59
  if TYPE_CHECKING:
58
- from collections.abc import Mapping
60
+ from collections.abc import Iterator
59
61
 
60
62
  from utilities.types import Duration, MaybeCallableEvent, MaybeType
61
63
 
@@ -338,58 +340,113 @@ class TestGetEvent:
338
340
  class TestInfiniteLooper:
339
341
  @given(n=integers(10, 11))
340
342
  async def test_main(self, *, n: int) -> None:
341
- class CustomTrueError(BaseException): ...
343
+ class TrueError(BaseException): ...
342
344
 
343
- class CustomFalseError(BaseException): ...
345
+ class FalseError(BaseException): ...
344
346
 
345
347
  @dataclass(kw_only=True)
346
348
  class Example(InfiniteLooper[bool]):
347
- counter: int = field(init=False, repr=False)
349
+ counter: int = 0
348
350
 
349
351
  @override
350
- async def initialize(self) -> None:
352
+ async def _initialize(self) -> None:
351
353
  self.counter = 0
352
354
 
353
355
  @override
354
- async def core(self) -> None:
356
+ async def _core(self) -> None:
355
357
  self.counter += 1
356
358
  if self.counter >= n:
357
- self.events[n % 2 == 0].set()
359
+ self._set_event(n % 2 == 0)
358
360
 
359
- @property
360
361
  @override
361
- def events_and_exceptions(self) -> Mapping[bool, MaybeType[BaseException]]:
362
- return {True: CustomTrueError, False: CustomFalseError}
362
+ def _yield_events_and_exceptions(
363
+ self,
364
+ ) -> Iterator[tuple[bool, MaybeType[BaseException]]]:
365
+ yield (True, TrueError)
366
+ yield (False, FalseError)
363
367
 
364
368
  looper = Example(sleep_core=0.1)
365
369
  match n % 2 == 0:
366
370
  case True:
367
- with raises(CustomTrueError):
371
+ with raises(TrueError):
368
372
  _ = await looper()
369
373
  case False:
370
- with raises(CustomFalseError):
374
+ with raises(FalseError):
371
375
  _ = await looper()
372
376
 
377
+ async def test_multiple(self) -> None:
378
+ class ChildError(BaseException): ...
379
+
380
+ @dataclass(kw_only=True)
381
+ class Child(InfiniteLooper[None]):
382
+ counter: int = 0
383
+
384
+ @override
385
+ async def _initialize(self) -> None:
386
+ self.counter = 0
387
+
388
+ @override
389
+ async def _core(self) -> None:
390
+ self.counter += 1
391
+ if self.counter >= 10:
392
+ self._set_event(None)
393
+
394
+ @override
395
+ def _yield_events_and_exceptions(
396
+ self,
397
+ ) -> Iterator[tuple[None, MaybeType[BaseException]]]:
398
+ yield (None, ChildError)
399
+
400
+ class ParentError(BaseException): ...
401
+
402
+ @dataclass(kw_only=True)
403
+ class Parent(InfiniteLooper[None]):
404
+ counter: int = 0
405
+ child: Child
406
+
407
+ @override
408
+ async def _initialize(self) -> None:
409
+ self.counter = 0
410
+
411
+ @override
412
+ async def _core(self) -> None:
413
+ self.counter += 1
414
+ self.child.counter += 1
415
+ if self.counter >= 10:
416
+ self._set_event(None)
417
+
418
+ @override
419
+ def _yield_events_and_exceptions(
420
+ self,
421
+ ) -> Iterator[tuple[None, MaybeType[BaseException]]]:
422
+ yield (None, ParentError)
423
+
424
+ @override
425
+ def _yield_loopers(self) -> Iterator[InfiniteLooper]:
426
+ yield self.child
427
+
428
+ parent = Parent(sleep_core=0.1, child=Child(sleep_core=0.1))
429
+ with raises(BaseExceptionGroup) as error:
430
+ async with timeout_dur(duration=1.5):
431
+ await parent()
432
+ inner = one(error.value.exceptions)
433
+ assert isinstance(inner, ChildError)
434
+ assert 10 <= parent.child.counter <= 15
435
+ assert 3 <= parent.counter <= 7
436
+
373
437
  async def test_error_upon_initialize(self) -> None:
374
438
  class CustomError(Exception): ...
375
439
 
376
440
  @dataclass(kw_only=True)
377
441
  class Example(InfiniteLooper[None]):
378
- counter: int = field(init=False, repr=False)
379
-
380
442
  @override
381
- async def initialize(self) -> None:
443
+ async def _initialize(self) -> None:
382
444
  raise CustomError
383
445
 
384
446
  @override
385
- async def core(self) -> None:
447
+ async def _core(self) -> None:
386
448
  raise NotImplementedError
387
449
 
388
- @property
389
- @override
390
- def events_and_exceptions(self) -> Mapping[None, MaybeType[BaseException]]:
391
- return {None: CustomError}
392
-
393
450
  with raises(TimeoutError):
394
451
  async with timeout_dur(duration=0.5):
395
452
  _ = await Example(sleep_core=0.1)()
@@ -399,23 +456,93 @@ class TestInfiniteLooper:
399
456
 
400
457
  @dataclass(kw_only=True)
401
458
  class Example(InfiniteLooper[None]):
402
- counter: int = field(init=False, repr=False)
459
+ @override
460
+ async def _core(self) -> None:
461
+ raise CustomError
403
462
 
404
463
  @override
405
- async def initialize(self) -> None: ...
464
+ def _yield_events_and_exceptions(
465
+ self,
466
+ ) -> Iterator[tuple[None, MaybeType[BaseException]]]:
467
+ yield (None, CustomError)
468
+
469
+ with raises(TimeoutError):
470
+ async with timeout_dur(duration=0.5):
471
+ _ = await Example(sleep_core=0.1)()
472
+
473
+ async def test_error_no_event_found(self) -> None:
474
+ @dataclass(kw_only=True)
475
+ class Example(InfiniteLooper[None]):
476
+ counter: int = 0
406
477
 
407
478
  @override
408
- async def core(self) -> None:
409
- raise CustomError
479
+ async def _initialize(self) -> None:
480
+ self.counter = 0
481
+
482
+ @override
483
+ async def _core(self) -> None:
484
+ self.counter += 1
485
+ if self.counter >= 10:
486
+ self._set_event(None)
487
+
488
+ looper = Example(sleep_core=0.1)
489
+ with raises(InfiniteLooperError, match="No event None found"):
490
+ _ = await looper()
491
+
492
+
493
+ class TestInfiniteQueueLooper:
494
+ async def test_main(self) -> None:
495
+ @dataclass(kw_only=True)
496
+ class Example(InfiniteQueueLooper[None, int]):
497
+ output: set[int] = field(default_factory=set)
498
+
499
+ @override
500
+ async def _process_items(self, *items: int) -> None:
501
+ self.output.update(items)
502
+
503
+ processor = Example(sleep_core=0.1)
504
+
505
+ async def add_items() -> None:
506
+ for i in count():
507
+ processor.put_items_nowait(i)
508
+ await sleep(0.1)
509
+
510
+ with raises(ExceptionGroup): # noqa: PT012
511
+ async with EnhancedTaskGroup(timeout=1.0) as tg:
512
+ _ = tg.create_task(processor())
513
+ _ = tg.create_task(add_items())
514
+ assert 5 <= len(processor.output) <= 15
515
+
516
+ async def test_no_items(self) -> None:
517
+ @dataclass(kw_only=True)
518
+ class Example(InfiniteQueueLooper[None, int]):
519
+ output: set[int] = field(default_factory=set)
410
520
 
411
- @property
412
521
  @override
413
- def events_and_exceptions(self) -> Mapping[None, MaybeType[BaseException]]:
414
- return {None: CustomError}
522
+ async def _process_items(self, *items: int) -> None:
523
+ self.output.update(items)
415
524
 
525
+ processor = Example(sleep_core=0.1)
416
526
  with raises(TimeoutError):
417
527
  async with timeout_dur(duration=0.5):
418
- _ = await Example(sleep_core=0.1)()
528
+ _ = await processor()
529
+
530
+ async def test_error_process_items(self) -> None:
531
+ class CustomError(Exception): ...
532
+
533
+ @dataclass(kw_only=True)
534
+ class Example(InfiniteQueueLooper[None, int]):
535
+ output: set[int] = field(default_factory=set)
536
+
537
+ @override
538
+ async def _process_items(self, *items: int) -> None:
539
+ raise CustomError
540
+
541
+ processor = Example(sleep_core=0.1)
542
+ processor.put_items_nowait(1)
543
+ with raises(TimeoutError):
544
+ async with timeout_dur(duration=0.5):
545
+ _ = await processor()
419
546
 
420
547
 
421
548
  class TestPutAndGetItems:
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.114.0"
3
+ __version__ = "0.114.1"
@@ -16,7 +16,7 @@ from asyncio import (
16
16
  sleep,
17
17
  timeout,
18
18
  )
19
- from collections.abc import Callable, Iterable, Mapping
19
+ from collections.abc import Callable, Hashable, Iterable, Iterator, Mapping
20
20
  from contextlib import (
21
21
  AsyncExitStack,
22
22
  _AsyncGeneratorContextManager,
@@ -30,6 +30,7 @@ from sys import stderr, stdout
30
30
  from typing import (
31
31
  TYPE_CHECKING,
32
32
  Generic,
33
+ NoReturn,
33
34
  Self,
34
35
  TextIO,
35
36
  TypeVar,
@@ -43,7 +44,6 @@ from utilities.errors import ImpossibleCaseError
43
44
  from utilities.functions import ensure_int, ensure_not_none
44
45
  from utilities.sentinel import Sentinel, sentinel
45
46
  from utilities.types import (
46
- Coroutine1,
47
47
  MaybeCallableEvent,
48
48
  MaybeType,
49
49
  THashable,
@@ -328,61 +328,155 @@ class ExceptionProcessor(QueueProcessor[Exception | type[Exception]]):
328
328
  class InfiniteLooper(ABC, Generic[THashable]):
329
329
  """An infinite loop which can throw exceptions by setting events."""
330
330
 
331
- events: Mapping[THashable, Event] = field(
331
+ _events: Mapping[THashable, Event] = field(
332
332
  default_factory=dict, init=False, repr=False
333
333
  )
334
334
  sleep_core: Duration = SECOND
335
335
  sleep_restart: Duration = MINUTE
336
336
 
337
337
  def __post_init__(self) -> None:
338
- self._reset_events()
339
-
340
- async def __call__(self) -> Coroutine1[None]:
338
+ self._events = {
339
+ event: Event() for event, _ in self._yield_events_and_exceptions()
340
+ }
341
+
342
+ async def __call__(self) -> None:
343
+ """Create a coroutine to run the looper."""
344
+ loopers = list(self._yield_loopers())
345
+ if len(loopers) == 0:
346
+ return await self._run_looper()
347
+ return await self._run_multiple_loopers(*loopers)
348
+
349
+ async def _run_looper(self) -> None:
350
+ """Run the looper by itself."""
341
351
  while True:
342
352
  try:
343
353
  self._reset_events()
344
354
  try:
345
- await self.initialize()
355
+ await self._initialize()
346
356
  except Exception as error: # noqa: BLE001
347
- self.error_upon_initialize(error)
357
+ self._error_upon_initialize(error)
348
358
  await sleep_dur(duration=self.sleep_restart)
349
359
  else:
350
360
  while True:
351
361
  try:
352
362
  event = next(
353
363
  key
354
- for (key, value) in self.events.items()
364
+ for (key, value) in self._events.items()
355
365
  if value.is_set()
356
366
  )
357
367
  except StopIteration:
358
- await self.core()
368
+ await self._core()
359
369
  await sleep_dur(duration=self.sleep_core)
360
370
  else:
361
- raise self.events_and_exceptions[event]
371
+ self._raise_error(event)
372
+ except InfiniteLooperError:
373
+ raise
362
374
  except Exception as error: # noqa: BLE001
363
- self.error_upon_core(error)
375
+ self._error_upon_core(error)
364
376
  await sleep_dur(duration=self.sleep_restart)
365
377
 
366
- @property
367
- @abstractmethod
368
- def events_and_exceptions(self) -> Mapping[THashable, MaybeType[BaseException]]:
369
- """A mapping of events to exceptions."""
378
+ async def _run_multiple_loopers(self, *loopers: InfiniteLooper) -> None:
379
+ """Run multiple loopers."""
380
+ while True:
381
+ self._reset_events()
382
+ try:
383
+ async with TaskGroup() as tg:
384
+ _ = tg.create_task(self._run_looper())
385
+ _ = [tg.create_task(looper()) for looper in loopers]
386
+ except Exception as error: # noqa: BLE001
387
+ self._error_upon_core(error) # pragma: no cover
388
+ await sleep_dur(duration=self.sleep_restart) # pragma: no cover
370
389
 
371
- async def initialize(self) -> None:
390
+ async def _initialize(self) -> None:
372
391
  """Initialize the loop."""
373
392
 
374
- async def core(self) -> None:
375
- """Run the core."""
393
+ async def _core(self) -> None:
394
+ """Run the core part of the loop."""
376
395
 
377
- def error_upon_initialize(self, error: Exception, /) -> None:
396
+ def _error_upon_initialize(self, error: Exception, /) -> None:
397
+ """Handle any errors upon initializing the looper."""
378
398
  _ = error
379
399
 
380
- def error_upon_core(self, error: Exception, /) -> None:
400
+ def _error_upon_core(self, error: Exception, /) -> None:
401
+ """Handle any errors upon running the core function."""
381
402
  _ = error
382
403
 
404
+ def _raise_error(self, event: THashable, /) -> NoReturn:
405
+ """Raise the error corresponding to given event."""
406
+ mapping = dict(self._yield_events_and_exceptions())
407
+ error = mapping.get(event, InfiniteLooperError)
408
+ raise error
409
+
383
410
  def _reset_events(self) -> None:
384
411
  """Reset the events."""
385
- self.events = {event: Event() for event in self.events_and_exceptions}
412
+ self._events = {
413
+ event: Event() for event, _ in self._yield_events_and_exceptions()
414
+ }
415
+
416
+ def _set_event(self, event: THashable, /) -> None:
417
+ """Set the given event."""
418
+ try:
419
+ event_obj = self._events[event]
420
+ except KeyError:
421
+ raise InfiniteLooperError(event=event) from None
422
+ event_obj.set()
423
+
424
+ def _yield_events_and_exceptions(
425
+ self,
426
+ ) -> Iterator[tuple[THashable, MaybeType[BaseException]]]:
427
+ """Yield the events & exceptions."""
428
+ yield from []
429
+
430
+ def _yield_loopers(self) -> Iterator[InfiniteLooper]:
431
+ """Yield any other infinite loopers which must also be run."""
432
+ yield from []
433
+
434
+
435
+ @dataclass(kw_only=True, slots=True)
436
+ class InfiniteLooperError(Exception):
437
+ event: Hashable
438
+
439
+ @override
440
+ def __str__(self) -> str:
441
+ return f"No event {self.event!r} found"
442
+
443
+
444
+ ##
445
+
446
+
447
+ @dataclass(kw_only=True)
448
+ class InfiniteQueueLooper(InfiniteLooper[THashable], Generic[THashable, _T]):
449
+ """An infinite loop which processes a queue."""
450
+
451
+ queue_type: type[Queue[_T]] = field(default=Queue, repr=False)
452
+ _queue: Queue[_T] = field(init=False)
453
+ _current: Queue[_T] = field(init=False)
454
+
455
+ @override
456
+ def __post_init__(self) -> None:
457
+ super().__post_init__()
458
+ self._queue = self.queue_type()
459
+ self._current = self.queue_type()
460
+
461
+ @override
462
+ async def _core(self) -> None:
463
+ """Run the core part of the loop."""
464
+ items = await get_items(self._queue)
465
+ _ = get_items_nowait(self._current)
466
+ put_items_nowait(items, self._current)
467
+ try:
468
+ await self._process_items(*items)
469
+ except Exception:
470
+ put_items_nowait(items, self._queue)
471
+ raise
472
+
473
+ @abstractmethod
474
+ async def _process_items(self, *items: _T) -> None:
475
+ """Process the items."""
476
+
477
+ def put_items_nowait(self, *items: _T) -> None:
478
+ """Put items into the queue."""
479
+ put_items_nowait(items, self._queue)
386
480
 
387
481
 
388
482
  ##
@@ -590,6 +684,7 @@ __all__ = [
590
684
  "AsyncService",
591
685
  "EnhancedTaskGroup",
592
686
  "ExceptionProcessor",
687
+ "InfiniteLooperError",
593
688
  "QueueProcessor",
594
689
  "StreamCommandOutput",
595
690
  "UniquePriorityQueue",