dycw-utilities 0.137.0__tar.gz → 0.138.0__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 (216) hide show
  1. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/PKG-INFO +1 -1
  2. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/pyproject.toml +2 -2
  3. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_click.py +15 -6
  4. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_hypothesis.py +38 -19
  5. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_objects/objects.py +4 -0
  6. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_parse.py +29 -7
  7. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_typed_settings.py +74 -29
  8. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_whenever.py +7 -133
  9. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/__init__.py +1 -1
  10. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/click.py +47 -12
  11. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/hypothesis.py +56 -30
  12. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/orjson.py +17 -1
  13. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/parse.py +6 -3
  14. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/typed_settings.py +5 -0
  15. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/types.py +6 -0
  16. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/whenever.py +4 -142
  17. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/.gitignore +0 -0
  18. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/LICENSE +0 -0
  19. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/README.md +0 -0
  20. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/__init__.py +0 -0
  21. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/conftest.py +0 -0
  22. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/__init__.py +0 -0
  23. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_missing/__init__.py +0 -0
  24. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_missing/module.py +0 -0
  25. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_with/__init__.py +0 -0
  26. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_with/outer_1.py +0 -0
  27. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_with/outer_2.py +0 -0
  28. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  29. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  30. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  31. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  32. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_without/__init__.py +0 -0
  33. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_without/module_1.py +0 -0
  34. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/package_without/module_2.py +0 -0
  35. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/standalone.py +0 -0
  36. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/modules/with_imports.py +0 -0
  37. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  38. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  39. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  40. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  41. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  42. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  43. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  44. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  45. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_aiolimiter.py +0 -0
  46. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_altair.py +0 -0
  47. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_asyncio.py +0 -0
  48. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_asyncio_classes/__init__.py +0 -0
  49. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_asyncio_classes/loopers.py +0 -0
  50. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_asyncio_classes/redis.py +0 -0
  51. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_atomicwrites.py +0 -0
  52. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_atools.py +0 -0
  53. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_cachetools.py +0 -0
  54. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_concurrent.py +0 -0
  55. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_contextlib.py +0 -0
  56. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_contextvars.py +0 -0
  57. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_cryptography.py +0 -0
  58. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_cvxpy.py +0 -0
  59. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_dataclasses.py +0 -0
  60. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_enum.py +0 -0
  61. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_errors.py +0 -0
  62. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_eventkit.py +0 -0
  63. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_fastapi.py +0 -0
  64. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_fpdf2.py +0 -0
  65. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_functions.py +0 -0
  66. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_functools.py +0 -0
  67. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_getpass.py +0 -0
  68. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_git.py +0 -0
  69. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_hashlib.py +0 -0
  70. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_http.py +0 -0
  71. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_importlib.py +0 -0
  72. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_inflect.py +0 -0
  73. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_ipython.py +0 -0
  74. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_iterables.py +0 -0
  75. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_jupyter.py +0 -0
  76. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_libcst.py +0 -0
  77. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_lightweight_charts.py +0 -0
  78. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_logging.py +0 -0
  79. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_luigi.py +0 -0
  80. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_math.py +0 -0
  81. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_memory_profiler.py +0 -0
  82. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_modules.py +0 -0
  83. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_more_itertools.py +0 -0
  84. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_numpy.py +0 -0
  85. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_objects/__init__.py +0 -0
  86. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_operator.py +0 -0
  87. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_optuna.py +0 -0
  88. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_orjson.py +0 -0
  89. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_os.py +0 -0
  90. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_pathlib.py +0 -0
  91. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_period.py +0 -0
  92. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_pickle.py +0 -0
  93. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_platform.py +0 -0
  94. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_polars.py +0 -0
  95. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_polars_ols.py +0 -0
  96. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_pottery.py +0 -0
  97. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_pqdm.py +0 -0
  98. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_psutil.py +0 -0
  99. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_pydantic.py +0 -0
  100. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_pyinstrument.py +0 -0
  101. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_pytest.py +0 -0
  102. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_pytest_regressions.py +0 -0
  103. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_python_dotenv.py +0 -0
  104. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_random.py +0 -0
  105. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_re.py +0 -0
  106. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_redis.py +0 -0
  107. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_reprlib.py +0 -0
  108. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_scipy.py +0 -0
  109. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_sentinel.py +0 -0
  110. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_shelve.py +0 -0
  111. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_slack_sdk.py +0 -0
  112. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_socket.py +0 -0
  113. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_sqlalchemy.py +0 -0
  114. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_sqlalchemy_polars.py +0 -0
  115. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_statsmodels.py +0 -0
  116. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_streamlit.py +0 -0
  117. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_string.py +0 -0
  118. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_tempfile.py +0 -0
  119. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_text.py +0 -0
  120. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_threading.py +0 -0
  121. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_timer.py +0 -0
  122. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_traceback.py +0 -0
  123. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_types.py +0 -0
  124. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_typing.py +0 -0
  125. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_typing_funcs/__init__.py +0 -0
  126. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_typing_funcs/no_future.py +0 -0
  127. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_typing_funcs/with_future.py +0 -0
  128. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_tzdata.py +0 -0
  129. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_tzlocal.py +0 -0
  130. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_uuid.py +0 -0
  131. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_version.py +0 -0
  132. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_warnings.py +0 -0
  133. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_zipfile.py +0 -0
  134. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/tests/test_zoneinfo.py +0 -0
  135. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/aiolimiter.py +0 -0
  136. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/altair.py +0 -0
  137. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/asyncio.py +0 -0
  138. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/atomicwrites.py +0 -0
  139. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/atools.py +0 -0
  140. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/cachetools.py +0 -0
  141. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/concurrent.py +0 -0
  142. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/contextlib.py +0 -0
  143. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/contextvars.py +0 -0
  144. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/cryptography.py +0 -0
  145. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/cvxpy.py +0 -0
  146. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/dataclasses.py +0 -0
  147. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/enum.py +0 -0
  148. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/errors.py +0 -0
  149. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/eventkit.py +0 -0
  150. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/fastapi.py +0 -0
  151. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/fpdf2.py +0 -0
  152. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/functions.py +0 -0
  153. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/functools.py +0 -0
  154. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/getpass.py +0 -0
  155. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/git.py +0 -0
  156. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/hashlib.py +0 -0
  157. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/http.py +0 -0
  158. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/importlib.py +0 -0
  159. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/inflect.py +0 -0
  160. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/ipython.py +0 -0
  161. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/iterables.py +0 -0
  162. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/jupyter.py +0 -0
  163. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/libcst.py +0 -0
  164. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/lightweight_charts.py +0 -0
  165. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/logging.py +0 -0
  166. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/luigi.py +0 -0
  167. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/math.py +0 -0
  168. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/memory_profiler.py +0 -0
  169. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/modules.py +0 -0
  170. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/more_itertools.py +0 -0
  171. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/numpy.py +0 -0
  172. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/operator.py +0 -0
  173. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/optuna.py +0 -0
  174. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/os.py +0 -0
  175. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/pathlib.py +0 -0
  176. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/period.py +0 -0
  177. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/pickle.py +0 -0
  178. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/platform.py +0 -0
  179. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/polars.py +0 -0
  180. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/polars_ols.py +0 -0
  181. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/pottery.py +0 -0
  182. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/pqdm.py +0 -0
  183. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/psutil.py +0 -0
  184. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/py.typed +0 -0
  185. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/pydantic.py +0 -0
  186. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/pyinstrument.py +0 -0
  187. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/pytest.py +0 -0
  188. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/pytest_regressions.py +0 -0
  189. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/python_dotenv.py +0 -0
  190. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/random.py +0 -0
  191. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/re.py +0 -0
  192. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/redis.py +0 -0
  193. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/reprlib.py +0 -0
  194. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/scipy.py +0 -0
  195. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/sentinel.py +0 -0
  196. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/shelve.py +0 -0
  197. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/slack_sdk.py +0 -0
  198. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/socket.py +0 -0
  199. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/sqlalchemy.py +0 -0
  200. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/sqlalchemy_polars.py +0 -0
  201. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/statsmodels.py +0 -0
  202. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/streamlit.py +0 -0
  203. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/string.py +0 -0
  204. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/tempfile.py +0 -0
  205. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/text.py +0 -0
  206. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/threading.py +0 -0
  207. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/timer.py +0 -0
  208. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/traceback.py +0 -0
  209. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/typing.py +0 -0
  210. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/tzdata.py +0 -0
  211. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/tzlocal.py +0 -0
  212. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/uuid.py +0 -0
  213. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/version.py +0 -0
  214. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/warnings.py +0 -0
  215. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/zipfile.py +0 -0
  216. {dycw_utilities-0.137.0 → dycw_utilities-0.138.0}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.137.0
