dycw-utilities 0.131.0__tar.gz → 0.131.2__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.0 → dycw_utilities-0.131.2}/PKG-INFO +1 -1
  2. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/pyproject.toml +4 -2
  3. dycw_utilities-0.131.2/src/tests/conftest.py +425 -0
  4. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_hypothesis.py +80 -39
  5. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_sqlalchemy.py +283 -258
  6. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_sqlalchemy_polars.py +125 -98
  7. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_whenever.py +1 -20
  8. dycw_utilities-0.131.2/src/tests/test_whenever2.py +194 -0
  9. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/__init__.py +1 -1
  10. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/hypothesis.py +162 -51
  11. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/logging.py +1 -1
  12. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/sqlalchemy_polars.py +1 -17
  13. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/typing.py +1 -1
  14. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/whenever.py +1 -64
  15. dycw_utilities-0.131.2/src/utilities/whenever2.py +139 -0
  16. dycw_utilities-0.131.0/src/tests/conftest.py +0 -27
  17. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/.gitignore +0 -0
  18. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/LICENSE +0 -0
  19. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/README.md +0 -0
  20. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/__init__.py +0 -0
  21. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/__init__.py +0 -0
  22. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_missing/__init__.py +0 -0
  23. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_missing/module.py +0 -0
  24. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_with/__init__.py +0 -0
  25. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_with/outer_1.py +0 -0
  26. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_with/outer_2.py +0 -0
  27. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  28. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  29. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  30. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  31. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_without/__init__.py +0 -0
  32. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_without/module_1.py +0 -0
  33. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/package_without/module_2.py +0 -0
  34. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/standalone.py +0 -0
  35. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/modules/with_imports.py +0 -0
  36. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  37. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  38. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  39. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  40. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  41. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  42. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  43. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  44. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_aiolimiter.py +0 -0
  45. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_altair.py +0 -0
  46. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_asyncio.py +0 -0
  47. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_asyncio_classes/__init__.py +0 -0
  48. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_asyncio_classes/loopers.py +0 -0
  49. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_asyncio_classes/redis.py +0 -0
  50. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_atomicwrites.py +0 -0
  51. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_atools.py +0 -0
  52. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_cachetools.py +0 -0
  53. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_click.py +0 -0
  54. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_concurrent.py +0 -0
  55. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_contextlib.py +0 -0
  56. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_contextvars.py +0 -0
  57. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_cryptography.py +0 -0
  58. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_cvxpy.py +0 -0
  59. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_dataclasses.py +0 -0
  60. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_datetime.py +0 -0
  61. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_enum.py +0 -0
  62. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_errors.py +0 -0
  63. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_eventkit.py +0 -0
  64. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_fastapi.py +0 -0
  65. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_fpdf2.py +0 -0
  66. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_functions.py +0 -0
  67. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_functools.py +0 -0
  68. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_getpass.py +0 -0
  69. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_git.py +0 -0
  70. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_hashlib.py +0 -0
  71. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_http.py +0 -0
  72. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_importlib.py +0 -0
  73. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_inflect.py +0 -0
  74. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_ipython.py +0 -0
  75. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_iterables.py +0 -0
  76. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_jupyter.py +0 -0
  77. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_libcst.py +0 -0
  78. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_lightweight_charts.py +0 -0
  79. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_logging.py +0 -0
  80. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_luigi.py +0 -0
  81. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_math.py +0 -0
  82. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_memory_profiler.py +0 -0
  83. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_modules.py +0 -0
  84. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_more_itertools.py +0 -0
  85. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_numpy.py +0 -0
  86. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_operator.py +0 -0
  87. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_optuna.py +0 -0
  88. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_orjson.py +0 -0
  89. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_os.py +0 -0
  90. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_parse.py +0 -0
  91. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pathlib.py +0 -0
  92. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_period.py +0 -0
  93. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pickle.py +0 -0
  94. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_platform.py +0 -0
  95. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_polars.py +0 -0
  96. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_polars_ols.py +0 -0
  97. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pottery.py +0 -0
  98. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pqdm.py +0 -0
  99. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_psutil.py +0 -0
  100. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pydantic.py +0 -0
  101. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pyinstrument.py +0 -0
  102. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pyrsistent.py +0 -0
  103. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pytest.py +0 -0
  104. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_pytest_regressions.py +0 -0
  105. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_python_dotenv.py +0 -0
  106. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_random.py +0 -0
  107. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_re.py +0 -0
  108. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_redis.py +0 -0
  109. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_reprlib.py +0 -0
  110. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_scipy.py +0 -0
  111. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_sentinel.py +0 -0
  112. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_shelve.py +0 -0
  113. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_slack_sdk.py +0 -0
  114. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_socket.py +0 -0
  115. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_statsmodel.py +0 -0
  116. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_streamlit.py +0 -0
  117. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_string.py +0 -0
  118. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_tempfile.py +0 -0
  119. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_tenacity.py +0 -0
  120. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_text.py +0 -0
  121. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_threading.py +0 -0
  122. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_timer.py +0 -0
  123. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_traceback.py +0 -0
  124. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_types.py +0 -0
  125. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_typing.py +0 -0
  126. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_typing_funcs/__init__.py +0 -0
  127. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_typing_funcs/no_future.py +0 -0
  128. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_typing_funcs/with_future.py +0 -0
  129. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_tzdata.py +0 -0
  130. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_tzlocal.py +0 -0
  131. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_uuid.py +0 -0
  132. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_version.py +0 -0
  133. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_warnings.py +0 -0
  134. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_zipfile.py +0 -0
  135. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/tests/test_zoneinfo.py +0 -0
  136. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/aiolimiter.py +0 -0
  137. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/altair.py +0 -0
  138. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/asyncio.py +0 -0
  139. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/atomicwrites.py +0 -0
  140. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/atools.py +0 -0
  141. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/cachetools.py +0 -0
  142. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/click.py +0 -0
  143. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/concurrent.py +0 -0
  144. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/contextlib.py +0 -0
  145. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/contextvars.py +0 -0
  146. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/cryptography.py +0 -0
  147. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/cvxpy.py +0 -0
  148. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/dataclasses.py +0 -0
  149. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/datetime.py +0 -0
  150. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/enum.py +0 -0
  151. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/errors.py +0 -0
  152. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/eventkit.py +0 -0
  153. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/fastapi.py +0 -0
  154. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/fpdf2.py +0 -0
  155. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/functions.py +0 -0
  156. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/functools.py +0 -0
  157. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/getpass.py +0 -0
  158. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/git.py +0 -0
  159. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/hashlib.py +0 -0
  160. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/http.py +0 -0
  161. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/importlib.py +0 -0
  162. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/inflect.py +0 -0
  163. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/ipython.py +0 -0
  164. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/iterables.py +0 -0
  165. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/jupyter.py +0 -0
  166. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/libcst.py +0 -0
  167. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/lightweight_charts.py +0 -0
  168. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/luigi.py +0 -0
  169. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/math.py +0 -0
  170. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/memory_profiler.py +0 -0
  171. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/modules.py +0 -0
  172. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/more_itertools.py +0 -0
  173. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/numpy.py +0 -0
  174. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/operator.py +0 -0
  175. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/optuna.py +0 -0
  176. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/orjson.py +0 -0
  177. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/os.py +0 -0
  178. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/parse.py +0 -0
  179. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pathlib.py +0 -0
  180. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/period.py +0 -0
  181. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pickle.py +0 -0
  182. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/platform.py +0 -0
  183. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/polars.py +0 -0
  184. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/polars_ols.py +0 -0
  185. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pottery.py +0 -0
  186. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pqdm.py +0 -0
  187. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/psutil.py +0 -0
  188. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/py.typed +0 -0
  189. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pydantic.py +0 -0
  190. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pyinstrument.py +0 -0
  191. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pyrsistent.py +0 -0
  192. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pytest.py +0 -0
  193. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/pytest_regressions.py +0 -0
  194. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/python_dotenv.py +0 -0
  195. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/random.py +0 -0
  196. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/re.py +0 -0
  197. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/redis.py +0 -0
  198. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/reprlib.py +0 -0
  199. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/scipy.py +0 -0
  200. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/sentinel.py +0 -0
  201. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/shelve.py +0 -0
  202. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/slack_sdk.py +0 -0
  203. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/socket.py +0 -0
  204. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/sqlalchemy.py +0 -0
  205. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/statsmodels.py +0 -0
  206. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/streamlit.py +0 -0
  207. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/string.py +0 -0
  208. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/tempfile.py +0 -0
  209. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/tenacity.py +0 -0
  210. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/text.py +0 -0
  211. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/threading.py +0 -0
  212. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/timer.py +0 -0
  213. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/traceback.py +0 -0
  214. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/types.py +0 -0
  215. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/tzdata.py +0 -0
  216. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/tzlocal.py +0 -0
  217. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/uuid.py +0 -0
  218. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/version.py +0 -0
  219. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/warnings.py +0 -0
  220. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/src/utilities/zipfile.py +0 -0
  221. {dycw_utilities-0.131.0 → dycw_utilities-0.131.2}/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.0
