dycw-utilities 0.166.1__tar.gz → 0.166.3__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 (211) hide show
  1. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/PKG-INFO +2 -2
  2. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/pyproject.toml +5 -5
  3. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_whenever.py +83 -24
  4. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/__init__.py +1 -1
  5. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/types.py +2 -0
  6. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/whenever.py +134 -73
  7. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/.gitignore +0 -0
  8. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/LICENSE +0 -0
  9. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/README.md +0 -0
  10. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/__init__.py +0 -0
  11. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/conftest.py +0 -0
  12. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/__init__.py +0 -0
  13. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_missing/__init__.py +0 -0
  14. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_missing/module.py +0 -0
  15. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_with/__init__.py +0 -0
  16. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_with/outer_1.py +0 -0
  17. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_with/outer_2.py +0 -0
  18. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  19. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  20. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  21. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  22. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_without/__init__.py +0 -0
  23. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_without/module_1.py +0 -0
  24. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/package_without/module_2.py +0 -0
  25. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/standalone.py +0 -0
  26. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/modules/with_imports.py +0 -0
  27. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  28. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  29. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  30. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  31. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  32. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  33. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  34. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  35. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_aeventkit.py +0 -0
  36. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_altair.py +0 -0
  37. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_asyncio.py +0 -0
  38. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_atomicwrites.py +0 -0
  39. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_atools.py +0 -0
  40. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_cachetools.py +0 -0
  41. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_click.py +0 -0
  42. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_concurrent.py +0 -0
  43. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_contextlib.py +0 -0
  44. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_contextvars.py +0 -0
  45. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_cryptography.py +0 -0
  46. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_cvxpy.py +0 -0
  47. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_dataclasses.py +0 -0
  48. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_enum.py +0 -0
  49. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_errors.py +0 -0
  50. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_fastapi.py +0 -0
  51. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_fpdf2.py +0 -0
  52. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_functions.py +0 -0
  53. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_functools.py +0 -0
  54. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_getpass.py +0 -0
  55. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_gzip.py +0 -0
  56. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_hashlib.py +0 -0
  57. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_http.py +0 -0
  58. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_hypothesis.py +0 -0
  59. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_importlib.py +0 -0
  60. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_inflect.py +0 -0
  61. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_ipython.py +0 -0
  62. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_iterables.py +0 -0
  63. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_json.py +0 -0
  64. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_jupyter.py +0 -0
  65. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_libcst.py +0 -0
  66. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_lightweight_charts.py +0 -0
  67. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_logging.py +0 -0
  68. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_math.py +0 -0
  69. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_memory_profiler.py +0 -0
  70. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_modules.py +0 -0
  71. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_more_itertools.py +0 -0
  72. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_numpy.py +0 -0
  73. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_objects/__init__.py +0 -0
  74. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_objects/objects.py +0 -0
  75. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_operator.py +0 -0
  76. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_optuna.py +0 -0
  77. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_orjson.py +0 -0
  78. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_os.py +0 -0
  79. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_parse.py +0 -0
  80. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_pathlib.py +0 -0
  81. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_pickle.py +0 -0
  82. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_platform.py +0 -0
  83. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_polars.py +0 -0
  84. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_polars_ols.py +0 -0
  85. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_postgres.py +0 -0
  86. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_pottery.py +0 -0
  87. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_pqdm.py +0 -0
  88. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_psutil.py +0 -0
  89. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_pyinstrument.py +0 -0
  90. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_pytest.py +0 -0
  91. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_pytest_randomly.py +0 -0
  92. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_pytest_regressions.py +0 -0
  93. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_random.py +0 -0
  94. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_re.py +0 -0
  95. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_redis.py +0 -0
  96. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_reprlib.py +0 -0
  97. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_scipy.py +0 -0
  98. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_sentinel.py +0 -0
  99. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_shelve.py +0 -0
  100. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_slack_sdk.py +0 -0
  101. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_socket.py +0 -0
  102. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_sqlalchemy.py +0 -0
  103. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_sqlalchemy_polars.py +0 -0
  104. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_statsmodels.py +0 -0
  105. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_string.py +0 -0
  106. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_tempfile.py +0 -0
  107. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_testbook.py +0 -0
  108. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_text.py +0 -0
  109. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_threading.py +0 -0
  110. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_timer.py +0 -0
  111. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_traceback.py +0 -0
  112. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_typed_settings.py +0 -0
  113. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_types.py +0 -0
  114. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_typing.py +0 -0
  115. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_typing_funcs/__init__.py +0 -0
  116. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_typing_funcs/no_future.py +0 -0
  117. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_typing_funcs/with_future.py +0 -0
  118. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_tzdata.py +0 -0
  119. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_tzlocal.py +0 -0
  120. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_uuid.py +0 -0
  121. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_version.py +0 -0
  122. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_warnings.py +0 -0
  123. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_zipfile.py +0 -0
  124. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/tests/test_zoneinfo.py +0 -0
  125. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/aeventkit.py +0 -0
  126. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/altair.py +0 -0
  127. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/asyncio.py +0 -0
  128. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/atomicwrites.py +0 -0
  129. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/atools.py +0 -0
  130. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/cachetools.py +0 -0
  131. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/click.py +0 -0
  132. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/concurrent.py +0 -0
  133. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/contextlib.py +0 -0
  134. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/contextvars.py +0 -0
  135. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/cryptography.py +0 -0
  136. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/cvxpy.py +0 -0
  137. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/dataclasses.py +0 -0
  138. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/enum.py +0 -0
  139. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/errors.py +0 -0
  140. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/fastapi.py +0 -0
  141. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/fpdf2.py +0 -0
  142. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/functions.py +0 -0
  143. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/functools.py +0 -0
  144. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/getpass.py +0 -0
  145. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/gzip.py +0 -0
  146. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/hashlib.py +0 -0
  147. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/http.py +0 -0
  148. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/hypothesis.py +0 -0
  149. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/importlib.py +0 -0
  150. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/inflect.py +0 -0
  151. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/ipython.py +0 -0
  152. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/iterables.py +0 -0
  153. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/json.py +0 -0
  154. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/jupyter.py +0 -0
  155. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/libcst.py +0 -0
  156. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/lightweight_charts.py +0 -0
  157. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/logging.py +0 -0
  158. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/math.py +0 -0
  159. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/memory_profiler.py +0 -0
  160. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/modules.py +0 -0
  161. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/more_itertools.py +0 -0
  162. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/numpy.py +0 -0
  163. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/operator.py +0 -0
  164. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/optuna.py +0 -0
  165. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/orjson.py +0 -0
  166. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/os.py +0 -0
  167. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/parse.py +0 -0
  168. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pathlib.py +0 -0
  169. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pickle.py +0 -0
  170. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/platform.py +0 -0
  171. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/polars.py +0 -0
  172. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/polars_ols.py +0 -0
  173. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/postgres.py +0 -0
  174. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pottery.py +0 -0
  175. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pqdm.py +0 -0
  176. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/psutil.py +0 -0
  177. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/py.typed +0 -0
  178. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pyinstrument.py +0 -0
  179. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pytest.py +0 -0
  180. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pytest_plugins/__init__.py +0 -0
  181. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
  182. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
  183. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/pytest_regressions.py +0 -0
  184. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/random.py +0 -0
  185. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/re.py +0 -0
  186. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/redis.py +0 -0
  187. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/reprlib.py +0 -0
  188. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/scipy.py +0 -0
  189. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/sentinel.py +0 -0
  190. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/shelve.py +0 -0
  191. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/slack_sdk.py +0 -0
  192. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/socket.py +0 -0
  193. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/sqlalchemy.py +0 -0
  194. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/sqlalchemy_polars.py +0 -0
  195. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/statsmodels.py +0 -0
  196. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/string.py +0 -0
  197. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/tempfile.py +0 -0
  198. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/testbook.py +0 -0
  199. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/text.py +0 -0
  200. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/threading.py +0 -0
  201. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/timer.py +0 -0
  202. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/traceback.py +0 -0
  203. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/typed_settings.py +0 -0
  204. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/typing.py +0 -0
  205. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/tzdata.py +0 -0
  206. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/tzlocal.py +0 -0
  207. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/uuid.py +0 -0
  208. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/version.py +0 -0
  209. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/warnings.py +0 -0
  210. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/zipfile.py +0 -0
  211. {dycw_utilities-0.166.1 → dycw_utilities-0.166.3}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.166.1
3
+ Version: 0.166.3
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -12,7 +12,7 @@ Provides-Extra: logging
12
12
  Requires-Dist: coloredlogs<15.1,>=15.0.1; extra == 'logging'
13
13
  Provides-Extra: test
14
14
  Requires-Dist: dycw-pytest-only<2.2,>=2.1.1; extra == 'test'
15
- Requires-Dist: hypothesis<6.139,>=6.138.2; extra == 'test'
15
+ Requires-Dist: hypothesis<6.139,>=6.138.3; extra == 'test'
16
16
  Requires-Dist: pytest-asyncio<1.2,>=1.1.0; extra == 'test'
17
17
  Requires-Dist: pytest-cov<6.3,>=6.2.1; extra == 'test'
18
18
  Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
@@ -37,7 +37,7 @@ cryptography = [
37
37
  "cryptography >=45.0.4, <45.1",
38
38
  ]
39
39
  cvxpy = [
40
- "cvxpy >=1.7.1, <1.8",
40
+ "cvxpy >=1.7.2, <1.8",
41
41
  ]
42
42
  dataclasses-test = [
43
43
  "orjson",
@@ -68,7 +68,7 @@ http-test = [
68
68
  "orjson",
69
69
  ]
70
70
  hypothesis = [
71
- "hypothesis >=6.138.2, <6.139",
71
+ "hypothesis >=6.138.3, <6.139",
72
72
  ]
73
73
  hypothesis-test = [
74
74
  "libcst",
@@ -233,7 +233,7 @@ dependencies = [
233
233
  name = "dycw-utilities"
234
234
  readme = "README.md"
235
235
  requires-python = ">= 3.12"
236
- version = "0.166.1"
236
+ version = "0.166.3"
237
237
 
238
238
  [project.entry-points.pytest11]
239
239
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -245,7 +245,7 @@ logging = [
245
245
  ]
246
246
  test = [
247
247
  "dycw-pytest-only >=2.1.1, <2.2",
248
- "hypothesis >=6.138.2, <6.139",
248
+ "hypothesis >=6.138.3, <6.139",
249
249
  "pytest >=8.4.1, <8.5",
250
250
  "pytest-asyncio >=1.1.0, <1.2",
251
251
  "pytest-cov >=6.2.1, <6.3",
@@ -266,7 +266,7 @@ test = [
266
266
  # bump-my-version
267
267
  [tool.bumpversion]
268
268
  allow_dirty = true
269
- current_version = "0.166.1"
269
+ current_version = "0.166.3"
270
270
 
271
271
  [[tool.bumpversion.files]]
272
272
  filename = "src/utilities/__init__.py"
@@ -40,7 +40,7 @@ from utilities.hypothesis import (
40
40
  zoned_date_times_2000,
41
41
  )
42
42
  from utilities.sentinel import Sentinel, sentinel
43
- from utilities.types import TIME_ZONES
43
+ from utilities.types import TIME_ZONES, MaybeCallableTimeLike
44
44
  from utilities.tzdata import HongKong, Tokyo, USCentral, USEastern
45
45
  from utilities.tzlocal import LOCAL_TIME_ZONE_NAME
46
46
  from utilities.whenever import (
@@ -63,6 +63,8 @@ from utilities.whenever import (
63
63
  SECOND,
64
64
  TIME_DELTA_MAX,
65
65
  TIME_DELTA_MIN,
66
+ TIME_LOCAL,
67
+ TIME_UTC,
66
68
  TODAY_LOCAL,
67
69
  TODAY_UTC,
68
70
  ZERO_DAYS,
@@ -72,7 +74,6 @@ from utilities.whenever import (
72
74
  DatePeriodError,
73
75
  MeanDateTimeError,
74
76
  MinMaxDateError,
75
- PeriodDict,
76
77
  TimePeriod,
77
78
  ToMonthsAndDaysError,
78
79
  ToNanosecondsError,
@@ -120,6 +121,8 @@ from utilities.whenever import (
120
121
  get_now_local,
121
122
  get_now_local_plain,
122
123
  get_now_plain,
124
+ get_time,
125
+ get_time_local,
123
126
  get_today,
124
127
  get_today_local,
125
128
  mean_datetime,
@@ -139,6 +142,7 @@ from utilities.whenever import (
139
142
  to_py_date_or_date_time,
140
143
  to_py_time_delta,
141
144
  to_seconds,
145
+ to_time,
142
146
  to_time_delta,
143
147
  to_weeks,
144
148
  to_years,
@@ -280,13 +284,8 @@ class TestDatePeriod:
280
284
 
281
285
  @given(data=data(), period=date_periods())
282
286
  def test_to_and_from_dict(self, *, data: DataObject, period: DatePeriod) -> None:
283
- dict1 = period.to_dict()
284
- dstart, dend = dict1["start"], dict1["end"]
285
- dict2 = PeriodDict(
286
- start=data.draw(sampled_from([dstart, dstart.py_date()])),
287
- end=data.draw(sampled_from([dend, dend.py_date()])),
288
- )
289
- result = DatePeriod.from_dict(dict2)
287
+ dict_ = data.draw(sampled_from([period.to_dict(), period.to_py_dict()]))
288
+ result = DatePeriod.from_dict(dict_)
290
289
  assert result == period
291
290
 
292
291
  @given(dates=pairs(dates(), unique=True, sorted=True))
@@ -471,6 +470,25 @@ class TestGetNowPlain:
471
470
  assert isinstance(NOW_PLAIN, PlainDateTime)
472
471
 
473
472
 
473
+ class TestGetTime:
474
+ @given(time_zone=zone_infos())
475
+ def test_function(self, *, time_zone: ZoneInfo) -> None:
476
+ now = get_time(time_zone)
477
+ assert isinstance(now, Time)
478
+
479
+ def test_constant(self) -> None:
480
+ assert isinstance(TIME_UTC, Time)
481
+
482
+
483
+ class TestGetTimeLocal:
484
+ def test_function(self) -> None:
485
+ now = get_time_local()
486
+ assert isinstance(now, Time)
487
+
488
+ def test_constant(self) -> None:
489
+ assert isinstance(TIME_LOCAL, Time)
490
+
491
+
474
492
  class TestGetToday:
475
493
  def test_function(self) -> None:
476
494
  today = get_today()
@@ -853,14 +871,11 @@ class TestTimePeriod:
853
871
  )
854
872
 
855
873
  @given(data=data(), period=time_periods())
856
- def test_to_and_from_dict(self, *, data: DataObject, period: TimePeriod) -> None:
857
- dict1 = period.to_dict()
858
- dstart, dend = dict1["start"], dict1["end"]
859
- dict2 = PeriodDict(
860
- start=data.draw(sampled_from([dstart, dstart.py_time()])),
861
- end=data.draw(sampled_from([dend, dend.py_time()])),
862
- )
863
- result = TimePeriod.from_dict(dict2)
874
+ def test_to_dict_and_from_dict(
875
+ self, *, data: DataObject, period: TimePeriod
876
+ ) -> None:
877
+ dict_ = data.draw(sampled_from([period.to_dict(), period.to_py_dict()]))
878
+ result = TimePeriod.from_dict(dict_)
864
879
  assert result == period
865
880
 
866
881
 
@@ -1319,6 +1334,55 @@ class TestToSeconds:
1319
1334
  _ = to_seconds(delta)
1320
1335
 
1321
1336
 
1337
+ class TestToTime:
1338
+ def test_default(self) -> None:
1339
+ first = get_today().at(to_time()).assume_tz(UTC.key)
1340
+ second = get_today().at(to_time()).assume_tz(UTC.key)
1341
+ assert abs(first - second) <= SECOND
1342
+
1343
+ @given(time=times())
1344
+ def test_time(self, *, time: Time) -> None:
1345
+ assert to_time(time) == time
1346
+
1347
+ @given(time=times())
1348
+ def test_str(self, *, time: Time) -> None:
1349
+ assert to_time(time.format_common_iso()) == time
1350
+
1351
+ @given(time=times())
1352
+ def test_py_time(self, *, time: Time) -> None:
1353
+ assert to_time(time.py_time()) == time
1354
+
1355
+ @given(time=times())
1356
+ def test_callable(self, *, time: Time) -> None:
1357
+ assert to_time(lambda: time) == time
1358
+
1359
+ def test_none(self) -> None:
1360
+ first = get_today().at(to_time(None)).assume_tz(UTC.key)
1361
+ second = get_today().at(get_time()).assume_tz(UTC.key)
1362
+ assert abs(first - second) <= SECOND
1363
+
1364
+ def test_sentinel(self) -> None:
1365
+ assert to_time(sentinel) is sentinel
1366
+
1367
+ @given(times=pairs(times()))
1368
+ def test_replace_non_sentinel(self, *, times: tuple[Time, Time]) -> None:
1369
+ time1, time2 = times
1370
+
1371
+ @dataclass(kw_only=True, slots=True)
1372
+ class Example:
1373
+ time: Time = field(default_factory=get_time)
1374
+
1375
+ def replace(
1376
+ self, *, time: MaybeCallableTimeLike | Sentinel = sentinel
1377
+ ) -> Self:
1378
+ return replace_non_sentinel(self, time=to_time(time))
1379
+
1380
+ obj = Example(time=time1)
1381
+ assert obj.time == time1
1382
+ assert obj.replace().time == time1
1383
+ assert obj.replace(time=time2).time == time2
1384
+
1385
+
1322
1386
  class TestToWeeks:
1323
1387
  @given(cls=sampled_from([DateDelta, DateTimeDelta]), weeks=integers())
1324
1388
  def test_date_or_date_time_delta(
@@ -1695,13 +1759,8 @@ class TestZonedDateTimePeriod:
1695
1759
  ) -> None:
1696
1760
  start, end = datetimes
1697
1761
  period = ZonedDateTimePeriod(start, end)
1698
- dict1 = period.to_dict()
1699
- dstart, dend = dict1["start"], dict1["end"]
1700
- dict2 = PeriodDict(
1701
- start=data.draw(sampled_from([dstart, dstart.py_datetime()])),
1702
- end=data.draw(sampled_from([dend, dend.py_datetime()])),
1703
- )
1704
- result = ZonedDateTimePeriod.from_dict(dict2)
1762
+ dict_ = data.draw(sampled_from([period.to_dict(), period.to_py_dict()]))
1763
+ result = ZonedDateTimePeriod.from_dict(dict_)
1705
1764
  assert result == period
1706
1765
 
1707
1766
  @given(period=zoned_date_time_periods())
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.166.1"
3
+ __version__ = "0.166.3"
@@ -255,6 +255,7 @@ type DateTimeRoundMode = Literal[
255
255
  ]
256
256
  type Delta = DateDelta | TimeDelta | DateTimeDelta
257
257
  type MaybeCallableDateLike = MaybeCallable[DateLike]
258
+ type MaybeCallableTimeLike = MaybeCallable[TimeLike]
258
259
  type MaybeCallableZonedDateTimeLike = MaybeCallable[ZonedDateTimeLike]
259
260
  type MonthDayLike = MaybeStr[MonthDay]
260
261
  type PlainDateTimeLike = MaybeStr[PlainDateTime]
@@ -308,6 +309,7 @@ __all__ = [
308
309
  "MaybeCallableDateLike",
309
310
  "MaybeCallablePathLike",
310
311
  "MaybeCallableStr",
312
+ "MaybeCallableTimeLike",
311
313
  "MaybeCallableUUIDLike",
312
314
  "MaybeCallableZonedDateTimeLike",
313
315
  "MaybeCollection",
@@ -13,7 +13,6 @@ from typing import (
13
13
  Self,
14
14
  SupportsFloat,
15
15
  TypedDict,
16
- TypeVar,
17
16
  assert_never,
18
17
  cast,
19
18
  overload,
@@ -47,6 +46,7 @@ if TYPE_CHECKING:
47
46
  DateTimeRoundMode,
48
47
  Delta,
49
48
  MaybeCallableDateLike,
49
+ MaybeCallableTimeLike,
50
50
  MaybeCallableZonedDateTimeLike,
51
51
  TimeOrDateTimeDelta,
52
52
  TimeZoneLike,
@@ -146,9 +146,6 @@ def sub_year_month(x: YearMonth, /, *, years: int = 0, months: int = 0) -> YearM
146
146
  ##
147
147
 
148
148
 
149
- _TDate_co = TypeVar("_TDate_co", bound=Date | dt.date, covariant=True)
150
-
151
-
152
149
  @dataclass(repr=False, order=True, unsafe_hash=True, kw_only=False)
153
150
  class DatePeriod:
154
151
  """A period of dates."""
@@ -210,7 +207,7 @@ class DatePeriod:
210
207
  return f"{fc(start)}-{fc(end)}"
211
208
 
212
209
  @classmethod
213
- def from_dict(cls, mapping: PeriodDict[_TDate_co], /) -> Self:
210
+ def from_dict(cls, mapping: PeriodDict[Date] | PeriodDict[dt.date], /) -> Self:
214
211
  """Convert the dictionary to a period."""
215
212
  match mapping["start"]:
216
213
  case Date() as start:
@@ -238,6 +235,10 @@ class DatePeriod:
238
235
  """Convert the period to a dictionary."""
239
236
  return PeriodDict(start=self.start, end=self.end)
240
237
 
238
+ def to_py_dict(self) -> PeriodDict[dt.date]:
239
+ """Convert the period to a dictionary."""
240
+ return PeriodDict(start=self.start.py_date(), end=self.end.py_date())
241
+
241
242
 
242
243
  @dataclass(kw_only=True, slots=True)
243
244
  class DatePeriodError(Exception):
@@ -368,7 +369,7 @@ NOW_UTC = get_now(UTC)
368
369
 
369
370
 
370
371
  def get_now_local() -> ZonedDateTime:
371
- """Get the current local date-time."""
372
+ """Get the current zoned date-time in the local time-zone."""
372
373
  return get_now(LOCAL_TIME_ZONE)
373
374
 
374
375
 
@@ -376,7 +377,7 @@ NOW_LOCAL = get_now_local()
376
377
 
377
378
 
378
379
  def get_now_plain(time_zone: TimeZoneLike = UTC, /) -> PlainDateTime:
379
- """Get the current date-time as a plain date-time."""
380
+ """Get the current plain date-time."""
380
381
  return get_now(time_zone).to_plain()
381
382
 
382
383
 
@@ -384,7 +385,7 @@ NOW_PLAIN = get_now_plain()
384
385
 
385
386
 
386
387
  def get_now_local_plain() -> PlainDateTime:
387
- """Get the current local date-time as a plain date-time."""
388
+ """Get the current plain date-time in the local time-zone."""
388
389
  return get_now_local().to_plain()
389
390
 
390
391
 
@@ -394,6 +395,25 @@ NOW_LOCAL_PLAIN = get_now_local_plain()
394
395
  ##
395
396
 
396
397
 
398
+ def get_time(time_zone: TimeZoneLike = UTC, /) -> Time:
399
+ """Get the current time."""
400
+ return get_now(time_zone).time()
401
+
402
+
403
+ TIME_UTC = get_time(UTC)
404
+
405
+
406
+ def get_time_local() -> Time:
407
+ """Get the current time in the local time-zone."""
408
+ return get_time(LOCAL_TIME_ZONE)
409
+
410
+
411
+ TIME_LOCAL = get_time_local()
412
+
413
+
414
+ ##
415
+
416
+
397
417
  def get_today(time_zone: TimeZoneLike = UTC, /) -> Date:
398
418
  """Get the current, timezone-aware local date."""
399
419
  return get_now(time_zone).date()
@@ -788,9 +808,6 @@ class _RoundDateOrDateTimeDateTimeIntraDayWithWeekdayError(RoundDateOrDateTimeEr
788
808
  ##
789
809
 
790
810
 
791
- _TTime_co = TypeVar("_TTime_co", bound=Time | dt.time, covariant=True)
792
-
793
-
794
811
  @dataclass(repr=False, order=True, unsafe_hash=True, kw_only=False)
795
812
  class TimePeriod:
796
813
  """A period of times."""
@@ -817,7 +834,7 @@ class TimePeriod:
817
834
  return DatePeriod(start, end).at((self.start, self.end), time_zone=time_zone)
818
835
 
819
836
  @classmethod
820
- def from_dict(cls, mapping: PeriodDict[_TTime_co], /) -> Self:
837
+ def from_dict(cls, mapping: PeriodDict[Time] | PeriodDict[dt.time], /) -> Self:
821
838
  """Convert the dictionary to a period."""
822
839
  match mapping["start"]:
823
840
  case Time() as start:
@@ -845,6 +862,10 @@ class TimePeriod:
845
862
  """Convert the period to a dictionary."""
846
863
  return PeriodDict(start=self.start, end=self.end)
847
864
 
865
+ def to_py_dict(self) -> PeriodDict[dt.time]:
866
+ """Convert the period to a dictionary."""
867
+ return PeriodDict(start=self.start.py_time(), end=self.end.py_time())
868
+
848
869
 
849
870
  ##
850
871
 
@@ -1377,6 +1398,95 @@ class ToPyTimeDeltaError(Exception):
1377
1398
  ##
1378
1399
 
1379
1400
 
1401
+ def to_seconds(delta: Delta, /) -> int:
1402
+ """Compute the number of seconds in a delta."""
1403
+ match delta:
1404
+ case DateDelta():
1405
+ try:
1406
+ days = to_days(delta)
1407
+ except _ToDaysMonthsError as error:
1408
+ raise _ToSecondsMonthsError(delta=delta, months=error.months) from None
1409
+ return 24 * 60 * 60 * days
1410
+ case TimeDelta():
1411
+ nanos = to_nanoseconds(delta)
1412
+ seconds, remainder = divmod(nanos, int(1e9))
1413
+ if remainder != 0:
1414
+ raise _ToSecondsNanosecondsError(delta=delta, nanoseconds=remainder)
1415
+ return seconds
1416
+ case DateTimeDelta():
1417
+ try:
1418
+ return to_seconds(delta.date_part()) + to_seconds(delta.time_part())
1419
+ except _ToSecondsMonthsError as error:
1420
+ raise _ToSecondsMonthsError(delta=delta, months=error.months) from None
1421
+ except _ToSecondsNanosecondsError as error:
1422
+ raise _ToSecondsNanosecondsError(
1423
+ delta=delta, nanoseconds=error.nanoseconds
1424
+ ) from None
1425
+ case never:
1426
+ assert_never(never)
1427
+
1428
+
1429
+ @dataclass(kw_only=True, slots=True)
1430
+ class ToSecondsError(Exception): ...
1431
+
1432
+
1433
+ @dataclass(kw_only=True, slots=True)
1434
+ class _ToSecondsMonthsError(ToSecondsError):
1435
+ delta: DateOrDateTimeDelta
1436
+ months: int
1437
+
1438
+ @override
1439
+ def __str__(self) -> str:
1440
+ return f"Delta must not contain months; got {self.months}"
1441
+
1442
+
1443
+ @dataclass(kw_only=True, slots=True)
1444
+ class _ToSecondsNanosecondsError(ToSecondsError):
1445
+ delta: TimeOrDateTimeDelta
1446
+ nanoseconds: int
1447
+
1448
+ @override
1449
+ def __str__(self) -> str:
1450
+ return f"Delta must not contain extra nanoseconds; got {self.nanoseconds}"
1451
+
1452
+
1453
+ ##
1454
+
1455
+
1456
+ @overload
1457
+ def to_time(time: Sentinel, /, *, time_zone: TimeZoneLike = UTC) -> Sentinel: ...
1458
+ @overload
1459
+ def to_time(
1460
+ time: MaybeCallableTimeLike | None | dt.time = get_time,
1461
+ /,
1462
+ *,
1463
+ time_zone: TimeZoneLike = UTC,
1464
+ ) -> Time: ...
1465
+ def to_time(
1466
+ time: MaybeCallableTimeLike | dt.time | None | Sentinel = get_time,
1467
+ /,
1468
+ *,
1469
+ time_zone: TimeZoneLike = UTC,
1470
+ ) -> Time | Sentinel:
1471
+ """Convert to a time."""
1472
+ match time:
1473
+ case Time() | Sentinel():
1474
+ return time
1475
+ case None:
1476
+ return get_time(time_zone)
1477
+ case str():
1478
+ return Time.parse_common_iso(time)
1479
+ case dt.time():
1480
+ return Time.from_py_time(time)
1481
+ case Callable() as func:
1482
+ return to_time(func(), time_zone=time_zone)
1483
+ case never:
1484
+ assert_never(never)
1485
+
1486
+
1487
+ ##
1488
+
1489
+
1380
1490
  def to_time_delta(nanos: int, /) -> TimeDelta:
1381
1491
  """Construct a time delta."""
1382
1492
  components = _to_time_delta_components(nanos)
@@ -1455,61 +1565,6 @@ def _to_time_delta_components(nanos: int, /) -> _TimeDeltaComponents:
1455
1565
  ##
1456
1566
 
1457
1567
 
1458
- def to_seconds(delta: Delta, /) -> int:
1459
- """Compute the number of seconds in a delta."""
1460
- match delta:
1461
- case DateDelta():
1462
- try:
1463
- days = to_days(delta)
1464
- except _ToDaysMonthsError as error:
1465
- raise _ToSecondsMonthsError(delta=delta, months=error.months) from None
1466
- return 24 * 60 * 60 * days
1467
- case TimeDelta():
1468
- nanos = to_nanoseconds(delta)
1469
- seconds, remainder = divmod(nanos, int(1e9))
1470
- if remainder != 0:
1471
- raise _ToSecondsNanosecondsError(delta=delta, nanoseconds=remainder)
1472
- return seconds
1473
- case DateTimeDelta():
1474
- try:
1475
- return to_seconds(delta.date_part()) + to_seconds(delta.time_part())
1476
- except _ToSecondsMonthsError as error:
1477
- raise _ToSecondsMonthsError(delta=delta, months=error.months) from None
1478
- except _ToSecondsNanosecondsError as error:
1479
- raise _ToSecondsNanosecondsError(
1480
- delta=delta, nanoseconds=error.nanoseconds
1481
- ) from None
1482
- case never:
1483
- assert_never(never)
1484
-
1485
-
1486
- @dataclass(kw_only=True, slots=True)
1487
- class ToSecondsError(Exception): ...
1488
-
1489
-
1490
- @dataclass(kw_only=True, slots=True)
1491
- class _ToSecondsMonthsError(ToSecondsError):
1492
- delta: DateOrDateTimeDelta
1493
- months: int
1494
-
1495
- @override
1496
- def __str__(self) -> str:
1497
- return f"Delta must not contain months; got {self.months}"
1498
-
1499
-
1500
- @dataclass(kw_only=True, slots=True)
1501
- class _ToSecondsNanosecondsError(ToSecondsError):
1502
- delta: TimeOrDateTimeDelta
1503
- nanoseconds: int
1504
-
1505
- @override
1506
- def __str__(self) -> str:
1507
- return f"Delta must not contain extra nanoseconds; got {self.nanoseconds}"
1508
-
1509
-
1510
- ##
1511
-
1512
-
1513
1568
  def to_weeks(delta: Delta, /) -> int:
1514
1569
  """Compute the number of weeks in a delta."""
1515
1570
  try:
@@ -1726,11 +1781,6 @@ class WheneverLogRecord(LogRecord):
1726
1781
  ##
1727
1782
 
1728
1783
 
1729
- _TDateTime_co = TypeVar(
1730
- "_TDateTime_co", bound=ZonedDateTime | dt.datetime, covariant=True
1731
- )
1732
-
1733
-
1734
1784
  @dataclass(repr=False, order=True, unsafe_hash=True, kw_only=False)
1735
1785
  class ZonedDateTimePeriod:
1736
1786
  """A period of time."""
@@ -1833,7 +1883,9 @@ class ZonedDateTimePeriod:
1833
1883
  return f"{fc(start.to_plain())}-{fc(end, fmt='%Y%m%dT%H')}"
1834
1884
 
1835
1885
  @classmethod
1836
- def from_dict(cls, mapping: PeriodDict[_TDateTime_co], /) -> Self:
1886
+ def from_dict(
1887
+ cls, mapping: PeriodDict[ZonedDateTime] | PeriodDict[dt.datetime], /
1888
+ ) -> Self:
1837
1889
  """Convert the dictionary to a period."""
1838
1890
  match mapping["start"]:
1839
1891
  case ZonedDateTime() as start:
@@ -1869,6 +1921,10 @@ class ZonedDateTimePeriod:
1869
1921
  """Convert the period to a dictionary."""
1870
1922
  return PeriodDict(start=self.start, end=self.end)
1871
1923
 
1924
+ def to_py_dict(self) -> PeriodDict[dt.datetime]:
1925
+ """Convert the period to a dictionary."""
1926
+ return PeriodDict(start=self.start.py_datetime(), end=self.end.py_datetime())
1927
+
1872
1928
  def to_tz(self, time_zone: TimeZoneLike, /) -> Self:
1873
1929
  """Convert the time zone."""
1874
1930
  tz = to_time_zone_name(time_zone)
@@ -1933,6 +1989,8 @@ __all__ = [
1933
1989
  "SECOND",
1934
1990
  "TIME_DELTA_MAX",
1935
1991
  "TIME_DELTA_MIN",
1992
+ "TIME_LOCAL",
1993
+ "TIME_UTC",
1936
1994
  "TODAY_LOCAL",
1937
1995
  "TODAY_UTC",
1938
1996
  "WEEK",
@@ -1971,6 +2029,8 @@ __all__ = [
1971
2029
  "get_now_local",
1972
2030
  "get_now_local_plain",
1973
2031
  "get_now_plain",
2032
+ "get_time",
2033
+ "get_time_local",
1974
2034
  "get_today",
1975
2035
  "get_today_local",
1976
2036
  "mean_datetime",
@@ -1989,6 +2049,7 @@ __all__ = [
1989
2049
  "to_py_date_or_date_time",
1990
2050
  "to_py_time_delta",
1991
2051
  "to_seconds",
2052
+ "to_time",
1992
2053
  "to_weeks",
1993
2054
  "to_years",
1994
2055
  "to_zoned_date_time",