dycw-utilities 0.114.3__tar.gz → 0.114.5__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.3 → dycw_utilities-0.114.5}/PKG-INFO +1 -1
  2. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/pyproject.toml +2 -2
  3. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_asyncio.py +24 -0
  4. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_slack_sdk.py +49 -1
  5. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/__init__.py +1 -1
  6. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/asyncio.py +2 -2
  7. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/logging.py +25 -15
  8. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/slack_sdk.py +50 -2
  9. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/traceback.py +14 -1
  10. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/.gitignore +0 -0
  11. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/LICENSE +0 -0
  12. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/README.md +0 -0
  13. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/__init__.py +0 -0
  14. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/conftest.py +0 -0
  15. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/__init__.py +0 -0
  16. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_missing/__init__.py +0 -0
  17. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_missing/module.py +0 -0
  18. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_with/__init__.py +0 -0
  19. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_with/outer_1.py +0 -0
  20. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_with/outer_2.py +0 -0
  21. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  22. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  23. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  24. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  25. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_without/__init__.py +0 -0
  26. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_without/module_1.py +0 -0
  27. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/package_without/module_2.py +0 -0
  28. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/standalone.py +0 -0
  29. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/modules/with_imports.py +0 -0
  30. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  31. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  32. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  33. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  34. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  35. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  36. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  37. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  38. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/scripts/__init__.py +0 -0
  39. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/scripts/test_async_service/__init__.py +0 -0
  40. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/scripts/test_async_service/__main__.py +0 -0
  41. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/scripts/test_async_service/run.sh +0 -0
  42. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  43. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  44. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  45. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_altair.py +0 -0
  46. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_astor.py +0 -0
  47. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_atomicwrites.py +0 -0
  48. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_atools.py +0 -0
  49. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_cachetools.py +0 -0
  50. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_click.py +0 -0
  51. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_concurrent.py +0 -0
  52. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_contextlib.py +0 -0
  53. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_contextvars.py +0 -0
  54. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_cryptography.py +0 -0
  55. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_cvxpy.py +0 -0
  56. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_dataclasses.py +0 -0
  57. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_datetime.py +0 -0
  58. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_enum.py +0 -0
  59. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_errors.py +0 -0
  60. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_eventkit.py +0 -0
  61. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_fastapi.py +0 -0
  62. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_fpdf2.py +0 -0
  63. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_functions.py +0 -0
  64. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_functools.py +0 -0
  65. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_getpass.py +0 -0
  66. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_git.py +0 -0
  67. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_hashlib.py +0 -0
  68. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_http.py +0 -0
  69. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_hypothesis.py +0 -0
  70. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_ipython.py +0 -0
  71. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_iterables.py +0 -0
  72. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_jupyter.py +0 -0
  73. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_lightweight_charts.py +0 -0
  74. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_logging.py +0 -0
  75. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_loguru.py +0 -0
  76. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_luigi.py +0 -0
  77. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_math.py +0 -0
  78. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_memory_profiler.py +0 -0
  79. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_modules.py +0 -0
  80. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_more_itertools.py +0 -0
  81. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_numpy.py +0 -0
  82. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_operator.py +0 -0
  83. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_optuna.py +0 -0
  84. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_orjson.py +0 -0
  85. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_os.py +0 -0
  86. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_parse.py +0 -0
  87. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_pathlib.py +0 -0
  88. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_period.py +0 -0
  89. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_pickle.py +0 -0
  90. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_platform.py +0 -0
  91. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_polars.py +0 -0
  92. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_polars_ols.py +0 -0
  93. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_pqdm.py +0 -0
  94. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_pydantic.py +0 -0
  95. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_pyinstrument.py +0 -0
  96. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_pyrsistent.py +0 -0
  97. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_pytest.py +0 -0
  98. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_pytest_regressions.py +0 -0
  99. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_python_dotenv.py +0 -0
  100. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_random.py +0 -0
  101. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_re.py +0 -0
  102. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_redis.py +0 -0
  103. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_reprlib.py +0 -0
  104. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_rich.py +0 -0
  105. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_scipy.py +0 -0
  106. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_sentinel.py +0 -0
  107. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_shelve.py +0 -0
  108. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_socket.py +0 -0
  109. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_sqlalchemy.py +0 -0
  110. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_sqlalchemy_polars.py +0 -0
  111. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_statsmodel.py +0 -0
  112. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_streamlit.py +0 -0
  113. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_sys.py +0 -0
  114. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_tempfile.py +0 -0
  115. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_tenacity.py +0 -0
  116. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_text.py +0 -0
  117. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_threading.py +0 -0
  118. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_timer.py +0 -0
  119. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback.py +0 -0
  120. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/__init__.py +0 -0
  121. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/chain.py +0 -0
  122. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  123. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  124. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  125. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/many.py +0 -0
  126. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/one.py +0 -0
  127. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/recursive.py +0 -0
  128. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  129. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  130. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/two.py +0 -0
  131. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_traceback_funcs/untraced.py +0 -0
  132. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_types.py +0 -0
  133. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_typing.py +0 -0
  134. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_typing_funcs/__init__.py +0 -0
  135. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_typing_funcs/no_future.py +0 -0
  136. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_typing_funcs/with_future.py +0 -0
  137. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_tzdata.py +0 -0
  138. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_tzlocal.py +0 -0
  139. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_uuid.py +0 -0
  140. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_version.py +0 -0
  141. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_warnings.py +0 -0
  142. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_whenever.py +0 -0
  143. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_zipfile.py +0 -0
  144. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/tests/test_zoneinfo.py +0 -0
  145. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/altair.py +0 -0
  146. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/astor.py +0 -0
  147. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/atomicwrites.py +0 -0
  148. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/atools.py +0 -0
  149. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/cachetools.py +0 -0
  150. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/click.py +0 -0
  151. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/concurrent.py +0 -0
  152. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/contextlib.py +0 -0
  153. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/contextvars.py +0 -0
  154. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/cryptography.py +0 -0
  155. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/cvxpy.py +0 -0
  156. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/dataclasses.py +0 -0
  157. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/datetime.py +0 -0
  158. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/enum.py +0 -0
  159. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/errors.py +0 -0
  160. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/eventkit.py +0 -0
  161. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/fastapi.py +0 -0
  162. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/fpdf2.py +0 -0
  163. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/functions.py +0 -0
  164. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/functools.py +0 -0
  165. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/getpass.py +0 -0
  166. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/git.py +0 -0
  167. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/hashlib.py +0 -0
  168. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/http.py +0 -0
  169. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/hypothesis.py +0 -0
  170. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/ipython.py +0 -0
  171. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/iterables.py +0 -0
  172. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/jupyter.py +0 -0
  173. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/lightweight_charts.py +0 -0
  174. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/loguru.py +0 -0
  175. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/luigi.py +0 -0
  176. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/math.py +0 -0
  177. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/memory_profiler.py +0 -0
  178. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/modules.py +0 -0
  179. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/more_itertools.py +0 -0
  180. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/numpy.py +0 -0
  181. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/operator.py +0 -0
  182. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/optuna.py +0 -0
  183. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/orjson.py +0 -0
  184. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/os.py +0 -0
  185. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/parse.py +0 -0
  186. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/pathlib.py +0 -0
  187. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/period.py +0 -0
  188. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/pickle.py +0 -0
  189. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/platform.py +0 -0
  190. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/polars.py +0 -0
  191. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/polars_ols.py +0 -0
  192. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/pqdm.py +0 -0
  193. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/py.typed +0 -0
  194. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/pydantic.py +0 -0
  195. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/pyinstrument.py +0 -0
  196. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/pyrsistent.py +0 -0
  197. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/pytest.py +0 -0
  198. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/pytest_regressions.py +0 -0
  199. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/python_dotenv.py +0 -0
  200. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/random.py +0 -0
  201. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/re.py +0 -0
  202. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/redis.py +0 -0
  203. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/reprlib.py +0 -0
  204. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/rich.py +0 -0
  205. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/scipy.py +0 -0
  206. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/sentinel.py +0 -0
  207. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/shelve.py +0 -0
  208. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/socket.py +0 -0
  209. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/sqlalchemy.py +0 -0
  210. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/sqlalchemy_polars.py +0 -0
  211. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/statsmodels.py +0 -0
  212. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/streamlit.py +0 -0
  213. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/sys.py +0 -0
  214. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/tempfile.py +0 -0
  215. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/tenacity.py +0 -0
  216. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/text.py +0 -0
  217. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/threading.py +0 -0
  218. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/timer.py +0 -0
  219. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/types.py +0 -0
  220. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/typing.py +0 -0
  221. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/tzdata.py +0 -0
  222. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/tzlocal.py +0 -0
  223. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/uuid.py +0 -0
  224. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/version.py +0 -0
  225. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/warnings.py +0 -0
  226. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/whenever.py +0 -0
  227. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/src/utilities/zipfile.py +0 -0
  228. {dycw_utilities-0.114.3 → dycw_utilities-0.114.5}/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.3