3
+ Version: 0.131.2
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.0"
97
+ version = "0.131.2"
98
98
 
99
99
  [project.optional-dependencies]
100
100
  logging = [
@@ -341,7 +341,7 @@ zzz-test-zoneinfo = [
341
341
  # bump-my-version
342
342
  [tool.bumpversion]
343
343
  allow_dirty = true
344
- current_version = "0.131.0"
344
+ current_version = "0.131.2"
345
345
 
346
346
  [[tool.bumpversion.files]]
347
347
  filename = "src/utilities/__init__.py"
@@ -354,6 +354,7 @@ search = "__version__ = \"{current_version}\""
354
354
  [tool.coverage.coverage_conditional_plugin.rules]
355
355
  skipif-ci = '"CI" in os_environ'
356
356
  skipif-ci-and-not-linux = '("CI" in os_environ) and (sys_platform != "linux")'
357
+ skipif-ci-and-not-windows = '("CI" in os_environ) and (sys_platform != "windows")'
357
358
  skipif-ci-and-windows = '("CI" in os_environ) and (sys_platform != "windows")'
358
359
  skipif-linux = 'sys_platform == "linux"'
359
360
  skipif-mac = 'sys_platform == "darwin"'
@@ -460,6 +461,7 @@ filterwarnings = [
460
461
  "ignore:unclosed <StreamWriter .*>:ResourceWarning", # redis
461
462
  "ignore:unclosed <socket.*socket .*>:ResourceWarning", # redis
462
463
  "ignore:unclosed Connection <redis.*asyncio.*connection.*Connection.*>:ResourceWarning", # redis
464
+ "ignore:unclosed connection <asyncpg.*connection.*Connection.*>:ResourceWarning", # asyncpg
463
465
  "ignore:unclosed event loop <_UnixSelectorEventLoop .*>:ResourceWarning", # redis
464
466
  "ignore:unclosed file <_io.*TextIOWrapper .*>:ResourceWarning", # logging
465
467
  "ignore:unclosed transport <_SelectorSocketTransport .*>:ResourceWarning", # redis
@@ -0,0 +1,425 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from asyncio import sleep
5
+ from contextlib import suppress
6
+ from os import environ
7
+ from re import MULTILINE, Pattern
8
+ from typing import TYPE_CHECKING, Any
9
+
10
+ from pytest import fixture, mark, param
11
+ from sqlalchemy import text
12
+
13
+ from utilities.datetime import MINUTE, get_now, parse_datetime_compact
14
+ from utilities.platform import IS_NOT_LINUX, IS_WINDOWS
15
+ from utilities.re import ExtractGroupError, extract_group
16
+ from utilities.text import strip_and_dedent
17
+
18
+ if TYPE_CHECKING:
19
+ from collections.abc import Sequence
20
+ from pathlib import Path
21
+
22
+ from _pytest.fixtures import SubRequest
23
+
24
+
25
+ FLAKY = mark.flaky(reruns=5, reruns_delay=1)
26
+ IS_CI = "CI" in environ
27
+ SKIPIF_CI = mark.skipif(IS_CI, reason="Skipped for CI")
28
+ IS_CI_AND_WINDOWS = IS_CI and IS_WINDOWS
29
+ SKIPIF_CI_AND_WINDOWS = mark.skipif(IS_CI_AND_WINDOWS, reason="Skipped for CI/Windows")
30
+ SKIPIF_CI_AND_NOT_LINUX = mark.skipif(
31
+ IS_CI and IS_NOT_LINUX, reason="Skipped for CI/non-Linux"
32
+ )
33
+
34
+
35
+ # hypothesis
36
+
37
+
38
+ try:
39
+ from utilities.hypothesis import setup_hypothesis_profiles
40
+ except ModuleNotFoundError:
41
+ pass
42
+ else:
43
+ setup_hypothesis_profiles()
44
+
45
+
46
+ # fixtures - sqlalchemy
47
+
48
+
49
+ @fixture(params=[param("sqlite"), param("postgresql", marks=SKIPIF_CI)])
50
+ async def test_engine(*, request: SubRequest, tmp_path: Path) -> Any:
51
+ from utilities.sqlalchemy import create_async_engine
52
+
53
+ dialect = request.param
54
+ match dialect:
55
+ case "sqlite":
56
+ db_path = tmp_path / "db.sqlite"
57
+ return create_async_engine("sqlite+aiosqlite", database=str(db_path))
58
+ case "postgresql":
59
+ engine = create_async_engine(
60
+ "postgresql+asyncpg", host="localhost", port=5432, database="testing"
61
+ )
62
+ query = text("SELECT tablename FROM pg_tables")
63
+ async with engine.begin() as conn:
64
+ tables: Sequence[str] = (await conn.execute(query)).scalars().all()
65
+ for table in tables:
66
+ if _is_to_drop(table):
67
+ async with engine.begin() as conn:
68
+ with suppress(Exception):
69
+ _ = await conn.execute(
70
+ text(f'DROP TABLE IF EXISTS "{table}" CASCADE')
71
+ )
72
+ await sleep(0.01)
73
+ return engine
74
+ case _:
75
+ msg = f"Unsupported dialect: {dialect}"
76
+ raise NotImplementedError(msg)
77
+
78
+
79
+ def _is_to_drop(table: str, /) -> bool:
80
+ try:
81
+ datetime_str = extract_group(r"^(\d{8}T\d{6})_", table)
82
+ except ExtractGroupError:
83
+ return True
84
+ datetime = parse_datetime_compact(datetime_str)
85
+ now = get_now()
86
+ return (now - datetime) >= MINUTE
87
+
88
+
89
+ # fixtures - traceback
90
+
91
+
92
+ @fixture
93
+ def traceback_func_chain() -> Pattern[str]:
94
+ return re.compile(
95
+ strip_and_dedent(
96
+ r"""
97
+ Date/time \| .+
98
+ Started \| .+
99
+ Duration \| .+
100
+ User \| .+
101
+ Host \| .+
102
+ Version \|\s
103
+
104
+ Exception chain 1/2:
105
+ Frame 1/1: func_chain_first \(tests\.test_traceback_funcs\.chain\)
106
+ Inputs:
107
+ args\[0\] = 1
108
+ args\[1\] = 2
109
+ args\[2\] = 3
110
+ args\[3\] = 4
111
+ kwargs\[c\] = 5
112
+ kwargs\[d\] = 6
113
+ kwargs\[e\] = 7
114
+ Locals:
115
+ a = 2
116
+ b = 4
117
+ c = 10
118
+ args = \(6, 8\)
119
+ kwargs = {'d': 12, 'e': 14}
120
+ msg = 'Assertion failed: Result \(112\) must be divisible by 10'
121
+ Line 19:
122
+ raise ValueError\(msg\) from error
123
+ Raised:
124
+ builtins\.ValueError\(Assertion failed: Result \(112\) must be divisible by 10\)
125
+
126
+ Exception chain 2/2:
127
+ Frame 1/1: func_chain_second \(tests\.test_traceback_funcs\.chain\)
128
+ Inputs:
129
+ args\[0\] = 2
130
+ args\[1\] = 4
131
+ args\[2\] = 6
132
+ args\[3\] = 8
133
+ kwargs\[c\] = 10
134
+ kwargs\[d\] = 12
135
+ kwargs\[e\] = 14
136
+ Locals:
137
+ a = 4
138
+ b = 8
139
+ c = 20
140
+ args = \(12, 16\)
141
+ kwargs = {'d': 24, 'e': 28}
142
+ result = 112
143
+ Line 30:
144
+ assert result % 10 == 0, f"Result \({result}\) must be divisible by 10"
145
+ Raised:
146
+ builtins\.AssertionError\(Result \(112\) must be divisible by 10\)
147
+ """
148
+ ),
149
+ flags=MULTILINE,
150
+ )
151
+
152
+
153
+ @fixture
154
+ def traceback_func_one() -> Pattern[str]:
155
+ return re.compile(
156
+ strip_and_dedent(
157
+ r"""
158
+ Date/time \| .+
159
+ Started \| .+
160
+ Duration \| .+
161
+ User \| .+
162
+ Host \| .+
163
+ Version \|\s
164
+
165
+ Frame 1/1: func_one \(tests\.test_traceback_funcs\.one\)
166
+ Inputs:
167
+ args\[0\] = 1
168
+ args\[1\] = 2
169
+ args\[2\] = 3
170
+ args\[3\] = 4
171
+ kwargs\[c\] = 5
172
+ kwargs\[d\] = 6
173
+ kwargs\[e\] = 7
174
+ Locals:
175
+ a = 2
176
+ b = 4
177
+ c = 10
178
+ args = \(6, 8\)
179
+ kwargs = {'d': 12, 'e': 14}
180
+ result = 56
181
+ Line 16:
182
+ assert result % 10 == 0, f"Result \({result}\) must be divisible by 10"
183
+ Raised:
184
+ builtins\.AssertionError\(Result \(56\) must be divisible by 10\)
185
+ """
186
+ ),
187
+ flags=MULTILINE,
188
+ )
189
+
190
+
191
+ @fixture
192
+ def traceback_func_many_long() -> Pattern[str]:
193
+ return re.compile(
194
+ strip_and_dedent(
195
+ r"""
196
+ Date/time \| .+
197
+ Started \| .+
198
+ Duration \| .+
199
+ User \| .+
200
+ Host \| .+
201
+ Version \|\s
202
+
203
+ Frame 1/1: func_many \(tests.test_traceback_funcs.many\)
204
+ Inputs:
205
+ args\[0\] = 1
206
+ args\[1\] = 2
207
+ args\[2\] = 3
208
+ args\[3\] = 4
209
+ kwargs\[c\] = 5
210
+ kwargs\[d\] = 6
211
+ kwargs\[e\] = 7
212
+ Locals:
213
+ a = 2
214
+ b = 4
215
+ c = 10
216
+ args = \(
217
+ 6,
218
+ 8,
219
+ 0,
220
+ 2,
221
+ 4,
222
+ 6,
223
+ 8,
224
+ 10,
225
+ 12,
226
+ 14,
227
+ 16,
228
+ 18,
229
+ 20,
230
+ 22,
231
+ 24,
232
+ 26,
233
+ 28,
234
+ 30,
235
+ 32,
236
+ 34,
237
+ ... \+82
238
+ \)
239
+ kwargs = {'d': 12, 'e': 14}
240
+ result = 9956
241
+ Line 16:
242
+ assert result % 10 == 0, f"Result \({result}\) must be divisible by 10"
243
+ Raised:
244
+ builtins\.AssertionError\(Result \(9956\) must be divisible by 10\)
245
+ """
246
+ ),
247
+ flags=MULTILINE,
248
+ )
249
+
250
+
251
+ @fixture
252
+ def traceback_func_many_short() -> Pattern[str]:
253
+ return re.compile(
254
+ strip_and_dedent(
255
+ r"""
256
+ Date/time \| .+
257
+ Started \| .+
258
+ Duration \| .+
259
+ User \| .+
260
+ Host \| .+
261
+ Version \|\s
262
+
263
+ Frame 1/1: func_many \(tests.test_traceback_funcs.many\)
264
+ Inputs:
265
+ args\[0\] = 1
266
+ args\[1\] = 2
267
+ args\[2\] = 3
268
+ args\[3\] = 4
269
+ kwargs\[c\] = 5
270
+ kwargs\[d\] = 6
271
+ kwargs\[e\] = 7
272
+ Locals:
273
+ a = 2
274
+ b = 4
275
+ c = 10
276
+ args = \(6, 8, 0, 2, 4, ... \+97\)
277
+ kwargs = {'d': 12, 'e': 14}
278
+ result = 9956
279
+ Line 16:
280
+ assert result % 10 == 0, f"Result \({result}\) must be divisible by 10"
281
+ Raised:
282
+ builtins\.AssertionError\(Result \(9956\) must be divisible by 10\)
283
+ """
284
+ ),
285
+ flags=MULTILINE,
286
+ )
287
+
288
+
289
+ @fixture
290
+ def traceback_func_task_group_one() -> Pattern[str]:
291
+ return re.compile(
292
+ strip_and_dedent(
293
+ r"""
294
+ Date/time \| .+
295
+ Started \| .+
296
+ Duration \| .+
297
+ User \| .+
298
+ Host \| .+
299
+ Version \|\s
300
+
301
+ Exception group:
302
+ Frame 1/1: func_task_group_one_first \(tests\.test_traceback_funcs\.task_group_one\)
303
+ Inputs:
304
+ args\[0\] = 1
305
+ args\[1\] = 2
306
+ args\[2\] = 3
307
+ args\[3\] = 4
308
+ kwargs\[c\] = 5
309
+ kwargs\[d\] = 6
310
+ kwargs\[e\] = 7
311
+ Locals:
312
+ a = 2
313
+ b = 4
314
+ c = 10
315
+ args = \(6, 8\)
316
+ kwargs = {'d': 12, 'e': 14}
317
+ tg = <TaskGroup cancelling>
318
+ _ = <Task finished name='Task-\d+' coro=<func_task_group_one_second\(\) done, defined at .+src.+utilities.+traceback\.py:\d+> exception=AssertionError\('Result \(112\) must be divisible by 10'\)>
319
+ Line 18:
320
+ async with TaskGroup\(\) as tg:
321
+ Raised:
322
+ builtins\.ExceptionGroup\(unhandled errors in a TaskGroup \(1 sub-exception\)\)
323
+
324
+ Exception group error 1/1:
325
+ Frame 1/1: func_task_group_one_second \(tests\.test_traceback_funcs\.task_group_one\)
326
+ Inputs:
327
+ args\[0\] = 2
328
+ args\[1\] = 4
329
+ args\[2\] = 6
330
+ args\[3\] = 8
331
+ kwargs\[c\] = 10
332
+ kwargs\[d\] = 12
333
+ kwargs\[e\] = 14
334
+ Locals:
335
+ a = 4
336
+ b = 8
337
+ c = 20
338
+ args = \(12, 16\)
339
+ kwargs = {'d': 24, 'e': 28}
340
+ result = 112
341
+ Line 33:
342
+ assert result % 10 == 0, f"Result \({result}\) must be divisible by 10"
343
+ Raised:
344
+ builtins\.AssertionError\(Result \(112\) must be divisible by 10\)
345
+ """
346
+ )
347
+ )
348
+
349
+
350
+ @fixture
351
+ def traceback_func_two() -> Pattern[str]:
352
+ return re.compile(
353
+ strip_and_dedent(
354
+ r"""
355
+ Date/time \| .+
356
+ Started \| .+
357
+ Duration \| .+
358
+ User \| .+
359
+ Host \| .+
360
+ Version \|\s
361
+
362
+ Frame 1/2: func_two_first \(tests\.test_traceback_funcs\.two\)
363
+ Inputs:
364
+ args\[0\] = 1
365
+ args\[1\] = 2
366
+ args\[2\] = 3
367
+ args\[3\] = 4
368
+ kwargs\[c\] = 5
369
+ kwargs\[d\] = 6
370
+ kwargs\[e\] = 7
371
+ Locals:
372
+ a = 2
373
+ b = 4
374
+ c = 10
375
+ args = \(6, 8\)
376
+ kwargs = {'d': 12, 'e': 14}
377
+ Line 15:
378
+ return func_two_second\(a, b, \*args, c=c, \*\*kwargs\)
379
+
380
+ Frame 2/2: func_two_second \(tests\.test_traceback_funcs\.two\)
381
+ Inputs:
382
+ args\[0\] = 2
383
+ args\[1\] = 4
384
+ args\[2\] = 6
385
+ args\[3\] = 8
386
+ kwargs\[c\] = 10
387
+ kwargs\[d\] = 12
388
+ kwargs\[e\] = 14
389
+ Locals:
390
+ a = 4
391
+ b = 8
392
+ c = 20
393
+ args = \(12, 16\)
394
+ kwargs = {'d': 24, 'e': 28}
395
+ result = 112
396
+ Line 26:
397
+ assert result % 10 == 0, f"Result \({result}\) must be divisible by 10"
398
+ Raised:
399
+ builtins\.AssertionError\(Result \(112\) must be divisible by 10\)
400
+ """
401
+ ),
402
+ flags=MULTILINE,
403
+ )
404
+
405
+
406
+ @fixture
407
+ def traceback_func_untraced() -> Pattern[str]:
408
+ return re.compile(
409
+ strip_and_dedent(
410
+ r"""
411
+ Traceback \(most recent call last\):
412
+
413
+ File ".+src.+tests.+test_(logging|sys|traceback)\.py", line \d+, in test_.+
414
+ _ = func_untraced\(1, 2, 3, 4, c=5, d=6, e=7\)
415
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
416
+
417
+ File ".+src.+tests.+test_traceback_funcs.+untraced\.py", line 13, in func_untraced
418
+ assert result % 10 == 0, f"Result \({result}\) must be divisible by 10"
419
+ ^^^^^^^^^^^^^^^^
420
+
421
+ AssertionError: Result \(56\) must be divisible by 10
422
+ """
423
+ ).replace("^", r"\^"),
424
+ flags=MULTILINE,
425
+ )
@@ -23,14 +23,12 @@ from hypothesis.strategies import (
23
23
  sets,
24
24
  timedeltas,
25
25
  timezones,
26
- uuids,
27
26
  )
28
27
  from luigi import Task
29
28
  from numpy import inf, int64, isfinite, isinf, isnan, ravel, rint
30
29
  from pathvalidate import validate_filepath
31
30
  from pytest import mark, raises
32
- from sqlalchemy import Column, Integer, MetaData, Table, insert, select
33
- from sqlalchemy.ext.asyncio import AsyncEngine
31
+ from whenever import Date, DateDelta, PlainDateTime, ZonedDateTime
34
32
 
35
33
  from tests.conftest import SKIPIF_CI_AND_WINDOWS
36
34
  from utilities.datetime import (
@@ -45,7 +43,6 @@ from utilities.datetime import (
45
43
  )
46
44
  from utilities.functions import ensure_int
47
45
  from utilities.hypothesis import (
48
- _SQLALCHEMY_ENGINE_DIALECTS,
49
46
  MaybeSearchStrategy,
50
47
  PlainDateTimesError,
51
48
  Shape,
@@ -54,8 +51,10 @@ from utilities.hypothesis import (
54
51
  _Draw2InputResolvedToSentinelError,
55
52
  assume_does_not_raise,
56
53
  bool_arrays,
54
+ date_deltas_whenever,
57
55
  date_durations,
58
56
  dates_two_digit_year,
57
+ dates_whenever,
59
58
  datetime_durations,
60
59
  draw2,
61
60
  float32s,
@@ -77,13 +76,13 @@ from utilities.hypothesis import (
77
76
  pairs,
78
77
  paths,
79
78
  plain_datetimes,
79
+ plain_datetimes_whenever,
80
80
  random_states,
81
81
  sentinels,
82
82
  sets_fixed_length,
83
83
  settings_with_reduced_examples,
84
84
  setup_hypothesis_profiles,
85
85
  slices,
86
- sqlalchemy_engines,
87
86
  str_arrays,
88
87
  temp_dirs,
89
88
  temp_paths,
@@ -99,6 +98,7 @@ from utilities.hypothesis import (
99
98
  uint64s,
100
99
  versions,
101
100
  zoned_datetimes,
101
+ zoned_datetimes_whenever,
102
102
  )
103
103
  from utilities.math import (
104
104
  MAX_FLOAT32,
@@ -119,7 +119,6 @@ from utilities.math import (
119
119
  from utilities.os import temp_environ
120
120
  from utilities.platform import maybe_yield_lower_case
121
121
  from utilities.sentinel import Sentinel
122
- from utilities.sqlalchemy import Dialect, _get_dialect
123
122
  from utilities.version import Version
124
123
  from utilities.whenever import (
125
124
  MAX_SERIALIZABLE_TIMEDELTA,
@@ -134,7 +133,6 @@ from utilities.whenever import (
134
133
  if TYPE_CHECKING:
135
134
  from collections.abc import Iterable
136
135
  from collections.abc import Set as AbstractSet
137
- from uuid import UUID
138
136
  from zoneinfo import ZoneInfo
139
137
 
140
138
  from utilities.datetime import Month
@@ -185,6 +183,31 @@ class TestBoolArrays:
185
183
  assert array.shape == shape
186
184
 
187
185
 
186
+ class TestDateDeltas:
187
+ @given(data=data())
188
+ def test_main(self, *, data: DataObject) -> None:
189
+ min_value = data.draw(date_deltas_whenever() | none())
190
+ max_value = data.draw(date_deltas_whenever() | none())
191
+ with assume_does_not_raise(InvalidArgument):
192
+ delta = data.draw(
193
+ date_deltas_whenever(min_value=min_value, max_value=max_value)
194
+ )
195
+ assert isinstance(delta, DateDelta)
196
+ years, months, days = delta.in_years_months_days()
197
+ assert years == 0
198
+ assert months == 0
199
+ if min_value is not None:
200
+ min_years, min_months, min_days = min_value.in_years_months_days()
201
+ assert min_years == 0
202
+ assert min_months == 0
203
+ assert days >= min_days
204
+ if max_value is not None:
205
+ max_years, max_months, max_days = max_value.in_years_months_days()
206
+ assert max_years == 0
207
+ assert max_months == 0
208
+ assert days <= max_days
209
+
210
+
188
211
  class TestDateDurations:
189
212
  @given(
190
213
  data=data(),
@@ -264,6 +287,20 @@ class TestDatesTwoDigitYear:
264
287
  assert date.year == parsed
265
288
 
266
289
 
290
+ class TestDatesWhenever:
291
+ @given(data=data())
292
+ def test_main(self, *, data: DataObject) -> None:
293
+ min_value = data.draw(dates_whenever() | none())
294
+ max_value = data.draw(dates_whenever() | none())
295
+ with assume_does_not_raise(InvalidArgument):
296
+ date = data.draw(dates_whenever(min_value=min_value, max_value=max_value))
297
+ assert isinstance(date, Date)
298
+ if min_value is not None:
299
+ assert date >= min_value
300
+ if max_value is not None:
301
+ assert date <= max_value
302
+
303
+
267
304
  class TestDateTimeDurations:
268
305
  @given(
269
306
  data=data(),
@@ -847,6 +884,22 @@ class TestPlainDateTimes:
847
884
  _ = data.draw(plain_datetimes(round_="standard"))
848
885
 
849
886
 
887
+ class TestPlainDateTimesWhenever:
888
+ @given(data=data())
889
+ def test_main(self, *, data: DataObject) -> None:
890
+ min_value = data.draw(plain_datetimes_whenever() | none())
891
+ max_value = data.draw(plain_datetimes_whenever() | none())
892
+ with assume_does_not_raise(InvalidArgument):
893
+ datetime = data.draw(
894
+ plain_datetimes_whenever(min_value=min_value, max_value=max_value)
895
+ )
896
+ assert isinstance(datetime, PlainDateTime)
897
+ if min_value is not None:
898
+ assert datetime >= min_value
899
+ if max_value is not None:
900
+ assert datetime <= max_value
901
+
902
+
850
903
  class TestRandomStates:
851
904
  @given(data=data())
852
905
  def test_main(self, *, data: DataObject) -> None:
@@ -917,38 +970,6 @@ class TestSlices:
917
970
  _ = data.draw(slices(iter_len, slice_len=iter_len + 1))
918
971
 
919
972
 
920
- class TestSQLAlchemyEngines:
921
- @given(
922
- data=data(),
923
- name=uuids(),
924
- dialect=_SQLALCHEMY_ENGINE_DIALECTS,
925
- ids=sets(integers(0, 10), min_size=1),
926
- )
927
- @settings(phases={Phase.generate})
928
- async def test_main(
929
- self, *, data: DataObject, name: UUID, dialect: Dialect, ids: set[int]
930
- ) -> None:
931
- table = Table(
932
- f"test_{name}", MetaData(), Column("id_", Integer, primary_key=True)
933
- )
934
- engine = await sqlalchemy_engines(data, table, dialect=dialect)
935
- assert isinstance(engine, AsyncEngine)
936
- assert _get_dialect(engine) == dialect
937
- if dialect == "sqlite":
938
- database = engine.url.database
939
- assert database is not None
940
- assert not Path(database).exists()
941
- async with engine.begin() as conn:
942
- await conn.run_sync(table.metadata.create_all)
943
- ins = insert(table).values([(id_,) for id_ in ids])
944
- async with engine.begin() as conn:
945
- _ = await conn.execute(ins)
946
- sel = select(table.c["id_"])
947
- async with engine.begin() as conn:
948
- results = (await conn.execute(sel)).scalars().all()
949
- assert set(results) == ids
950
-
951
-
952
973
  class TestStrArrays:
953
974
  @given(
954
975
  data=data(),
@@ -1237,3 +1258,23 @@ class TestZonedDateTimes:
1237
1258
  ZonedDateTimesError, match="Rounding requires a timedelta; got None"
1238
1259
  ):
1239
1260
  _ = data.draw(zoned_datetimes(round_="standard"))
1261
+
1262
+
1263
+ class TestZonedDateTimesWhenever:
1264
+ @given(data=data(), time_zone=timezones())
1265
+ @settings(suppress_health_check={HealthCheck.filter_too_much})
1266
+ def test_main(self, *, data: DataObject, time_zone: ZoneInfo) -> None:
1267
+ min_value = data.draw(zoned_datetimes_whenever() | none())
1268
+ max_value = data.draw(zoned_datetimes_whenever() | none())
1269
+ with assume_does_not_raise(InvalidArgument):
1270
+ datetime = data.draw(
1271
+ zoned_datetimes_whenever(
1272
+ min_value=min_value, max_value=max_value, time_zone=time_zone
1273
+ )
1274
+ )
1275
+ assert isinstance(datetime, ZonedDateTime)
1276
+ assert datetime.tz == time_zone.key
1277
+ if min_value is not None:
1278
+ assert datetime >= min_value
1279
+ if max_value is not None:
1280
+ assert datetime <= max_value