dycw-utilities 0.131.11__tar.gz → 0.131.12__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 (221) hide show
  1. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/PKG-INFO +1 -1
  2. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/pyproject.toml +2 -2
  3. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/conftest.py +18 -2
  4. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_dataclasses.py +3 -1
  5. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_logging.py +36 -65
  6. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_orjson.py +37 -34
  7. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pyinstrument.py +1 -1
  8. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_traceback.py +1 -1
  9. dycw_utilities-0.131.12/src/tests/test_tzlocal.py +15 -0
  10. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_whenever2.py +22 -3
  11. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/__init__.py +1 -1
  12. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/datetime.py +2 -9
  13. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/fastapi.py +2 -4
  14. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/fpdf2.py +2 -2
  15. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/logging.py +54 -52
  16. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/orjson.py +46 -45
  17. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pyinstrument.py +2 -3
  18. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/traceback.py +18 -21
  19. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/typing.py +25 -1
  20. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/tzlocal.py +2 -26
  21. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/whenever2.py +12 -0
  22. dycw_utilities-0.131.11/src/tests/test_tzlocal.py +0 -45
  23. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/.gitignore +0 -0
  24. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/LICENSE +0 -0
  25. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/README.md +0 -0
  26. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/__init__.py +0 -0
  27. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/__init__.py +0 -0
  28. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_missing/__init__.py +0 -0
  29. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_missing/module.py +0 -0
  30. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_with/__init__.py +0 -0
  31. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_with/outer_1.py +0 -0
  32. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_with/outer_2.py +0 -0
  33. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  34. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  35. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  36. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  37. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_without/__init__.py +0 -0
  38. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_without/module_1.py +0 -0
  39. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/package_without/module_2.py +0 -0
  40. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/standalone.py +0 -0
  41. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/modules/with_imports.py +0 -0
  42. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  43. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  44. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  45. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  46. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  47. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  48. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  49. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  50. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_aiolimiter.py +0 -0
  51. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_altair.py +0 -0
  52. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_asyncio.py +0 -0
  53. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_asyncio_classes/__init__.py +0 -0
  54. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_asyncio_classes/loopers.py +0 -0
  55. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_asyncio_classes/redis.py +0 -0
  56. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_atomicwrites.py +0 -0
  57. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_atools.py +0 -0
  58. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_cachetools.py +0 -0
  59. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_click.py +0 -0
  60. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_concurrent.py +0 -0
  61. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_contextlib.py +0 -0
  62. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_contextvars.py +0 -0
  63. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_cryptography.py +0 -0
  64. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_cvxpy.py +0 -0
  65. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_datetime.py +0 -0
  66. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_enum.py +0 -0
  67. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_errors.py +0 -0
  68. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_eventkit.py +0 -0
  69. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_fastapi.py +0 -0
  70. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_fpdf2.py +0 -0
  71. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_functions.py +0 -0
  72. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_functools.py +0 -0
  73. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_getpass.py +0 -0
  74. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_git.py +0 -0
  75. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_hashlib.py +0 -0
  76. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_http.py +0 -0
  77. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_hypothesis.py +0 -0
  78. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_importlib.py +0 -0
  79. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_inflect.py +0 -0
  80. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_ipython.py +0 -0
  81. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_iterables.py +0 -0
  82. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_jupyter.py +0 -0
  83. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_libcst.py +0 -0
  84. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_lightweight_charts.py +0 -0
  85. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_luigi.py +0 -0
  86. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_math.py +0 -0
  87. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_memory_profiler.py +0 -0
  88. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_modules.py +0 -0
  89. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_more_itertools.py +0 -0
  90. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_numpy.py +0 -0
  91. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_operator.py +0 -0
  92. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_optuna.py +0 -0
  93. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_os.py +0 -0
  94. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_parse.py +0 -0
  95. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pathlib.py +0 -0
  96. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_period.py +0 -0
  97. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pickle.py +0 -0
  98. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_platform.py +0 -0
  99. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_polars.py +0 -0
  100. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_polars_ols.py +0 -0
  101. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pottery.py +0 -0
  102. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pqdm.py +0 -0
  103. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_psutil.py +0 -0
  104. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pydantic.py +0 -0
  105. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pyrsistent.py +0 -0
  106. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pytest.py +0 -0
  107. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_pytest_regressions.py +0 -0
  108. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_python_dotenv.py +0 -0
  109. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_random.py +0 -0
  110. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_re.py +0 -0
  111. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_redis.py +0 -0
  112. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_reprlib.py +0 -0
  113. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_scipy.py +0 -0
  114. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_sentinel.py +0 -0
  115. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_shelve.py +0 -0
  116. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_slack_sdk.py +0 -0
  117. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_socket.py +0 -0
  118. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_sqlalchemy.py +0 -0
  119. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_sqlalchemy_polars.py +0 -0
  120. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_statsmodel.py +0 -0
  121. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_streamlit.py +0 -0
  122. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_string.py +0 -0
  123. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_tempfile.py +0 -0
  124. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_tenacity.py +0 -0
  125. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_text.py +0 -0
  126. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_threading.py +0 -0
  127. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_timer.py +0 -0
  128. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_types.py +0 -0
  129. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_typing.py +0 -0
  130. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_typing_funcs/__init__.py +0 -0
  131. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_typing_funcs/no_future.py +0 -0
  132. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_typing_funcs/with_future.py +0 -0
  133. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_tzdata.py +0 -0
  134. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_uuid.py +0 -0
  135. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_version.py +0 -0
  136. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_warnings.py +0 -0
  137. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_whenever.py +0 -0
  138. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_zipfile.py +0 -0
  139. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/tests/test_zoneinfo.py +0 -0
  140. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/aiolimiter.py +0 -0
  141. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/altair.py +0 -0
  142. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/asyncio.py +0 -0
  143. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/atomicwrites.py +0 -0
  144. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/atools.py +0 -0
  145. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/cachetools.py +0 -0
  146. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/click.py +0 -0
  147. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/concurrent.py +0 -0
  148. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/contextlib.py +0 -0
  149. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/contextvars.py +0 -0
  150. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/cryptography.py +0 -0
  151. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/cvxpy.py +0 -0
  152. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/dataclasses.py +0 -0
  153. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/enum.py +0 -0
  154. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/errors.py +0 -0
  155. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/eventkit.py +0 -0
  156. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/functions.py +0 -0
  157. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/functools.py +0 -0
  158. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/getpass.py +0 -0
  159. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/git.py +0 -0
  160. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/hashlib.py +0 -0
  161. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/http.py +0 -0
  162. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/hypothesis.py +0 -0
  163. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/importlib.py +0 -0
  164. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/inflect.py +0 -0
  165. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/ipython.py +0 -0
  166. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/iterables.py +0 -0
  167. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/jupyter.py +0 -0
  168. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/libcst.py +0 -0
  169. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/lightweight_charts.py +0 -0
  170. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/luigi.py +0 -0
  171. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/math.py +0 -0
  172. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/memory_profiler.py +0 -0
  173. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/modules.py +0 -0
  174. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/more_itertools.py +0 -0
  175. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/numpy.py +0 -0
  176. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/operator.py +0 -0
  177. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/optuna.py +0 -0
  178. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/os.py +0 -0
  179. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/parse.py +0 -0
  180. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pathlib.py +0 -0
  181. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/period.py +0 -0
  182. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pickle.py +0 -0
  183. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/platform.py +0 -0
  184. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/polars.py +0 -0
  185. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/polars_ols.py +0 -0
  186. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pottery.py +0 -0
  187. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pqdm.py +0 -0
  188. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/psutil.py +0 -0
  189. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/py.typed +0 -0
  190. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pydantic.py +0 -0
  191. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pyrsistent.py +0 -0
  192. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pytest.py +0 -0
  193. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/pytest_regressions.py +0 -0
  194. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/python_dotenv.py +0 -0
  195. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/random.py +0 -0
  196. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/re.py +0 -0
  197. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/redis.py +0 -0
  198. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/reprlib.py +0 -0
  199. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/scipy.py +0 -0
  200. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/sentinel.py +0 -0
  201. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/shelve.py +0 -0
  202. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/slack_sdk.py +0 -0
  203. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/socket.py +0 -0
  204. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/sqlalchemy.py +0 -0
  205. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/sqlalchemy_polars.py +0 -0
  206. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/statsmodels.py +0 -0
  207. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/streamlit.py +0 -0
  208. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/string.py +0 -0
  209. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/tempfile.py +0 -0
  210. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/tenacity.py +0 -0
  211. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/text.py +0 -0
  212. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/threading.py +0 -0
  213. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/timer.py +0 -0
  214. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/types.py +0 -0
  215. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/tzdata.py +0 -0
  216. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/uuid.py +0 -0
  217. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/version.py +0 -0
  218. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/warnings.py +0 -0
  219. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/whenever.py +0 -0
  220. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/zipfile.py +0 -0
  221. {dycw_utilities-0.131.11 → dycw_utilities-0.131.12}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.131.11
3
+ Version: 0.131.12
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -94,7 +94,7 @@ dependencies = [
94
94
  name = "dycw-utilities"
95
95
  readme = "README.md"
96
96
  requires-python = ">= 3.12"
97
- version = "0.131.11"
97
+ version = "0.131.12"
98
98
 
99
99
  [project.optional-dependencies]
100
100
  logging = [
@@ -121,7 +121,7 @@ test = [
121
121
  # bump-my-version
122
122
  [tool.bumpversion]
123
123
  allow_dirty = true
124
- current_version = "0.131.11"
124
+ current_version = "0.131.12"
125
125
 
126
126
  [[tool.bumpversion.files]]
127
127
  filename = "src/utilities/__init__.py"
@@ -2,7 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import re
4
4
  from asyncio import sleep
5
- from contextlib import suppress
5
+ from contextlib import AbstractContextManager, contextmanager, suppress
6
+ from logging import LogRecord, setLogRecordFactory
6
7
  from os import environ
7
8
  from re import MULTILINE, Pattern
8
9
  from typing import TYPE_CHECKING, Any
@@ -16,7 +17,7 @@ from utilities.re import ExtractGroupError, extract_group
16
17
  from utilities.text import strip_and_dedent
17
18
 
18
19
  if TYPE_CHECKING:
19
- from collections.abc import Sequence
20
+ from collections.abc import Iterator, Sequence
20
21
  from pathlib import Path
21
22
 
22
23
  from _pytest.fixtures import SubRequest
@@ -43,6 +44,21 @@ else:
43
44
  setup_hypothesis_profiles()
44
45
 
45
46
 
47
+ # fixture - logging
48
+
49
+
50
+ @fixture
51
+ def set_log_factory() -> AbstractContextManager[None]:
52
+ @contextmanager
53
+ def cm() -> Iterator[None]:
54
+ try:
55
+ yield
56
+ finally:
57
+ setLogRecordFactory(LogRecord)
58
+
59
+ return cm()
60
+
61
+
46
62
  # fixtures - sqlalchemy
47
63
 
48
64
 
@@ -928,7 +928,9 @@ class TestYieldFields:
928
928
  assert get_args(args[0]) == ("true", "false")
929
929
 
930
930
  def test_class_orjson_log_record(self) -> None:
931
- result = list(yield_fields(OrjsonLogRecord, globalns=globals()))
931
+ result = list(
932
+ yield_fields(OrjsonLogRecord, globalns=globals(), warn_name_errors=True)
933
+ )
932
934
  exp_head = [
933
935
  _YieldFieldsClass(name="name", type_=str, kw_only=True),
934
936
  _YieldFieldsClass(name="message", type_=str, kw_only=True),
@@ -1,16 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from asyncio import sleep
4
- from contextlib import contextmanager
5
4
  from io import StringIO
6
- from logging import (
7
- Formatter,
8
- Logger,
9
- LogRecord,
10
- StreamHandler,
11
- getLogger,
12
- setLogRecordFactory,
13
- )
5
+ from logging import Formatter, Logger, StreamHandler, getLogger
14
6
  from pathlib import Path
15
7
  from re import search
16
8
  from typing import TYPE_CHECKING, Any, cast
@@ -20,13 +12,12 @@ from hypothesis.strategies import booleans, integers, none, sampled_from
20
12
  from pytest import LogCaptureFixture, mark, param, raises
21
13
 
22
14
  from tests.conftest import SKIPIF_CI_AND_WINDOWS
23
- from utilities.datetime import NOW_UTC, SECOND, serialize_compact
24
15
  from utilities.hypothesis import (
25
16
  assume_does_not_raise,
26
17
  pairs,
27
18
  temp_paths,
28
19
  text_ascii,
29
- zoned_datetimes,
20
+ zoned_datetimes_whenever,
30
21
  )
31
22
  from utilities.iterables import one
32
23
  from utilities.logging import (
@@ -47,19 +38,14 @@ from utilities.logging import (
47
38
  from utilities.text import unique_str
48
39
  from utilities.types import LogLevel
49
40
  from utilities.typing import get_args
41
+ from utilities.whenever2 import format_compact, get_now
50
42
 
51
43
  if TYPE_CHECKING:
52
- import datetime as dt
53
- from collections.abc import Iterator, Mapping
44
+ from collections.abc import Mapping
45
+ from contextlib import AbstractContextManager
54
46
  from logging import _FilterType
55
47
 
56
-
57
- @contextmanager
58
- def _temp_log_factory() -> Iterator[None]:
59
- try:
60
- yield
61
- finally:
62
- setLogRecordFactory(LogRecord)
48
+ from whenever import ZonedDateTime
63
49
 
64
50
 
65
51
  class TestAddFilters:
@@ -81,7 +67,6 @@ class TestAddFilters:
81
67
 
82
68
 
83
69
  class TestBasicConfig:
84
- @mark.parametrize("whenever", [param(True), param(False)])
85
70
  @mark.parametrize(
86
71
  "filters",
87
72
  [
@@ -94,21 +79,20 @@ class TestBasicConfig:
94
79
  self,
95
80
  *,
96
81
  caplog: LogCaptureFixture,
97
- whenever: bool,
98
82
  filters: _FilterType | None,
99
83
  plain: bool,
84
+ set_log_factory: AbstractContextManager[None],
100
85
  ) -> None:
101
86
  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"
87
+ with set_log_factory:
88
+ basic_config(obj=name, filters=filters, plain=plain)
89
+ getLogger(name).warning("message")
90
+ record = one(r for r in caplog.records if r.name == name)
91
+ assert record.message == "message"
107
92
 
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)
93
+ def test_none(self, *, set_log_factory: AbstractContextManager[None]) -> None:
94
+ with set_log_factory:
95
+ basic_config()
112
96
 
113
97
 
114
98
  class TestComputeRolloverActions:
@@ -208,7 +192,7 @@ class TestComputeRolloverActions:
208
192
 
209
193
  await sleep(1)
210
194
  tmp_path.joinpath("log.txt").touch()
211
- now = serialize_compact(NOW_UTC)
195
+ now = format_compact(get_now())
212
196
  tmp_path.joinpath(f"log.99__{now}__{now}.txt").touch()
213
197
  actions = _compute_rollover_actions(tmp_path, "log", ".txt")
214
198
  assert len(actions.deletions) == 2
@@ -249,21 +233,20 @@ class TestFilterForKey:
249
233
 
250
234
 
251
235
  class TestGetFormatter:
252
- @mark.parametrize("whenever", [param(True), param(False)])
253
236
  @mark.parametrize("plain", [param(True), param(False)])
254
237
  @mark.parametrize("color_field_styles", [param({}), param(None)])
255
238
  def test_main(
256
239
  self,
257
240
  *,
258
- whenever: bool,
259
241
  plain: bool,
260
242
  color_field_styles: Mapping[str, _FieldStyleKeys] | None,
243
+ set_log_factory: AbstractContextManager[None],
261
244
  ) -> None:
262
- with _temp_log_factory():
245
+ with set_log_factory:
263
246
  formatter = get_formatter(
264
- whenever=whenever, plain=plain, color_field_styles=color_field_styles
247
+ plain=plain, color_field_styles=color_field_styles
265
248
  )
266
- assert isinstance(formatter, Formatter)
249
+ assert isinstance(formatter, Formatter)
267
250
 
268
251
 
269
252
  class TestGetLogger:
@@ -332,42 +315,35 @@ class TestRotatingLogFile:
332
315
  assert result.start is None
333
316
  assert result.end is None
334
317
 
335
- @given(
336
- index=integers(min_value=1),
337
- end=zoned_datetimes(round_="standard", timedelta=SECOND),
338
- )
318
+ @given(index=integers(min_value=1), end=zoned_datetimes_whenever())
339
319
  def test_from_path_with_index_and_end(
340
- self, *, index: int, end: dt.datetime
320
+ self, *, index: int, end: ZonedDateTime
341
321
  ) -> None:
342
- path = Path(f"log.{index}__{serialize_compact(end)}.txt")
322
+ path = Path(f"log.{index}__{format_compact(end)}.txt")
343
323
  result = _RotatingLogFile.from_path(path, "log", ".txt")
344
324
  assert result is not None
345
325
  assert result.stem == "log"
346
326
  assert result.suffix == ".txt"
347
327
  assert result.index == index
348
328
  assert result.start is None
349
- assert result.end == end
329
+ assert result.end == end.round()
350
330
 
351
331
  @given(
352
332
  index=integers(min_value=1),
353
- datetimes=pairs(
354
- zoned_datetimes(round_="standard", timedelta=SECOND), sorted=True
355
- ),
333
+ datetimes=pairs(zoned_datetimes_whenever(), sorted=True),
356
334
  )
357
335
  def test_from_path_with_index_start_and_end(
358
- self, *, index: int, datetimes: tuple[dt.datetime, dt.datetime]
336
+ self, *, index: int, datetimes: tuple[ZonedDateTime, ZonedDateTime]
359
337
  ) -> None:
360
338
  start, end = datetimes
361
- path = Path(
362
- f"log.{index}__{serialize_compact(start)}__{serialize_compact(end)}.txt"
363
- )
339
+ path = Path(f"log.{index}__{format_compact(start)}__{format_compact(end)}.txt")
364
340
  result = _RotatingLogFile.from_path(path, "log", ".txt")
365
341
  assert result is not None
366
342
  assert result.stem == "log"
367
343
  assert result.suffix == ".txt"
368
344
  assert result.index == index
369
- assert result.start == start
370
- assert result.end == end
345
+ assert result.start == start.round()
346
+ assert result.end == end.round()
371
347
 
372
348
  def test_from_path_none(self) -> None:
373
349
  path = Path("invalid.txt")
@@ -384,34 +360,30 @@ class TestRotatingLogFile:
384
360
  assert file.path == root.joinpath(f"log.{index}.txt")
385
361
 
386
362
  @given(
387
- root=temp_paths(),
388
- index=integers(min_value=1),
389
- end=zoned_datetimes(round_="standard", timedelta=SECOND),
363
+ root=temp_paths(), index=integers(min_value=1), end=zoned_datetimes_whenever()
390
364
  )
391
365
  def test_path_with_index_and_end(
392
- self, *, root: Path, index: int, end: dt.datetime
366
+ self, *, root: Path, index: int, end: ZonedDateTime
393
367
  ) -> None:
394
368
  file = _RotatingLogFile(
395
369
  directory=root, stem="log", suffix=".txt", index=index, end=end
396
370
  )
397
- assert file.path == root.joinpath(f"log.{index}__{serialize_compact(end)}.txt")
371
+ assert file.path == root.joinpath(f"log.{index}__{format_compact(end)}.txt")
398
372
 
399
373
  @given(
400
374
  root=temp_paths(),
401
375
  index=integers(min_value=1),
402
- datetimes=pairs(
403
- zoned_datetimes(round_="standard", timedelta=SECOND), sorted=True
404
- ),
376
+ datetimes=pairs(zoned_datetimes_whenever(), sorted=True),
405
377
  )
406
378
  def test_path_with_index_start_and_end(
407
- self, *, root: Path, index: int, datetimes: tuple[dt.datetime, dt.datetime]
379
+ self, *, root: Path, index: int, datetimes: tuple[ZonedDateTime, ZonedDateTime]
408
380
  ) -> None:
409
381
  start, end = datetimes
410
382
  file = _RotatingLogFile(
411
383
  directory=root, stem="log", suffix=".txt", index=index, start=start, end=end
412
384
  )
413
385
  assert file.path == root.joinpath(
414
- f"log.{index}__{serialize_compact(start)}__{serialize_compact(end)}.txt"
386
+ f"log.{index}__{format_compact(start)}__{format_compact(end)}.txt"
415
387
  )
416
388
 
417
389
 
@@ -440,8 +412,7 @@ class TestSizeAndTimeRotatingFileHandler:
440
412
  filename = tmp_path.joinpath("log")
441
413
  logger.addHandler(SizeAndTimeRotatingFileHandler(filename=filename))
442
414
  logger.warning("message")
443
- with filename.open() as fh:
444
- content = fh.read()
415
+ content = filename.read_text()
445
416
  assert content == "message\n"
446
417
 
447
418
  def test_create_parents(self, *, tmp_path: Path) -> None:
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import datetime as dt
4
3
  from collections.abc import Iterable
5
4
  from io import StringIO
6
5
  from logging import DEBUG, WARNING, FileHandler, StreamHandler, getLogger
@@ -12,7 +11,6 @@ from hypothesis import assume, given
12
11
  from hypothesis.strategies import (
13
12
  booleans,
14
13
  builds,
15
- dates,
16
14
  dictionaries,
17
15
  integers,
18
16
  lists,
@@ -51,16 +49,16 @@ from tests.test_typing_funcs.with_future import (
51
49
  DataClassFutureTypeLiteral,
52
50
  DataClassFutureTypeLiteralNullable,
53
51
  )
54
- from utilities.datetime import MINUTE, SECOND, get_now
55
52
  from utilities.functions import is_sequence_of
56
53
  from utilities.hypothesis import (
57
54
  assume_does_not_raise,
55
+ dates_whenever,
58
56
  int64s,
59
57
  paths,
60
58
  temp_paths,
61
59
  text_ascii,
62
60
  text_printable,
63
- zoned_datetimes,
61
+ zoned_datetimes_whenever,
64
62
  )
65
63
  from utilities.iterables import always_iterable, one
66
64
  from utilities.logging import get_logging_level_number
@@ -81,13 +79,15 @@ from utilities.orjson import (
81
79
  )
82
80
  from utilities.polars import check_polars_dataframe, zoned_datetime
83
81
  from utilities.sentinel import Sentinel, sentinel
84
- from utilities.types import DateOrDateTime, LogLevel, MaybeIterable, PathLike
82
+ from utilities.types import LogLevel, MaybeIterable, PathLike
85
83
  from utilities.typing import get_args
86
- from utilities.tzlocal import get_now_local
84
+ from utilities.whenever2 import MINUTE, SECOND, get_now
87
85
 
88
86
  if TYPE_CHECKING:
89
87
  from collections.abc import Sequence
90
88
 
89
+ from whenever import Date, ZonedDateTime
90
+
91
91
  from utilities.types import Dataclass, StrMapping
92
92
 
93
93
 
@@ -195,9 +195,12 @@ class TestGetLogRecords:
195
195
  level=sampled_from(get_args(LogLevel)) | none(),
196
196
  min_level=sampled_from(get_args(LogLevel)) | none(),
197
197
  max_level=sampled_from(get_args(LogLevel)) | none(),
198
- date_or_datetime=dates() | zoned_datetimes() | none(),
199
- min_date_or_datetime=dates() | zoned_datetimes() | none(),
200
- max_date_or_datetime=dates() | zoned_datetimes() | none(),
198
+ date=dates_whenever() | none(),
199
+ min_date=dates_whenever() | none(),
200
+ max_date=dates_whenever() | none(),
201
+ datetime=zoned_datetimes_whenever() | none(),
202
+ min_datetime=zoned_datetimes_whenever() | none(),
203
+ max_datetime=zoned_datetimes_whenever() | none(),
201
204
  func_name=booleans() | text_ascii() | none(),
202
205
  extra=booleans() | text_ascii() | sets(text_ascii()) | none(),
203
206
  log_file=booleans() | paths() | text_ascii() | none(),
@@ -218,9 +221,12 @@ class TestGetLogRecords:
218
221
  level: LogLevel | None,
219
222
  min_level: LogLevel | None,
220
223
  max_level: LogLevel | None,
221
- date_or_datetime: DateOrDateTime | None,
222
- min_date_or_datetime: DateOrDateTime | None,
223
- max_date_or_datetime: DateOrDateTime | None,
224
+ date: Date | None,
225
+ min_date: Date | None,
226
+ max_date: Date | None,
227
+ datetime: ZonedDateTime | None,
228
+ min_datetime: ZonedDateTime | None,
229
+ max_datetime: ZonedDateTime | None,
224
230
  func_name: bool | str | None,
225
231
  extra: bool | MaybeIterable[str] | None,
226
232
  log_file: bool | PathLike | None,
@@ -245,9 +251,12 @@ class TestGetLogRecords:
245
251
  level=level,
246
252
  min_level=min_level,
247
253
  max_level=max_level,
248
- date_or_datetime=date_or_datetime,
249
- min_date_or_datetime=min_date_or_datetime,
250
- max_date_or_datetime=max_date_or_datetime,
254
+ date=date,
255
+ min_date=min_date,
256
+ max_date=max_date,
257
+ datetime=datetime,
258
+ min_datetime=min_datetime,
259
+ max_datetime=max_datetime,
251
260
  func_name=func_name,
252
261
  extra=extra,
253
262
  log_file=log_file,
@@ -272,24 +281,18 @@ class TestGetLogRecords:
272
281
  assert all(r.level >= get_logging_level_number(min_level) for r in records)
273
282
  if max_level is not None:
274
283
  assert all(r.level <= get_logging_level_number(max_level) for r in records)
275
- if date_or_datetime is not None:
276
- match date_or_datetime:
277
- case dt.datetime() as datetime:
278
- assert all(r.datetime == datetime for r in records)
279
- case dt.date() as date:
280
- assert all(r.date == date for r in records)
281
- if min_date_or_datetime is not None:
282
- match min_date_or_datetime:
283
- case dt.datetime() as min_datetime:
284
- assert all(r.datetime >= min_datetime for r in records)
285
- case dt.date() as min_date:
286
- assert all(r.date >= min_date for r in records)
287
- if max_date_or_datetime is not None:
288
- match max_date_or_datetime:
289
- case dt.datetime() as max_datetime:
290
- assert all(r.datetime <= max_datetime for r in records)
291
- case dt.date() as max_date:
292
- assert all(r.date <= max_date for r in records)
284
+ if date is not None:
285
+ assert all(r.date == date for r in records)
286
+ if min_date is not None:
287
+ assert all(r.date >= min_date for r in records)
288
+ if max_date is not None:
289
+ assert all(r.date <= max_date for r in records)
290
+ if datetime is not None:
291
+ assert all(r.datetime == datetime for r in records)
292
+ if min_datetime is not None:
293
+ assert all(r.datetime >= min_datetime for r in records)
294
+ if max_datetime is not None:
295
+ assert all(r.datetime <= max_datetime for r in records)
293
296
  if func_name is not None:
294
297
  match func_name:
295
298
  case bool() as has_func_name:
@@ -425,7 +428,7 @@ class TestOrjsonFormatter:
425
428
  assert record.message == "message"
426
429
  assert record.level == WARNING
427
430
  assert record.path_name == Path(__file__)
428
- assert abs(record.datetime - get_now_local()) <= SECOND
431
+ assert abs(record.datetime - get_now()) <= SECOND
429
432
  assert record.func_name == TestOrjsonFormatter.test_main.__name__
430
433
  assert record.stack_info is None
431
434
  assert record.extra == {"a": 1, "b": 2}
@@ -16,4 +16,4 @@ class TestProfile:
16
16
  sleep(1e-3)
17
17
 
18
18
  (file,) = tmp_path.iterdir()
19
- assert search(r"^profile__\d{8}T\d{6}\.html$", file.name)
19
+ assert search(r"^profile__[\dT]+\.html$", file.name)
@@ -99,7 +99,7 @@ class TestMakeExceptHook:
99
99
  exc_type, exc_val, traceback = exc_info()
100
100
  hook(exc_type, exc_val, traceback)
101
101
  path = one(tmp_path.iterdir())
102
- assert search(r"^\d{8}T\d{6}\.txt$", path.name)
102
+ assert search(r"^[\dT]+\.txt$", path.name)
103
103
 
104
104
  def test_non_error(self) -> None:
105
105
  hook = make_except_hook()
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from zoneinfo import ZoneInfo
4
+
5
+ from utilities.tzlocal import LOCAL_TIME_ZONE, LOCAL_TIME_ZONE_NAME, get_local_time_zone
6
+
7
+
8
+ class TestGetLocalTimeZone:
9
+ def test_function(self) -> None:
10
+ time_zone = get_local_time_zone()
11
+ assert isinstance(time_zone, ZoneInfo)
12
+
13
+ def test_constants(self) -> None:
14
+ assert isinstance(LOCAL_TIME_ZONE, ZoneInfo)
15
+ assert isinstance(LOCAL_TIME_ZONE_NAME, str)
@@ -8,14 +8,21 @@ from zoneinfo import ZoneInfo
8
8
  from hypothesis import given
9
9
  from hypothesis.strategies import just, none, timezones
10
10
  from pytest import mark, param, raises
11
- from whenever import Date, DateDelta, DateTimeDelta, TimeDelta, ZonedDateTime
11
+ from whenever import (
12
+ Date,
13
+ DateDelta,
14
+ DateTimeDelta,
15
+ PlainDateTime,
16
+ TimeDelta,
17
+ ZonedDateTime,
18
+ )
12
19
 
13
20
  from tests.conftest import IS_CI
14
21
  from utilities.dataclasses import replace_non_sentinel
15
22
  from utilities.hypothesis import dates_whenever, sentinels, zoned_datetimes_whenever
16
23
  from utilities.sentinel import Sentinel, sentinel
17
24
  from utilities.tzdata import HongKong, Tokyo
18
- from utilities.tzlocal import LOCAL_TIME_ZONE
25
+ from utilities.tzlocal import LOCAL_TIME_ZONE_NAME
19
26
  from utilities.whenever2 import (
20
27
  DATE_DELTA_MAX,
21
28
  DATE_DELTA_MIN,
@@ -39,6 +46,7 @@ from utilities.whenever2 import (
39
46
  ZONED_DATE_TIME_MAX,
40
47
  ZONED_DATE_TIME_MIN,
41
48
  WheneverLogRecord,
49
+ format_compact,
42
50
  from_timestamp,
43
51
  from_timestamp_millis,
44
52
  from_timestamp_nanos,
@@ -56,6 +64,17 @@ if TYPE_CHECKING:
56
64
  from utilities.types import MaybeCallableDate, MaybeCallableZonedDateTime
57
65
 
58
66
 
67
+ class TestFormatCompact:
68
+ @given(datetime=zoned_datetimes_whenever())
69
+ def test_main(self, *, datetime: ZonedDateTime) -> None:
70
+ result = format_compact(datetime)
71
+ assert isinstance(result, str)
72
+ parsed = PlainDateTime.parse_common_iso(result)
73
+ assert parsed.nanosecond == 0
74
+ expected = datetime.round().to_tz(LOCAL_TIME_ZONE_NAME).to_plain()
75
+ assert parsed == expected
76
+
77
+
59
78
  class TestFromTimeStamp:
60
79
  @given(datetime=zoned_datetimes_whenever(time_zone=UTC if IS_CI else timezones()))
61
80
  def test_main(self, *, datetime: ZonedDateTime) -> None:
@@ -100,7 +119,7 @@ class TestGetNowLocal:
100
119
 
101
120
  def test_constant(self) -> None:
102
121
  assert isinstance(NOW_LOCAL, ZonedDateTime)
103
- assert NOW_LOCAL.tz == LOCAL_TIME_ZONE.key
122
+ assert NOW_LOCAL.tz == LOCAL_TIME_ZONE_NAME
104
123
 
105
124
 
106
125
  class TestGetToday:
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.131.11"
3
+ __version__ = "0.131.12"
@@ -21,21 +21,14 @@ from utilities.iterables import OneEmptyError, one
21
21
  from utilities.math import SafeRoundError, round_, safe_round
22
22
  from utilities.platform import SYSTEM
23
23
  from utilities.sentinel import Sentinel, sentinel
24
- from utilities.types import MaybeStr
24
+ from utilities.types import MaybeCallablePyDate, MaybeCallablePyDateTime, MaybeStr
25
25
  from utilities.typing import is_instance_gen
26
26
  from utilities.zoneinfo import UTC, ensure_time_zone, get_time_zone_name
27
27
 
28
28
  if TYPE_CHECKING:
29
29
  from collections.abc import Iterator
30
30
 
31
- from utilities.types import (
32
- DateOrDateTime,
33
- Duration,
34
- MathRoundMode,
35
- MaybeCallablePyDate,
36
- MaybeCallablePyDateTime,
37
- TimeZoneLike,
38
- )
31
+ from utilities.types import DateOrDateTime, Duration, MathRoundMode, TimeZoneLike
39
32
 
40
33
 
41
34
  _DAYS_PER_YEAR = 365.25
@@ -9,8 +9,7 @@ from uvicorn import Config, Server
9
9
 
10
10
  from utilities.asyncio import Looper
11
11
  from utilities.datetime import SECOND, datetime_duration_to_float
12
- from utilities.tzlocal import get_now_local # skipif-ci
13
- from utilities.whenever import serialize_zoned_datetime # skipif-ci
12
+ from utilities.whenever2 import get_now_local
14
13
 
15
14
  if TYPE_CHECKING:
16
15
  from types import TracebackType
@@ -31,8 +30,7 @@ class _PingerReceiverApp(FastAPI):
31
30
 
32
31
  @self.get("/ping") # skipif-ci
33
32
  def ping() -> str:
34
- now = serialize_zoned_datetime(get_now_local()) # skipif-ci
35
- return f"pong @ {now}" # skipif-ci
33
+ return f"pong @ {get_now_local()}" # skipif-ci
36
34
 
37
35
  _ = ping # skipif-ci
38
36
 
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, override
6
6
  from fpdf import FPDF
7
7
  from fpdf.enums import XPos, YPos
8
8
 
9
- from utilities.tzlocal import get_now_local
9
+ from utilities.whenever2 import format_compact, get_now
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  from collections.abc import Iterator
@@ -47,7 +47,7 @@ def yield_pdf(*, header: str | None = None) -> Iterator[_BasePDF]:
47
47
  def footer(self) -> None:
48
48
  self.set_y(-15)
49
49
  self.set_font(family="Helvetica", style="I", size=8)
50
- page_no, now = self.page_no(), get_now_local()
50
+ page_no, now = self.page_no(), format_compact(get_now())
51
51
  text = f"page {page_no}/{{}}; {now}"
52
52
  _ = self.cell(
53
53
  w=0,