dycw-utilities 0.168.1__tar.gz → 0.168.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/PKG-INFO +1 -1
  2. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/pyproject.toml +2 -2
  3. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_logging.py +2 -0
  4. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pydantic_settings.py +125 -4
  5. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/__init__.py +1 -1
  6. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pydantic_settings.py +77 -7
  7. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/.gitignore +0 -0
  8. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/LICENSE +0 -0
  9. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/README.md +0 -0
  10. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/__init__.py +0 -0
  11. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/conftest.py +0 -0
  12. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/__init__.py +0 -0
  13. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_missing/__init__.py +0 -0
  14. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_missing/module.py +0 -0
  15. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_with/__init__.py +0 -0
  16. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_with/outer_1.py +0 -0
  17. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_with/outer_2.py +0 -0
  18. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  19. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  20. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  21. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  22. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_without/__init__.py +0 -0
  23. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_without/module_1.py +0 -0
  24. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/package_without/module_2.py +0 -0
  25. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/standalone.py +0 -0
  26. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/modules/with_imports.py +0 -0
  27. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  28. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  29. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  30. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  31. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  32. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  33. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  34. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  35. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_aeventkit.py +0 -0
  36. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_altair.py +0 -0
  37. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_asyncio.py +0 -0
  38. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_atomicwrites.py +0 -0
  39. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_atools.py +0 -0
  40. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_cachetools.py +0 -0
  41. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_click.py +0 -0
  42. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_concurrent.py +0 -0
  43. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_contextlib.py +0 -0
  44. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_contextvars.py +0 -0
  45. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_cryptography.py +0 -0
  46. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_cvxpy.py +0 -0
  47. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_dataclasses.py +0 -0
  48. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_docker.py +0 -0
  49. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_enum.py +0 -0
  50. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_errors.py +0 -0
  51. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_fastapi.py +0 -0
  52. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_fpdf2.py +0 -0
  53. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_functions.py +0 -0
  54. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_functools.py +0 -0
  55. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_getpass.py +0 -0
  56. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_git.py +0 -0
  57. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_gzip.py +0 -0
  58. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_hashlib.py +0 -0
  59. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_http.py +0 -0
  60. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_hypothesis.py +0 -0
  61. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_importlib.py +0 -0
  62. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_inflect.py +0 -0
  63. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_ipython.py +0 -0
  64. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_iterables.py +0 -0
  65. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_jinja2.py +0 -0
  66. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_json.py +0 -0
  67. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_jupyter.py +0 -0
  68. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_libcst.py +0 -0
  69. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_lightweight_charts.py +0 -0
  70. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_math.py +0 -0
  71. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_memory_profiler.py +0 -0
  72. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_modules.py +0 -0
  73. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_more_itertools.py +0 -0
  74. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_numpy.py +0 -0
  75. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_objects/__init__.py +0 -0
  76. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_objects/objects.py +0 -0
  77. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_operator.py +0 -0
  78. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_optuna.py +0 -0
  79. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_orjson.py +0 -0
  80. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_os.py +0 -0
  81. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_parse.py +0 -0
  82. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pathlib.py +0 -0
  83. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pickle.py +0 -0
  84. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_platform.py +0 -0
  85. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_polars.py +0 -0
  86. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_polars_ols.py +0 -0
  87. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_postgres.py +0 -0
  88. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pottery.py +0 -0
  89. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pqdm.py +0 -0
  90. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_psutil.py +0 -0
  91. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pydantic_settings_sops.py +0 -0
  92. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pyinstrument.py +0 -0
  93. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pytest.py +0 -0
  94. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pytest_randomly.py +0 -0
  95. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_pytest_regressions.py +0 -0
  96. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_random.py +0 -0
  97. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_re.py +0 -0
  98. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_redis.py +0 -0
  99. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_reprlib.py +0 -0
  100. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_scipy.py +0 -0
  101. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_sentinel.py +0 -0
  102. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_shelve.py +0 -0
  103. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_slack_sdk.py +0 -0
  104. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_socket.py +0 -0
  105. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_sqlalchemy.py +0 -0
  106. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_sqlalchemy_polars.py +0 -0
  107. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_statsmodels.py +0 -0
  108. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_string.py +0 -0
  109. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_tempfile.py +0 -0
  110. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_testbook.py +0 -0
  111. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_text.py +0 -0
  112. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_threading.py +0 -0
  113. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_timer.py +0 -0
  114. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_traceback.py +0 -0
  115. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_typed_settings.py +0 -0
  116. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_types.py +0 -0
  117. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_typing.py +0 -0
  118. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_typing_funcs/__init__.py +0 -0
  119. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_typing_funcs/no_future.py +0 -0
  120. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_typing_funcs/with_future.py +0 -0
  121. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_tzdata.py +0 -0
  122. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_tzlocal.py +0 -0
  123. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_uuid.py +0 -0
  124. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_version.py +0 -0
  125. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_warnings.py +0 -0
  126. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_whenever.py +0 -0
  127. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_zipfile.py +0 -0
  128. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/tests/test_zoneinfo.py +0 -0
  129. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/aeventkit.py +0 -0
  130. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/altair.py +0 -0
  131. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/asyncio.py +0 -0
  132. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/atomicwrites.py +0 -0
  133. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/atools.py +0 -0
  134. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/cachetools.py +0 -0
  135. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/click.py +0 -0
  136. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/concurrent.py +0 -0
  137. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/contextlib.py +0 -0
  138. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/contextvars.py +0 -0
  139. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/cryptography.py +0 -0
  140. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/cvxpy.py +0 -0
  141. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/dataclasses.py +0 -0
  142. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/docker.py +0 -0
  143. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/enum.py +0 -0
  144. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/errors.py +0 -0
  145. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/fastapi.py +0 -0
  146. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/fpdf2.py +0 -0
  147. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/functions.py +0 -0
  148. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/functools.py +0 -0
  149. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/getpass.py +0 -0
  150. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/git.py +0 -0
  151. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/gzip.py +0 -0
  152. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/hashlib.py +0 -0
  153. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/http.py +0 -0
  154. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/hypothesis.py +0 -0
  155. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/importlib.py +0 -0
  156. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/inflect.py +0 -0
  157. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/ipython.py +0 -0
  158. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/iterables.py +0 -0
  159. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/jinja2.py +0 -0
  160. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/json.py +0 -0
  161. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/jupyter.py +0 -0
  162. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/libcst.py +0 -0
  163. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/lightweight_charts.py +0 -0
  164. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/logging.py +0 -0
  165. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/math.py +0 -0
  166. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/memory_profiler.py +0 -0
  167. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/modules.py +0 -0
  168. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/more_itertools.py +0 -0
  169. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/numpy.py +0 -0
  170. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/operator.py +0 -0
  171. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/optuna.py +0 -0
  172. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/orjson.py +0 -0
  173. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/os.py +0 -0
  174. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/parse.py +0 -0
  175. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pathlib.py +0 -0
  176. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pickle.py +0 -0
  177. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/platform.py +0 -0
  178. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/polars.py +0 -0
  179. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/polars_ols.py +0 -0
  180. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/postgres.py +0 -0
  181. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pottery.py +0 -0
  182. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pqdm.py +0 -0
  183. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/psutil.py +0 -0
  184. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/py.typed +0 -0
  185. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pydantic_settings_sops.py +0 -0
  186. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pyinstrument.py +0 -0
  187. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pytest.py +0 -0
  188. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pytest_plugins/__init__.py +0 -0
  189. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
  190. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
  191. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/pytest_regressions.py +0 -0
  192. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/random.py +0 -0
  193. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/re.py +0 -0
  194. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/redis.py +0 -0
  195. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/reprlib.py +0 -0
  196. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/scipy.py +0 -0
  197. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/sentinel.py +0 -0
  198. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/shelve.py +0 -0
  199. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/slack_sdk.py +0 -0
  200. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/socket.py +0 -0
  201. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/sqlalchemy.py +0 -0
  202. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/sqlalchemy_polars.py +0 -0
  203. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/statsmodels.py +0 -0
  204. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/string.py +0 -0
  205. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/tempfile.py +0 -0
  206. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/testbook.py +0 -0
  207. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/text.py +0 -0
  208. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/threading.py +0 -0
  209. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/timer.py +0 -0
  210. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/traceback.py +0 -0
  211. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/typed_settings.py +0 -0
  212. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/types.py +0 -0
  213. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/typing.py +0 -0
  214. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/tzdata.py +0 -0
  215. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/tzlocal.py +0 -0
  216. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/uuid.py +0 -0
  217. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/version.py +0 -0
  218. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/warnings.py +0 -0
  219. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/whenever.py +0 -0
  220. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/zipfile.py +0 -0
  221. {dycw_utilities-0.168.1 → dycw_utilities-0.168.3}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.168.1
