dycw-utilities 0.116.4__tar.gz → 0.116.6__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 (230) hide show
  1. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/PKG-INFO +4 -4
  2. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/pyproject.toml +7 -7
  3. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_asyncio.py +44 -0
  4. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_redis.py +36 -7
  5. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/__init__.py +1 -1
  6. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/asyncio.py +12 -0
  7. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/redis.py +40 -28
  8. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/.gitignore +0 -0
  9. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/LICENSE +0 -0
  10. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/README.md +0 -0
  11. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/__init__.py +0 -0
  12. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/conftest.py +0 -0
  13. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/__init__.py +0 -0
  14. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_missing/__init__.py +0 -0
  15. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_missing/module.py +0 -0
  16. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_with/__init__.py +0 -0
  17. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_with/outer_1.py +0 -0
  18. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_with/outer_2.py +0 -0
  19. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  20. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  21. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  22. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  23. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_without/__init__.py +0 -0
  24. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_without/module_1.py +0 -0
  25. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/package_without/module_2.py +0 -0
  26. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/standalone.py +0 -0
  27. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/modules/with_imports.py +0 -0
  28. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  29. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  30. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  31. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  32. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  33. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  34. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  35. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  36. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/scripts/__init__.py +0 -0
  37. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/scripts/test_async_service/__init__.py +0 -0
  38. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/scripts/test_async_service/__main__.py +0 -0
  39. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/scripts/test_async_service/run.sh +0 -0
  40. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  41. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  42. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  43. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_altair.py +0 -0
  44. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_astor.py +0 -0
  45. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_atomicwrites.py +0 -0
  46. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_atools.py +0 -0
  47. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_cachetools.py +0 -0
  48. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_click.py +0 -0
  49. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_concurrent.py +0 -0
  50. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_contextlib.py +0 -0
  51. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_contextvars.py +0 -0
  52. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_cryptography.py +0 -0
  53. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_cvxpy.py +0 -0
  54. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_dataclasses.py +0 -0
  55. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_datetime.py +0 -0
  56. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_enum.py +0 -0
  57. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_errors.py +0 -0
  58. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_eventkit.py +0 -0
  59. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_fastapi.py +0 -0
  60. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_fpdf2.py +0 -0
  61. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_functions.py +0 -0
  62. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_functools.py +0 -0
  63. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_getpass.py +0 -0
  64. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_git.py +0 -0
  65. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_hashlib.py +0 -0
  66. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_http.py +0 -0
  67. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_hypothesis.py +0 -0
  68. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_importlib.py +0 -0
  69. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_ipython.py +0 -0
  70. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_iterables.py +0 -0
  71. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_jupyter.py +0 -0
  72. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_lightweight_charts.py +0 -0
  73. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_logging.py +0 -0
  74. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_loguru.py +0 -0
  75. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_luigi.py +0 -0
  76. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_math.py +0 -0
  77. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_memory_profiler.py +0 -0
  78. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_modules.py +0 -0
  79. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_more_itertools.py +0 -0
  80. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_numpy.py +0 -0
  81. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_operator.py +0 -0
  82. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_optuna.py +0 -0
  83. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_orjson.py +0 -0
  84. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_os.py +0 -0
  85. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_parse.py +0 -0
  86. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_pathlib.py +0 -0
  87. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_period.py +0 -0
  88. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_pickle.py +0 -0
  89. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_platform.py +0 -0
  90. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_polars.py +0 -0
  91. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_polars_ols.py +0 -0
  92. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_pqdm.py +0 -0
  93. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_pydantic.py +0 -0
  94. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_pyinstrument.py +0 -0
  95. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_pyrsistent.py +0 -0
  96. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_pytest.py +0 -0
  97. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_pytest_regressions.py +0 -0
  98. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_python_dotenv.py +0 -0
  99. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_random.py +0 -0
  100. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_re.py +0 -0
  101. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_reprlib.py +0 -0
  102. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_rich.py +0 -0
  103. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_scipy.py +0 -0
  104. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_sentinel.py +0 -0
  105. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_shelve.py +0 -0
  106. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_slack_sdk.py +0 -0
  107. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_socket.py +0 -0
  108. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_sqlalchemy.py +0 -0
  109. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_sqlalchemy_polars.py +0 -0
  110. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_statsmodel.py +0 -0
  111. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_streamlit.py +0 -0
  112. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_sys.py +0 -0
  113. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_tempfile.py +0 -0
  114. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_tenacity.py +0 -0
  115. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_text.py +0 -0
  116. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_threading.py +0 -0
  117. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_timer.py +0 -0
  118. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback.py +0 -0
  119. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/__init__.py +0 -0
  120. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/chain.py +0 -0
  121. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  122. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  123. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  124. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/many.py +0 -0
  125. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/one.py +0 -0
  126. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/recursive.py +0 -0
  127. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  128. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  129. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/two.py +0 -0
  130. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_traceback_funcs/untraced.py +0 -0
  131. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_types.py +0 -0
  132. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_typing.py +0 -0
  133. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_typing_funcs/__init__.py +0 -0
  134. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_typing_funcs/no_future.py +0 -0
  135. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_typing_funcs/with_future.py +0 -0
  136. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_tzdata.py +0 -0
  137. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_tzlocal.py +0 -0
  138. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_uuid.py +0 -0
  139. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_version.py +0 -0
  140. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_warnings.py +0 -0
  141. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_whenever.py +0 -0
  142. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_zipfile.py +0 -0
  143. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/tests/test_zoneinfo.py +0 -0
  144. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/altair.py +0 -0
  145. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/astor.py +0 -0
  146. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/atomicwrites.py +0 -0
  147. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/atools.py +0 -0
  148. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/cachetools.py +0 -0
  149. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/click.py +0 -0
  150. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/concurrent.py +0 -0
  151. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/contextlib.py +0 -0
  152. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/contextvars.py +0 -0
  153. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/cryptography.py +0 -0
  154. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/cvxpy.py +0 -0
  155. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/dataclasses.py +0 -0
  156. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/datetime.py +0 -0
  157. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/enum.py +0 -0
  158. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/errors.py +0 -0
  159. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/eventkit.py +0 -0
  160. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/fastapi.py +0 -0
  161. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/fpdf2.py +0 -0
  162. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/functions.py +0 -0
  163. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/functools.py +0 -0
  164. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/getpass.py +0 -0
  165. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/git.py +0 -0
  166. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/hashlib.py +0 -0
  167. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/http.py +0 -0
  168. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/hypothesis.py +0 -0
  169. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/importlib.py +0 -0
  170. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/ipython.py +0 -0
  171. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/iterables.py +0 -0
  172. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/jupyter.py +0 -0
  173. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/lightweight_charts.py +0 -0
  174. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/logging.py +0 -0
  175. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/loguru.py +0 -0
  176. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/luigi.py +0 -0
  177. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/math.py +0 -0
  178. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/memory_profiler.py +0 -0
  179. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/modules.py +0 -0
  180. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/more_itertools.py +0 -0
  181. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/numpy.py +0 -0
  182. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/operator.py +0 -0
  183. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/optuna.py +0 -0
  184. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/orjson.py +0 -0
  185. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/os.py +0 -0
  186. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/parse.py +0 -0
  187. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/pathlib.py +0 -0
  188. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/period.py +0 -0
  189. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/pickle.py +0 -0
  190. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/platform.py +0 -0
  191. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/polars.py +0 -0
  192. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/polars_ols.py +0 -0
  193. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/pqdm.py +0 -0
  194. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/py.typed +0 -0
  195. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/pydantic.py +0 -0
  196. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/pyinstrument.py +0 -0
  197. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/pyrsistent.py +0 -0
  198. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/pytest.py +0 -0
  199. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/pytest_regressions.py +0 -0
  200. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/python_dotenv.py +0 -0
  201. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/random.py +0 -0
  202. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/re.py +0 -0
  203. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/reprlib.py +0 -0
  204. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/rich.py +0 -0
  205. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/scipy.py +0 -0
  206. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/sentinel.py +0 -0
  207. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/shelve.py +0 -0
  208. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/slack_sdk.py +0 -0
  209. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/socket.py +0 -0
  210. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/sqlalchemy.py +0 -0
  211. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/sqlalchemy_polars.py +0 -0
  212. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/statsmodels.py +0 -0
  213. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/streamlit.py +0 -0
  214. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/sys.py +0 -0
  215. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/tempfile.py +0 -0
  216. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/tenacity.py +0 -0
  217. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/text.py +0 -0
  218. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/threading.py +0 -0
  219. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/timer.py +0 -0
  220. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/traceback.py +0 -0
  221. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/types.py +0 -0
  222. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/typing.py +0 -0
  223. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/tzdata.py +0 -0
  224. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/tzlocal.py +0 -0
  225. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/uuid.py +0 -0
  226. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/version.py +0 -0
  227. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/warnings.py +0 -0
  228. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/whenever.py +0 -0
  229. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/zipfile.py +0 -0
  230. {dycw_utilities-0.116.4 → dycw_utilities-0.116.6}/src/utilities/zoneinfo.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.116.4