3
+ Version: 0.114.5
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.3"
95
+ version = "0.114.5"
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.3"
337
+ current_version = "0.114.5"
338
338
 
339
339
  [[tool.bumpversion.files]]
340
340
  filename = "src/utilities/__init__.py"
@@ -375,6 +375,30 @@ class TestInfiniteLooper:
375
375
  with raises(FalseError):
376
376
  _ = await looper()
377
377
 
378
+ async def test_hashable(self) -> None:
379
+ class CustomError(BaseException): ...
380
+
381
+ @dataclass(kw_only=True, unsafe_hash=True)
382
+ class Example(InfiniteLooper[None]):
383
+ counter: int = 0
384
+
385
+ @override
386
+ async def _initialize(self) -> None:
387
+ self.counter = 0
388
+
389
+ @override
390
+ async def _core(self) -> None:
391
+ self.counter += 1
392
+
393
+ @override
394
+ def _yield_events_and_exceptions(
395
+ self,
396
+ ) -> Iterator[tuple[bool, MaybeType[BaseException]]]:
397
+ yield (None, CustomError)
398
+
399
+ looper = Example(sleep_core=0.1)
400
+ _ = hash(looper)
401
+
378
402
  async def test_multiple(self) -> None:
379
403
  class ChildError(BaseException): ...
