dycw-utilities 0.129.15__tar.gz → 0.130.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/PKG-INFO +1 -3
  2. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/pyproject.toml +5 -5
  3. dycw_utilities-0.130.1/src/tests/conftest.py +27 -0
  4. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_logging.py +98 -193
  5. dycw_utilities-0.130.1/src/tests/test_traceback.py +144 -0
  6. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_whenever.py +3 -2
  7. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/__init__.py +1 -1
  8. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/logging.py +276 -498
  9. dycw_utilities-0.130.1/src/utilities/traceback.py +287 -0
  10. dycw_utilities-0.129.15/src/tests/conftest.py +0 -369
  11. dycw_utilities-0.129.15/src/tests/test_loguru.py +0 -139
  12. dycw_utilities-0.129.15/src/tests/test_sys.py +0 -134
  13. dycw_utilities-0.129.15/src/tests/test_traceback.py +0 -725
  14. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/__init__.py +0 -1
  15. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/chain.py +0 -31
  16. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/decorated_async.py +0 -89
  17. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/decorated_sync.py +0 -93
  18. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/error_bind.py +0 -17
  19. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/many.py +0 -17
  20. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/one.py +0 -17
  21. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/recursive.py +0 -19
  22. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/task_group_one.py +0 -34
  23. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/task_group_two.py +0 -43
  24. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/two.py +0 -27
  25. dycw_utilities-0.129.15/src/tests/test_traceback_funcs/untraced.py +0 -14
  26. dycw_utilities-0.129.15/src/utilities/loguru.py +0 -144
  27. dycw_utilities-0.129.15/src/utilities/sys.py +0 -87
  28. dycw_utilities-0.129.15/src/utilities/traceback.py +0 -1086
  29. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/.gitignore +0 -0
  30. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/LICENSE +0 -0
  31. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/README.md +0 -0
  32. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/__init__.py +0 -0
  33. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/__init__.py +0 -0
  34. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_missing/__init__.py +0 -0
  35. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_missing/module.py +0 -0
  36. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/__init__.py +0 -0
  37. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/outer_1.py +0 -0
  38. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/outer_2.py +0 -0
  39. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  40. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  41. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  42. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  43. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_without/__init__.py +0 -0
  44. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_without/module_1.py +0 -0
  45. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_without/module_2.py +0 -0
  46. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/standalone.py +0 -0
  47. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/with_imports.py +0 -0
  48. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  49. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  50. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  51. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  52. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  53. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  54. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  55. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  56. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_aiolimiter.py +0 -0
  57. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_altair.py +0 -0
  58. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_asyncio.py +0 -0
  59. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_asyncio_classes/__init__.py +0 -0
  60. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_asyncio_classes/loopers.py +0 -0
  61. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_asyncio_classes/redis.py +0 -0
  62. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_atomicwrites.py +0 -0
  63. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_atools.py +0 -0
  64. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_cachetools.py +0 -0
  65. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_click.py +0 -0
  66. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_concurrent.py +0 -0
  67. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_contextlib.py +0 -0
  68. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_contextvars.py +0 -0
  69. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_cryptography.py +0 -0
  70. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_cvxpy.py +0 -0
  71. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_dataclasses.py +0 -0
  72. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_datetime.py +0 -0
  73. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_enum.py +0 -0
  74. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_errors.py +0 -0
  75. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_eventkit.py +0 -0
  76. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_fastapi.py +0 -0
  77. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_fpdf2.py +0 -0
  78. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_functions.py +0 -0
  79. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_functools.py +0 -0
  80. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_getpass.py +0 -0
  81. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_git.py +0 -0
  82. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_hashlib.py +0 -0
  83. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_http.py +0 -0
  84. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_hypothesis.py +0 -0
  85. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_importlib.py +0 -0
  86. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_inflect.py +0 -0
  87. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_ipython.py +0 -0
  88. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_iterables.py +0 -0
  89. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_jupyter.py +0 -0
  90. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_libcst.py +0 -0
  91. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_lightweight_charts.py +0 -0
  92. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_luigi.py +0 -0
  93. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_math.py +0 -0
  94. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_memory_profiler.py +0 -0
  95. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_modules.py +0 -0
  96. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_more_itertools.py +0 -0
  97. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_numpy.py +0 -0
  98. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_operator.py +0 -0
  99. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_optuna.py +0 -0
  100. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_orjson.py +0 -0
  101. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_os.py +0 -0
  102. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_parse.py +0 -0
  103. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pathlib.py +0 -0
  104. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_period.py +0 -0
  105. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pickle.py +0 -0
  106. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_platform.py +0 -0
  107. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_polars.py +0 -0
  108. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_polars_ols.py +0 -0
  109. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pottery.py +0 -0
  110. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pqdm.py +0 -0
  111. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_psutil.py +0 -0
  112. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pydantic.py +0 -0
  113. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pyinstrument.py +0 -0
  114. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pyrsistent.py +0 -0
  115. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pytest.py +0 -0
  116. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pytest_regressions.py +0 -0
  117. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_python_dotenv.py +0 -0
  118. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_random.py +0 -0
  119. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_re.py +0 -0
  120. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_redis.py +0 -0
  121. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_reprlib.py +0 -0
  122. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_scipy.py +0 -0
  123. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_sentinel.py +0 -0
  124. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_shelve.py +0 -0
  125. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_slack_sdk.py +0 -0
  126. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_socket.py +0 -0
  127. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_sqlalchemy.py +0 -0
  128. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_sqlalchemy_polars.py +0 -0
  129. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_statsmodel.py +0 -0
  130. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_streamlit.py +0 -0
  131. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_string.py +0 -0
  132. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_tempfile.py +0 -0
  133. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_tenacity.py +0 -0
  134. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_text.py +0 -0
  135. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_threading.py +0 -0
  136. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_timer.py +0 -0
  137. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_types.py +0 -0
  138. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_typing.py +0 -0
  139. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_typing_funcs/__init__.py +0 -0
  140. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_typing_funcs/no_future.py +0 -0
  141. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_typing_funcs/with_future.py +0 -0
  142. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_tzdata.py +0 -0
  143. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_tzlocal.py +0 -0
  144. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_uuid.py +0 -0
  145. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_version.py +0 -0
  146. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_warnings.py +0 -0
  147. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_zipfile.py +0 -0
  148. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_zoneinfo.py +0 -0
  149. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/aiolimiter.py +0 -0
  150. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/altair.py +0 -0
  151. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/asyncio.py +0 -0
  152. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/atomicwrites.py +0 -0
  153. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/atools.py +0 -0
  154. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/cachetools.py +0 -0
  155. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/click.py +0 -0
  156. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/concurrent.py +0 -0
  157. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/contextlib.py +0 -0
  158. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/contextvars.py +0 -0
  159. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/cryptography.py +0 -0
  160. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/cvxpy.py +0 -0
  161. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/dataclasses.py +0 -0
  162. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/datetime.py +0 -0
  163. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/enum.py +0 -0
  164. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/errors.py +0 -0
  165. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/eventkit.py +0 -0
  166. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/fastapi.py +0 -0
  167. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/fpdf2.py +0 -0
  168. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/functions.py +0 -0
  169. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/functools.py +0 -0
  170. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/getpass.py +0 -0
  171. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/git.py +0 -0
  172. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/hashlib.py +0 -0
  173. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/http.py +0 -0
  174. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/hypothesis.py +0 -0
  175. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/importlib.py +0 -0
  176. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/inflect.py +0 -0
  177. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/ipython.py +0 -0
  178. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/iterables.py +0 -0
  179. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/jupyter.py +0 -0
  180. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/libcst.py +0 -0
  181. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/lightweight_charts.py +0 -0
  182. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/luigi.py +0 -0
  183. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/math.py +0 -0
  184. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/memory_profiler.py +0 -0
  185. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/modules.py +0 -0
  186. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/more_itertools.py +0 -0
  187. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/numpy.py +0 -0
  188. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/operator.py +0 -0
  189. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/optuna.py +0 -0
  190. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/orjson.py +0 -0
  191. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/os.py +0 -0
  192. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/parse.py +0 -0
  193. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pathlib.py +0 -0
  194. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/period.py +0 -0
  195. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pickle.py +0 -0
  196. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/platform.py +0 -0
  197. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/polars.py +0 -0
  198. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/polars_ols.py +0 -0
  199. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pottery.py +0 -0
  200. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pqdm.py +0 -0
  201. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/psutil.py +0 -0
  202. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/py.typed +0 -0
  203. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pydantic.py +0 -0
  204. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pyinstrument.py +0 -0
  205. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pyrsistent.py +0 -0
  206. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pytest.py +0 -0
  207. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pytest_regressions.py +0 -0
  208. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/python_dotenv.py +0 -0
  209. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/random.py +0 -0
  210. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/re.py +0 -0
  211. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/redis.py +0 -0
  212. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/reprlib.py +0 -0
  213. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/scipy.py +0 -0
  214. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/sentinel.py +0 -0
  215. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/shelve.py +0 -0
  216. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/slack_sdk.py +0 -0
  217. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/socket.py +0 -0
  218. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/sqlalchemy.py +0 -0
  219. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/sqlalchemy_polars.py +0 -0
  220. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/statsmodels.py +0 -0
  221. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/streamlit.py +0 -0
  222. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/string.py +0 -0
  223. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/tempfile.py +0 -0
  224. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/tenacity.py +0 -0
  225. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/text.py +0 -0
  226. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/threading.py +0 -0
  227. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/timer.py +0 -0
  228. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/types.py +0 -0
  229. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/typing.py +0 -0
  230. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/tzdata.py +0 -0
  231. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/tzlocal.py +0 -0
  232. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/uuid.py +0 -0
  233. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/version.py +0 -0
  234. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/warnings.py +0 -0
  235. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/whenever.py +0 -0
  236. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/zipfile.py +0 -0
  237. {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.129.15
3
+ Version: 0.130.1
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -109,8 +109,6 @@ Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-logging'
109
109
  Requires-Dist: tomlkit<0.14,>=0.13.2; extra == 'zzz-test-logging'
110
110
  Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-logging'
111
111
  Requires-Dist: whenever<0.9,>=0.8.5; extra == 'zzz-test-logging'
112
- Provides-Extra: zzz-test-loguru
113
- Requires-Dist: loguru<0.8,>=0.7.3; extra == 'zzz-test-loguru'
114
112
  Provides-Extra: zzz-test-luigi
115
113
  Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-luigi'
116
114
  Requires-Dist: whenever<0.9,>=0.8.5; extra == 'zzz-test-luigi'
@@ -29,7 +29,6 @@ dev = [
29
29
  "img2pdf >= 0.6.0, < 0.7",
30
30
  "inflect >= 7.5.0, < 7.6",
31
31
  "lightweight-charts >= 2.1, < 2.2",
32
- "loguru >= 0.7.3, < 0.8",
33
32
  "luigi >= 3.6.0, < 3.7",
34
33
  "memory-profiler >= 0.61.0, < 0.62",
35
34
  "more-itertools >= 10.7.0, < 10.8",
@@ -83,7 +82,6 @@ dev = [
83
82
  "pytest-timeout >= 2.4.0, < 2.5",
84
83
  "pytest-xdist >= 3.7.0, < 3.8",
85
84
  # CI
86
- "win32_setctime >= 1.2.0, < 1.3", # https://github.com/Delgan/loguru/issues/147
87
85
  "aiolimiter>=1.2.1",
88
86
  ]
89
87
 
@@ -96,7 +94,7 @@ dependencies = [
96
94
  name = "dycw-utilities"
97
95
  readme = "README.md"
98
96
  requires-python = ">= 3.12"
99
- version = "0.129.15"
97
+ version = "0.130.1"
100
98
 
101
99
  [project.optional-dependencies]
102
100
  logging = [
@@ -213,7 +211,6 @@ zzz-test-logging = [
213
211
  "tzlocal >= 5.3.1, < 5.4",
214
212
  "whenever >= 0.8.5, < 0.9",
215
213
  ]
216
- zzz-test-loguru = ["loguru >= 0.7.3, < 0.8"]
217
214
  zzz-test-luigi = [
218
215
  "luigi >= 3.6.0, < 3.7",
219
216
  "whenever >= 0.8.5, < 0.9",
@@ -344,7 +341,7 @@ zzz-test-zoneinfo = [
344
341
  # bump-my-version
345
342
  [tool.bumpversion]
346
343
  allow_dirty = true
347
- current_version = "0.129.15"
344
+ current_version = "0.130.1"
348
345
 
349
346
  [[tool.bumpversion.files]]
350
347
  filename = "src/utilities/__init__.py"
@@ -464,6 +461,7 @@ filterwarnings = [
464
461
  "ignore:unclosed <socket.*socket .*>:ResourceWarning", # redis
465
462
  "ignore:unclosed Connection <redis.*asyncio.*connection.*Connection.*>:ResourceWarning", # redis
466
463
  "ignore:unclosed event loop <_UnixSelectorEventLoop .*>:ResourceWarning", # redis
464
+ "ignore:unclosed file <_io.*TextIOWrapper .*>:ResourceWarning", # logging
467
465
  "ignore:unclosed transport <_SelectorSocketTransport .*>:ResourceWarning", # redis
468
466
  ]
469
467
  minversion = "8.0"
@@ -478,6 +476,7 @@ unsafe-fixes = true
478
476
 
479
477
  [tool.ruff.format]
480
478
  preview = true
479
+ skip-magic-trailing-comma = true
481
480
 
482
481
  [tool.ruff.lint]
483
482
  explicit-preview-rules = true
@@ -545,3 +544,4 @@ ban-relative-imports = "all"
545
544
 
546
545
  [tool.ruff.lint.isort]
547
546
  required-imports = ["from __future__ import annotations"]
547
+ split-on-trailing-comma = false
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ from os import environ
4
+
5
+ from pytest import mark
6
+
7
+ from utilities.platform import IS_NOT_LINUX, IS_WINDOWS
8
+
9
+ FLAKY = mark.flaky(reruns=5, reruns_delay=1)
10
+ IS_CI = "CI" in environ
11
+ SKIPIF_CI = mark.skipif(IS_CI, reason="Skipped for CI")
12
+ IS_CI_AND_WINDOWS = IS_CI and IS_WINDOWS
13
+ SKIPIF_CI_AND_WINDOWS = mark.skipif(IS_CI_AND_WINDOWS, reason="Skipped for CI/Windows")
14
+ SKIPIF_CI_AND_NOT_LINUX = mark.skipif(
15
+ IS_CI and IS_NOT_LINUX, reason="Skipped for CI/non-Linux"
16
+ )
17
+
18
+
19
+ # hypothesis
20
+
21
+
22
+ try:
23
+ from utilities.hypothesis import setup_hypothesis_profiles
24
+ except ModuleNotFoundError:
25
+ pass
26
+ else:
27
+ setup_hypothesis_profiles()
@@ -1,19 +1,25 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from asyncio import sleep
4
+ from contextlib import contextmanager
3
5
  from io import StringIO
4
- from logging import DEBUG, NOTSET, FileHandler, Logger, StreamHandler, getLogger
6
+ from logging import (
7
+ Formatter,
8
+ Logger,
9
+ LogRecord,
10
+ StreamHandler,
11
+ getLogger,
12
+ setLogRecordFactory,
13
+ )
5
14
  from pathlib import Path
6
15
  from re import search
7
- from time import sleep
8
- from typing import TYPE_CHECKING, Any, Literal, cast
16
+ from typing import TYPE_CHECKING, Any, cast
9
17
 
10
18
  from hypothesis import given
11
19
  from hypothesis.strategies import booleans, integers, none, sampled_from
12
20
  from pytest import LogCaptureFixture, mark, param, raises
13
- from whenever import ZonedDateTime
14
21
 
15
- from tests.test_traceback_funcs.one import func_one
16
- from tests.test_traceback_funcs.untraced import func_untraced
22
+ from tests.conftest import SKIPIF_CI_AND_WINDOWS
17
23
  from utilities.datetime import NOW_UTC, SECOND, serialize_compact
18
24
  from utilities.hypothesis import (
19
25
  assume_does_not_raise,
@@ -27,30 +33,33 @@ from utilities.logging import (
27
33
  FilterForKeyError,
28
34
  GetLoggingLevelNumberError,
29
35
  SizeAndTimeRotatingFileHandler,
30
- StandaloneFileHandler,
31
- _AdvancedLogRecord,
32
36
  _compute_rollover_actions,
37
+ _FieldStyleKeys,
33
38
  _RotatingLogFile,
34
39
  add_filters,
35
40
  basic_config,
36
41
  filter_for_key,
37
- get_default_logging_path,
42
+ get_formatter,
38
43
  get_logger,
39
44
  get_logging_level_number,
40
45
  setup_logging,
41
- temp_handler,
42
- temp_logger,
43
46
  )
44
- from utilities.pytest import skipif_windows
45
47
  from utilities.text import unique_str
46
48
  from utilities.types import LogLevel
47
49
  from utilities.typing import get_args
48
50
 
49
51
  if TYPE_CHECKING:
50
52
  import datetime as dt
51
- from re import Pattern
53
+ from collections.abc import Iterator, Mapping
54
+ from logging import _FilterType
55
+
52
56
 
53
- from utilities.types import LoggerOrName
57
+ @contextmanager
58
+ def _temp_log_factory() -> Iterator[None]:
59
+ try:
60
+ yield
61
+ finally:
62
+ setLogRecordFactory(LogRecord)
54
63
 
55
64
 
56
65
  class TestAddFilters:
@@ -72,22 +81,38 @@ class TestAddFilters:
72
81
 
73
82
 
74
83
  class TestBasicConfig:
75
- @mark.parametrize("log", [param(True), param(False)])
76
84
  @mark.parametrize("whenever", [param(True), param(False)])
85
+ @mark.parametrize(
86
+ "filters",
87
+ [
88
+ param(lambda _: True), # pyright: ignore[reportUnknownLambdaType]
89
+ param(None),
90
+ ],
91
+ )
77
92
  @mark.parametrize("plain", [param(True), param(False)])
78
93
  def test_main(
79
- self, *, caplog: LogCaptureFixture, log: bool, whenever: bool, plain: bool
94
+ self,
95
+ *,
96
+ caplog: LogCaptureFixture,
97
+ whenever: bool,
98
+ filters: _FilterType | None,
99
+ plain: bool,
80
100
  ) -> None:
81
- logger = unique_str() if log else None
82
- basic_config(obj=logger, whenever=whenever, plain=plain)
83
- logger_use = getLogger()
84
- logger_use.warning("message")
85
- assert "message" in caplog.messages
101
+ name = unique_str()
102
+ with _temp_log_factory():
103
+ basic_config(obj=name, whenever=whenever, filters=filters, plain=plain)
104
+ getLogger(name).warning("message")
105
+ record = one(r for r in caplog.records if r.name == name)
106
+ assert record.message == "message"
107
+
108
+ @mark.parametrize("whenever", [param(True), param(False)])
109
+ def test_none(self, *, whenever: bool) -> None:
110
+ with _temp_log_factory():
111
+ basic_config(whenever=whenever)
86
112
 
87
113
 
88
114
  class TestComputeRolloverActions:
89
- @skipif_windows
90
- def test_main(self, *, tmp_path: Path) -> None:
115
+ async def test_main(self, *, tmp_path: Path) -> None:
91
116
  tmp_path.joinpath("log.txt").touch()
92
117
 
93
118
  actions = _compute_rollover_actions(tmp_path, "log", ".txt")
@@ -99,7 +124,7 @@ class TestComputeRolloverActions:
99
124
  assert any(p for p in files if search(r"^log\.1\__[\dT]+\.txt$", p.name))
100
125
 
101
126
  for _ in range(2):
102
- sleep(1)
127
+ await sleep(1)
103
128
  tmp_path.joinpath("log.txt").touch()
104
129
  actions = _compute_rollover_actions(tmp_path, "log", ".txt")
105
130
  assert len(actions.deletions) == 1
@@ -111,8 +136,7 @@ class TestComputeRolloverActions:
111
136
  p for p in files if search(r"^log\.1\__[\dT]+__[\dT]+\.txt$", p.name)
112
137
  )
113
138
 
114
- @skipif_windows
115
- def test_multiple_backups(self, *, tmp_path: Path) -> None:
139
+ async def test_multiple_backups(self, *, tmp_path: Path) -> None:
116
140
  tmp_path.joinpath("log.txt").touch()
117
141
 
118
142
  actions = _compute_rollover_actions(tmp_path, "log", ".txt", backup_count=3)
@@ -123,7 +147,7 @@ class TestComputeRolloverActions:
123
147
  assert len(files) == 1
124
148
  assert any(p for p in files if search(r"^log\.1\__[\dT]+\.txt$", p.name))
125
149
 
126
- sleep(1)
150
+ await sleep(1)
127
151
  tmp_path.joinpath("log.txt").touch()
128
152
  actions = _compute_rollover_actions(tmp_path, "log", ".txt", backup_count=3)
129
153
  assert len(actions.deletions) == 0
@@ -136,7 +160,7 @@ class TestComputeRolloverActions:
136
160
  )
137
161
  assert any(p for p in files if search(r"^log\.2\__[\dT]+\.txt$", p.name))
138
162
 
139
- sleep(1)
163
+ await sleep(1)
140
164
  tmp_path.joinpath("log.txt").touch()
141
165
  actions = _compute_rollover_actions(tmp_path, "log", ".txt", backup_count=3)
142
166
  assert len(actions.deletions) == 0
@@ -153,7 +177,7 @@ class TestComputeRolloverActions:
153
177
  assert all(p for p in files if search(r"^log\.3\__[\dT]+\.txt$", p.name))
154
178
 
155
179
  for _ in range(2):
156
- sleep(1)
180
+ await sleep(1)
157
181
  tmp_path.joinpath("log.txt").touch()
158
182
  actions = _compute_rollover_actions(tmp_path, "log", ".txt", backup_count=3)
159
183
  assert len(actions.deletions) == 1
@@ -171,8 +195,7 @@ class TestComputeRolloverActions:
171
195
  p for p in files if search(r"^log\.3\__[\dT]+__[\dT]+\.txt$", p.name)
172
196
  )
173
197
 
174
- @skipif_windows
175
- def test_deleting_old_files(self, *, tmp_path: Path) -> None:
198
+ async def test_deleting_old_files(self, *, tmp_path: Path) -> None:
176
199
  tmp_path.joinpath("log.txt").touch()
177
200
 
178
201
  actions = _compute_rollover_actions(tmp_path, "log", ".txt")
@@ -183,7 +206,7 @@ class TestComputeRolloverActions:
183
206
  assert len(files) == 1
184
207
  assert any(p for p in files if search(r"^log\.1\__[\dT]+\.txt$", p.name))
185
208
 
186
- sleep(1)
209
+ await sleep(1)
187
210
  tmp_path.joinpath("log.txt").touch()
188
211
  now = serialize_compact(NOW_UTC)
189
212
  tmp_path.joinpath(f"log.99__{now}__{now}.txt").touch()
@@ -225,9 +248,22 @@ class TestFilterForKey:
225
248
  _ = filter_for_key(key)
226
249
 
227
250
 
228
- class TestGetDefaultLoggingPath:
229
- def test_main(self) -> None:
230
- assert isinstance(get_default_logging_path(), Path)
251
+ class TestGetFormatter:
252
+ @mark.parametrize("whenever", [param(True), param(False)])
253
+ @mark.parametrize("plain", [param(True), param(False)])
254
+ @mark.parametrize("color_field_styles", [param({}), param(None)])
255
+ def test_main(
256
+ self,
257
+ *,
258
+ whenever: bool,
259
+ plain: bool,
260
+ color_field_styles: Mapping[str, _FieldStyleKeys] | None,
261
+ ) -> None:
262
+ with _temp_log_factory():
263
+ formatter = get_formatter(
264
+ whenever=whenever, plain=plain, color_field_styles=color_field_styles
265
+ )
266
+ assert isinstance(formatter, Formatter)
231
267
 
232
268
 
233
269
  class TestGetLogger:
@@ -380,105 +416,25 @@ class TestRotatingLogFile:
380
416
 
381
417
 
382
418
  class TestSetupLogging:
383
- @skipif_windows
384
- def test_decorated(
385
- self, *, tmp_path: Path, traceback_func_one: Pattern[str]
386
- ) -> None:
387
- name = unique_str()
388
- setup_logging(logger=name, files_dir=tmp_path)
389
- logger = getLogger(name)
390
- assert len(logger.handlers) == 7
391
- self.assert_files(tmp_path, "init")
392
- try:
393
- _ = func_one(1, 2, 3, 4, c=5, d=6, e=7)
394
- except AssertionError:
395
- logger.exception("message")
396
- self.assert_files(tmp_path, ("post", traceback_func_one))
397
-
398
- @skipif_windows
399
- def test_undecorated(
400
- self, *, tmp_path: Path, traceback_func_untraced: Pattern[str]
401
- ) -> None:
419
+ def test_main(self, *, tmp_path: Path) -> None:
402
420
  name = unique_str()
403
421
  setup_logging(logger=name, files_dir=tmp_path)
404
422
  logger = getLogger(name)
405
423
  assert len(logger.handlers) == 7
406
- self.assert_files(tmp_path, "init")
407
- try:
408
- _ = func_untraced(1, 2, 3, 4, c=5, d=6, e=7)
409
- except AssertionError:
410
- logger.exception("message")
411
- self.assert_files(tmp_path, ("post", traceback_func_untraced))
412
-
413
- @skipif_windows
414
- def test_regular_percent_formatting(
415
- self, *, tmp_path: Path, caplog: LogCaptureFixture
416
- ) -> None:
417
- name = unique_str()
418
- setup_logging(logger=name, files_dir=tmp_path)
419
- logger = getLogger(name)
420
- logger.info("int: %d, float: %.2f", 1, 12.3456)
421
- record = one(caplog.records)
422
- assert isinstance(record, _AdvancedLogRecord)
423
- expected = "int: 1, float: 12.35"
424
- assert record.message == expected
425
-
426
- @skipif_windows
427
- def test_no_console(self, *, tmp_path: Path) -> None:
428
- name = unique_str()
429
- setup_logging(logger=name, console_level=None, files_dir=tmp_path)
430
- logger = getLogger(name)
431
- assert len(logger.handlers) == 5
432
-
433
- @skipif_windows
434
- def test_zoned_datetime(self, *, tmp_path: Path, caplog: LogCaptureFixture) -> None:
435
- name = unique_str()
436
- setup_logging(logger=name, files_dir=tmp_path)
437
- logger = getLogger(name)
438
- logger.info("")
439
- record = one(caplog.records)
440
- assert isinstance(record, _AdvancedLogRecord)
441
- assert isinstance(record._zoned_datetime, ZonedDateTime)
442
- assert isinstance(record._zoned_datetime_str, str)
443
-
444
- @skipif_windows
445
- def test_extra(self, *, tmp_path: Path) -> None:
446
- name = unique_str()
447
-
448
- def extra(logger: LoggerOrName | None, /) -> None:
449
- get_logger(logger=logger).addHandler(
450
- FileHandler(tmp_path.joinpath("extra.log"))
451
- )
452
-
453
- setup_logging(logger=name, files_dir=tmp_path, extra=extra)
454
- logger = getLogger(name)
455
- logger.info("")
456
- files = list(tmp_path.iterdir())
457
- names = {f.name for f in files}
458
- assert len(names) == 4
459
-
460
- @classmethod
461
- def assert_files(
462
- cls, path: Path, check: Literal["init"] | tuple[Literal["post"], Pattern[str]]
463
- ) -> None:
464
- files = list(path.iterdir())
465
- names = {f.name for f in files}
466
- match check:
467
- case "init":
468
- assert names == {"debug.txt", "info.txt", "plain"}
469
- case "post", pattern:
470
- assert names == {"debug.txt", "info.txt", "errors", "plain"}
471
- errors = path.joinpath("errors")
472
- assert errors.is_dir()
473
- files = list(errors.iterdir())
474
- assert len(files) == 1
475
- with one(files).open() as fh:
476
- contents = fh.read()
477
- assert pattern.search(contents)
424
+ logger.warning("message")
425
+ files = {p.name for p in tmp_path.iterdir() if p.is_file()}
426
+ expected = {
427
+ "debug.txt",
428
+ "info.txt",
429
+ "error.txt",
430
+ f"{name}-debug.txt",
431
+ f"{name}-info.txt",
432
+ f"{name}-error.txt",
433
+ }
434
+ assert files == expected
478
435
 
479
436
 
480
437
  class TestSizeAndTimeRotatingFileHandler:
481
- @skipif_windows
482
438
  def test_handlers(self, *, tmp_path: Path) -> None:
483
439
  logger = getLogger(unique_str())
484
440
  filename = tmp_path.joinpath("log")
@@ -488,15 +444,14 @@ class TestSizeAndTimeRotatingFileHandler:
488
444
  content = fh.read()
489
445
  assert content == "message\n"
490
446
 
491
- @skipif_windows
492
447
  def test_create_parents(self, *, tmp_path: Path) -> None:
493
448
  logger = getLogger(unique_str())
494
449
  filename = tmp_path.joinpath("foo", "bar", "bar", "log")
495
450
  logger.addHandler(SizeAndTimeRotatingFileHandler(filename=filename))
496
451
  assert filename.exists()
497
452
 
498
- @skipif_windows
499
- def test_size(self, *, tmp_path: Path) -> None:
453
+ @SKIPIF_CI_AND_WINDOWS
454
+ async def test_size(self, *, tmp_path: Path) -> None:
500
455
  logger = getLogger(unique_str())
501
456
  logger.addHandler(
502
457
  SizeAndTimeRotatingFileHandler(
@@ -552,10 +507,10 @@ class TestSizeAndTimeRotatingFileHandler:
552
507
  for p in files
553
508
  if search(r"^log\.3__[\dT]+__[\dT]+\.txt$", p.name)
554
509
  )
510
+ await sleep(0.1)
555
511
 
556
- @mark.flaky
557
- @skipif_windows
558
- def test_time(self, *, tmp_path: Path) -> None:
512
+ @SKIPIF_CI_AND_WINDOWS
513
+ async def test_time(self, *, tmp_path: Path) -> None:
559
514
  logger = getLogger(unique_str())
560
515
  logger.addHandler(
561
516
  SizeAndTimeRotatingFileHandler(
@@ -575,7 +530,7 @@ class TestSizeAndTimeRotatingFileHandler:
575
530
  assert len(files) == 1
576
531
  assert any(p for p in files if search(r"^log\.txt$", p.name))
577
532
 
578
- sleep(1.01)
533
+ await sleep(1.1)
579
534
  for i in range(2, 4):
580
535
  logger.warning("message %d", i)
581
536
  files = list(tmp_path.iterdir())
@@ -583,7 +538,7 @@ class TestSizeAndTimeRotatingFileHandler:
583
538
  assert any(p for p in files if search(r"^log\.txt$", p.name))
584
539
  assert any(p for p in files if search(r"^log\.1__[\dT]+\.txt$", p.name))
585
540
 
586
- sleep(1.01)
541
+ await sleep(1.1)
587
542
  for i in range(4, 6):
588
543
  logger.warning("message %d", i)
589
544
  files = list(tmp_path.iterdir())
@@ -594,7 +549,7 @@ class TestSizeAndTimeRotatingFileHandler:
594
549
  )
595
550
  assert any(p for p in files if search(r"^log\.2__[\dT]+\.txt$", p.name))
596
551
 
597
- sleep(1.01)
552
+ await sleep(1.1)
598
553
  for i in range(6, 8):
599
554
  logger.warning("message %d", i)
600
555
  files = list(tmp_path.iterdir())
@@ -609,7 +564,7 @@ class TestSizeAndTimeRotatingFileHandler:
609
564
  assert any(p for p in files if search(r"^log\.3__[\dT]+\.txt$", p.name))
610
565
 
611
566
  for _ in range(2):
612
- sleep(1.01)
567
+ await sleep(1.1)
613
568
  for i in range(8, 10):
614
569
  logger.warning("message %d", i)
615
570
  files = list(tmp_path.iterdir())
@@ -625,67 +580,17 @@ class TestSizeAndTimeRotatingFileHandler:
625
580
  p for p in files if search(r"^log\.3__[\dT]+__[\dT]+\.txt$", p.name)
626
581
  )
627
582
 
628
- @skipif_windows
583
+ @mark.parametrize("max_bytes", [param(0), param(1)])
584
+ @SKIPIF_CI_AND_WINDOWS
629
585
  def test_should_rollover_file_not_found(
630
- self, *, tmp_path: Path, caplog: LogCaptureFixture
586
+ self, *, tmp_path: Path, max_bytes: int, caplog: LogCaptureFixture
631
587
  ) -> None:
632
- logger = getLogger(unique_str())
588
+ logger = getLogger(name := unique_str())
633
589
  path = tmp_path.joinpath("log")
634
590
  logger.addHandler(
635
- handler := SizeAndTimeRotatingFileHandler(filename=path, maxBytes=1)
591
+ handler := SizeAndTimeRotatingFileHandler(filename=path, maxBytes=max_bytes)
636
592
  )
637
593
  logger.warning("message")
638
- record = one(caplog.records)
594
+ record = one(r for r in caplog.records if r.name == name)
639
595
  path.unlink()
640
596
  assert not handler._should_rollover(record)
641
-
642
-
643
- class TestStandaloneFileHandler:
644
- @skipif_windows
645
- def test_main(self, *, tmp_path: Path) -> None:
646
- logger = getLogger(unique_str())
647
- logger.addHandler(StandaloneFileHandler(level=DEBUG, path=tmp_path))
648
- assert len(list(tmp_path.iterdir())) == 0
649
- logger.warning("message")
650
- files = list(tmp_path.iterdir())
651
- assert len(files) == 1
652
- with one(files).open() as fh:
653
- contents = fh.read()
654
- assert contents == "message"
655
-
656
-
657
- class TestTempHandler:
658
- def test_main(self) -> None:
659
- logger = getLogger(unique_str())
660
- logger.addHandler(h1 := StreamHandler())
661
- logger.addHandler(h2 := StreamHandler())
662
- assert len(logger.handlers) == 2
663
- handler = StreamHandler()
664
- with temp_handler(handler, logger=logger):
665
- assert len(logger.handlers) == 3
666
- assert len(logger.handlers) == 2
667
- assert logger.handlers[0] is h1
668
- assert logger.handlers[1] is h2
669
-
670
-
671
- class TestTempLogger:
672
- def test_disabled(self) -> None:
673
- logger = getLogger(unique_str())
674
- assert not logger.disabled
675
- with temp_logger(logger, disabled=True):
676
- assert logger.disabled
677
- assert not logger.disabled
678
-
679
- def test_level(self) -> None:
680
- logger = getLogger(unique_str())
681
- assert logger.level == NOTSET
682
- with temp_logger(logger, level="DEBUG"):
683
- assert logger.level == DEBUG
684
- assert logger.level == NOTSET
685
-
686
- def test_propagate(self) -> None:
687
- logger = getLogger(unique_str())
688
- assert logger.propagate
689
- with temp_logger(logger, propagate=False):
690
- assert not logger.propagate
691
- assert logger.propagate