3
+ Version: 0.168.3
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -249,7 +249,7 @@ dependencies = [
249
249
  name = "dycw-utilities"
250
250
  readme = "README.md"
251
251
  requires-python = ">= 3.12"
252
- version = "0.168.1"
252
+ version = "0.168.3"
253
253
 
254
254
  [project.entry-points.pytest11]
255
255
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -282,7 +282,7 @@ test = [
282
282
  # bump-my-version
283
283
  [tool.bumpversion]
284
284
  allow_dirty = true
285
- current_version = "0.168.1"
285
+ current_version = "0.168.3"
286
286
 
287
287
  [[tool.bumpversion.files]]
288
288
  filename = "src/utilities/__init__.py"
@@ -449,10 +449,12 @@ class TestSizeAndTimeRotatingFileHandler:
449
449
  )
450
450
  )
451
451
 
452
+ await sleep(0.1)
452
453
  files = list(tmp_path.iterdir())
453
454
  assert len(files) == 1
454
455
  assert any(p for p in files if search(r"^log\.txt$", p.name))
455
456
 
457
+ await sleep(0.1)
456
458
  logger.warning("message 1")
457
459
  files = list(tmp_path.iterdir())
458
460
  assert len(files) == 1
@@ -1,15 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ from stat import S_IXUSR
5
+ from subprocess import STDOUT, CalledProcessError, check_output
4
6
  from typing import TYPE_CHECKING, ClassVar