380
404
 
@@ -9,11 +9,17 @@ from aiohttp import InvalidUrlClientError
9
9
  from pytest import mark, raises
10
10
  from slack_sdk.webhook.async_client import AsyncWebhookClient
11
11
 
12
+ from utilities.asyncio import EnhancedTaskGroup, sleep_dur
12
13
  from utilities.datetime import MINUTE
13
14
  from utilities.iterables import one
14
15
  from utilities.os import get_env_var
15
16
  from utilities.pytest import throttle
16
- from utilities.slack_sdk import SlackHandler, _get_client, send_to_slack
17
+ from utilities.slack_sdk import (
18
+ SlackHandler,
19
+ SlackHandlerIQL,
20
+ _get_client,
21
+ send_to_slack,
22
+ )
17
23
 
18
24
  if TYPE_CHECKING:
19
25
  from collections.abc import Sequence
@@ -138,3 +144,45 @@ class TestSlackHandler:
138
144
  "message %d from %s", i, TestSlackHandler.test_real.__qualname__
139
145
  )
140
146
  await sleep(0.1)
147
+
148
+
149
+ class TestSlackHandlerIQL:
150
+ async def test_main(self, *, tmp_path: Path) -> None:
151
+ messages: Sequence[str] = []
152
+
153
+ async def sender(_: str, text: str, /) -> None:
154
+ await sleep(0.01)
155
+ messages.append(text)
156
+
157
+ logger = getLogger(str(tmp_path))
158
+ logger.addHandler(handler := SlackHandlerIQL("url", sender=sender))
159
+
160
+ async def sleep_then_log() -> None:
161
+ await sleep_dur(duration=0.1)
162
+ logger.warning("message")
163
+
164
+ with raises(ExceptionGroup): # noqa: PT012
165
+ async with EnhancedTaskGroup(timeout=0.5) as tg:
166
+ _ = tg.create_task(handler())
167
+ _ = tg.create_task(sleep_then_log())
168
+
169
+ assert messages == ["message"]
170
+
171
+ @mark.skipif(get_env_var("SLACK", nullable=True) is None, reason="'SLACK' not set")
172
+ @throttle(duration=5 * MINUTE)
173
+ async def test_real(self, *, tmp_path: Path) -> None:
174
+ url = get_env_var("SLACK")
175
+ logger = getLogger(str(tmp_path))
176
+ logger.addHandler(handler := SlackHandlerIQL(url))
177
+
178
+ async def sleep_then_log() -> None:
179
+ await sleep_dur(duration=0.1)
180
+ for i in range(10):
181
+ logger.warning(
182
+ "message %d from %s", i, TestSlackHandlerIQL.test_real.__qualname__
183
+ )
184
+
185
+ with raises(ExceptionGroup): # noqa: PT012
186
+ async with EnhancedTaskGroup(timeout=0.5) as tg:
187
+ _ = tg.create_task(handler())
188
+ _ = tg.create_task(sleep_then_log())
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.114.3"
3
+ __version__ = "0.114.5"
@@ -326,7 +326,7 @@ class ExceptionProcessor(QueueProcessor[Exception | type[Exception]]):
326
326
  ##