3
+ Version: 0.116.6
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
7
7
  Requires-Dist: typing-extensions<4.14,>=4.13.1
8
8
  Provides-Extra: test
9
- Requires-Dist: hypothesis<6.132,>=6.131.17; extra == 'test'
9
+ Requires-Dist: hypothesis<6.132,>=6.131.19; extra == 'test'
10
10
  Requires-Dist: pytest-asyncio<0.27,>=0.26.0; extra == 'test'
11
11
  Requires-Dist: pytest-cov<6.2,>=6.1.1; extra == 'test'
12
12
  Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
@@ -43,7 +43,7 @@ Requires-Dist: whenever<0.8,>=0.7.3; extra == 'zzz-test-click'
43
43
  Provides-Extra: zzz-test-contextlib
44
44
  Provides-Extra: zzz-test-contextvars
45
45
  Provides-Extra: zzz-test-cryptography
46
- Requires-Dist: cryptography<44.1,>=44.0.2; extra == 'zzz-test-cryptography'
46
+ Requires-Dist: cryptography<46.0,>=45.0.2; extra == 'zzz-test-cryptography'
47
47
  Provides-Extra: zzz-test-cvxpy
48
48
  Requires-Dist: cvxpy<1.7,>=1.6.5; extra == 'zzz-test-cvxpy'