5
7
 
6
8
  import tomlkit
7
9
  import yaml
8
10
  from pydantic_settings import BaseSettings, SettingsConfigDict
11
+ from pytest import mark, param
9
12
 
13
+ from tests.conftest import SKIPIF_CI_AND_WINDOWS
10
14
  from utilities.os import temp_environ
11
15
  from utilities.pydantic_settings import (
12
16
  CustomBaseSettings,
17
+ HashableBaseSettings,
13
18
  PathLikeOrWithSection,
14
19
  load_settings,
15
20
  )
@@ -101,11 +106,12 @@ class TestCustomBaseSettings:
101
106
  settings = load_settings(Settings)
102
107
  assert settings.x == 1
103
108
 
104
- def test_env_var_with_nested(self) -> None:
109
+ @mark.parametrize("inner_cls", [param(BaseSettings), param(HashableBaseSettings)])
110
+ def test_env_var_with_nested(self, *, inner_cls: type[BaseSettings]) -> None:
105
111
  class Settings(CustomBaseSettings):
106
112
  inner: Inner
107
113
 
108
- class Inner(BaseSettings):
114
+ class Inner(inner_cls):
109
115
  x: int
110
116
 
111
117
  _ = Settings.model_rebuild()
@@ -114,12 +120,15 @@ class TestCustomBaseSettings:
114
120
  settings = load_settings(Settings)
115
121
  assert settings.inner.x == 1
116
122
 
117
- def test_env_var_with_prefix_and_nested(self) -> None:
123
+ @mark.parametrize("inner_cls", [param(BaseSettings), param(HashableBaseSettings)])
124
+ def test_env_var_with_prefix_and_nested(
125
+ self, *, inner_cls: type[BaseSettings]
126
+ ) -> None:
118
127
  class Settings(CustomBaseSettings):
119
128
  model_config = SettingsConfigDict(env_prefix="test__")
120
129
  inner: Inner
121
130
 
122
- class Inner(BaseSettings):
131
+ class Inner(inner_cls):
123
132
  x: int
124
133
 
125
134
  _ = Settings.model_rebuild()
@@ -131,3 +140,115 @@ class TestCustomBaseSettings:
131
140
  class Settings(CustomBaseSettings): ...
132
141
 
133
142
  _ = load_settings(Settings)