3
+ Version: 0.138.0
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -105,7 +105,7 @@ dependencies = [
105
105
  name = "dycw-utilities"
106
106
  readme = "README.md"
107
107
  requires-python = ">= 3.12"
108
- version = "0.137.0"
108
+ version = "0.138.0"
109
109
 
110
110
  [project.optional-dependencies]
111
111
  logging = [
@@ -133,7 +133,7 @@ test = [
133
133
  # bump-my-version
134
134
  [tool.bumpversion]
135
135
  allow_dirty = true
136
- current_version = "0.137.0"
136
+ current_version = "0.138.0"
137
137
 
138
138
  [[tool.bumpversion.files]]
139
139
  filename = "src/utilities/__init__.py"
@@ -43,10 +43,11 @@ from utilities.click import (
43
43
  ListChoices,
44
44
  ListEnums,
45
45
  ListStrs,
46
- Month,
46
+ MonthDay,
47
47
  PlainDateTime,
48
48
  Time,
49
49
  TimeDelta,
50
+ YearMonth,
50
51
  ZonedDateTime,
51
52
  )
52
53
  from utilities.hypothesis import (
@@ -54,11 +55,12 @@ from utilities.hypothesis import (
54
55
  date_time_deltas,
55
56
  dates,
56
57
  freqs,
57
- months,
58
+ month_days,
58
59
  plain_datetimes,
59
60
  text_ascii,
60
61
  time_deltas,
61
62
  times,
63
+ year_months,
62
64
  zoned_datetimes,
63
65
  )
64
66
  from utilities.text import join_strs, strip_and_dedent
@@ -283,10 +285,10 @@ class TestParameters:
283
285
  failable=True,
284
286
  ),
285
287
  _Case(
286
- param=Month(),
287
- name="month",
288
- strategy=months(),
289
- serialize=utilities.whenever.Month.format_common_iso,
288
+ param=MonthDay(),
289
+ name="month-day",
290
+ strategy=month_days(),
291
+ serialize=whenever.MonthDay.format_common_iso,
290
292
  failable=True,
291
293
  ),
292
294
  _Case(
@@ -310,6 +312,13 @@ class TestParameters:
310
312
  serialize=whenever.TimeDelta.format_common_iso,
311
313
  failable=True,
312
314
  ),
315
+ _Case(
316
+ param=YearMonth(),
317
+ name="year-month",
318
+ strategy=year_months(),
319
+ serialize=whenever.YearMonth.format_common_iso,
320
+ failable=True,
321
+ ),
313
322
  _Case(
314
323
  param=ZonedDateTime(),
315
324
  name="zoned date-time",
@@ -30,10 +30,12 @@ from whenever import (
30
30
  Date,
31
31
  DateDelta,
32
32
  DateTimeDelta,
33
+ MonthDay,
33
34
  PlainDateTime,
34
35
  Time,
35
36
  TimeDelta,
36
37
  TimeZoneNotFoundError,
38
+ YearMonth,
37
39
  ZonedDateTime,
38
40
  )
39
41
 
@@ -62,7 +64,7 @@ from utilities.hypothesis import (
62
64
  int64s,
63
65
  int_arrays,
64
66
  lists_fixed_length,
65
- months,
67
+ month_days,
66
68
  namespace_mixins,
67
69
  numbers,
68
70
  pairs,
@@ -89,6 +91,7 @@ from utilities.hypothesis import (
89
91
  uint32s,
90
92
  uint64s,
91
93
  versions,
94
+ year_months,
92
95
  zoned_datetimes,
93
96
  )
94
97
  from utilities.iterables import one
@@ -115,7 +118,6 @@ from utilities.whenever import (
115
118
  DATE_TWO_DIGIT_YEAR_MAX,
116
119
  DATE_TWO_DIGIT_YEAR_MIN,
117
120
  Freq,
118
- Month,
119
121
  to_days,
120
122
  to_nanos,
121
123
  )
@@ -611,24 +613,19 @@ class TestListsFixedLength:
611
613
  assert sorted(result) == result
612
614
 
613
615
 
614
- class TestMonths:
615
- @given(data=data(), two_digit=booleans())
616
- def test_main(self, *, data: DataObject, two_digit: bool) -> None:
617
- min_value = data.draw(months() | none())
618
- max_value = data.draw(months() | none())
616
+ class TestMonthDays:
617
+ @given(data=data())
618
+ def test_main(self, *, data: DataObject) -> None:
619
+ min_value = data.draw(month_days() | none())
620
+ max_value = data.draw(month_days() | none())
619
621
  with assume_does_not_raise(InvalidArgument):
620
- month = data.draw(
621
- months(min_value=min_value, max_value=max_value, two_digit=two_digit)
622
- )
623
- assert isinstance(month, Month)
624
- assert Month.parse_common_iso(month.format_common_iso()) == month
622
+ month_day = data.draw(month_days(min_value=min_value, max_value=max_value))
623
+ assert isinstance(month_day, MonthDay)
624
+ assert MonthDay.parse_common_iso(month_day.format_common_iso()) == month_day
625
625
  if min_value is not None:
626
- assert month >= min_value
626
+ assert month_day >= min_value
627
627
  if max_value is not None:
628
- assert month <= max_value
629
- if two_digit:
630
- assert month.to_date() >= DATE_TWO_DIGIT_YEAR_MIN
631
- assert month.to_date() <= DATE_TWO_DIGIT_YEAR_MAX
628
+ assert month_day <= max_value
632
629
 
633
630
 
634
631
  class TestNamespaceMixins:
@@ -683,8 +680,8 @@ class TestPairs:
683
680
  class TestPaths:
684
681
  @given(data=data())
685
682
  def test_main(self, *, data: DataObject) -> None:
686
- min_depth = data.draw(integers(0, 10) | none())
687
- max_depth = data.draw(integers(0, 10) | none())
683
+ min_depth = data.draw(integers(0, 5) | none())
684
+ max_depth = data.draw(integers(0, 5) | none())
688
685
  with assume_does_not_raise(InvalidArgument):
689
686
  path = data.draw(paths(min_depth=min_depth, max_depth=max_depth))
690
687
  assert isinstance(path, Path)
@@ -1010,6 +1007,28 @@ class TestVersions:
1010
1007
  assert version.suffix is None
1011
1008
 
1012
1009
 
1010
+ class TestYearMonths:
1011
+ @given(data=data(), two_digit=booleans())
1012
+ def test_main(self, *, data: DataObject, two_digit: bool) -> None:
1013
+ min_value = data.draw(year_months() | none())
1014
+ max_value = data.draw(year_months() | none())
1015
+ with assume_does_not_raise(InvalidArgument):
1016
+ year_month = data.draw(
1017
+ year_months(
1018
+ min_value=min_value, max_value=max_value, two_digit=two_digit
1019
+ )
1020
+ )
1021
+ assert isinstance(year_month, YearMonth)
1022
+ assert YearMonth.parse_common_iso(year_month.format_common_iso()) == year_month
1023
+ if min_value is not None:
1024
+ assert year_month >= min_value
1025
+ if max_value is not None:
1026
+ assert year_month <= max_value
1027
+ if two_digit:
1028
+ assert year_month.on_day(1) >= DATE_TWO_DIGIT_YEAR_MIN
1029
+ assert year_month.on_day(28) <= DATE_TWO_DIGIT_YEAR_MAX
1030
+
1031
+
1013
1032
  class TestZonedDateTimes:
1014
1033
  @given(data=data(), time_zone=timezones())
1015
1034
  def test_main(self, *, data: DataObject, time_zone: ZoneInfo) -> None:
@@ -39,6 +39,7 @@ from utilities.hypothesis import (
39
39
  date_time_deltas,
40
40
  dates,
41
41
  int64s,
42
+ month_days,
42
43
  paths,
43
44
  plain_datetimes,
44
45
  text_ascii,
@@ -46,6 +47,7 @@ from utilities.hypothesis import (
46
47
  time_deltas,
47
48
  times,
48
49
  versions,
50
+ year_months,
49
51
  zoned_datetimes,
50
52
  )
51
53
  from utilities.math import MAX_INT64, MIN_INT64
@@ -81,6 +83,7 @@ def objects(
81
83
  | dates()
82
84
  | floats(allow_nan=floats_allow_nan)
83
85
  | (int64s() if parsable else integers())
86
+ | month_days()
84
87
  | none()
85
88
  | paths()
86
89
  | plain_datetimes()
@@ -89,6 +92,7 @@ def objects(
89
92
  | times()
90
93
  | uuids()
91
94
  | versions()
95
+ | year_months()
92
96
  | zoned_datetimes()
93
97
  )
94
98
  if dataclass_custom_equality:
@@ -24,9 +24,11 @@ from whenever import (
24
24
  Date,
25
25
  DateDelta,
26
26
  DateTimeDelta,
27
+ MonthDay,
27
28
  PlainDateTime,
28
29
  Time,
29
30
  TimeDelta,
31
+ YearMonth,
30
32
  ZonedDateTime,
31
33
  )
32
34
 
@@ -45,7 +47,7 @@ from utilities.functions import ensure_path
45
47
  from utilities.hypothesis import (
46
48
  dates,
47
49
  int64s,
48
- months,
50
+ month_days,
49
51
  numbers,
50
52
  paths,
51
53
  plain_datetimes,
@@ -53,6 +55,7 @@ from utilities.hypothesis import (
53
55
  time_deltas,
54
56
  times,
55
57
  versions,
58
+ year_months,
56
59
  zoned_datetimes,
57
60
  )
58
61
  from utilities.math import is_equal
@@ -68,7 +71,6 @@ from utilities.sentinel import Sentinel, sentinel
68
71
  from utilities.text import parse_bool
69
72
  from utilities.types import Number
70
73
  from utilities.version import Version
71
- from utilities.whenever import Month
72
74
 
73
75
 
74
76
  class TestSerializeAndParseObject:
@@ -143,11 +145,11 @@ class TestSerializeAndParseObject:
143
145
  result = parse_object(TrueOrFalseFutureLit, truth)
144
146
  assert result == truth
145
147
 
146
- @given(month=months())
147
- def test_month(self, *, month: Month) -> None:
148
- serialized = serialize_object(month)
149
- result = parse_object(Month, serialized)
150
- assert result == month
148
+ @given(month_day=month_days())
149
+ def test_month_day(self, *, month_day: MonthDay) -> None:
150
+ serialized = serialize_object(month_day)
151
+ result = parse_object(MonthDay, serialized)
152
+ assert result == month_day
151
153
 
152
154
  def test_none(self) -> None:
153
155
  serialized = serialize_object(None)
@@ -316,6 +318,12 @@ class TestSerializeAndParseObject:
316
318
  result = parse_object(Version, serialized)
317
319
  assert result == version
318
320
 
321
+ @given(year_month=year_months())
322
+ def test_year_month(self, *, year_month: YearMonth) -> None:
323
+ serialized = serialize_object(year_month)
324
+ result = parse_object(YearMonth, serialized)
325
+ assert result == year_month
326
+
319
327
  @given(datetime=zoned_datetimes())
320
328
  def test_zoned_datetime(self, *, datetime: ZonedDateTime) -> None:
321
329
  serialized = serialize_object(datetime)
@@ -507,6 +515,13 @@ class TestParseObject:
507
515
  ):
508
516
  _ = parse_object(list[int], "[invalid]")
509
517
 
518
+ def test_error_month_day(self) -> None:
519
+ with raises(
520
+ _ParseObjectParseError,
521
+ match=r"Unable to parse <class 'whenever\.MonthDay'>; got 'invalid'",
522
+ ):
523
+ _ = parse_object(MonthDay, "invalid")
524
+
510
525
  def test_error_none(self) -> None:
511
526
  with raises(
512
527
  _ParseObjectParseError, match="Unable to parse None; got 'invalid'"
@@ -622,6 +637,13 @@ class TestParseObject:
622
637
  ):
623
638
  _ = parse_object(Version, "invalid")
624
639
 
640
+ def test_error_year_month(self) -> None:
641
+ with raises(
642
+ _ParseObjectParseError,
643
+ match=r"Unable to parse <class 'whenever\.YearMonth'>; got 'invalid'",
644
+ ):
645
+ _ = parse_object(YearMonth, "invalid")
646
+
625
647
  def test_error_zoned_datetime(self) -> None:
626
648
  with raises(
627
649
  _ParseObjectParseError,
@@ -2,7 +2,7 @@ from collections.abc import Callable
2
2
  from dataclasses import dataclass
3
3
  from ipaddress import IPv4Address, IPv6Address
4
4
  from pathlib import Path
5
- from typing import assert_never
5
+ from typing import Any, ClassVar, assert_never
6
6
 
7
7
  import typed_settings
8
8
  from hypothesis import given
@@ -20,9 +20,11 @@ from whenever import (
20
20
  Date,
21
21
  DateDelta,
22
22
  DateTimeDelta,
23
+ MonthDay,
23
24
  PlainDateTime,
24
25
  Time,
25
26
  TimeDelta,
27
+ YearMonth,
26
28
  ZonedDateTime,
27
29
  )
28
30
 
@@ -31,12 +33,14 @@ from utilities.hypothesis import (
31
33
  date_time_deltas,
32
34
  dates,
33
35
  freqs,
36
+ month_days,
34
37
  paths,
35
38
  plain_datetimes,
36
39
  temp_paths,
37
40
  text_ascii,
38
41
  time_deltas,
39
42
  times,
43
+ year_months,
40
44
  zoned_datetimes,
41
45
  )
42
46
  from utilities.os import temp_environ
@@ -51,47 +55,88 @@ from utilities.whenever import Freq
51
55
  app_names = text_ascii(min_size=1).map(str.lower)
52
56
 
53
57
 
58
+ @dataclass(kw_only=True, slots=True)
59
+ class _Case[T]:
60
+ cls: type[T]
61
+ strategy: SearchStrategy[T]
62
+ serialize: Callable[[T], str]
63
+
64
+
54
65
  class TestExtendedTSConverter:
66
+ cases: ClassVar[list[_Case]] = [
67
+ _Case(cls=Date, strategy=dates(), serialize=Date.format_common_iso),
68
+ _Case(
69
+ cls=DateDelta,
70
+ strategy=date_deltas(parsable=True),
71
+ serialize=DateDelta.format_common_iso,
72
+ ),
73
+ _Case(
74
+ cls=DateTimeDelta,
75
+ strategy=date_time_deltas(parsable=True),
76
+ serialize=DateTimeDelta.format_common_iso,
77
+ ),
78
+ _Case(cls=Freq, strategy=freqs(), serialize=Freq.serialize),
79
+ _Case(cls=IPv4Address, strategy=ip_addresses(v=4), serialize=str),
80
+ _Case(cls=IPv6Address, strategy=ip_addresses(v=6), serialize=str),
81
+ _Case(
82
+ cls=MonthDay, strategy=month_days(), serialize=MonthDay.format_common_iso
83
+ ),
84
+ _Case(
85
+ cls=PlainDateTime,
86
+ strategy=plain_datetimes(),
87
+ serialize=PlainDateTime.format_common_iso,
88
+ ),
89
+ _Case(cls=Time, strategy=times(), serialize=Time.format_common_iso),
90
+ _Case(
91
+ cls=TimeDelta, strategy=time_deltas(), serialize=TimeDelta.format_common_iso
92
+ ),
93
+ _Case(
94
+ cls=YearMonth, strategy=year_months(), serialize=YearMonth.format_common_iso
95
+ ),
96
+ _Case(
97
+ cls=ZonedDateTime,
98
+ strategy=zoned_datetimes(),
99
+ serialize=ZonedDateTime.format_common_iso,
100
+ ),
101
+ ]
102
+
103
+ @given(data=data())
104
+ @mark.parametrize(("cls", "strategy"), [param(c.cls, c.strategy) for c in cases])
105
+ def test_default(
106
+ self, *, data: DataObject, cls: type[Any], strategy: SearchStrategy[Any]
107
+ ) -> None:
108
+ default = data.draw(strategy)
109
+
110
+ @dataclass(frozen=True, kw_only=True, slots=True)
111
+ class Settings:
112
+ value: cls = default # pyright: ignore[reportInvalidTypeForm]
113
+
114
+ loaded = typed_settings.load_settings(
115
+ Settings, loaders=[], converter=ExtendedTSConverter()
116
+ )
117
+ assert loaded.value == default
118
+
55
119
  @given(data=data(), root=temp_paths(), app_name=app_names)
56
120
  @mark.parametrize(
57
- ("test_cls", "strategy", "serialize"),
58
- [
59
- param(Date, dates(), Date.format_common_iso),
60
- param(DateDelta, date_deltas(parsable=True), DateDelta.format_common_iso),
61
- param(
62
- DateTimeDelta,
63
- date_time_deltas(parsable=True),
64
- DateTimeDelta.format_common_iso,
65
- ),
66
- param(Freq, freqs(), Freq.serialize),
67
- param(IPv4Address, ip_addresses(v=4), IPv4Address),
68
- param(IPv6Address, ip_addresses(v=6), IPv6Address),
69
- param(PlainDateTime, plain_datetimes(), PlainDateTime.format_common_iso),
70
- param(Time, times(), Time.format_common_iso),
71
- param(TimeDelta, time_deltas(), TimeDelta.format_common_iso),
72
- param(ZonedDateTime, zoned_datetimes(), ZonedDateTime.format_common_iso),
73
- ],
121
+ ("cls", "strategy", "serialize"),
122
+ [param(c.cls, c.strategy, c.serialize) for c in cases],
74
123
  )
75
- def test_main[T](
124
+ def test_loaded(
76
125
  self,
77
126
  *,
78
127
  data: DataObject,
79
128
  root: Path,
80
129
  app_name: str,
81
- test_cls: type[T],
82
- strategy: SearchStrategy[T],
83
- serialize: Callable[[T], str],
130
+ cls: type[Any],
131
+ strategy: SearchStrategy[Any],
132
+ serialize: Callable[[Any], str],
84
133
  ) -> None:
85
134
  default, value = data.draw(tuples(strategy, strategy))
86
135
 
87
136
  @dataclass(frozen=True, kw_only=True, slots=True)
88
137
  class Settings:
89
- value: test_cls = default # pyright: ignore[reportInvalidTypeForm]
138
+ value: cls = default # pyright: ignore[reportInvalidTypeForm]
90
139
 
91
- settings_default = typed_settings.load_settings(
92
- Settings, loaders=[], converter=ExtendedTSConverter()
93
- )
94
- assert settings_default.value == default
95
140
  file = Path(root, "file.toml")
96
141
  _ = file.write_text(
97
142
  strip_and_dedent(f"""
@@ -99,14 +144,14 @@ class TestExtendedTSConverter:
99
144
  value = '{serialize(value)}'
100
145
  """)
101
146
  )
102
- settings_loaded = typed_settings.load_settings(
147
+ loaded = typed_settings.load_settings(
103
148
  Settings,
104
149
  loaders=[
105
150
  FileLoader(formats={"*.toml": TomlFormat(app_name)}, files=[file])
106
151
  ],
107
152
  converter=ExtendedTSConverter(),
108
153
  )
109
- assert settings_loaded.value == value
154
+ assert loaded.value == value
110
155
 
111
156
  @given(
112
157
  root=temp_paths(),
@@ -6,15 +6,8 @@ from typing import TYPE_CHECKING, ClassVar, Self
6
6
  from zoneinfo import ZoneInfo
7
7
 
8
8
  from hypothesis import given
9
- from hypothesis.strategies import (
10
- DataObject,
11
- data,
12
- integers,
13
- none,
14
- sampled_from,
15
- timezones,
16
- )
17
- from pytest import mark, param, raises
9
+ from hypothesis.strategies import integers, none, sampled_from, timezones
10
+ from pytest import raises
18
11
  from whenever import (
19
12
  Date,
20
13
  DateDelta,
@@ -32,7 +25,6 @@ from utilities.hypothesis import (
32
25
  date_deltas,
33
26
  dates,
34
27
  freqs,
35
- months,
36
28
  pairs,
37
29
  plain_datetimes,
38
30
  sentinels,
@@ -49,8 +41,6 @@ from utilities.whenever import (
49
41
  DATE_DELTA_MIN,
50
42
  DATE_DELTA_PARSABLE_MAX,
51
43
  DATE_DELTA_PARSABLE_MIN,
52
- DATE_MAX,
53
- DATE_MIN,
54
44
  DATE_TIME_DELTA_MAX,
55
45
  DATE_TIME_DELTA_MIN,
56
46
  DATE_TIME_DELTA_PARSABLE_MAX,
@@ -60,8 +50,6 @@ from utilities.whenever import (
60
50
  MINUTE,
61
51
  NOW_LOCAL,
62
52
  NOW_UTC,
63
- PLAIN_DATE_TIME_MAX,
64
- PLAIN_DATE_TIME_MIN,
65
53
  SECOND,
66
54
  TIME_DELTA_MAX,
67
55
  TIME_DELTA_MIN,
@@ -73,7 +61,6 @@ from utilities.whenever import (
73
61
  Freq,
74
62
  MeanDateTimeError,
75
63
  MinMaxDateError,
76
- Month,
77
64
  ToDaysError,
78
65
  ToNanosError,
79
66
  WheneverLogRecord,
@@ -83,8 +70,6 @@ from utilities.whenever import (
83
70
  _MinMaxDateMaxDateError,
84
71
  _MinMaxDateMinDateError,
85
72
  _MinMaxDatePeriodError,
86
- _MonthInvalidError,
87
- _MonthParseCommonISOError,
88
73
  datetime_utc,
89
74
  format_compact,
90
75
  from_timestamp,
@@ -107,8 +92,6 @@ from utilities.whenever import (
107
92
  from utilities.zoneinfo import UTC
108
93
 
109
94
  if TYPE_CHECKING:
110
- from collections.abc import Callable
111
-
112
95
  from utilities.sentinel import Sentinel
113
96
  from utilities.types import MaybeCallableDate, MaybeCallableZonedDateTime
114
97
 
@@ -141,7 +124,9 @@ class TestFormatCompact:
141
124
  result = format_compact(time)
142
125
  assert isinstance(result, str)
143
126
  parsed = Time.parse_common_iso(result)
144
- assert parsed == time
127
+ assert parsed.nanosecond == 0
128
+ expected = time.round()
129
+ assert parsed == expected
145
130
 
146
131
  @given(datetime=plain_datetimes())
147
132
  def test_plain_datetime(self, *, datetime: PlainDateTime) -> None:
@@ -325,14 +310,6 @@ class TestMeanDateTime:
325
310
 
326
311
 
327
312
  class TestMinMax:
328
- def test_date_min(self) -> None:
329
- with raises(ValueError, match="Resulting date out of range"):
330
- _ = DATE_MIN - DateDelta(days=1)
331
-
332
- def test_date_max(self) -> None:
333
- with raises(ValueError, match="Resulting date out of range"):
334
- _ = DATE_MAX + DateDelta(days=1)
335
-
336
313
  def test_date_delta_min(self) -> None:
337
314
  with raises(ValueError, match="Addition result out of bounds"):
338
315
  _ = DATE_DELTA_MIN - DateDelta(days=1)
@@ -375,11 +352,11 @@ class TestMinMax:
375
352
 
376
353
  def test_plain_date_time_min(self) -> None:
377
354
  with raises(ValueError, match=r"Result of subtract\(\) out of range"):
378
- _ = PLAIN_DATE_TIME_MIN.subtract(nanoseconds=1, ignore_dst=True)
355
+ _ = PlainDateTime.MIN.subtract(nanoseconds=1, ignore_dst=True)
379
356
 
380
357
  def test_plain_date_time_max(self) -> None:
381
358
  with raises(ValueError, match=r"Result of add\(\) out of range"):
382
- _ = PLAIN_DATE_TIME_MAX.add(microseconds=1, ignore_dst=True)
359
+ _ = PlainDateTime.MAX.add(microseconds=1, ignore_dst=True)
383
360
 
384
361
  def test_time_delta_min(self) -> None:
385
362
  nanos = TIME_DELTA_MIN.in_nanoseconds()
@@ -466,109 +443,6 @@ class TestMinMaxDate:
466
443
  _ = min_max_date(min_date=dates[1], max_date=dates[0])
467
444
 
468
445
 
469
- class TestMonth:
470
- @mark.parametrize(
471
- ("month", "n", "expected"),
472
- [
473
- param(Month(2000, 1), -2, Month(1999, 11)),
474
- param(Month(2000, 1), -1, Month(1999, 12)),
475
- param(Month(2000, 1), 0, Month(2000, 1)),
476
- param(Month(2000, 1), 1, Month(2000, 2)),
477
- param(Month(2000, 1), 2, Month(2000, 3)),
478
- param(Month(2000, 1), 11, Month(2000, 12)),
479
- param(Month(2000, 1), 12, Month(2001, 1)),
480
- ],
481
- )
482
- def test_add(self, *, month: Month, n: int, expected: Month) -> None:
483
- result = month + n
484
- assert result == expected
485
-
486
- @given(month=months())
487
- def test_common_iso(self, *, month: Month) -> None:
488
- result = Month.parse_common_iso(month.format_common_iso())
489
- assert result == month
490
-
491
- @given(data=data(), month=months())
492
- def test_ensure(self, *, data: DataObject, month: Month) -> None:
493
- str_or_value = data.draw(sampled_from([month, month.format_common_iso()]))
494
- result = Month.ensure(str_or_value)
495
- assert result == month
496
-
497
- @mark.parametrize(
498
- ("x", "y", "expected"),
499
- [
500
- param(Month(2000, 1), Month(1999, 11), 2),
501
- param(Month(2000, 1), Month(1999, 12), 1),
502
- param(Month(2000, 1), Month(2000, 1), 0),
503
- param(Month(2000, 1), Month(2000, 2), -1),
504
- param(Month(2000, 1), Month(2000, 3), -2),
505
- param(Month(2000, 1), Month(2000, 12), -11),
506
- param(Month(2000, 1), Month(2001, 1), -12),
507
- ],
508
- )
509
- def test_diff(self, *, x: Month, y: Month, expected: int) -> None:
510
- result = x - y
511
- assert result == expected
512
-
513
- @given(month=months())
514
- def test_hashable(self, *, month: Month) -> None:
515
- _ = hash(month)
516
-
517
- @mark.parametrize(
518
- ("text", "expected"),
519
- [
520
- param("2000-01", Month(2000, 1)),
521
- param("2000.01", Month(2000, 1)),
522
- param("2000 01", Month(2000, 1)),
523
- param("200001", Month(2000, 1)),
524
- param("20-01", Month(2020, 1)),
525
- param("20.01", Month(2020, 1)),
526
- ],
527
- )
528
- def test_parse_common_iso(self, *, text: str, expected: Month) -> None:
529
- result = Month.parse_common_iso(text)
530
- assert result == expected
531
-
532
- @mark.parametrize("func", [param(repr), param(str)])
533
- def test_repr(self, *, func: Callable[..., str]) -> None:
534
- result = func(Month(2000, 12))
535
- expected = "2000-12"
536
- assert result == expected
537
-
538
- @mark.parametrize(
539
- ("month", "n", "expected"),
540
- [
541
- param(Month(2000, 1), -2, Month(2000, 3)),
542
- param(Month(2000, 1), -1, Month(2000, 2)),
543
- param(Month(2000, 1), 0, Month(2000, 1)),
544
- param(Month(2000, 1), 1, Month(1999, 12)),
545
- param(Month(2000, 1), 2, Month(1999, 11)),
546
- param(Month(2000, 1), 12, Month(1999, 1)),
547
- param(Month(2000, 1), 13, Month(1998, 12)),
548
- ],
549
- )
550
- def test_subtract(self, *, month: Month, n: int, expected: Month) -> None:
551
- result = month - n
552
- assert result == expected
553
-
554
- @given(date=dates())
555
- def test_to_and_from_date(self, *, date: Date) -> None:
556
- month = Month.from_date(date)
557
- result = month.to_date(day=date.day)
558
- assert result == date
559
-
560
- def test_error_invalid(self) -> None:
561
- with raises(_MonthInvalidError, match=r"Invalid year and month: \d+, \d+"):
562
- _ = Month(2000, 13)
563
-
564
- @mark.parametrize("text", [param("invalid"), param("202-01")])
565
- def test_error_parse_common_iso(self, *, text: str) -> None:
566
- with raises(
567
- _MonthParseCommonISOError, match=r"Unable to parse month; got '.*'"
568
- ):
569
- _ = Month.parse_common_iso(text)
570
-
571
-
572
446
  class TestToDate:
573
447
  @given(date=dates())
574
448
  def test_date(self, *, date: Date) -> None: