dycw-utilities 0.152.0__tar.gz → 0.153.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.152.0 → dycw_utilities-0.153.0}/PKG-INFO +1 -1
  2. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/pyproject.toml +2 -2
  3. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_functions.py +1 -13
  4. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_logging.py +18 -20
  5. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_pathlib.py +55 -50
  6. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_polars.py +5 -5
  7. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_pottery.py +3 -3
  8. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_pyinstrument.py +1 -1
  9. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_random.py +1 -1
  10. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_text.py +18 -1
  11. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_traceback.py +3 -9
  12. dycw_utilities-0.153.0/src/tests/test_uuid.py +89 -0
  13. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_version.py +19 -19
  14. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_whenever.py +571 -38
  15. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/__init__.py +1 -1
  16. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/asyncio.py +12 -11
  17. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/cryptography.py +3 -3
  18. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/eventkit.py +8 -8
  19. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/functions.py +1 -33
  20. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/logging.py +23 -24
  21. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pathlib.py +34 -34
  22. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/postgres.py +12 -12
  23. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pottery.py +5 -5
  24. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pyinstrument.py +3 -3
  25. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pytest.py +8 -8
  26. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pytest_plugins/pytest_randomly.py +1 -1
  27. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pytest_plugins/pytest_regressions.py +1 -1
  28. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/random.py +8 -6
  29. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/text.py +37 -2
  30. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/traceback.py +15 -18
  31. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/typed_settings.py +3 -3
  32. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/types.py +24 -14
  33. dycw_utilities-0.153.0/src/utilities/uuid.py +61 -0
  34. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/version.py +27 -26
  35. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/whenever.py +431 -37
  36. dycw_utilities-0.152.0/src/tests/test_period.py +0 -531
  37. dycw_utilities-0.152.0/src/tests/test_uuid.py +0 -37
  38. dycw_utilities-0.152.0/src/utilities/period.py +0 -370
  39. dycw_utilities-0.152.0/src/utilities/uuid.py +0 -24
  40. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/.gitignore +0 -0
  41. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/LICENSE +0 -0
  42. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/README.md +0 -0
  43. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/__init__.py +0 -0
  44. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/conftest.py +0 -0
  45. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/__init__.py +0 -0
  46. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_missing/__init__.py +0 -0
  47. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_missing/module.py +0 -0
  48. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_with/__init__.py +0 -0
  49. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_with/outer_1.py +0 -0
  50. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_with/outer_2.py +0 -0
  51. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  52. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  53. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  54. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  55. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_without/__init__.py +0 -0
  56. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_without/module_1.py +0 -0
  57. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/package_without/module_2.py +0 -0
  58. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/standalone.py +0 -0
  59. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/modules/with_imports.py +0 -0
  60. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  61. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  62. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  63. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  64. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  65. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  66. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  67. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  68. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_altair.py +0 -0
  69. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_asyncio.py +0 -0
  70. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_atomicwrites.py +0 -0
  71. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_atools.py +0 -0
  72. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_cachetools.py +0 -0
  73. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_click.py +0 -0
  74. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_concurrent.py +0 -0
  75. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_contextlib.py +0 -0
  76. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_contextvars.py +0 -0
  77. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_cryptography.py +0 -0
  78. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_cvxpy.py +0 -0
  79. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_dataclasses.py +0 -0
  80. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_enum.py +0 -0
  81. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_errors.py +0 -0
  82. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_eventkit.py +0 -0
  83. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_fastapi.py +0 -0
  84. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_fpdf2.py +0 -0
  85. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_functools.py +0 -0
  86. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_getpass.py +0 -0
  87. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_gzip.py +0 -0
  88. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_hashlib.py +0 -0
  89. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_http.py +0 -0
  90. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_hypothesis.py +0 -0
  91. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_importlib.py +0 -0
  92. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_inflect.py +0 -0
  93. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_ipython.py +0 -0
  94. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_iterables.py +0 -0
  95. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_json.py +0 -0
  96. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_jupyter.py +0 -0
  97. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_libcst.py +0 -0
  98. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_lightweight_charts.py +0 -0
  99. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_math.py +0 -0
  100. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_memory_profiler.py +0 -0
  101. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_modules.py +0 -0
  102. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_more_itertools.py +0 -0
  103. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_numpy.py +0 -0
  104. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_objects/__init__.py +0 -0
  105. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_objects/objects.py +0 -0
  106. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_operator.py +0 -0
  107. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_optuna.py +0 -0
  108. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_orjson.py +0 -0
  109. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_os.py +0 -0
  110. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_parse.py +0 -0
  111. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_pickle.py +0 -0
  112. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_platform.py +0 -0
  113. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_polars_ols.py +0 -0
  114. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_postgres.py +0 -0
  115. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_pqdm.py +0 -0
  116. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_psutil.py +0 -0
  117. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_pytest.py +0 -0
  118. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_pytest_randomly.py +0 -0
  119. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_pytest_regressions.py +0 -0
  120. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_re.py +0 -0
  121. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_redis.py +0 -0
  122. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_reprlib.py +0 -0
  123. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_scipy.py +0 -0
  124. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_sentinel.py +0 -0
  125. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_shelve.py +0 -0
  126. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_slack_sdk.py +0 -0
  127. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_socket.py +0 -0
  128. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_sqlalchemy.py +0 -0
  129. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_sqlalchemy_polars.py +0 -0
  130. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_statsmodels.py +0 -0
  131. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_string.py +0 -0
  132. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_tempfile.py +0 -0
  133. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_threading.py +0 -0
  134. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_timer.py +0 -0
  135. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_typed_settings.py +0 -0
  136. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_types.py +0 -0
  137. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_typing.py +0 -0
  138. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_typing_funcs/__init__.py +0 -0
  139. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_typing_funcs/no_future.py +0 -0
  140. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_typing_funcs/with_future.py +0 -0
  141. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_tzdata.py +0 -0
  142. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_tzlocal.py +0 -0
  143. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_warnings.py +0 -0
  144. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_yield_access/__init__.py +0 -0
  145. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_yield_access/script.py +0 -0
  146. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_yield_access/script.sh +0 -0
  147. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_zipfile.py +0 -0
  148. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/tests/test_zoneinfo.py +0 -0
  149. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/altair.py +0 -0
  150. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/atomicwrites.py +0 -0
  151. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/atools.py +0 -0
  152. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/cachetools.py +0 -0
  153. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/click.py +0 -0
  154. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/concurrent.py +0 -0
  155. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/contextlib.py +0 -0
  156. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/contextvars.py +0 -0
  157. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/cvxpy.py +0 -0
  158. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/dataclasses.py +0 -0
  159. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/enum.py +0 -0
  160. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/errors.py +0 -0
  161. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/fastapi.py +0 -0
  162. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/fpdf2.py +0 -0
  163. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/functools.py +0 -0
  164. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/getpass.py +0 -0
  165. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/gzip.py +0 -0
  166. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/hashlib.py +0 -0
  167. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/http.py +0 -0
  168. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/hypothesis.py +0 -0
  169. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/importlib.py +0 -0
  170. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/inflect.py +0 -0
  171. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/ipython.py +0 -0
  172. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/iterables.py +0 -0
  173. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/json.py +0 -0
  174. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/jupyter.py +0 -0
  175. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/libcst.py +0 -0
  176. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/lightweight_charts.py +0 -0
  177. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/math.py +0 -0
  178. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/memory_profiler.py +0 -0
  179. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/modules.py +0 -0
  180. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/more_itertools.py +0 -0
  181. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/numpy.py +0 -0
  182. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/operator.py +0 -0
  183. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/optuna.py +0 -0
  184. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/orjson.py +0 -0
  185. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/os.py +0 -0
  186. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/parse.py +0 -0
  187. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pickle.py +0 -0
  188. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/platform.py +0 -0
  189. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/polars.py +0 -0
  190. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/polars_ols.py +0 -0
  191. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pqdm.py +0 -0
  192. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/psutil.py +0 -0
  193. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/py.typed +0 -0
  194. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pytest_plugins/__init__.py +0 -0
  195. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/pytest_regressions.py +0 -0
  196. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/re.py +0 -0
  197. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/redis.py +0 -0
  198. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/reprlib.py +0 -0
  199. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/scipy.py +0 -0
  200. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/sentinel.py +0 -0
  201. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/shelve.py +0 -0
  202. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/slack_sdk.py +0 -0
  203. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/socket.py +0 -0
  204. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/sqlalchemy.py +0 -0
  205. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/sqlalchemy_polars.py +0 -0
  206. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/statsmodels.py +0 -0
  207. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/string.py +0 -0
  208. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/tempfile.py +0 -0
  209. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/threading.py +0 -0
  210. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/timer.py +0 -0
  211. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/typing.py +0 -0
  212. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/tzdata.py +0 -0
  213. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/tzlocal.py +0 -0
  214. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/warnings.py +0 -0
  215. {dycw_utilities-0.152.0 → dycw_utilities-0.153.0}/src/utilities/zipfile.py +0 -0
  216. {dycw_utilities-0.152.0 → dycw_utilities-0.153.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.152.0
3
+ Version: 0.153.0
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -229,7 +229,7 @@ dependencies = [
229
229
  name = "dycw-utilities"
230
230
  readme = "README.md"
231
231
  requires-python = ">= 3.12"
232
- version = "0.152.0"
232
+ version = "0.153.0"
233
233
 
234
234
  [project.entry-points.pytest11]
235
235
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -262,7 +262,7 @@ test = [
262
262
  # bump-my-version
263
263
  [tool.bumpversion]
264
264
  allow_dirty = true
265
- current_version = "0.152.0"
265
+ current_version = "0.153.0"
266
266
 
267
267
  [[tool.bumpversion.files]]
268
268
  filename = "src/utilities/__init__.py"
@@ -90,13 +90,11 @@ from utilities.functions import (
90
90
  min_nullable,
91
91
  not_func,
92
92
  second,
93
- to_bool,
94
93
  yield_object_attributes,
95
94
  yield_object_cached_properties,
96
95
  yield_object_properties,
97
96
  )
98
- from utilities.hypothesis import sentinels
99
- from utilities.sentinel import Sentinel, sentinel
97
+ from utilities.sentinel import sentinel
100
98
  from utilities.whenever import NOW_UTC, ZERO_TIME, get_now, get_today
101
99
 
102
100
  if TYPE_CHECKING:
@@ -917,16 +915,6 @@ class TestSecond:
917
915
  assert second(pair) == y
918
916
 
919
917
 
920
- class TestToBool:
921
- @given(bool_=booleans() | none() | sentinels())
922
- def test_bool_none_or_sentinel(self, *, bool_: bool | None | Sentinel) -> None:
923
- assert to_bool(bool_=bool_) is bool_
924
-
925
- @given(bool_=booleans())
926
- def test_callable(self, *, bool_: bool) -> None:
927
- assert to_bool(bool_=lambda: bool_) is bool_
928
-
929
-
930
918
  class TestYieldObjectAttributes:
931
919
  @given(n=integers())
932
920
  def test_main(self, *, n: int) -> None:
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from asyncio import sleep
4
4
  from io import StringIO
5
- from logging import Formatter, Logger, StreamHandler, getLogger
5
+ from logging import Formatter, StreamHandler, getLogger
6
6
  from pathlib import Path
7
7
  from re import search
8
8
  from typing import TYPE_CHECKING, Any, cast
@@ -32,9 +32,9 @@ from utilities.logging import (
32
32
  filter_for_key,
33
33
  get_format_str,
34
34
  get_formatter,
35
- get_logger,
36
35
  get_logging_level_number,
37
36
  setup_logging,
37
+ to_logger,
38
38
  )
39
39
  from utilities.text import unique_str
40
40
  from utilities.types import LogLevel
@@ -261,24 +261,6 @@ class TestGetFormatter:
261
261
  assert isinstance(formatter, Formatter)
262
262
 
263
263
 
264
- class TestGetLogger:
265
- def test_logger(self) -> None:
266
- logger = getLogger(unique_str())
267
- result = get_logger(logger=logger)
268
- assert result is logger
269
-
270
- def test_str(self) -> None:
271
- name = unique_str()
272
- logger = getLogger(name)
273
- assert isinstance(logger, Logger)
274
- assert logger.name == name
275
-
276
- def test_none(self) -> None:
277
- result = get_logger()
278
- assert isinstance(result, Logger)
279
- assert result.name == "root"
280
-
281
-
282
264
  class TestGetLoggingLevelNumber:
283
265
  @mark.parametrize(
284
266
  ("level", "expected"),
@@ -576,3 +558,19 @@ class TestSizeAndTimeRotatingFileHandler:
576
558
  record = one(r for r in caplog.records if r.name == name)
577
559
  path.unlink()
578
560
  assert not handler._should_rollover(record)
561
+
562
+
563
+ class TestToLogger:
564
+ def test_default(self) -> None:
565
+ assert to_logger().name == "root"
566
+
567
+ @given(name=text_ascii(min_size=1))
568
+ def test_logger(self, *, name: str) -> None:
569
+ assert to_logger(getLogger(name)).name == name
570
+
571
+ @given(name=text_ascii(min_size=1))
572
+ def test_str(self, *, name: str) -> None:
573
+ assert to_logger(name).name == name
574
+
575
+ def test_none(self) -> None:
576
+ assert to_logger(None).name == "root"
@@ -11,7 +11,7 @@ from pytest import mark, param, raises
11
11
 
12
12
  from tests.conftest import SKIPIF_CI_AND_WINDOWS
13
13
  from utilities.dataclasses import replace_non_sentinel
14
- from utilities.hypothesis import git_repos, paths, temp_paths
14
+ from utilities.hypothesis import git_repos, pairs, paths, temp_paths
15
15
  from utilities.pathlib import (
16
16
  GetPackageRootError,
17
17
  GetRepoRootError,
@@ -23,7 +23,6 @@ from utilities.pathlib import (
23
23
  ensure_suffix,
24
24
  expand_path,
25
25
  get_package_root,
26
- get_path,
27
26
  get_repo_root,
28
27
  get_root,
29
28
  get_tail,
@@ -31,6 +30,7 @@ from utilities.pathlib import (
31
30
  list_dir,
32
31
  module_path,
33
32
  temp_cwd,
33
+ to_path,
34
34
  )
35
35
  from utilities.sentinel import Sentinel, sentinel
36
36
  from utilities.tempfile import TemporaryDirectory
@@ -77,42 +77,6 @@ class TestExpandPath:
77
77
  assert result == expected
78
78
 
79
79
 
80
- class TestGetPath:
81
- @given(path=paths())
82
- def test_path(self, *, path: Path) -> None:
83
- assert get_path(path=path) == path
84
-
85
- @given(path=paths())
86
- def test_str(self, *, path: Path) -> None:
87
- assert get_path(path=str(path)) == path
88
-
89
- def test_none(self) -> None:
90
- assert get_path(path=None) == Path.cwd()
91
-
92
- def test_sentinel(self) -> None:
93
- assert get_path(path=sentinel) is sentinel
94
-
95
- @given(path1=paths(), path2=paths())
96
- def test_replace_non_sentinel(self, *, path1: Path, path2: Path) -> None:
97
- @dataclass(kw_only=True, slots=True)
98
- class Example:
99
- path: Path = field(default_factory=Path.cwd)
100
-
101
- def replace(
102
- self, *, path: MaybeCallablePathLike | Sentinel = sentinel
103
- ) -> Self:
104
- return replace_non_sentinel(self, path=get_path(path=path))
105
-
106
- obj = Example(path=path1)
107
- assert obj.path == path1
108
- assert obj.replace().path == path1
109
- assert obj.replace(path=path2).path == path2
110
-
111
- @given(path=paths())
112
- def test_callable(self, *, path: Path) -> None:
113
- assert get_path(path=lambda: path) == path
114
-
115
-
116
80
  class TestGetPackageRoot:
117
81
  @given(tail=paths())
118
82
  @settings(
@@ -121,7 +85,7 @@ class TestGetPackageRoot:
121
85
  def test_dir(self, *, tmp_path: Path, tail: Path) -> None:
122
86
  tmp_path.joinpath("pyproject.toml").touch()
123
87
  path = tmp_path.joinpath(tail)
124
- result = get_package_root(path=path)
88
+ result = get_package_root(path)
125
89
  expected = tmp_path.resolve()
126
90
  assert result == expected
127
91
 
@@ -133,20 +97,20 @@ class TestGetPackageRoot:
133
97
  tmp_path.joinpath("pyproject.toml").touch()
134
98
  path = tmp_path.joinpath(tail)
135
99
  path.touch()
136
- root = get_package_root(path=path)
100
+ root = get_package_root(path)
137
101
  expected = tmp_path.resolve()
138
102
  assert root == expected
139
103
 
140
104
  def test_error(self, *, tmp_path: Path) -> None:
141
105
  with raises(GetPackageRootError, match="Path is not part of a package: .*"):
142
- _ = get_package_root(path=tmp_path)
106
+ _ = get_package_root(tmp_path)
143
107
 
144
108
 
145
109
  class TestGetRepoRoot:
146
110
  @given(repo=git_repos(), tail=paths())
147
111
  @settings(max_examples=1)
148
112
  def test_dir(self, *, repo: Path, tail: Path) -> None:
149
- root = get_repo_root(path=repo.joinpath(tail))
113
+ root = get_repo_root(repo.joinpath(tail))
150
114
  expected = repo.resolve()
151
115
  assert root == expected
152
116
 
@@ -155,7 +119,7 @@ class TestGetRepoRoot:
155
119
  def test_file(self, *, repo: Path, tail: Path) -> None:
156
120
  path = repo.joinpath(tail)
157
121
  path.touch()
158
- root = get_repo_root(path=path)
122
+ root = get_repo_root(path)
159
123
  expected = repo.resolve()
160
124
  assert root == expected
161
125
 
@@ -163,14 +127,14 @@ class TestGetRepoRoot:
163
127
  with raises(
164
128
  GetRepoRootError, match="Path is not part of a `git` repository: .*"
165
129
  ):
166
- _ = get_repo_root(path=tmp_path)
130
+ _ = get_repo_root(tmp_path)
167
131
 
168
132
 
169
133
  class TestGetRoot:
170
134
  @given(repo=git_repos(), tail=paths())
171
135
  @settings(max_examples=1)
172
136
  def test_repo_only(self, *, repo: Path, tail: Path) -> None:
173
- root = get_root(path=repo.joinpath(tail))
137
+ root = get_root(repo.joinpath(tail))
174
138
  expected = repo.resolve()
175
139
  assert root == expected
176
140
 
@@ -181,7 +145,7 @@ class TestGetRoot:
181
145
  def test_package_only(self, *, tmp_path: Path, tail: Path) -> None:
182
146
  tmp_path.joinpath("pyproject.toml").touch()
183
147
  path = tmp_path.joinpath(tail)
184
- result = get_root(path=path)
148
+ result = get_root(path)
185
149
  expected = tmp_path.resolve()
186
150
  assert result == expected
187
151
 
@@ -192,7 +156,7 @@ class TestGetRoot:
192
156
  def test_repo_and_package(self, *, repo: Path, tail: Path) -> None:
193
157
  repo.joinpath("pyproject.toml").touch()
194
158
  path = repo.joinpath(tail)
195
- root = get_root(path=path)
159
+ root = get_root(path)
196
160
  expected = repo.resolve()
197
161
  assert root == expected
198
162
 
@@ -204,7 +168,7 @@ class TestGetRoot:
204
168
  path = repo.joinpath(tail)
205
169
  path.mkdir(parents=True)
206
170
  path.joinpath("pyproject.toml").touch()
207
- root = get_root(path=path)
171
+ root = get_root(path)
208
172
  expected = path.resolve()
209
173
  assert root == expected
210
174
 
@@ -217,13 +181,13 @@ class TestGetRoot:
217
181
  temp.joinpath("pyproject.toml").touch()
218
182
  path = temp.joinpath(tail)
219
183
  _ = copytree(repo, path)
220
- root = get_root(path=path)
184
+ root = get_root(path)
221
185
  expected = path.resolve()
222
186
  assert root == expected
223
187
 
224
188
  def test_error(self, *, tmp_path: Path) -> None:
225
189
  with raises(GetRootError, match="Unable to determine root from '.*'"):
226
- _ = get_root(path=tmp_path)
190
+ _ = get_root(tmp_path)
227
191
 
228
192
 
229
193
  class TestGetTail:
@@ -317,3 +281,44 @@ class TestTempCWD:
317
281
  with temp_cwd(tmp_path):
318
282
  assert Path.cwd() == tmp_path
319
283
  assert Path.cwd() != tmp_path
284
+
285
+
286
+ class TestToPath:
287
+ def test_default(self) -> None:
288
+ assert to_path() == Path.cwd()
289
+
290
+ @given(path=paths())
291
+ def test_path(self, *, path: Path) -> None:
292
+ assert to_path(path) == path
293
+
294
+ @given(path=paths())
295
+ def test_str(self, *, path: Path) -> None:
296
+ assert to_path(str(path)) == path
297
+
298
+ @given(path=paths())
299
+ def test_callable(self, *, path: Path) -> None:
300
+ assert to_path(lambda: path) == path
301
+
302
+ def test_none(self) -> None:
303
+ assert to_path(None) == Path.cwd()
304
+
305
+ def test_sentinel(self) -> None:
306
+ assert to_path(sentinel) is sentinel
307
+
308
+ @given(paths=pairs(paths()))
309
+ def test_replace_non_sentinel(self, *, paths: tuple[Path, Path]) -> None:
310
+ path1, path2 = paths
311
+
312
+ @dataclass(kw_only=True, slots=True)
313
+ class Example:
314
+ path: Path = field(default_factory=Path.cwd)
315
+
316
+ def replace(
317
+ self, *, path: MaybeCallablePathLike | Sentinel = sentinel
318
+ ) -> Self:
319
+ return replace_non_sentinel(self, path=to_path(path))
320
+
321
+ obj = Example(path=path1)
322
+ assert obj.path == path1
323
+ assert obj.replace().path == path1
324
+ assert obj.replace(path=path2).path == path2
@@ -1115,7 +1115,7 @@ class TestDataClassToSchema:
1115
1115
  @given(time_zone=timezones())
1116
1116
  def test_date_or_datetime_as_zoned_datetime(self, *, time_zone: ZoneInfo) -> None:
1117
1117
  with assume_does_not_raise(TimeZoneNotFoundError):
1118
- now = get_now(time_zone=time_zone).py_datetime()
1118
+ now = get_now(time_zone).py_datetime()
1119
1119
 
1120
1120
  @dataclass(kw_only=True, slots=True)
1121
1121
  class Example:
@@ -1247,7 +1247,7 @@ class TestDataClassToSchema:
1247
1247
  @given(time_zone=timezones())
1248
1248
  def test_zoned_datetime(self, *, time_zone: ZoneInfo) -> None:
1249
1249
  with assume_does_not_raise(TimeZoneNotFoundError):
1250
- now = get_now(time_zone=time_zone).py_datetime()
1250
+ now = get_now(time_zone).py_datetime()
1251
1251
 
1252
1252
  @dataclass(kw_only=True, slots=True)
1253
1253
  class Example:
@@ -1261,8 +1261,8 @@ class TestDataClassToSchema:
1261
1261
  @given(start=timezones(), end=timezones())
1262
1262
  def test_zoned_datetime_nested(self, *, start: ZoneInfo, end: ZoneInfo) -> None:
1263
1263
  with assume_does_not_raise(TimeZoneNotFoundError):
1264
- now_start = get_now(time_zone=start).py_datetime()
1265
- now_end = get_now(time_zone=end).py_datetime()
1264
+ now_start = get_now(start).py_datetime()
1265
+ now_end = get_now(end).py_datetime()
1266
1266
 
1267
1267
  @dataclass(kw_only=True, slots=True)
1268
1268
  class Inner:
@@ -1410,7 +1410,7 @@ class TestFiniteEWMMean:
1410
1410
  )
1411
1411
  def test_main(self, *, case: tuple[float, float, list[float], list[float]]) -> None:
1412
1412
  alpha, min_weight, exp_base, exp_result = case
1413
- state = get_state(seed=0)
1413
+ state = get_state(0)
1414
1414
  series = Series(values=[state.randint(-10, 10) for _ in range(100)])
1415
1415
  base = series.ewm_mean(alpha=alpha)
1416
1416
  exp_base_sr = Series(values=exp_base, dtype=Float64)
@@ -23,7 +23,7 @@ if TYPE_CHECKING:
23
23
  from redis.asyncio import Redis
24
24
  from whenever import TimeDelta
25
25
 
26
- from utilities.types import LoggerOrName
26
+ from utilities.types import LoggerLike
27
27
 
28
28
 
29
29
  class TestExtendLock:
@@ -79,7 +79,7 @@ class TestTryYieldCoroutineLooper:
79
79
  lst: list[None],
80
80
  /,
81
81
  *,
82
- logger: LoggerOrName | None = None,
82
+ logger: LoggerLike | None = None,
83
83
  context: ContextVar[bool] | None = None,
84
84
  ) -> None:
85
85
  async with try_yield_coroutine_looper(
@@ -95,7 +95,7 @@ class TestTryYieldCoroutineLooper:
95
95
  lst: list[None],
96
96
  /,
97
97
  *,
98
- logger: LoggerOrName | None = None,
98
+ logger: LoggerLike | None = None,
99
99
  context: ContextVar[bool] | None = None,
100
100
  ) -> None:
101
101
  await sleep_td(self.delta)
@@ -12,7 +12,7 @@ if TYPE_CHECKING:
12
12
 
13
13
  class TestProfile:
14
14
  def test_main(self, tmp_path: Path) -> None:
15
- with profile(path=tmp_path):
15
+ with profile(tmp_path):
16
16
  sleep(1e-3)
17
17
 
18
18
  (file,) = tmp_path.iterdir()
@@ -36,7 +36,7 @@ class TestGetDockerName:
36
36
  class TestGetState:
37
37
  @given(seed=integers() | just(SYSTEM_RANDOM))
38
38
  def test_main(self, *, seed: int | SystemRandom) -> None:
39
- state = get_state(seed=seed)
39
+ state = get_state(seed)
40
40
  assert isinstance(state, Random)
41
41
 
42
42
 
@@ -17,7 +17,7 @@ from hypothesis.strategies import (
17
17
  )
18
18
  from pytest import mark, param, raises
19
19
 
20
- from utilities.hypothesis import text_ascii
20
+ from utilities.hypothesis import sentinels, text_ascii
21
21
  from utilities.text import (
22
22
  ParseBoolError,
23
23
  ParseNoneError,
@@ -37,12 +37,15 @@ from utilities.text import (
37
37
  split_str,
38
38
  str_encode,
39
39
  strip_and_dedent,
40
+ to_bool,
40
41
  unique_str,
41
42
  )
42
43
 
43
44
  if TYPE_CHECKING:
44
45
  from collections.abc import Sequence
45
46
 
47
+ from utilities.sentinel import Sentinel
48
+
46
49
 
47
50
  class TestParseBool:
48
51
  @given(data=data(), value=booleans())
@@ -323,6 +326,20 @@ class TestStripAndDedent:
323
326
  assert result == expected
324
327
 
325
328
 
329
+ class TestToBool:
330
+ @given(bool_=booleans() | none() | sentinels())
331
+ def test_bool_none_or_sentinel(self, *, bool_: bool | None | Sentinel) -> None:
332
+ assert to_bool(bool_) is bool_
333
+
334
+ @given(bool_=booleans())
335
+ def test_str(self, *, bool_: bool) -> None:
336
+ assert to_bool(str(bool_)) is bool_
337
+
338
+ @given(bool_=booleans())
339
+ def test_callable(self, *, bool_: bool) -> None:
340
+ assert to_bool(lambda: bool_) is bool_
341
+
342
+
326
343
  class TestUniqueStrs:
327
344
  def test_main(self) -> None:
328
345
  first, second = [unique_str() for _ in range(2)]
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING
8
8
 
9
9
  from hypothesis import given
10
10
  from hypothesis.strategies import sampled_from
11
- from pytest import CaptureFixture, mark, param, raises
11
+ from pytest import CaptureFixture, raises
12
12
 
13
13
  from utilities.iterables import one
14
14
  from utilities.traceback import (
@@ -18,13 +18,10 @@ from utilities.traceback import (
18
18
  make_except_hook,
19
19
  )
20
20
  from utilities.tzlocal import LOCAL_TIME_ZONE_NAME
21
- from utilities.whenever import get_now
22
21
 
23
22
  if TYPE_CHECKING:
24
23
  from collections.abc import Iterable
25
24
 
26
- from utilities.types import MaybeCallableZonedDateTime
27
-
28
25
 
29
26
  class TestFormatExceptionStack:
30
27
  @classmethod
@@ -45,14 +42,11 @@ class TestFormatExceptionStack:
45
42
  result = format_exception_stack(error).splitlines()
46
43
  self._assert_lines(result)
47
44
 
48
- @mark.parametrize("start", [param(get_now), param(None)])
49
- def test_header(self, *, start: MaybeCallableZonedDateTime) -> None:
45
+ def test_header(self) -> None:
50
46
  try:
51
47
  _ = self.func(1, 2, 3, 4, c=5, d=6, e=7)
52
48
  except AssertionError as error:
53
- result = format_exception_stack(
54
- error, header=True, start=start
55
- ).splitlines()
49
+ result = format_exception_stack(error, header=True).splitlines()
56
50
  patterns = [
57
51
  rf"^Date/time \| \d{{8}}T\d{{6}}\[{LOCAL_TIME_ZONE_NAME}\]$",
58
52
  rf"^Started \| (\d{{8}}T\d{{6}}\[{LOCAL_TIME_ZONE_NAME}\]|)$",
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from re import search
5
+ from typing import TYPE_CHECKING, Self
6
+ from uuid import UUID
7
+
8
+ from hypothesis import given
9
+ from hypothesis.strategies import integers, none, randoms, uuids
10
+
11
+ from utilities.dataclasses import replace_non_sentinel
12
+ from utilities.hypothesis import pairs
13
+ from utilities.sentinel import Sentinel, sentinel
14
+ from utilities.uuid import UUID_EXACT_PATTERN, UUID_PATTERN, get_uuid, to_uuid
15
+
16
+ if TYPE_CHECKING:
17
+ from random import Random
18
+
19
+ from utilities.sentinel import Sentinel
20
+ from utilities.types import MaybeCallableUUIDLike
21
+
22
+
23
+ class TestGetUUID:
24
+ @given(seed=randoms() | none())
25
+ def test_main(self, *, seed: Random | None) -> None:
26
+ assert isinstance(get_uuid(seed), UUID)
27
+
28
+ @given(seed=integers())
29
+ def test_deterministic(self, *, seed: int) -> None:
30
+ uuid1, uuid2 = [get_uuid(seed) for _ in range(2)]
31
+ assert uuid1 == uuid2
32
+
33
+
34
+ class TestToUUID:
35
+ def test_default(self) -> None:
36
+ assert isinstance(to_uuid(), UUID)
37
+
38
+ @given(uuid=uuids())
39
+ def test_uuid(self, *, uuid: UUID) -> None:
40
+ assert to_uuid(uuid) == uuid
41
+
42
+ @given(uuid=uuids())
43
+ def test_str(self, *, uuid: UUID) -> None:
44
+ assert to_uuid(str(uuid)) == uuid
45
+
46
+ @given(seed=randoms())
47
+ def test_seed(self, *, seed: Random) -> None:
48
+ assert isinstance(to_uuid(seed), UUID)
49
+
50
+ @given(uuid=uuids())
51
+ def test_callable(self, *, uuid: UUID) -> None:
52
+ assert to_uuid(lambda: uuid) == uuid
53
+
54
+ def test_none(self) -> None:
55
+ assert isinstance(to_uuid(None), UUID)
56
+
57
+ def test_sentinel(self) -> None:
58
+ assert to_uuid(sentinel) is sentinel
59
+
60
+ @given(uuids=pairs(uuids()))
61
+ def test_replace_non_sentinel(self, *, uuids: tuple[UUID, UUID]) -> None:
62
+ uuid1, uuid2 = uuids
63
+
64
+ @dataclass(kw_only=True, slots=True)
65
+ class Example:
66
+ uuid: UUID = field(default_factory=get_uuid)
67
+
68
+ def replace(
69
+ self, *, uuid: MaybeCallableUUIDLike | Sentinel = sentinel
70
+ ) -> Self:
71
+ return replace_non_sentinel(self, uuid=to_uuid(uuid))
72
+
73
+ obj = Example(uuid=uuid1)
74
+ assert obj.uuid == uuid1
75
+ assert obj.replace().uuid == uuid1
76
+ assert obj.replace(uuid=uuid2).uuid == uuid2
77
+ assert isinstance(obj.replace(uuid=get_uuid).uuid, UUID)
78
+
79
+
80
+ class TestUUIDPattern:
81
+ @given(uuid=uuids())
82
+ def test_main(self, *, uuid: UUID) -> None:
83
+ assert search(UUID_PATTERN, str(uuid))
84
+
85
+ @given(uuid=uuids())
86
+ def test_exact(self, *, uuid: UUID) -> None:
87
+ text = f".{uuid}."
88
+ assert search(UUID_PATTERN, text)
89
+ assert not search(UUID_EXACT_PATTERN, text)
@@ -16,32 +16,14 @@ from utilities.version import (
16
16
  _VersionNegativeMinorVersionError,
17
17
  _VersionNegativePatchVersionError,
18
18
  _VersionZeroError,
19
- get_version,
20
19
  parse_version,
20
+ to_version,
21
21
  )
22
22
 
23
23
  if TYPE_CHECKING:
24
24
  from utilities.sentinel import Sentinel
25
25
 
26
26
 
27
- class TestGetVersion:
28
- @given(version=versions())
29
- def test_version(self, *, version: Version) -> None:
30
- assert get_version(version=version) == version
31
-
32
- @given(version=versions())
33
- def test_str(self, *, version: Version) -> None:
34
- assert get_version(version=str(version)) == version
35
-
36
- @given(version=none() | sentinels())
37
- def test_none_or_sentinel(self, *, version: None | Sentinel) -> None:
38
- assert get_version(version=version) is version
39
-
40
- @given(version=versions())
41
- def test_callable(self, *, version: Version) -> None:
42
- assert get_version(version=lambda: version) == version
43
-
44
-
45
27
  class TestParseVersion:
46
28
  @given(version=versions())
47
29
  def test_main(self, *, version: Version) -> None:
@@ -140,3 +122,21 @@ class TestVersion:
140
122
  def test_error_empty_suffix(self) -> None:
141
123
  with raises(_VersionEmptySuffixError, match="Suffix must be non-empty; got .*"):
142
124
  _ = Version(suffix="")
125
+
126
+
127
+ class TestGetVersion:
128
+ @given(version=versions())
129
+ def test_version(self, *, version: Version) -> None:
130
+ assert to_version(version) == version
131
+
132
+ @given(version=versions())
133
+ def test_str(self, *, version: Version) -> None:
134
+ assert to_version(str(version)) == version
135
+
136
+ @given(version=none() | sentinels())
137
+ def test_none_or_sentinel(self, *, version: None | Sentinel) -> None:
138
+ assert to_version(version) is version
139
+
140
+ @given(version=versions())
141
+ def test_callable(self, *, version: Version) -> None:
142
+ assert to_version(lambda: version) == version