49
49
  Provides-Extra: zzz-test-dataclasses
@@ -80,7 +80,7 @@ Provides-Extra: zzz-test-hypothesis
80
80
  Requires-Dist: aiosqlite<0.22,>=0.21.0; extra == 'zzz-test-hypothesis'
81
81
  Requires-Dist: asyncpg<0.31,>=0.30.0; extra == 'zzz-test-hypothesis'
82
82
  Requires-Dist: greenlet<3.3,>=3.2.0; extra == 'zzz-test-hypothesis'
83
- Requires-Dist: hypothesis<6.132,>=6.131.17; extra == 'zzz-test-hypothesis'
83
+ Requires-Dist: hypothesis<6.132,>=6.131.19; extra == 'zzz-test-hypothesis'
84
84
  Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-hypothesis'
85
85
  Requires-Dist: numpy<2.3,>=2.2.5; extra == 'zzz-test-hypothesis'
86
86
  Requires-Dist: pathvalidate<3.3,>=3.2.3; extra == 'zzz-test-hypothesis'
@@ -19,14 +19,14 @@ dev = [
19
19
  "click >= 8.2.0, < 8.3",
20
20
  "coloredlogs >= 15.0.1, < 15.1",
21
21
  "concurrent-log-handler >= 0.9.26, < 0.10",
22
- "cryptography >= 44.0.2, < 44.1",
22
+ "cryptography >= 45.0.2, < 46.0",
23
23
  "cvxpy >= 1.6.5, < 1.7",
24
24
  "eventkit >= 1.0.3, < 1.1",
25
25
  "fastapi >= 0.115.11, < 0.116",
26
26
  "fpdf2 >= 2.8.3, < 2.9",
27
27
  "greenlet >= 3.2.0, < 3.3", # for sqlalchemy async
28
28
  "httpx >= 0.28.1, < 0.29", # for fastapi
29
- "hypothesis >= 6.131.17, < 6.132",
29
+ "hypothesis >= 6.131.19, < 6.132",
30
30
  "img2pdf >= 0.6.0, < 0.7",
31
31
  "lightweight-charts >= 2.1, < 2.2",
32
32
  "loguru >= 0.7.3, < 0.8",
@@ -92,11 +92,11 @@ dependencies = [
92
92
  name = "dycw-utilities"
93
93
  readme = "README.md"
94
94
  requires-python = ">= 3.12"
95
- version = "0.116.4"
95
+ version = "0.116.6"
96
96
 
97
97
  [project.optional-dependencies]
98
98
  test = [
99
- "hypothesis >= 6.131.17, < 6.132",
99
+ "hypothesis >= 6.131.19, < 6.132",
100
100
  "pytest >= 8.3.5, < 8.4",
101
101
  "pytest-asyncio >= 0.26.0, < 0.27",
102
102
  "pytest-cov >= 6.1.1, < 6.2",
@@ -133,7 +133,7 @@ zzz-test-click = [
133
133
  ]
134
134
  zzz-test-contextlib = []
135
135
  zzz-test-contextvars = []
136
- zzz-test-cryptography = ["cryptography >= 44.0.2, < 44.1"]
136
+ zzz-test-cryptography = ["cryptography >= 45.0.2, < 46.0"]
137
137
  zzz-test-cvxpy = ["cvxpy >= 1.6.5, < 1.7"]
138
138
  zzz-test-dataclasses = [
139
139
  "orjson >= 3.10.15, < 3.11",
@@ -174,7 +174,7 @@ zzz-test-hypothesis = [
174
174
  "aiosqlite >= 0.21.0, < 0.22",
175
175
  "asyncpg >= 0.30.0, < 0.31", # for sqlalchemy async
176
176
  "greenlet >= 3.2.0, < 3.3", # for sqlalchemy async
177
- "hypothesis >= 6.131.17, < 6.132",
177
+ "hypothesis >= 6.131.19, < 6.132",
178
178
  "luigi >= 3.6.0, < 3.7",
179
179
  "numpy >= 2.2.5, < 2.3",
180
180
  "pathvalidate >= 3.2.3, < 3.3",
@@ -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.116.4"
337
+ current_version = "0.116.6"
338
338
 
339
339
  [[tool.bumpversion.files]]
340
340
  filename = "src/utilities/__init__.py"
@@ -602,6 +602,22 @@ class TestInfiniteQueueLooper:
602
602
  _ = tg.create_task(add_items())
603
603
  assert 15 <= len(looper.output) <= 20
604
604
 
605
+ @given(n=integers(1, 10))
606
+ def test_len_and_empty(self, *, n: int) -> None:
607
+ class Example(InfiniteQueueLooper[None, int]):
608
+ output: set[int] = field(default_factory=set)
609
+
610
+ @override
611
+ async def _process_items(self, *items: int) -> None:
612
+ self.output.update(items)
613
+
614
+ looper = Example(sleep_core=0.05)
615
+ assert len(looper) == 0
616
+ assert looper.empty()
617
+ looper.put_items_nowait(*range(n))
618
+ assert len(looper) == n
619
+ assert not looper.empty()
620
+
605
621
  async def test_no_items(self) -> None:
606
622
  @dataclass(kw_only=True)
607
623
  class Example(InfiniteQueueLooper[None, int]):
@@ -616,6 +632,34 @@ class TestInfiniteQueueLooper:
616
632
  async with timeout_dur(duration=0.5):
617
633
  _ = await looper()
618
634
 
635
+ async def test_run_until_empty(self) -> None:
636
+ @dataclass(kw_only=True)
637
+ class Example(InfiniteQueueLooper[None, int]):
638
+ output: set[int] = field(default_factory=set)
639
+
640
+ @override
641
+ async def _process_items(self, *items: int) -> None:
642
+ self.output.update(items)
643
+
644
+ looper = Example(sleep_core=0.5)
645
+
646
+ async def add_items() -> None:
647
+ for i in count():
648
+ looper.put_items_nowait(i)
649
+ await sleep(0.01)
650
+
651
+ with raises(ExceptionGroup): # noqa: PT012
652
+ async with EnhancedTaskGroup(timeout=1.0) as tg:
653
+ _ = tg.create_task(looper())
654
+ _ = tg.create_task(add_items())
655
+
656
+ tasks = len(looper)
657
+ assert tasks >= 1
658
+ await sleep(0.1)
659
+ assert len(looper) == tasks
660
+ await looper.run_until_empty()
661
+ assert looper.empty()
662
+
619
663
  @given(logger=just("logger") | none())
620
664
  async def test_error_process_items(self, *, logger: str | None) -> None:
621
665
  class CustomError(Exception): ...
@@ -45,13 +45,14 @@ if TYPE_CHECKING:
45
45
  from collections.abc import Mapping
46
46
 
47
47
  from pytest import CaptureFixture
48
+ from redis.asyncio.client import PubSub
48
49
 
49
50
 
50
51
  class TestPublishAndSubscribe:
51
52
  @given(
52
53
  data=data(),
53
54
  channel=text_ascii(min_size=1).map(
54
- lambda c: f"{get_class_name(TestPublishAndSubscribe)}_obj_ser_{c}"
55
+ lambda c: f"{get_class_name(TestPublishAndSubscribe)}_all_objects_with_serialize_{c}"
55
56
  ),
56
57
  obj=make_objects(),
57
58
  )
@@ -87,7 +88,7 @@ class TestPublishAndSubscribe:
87
88
  @given(
88
89
  data=data(),
89
90
  channel=text_ascii(min_size=1).map(
90
- lambda c: f"{get_class_name(TestPublishAndSubscribe)}_text_no_ser_{c}"
91
+ lambda c: f"{get_class_name(TestPublishAndSubscribe)}_text_without_serialize_{c}"
91
92
  ),
92
93
  text=text_ascii(min_size=1),
93
94
  )
@@ -282,7 +283,7 @@ class TestPublisherIQL:
282
283
  class TestSubscribeMessages:
283
284
  @given(
284
285
  channel=text_ascii(min_size=1).map(
285
- lambda c: f"{get_class_name(TestSubscribeMessages)}_{c}"
286
+ lambda c: f"{get_class_name(TestSubscribeMessages)}_redis_{c}"
286
287
  ),
287
288
  message=text_ascii(min_size=1),
288
289
  )
@@ -292,18 +293,46 @@ class TestSubscribeMessages:
292
293
  suppress_health_check={HealthCheck.function_scoped_fixture},
293
294
  )
294
295
  @SKIPIF_CI_AND_NOT_LINUX
295
- async def test_main(
296
+ async def test_redis(
296
297
  self, *, capsys: CaptureFixture, channel: str, message: str
297
298
  ) -> None:
298
- client = Redis()
299
+ redis = Redis()
300
+ await self._run_test(redis, redis, capsys, channel, message)
299
301
 
302
+ @given(
303
+ channel=text_ascii(min_size=1).map(
304
+ lambda c: f"{get_class_name(TestSubscribeMessages)}_pubsub_{c}"
305
+ ),
306
+ message=text_ascii(min_size=1),
307
+ )
308
+ @settings(
309
+ max_examples=1,
310
+ phases={Phase.generate},
311
+ suppress_health_check={HealthCheck.function_scoped_fixture},
312
+ )
313
+ @SKIPIF_CI_AND_NOT_LINUX
314
+ async def test_pubsub(
315
+ self, *, capsys: CaptureFixture, channel: str, message: str
316
+ ) -> None:
317
+ redis = Redis()
318
+ await self._run_test(redis, redis.pubsub(), capsys, channel, message)
319
+
320
+ async def _run_test(
321
+ self,
322
+ redis: Redis,
323
+ redis_or_pubsub: Redis | PubSub,
324
+ capsys: CaptureFixture,
325
+ channel: str,
326
+ message: str,
327
+ /,
328
+ ) -> None:
300
329
  async def listener() -> None:
301
- async for msg in subscribe_messages(client.pubsub(), channel):
330
+ async for msg in subscribe_messages(redis_or_pubsub, channel):
302
331
  print(msg) # noqa: T201
303
332
 
304
333
  task = get_running_loop().create_task(listener())
305
334
  await sleep(0.05)
306
- _ = await client.publish(channel, message)
335
+ _ = await redis.publish(channel, message)
307
336
  await sleep(0.05)
308
337
  try:
309
338
  out = capsys.readouterr().out
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.116.4"
3
+ __version__ = "0.116.6"
@@ -490,6 +490,9 @@ class InfiniteQueueLooper(InfiniteLooper[THashable], Generic[THashable, _T]):
490
490
  super().__post_init__()
491
491
  self._queue = self.queue_type()
492
492
 
493
+ def __len__(self) -> int:
494
+ return self._queue.qsize()
495
+
493
496
  @override
494
497
  async def _core(self) -> None:
495
498
  """Run the core part of the loop."""
@@ -505,10 +508,19 @@ class InfiniteQueueLooper(InfiniteLooper[THashable], Generic[THashable, _T]):
505
508
  async def _process_items(self, *items: _T) -> None:
506
509
  """Process the items."""
507
510
 
511
+ def empty(self) -> bool:
512
+ """Check if the queue is empty."""
513
+ return self._queue.empty()
514
+
508
515
  def put_items_nowait(self, *items: _T) -> None:
509
516
  """Put items into the queue."""
510
517
  put_items_nowait(items, self._queue)
511
518
 
519
+ async def run_until_empty(self) -> None:
520
+ """Run until the queue is empty."""
521
+ while not self.empty():
522
+ await self._process_items(*get_items_nowait(self._queue))
523
+
512
524
  @override
513
525
  def _error_upon_core(self, error: Exception, /) -> None:
514
526
  """Handle any errors upon running the core function."""
@@ -19,6 +19,7 @@ from typing import (
19
19
  from uuid import UUID, uuid4
20
20
 
21
21
  from redis.asyncio import Redis
22
+ from redis.asyncio.client import PubSub
22
23
  from redis.typing import EncodableT
23
24
 
24
25
  from utilities.asyncio import InfiniteQueueLooper, QueueProcessor, timeout_dur
@@ -46,7 +47,6 @@ if TYPE_CHECKING:
46
47
  )
47
48
 
48
49
  from redis.asyncio import ConnectionPool
49
- from redis.asyncio.client import PubSub
50
50
  from redis.typing import ResponseT
51
51
 
52
52
  from utilities.iterables import MaybeIterable
@@ -649,7 +649,7 @@ _SUBSCRIBE_SLEEP: Duration = MILLISECOND
649
649
 
650
650
  @overload
651
651
  def subscribe(
652
- pubsub: PubSub,
652
+ redis_or_pubsub: Redis | PubSub,
653
653
  channels: MaybeIterable[str],
654
654
  /,
655
655
  *,
@@ -659,7 +659,7 @@ def subscribe(
659
659
  ) -> AsyncIterator[_T]: ...
660
660
  @overload
661
661
  def subscribe(
662
- pubsub: PubSub,
662
+ redis_or_pubsub: Redis | PubSub,
663
663
  channels: MaybeIterable[str],
664
664
  /,
665
665
  *,
@@ -668,7 +668,7 @@ def subscribe(
668
668
  sleep: Duration = _SUBSCRIBE_SLEEP,
669
669
  ) -> AsyncIterator[bytes]: ...
670
670
  async def subscribe( # pyright: ignore[reportInconsistentOverload]
671
- pubsub: PubSub,
671
+ redis_or_pubsub: Redis | PubSub,
672
672
  channels: MaybeIterable[str],
673
673
  /,
674
674
  *,
@@ -679,7 +679,7 @@ async def subscribe( # pyright: ignore[reportInconsistentOverload]
679
679
  """Subscribe to the data of a given channel(s)."""
680
680
  channels = list(always_iterable(channels)) # skipif-ci-and-not-linux
681
681
  messages = subscribe_messages( # skipif-ci-and-not-linux
682
- pubsub, channels, timeout=timeout, sleep=sleep
682
+ redis_or_pubsub, channels, timeout=timeout, sleep=sleep
683
683
  )
684
684
  if deserializer is None: # skipif-ci-and-not-linux
685
685
  async for message in messages:
@@ -690,7 +690,7 @@ async def subscribe( # pyright: ignore[reportInconsistentOverload]
690
690
 
691
691
 
692
692
  async def subscribe_messages(
693
- pubsub: PubSub,
693
+ redis_or_pubsub: Redis | PubSub,
694
694
  channels: MaybeIterable[str],
695
695
  /,
696
696
  *,
@@ -698,28 +698,40 @@ async def subscribe_messages(
698
698
  sleep: Duration = _SUBSCRIBE_SLEEP,
699
699
  ) -> AsyncIterator[_RedisMessageSubscribe]:
700
700
  """Subscribe to the messages of a given channel(s)."""
701
- channels = list(always_iterable(channels)) # skipif-ci-and-not-linux
702
- for channel in channels: # skipif-ci-and-not-linux
703
- await pubsub.subscribe(channel)
704
- channels_bytes = [c.encode() for c in channels] # skipif-ci-and-not-linux
705
- timeout_use = ( # skipif-ci-and-not-linux
706
- None if timeout is None else datetime_duration_to_float(timeout)
707
- )
708
- sleep_use = datetime_duration_to_float(sleep) # skipif-ci-and-not-linux
709
- while True: # skipif-ci-and-not-linux
710
- message = cast(
711
- "_RedisMessageSubscribe | _RedisMessageUnsubscribe | None",
712
- await pubsub.get_message(timeout=timeout_use),
713
- )
714
- if (
715
- (message is not None)
716
- and (message["type"] in {"subscribe", "psubscribe", "message", "pmessage"})
717
- and (message["channel"] in channels_bytes)
718
- and isinstance(message["data"], bytes)
719
- ):
720
- yield cast("_RedisMessageSubscribe", message)
721
- else:
722
- await asyncio.sleep(sleep_use)
701
+ match redis_or_pubsub: # skipif-ci-and-not-linux
702
+ case Redis() as redis:
703
+ async for msg in subscribe_messages(
704
+ redis.pubsub(), channels, timeout=timeout, sleep=sleep
705
+ ):
706
+ yield msg
707
+ case PubSub() as pubsub:
708
+ channels = list(always_iterable(channels))
709
+ for channel in channels:
710
+ await pubsub.subscribe(channel)
711
+ channels_bytes = [c.encode() for c in channels]
712
+ timeout_use = (
713
+ None if timeout is None else datetime_duration_to_float(timeout)
714
+ )
715
+ sleep_use = datetime_duration_to_float(sleep)
716
+ while True:
717
+ message = cast(
718
+ "_RedisMessageSubscribe | _RedisMessageUnsubscribe | None",
719
+ await pubsub.get_message(timeout=timeout_use),
720
+ )
721
+ if (
722
+ (message is not None)
723
+ and (
724
+ message["type"]
725
+ in {"subscribe", "psubscribe", "message", "pmessage"}
726
+ )
727
+ and (message["channel"] in channels_bytes)
728
+ and isinstance(message["data"], bytes)
729
+ ):
730
+ yield cast("_RedisMessageSubscribe", message)
731
+ else:
732
+ await asyncio.sleep(sleep_use)
733
+ case _ as never:
734
+ assert_never(never)
723
735
 
724
736
 
725
737
  class _RedisMessageSubscribe(TypedDict):