dycw-utilities 0.168.3__tar.gz → 0.168.4__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.

Potentially problematic release.


This version of dycw-utilities might be problematic. Click here for more details.

Files changed (221) hide show
  1. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/PKG-INFO +4 -4
  2. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/pyproject.toml +11 -15
  3. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/__init__.py +1 -1
  4. dycw_utilities-0.168.3/src/tests/test_typed_settings.py +0 -321
  5. dycw_utilities-0.168.3/src/utilities/typed_settings.py +0 -152
  6. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/.gitignore +0 -0
  7. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/LICENSE +0 -0
  8. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/README.md +0 -0
  9. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/__init__.py +0 -0
  10. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/conftest.py +0 -0
  11. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/__init__.py +0 -0
  12. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_missing/__init__.py +0 -0
  13. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_missing/module.py +0 -0
  14. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_with/__init__.py +0 -0
  15. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_with/outer_1.py +0 -0
  16. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_with/outer_2.py +0 -0
  17. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  18. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  19. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  20. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  21. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_without/__init__.py +0 -0
  22. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_without/module_1.py +0 -0
  23. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/package_without/module_2.py +0 -0
  24. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/standalone.py +0 -0
  25. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/modules/with_imports.py +0 -0
  26. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  27. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  28. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  29. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  30. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  31. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  32. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  33. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  34. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_aeventkit.py +0 -0
  35. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_altair.py +0 -0
  36. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_asyncio.py +0 -0
  37. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_atomicwrites.py +0 -0
  38. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_atools.py +0 -0
  39. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_cachetools.py +0 -0
  40. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_click.py +0 -0
  41. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_concurrent.py +0 -0
  42. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_contextlib.py +0 -0
  43. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_contextvars.py +0 -0
  44. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_cryptography.py +0 -0
  45. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_cvxpy.py +0 -0
  46. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_dataclasses.py +0 -0
  47. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_docker.py +0 -0
  48. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_enum.py +0 -0
  49. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_errors.py +0 -0
  50. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_fastapi.py +0 -0
  51. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_fpdf2.py +0 -0
  52. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_functions.py +0 -0
  53. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_functools.py +0 -0
  54. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_getpass.py +0 -0
  55. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_git.py +0 -0
  56. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_gzip.py +0 -0
  57. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_hashlib.py +0 -0
  58. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_http.py +0 -0
  59. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_hypothesis.py +0 -0
  60. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_importlib.py +0 -0
  61. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_inflect.py +0 -0
  62. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_ipython.py +0 -0
  63. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_iterables.py +0 -0
  64. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_jinja2.py +0 -0
  65. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_json.py +0 -0
  66. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_jupyter.py +0 -0
  67. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_libcst.py +0 -0
  68. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_lightweight_charts.py +0 -0
  69. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_logging.py +0 -0
  70. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_math.py +0 -0
  71. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_memory_profiler.py +0 -0
  72. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_modules.py +0 -0
  73. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_more_itertools.py +0 -0
  74. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_numpy.py +0 -0
  75. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_objects/__init__.py +0 -0
  76. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_objects/objects.py +0 -0
  77. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_operator.py +0 -0
  78. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_optuna.py +0 -0
  79. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_orjson.py +0 -0
  80. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_os.py +0 -0
  81. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_parse.py +0 -0
  82. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pathlib.py +0 -0
  83. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pickle.py +0 -0
  84. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_platform.py +0 -0
  85. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_polars.py +0 -0
  86. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_polars_ols.py +0 -0
  87. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_postgres.py +0 -0
  88. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pottery.py +0 -0
  89. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pqdm.py +0 -0
  90. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_psutil.py +0 -0
  91. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pydantic_settings.py +0 -0
  92. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pydantic_settings_sops.py +0 -0
  93. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pyinstrument.py +0 -0
  94. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pytest.py +0 -0
  95. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pytest_randomly.py +0 -0
  96. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_pytest_regressions.py +0 -0
  97. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_random.py +0 -0
  98. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_re.py +0 -0
  99. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_redis.py +0 -0
  100. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_reprlib.py +0 -0
  101. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_scipy.py +0 -0
  102. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_sentinel.py +0 -0
  103. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_shelve.py +0 -0
  104. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_slack_sdk.py +0 -0
  105. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_socket.py +0 -0
  106. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_sqlalchemy.py +0 -0
  107. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_sqlalchemy_polars.py +0 -0
  108. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_statsmodels.py +0 -0
  109. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_string.py +0 -0
  110. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_tempfile.py +0 -0
  111. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_testbook.py +0 -0
  112. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_text.py +0 -0
  113. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_threading.py +0 -0
  114. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_timer.py +0 -0
  115. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_traceback.py +0 -0
  116. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_types.py +0 -0
  117. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_typing.py +0 -0
  118. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_typing_funcs/__init__.py +0 -0
  119. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_typing_funcs/no_future.py +0 -0
  120. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_typing_funcs/with_future.py +0 -0
  121. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_tzdata.py +0 -0
  122. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_tzlocal.py +0 -0
  123. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_uuid.py +0 -0
  124. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_version.py +0 -0
  125. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_warnings.py +0 -0
  126. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_whenever.py +0 -0
  127. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_zipfile.py +0 -0
  128. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/tests/test_zoneinfo.py +0 -0
  129. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/aeventkit.py +0 -0
  130. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/altair.py +0 -0
  131. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/asyncio.py +0 -0
  132. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/atomicwrites.py +0 -0
  133. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/atools.py +0 -0
  134. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/cachetools.py +0 -0
  135. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/click.py +0 -0
  136. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/concurrent.py +0 -0
  137. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/contextlib.py +0 -0
  138. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/contextvars.py +0 -0
  139. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/cryptography.py +0 -0
  140. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/cvxpy.py +0 -0
  141. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/dataclasses.py +0 -0
  142. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/docker.py +0 -0
  143. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/enum.py +0 -0
  144. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/errors.py +0 -0
  145. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/fastapi.py +0 -0
  146. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/fpdf2.py +0 -0
  147. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/functions.py +0 -0
  148. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/functools.py +0 -0
  149. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/getpass.py +0 -0
  150. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/git.py +0 -0
  151. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/gzip.py +0 -0
  152. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/hashlib.py +0 -0
  153. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/http.py +0 -0
  154. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/hypothesis.py +0 -0
  155. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/importlib.py +0 -0
  156. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/inflect.py +0 -0
  157. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/ipython.py +0 -0
  158. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/iterables.py +0 -0
  159. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/jinja2.py +0 -0
  160. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/json.py +0 -0
  161. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/jupyter.py +0 -0
  162. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/libcst.py +0 -0
  163. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/lightweight_charts.py +0 -0
  164. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/logging.py +0 -0
  165. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/math.py +0 -0
  166. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/memory_profiler.py +0 -0
  167. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/modules.py +0 -0
  168. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/more_itertools.py +0 -0
  169. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/numpy.py +0 -0
  170. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/operator.py +0 -0
  171. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/optuna.py +0 -0
  172. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/orjson.py +0 -0
  173. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/os.py +0 -0
  174. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/parse.py +0 -0
  175. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pathlib.py +0 -0
  176. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pickle.py +0 -0
  177. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/platform.py +0 -0
  178. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/polars.py +0 -0
  179. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/polars_ols.py +0 -0
  180. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/postgres.py +0 -0
  181. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pottery.py +0 -0
  182. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pqdm.py +0 -0
  183. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/psutil.py +0 -0
  184. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/py.typed +0 -0
  185. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pydantic_settings.py +0 -0
  186. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pydantic_settings_sops.py +0 -0
  187. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pyinstrument.py +0 -0
  188. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pytest.py +0 -0
  189. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pytest_plugins/__init__.py +0 -0
  190. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
  191. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
  192. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/pytest_regressions.py +0 -0
  193. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/random.py +0 -0
  194. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/re.py +0 -0
  195. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/redis.py +0 -0
  196. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/reprlib.py +0 -0
  197. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/scipy.py +0 -0
  198. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/sentinel.py +0 -0
  199. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/shelve.py +0 -0
  200. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/slack_sdk.py +0 -0
  201. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/socket.py +0 -0
  202. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/sqlalchemy.py +0 -0
  203. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/sqlalchemy_polars.py +0 -0
  204. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/statsmodels.py +0 -0
  205. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/string.py +0 -0
  206. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/tempfile.py +0 -0
  207. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/testbook.py +0 -0
  208. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/text.py +0 -0
  209. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/threading.py +0 -0
  210. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/timer.py +0 -0
  211. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/traceback.py +0 -0
  212. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/types.py +0 -0
  213. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/typing.py +0 -0
  214. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/tzdata.py +0 -0
  215. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/tzlocal.py +0 -0
  216. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/uuid.py +0 -0
  217. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/version.py +0 -0
  218. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/warnings.py +0 -0
  219. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/whenever.py +0 -0
  220. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/zipfile.py +0 -0
  221. {dycw_utilities-0.168.3 → dycw_utilities-0.168.4}/src/utilities/zoneinfo.py +0 -0