143
+
144
+
145
+ class TestHashableBaseSettings:
146
+ def test_hashable(self) -> None:
147
+ class Settings(HashableBaseSettings):
148
+ x: int = 1
149
+
150
+ settings = load_settings(Settings)
151
+ _ = hash(settings)
152
+
153
+
154
+ class TestLoadSettings:
155
+ @mark.parametrize(
156
+ ("args", "expected"),
157
+ [
158
+ param([], "settings=_Settings(a=1, b=2, inner=_Inner(c=3, d=4))"),
159
+ param(["-a", "5"], "settings=_Settings(a=5, b=2, inner=_Inner(c=3, d=4))"),
160
+ param(
161
+ ["--inner.c", "5"],
162
+ "settings=_Settings(a=1, b=2, inner=_Inner(c=5, d=4))",
163
+ ),
164
+ param(
165
+ ["-h"],
166
+ """
167
+ usage: script.py [-h] [-a int] [-b int] [--inner [JSON]] [--inner.c int]
168
+ [--inner.d int]
169
+
170
+ options:
171
+ -h, --help show this help message and exit
172
+ -a int (default: 1)
173
+ -b int (default: 2)
174
+
175
+ inner options:
176
+ --inner [JSON] set inner from JSON string (default: {})
177
+ --inner.c int (default: 3)
178
+ --inner.d int (default: 4)
179
+ """,
180
+ ),
181
+ ],
182
+ )
183
+ @SKIPIF_CI_AND_WINDOWS
184
+ def test_cli(self, *, tmp_path: Path, args: list[str], expected: str) -> None:
185
+ script = tmp_path.joinpath("script.py")
186
+ _ = script.write_text("""\
187
+ #!/usr/bin/env python3
188
+ from __future__ import annotations
189
+
190
+ from collections.abc import Sequence
191
+ from pathlib import Path
192
+ from typing import ClassVar
193
+
194
+ from pydantic_settings import BaseSettings
195
+
196
+ from utilities.pydantic_settings import CustomBaseSettings, PathLikeOrWithSection, load_settings
197
+
198
+ class _Settings(CustomBaseSettings):
199
+ toml_files: ClassVar[Sequence[PathLikeOrWithSection]] = [
200
+ Path(__file__).parent.joinpath("config.toml")
201
+ ]
202
+
203
+ a: int
204
+ b: int
205
+ inner: _Inner
206
+
207
+ class _Inner(BaseSettings):
208
+ c: int
209
+ d: int
210
+
211
+ def main() -> None:
212
+ settings = load_settings(_Settings, cli=True)
213
+ print(f"{settings=}")
214
+
215
+ if __name__ == "__main__":
216
+ main()
217
+ """)
218
+ script.chmod(script.stat().st_mode | S_IXUSR)
219
+ config = tmp_path.joinpath("config.toml")
220
+ _ = config.write_text(
221
+ """\
222
+ a = 1
223
+ b = 2
224
+
225
+ [inner]
226
+ c = 3
227
+ d = 4
228
+ """
229
+ )
230
+ try:
231
+ result = check_output([script, *args], stderr=STDOUT, text=True).strip("\n")
232
+ except CalledProcessError as error:
233
+ raise RuntimeError(error.stdout) from None
234
+ assert result == expected.strip("\n")
235
+
236
+ def test_cli_coverage(self, *, tmp_path: Path) -> None:
237
+ config = tmp_path.joinpath("config.toml")
238
+ _ = config.write_text("""
239
+ a = 1
240
+
241
+ [inner]
242
+ b = 2""")
243
+
244
+ class Example(CustomBaseSettings):
245
+ toml_files: ClassVar[Sequence[PathLikeOrWithSection]] = [config]
246
+
247
+ a: int
248
+ inner: _Inner
249
+
250
+ class _Inner(BaseSettings):
251
+ b: int
252
+
253
+ _ = Example.model_rebuild()
254
+ _ = load_settings(Example, cli=True)
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.168.1"
3
+ __version__ = "0.168.3"
@@ -2,10 +2,12 @@ from __future__ import annotations
2
2
 
3
3
  from functools import reduce
4
4
  from pathlib import Path
5
- from typing import TYPE_CHECKING, Any, ClassVar, assert_never, override
5
+ from typing import TYPE_CHECKING, Any, ClassVar, assert_never, cast, override
6
6
 
