dycw-utilities 0.131.3__tar.gz → 0.131.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. dycw_utilities-0.131.5/PKG-INFO +39 -0
  2. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/pyproject.toml +2 -182
  3. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_hypothesis.py +11 -4
  4. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_operator.py +9 -9
  5. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_parse.py +4 -3
  6. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_whenever2.py +42 -0
  7. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/__init__.py +1 -1
  8. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/hypothesis.py +24 -3
  9. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/whenever2.py +29 -2
  10. dycw_utilities-0.131.3/PKG-INFO +0 -205
  11. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/.gitignore +0 -0
  12. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/LICENSE +0 -0
  13. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/README.md +0 -0
  14. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/__init__.py +0 -0
  15. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/conftest.py +0 -0
  16. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/__init__.py +0 -0
  17. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_missing/__init__.py +0 -0
  18. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_missing/module.py +0 -0
  19. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_with/__init__.py +0 -0
  20. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_with/outer_1.py +0 -0
  21. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_with/outer_2.py +0 -0
  22. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  23. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  24. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  25. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  26. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_without/__init__.py +0 -0
  27. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_without/module_1.py +0 -0
  28. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/package_without/module_2.py +0 -0
  29. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/standalone.py +0 -0
  30. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/modules/with_imports.py +0 -0
  31. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  32. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  33. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  34. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  35. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  36. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  37. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  38. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  39. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_aiolimiter.py +0 -0
  40. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_altair.py +0 -0
  41. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_asyncio.py +0 -0
  42. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_asyncio_classes/__init__.py +0 -0
  43. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_asyncio_classes/loopers.py +0 -0
  44. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_asyncio_classes/redis.py +0 -0
  45. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_atomicwrites.py +0 -0
  46. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_atools.py +0 -0
  47. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_cachetools.py +0 -0
  48. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_click.py +0 -0
  49. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_concurrent.py +0 -0
  50. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_contextlib.py +0 -0
  51. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_contextvars.py +0 -0
  52. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_cryptography.py +0 -0
  53. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_cvxpy.py +0 -0
  54. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_dataclasses.py +0 -0
  55. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_datetime.py +0 -0
  56. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_enum.py +0 -0
  57. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_errors.py +0 -0
  58. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_eventkit.py +0 -0
  59. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_fastapi.py +0 -0
  60. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_fpdf2.py +0 -0
  61. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_functions.py +0 -0
  62. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_functools.py +0 -0
  63. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_getpass.py +0 -0
  64. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_git.py +0 -0
  65. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_hashlib.py +0 -0
  66. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_http.py +0 -0
  67. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_importlib.py +0 -0
  68. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_inflect.py +0 -0
  69. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_ipython.py +0 -0
  70. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_iterables.py +0 -0
  71. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_jupyter.py +0 -0
  72. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_libcst.py +0 -0
  73. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_lightweight_charts.py +0 -0
  74. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_logging.py +0 -0
  75. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_luigi.py +0 -0
  76. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_math.py +0 -0
  77. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_memory_profiler.py +0 -0
  78. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_modules.py +0 -0
  79. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_more_itertools.py +0 -0
  80. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_numpy.py +0 -0
  81. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_optuna.py +0 -0
  82. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_orjson.py +0 -0
  83. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_os.py +0 -0
  84. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pathlib.py +0 -0
  85. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_period.py +0 -0
  86. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pickle.py +0 -0
  87. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_platform.py +0 -0
  88. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_polars.py +0 -0
  89. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_polars_ols.py +0 -0
  90. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pottery.py +0 -0
  91. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pqdm.py +0 -0
  92. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_psutil.py +0 -0
  93. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pydantic.py +0 -0
  94. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pyinstrument.py +0 -0
  95. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pyrsistent.py +0 -0
  96. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pytest.py +0 -0
  97. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_pytest_regressions.py +0 -0
  98. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_python_dotenv.py +0 -0
  99. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_random.py +0 -0
  100. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_re.py +0 -0
  101. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_redis.py +0 -0
  102. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_reprlib.py +0 -0
  103. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_scipy.py +0 -0
  104. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_sentinel.py +0 -0
  105. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_shelve.py +0 -0
  106. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_slack_sdk.py +0 -0
  107. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_socket.py +0 -0
  108. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_sqlalchemy.py +0 -0
  109. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_sqlalchemy_polars.py +0 -0
  110. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_statsmodel.py +0 -0
  111. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_streamlit.py +0 -0
  112. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_string.py +0 -0
  113. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_tempfile.py +0 -0
  114. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_tenacity.py +0 -0
  115. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_text.py +0 -0
  116. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_threading.py +0 -0
  117. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_timer.py +0 -0
  118. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_traceback.py +0 -0
  119. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_types.py +0 -0
  120. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_typing.py +0 -0
  121. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_typing_funcs/__init__.py +0 -0
  122. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_typing_funcs/no_future.py +0 -0
  123. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_typing_funcs/with_future.py +0 -0
  124. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_tzdata.py +0 -0
  125. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_tzlocal.py +0 -0
  126. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_uuid.py +0 -0
  127. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_version.py +0 -0
  128. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_warnings.py +0 -0
  129. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_whenever.py +0 -0
  130. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_zipfile.py +0 -0
  131. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/tests/test_zoneinfo.py +0 -0
  132. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/aiolimiter.py +0 -0
  133. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/altair.py +0 -0
  134. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/asyncio.py +0 -0
  135. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/atomicwrites.py +0 -0
  136. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/atools.py +0 -0
  137. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/cachetools.py +0 -0
  138. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/click.py +0 -0
  139. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/concurrent.py +0 -0
  140. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/contextlib.py +0 -0
  141. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/contextvars.py +0 -0
  142. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/cryptography.py +0 -0
  143. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/cvxpy.py +0 -0
  144. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/dataclasses.py +0 -0
  145. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/datetime.py +0 -0
  146. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/enum.py +0 -0
  147. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/errors.py +0 -0
  148. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/eventkit.py +0 -0
  149. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/fastapi.py +0 -0
  150. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/fpdf2.py +0 -0
  151. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/functions.py +0 -0
  152. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/functools.py +0 -0
  153. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/getpass.py +0 -0
  154. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/git.py +0 -0
  155. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/hashlib.py +0 -0
  156. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/http.py +0 -0
  157. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/importlib.py +0 -0
  158. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/inflect.py +0 -0
  159. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/ipython.py +0 -0
  160. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/iterables.py +0 -0
  161. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/jupyter.py +0 -0
  162. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/libcst.py +0 -0
  163. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/lightweight_charts.py +0 -0
  164. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/logging.py +0 -0
  165. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/luigi.py +0 -0
  166. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/math.py +0 -0
  167. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/memory_profiler.py +0 -0
  168. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/modules.py +0 -0
  169. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/more_itertools.py +0 -0
  170. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/numpy.py +0 -0
  171. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/operator.py +0 -0
  172. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/optuna.py +0 -0
  173. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/orjson.py +0 -0
  174. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/os.py +0 -0
  175. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/parse.py +0 -0
  176. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pathlib.py +0 -0
  177. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/period.py +0 -0
  178. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pickle.py +0 -0
  179. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/platform.py +0 -0
  180. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/polars.py +0 -0
  181. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/polars_ols.py +0 -0
  182. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pottery.py +0 -0
  183. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pqdm.py +0 -0
  184. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/psutil.py +0 -0
  185. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/py.typed +0 -0
  186. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pydantic.py +0 -0
  187. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pyinstrument.py +0 -0
  188. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pyrsistent.py +0 -0
  189. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pytest.py +0 -0
  190. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/pytest_regressions.py +0 -0
  191. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/python_dotenv.py +0 -0
  192. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/random.py +0 -0
  193. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/re.py +0 -0
  194. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/redis.py +0 -0
  195. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/reprlib.py +0 -0
  196. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/scipy.py +0 -0
  197. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/sentinel.py +0 -0
  198. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/shelve.py +0 -0
  199. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/slack_sdk.py +0 -0
  200. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/socket.py +0 -0
  201. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/sqlalchemy.py +0 -0
  202. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/sqlalchemy_polars.py +0 -0
  203. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/statsmodels.py +0 -0
  204. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/streamlit.py +0 -0
  205. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/string.py +0 -0
  206. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/tempfile.py +0 -0
  207. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/tenacity.py +0 -0
  208. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/text.py +0 -0
  209. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/threading.py +0 -0
  210. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/timer.py +0 -0
  211. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/traceback.py +0 -0
  212. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/types.py +0 -0
  213. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/typing.py +0 -0
  214. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/tzdata.py +0 -0
  215. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/tzlocal.py +0 -0
  216. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/uuid.py +0 -0
  217. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/version.py +0 -0
  218. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/warnings.py +0 -0
  219. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/whenever.py +0 -0
  220. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/zipfile.py +0 -0
  221. {dycw_utilities-0.131.3 → dycw_utilities-0.131.5}/src/utilities/zoneinfo.py +0 -0
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.4
2
+ Name: dycw-utilities
3
+ Version: 0.131.5
4
+ Author-email: Derek Wan <d.wan@icloud.com>
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: atomicwrites<1.5,>=1.4.1
8
+ Requires-Dist: typing-extensions<4.15,>=4.14.0
9
+ Requires-Dist: tzlocal<5.4,>=5.3.1
10
+ Requires-Dist: whenever<0.9,>=0.8.5
11
+ Provides-Extra: logging
12
+ Requires-Dist: coloredlogs<15.1,>=15.0.1; extra == 'logging'
13
+ Provides-Extra: test
14
+ Requires-Dist: dycw-pytest-only<2.2,>=2.1.1; extra == 'test'
15
+ Requires-Dist: hypothesis<6.136,>=6.135.2; extra == 'test'
16
+ Requires-Dist: pytest-asyncio<1.1,>=1.0.0; extra == 'test'
17
+ Requires-Dist: pytest-cov<6.2,>=6.1.1; extra == 'test'
18
+ Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
19
+ Requires-Dist: pytest-lazy-fixtures<1.2,>=1.1.4; extra == 'test'
20
+ Requires-Dist: pytest-randomly<3.17,>=3.16.0; extra == 'test'
21
+ Requires-Dist: pytest-regressions<2.9,>=2.8.0; extra == 'test'
22
+ Requires-Dist: pytest-rerunfailures<16,>=15.1; extra == 'test'
23
+ Requires-Dist: pytest-rng<1.1,>=1.0.0; extra == 'test'
24
+ Requires-Dist: pytest-timeout<2.5,>=2.4.0; extra == 'test'
25
+ Requires-Dist: pytest-xdist<3.8,>=3.7.0; extra == 'test'
26
+ Requires-Dist: pytest<8.4,>=8.3.5; extra == 'test'
27
+ Description-Content-Type: text/markdown
28
+
29
+ [![PyPI version](https://badge.fury.io/py/dycw-utilities.svg)](https://badge.fury.io/py/dycw-utilities)
30
+
31
+ # `dycw-utilities`
32
+
33
+ [All the Python functions I don't want to write twice.](https://github.com/nvim-lua/plenary.nvim)
34
+
35
+ ## Installation
36
+
37
+ - `pip install dycw-utilities`
38
+
39
+ or with [extras](https://github.com/dycw/python-utilities/blob/master/pyproject.toml).
@@ -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.3"
97
+ version = "0.131.5"
98
98
 
99
99
  [project.optional-dependencies]
100
100
  logging = [
@@ -115,193 +115,13 @@ test = [
115
115
  "pytest-timeout >= 2.4.0, < 2.5",
116
116
  "pytest-xdist >= 3.7.0, < 3.8",
117
117
  ]
118
- zzz-test-aiolimiter = [
119
- "aiolimiter >= 1.2.1, < 1.3",
120
- ]
121
- zzz-test-altair = [
122
- "altair >= 5.5.0, < 5.6",
123
- "img2pdf >= 0.6.0, < 0.7",
124
- "polars-lts-cpu >= 1.30.0, < 1.31",
125
- "vl-convert-python >= 1.8.0, < 1.9",
126
- ]
127
- zzz-test-asyncio = []
128
- zzz-test-atomicwrites = []
129
- zzz-test-atools = [
130
- "atools >= 0.14.2, < 0.15",
131
- ]
132
- zzz-test-cachetools = ["cachetools >= 5.5.2, < 5.6"]
133
- zzz-test-click = [
134
- "click >= 8.2.1, < 8.3",
135
- "sqlalchemy >= 2.0.41, < 2.1",
136
- ]
137
- zzz-test-contextlib = []
138
- zzz-test-contextvars = []
139
- zzz-test-cryptography = ["cryptography >= 45.0.4, < 45.1"]
140
- zzz-test-cvxpy = ["cvxpy >= 1.6.5, < 1.7"]
141
- zzz-test-dataclasses = [
142
- "orjson >= 3.10.15, < 3.11",
143
- "polars-lts-cpu >= 1.30.0, < 1.31",
144
- ]
145
- zzz-test-datetime = [
146
- ]
147
- zzz-test-enum = []
148
- zzz-test-errors = []
149
- zzz-test-eventkit = ["eventkit >= 1.0.3, < 1.1"]
150
- zzz-test-fastapi = [
151
- "fastapi >= 0.115.11, < 0.116",
152
- "httpx >= 0.28.1, < 0.29",
153
- "uvicorn >= 0.34.1, < 0.35",
154
- ]
155
- zzz-test-fpdf2 = [
156
- "fpdf2 >= 2.8.3, < 2.9",
157
- ]
158
- zzz-test-functions = []
159
- zzz-test-functools = []
160
- zzz-test-getpass = []
161
- zzz-test-git = []
162
- zzz-test-hashlib = [
163
- "polars-lts-cpu >= 1.30.0, < 1.31",
164
- "orjson >= 3.10.15, < 3.11",
165
- ]
166
- zzz-test-http = [
167
- "orjson >= 3.10.18, < 3.11",
168
- ]
169
- zzz-test-hypothesis = [
170
- "aiosqlite >= 0.21.0, < 0.22",
171
- "asyncpg >= 0.30.0, < 0.31", # for sqlalchemy async
172
- "greenlet >= 3.2.0, < 3.3", # for sqlalchemy async
173
- "hypothesis >= 6.135.2, < 6.136",
174
- "luigi >= 3.6.0, < 3.7",
175
- "numpy >= 2.3.0, < 2.4",
176
- "pathvalidate >= 3.2.3, < 3.3",
177
- "redis >= 6.2.0, < 6.3",
178
- "sqlalchemy >= 2.0.41, < 2.1",
179
- "tenacity >= 8.5.0, < 9.0", # limited by luigi
180
- ]
181
- zzz-test-ipython = ["ipython >= 9.0.1, < 9.1"]
182
- zzz-test-iterables = [
183
- "polars-lts-cpu >= 1.30.0, < 1.31",
184
- ]
185
- zzz-test-jupyter = [
186
- "jupyterlab >= 4.2.0, < 4.3",
187
- "pandas >= 2.3.0, < 2.4",
188
- "polars-lts-cpu >= 1.30.0, < 1.31",
189
- ]
190
- zzz-test-logging = [
191
- "coloredlogs >= 15.0.1, < 15.1",
192
- "rich >= 14.0.0, < 14.1",
193
- "tomlkit >= 0.13.2, < 0.14",
194
- ]
195
- zzz-test-luigi = [
196
- "luigi >= 3.6.0, < 3.7",
197
- ]
198
- zzz-test-math = ["numpy >= 2.3.0, < 2.4"]
199
- zzz-test-memory-profiler = ["memory-profiler >= 0.61.0, < 0.62"]
200
- zzz-test-modules = []
201
- zzz-test-more-itertools = ["more-itertools >= 10.7.0, < 10.8"]
202
- zzz-test-numpy = ["numpy >= 2.3.0, < 2.4"]
203
- zzz-test-operator = [
204
- "polars-lts-cpu >= 1.30.0, < 1.31",
205
- ]
206
- zzz-test-optuna = ["optuna >= 4.3.0, < 4.4"]
207
- zzz-test-orjson = [
208
- "orjson >= 3.10.15, < 3.11",
209
- "polars-lts-cpu >= 1.30.0, < 1.31",
210
- "rich >= 14.0.0, < 14.1",
211
- ]
212
- zzz-test-os = []
213
- zzz-test-pathlib = []
214
- zzz-test-pickle = []
215
- zzz-test-platform = []
216
- zzz-test-polars = [
217
- "polars-lts-cpu >= 1.30.0, < 1.31",
218
- ]
219
- zzz-test-pqdm = ["pqdm >= 0.2.0, < 0.3"]
220
- zzz-test-pydantic = [
221
- "pydantic >= 2.11.4, < 2.12",
222
- ]
223
- zzz-test-pyinstrument = [
224
- "pyinstrument >= 5.0.2, < 5.1",
225
- ]
226
- zzz-test-pyrsistent = ["pyrsistent >= 0.20.0, < 0.21"]
227
- zzz-test-pytest = [
228
- "orjson >= 3.10.18, < 3.11",
229
- ]
230
- zzz-test-pytest-regressions = ["pytest-regressions >= 2.8.0, < 2.9"]
231
- zzz-test-python-dotenv = [
232
- "python-dotenv >= 1.1.0, < 1.2",
233
- ]
234
- zzz-test-random = []
235
- zzz-test-re = []
236
- zzz-test-redis = [
237
- "orjson >= 3.10.15, < 3.11",
238
- "polars-lts-cpu >= 1.30.0, < 1.31",
239
- "redis >= 6.2.0, < 6.3",
240
- "rich >= 14.0.0, < 14.1",
241
- "tenacity >= 8.5.0, < 9.0", # limited by luigi
242
- ]
243
- zzz-test-rich = ["rich >= 14.0.0, < 14.1"]
244
- zzz-test-scipy = ["scipy >= 1.15.3, < 1.16"]
245
- zzz-test-sentinel = []
246
- zzz-test-shelve = []
247
- zzz-test-slack-sdk = [
248
- "aiohttp >= 3.12.12, < 3.13", # for slack
249
- "slack-sdk >= 3.35.0, < 3.36",
250
- ]
251
- zzz-test-socket = []
252
- zzz-test-sqlalchemy = [
253
- "aiosqlite >= 0.21.0, < 0.22",
254
- "asyncpg >= 0.30.0, < 0.31", # for sqlalchemy async
255
- "greenlet >= 3.2.0, < 3.3", # for sqlalchemy async
256
- "nest-asyncio >= 1.6.0, < 1.7", # for sqlalchemy async
257
- "sqlalchemy >= 2.0.41, < 2.1",
258
- "tenacity >= 8.5.0, < 9.0", # limited by luigi
259
- ]
260
- zzz-test-sqlalchemy-polars = [
261
- "aiosqlite >= 0.21.0, < 0.22",
262
- "asyncpg >= 0.30.0, < 0.31", # for sqlalchemy async
263
- "greenlet >= 3.2.0, < 3.3", # for sqlalchemy async
264
- "nest-asyncio >= 1.6.0, < 1.7", # for sqlalchemy async
265
- "polars-lts-cpu >= 1.30.0, < 1.31",
266
- "sqlalchemy >= 2.0.41, < 2.1",
267
- "tenacity >= 8.5.0, < 9.0", # limited by luigi
268
- ]
269
- zzz-test-streamlit = ["streamlit >= 1.45.0, < 1.46"]
270
- zzz-test-sys = [
271
- "rich >= 14.0.0, < 14.1",
272
- "tomlkit >= 0.13.2, < 0.14",
273
- ]
274
- zzz-test-tempfile = []
275
- zzz-test-tenacity = [
276
- "tenacity >= 8.5.0, < 9.0", # limited by luigi
277
- ]
278
- zzz-test-text = []
279
- zzz-test-threading = []
280
- zzz-test-timer = []
281
- zzz-test-traceback = [
282
- "rich >= 14.0.0, < 14.1",
283
- "tomlkit >= 0.13.2, < 0.14",
284
- ]
285
- zzz-test-types = []
286
- zzz-test-typing = [
287
- "polars-lts-cpu >= 1.30.0, < 1.31",
288
- ]
289
- zzz-test-tzlocal = []
290
- zzz-test-uuid = []
291
- zzz-test-version = ["tomlkit >= 0.13.2, < 0.14"]
292
- zzz-test-warnings = []
293
- zzz-test-whenever = []
294
- zzz-test-zipfile = []
295
- zzz-test-zoneinfo = [
296
- "tzdata >= 2025.2, < 2025.3",
297
- ]
298
118
 
299
119
  [project.scripts]
300
120
 
301
121
  # bump-my-version
302
122
  [tool.bumpversion]
303
123
  allow_dirty = true
304
- current_version = "0.131.3"
124
+ current_version = "0.131.5"
305
125
 
306
126
  [[tool.bumpversion.files]]
307
127
  filename = "src/utilities/__init__.py"
@@ -183,14 +183,16 @@ class TestBoolArrays:
183
183
  assert array.shape == shape
184
184
 
185
185
 
186
- class TestDateDeltas:
187
- @given(data=data())
188
- def test_main(self, *, data: DataObject) -> None:
186
+ class TestDateDeltasWhenever:
187
+ @given(data=data(), parsable=booleans())
188
+ def test_main(self, *, data: DataObject, parsable: bool) -> None:
189
189
  min_value = data.draw(date_deltas_whenever() | none())
190
190
  max_value = data.draw(date_deltas_whenever() | none())
191
191
  with assume_does_not_raise(InvalidArgument):
192
192
  delta = data.draw(
193
- date_deltas_whenever(min_value=min_value, max_value=max_value)
193
+ date_deltas_whenever(
194
+ min_value=min_value, max_value=max_value, parsable=parsable
195
+ )
194
196
  )
195
197
  assert isinstance(delta, DateDelta)
196
198
  years, months, days = delta.in_years_months_days()
@@ -206,6 +208,8 @@ class TestDateDeltas:
206
208
  assert max_years == 0
207
209
  assert max_months == 0
208
210
  assert days <= max_days
211
+ if parsable:
212
+ assert DateDelta.parse_common_iso(delta.format_common_iso()) == delta
209
213
 
210
214
 
211
215
  class TestDateDurations:
@@ -295,6 +299,7 @@ class TestDatesWhenever:
295
299
  with assume_does_not_raise(InvalidArgument):
296
300
  date = data.draw(dates_whenever(min_value=min_value, max_value=max_value))
297
301
  assert isinstance(date, Date)
302
+ assert Date.parse_common_iso(date.format_common_iso()) == date
298
303
  if min_value is not None:
299
304
  assert date >= min_value
300
305
  if max_value is not None:
@@ -894,6 +899,7 @@ class TestPlainDateTimesWhenever:
894
899
  plain_datetimes_whenever(min_value=min_value, max_value=max_value)
895
900
  )
896
901
  assert isinstance(datetime, PlainDateTime)
902
+ assert PlainDateTime.parse_common_iso(datetime.format_common_iso()) == datetime
897
903
  if min_value is not None:
898
904
  assert datetime >= min_value
899
905
  if max_value is not None:
@@ -1273,6 +1279,7 @@ class TestZonedDateTimesWhenever:
1273
1279
  )
1274
1280
  )
1275
1281
  assert isinstance(datetime, ZonedDateTime)
1282
+ assert ZonedDateTime.parse_common_iso(datetime.format_common_iso()) == datetime
1276
1283
  assert datetime.tz == time_zone.key
1277
1284
  if min_value is not None:
1278
1285
  assert datetime >= min_value
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import datetime as dt
4
3
  from dataclasses import dataclass
5
4
  from enum import Enum, auto
6
5
  from functools import partial
@@ -23,16 +22,15 @@ from hypothesis.strategies import (
23
22
  recursive,
24
23
  sampled_from,
25
24
  times,
26
- timezones,
27
25
  tuples,
28
26
  uuids,
29
27
  )
30
28
  from polars import DataFrame, Int64
31
29
  from pytest import raises
30
+ from whenever import DateTimeDelta
32
31
 
33
32
  import utilities.math
34
33
  import utilities.operator
35
- from tests.conftest import IS_CI_AND_WINDOWS
36
34
  from tests.test_typing_funcs.with_future import (
37
35
  DataClassFutureCustomEquality,
38
36
  DataClassFutureDefaultInInitChild,
@@ -60,6 +58,7 @@ from utilities.hypothesis import (
60
58
  from utilities.math import MAX_INT64, MIN_INT64
61
59
  from utilities.operator import IsEqualError
62
60
  from utilities.polars import are_frames_equal
61
+ from utilities.whenever2 import get_now
63
62
 
64
63
  if TYPE_CHECKING:
65
64
  from collections.abc import Sequence
@@ -106,11 +105,12 @@ def base_objects(
106
105
  | timedeltas_2w()
107
106
  | uuids()
108
107
  | versions()
108
+ | zoned_datetimes(
109
+ min_value=get_now().py_datetime(),
110
+ max_value=(get_now() + DateTimeDelta(years=1)).py_datetime(),
111
+ valid=True,
112
+ )
109
113
  )
110
- if IS_CI_AND_WINDOWS:
111
- base |= zoned_datetimes()
112
- else:
113
- base |= zoned_datetimes(time_zone=timezones() | just(dt.UTC), valid=True)
114
114
  if dataclass_custom_equality:
115
115
  base |= builds(DataClassFutureCustomEquality)
116
116
  if dataclass_default_in_init_child:
@@ -348,8 +348,8 @@ class TestIsEqual:
348
348
  assert utilities.operator.is_equal(first, second, abs_tol=1e-8)
349
349
 
350
350
  @given(
351
- x=dates() | datetimes() | zoned_datetimes(time_zone=timezones()),
352
- y=dates() | datetimes() | zoned_datetimes(time_zone=timezones()),
351
+ x=dates() | datetimes() | zoned_datetimes(),
352
+ y=dates() | datetimes() | zoned_datetimes(),
353
353
  )
354
354
  def test_dates_or_datetimes(self, *, x: DateOrDateTime, y: DateOrDateTime) -> None:
355
355
  result = utilities.operator.is_equal(x, y)
@@ -36,6 +36,7 @@ from utilities.errors import ImpossibleCaseError
36
36
  from utilities.functions import ensure_path
37
37
  from utilities.hypothesis import (
38
38
  datetime_durations,
39
+ int64s,
39
40
  numbers,
40
41
  paths,
41
42
  plain_datetimes,
@@ -78,10 +79,10 @@ class TestSerializeAndParseObject:
78
79
  result = parse_object(dt.datetime, serialized)
79
80
  assert result == datetime
80
81
 
81
- @given(mapping=dictionaries(dates(), zoned_datetimes()))
82
- def test_dict(self, *, mapping: dict[dt.date, dt.datetime]) -> None:
82
+ @given(mapping=dictionaries(dates(), int64s()))
83
+ def test_dict(self, *, mapping: dict[dt.date, int]) -> None:
83
84
  serialized = serialize_object(mapping)
84
- result = parse_object(dict[dt.date, dt.datetime], serialized)
85
+ result = parse_object(dict[dt.date, int], serialized)
85
86
  assert result == mapping
86
87
 
87
88
  @given(duration=datetime_durations(two_way=True))
@@ -14,10 +14,14 @@ from utilities.tzdata import HongKong, Tokyo
14
14
  from utilities.whenever2 import (
15
15
  DATE_DELTA_MAX,
16
16
  DATE_DELTA_MIN,
17
+ DATE_DELTA_PARSABLE_MAX,
18
+ DATE_DELTA_PARSABLE_MIN,
17
19
  DATE_MAX,
18
20
  DATE_MIN,
19
21
  DATE_TIME_DELTA_MAX,
20
22
  DATE_TIME_DELTA_MIN,
23
+ DATE_TIME_DELTA_PARSABLE_MAX,
24
+ DATE_TIME_DELTA_PARSABLE_MIN,
21
25
  NOW_UTC,
22
26
  PLAIN_DATE_TIME_MAX,
23
27
  PLAIN_DATE_TIME_MIN,
@@ -95,6 +99,22 @@ class TestMinMax:
95
99
  with raises(ValueError, match="Addition result out of bounds"):
96
100
  _ = DATE_DELTA_MAX + DateDelta(days=1)
97
101
 
102
+ def test_date_delta_parsable_min(self) -> None:
103
+ def func(delta: DateDelta, /) -> None:
104
+ _ = DateDelta.parse_common_iso(delta.format_common_iso())
105
+
106
+ _ = func(DATE_DELTA_PARSABLE_MIN)
107
+ with raises(ValueError, match="Invalid format: '.*'"):
108
+ _ = func(DATE_DELTA_PARSABLE_MIN - DateDelta(days=1))
109
+
110
+ def test_date_delta_parsable_max(self) -> None:
111
+ def func(delta: DateDelta, /) -> None:
112
+ _ = DateDelta.parse_common_iso(delta.format_common_iso())
113
+
114
+ _ = func(DATE_DELTA_PARSABLE_MAX)
115
+ with raises(ValueError, match="Invalid format: '.*'"):
116
+ _ = func(DATE_DELTA_PARSABLE_MAX + DateDelta(days=1))
117
+
98
118
  @mark.parametrize(
99
119
  "delta",
100
120
  [
@@ -129,6 +149,22 @@ class TestMinMax:
129
149
  with raises(ValueError, match="Addition result out of bounds"):
130
150
  _ = DATE_TIME_DELTA_MAX + delta
131
151
 
152
+ def test_date_time_delta_parsable_min(self) -> None:
153
+ def func(delta: DateTimeDelta, /) -> None:
154
+ _ = DateDelta.parse_common_iso(delta.format_common_iso())
155
+
156
+ _ = func(DATE_TIME_DELTA_PARSABLE_MIN)
157
+ with raises(ValueError, match="Invalid format: '.*'"):
158
+ _ = func(DATE_TIME_DELTA_PARSABLE_MIN - DateTimeDelta(nanoseconds=1))
159
+
160
+ def test_date_time_delta_parsable_max(self) -> None:
161
+ def func(delta: DateTimeDelta, /) -> None:
162
+ _ = DateDelta.parse_common_iso(delta.format_common_iso())
163
+
164
+ _ = func(DATE_TIME_DELTA_PARSABLE_MAX)
165
+ with raises(ValueError, match="Invalid format: '.*'"):
166
+ _ = func(DATE_TIME_DELTA_PARSABLE_MAX + DateTimeDelta(nanoseconds=1))
167
+
132
168
  def test_plain_date_time_min(self) -> None:
133
169
  with raises(ValueError, match=r"Result of subtract\(\) out of range"):
134
170
  _ = PLAIN_DATE_TIME_MIN.subtract(nanoseconds=1, ignore_dst=True)
@@ -186,3 +222,9 @@ class TestWheneverLogRecord:
186
222
 
187
223
  def test_get_length(self) -> None:
188
224
  assert isinstance(WheneverLogRecord._get_length(), int)
225
+
226
+ def test_get_time_zone(self) -> None:
227
+ assert isinstance(WheneverLogRecord._get_time_zone(), ZoneInfo)
228
+
229
+ def test_get_time_zone_key(self) -> None:
230
+ assert isinstance(WheneverLogRecord._get_time_zone_key(), str)
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.131.3"
3
+ __version__ = "0.131.5"
@@ -47,7 +47,7 @@ from hypothesis.strategies import (
47
47
  uuids,
48
48
  )
49
49
  from hypothesis.utils.conventions import not_set
50
- from whenever import Date, DateDelta, PlainDateTime
50
+ from whenever import Date, DateDelta
51
51
 
52
52
  from utilities.datetime import (
53
53
  DATETIME_MAX_NAIVE,
@@ -97,7 +97,7 @@ if TYPE_CHECKING:
97
97
 
98
98
  from hypothesis.database import ExampleDatabase
99
99
  from numpy.random import RandomState
100
- from whenever import ZonedDateTime
100
+ from whenever import PlainDateTime, ZonedDateTime
101
101
 
102
102
  from utilities.numpy import NDArrayB, NDArrayF, NDArrayI, NDArrayO
103
103
  from utilities.types import Duration, Number, RoundMode, TimeZoneLike
@@ -167,9 +167,15 @@ def date_deltas_whenever(
167
167
  *,
168
168
  min_value: MaybeSearchStrategy[DateDelta | None] = None,
169
169
  max_value: MaybeSearchStrategy[DateDelta | None] = None,
170
+ parsable: MaybeSearchStrategy[bool] = False,
170
171
  ) -> DateDelta:
171
172
  """Strategy for generating date deltas."""
172
- from utilities.whenever2 import DATE_DELTA_MAX, DATE_DELTA_MIN
173
+ from utilities.whenever2 import (
174
+ DATE_DELTA_MAX,
175
+ DATE_DELTA_MIN,
176
+ DATE_DELTA_PARSABLE_MAX,
177
+ DATE_DELTA_PARSABLE_MIN,
178
+ )
173
179
 
174
180
  min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
175
181
  match min_value_:
@@ -192,6 +198,19 @@ def date_deltas_whenever(
192
198
  max_years, max_months, max_days = max_value_.in_years_months_days()
193
199
  assert max_years == 0
194
200
  assert max_months == 0
201
+ if draw2(draw, parsable):
202
+ parsable_min_years, parsable_min_months, parsable_min_days = (
203
+ DATE_DELTA_PARSABLE_MIN.in_years_months_days()
204
+ )
205
+ assert parsable_min_years == 0
206
+ assert parsable_min_months == 0
207
+ min_days = max(min_days, parsable_min_days)
208
+ parsable_max_years, parsable_max_months, parsable_max_days = (
209
+ DATE_DELTA_PARSABLE_MAX.in_years_months_days()
210
+ )
211
+ assert parsable_max_years == 0
212
+ assert parsable_max_months == 0
213
+ max_days = min(max_days, parsable_max_days)
195
214
  days = draw(integers(min_value=min_days, max_value=max_days))
196
215
  return DateDelta(days=days)
197
216
 
@@ -1050,6 +1069,8 @@ def plain_datetimes_whenever(
1050
1069
  max_value: MaybeSearchStrategy[PlainDateTime | None] = None,
1051
1070
  ) -> PlainDateTime:
1052
1071
  """Strategy for generating plain datetimes."""
1072
+ from whenever import PlainDateTime
1073
+
1053
1074
  from utilities.whenever2 import PLAIN_DATE_TIME_MAX, PLAIN_DATE_TIME_MIN
1054
1075
 
1055
1076
  min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
@@ -7,10 +7,11 @@ from typing import TYPE_CHECKING, Any, override
7
7
 
8
8
  from whenever import Date, DateTimeDelta, PlainDateTime, ZonedDateTime
9
9
 
10
- from utilities.tzlocal import LOCAL_TIME_ZONE
11
10
  from utilities.zoneinfo import UTC, get_time_zone_name
12
11
 
13
12
  if TYPE_CHECKING:
13
+ from zoneinfo import ZoneInfo
14
+
14
15
  from utilities.types import TimeZoneLike
15
16
 
16
17
 
@@ -27,6 +28,11 @@ DATE_DELTA_MAX = DATE_TIME_DELTA_MAX.date_part()
27
28
  TIME_DELTA_MIN = DATE_TIME_DELTA_MIN.time_part()
28
29
  TIME_DELTA_MAX = DATE_TIME_DELTA_MAX.time_part()
29
30
 
31
+ DATE_TIME_DELTA_PARSABLE_MIN = DateTimeDelta(days=-999999)
32
+ DATE_TIME_DELTA_PARSABLE_MAX = DateTimeDelta(days=999999)
33
+ DATE_DELTA_PARSABLE_MIN = DATE_TIME_DELTA_PARSABLE_MIN.date_part()
34
+ DATE_DELTA_PARSABLE_MAX = DATE_TIME_DELTA_PARSABLE_MAX.date_part()
35
+
30
36
 
31
37
  ##
32
38
 
@@ -88,7 +94,24 @@ class WheneverLogRecord(LogRecord):
88
94
  )
89
95
  length = self._get_length()
90
96
  plain = format(get_now_local().to_plain().format_common_iso(), f"{length}s")
91
- self.zoned_datetime = f"{plain}[{LOCAL_TIME_ZONE.key}]"
97
+ time_zone = self._get_time_zone_key()
98
+ self.zoned_datetime = f"{plain}[{time_zone}]"
99
+
100
+ @classmethod
101
+ @cache
102
+ def _get_time_zone(cls) -> ZoneInfo:
103
+ """Get the local timezone."""
104
+ try:
105
+ from utilities.tzlocal import get_local_time_zone
106
+ except ModuleNotFoundError: # pragma: no cover
107
+ return UTC
108
+ return get_local_time_zone()
109
+
110
+ @classmethod
111
+ @cache
112
+ def _get_time_zone_key(cls) -> str:
113
+ """Get the local timezone as a string."""
114
+ return cls._get_time_zone().key
92
115
 
93
116
  @classmethod
94
117
  @cache
@@ -101,10 +124,14 @@ class WheneverLogRecord(LogRecord):
101
124
  __all__ = [
102
125
  "DATE_DELTA_MAX",
103
126
  "DATE_DELTA_MIN",
127
+ "DATE_DELTA_PARSABLE_MAX",
128
+ "DATE_DELTA_PARSABLE_MIN",
104
129
  "DATE_MAX",
105
130
  "DATE_MIN",
106
131
  "DATE_TIME_DELTA_MAX",
107
132
  "DATE_TIME_DELTA_MIN",
133
+ "DATE_TIME_DELTA_PARSABLE_MAX",
134
+ "DATE_TIME_DELTA_PARSABLE_MIN",
108
135
  "PLAIN_DATE_TIME_MAX",
109
136
  "PLAIN_DATE_TIME_MIN",
110
137
  "TIME_DELTA_MAX",