@@ -1,22 +1,22 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.168.3
3
+ Version: 0.168.4
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
7
7
  Requires-Dist: atomicwrites<1.5,>=1.4.1
8
8
  Requires-Dist: typing-extensions<4.16,>=4.15.0
9
9
  Requires-Dist: tzlocal<5.4,>=5.3.1
10
- Requires-Dist: whenever<0.10,>=0.9.0
10
+ Requires-Dist: whenever<0.10,>=0.9.2
11
11
  Provides-Extra: logging
12
12
  Requires-Dist: coloredlogs<15.1,>=15.0.1; extra == 'logging'
13
13
  Provides-Extra: test
14
14
  Requires-Dist: dycw-pytest-only<2.2,>=2.1.1; extra == 'test'
15
- Requires-Dist: hypothesis<6.141,>=6.140.2; extra == 'test'
15
+ Requires-Dist: hypothesis<6.141,>=6.140.3; extra == 'test'
16
16
  Requires-Dist: pytest-asyncio<1.3,>=1.2.0; extra == 'test'
17
17
  Requires-Dist: pytest-cov<7.1,>=7.0.0; extra == 'test'
18
18
  Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
19
- Requires-Dist: pytest-lazy-fixtures<1.4,>=1.3.4; extra == 'test'
19
+ Requires-Dist: pytest-lazy-fixtures<1.5,>=1.4.0; extra == 'test'
20
20
  Requires-Dist: pytest-randomly<4.1,>=4.0.1; extra == 'test'