7
+ from pydantic import Field, create_model
7
8
  from pydantic_settings import (
8
9
  BaseSettings,
10
+ CliSettingsSource,
9
11
  JsonConfigSettingsSource,
10
12
  PydanticBaseSettingsSource,
11
13
  SettingsConfigDict,
@@ -14,6 +16,7 @@ from pydantic_settings import (
14
16
  )
15
17
  from pydantic_settings.sources import DEFAULT_PATH
16
18
 
19
+ from utilities.errors import ImpossibleCaseError
17
20
  from utilities.iterables import always_iterable
18
21
 
19
22
  if TYPE_CHECKING:
@@ -29,7 +32,7 @@ type PathLikeOrWithSection = PathLike | PathLikeWithSection
29
32
 
30
33
 
31
34
  class CustomBaseSettings(BaseSettings):
32
- """Base settings for loading JSON files."""
35
+ """Base settings for loading JSON/TOML/YAML files."""
33
36
 
34
37
  # paths
35
38
  json_files: ClassVar[Sequence[PathLikeOrWithSection]] = []
@@ -76,11 +79,6 @@ class CustomBaseSettings(BaseSettings):
76
79
  )
77
80
 
78
81
 
79
- def load_settings[T: BaseSettings](cls: type[T], /) -> T:
80
- """Load a set of settings."""
81
- return cls()
82
-
83
-
84
82
  class JsonConfigSectionSettingsSource(JsonConfigSettingsSource):
85
83
  @override
86
84
  def __init__(
@@ -158,8 +156,80 @@ def _get_section(
158
156
  return reduce(lambda acc, el: acc.get(el, {}), always_iterable(section), mapping)
159
157
 
160
158
 
159
+ ##
160
+
161
+
162
+ class HashableBaseSettings(BaseSettings):
163
+ """Base settings for loading JSON files."""
164
+
165
+ # config
166
+ model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(frozen=True)
167
+
168
+
169
+ ##
170
+
171
+
172
+ def load_settings[T: BaseSettings](cls: type[T], /, *, cli: bool = False) -> T:
173
+ """Load a set of settings."""
174
+ _ = cls.model_rebuild()
175
+ if cli:
176
+ cls_with_defaults = _load_settings_create_model(cls)
177
+
178
+ @classmethod
179
+ def settings_customise_sources(
180
+ cls: type[BaseSettings],
181
+ settings_cls: type[BaseSettings],
182
+ init_settings: PydanticBaseSettingsSource,
183
+ env_settings: PydanticBaseSettingsSource,
184
+ dotenv_settings: PydanticBaseSettingsSource,
185
+ file_secret_settings: PydanticBaseSettingsSource,
186
+ ) -> tuple[PydanticBaseSettingsSource, ...]:
187
+ parent = cast(
188
+ "Any", super(cls_with_defaults, cls)
189
+ ).settings_customise_sources(
190
+ settings_cls=settings_cls,
191
+ init_settings=init_settings,
192
+ env_settings=env_settings,
193
+ dotenv_settings=dotenv_settings,
194
+ file_secret_settings=file_secret_settings,
195
+ )
196
+ return (
197
+ CliSettingsSource(
198
+ settings_cls, cli_parse_args=True, case_sensitive=False
199
+ ),
200
+ *parent,
201
+ )
202
+
203
+ cls_use = type(
204
+ cls.__name__,
205
+ (cls_with_defaults,),
206
+ {"settings_customise_sources": settings_customise_sources},
207
+ )
208
+ cls_use = cast("type[T]", cls_use)
209
+ else:
210
+ cls_use = cls
211
+ return cls_use()
212
+
213
+
214
+ def _load_settings_create_model[T: BaseSettings](
215
+ cls: type[T], /, *, values: T | None = None
216
+ ) -> type[T]:
217
+ values_use = cls() if values is None else values
218
+ kwargs: dict[str, Any] = {}
219
+ for name, field in cls.model_fields.items():
220
+ if (ann := field.annotation) is None:
221
+ raise ImpossibleCaseError(case=[f"{ann=}"]) # pragma: no cover
222
+ value = getattr(values_use, name)
223
+ if issubclass(ann, BaseSettings):
224
+ kwargs[name] = _load_settings_create_model(ann, values=value)
225
+ else:
226
+ kwargs[name] = (field.annotation, Field(default=value))
227
+ return create_model(cls.__name__, __base__=cls, **kwargs)
228
+
229
+
161
230
  __all__ = [
162
231
  "CustomBaseSettings",
232
+ "HashableBaseSettings",
163
233
  "JsonConfigSectionSettingsSource",
164
234
  "TomlConfigSectionSettingsSource",
165
235
  "YamlConfigSectionSettingsSource",