dycw-utilities 0.129.7__tar.gz → 0.129.8__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.129.7 → dycw_utilities-0.129.8}/PKG-INFO +1 -2
  2. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/pyproject.toml +2 -4
  3. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_logging.py +13 -2
  4. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_whenever.py +10 -0
  5. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/__init__.py +1 -1
  6. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/logging.py +46 -18
  7. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/whenever.py +64 -1
  8. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/.gitignore +0 -0
  9. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/LICENSE +0 -0
  10. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/README.md +0 -0
  11. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/__init__.py +0 -0
  12. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/conftest.py +0 -0
  13. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/__init__.py +0 -0
  14. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_missing/__init__.py +0 -0
  15. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_missing/module.py +0 -0
  16. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_with/__init__.py +0 -0
  17. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_with/outer_1.py +0 -0
  18. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_with/outer_2.py +0 -0
  19. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  20. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  21. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  22. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  23. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_without/__init__.py +0 -0
  24. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_without/module_1.py +0 -0
  25. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/package_without/module_2.py +0 -0
  26. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/standalone.py +0 -0
  27. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/modules/with_imports.py +0 -0
  28. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  29. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  30. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  31. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  32. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  33. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  34. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  35. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  36. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_altair.py +0 -0
  37. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_asyncio.py +0 -0
  38. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_asyncio_classes/__init__.py +0 -0
  39. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_asyncio_classes/loopers.py +0 -0
  40. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_asyncio_classes/redis.py +0 -0
  41. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_atomicwrites.py +0 -0
  42. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_atools.py +0 -0
  43. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_cachetools.py +0 -0
  44. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_click.py +0 -0
  45. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_concurrent.py +0 -0
  46. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_contextlib.py +0 -0
  47. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_contextvars.py +0 -0
  48. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_cryptography.py +0 -0
  49. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_cvxpy.py +0 -0
  50. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_dataclasses.py +0 -0
  51. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_datetime.py +0 -0
  52. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_enum.py +0 -0
  53. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_errors.py +0 -0
  54. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_eventkit.py +0 -0
  55. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_fastapi.py +0 -0
  56. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_fpdf2.py +0 -0
  57. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_functions.py +0 -0
  58. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_functools.py +0 -0
  59. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_getpass.py +0 -0
  60. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_hashlib.py +0 -0
  61. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_http.py +0 -0
  62. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_hypothesis.py +0 -0
  63. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_importlib.py +0 -0
  64. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_ipython.py +0 -0
  65. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_iterables.py +0 -0
  66. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_jupyter.py +0 -0
  67. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_libcst.py +0 -0
  68. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_lightweight_charts.py +0 -0
  69. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_loguru.py +0 -0
  70. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_luigi.py +0 -0
  71. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_math.py +0 -0
  72. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_memory_profiler.py +0 -0
  73. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_modules.py +0 -0
  74. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_more_itertools.py +0 -0
  75. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_numpy.py +0 -0
  76. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_operator.py +0 -0
  77. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_optuna.py +0 -0
  78. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_orjson.py +0 -0
  79. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_os.py +0 -0
  80. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_parse.py +0 -0
  81. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pathlib.py +0 -0
  82. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_period.py +0 -0
  83. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pickle.py +0 -0
  84. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_platform.py +0 -0
  85. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_polars.py +0 -0
  86. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_polars_ols.py +0 -0
  87. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pottery.py +0 -0
  88. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pqdm.py +0 -0
  89. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_psutil.py +0 -0
  90. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pydantic.py +0 -0
  91. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pyinstrument.py +0 -0
  92. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pyrsistent.py +0 -0
  93. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pytest.py +0 -0
  94. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_pytest_regressions.py +0 -0
  95. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_python_dotenv.py +0 -0
  96. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_random.py +0 -0
  97. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_re.py +0 -0
  98. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_redis.py +0 -0
  99. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_reprlib.py +0 -0
  100. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_scipy.py +0 -0
  101. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_sentinel.py +0 -0
  102. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_shelve.py +0 -0
  103. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_slack_sdk.py +0 -0
  104. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_socket.py +0 -0
  105. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_sqlalchemy.py +0 -0
  106. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_sqlalchemy_polars.py +0 -0
  107. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_statsmodel.py +0 -0
  108. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_streamlit.py +0 -0
  109. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_string.py +0 -0
  110. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_sys.py +0 -0
  111. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_tempfile.py +0 -0
  112. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_tenacity.py +0 -0
  113. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_text.py +0 -0
  114. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_threading.py +0 -0
  115. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_timer.py +0 -0
  116. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback.py +0 -0
  117. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/__init__.py +0 -0
  118. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/chain.py +0 -0
  119. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  120. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  121. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  122. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/many.py +0 -0
  123. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/one.py +0 -0
  124. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/recursive.py +0 -0
  125. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  126. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  127. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/two.py +0 -0
  128. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_traceback_funcs/untraced.py +0 -0
  129. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_types.py +0 -0
  130. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_typing.py +0 -0
  131. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_typing_funcs/__init__.py +0 -0
  132. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_typing_funcs/no_future.py +0 -0
  133. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_typing_funcs/with_future.py +0 -0
  134. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_tzdata.py +0 -0
  135. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_tzlocal.py +0 -0
  136. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_uuid.py +0 -0
  137. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_version.py +0 -0
  138. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_warnings.py +0 -0
  139. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_zipfile.py +0 -0
  140. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/tests/test_zoneinfo.py +0 -0
  141. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/altair.py +0 -0
  142. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/asyncio.py +0 -0
  143. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/atomicwrites.py +0 -0
  144. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/atools.py +0 -0
  145. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/cachetools.py +0 -0
  146. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/click.py +0 -0
  147. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/concurrent.py +0 -0
  148. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/contextlib.py +0 -0
  149. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/contextvars.py +0 -0
  150. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/cryptography.py +0 -0
  151. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/cvxpy.py +0 -0
  152. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/dataclasses.py +0 -0
  153. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/datetime.py +0 -0
  154. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/enum.py +0 -0
  155. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/errors.py +0 -0
  156. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/eventkit.py +0 -0
  157. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/fastapi.py +0 -0
  158. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/fpdf2.py +0 -0
  159. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/functions.py +0 -0
  160. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/functools.py +0 -0
  161. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/getpass.py +0 -0
  162. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/hashlib.py +0 -0
  163. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/http.py +0 -0
  164. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/hypothesis.py +0 -0
  165. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/importlib.py +0 -0
  166. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/ipython.py +0 -0
  167. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/iterables.py +0 -0
  168. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/jupyter.py +0 -0
  169. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/libcst.py +0 -0
  170. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/lightweight_charts.py +0 -0
  171. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/loguru.py +0 -0
  172. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/luigi.py +0 -0
  173. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/math.py +0 -0
  174. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/memory_profiler.py +0 -0
  175. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/modules.py +0 -0
  176. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/more_itertools.py +0 -0
  177. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/numpy.py +0 -0
  178. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/operator.py +0 -0
  179. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/optuna.py +0 -0
  180. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/orjson.py +0 -0
  181. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/os.py +0 -0
  182. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/parse.py +0 -0
  183. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pathlib.py +0 -0
  184. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/period.py +0 -0
  185. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pickle.py +0 -0
  186. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/platform.py +0 -0
  187. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/polars.py +0 -0
  188. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/polars_ols.py +0 -0
  189. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pottery.py +0 -0
  190. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pqdm.py +0 -0
  191. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/psutil.py +0 -0
  192. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/py.typed +0 -0
  193. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pydantic.py +0 -0
  194. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pyinstrument.py +0 -0
  195. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pyrsistent.py +0 -0
  196. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pytest.py +0 -0
  197. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/pytest_regressions.py +0 -0
  198. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/python_dotenv.py +0 -0
  199. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/random.py +0 -0
  200. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/re.py +0 -0
  201. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/redis.py +0 -0
  202. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/reprlib.py +0 -0
  203. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/scipy.py +0 -0
  204. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/sentinel.py +0 -0
  205. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/shelve.py +0 -0
  206. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/slack_sdk.py +0 -0
  207. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/socket.py +0 -0
  208. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/sqlalchemy.py +0 -0
  209. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/sqlalchemy_polars.py +0 -0
  210. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/statsmodels.py +0 -0
  211. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/streamlit.py +0 -0
  212. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/string.py +0 -0
  213. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/sys.py +0 -0
  214. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/tempfile.py +0 -0
  215. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/tenacity.py +0 -0
  216. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/text.py +0 -0
  217. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/threading.py +0 -0
  218. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/timer.py +0 -0
  219. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/traceback.py +0 -0
  220. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/types.py +0 -0
  221. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/typing.py +0 -0
  222. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/tzdata.py +0 -0
  223. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/tzlocal.py +0 -0
  224. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/uuid.py +0 -0
  225. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/version.py +0 -0
  226. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/warnings.py +0 -0
  227. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/zipfile.py +0 -0
  228. {dycw_utilities-0.129.7 → dycw_utilities-0.129.8}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.129.7