327
327
 
328
328
 
329
- @dataclass(kw_only=True)
329
+ @dataclass(kw_only=True, unsafe_hash=True)
330
330
  class InfiniteLooper(ABC, Generic[THashable]):
331
331
  """An infinite loop which can throw exceptions by setting events."""
332
332
 
@@ -334,7 +334,7 @@ class InfiniteLooper(ABC, Generic[THashable]):
334
334
  sleep_restart: Duration = MINUTE
335
335
  logger: str | None = None
336
336
  _events: Mapping[THashable, Event] = field(
337
- default_factory=dict, init=False, repr=False
337
+ default_factory=dict, init=False, repr=False, hash=False
338
338
  )
339
339
 
340
340
  def __post_init__(self) -> None:
@@ -587,19 +587,19 @@ def setup_logging(
587
587
 
588
588
  # console
589
589
  if console_level is not None: # skipif-ci-and-windows
590
- console_low_handler = StreamHandler(stream=stdout)
591
- add_filters(console_low_handler, lambda x: x.levelno < ERROR)
592
- add_filters(console_low_handler, *console_filters)
593
- add_filters(console_low_handler, *filters)
594
- console_low_handler.setFormatter(console_formatter)
595
- console_low_handler.setLevel(console_level)
596
- logger_use.addHandler(console_low_handler)
597
-
598
- console_high_handler = StreamHandler(stream=stdout)
599
- add_filters(console_high_handler, *console_filters)
600
- add_filters(console_high_handler, *filters)
590
+ console_low_or_no_exc_handler = StreamHandler(stream=stdout)
591
+ add_filters(console_low_or_no_exc_handler, _console_low_or_no_exc_filter)
592
+ add_filters(console_low_or_no_exc_handler, *console_filters)
593
+ add_filters(console_low_or_no_exc_handler, *filters)
594
+ console_low_or_no_exc_handler.setFormatter(console_formatter)
595
+ console_low_or_no_exc_handler.setLevel(console_level)
596
+ logger_use.addHandler(console_low_or_no_exc_handler)
597
+
598
+ console_high_and_exc_handler = StreamHandler(stream=stdout)
599
+ add_filters(console_high_and_exc_handler, *console_filters)
600
+ add_filters(console_high_and_exc_handler, *filters)
601
601
  _ = RichTracebackFormatter.create_and_set(
602
- console_high_handler,
602
+ console_high_and_exc_handler,
603
603
  version=formatter_version,
604
604
  max_width=formatter_max_width,
605
605
  indent_size=formatter_indent_size,
@@ -610,10 +610,10 @@ def setup_logging(
610
610
  detail=True,
611
611
  post=_ansi_wrap_red,
612
612
  )
613
- console_high_handler.setLevel(
613
+ console_high_and_exc_handler.setLevel(
614
614
  max(get_logging_level_number(console_level), ERROR)
615
615
  )
616
- logger_use.addHandler(console_high_handler)
616
+ logger_use.addHandler(console_high_and_exc_handler)
617
617
 
618
618
  # debug & info
619
619
  directory = resolve_path(path=files_dir) # skipif-ci-and-windows
@@ -640,7 +640,7 @@ def setup_logging(
640
640
  standalone_file_handler = StandaloneFileHandler( # skipif-ci-and-windows
641
641
  level=ERROR, path=directory.joinpath("errors")
642
642
  )
643
- add_filters(standalone_file_handler, lambda x: x.exc_info is not None)
643
+ add_filters(standalone_file_handler, _standalone_file_filter)
644
644
  standalone_file_handler.setFormatter(
645
645
  RichTracebackFormatter(
646
646
  version=formatter_version,
@@ -660,6 +660,16 @@ def setup_logging(
660
660
  extra(logger_use)
661
661
 
662
662
 
663
+ def _console_low_or_no_exc_filter(record: LogRecord, /) -> bool:
664
+ return (record.levelno < ERROR) or (
665
+ (record.levelno >= ERROR) and (record.exc_info is None)
666
+ )
667
+
668
+
669
+ def _standalone_file_filter(record: LogRecord, /) -> bool:
670
+ return record.exc_info is not None
671
+
672
+
663
673
  ##
664
674
 
665
675
 
@@ -9,7 +9,12 @@ from typing import TYPE_CHECKING, override
9
9
 
10
10
  from slack_sdk.webhook.async_client import AsyncWebhookClient
11
11
 
12
- from utilities.asyncio import QueueProcessor, sleep_dur, timeout_dur
12
+ from utilities.asyncio import (
13
+ InfiniteQueueLooper,
14
+ QueueProcessor,
15
+ sleep_dur,
16
+ timeout_dur,
17
+ )
13
18
  from utilities.datetime import MINUTE, SECOND, datetime_duration_to_float
14
19
  from utilities.functools import cache
15
20
  from utilities.math import safe_round
@@ -95,6 +100,49 @@ class SlackHandler(Handler, QueueProcessor[str]):
95
100
  await sleep_dur(duration=self.sleep)
96
101
 
97
102
 
103
+ @dataclass(init=False, unsafe_hash=True)
104
+ class SlackHandlerIQL(Handler, InfiniteQueueLooper[None, str]):
105
+ """Handler for sending messages to Slack."""
106
+
107
+ @override
108
+ def __init__(
109
+ self,
110
+ url: str,
111
+ /,
112
+ *,
113
+ level: int = NOTSET,
114
+ sleep_core: Duration = _SLEEP,
115
+ sleep_restart: Duration = _SLEEP,
116
+ queue_type: type[Queue[str]] = Queue,
117
+ sender: Callable[[str, str], Coroutine1[None]] = _send_adapter,
118
+ timeout: Duration = _TIMEOUT,
119
+ ) -> None:
120
+ InfiniteQueueLooper.__init__( # InfiniteQueueLooper first
121
+ self, queue_type=queue_type
122
+ )
123
+ InfiniteQueueLooper.__post_init__(self)
124
+ Handler.__init__(self, level=level)
125
+ self.url = url
126
+ self.sender = sender
127
+ self.timeout = timeout
128
+ self.sleep_core = sleep_core
129
+ self.sleep_restart = sleep_restart
130
+
131
+ @override
132
+ def emit(self, record: LogRecord) -> None:
133
+ try:
134
+ self.put_items_nowait(self.format(record))
135
+ except Exception: # noqa: BLE001 # pragma: no cover
136
+ self.handleError(record)
137
+
138
+ @override
139
+ async def _process_items(self, *items: str) -> None:
140
+ """Process the first item."""
141
+ text = "\n".join(items)
142
+ async with timeout_dur(duration=self.timeout):
143
+ await self.sender(self.url, text)
144
+
145
+
98
146
  ##
99
147
 
100
148
 
@@ -128,4 +176,4 @@ def _get_client(url: str, /, *, timeout: Duration = _TIMEOUT) -> AsyncWebhookCli
128
176
  return AsyncWebhookClient(url, timeout=timeout_use)
129
177
 
130
178
 
131
- __all__ = ["SendToSlackError", "SlackHandler", "send_to_slack"]
179
+ __all__ = ["SendToSlackError", "SlackHandler", "SlackHandlerIQL", "send_to_slack"]
@@ -60,6 +60,9 @@ _CALL_ARGS = "_CALL_ARGS"
60
60
  _INDENT = 4 * " "
61
61
 
62
62
 
63
+ ##
64
+
65
+
63
66
  class RichTracebackFormatter(Formatter):
64
67
  """Formatter for rich tracebacks."""
65
68
 
@@ -162,10 +165,17 @@ class RichTracebackFormatter(Formatter):
162
165
  detail=detail,
163
166
  post=post,
164
167
  )
165
- handler.addFilter(lambda r: r.exc_info is not None)
168
+ handler.addFilter(cls._has_exc_info)
166
169
  handler.setFormatter(formatter)
167
170
  return formatter
168
171
 
172
+ @classmethod
173
+ def _has_exc_info(cls, record: LogRecord, /) -> bool:
174
+ return record.exc_info is not None
175
+
176
+
177
+ ##
178
+
169
179
 
170
180
  @dataclass(repr=False, kw_only=True, slots=True)
171
181
  class _CallArgs:
@@ -470,6 +480,9 @@ class _Frame:
470
480
  return indent("\n".join(lines), depth * _INDENT)
471
481
 
472
482
 
483
+ ##
484
+
485
+
473
486
  def get_rich_traceback(
474
487
  error: TBaseException,
475
488
  /,