21
21
  Requires-Dist: pytest-regressions<2.9,>=2.8.3; extra == 'test'
22
22
  Requires-Dist: pytest-repeat<0.10,>=0.9.4; extra == 'test'
@@ -31,10 +31,10 @@ core = [
31
31
  "atomicwrites >=1.4.1, <1.5",
32
32
  "typing-extensions >=4.15.0, <4.16",
33
33
  "tzlocal >=5.3.1, <5.4",
34
- "whenever >=0.9.0, <0.10",
34
+ "whenever >=0.9.2, <0.10",
35
35
  ]
36
36
  cryptography = [
37
- "cryptography >=46.0.1, <46.1",
37
+ "cryptography >=46.0.2, <46.1",
38
38
  ]
39
39
  cvxpy = [
40
40
  "cvxpy >=1.7.3, <1.8",
@@ -52,7 +52,7 @@ dev = [
52
52
  "pytest-timeout >=2.4.0, <2.5",
53
53
  ]
54
54
  fastapi = [
55
- "fastapi >=0.117.1, <0.118",
55
+ "fastapi >=0.118.0, <0.119",
56
56
  ]
57
57
  fastapi-test = [
58
58
  "httpx",
@@ -71,7 +71,7 @@ http-test = [
71
71
  "orjson",
72
72
  ]
73
73
  hypothesis = [
74
- "hypothesis >=6.140.2, <6.141",
74
+ "hypothesis >=6.140.3, <6.141",
75
75
  ]
76
76
  hypothesis-test = [
77
77
  "libcst",
@@ -124,7 +124,7 @@ orjson-test = [
124
124
  "polars",
125
125
  ]
126
126
  polars = [
127
- "polars >=1.33.1, <1.34",
127
+ "polars >=1.34.0, <1.35",
128
128
  ]
129
129
  polars-ols = [
130
130
  "polars-ols >=0.3.5, <0.4",
@@ -198,7 +198,7 @@ sklearn = [
198
198
  "scikit-learn >=1.7.2, <1.8",
199
199
  ]
200
200
  slack-sdk = [
201
- "slack-sdk >=3.36.0, <3.37",
201
+ "slack-sdk >=3.37.0, <3.38",
202
202
  ]
203
203
  slack-sdk-test = [
204
204
  "aiohttp",
@@ -227,9 +227,6 @@ statsmodels = [
227
227
  testbook = [
228
228
  "testbook >=0.4.2, <0.5",
229
229
  ]
230
- typed-settings = [
231
- "typed-settings >=25.0.0, <25.1",
232
- ]
233
230
  tzdata = [
234
231
  "tzdata >=2025.2, <2025.3",
235
232
  ]
@@ -244,12 +241,12 @@ dependencies = [
244
241
  "atomicwrites >=1.4.1, <1.5",
245
242
  "typing-extensions >=4.15.0, <4.16",
246
243
  "tzlocal >=5.3.1, <5.4",
247
- "whenever >=0.9.0, <0.10",
244
+ "whenever >=0.9.2, <0.10",
248
245
  ]
249
246
  name = "dycw-utilities"
250
247
  readme = "README.md"
251
248
  requires-python = ">= 3.12"
252
- version = "0.168.3"
249
+ version = "0.168.4"
253
250
 
254
251
  [project.entry-points.pytest11]
255
252
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -261,12 +258,12 @@ logging = [
261
258
  ]
262
259
  test = [
263
260
  "dycw-pytest-only >=2.1.1, <2.2",
264
- "hypothesis >=6.140.2, <6.141",
261
+ "hypothesis >=6.140.3, <6.141",
265
262
  "pytest >=8.4.2, <8.5",
266
263
  "pytest-asyncio >=1.2.0, <1.3",
267
264
  "pytest-cov >=7.0.0, <7.1",
268
265
  "pytest-instafail >=0.5.0, <0.6",
269
- "pytest-lazy-fixtures >=1.3.4, <1.4",
266
+ "pytest-lazy-fixtures >=1.4.0, <1.5",
270
267
  "pytest-randomly >=4.0.1, <4.1",
271
268
  "pytest-regressions >=2.8.3, <2.9",
272
269
  "pytest-repeat >=0.9.4, <0.10",
@@ -282,7 +279,7 @@ test = [
282
279
  # bump-my-version
283
280
  [tool.bumpversion]
284
281
  allow_dirty = true
285
- current_version = "0.168.3"
282
+ current_version = "0.168.4"
286
283
 
287
284
  [[tool.bumpversion.files]]
288
285
  filename = "src/utilities/__init__.py"
@@ -486,7 +483,6 @@ select = [
486
483
  "S101", # assert
487
484
  "SLF001", # private-member-access
488
485
  ]
489
- "src/tests/test_typed_settings.py" = ["I002"] # missing-required-import
490
486
  "src/tests/test_typing_funcs/no_future.py" = ["I002"] # missing-required-import
491
487
 
492
488
  [tool.ruff.lint.flake8-tidy-imports]
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.168.3"
3
+ __version__ = "0.168.4"
@@ -1,321 +0,0 @@
1
- from collections.abc import Callable
2
- from dataclasses import dataclass
3
- from ipaddress import IPv4Address, IPv6Address
4
- from pathlib import Path
5
- from typing import Any, ClassVar, Self, assert_never, override
6
- from uuid import UUID
7
-
8
- import typed_settings
9
- from hypothesis import given
10
- from hypothesis.strategies import (
11
- DataObject,
12
- SearchStrategy,
13
- booleans,
14
- data,
15
- integers,
16
- ip_addresses,
17
- sampled_from,
18
- tuples,
19
- uuids,
20
- )
21
- from pytest import mark, param, raises
22
- from typed_settings import EnvLoader, FileLoader, TomlFormat
23
- from whenever import (
24
- Date,
25
- DateDelta,
26
- DateTimeDelta,
27
- MonthDay,
28
- PlainDateTime,
29
- Time,
30
- TimeDelta,
31
- YearMonth,
32
- ZonedDateTime,
33
- )
34
-
35
- from utilities.hypothesis import (
36
- date_deltas,
37
- date_time_deltas,
38
- dates,
39
- month_days,
40
- paths,
41
- plain_date_times,
42
- temp_paths,
43
- text_ascii,
44
- time_deltas,
45
- times,
46
- year_months,
47
- zoned_date_times,
48
- )
49
- from utilities.os import temp_environ
50
- from utilities.re import extract_group
51
- from utilities.sentinel import Sentinel, sentinel
52
- from utilities.text import strip_and_dedent
53
- from utilities.typed_settings import (
54
- ExtendedTSConverter,
55
- LoadSettingsError,
56
- load_settings,
57
- )
58
-
59
- app_names = text_ascii(min_size=1).map(str.lower)
60
-
61
-
62
- @dataclass(kw_only=True, slots=True)
63
- class _Case[T]:
64
- cls: type[T]
65
- strategy: SearchStrategy[T]
66
- serialize: Callable[[T], str]
67
-
68
-
69
- class TestExtendedTSConverter:
70
- cases: ClassVar[list[_Case]] = [
71
- _Case(cls=Date, strategy=dates(), serialize=str),
72
- _Case(cls=DateDelta, strategy=date_deltas(parsable=True), serialize=str),
73
- _Case(
74
- cls=DateTimeDelta, strategy=date_time_deltas(parsable=True), serialize=str
75
- ),
76
- _Case(cls=IPv4Address, strategy=ip_addresses(v=4), serialize=str),
77
- _Case(cls=IPv6Address, strategy=ip_addresses(v=6), serialize=str),
78
- _Case(cls=MonthDay, strategy=month_days(), serialize=str),
79
- _Case(cls=PlainDateTime, strategy=plain_date_times(), serialize=str),
80
- _Case(cls=Time, strategy=times(), serialize=str),
81
- _Case(cls=TimeDelta, strategy=time_deltas(), serialize=str),
82
- _Case(cls=UUID, strategy=uuids(), serialize=str),
83
- _Case(cls=YearMonth, strategy=year_months(), serialize=str),
84
- _Case(cls=ZonedDateTime, strategy=zoned_date_times(), serialize=str),
85
- ]
86
-
87
- @given(data=data())
88
- @mark.parametrize(("cls", "strategy"), [param(c.cls, c.strategy) for c in cases])
89
- def test_default(
90
- self, *, data: DataObject, cls: type[Any], strategy: SearchStrategy[Any]
91
- ) -> None:
92
- default = data.draw(strategy)
93
-
94
- @dataclass(frozen=True, kw_only=True, slots=True)
95
- class Settings:
96
- value: cls = default # pyright: ignore[reportInvalidTypeForm]
97
-
98
- loaded = typed_settings.load_settings(
99
- Settings, loaders=[], converter=ExtendedTSConverter()
100
- )
101
- assert loaded.value == default
102
-
103
- @given(data=data(), root=temp_paths(), app_name=app_names)
104
- @mark.parametrize(
105
- ("cls", "strategy", "serialize"),
106
- [param(c.cls, c.strategy, c.serialize) for c in cases],
107
- )
108
- def test_loaded(
109
- self,
110
- *,
111
- data: DataObject,
112
- root: Path,
113
- app_name: str,
114
- cls: type[Any],
115
- strategy: SearchStrategy[Any],
116
- serialize: Callable[[Any], str],
117
- ) -> None:
118
- default, value = data.draw(tuples(strategy, strategy))
119
-
120
- @dataclass(frozen=True, kw_only=True, slots=True)
121
- class Settings:
122
- value: cls = default # pyright: ignore[reportInvalidTypeForm]
123
-
124
- file = Path(root, "file.toml")
125
- _ = file.write_text(
126
- strip_and_dedent(f"""
127
- [{app_name}]
128
- value = '{serialize(value)}'
129
- """)
130
- )
131
- loaded = typed_settings.load_settings(
132
- Settings,
133
- loaders=[
134
- FileLoader(formats={"*.toml": TomlFormat(app_name)}, files=[file])
135
- ],
136
- converter=ExtendedTSConverter(),
137
- )
138
- assert loaded.value == value
139
-
140
- @given(
141
- root=temp_paths(),
142
- app_name=app_names,
143
- env_name=text_ascii(min_size=1).map(lambda text: f"TEST_{text}".upper()),
144
- env_value=text_ascii(min_size=1),
145
- )
146
- def test_path_env_var(
147
- self, *, root: str, app_name: str, env_name: str, env_value: str
148
- ) -> None:
149
- @dataclass(frozen=True, kw_only=True, slots=True)
150
- class Settings:
151
- value: Path
152
-
153
- file = Path(root, "file.toml")
154
- _ = file.write_text(
155
- strip_and_dedent(f"""
156
- [{app_name}]
157
- value = '${env_name}'
158
- """)
159
- )
160
- with temp_environ({env_name: env_value}):
161
- settings = typed_settings.load_settings(
162
- Settings,
163
- loaders=[
164
- FileLoader(formats={"*.toml": TomlFormat(app_name)}, files=[file])
165
- ],
166
- converter=ExtendedTSConverter(resolve_paths=False),
167
- )
168
- expected = Path(env_value)
169
- assert settings.value == expected
170
-
171
- @given(root=temp_paths(), app_name=app_names, path=paths(), resolve=booleans())
172
- def test_path_resolution(
173
- self, *, root: str, app_name: str, path: Path, resolve: bool
174
- ) -> None:
175
- @dataclass(frozen=True, kw_only=True, slots=True)
176
- class Settings:
177
- value: Path
178
-
179
- file = Path(root, "file.toml")
180
- _ = file.write_text(
181
- strip_and_dedent(f"""
182
- [{app_name}]
183
- value = '{path!s}'
184
- """)
185
- )
186
- settings = typed_settings.load_settings(
187
- Settings,
188
- loaders=[
189
- FileLoader(formats={"*.toml": TomlFormat(app_name)}, files=[file])
190
- ],
191
- converter=ExtendedTSConverter(resolve_paths=resolve),
192
- )
193
- match resolve:
194
- case True:
195
- expected = Path.cwd().joinpath(path)
196
- case False:
197
- expected = Path(path)
198
- case never:
199
- assert_never(never)
200
- assert settings.value == expected
201
-
202
-
203
- class TestLoadSettings:
204
- @given(root=temp_paths(), date_time=zoned_date_times(), app_name=app_names)
205
- def test_main(self, *, root: Path, date_time: ZonedDateTime, app_name: str) -> None:
206
- @dataclass(frozen=True, kw_only=True, slots=True)
207
- class Settings:
208
- date_time: ZonedDateTime
209
-
210
- file = root.joinpath("settings.toml")
211
- _ = file.write_text(
212
- strip_and_dedent(f"""
213
- [{app_name}]
214
- date_time = {str(date_time)!r}
215
- """)
216
- )
217
- settings = load_settings(Settings, app_name, start_dir=root)
218
- assert settings.date_time == date_time
219
-
220
- @given(
221
- prefix=app_names.map(lambda text: f"TEST_{text}".upper()),
222
- date_time=zoned_date_times(),
223
- app_name=app_names,
224
- )
225
- def test_loaders(
226
- self, *, prefix: str, date_time: ZonedDateTime, app_name: str
227
- ) -> None:
228
- key = f"{prefix}__DATE_TIME"
229
-
230
- @dataclass(frozen=True, kw_only=True, slots=True)
231
- class Settings:
232
- date_time: ZonedDateTime
233
-
234
- with temp_environ({key: str(date_time)}):
235
- settings = load_settings(
236
- Settings, app_name, loaders=[EnvLoader(prefix=f"{prefix}__")]
237
- )
238
- assert settings.date_time == date_time
239
-
240
- @given(root=temp_paths(), app_name=app_names)
241
- def test_converter_simple(self, *, root: Path, app_name: str) -> None:
242
- @dataclass(frozen=True, kw_only=True, slots=True)
243
- class Settings:
244
- sentinel: Sentinel
245
-
246
- file = root.joinpath("settings.toml")
247
- _ = file.write_text(
248
- strip_and_dedent(f"""
249
- [{app_name}]
250
- sentinel = 'sentinel'
251
- """)
252
- )
253
-
254
- def convert(text: str, /) -> Sentinel:
255
- if text == "sentinel":
256
- return sentinel
257
- raise ValueError
258
-
259
- settings = load_settings(
260
- Settings, app_name, start_dir=root, converters=[(Sentinel, convert)]
261
- )
262
- assert settings.sentinel is sentinel
263
-
264
- @given(data=data(), root=temp_paths(), n=integers(), app_name=app_names)
265
- def test_converter_dataclass(
266
- self, *, data: DataObject, root: Path, n: int, app_name: str
267
- ) -> None:
268
- @dataclass(repr=False, frozen=True, kw_only=True, slots=True)
269
- class Left:
270
- x: int
271
-
272
- @override
273
- def __str__(self) -> str:
274
- return f"left{self.x}"
275
-
276
- @classmethod
277
- def parse(cls, text: str, /) -> Self:
278
- x = extract_group(r"^left(.+?)$", text)
279
- return cls(x=int(x))
280
-
281
- @dataclass(frozen=True, kw_only=True, slots=True)
282
- class Right:
283
- y: int
284
-
285
- @override
286
- def __str__(self) -> str:
287
- return f"right{self.y}"
288
-
289
- @classmethod
290
- def parse(cls, text: str, /) -> Self:
291
- y = extract_group(r"^right(.+?)$", text)
292
- return cls(y=int(y))
293
-
294
- value = data.draw(sampled_from([Left(x=n), Right(y=n)]))
295
-
296
- @dataclass(frozen=True, kw_only=True, slots=True)
297
- class Settings:
298
- inner: Left | Right
299
-
300
- file = root.joinpath("settings.toml")
301
- _ = file.write_text(
302
- strip_and_dedent(f"""
303
- [{app_name}]
304
- inner = {str(value)!r}
305
- """)
306
- )
307
- settings = load_settings(
308
- Settings,
309
- app_name,
310
- start_dir=root,
311
- converters=[(Left, Left.parse), (Right, Right.parse)],
312
- )
313
- assert settings.inner == value
314
-
315
- @mark.parametrize("app_name", [param("app_"), param("app1"), param("app__name")])
316
- def test_error(self, *, app_name: str) -> None:
317
- @dataclass(frozen=True, kw_only=True, slots=True)
318
- class Settings: ...
319
-
320
- with raises(LoadSettingsError, match=r"Invalid app name; got '.+'"):
321
- _ = load_settings(Settings, app_name)
@@ -1,152 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from dataclasses import dataclass
4
- from functools import partial
5
- from ipaddress import IPv4Address, IPv6Address
6
- from os import environ
7
- from pathlib import Path
8
- from re import search
9
- from typing import TYPE_CHECKING, Any, assert_never, override
10
- from uuid import UUID
11
-
12
- import typed_settings
13
- from typed_settings import EnvLoader, FileLoader, find
14
- from typed_settings.converters import TSConverter
15
- from typed_settings.loaders import TomlFormat
16
- from whenever import (
17
- Date,
18
- DateDelta,
19
- DateTimeDelta,
20
- MonthDay,
21
- PlainDateTime,
22
- Time,
23
- TimeDelta,
24
- YearMonth,
25
- ZonedDateTime,
26
- )
27
-
28
- from utilities.iterables import always_iterable
29
- from utilities.pathlib import to_path
30
- from utilities.string import substitute_environ
31
-
32
- if TYPE_CHECKING:
33
- from collections.abc import Callable, Iterable
34
-
35
- from typed_settings.loaders import Loader
36
- from typed_settings.processors import Processor
37
-
38
- from utilities.types import MaybeCallablePathLike, MaybeIterable, PathLike
39
-
40
-
41
- type _ConverterItem = tuple[type[Any], Callable[..., Any]]
42
-
43
-
44
- ##
45
-
46
-
47
- class ExtendedTSConverter(TSConverter):
48
- """An extension of the TSConverter for custom types."""
49
-
50
- @override
51
- def __init__(
52
- self,
53
- *,
54
- resolve_paths: bool = True,
55
- strlist_sep: str | Callable[[str], list] | None = ":",
56
- extra: Iterable[_ConverterItem] = (),
57
- ) -> None:
58
- super().__init__(resolve_paths=resolve_paths, strlist_sep=strlist_sep)
59
- cases: list[_ConverterItem] = [
60
- (Date, Date.parse_iso),
61
- (DateDelta, DateDelta.parse_iso),
62
- (DateTimeDelta, DateTimeDelta.parse_iso),
63
- (IPv4Address, IPv4Address),
64
- (IPv6Address, IPv6Address),
65
- (MonthDay, MonthDay.parse_iso),
66
- (Path, partial(_parse_path, resolve=resolve_paths, pwd=Path.cwd())),
67
- (PlainDateTime, PlainDateTime.parse_iso),
68
- (Time, Time.parse_iso),
69
- (TimeDelta, TimeDelta.parse_iso),
70
- (UUID, UUID),
71
- (YearMonth, YearMonth.parse_iso),
72
- (ZonedDateTime, ZonedDateTime.parse_iso),
73
- *extra,
74
- ]
75
- extras = {cls: _make_converter(cls, func) for cls, func in cases}
76
- self.scalar_converters |= extras
77
-
78
-
79
- def _make_converter[T](
80
- cls: type[T], parser: Callable[[str], T], /
81
- ) -> Callable[[Any, type[Any]], Any]:
82
- def hook(value: T | str, _: type[T] = cls, /) -> Any:
83
- if not isinstance(value, (cls, str)): # pragma: no cover
84
- msg = f"Invalid type {type(value).__name__!r}; expected '{cls.__name__}' or 'str'"
85
- raise TypeError(msg)
86
- if isinstance(value, str):
87
- return parser(value)
88
- return value
89
-
90
- return hook
91
-
92
-
93
- def _parse_path(
94
- path: str, /, *, resolve: bool = False, pwd: MaybeCallablePathLike = Path.cwd
95
- ) -> Path:
96
- path = substitute_environ(path, **environ)
97
- match resolve:
98
- case True:
99
- return to_path(pwd).joinpath(path).resolve()
100
- case False:
101
- return Path(path)
102
- case never:
103
- assert_never(never)
104
-
105
-
106
- ##
107
-
108
-
109
- _BASE_DIR: Path = Path()
110
-
111
-
112
- def load_settings[T](
113
- cls: type[T],
114
- app_name: str,
115
- /,
116
- *,
117
- filenames: MaybeIterable[str] = "settings.toml",
118
- start_dir: PathLike | None = None,
119
- loaders: MaybeIterable[Loader] | None = None,
120
- processors: MaybeIterable[Processor] = (),
121
- converters: Iterable[_ConverterItem] = (),
122
- base_dir: Path = _BASE_DIR,
123
- ) -> T:
124
- if not search(r"^[A-Za-z]+(?:_[A-Za-z]+)*$", app_name):
125
- raise LoadSettingsError(appname=app_name)
126
- filenames_use = list(always_iterable(filenames))
127
- start_dir_use = None if start_dir is None else Path(start_dir)
128
- files = [find(filename, start_dir=start_dir_use) for filename in filenames_use]
129
- file_loader = FileLoader(formats={"*.toml": TomlFormat(app_name)}, files=files)
130
- env_loader = EnvLoader(f"{app_name.upper()}__", nested_delimiter="__")
131
- loaders_use: list[Loader] = [file_loader, env_loader]
132
- if loaders is not None:
133
- loaders_use.extend(always_iterable(loaders))
134
- return typed_settings.load_settings(
135
- cls,
136
- loaders_use,
137
- processors=list(always_iterable(processors)),
138
- converter=ExtendedTSConverter(extra=converters),
139
- base_dir=base_dir,
140
- )
141
-
142
-
143
- @dataclass(kw_only=True, slots=True)
144
- class LoadSettingsError(Exception):
145
- appname: str
146
-
147
- @override
148
- def __str__(self) -> str:
149
- return f"Invalid app name; got {self.appname!r}"
150
-
151
-
152
- __all__ = ["ExtendedTSConverter", "LoadSettingsError", "load_settings"]