3
+ Version: 0.129.8
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -98,7 +98,6 @@ Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-jupyter'
98
98
  Provides-Extra: zzz-test-logging
99
99
  Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-logging'
100
100
  Requires-Dist: coloredlogs<15.1,>=15.0.1; extra == 'zzz-test-logging'
101
- Requires-Dist: concurrent-log-handler<0.10,>=0.9.26; extra == 'zzz-test-logging'
102
101
  Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-logging'
103
102
  Requires-Dist: tomlkit<0.14,>=0.13.2; extra == 'zzz-test-logging'
104
103
  Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-logging'
@@ -17,7 +17,6 @@ dev = [
17
17
  "cachetools >= 5.5.2, < 5.6",
18
18
  "click >= 8.2.1, < 8.3",
19
19
  "coloredlogs >= 15.0.1, < 15.1",
20
- "concurrent-log-handler >= 0.9.26, < 0.10",
21
20
  "cryptography >= 45.0.3, < 45.1",
22
21
  "cvxpy >= 1.6.5, < 1.7",
23
22
  "eventkit >= 1.0.3, < 1.1",
@@ -94,7 +93,7 @@ dependencies = [
94
93
  name = "dycw-utilities"
95
94
  readme = "README.md"
96
95
  requires-python = ">= 3.12"
97
- version = "0.129.7"
96
+ version = "0.129.8"
98
97
 
99
98
  [project.optional-dependencies]
100
99
  test = [
@@ -197,7 +196,6 @@ zzz-test-jupyter = [
197
196
  zzz-test-logging = [
198
197
  "atomicwrites >= 1.4.1, < 1.5",
199
198
  "coloredlogs >= 15.0.1, < 15.1",
200
- "concurrent-log-handler >= 0.9.26, < 0.10",
201
199
  "rich >= 14.0.0, < 14.1",
202
200
  "tomlkit >= 0.13.2, < 0.14",
203
201
  "tzlocal >= 5.3.1, < 5.4",
@@ -334,7 +332,7 @@ zzz-test-zoneinfo = [
334
332
  # bump-my-version
335
333
  [tool.bumpversion]
336
334
  allow_dirty = true
337
- current_version = "0.129.7"
335
+ current_version = "0.129.8"
338
336
 
339
337
  [[tool.bumpversion.files]]
340
338
  filename = "src/utilities/__init__.py"
@@ -73,9 +73,13 @@ class TestAddFilters:
73
73
 
74
74
  class TestBasicConfig:
75
75
  @mark.parametrize("log", [param(True), param(False)])
76
- def test_main(self, *, caplog: LogCaptureFixture, log: bool) -> None:
76
+ @mark.parametrize("whenever", [param(True), param(False)])
77
+ @mark.parametrize("plain", [param(True), param(False)])
78
+ def test_main(
79
+ self, *, caplog: LogCaptureFixture, log: bool, whenever: bool, plain: bool
80
+ ) -> None:
77
81
  logger = unique_str() if log else None
78
- basic_config(logger=logger)
82
+ basic_config(obj=logger, whenever=whenever, plain=plain)
79
83
  logger_use = getLogger()
80
84
  logger_use.warning("message")
81
85
  assert "message" in caplog.messages
@@ -484,6 +488,13 @@ class TestSizeAndTimeRotatingFileHandler:
484
488
  content = fh.read()
485
489
  assert content == "message\n"
486
490
 
491
+ @skipif_windows
492
+ def test_create_parents(self, *, tmp_path: Path) -> None:
493
+ logger = getLogger(unique_str())
494
+ filename = tmp_path.joinpath("foo", "bar", "bar", "log")
495
+ logger.addHandler(SizeAndTimeRotatingFileHandler(filename=filename))
496
+ assert filename.exists()
497
+
487
498
  @skipif_windows
488
499
  def test_size(self, *, tmp_path: Path) -> None:
489
500
  logger = getLogger(unique_str())
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import datetime as dt
4
4
  from datetime import timezone
5
+ from logging import getLogger, setLogRecordFactory
5
6
  from re import escape
6
7
  from typing import TYPE_CHECKING
7
8
  from zoneinfo import ZoneInfo
@@ -40,6 +41,7 @@ from utilities.hypothesis import (
40
41
  timedeltas_2w,
41
42
  zoned_datetimes,
42
43
  )
44
+ from utilities.text import unique_str
43
45
  from utilities.tzdata import HongKong
44
46
  from utilities.whenever import (
45
47
  MAX_SERIALIZABLE_TIMEDELTA,
@@ -60,6 +62,7 @@ from utilities.whenever import (
60
62
  SerializePlainDateTimeError,
61
63
  SerializeTimeDeltaError,
62
64
  SerializeZonedDateTimeError,
65
+ WheneverLogRecord,
63
66
  _CheckValidZonedDateTimeUnequalError,
64
67
  _EnsureTimedeltaNanosecondError,
65
68
  _EnsureTimedeltaParseError,
@@ -492,3 +495,10 @@ class TestToDateTimeDelta:
492
495
  _ToDateTimeDeltaError, match="Unable to create DateTimeDelta; got .*"
493
496
  ):
494
497
  _ = _to_datetime_delta(timedelta)
498
+
499
+
500
+ class TestWheneverLogRecord:
501
+ def test_main(self) -> None:
502
+ logger = getLogger(unique_str())
503
+ setLogRecordFactory(WheneverLogRecord)
504
+ logger.warning("message")
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.129.7"
3
+ __version__ = "0.129.8"
@@ -107,8 +107,9 @@ class SizeAndTimeRotatingFileHandler(BaseRotatingHandler):
107
107
  utc: bool = False,
108
108
  atTime: dt.time | None = None,
109
109
  ) -> None:
110
- filename = str(Path(filename))
111
- super().__init__(filename, mode, encoding=encoding, delay=delay, errors=errors)
110
+ path = Path(filename)
111
+ path.parent.mkdir(parents=True, exist_ok=True)
112
+ super().__init__(path, mode, encoding=encoding, delay=delay, errors=errors)
112
113
  self._max_bytes = maxBytes if maxBytes >= 1 else None
113
114
  self._backup_count = backupCount if backupCount >= 1 else None
114
115
  self._filename = Path(self.baseFilename)
@@ -117,7 +118,7 @@ class SizeAndTimeRotatingFileHandler(BaseRotatingHandler):
117
118
  self._suffix = self._filename.suffix
118
119
  self._patterns = _compute_rollover_patterns(self._stem, self._suffix)
119
120
  self._time_handler = TimedRotatingFileHandler(
120
- filename,
121
+ path,
121
122
  when=when,
122
123
  interval=interval,
123
124
  backupCount=backupCount,
@@ -415,26 +416,53 @@ def add_filters(handler: Handler, /, *filters: _FilterType) -> None:
415
416
 
416
417
  def basic_config(
417
418
  *,
418
- logger: LoggerOrName | None = None,
419
+ obj: LoggerOrName | Handler | None = None,
419
420
  format_: str = "{asctime} | {name} | {levelname:8} | {message}",
421
+ whenever: bool = False,
420
422
  level: LogLevel = "INFO",
423
+ plain: bool = False,
421
424
  ) -> None:
422
425
  """Do the basic config."""
426
+ if whenever:
427
+ format_ = format_.replace("{asctime}", "{zoned_datetime}")
423
428
  datefmt = maybe_sub_pct_y("%Y-%m-%d %H:%M:%S")
424
- if logger is None:
425
- basicConfig(format=format_, datefmt=datefmt, style="{", level=level)
426
- else:
427
- logger_use = get_logger(logger=logger)
428
- logger_use.setLevel(level)
429
- logger_use.addHandler(handler := StreamHandler())
430
- handler.setLevel(level)
431
- try:
432
- from coloredlogs import ColoredFormatter
433
- except ModuleNotFoundError: # pragma: no cover
434
- formatter = Formatter(fmt=format_, datefmt=datefmt, style="{")
435
- else:
436
- formatter = ColoredFormatter(fmt=format_, datefmt=datefmt, style="{")
437
- handler.setFormatter(formatter)
429
+ match obj:
430
+ case None:
431
+ basicConfig(format=format_, datefmt=datefmt, style="{", level=level)
432
+ case Logger() as logger:
433
+ logger.setLevel(level)
434
+ logger.addHandler(handler := StreamHandler())
435
+ basic_config(
436
+ obj=handler,
437
+ format_=format_,
438
+ whenever=whenever,
439
+ level=level,
440
+ plain=plain,
441
+ )
442
+ case str() as name:
443
+ basic_config(
444
+ obj=get_logger(logger=name),
445
+ format_=format_,
446
+ whenever=whenever,
447
+ level=level,
448
+ plain=plain,
449
+ )
450
+ case Handler() as handler:
451
+ handler.setLevel(level)
452
+ if plain:
453
+ formatter = Formatter(fmt=format_, datefmt=datefmt, style="{")
454
+ else:
455
+ try:
456
+ from coloredlogs import ColoredFormatter
457
+ except ModuleNotFoundError: # pragma: no cover
458
+ formatter = Formatter(fmt=format_, datefmt=datefmt, style="{")
459
+ else:
460
+ formatter = ColoredFormatter(
461
+ fmt=format_, datefmt=datefmt, style="{"
462
+ )
463
+ handler.setFormatter(formatter)
464
+ case _ as never:
465
+ assert_never(never)
438
466
 
439
467
 
440
468
  ##
@@ -4,7 +4,9 @@ import datetime as dt
4
4
  import re
5
5
  from contextlib import suppress
6
6
  from dataclasses import dataclass
7
- from typing import TYPE_CHECKING, override
7
+ from functools import cache
8
+ from logging import LogRecord
9
+ from typing import TYPE_CHECKING, Any, override
8
10
 
9
11
  from whenever import (
10
12
  Date,
@@ -33,6 +35,8 @@ from utilities.re import (
33
35
  from utilities.zoneinfo import UTC, ensure_time_zone, get_time_zone_name
34
36
 
35
37
  if TYPE_CHECKING:
38
+ from zoneinfo import ZoneInfo
39
+
36
40
  from utilities.types import (
37
41
  DateLike,
38
42
  DateTimeLike,
@@ -561,6 +565,64 @@ class SerializeZonedDateTimeError(Exception):
561
565
  ##
562
566
 
563
567
 
568
+ class WheneverLogRecord(LogRecord):
569
+ """Log record powered by `whenever`."""
570
+
571
+ zoned_datetime: str
572
+
573
+ @override
574
+ def __init__(
575
+ self,
576
+ name: str,
577
+ level: int,
578
+ pathname: str,
579
+ lineno: int,
580
+ msg: object,
581
+ args: Any,
582
+ exc_info: Any,
583
+ func: str | None = None,
584
+ sinfo: str | None = None,
585
+ ) -> None:
586
+ super().__init__(
587
+ name, level, pathname, lineno, msg, args, exc_info, func, sinfo
588
+ )
589
+ length = self._get_length()
590
+ plain = format(self._get_now().to_plain().format_common_iso(), f"{length}s")
591
+ time_zone = self._get_time_zone_key()
592
+ self.zoned_datetime = f"{plain}[{time_zone}]"
593
+
594
+ @classmethod
595
+ @cache
596
+ def _get_time_zone(cls) -> ZoneInfo:
597
+ """Get the local timezone."""
598
+ try:
599
+ from utilities.tzlocal import get_local_time_zone
600
+ except ModuleNotFoundError: # pragma: no cover
601
+ return UTC
602
+ return get_local_time_zone()
603
+
604
+ @classmethod
605
+ @cache
606
+ def _get_time_zone_key(cls) -> str:
607
+ """Get the local timezone as a string."""
608
+ return cls._get_time_zone().key
609
+
610
+ @classmethod
611
+ @cache
612
+ def _get_length(cls) -> int:
613
+ """Get maximum length of a formatted string."""
614
+ now = cls._get_now().replace(nanosecond=1000).to_plain()
615
+ return len(now.format_common_iso())
616
+
617
+ @classmethod
618
+ def _get_now(cls) -> ZonedDateTime:
619
+ """Get the current zoned datetime."""
620
+ return ZonedDateTime.now(cls._get_time_zone().key)
621
+
622
+
623
+ ##
624
+
625
+
564
626
  def _to_datetime_delta(timedelta: dt.timedelta, /) -> DateTimeDelta:
565
627
  """Serialize a timedelta."""
566
628
  total_microseconds = datetime_duration_to_microseconds(timedelta)
@@ -610,6 +672,7 @@ __all__ = [
610
672
  "SerializePlainDateTimeError",
611
673
  "SerializeTimeDeltaError",
612
674
  "SerializeZonedDateTimeError",
675
+ "WheneverLogRecord",
613
676
  "check_valid_zoned_datetime",
614
677
  "ensure_date",
615
678
  "ensure_datetime",