dycw-utilities 0.166.15__tar.gz → 0.166.17__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 (218) hide show
  1. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/PKG-INFO +3 -3
  2. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/pyproject.toml +6 -6
  3. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_polars.py +107 -3
  4. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pydantic_settings.py +34 -5
  5. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pydantic_settings_sops.py +3 -2
  6. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/__init__.py +1 -1
  7. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/polars.py +137 -0
  8. dycw_utilities-0.166.17/src/utilities/pydantic_settings.py +106 -0
  9. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pydantic_settings_sops.py +4 -5
  10. dycw_utilities-0.166.15/src/utilities/pydantic_settings.py +0 -69
  11. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/.gitignore +0 -0
  12. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/LICENSE +0 -0
  13. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/README.md +0 -0
  14. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/__init__.py +0 -0
  15. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/conftest.py +0 -0
  16. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/__init__.py +0 -0
  17. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_missing/__init__.py +0 -0
  18. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_missing/module.py +0 -0
  19. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_with/__init__.py +0 -0
  20. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_with/outer_1.py +0 -0
  21. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_with/outer_2.py +0 -0
  22. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  23. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  24. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  25. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  26. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_without/__init__.py +0 -0
  27. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_without/module_1.py +0 -0
  28. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/package_without/module_2.py +0 -0
  29. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/standalone.py +0 -0
  30. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/modules/with_imports.py +0 -0
  31. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  32. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  33. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  34. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  35. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  36. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  37. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  38. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  39. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_aeventkit.py +0 -0
  40. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_altair.py +0 -0
  41. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_asyncio.py +0 -0
  42. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_atomicwrites.py +0 -0
  43. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_atools.py +0 -0
  44. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_cachetools.py +0 -0
  45. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_click.py +0 -0
  46. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_concurrent.py +0 -0
  47. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_contextlib.py +0 -0
  48. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_contextvars.py +0 -0
  49. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_cryptography.py +0 -0
  50. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_cvxpy.py +0 -0
  51. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_dataclasses.py +0 -0
  52. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_enum.py +0 -0
  53. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_errors.py +0 -0
  54. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_fastapi.py +0 -0
  55. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_fpdf2.py +0 -0
  56. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_functions.py +0 -0
  57. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_functools.py +0 -0
  58. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_getpass.py +0 -0
  59. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_git.py +0 -0
  60. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_gzip.py +0 -0
  61. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_hashlib.py +0 -0
  62. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_http.py +0 -0
  63. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_hypothesis.py +0 -0
  64. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_importlib.py +0 -0
  65. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_inflect.py +0 -0
  66. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_ipython.py +0 -0
  67. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_iterables.py +0 -0
  68. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_json.py +0 -0
  69. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_jupyter.py +0 -0
  70. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_libcst.py +0 -0
  71. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_lightweight_charts.py +0 -0
  72. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_logging.py +0 -0
  73. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_math.py +0 -0
  74. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_memory_profiler.py +0 -0
  75. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_modules.py +0 -0
  76. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_more_itertools.py +0 -0
  77. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_numpy.py +0 -0
  78. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_objects/__init__.py +0 -0
  79. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_objects/objects.py +0 -0
  80. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_operator.py +0 -0
  81. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_optuna.py +0 -0
  82. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_orjson.py +0 -0
  83. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_os.py +0 -0
  84. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_parse.py +0 -0
  85. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pathlib.py +0 -0
  86. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pickle.py +0 -0
  87. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_platform.py +0 -0
  88. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_polars_ols.py +0 -0
  89. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_postgres.py +0 -0
  90. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pottery.py +0 -0
  91. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pqdm.py +0 -0
  92. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_psutil.py +0 -0
  93. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pyinstrument.py +0 -0
  94. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pytest.py +0 -0
  95. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pytest_randomly.py +0 -0
  96. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_pytest_regressions.py +0 -0
  97. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_random.py +0 -0
  98. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_re.py +0 -0
  99. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_redis.py +0 -0
  100. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_reprlib.py +0 -0
  101. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_scipy.py +0 -0
  102. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_sentinel.py +0 -0
  103. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_shelve.py +0 -0
  104. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_slack_sdk.py +0 -0
  105. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_socket.py +0 -0
  106. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_sqlalchemy.py +0 -0
  107. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_sqlalchemy_polars.py +0 -0
  108. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_statsmodels.py +0 -0
  109. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_string.py +0 -0
  110. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_tempfile.py +0 -0
  111. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_testbook.py +0 -0
  112. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_text.py +0 -0
  113. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_threading.py +0 -0
  114. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_timer.py +0 -0
  115. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_traceback.py +0 -0
  116. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_typed_settings.py +0 -0
  117. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_types.py +0 -0
  118. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_typing.py +0 -0
  119. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_typing_funcs/__init__.py +0 -0
  120. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_typing_funcs/no_future.py +0 -0
  121. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_typing_funcs/with_future.py +0 -0
  122. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_tzdata.py +0 -0
  123. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_tzlocal.py +0 -0
  124. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_uuid.py +0 -0
  125. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_version.py +0 -0
  126. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_warnings.py +0 -0
  127. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_whenever.py +0 -0
  128. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_zipfile.py +0 -0
  129. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/tests/test_zoneinfo.py +0 -0
  130. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/aeventkit.py +0 -0
  131. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/altair.py +0 -0
  132. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/asyncio.py +0 -0
  133. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/atomicwrites.py +0 -0
  134. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/atools.py +0 -0
  135. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/cachetools.py +0 -0
  136. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/click.py +0 -0
  137. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/concurrent.py +0 -0
  138. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/contextlib.py +0 -0
  139. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/contextvars.py +0 -0
  140. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/cryptography.py +0 -0
  141. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/cvxpy.py +0 -0
  142. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/dataclasses.py +0 -0
  143. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/enum.py +0 -0
  144. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/errors.py +0 -0
  145. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/fastapi.py +0 -0
  146. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/fpdf2.py +0 -0
  147. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/functions.py +0 -0
  148. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/functools.py +0 -0
  149. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/getpass.py +0 -0
  150. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/git.py +0 -0
  151. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/gzip.py +0 -0
  152. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/hashlib.py +0 -0
  153. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/http.py +0 -0
  154. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/hypothesis.py +0 -0
  155. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/importlib.py +0 -0
  156. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/inflect.py +0 -0
  157. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/ipython.py +0 -0
  158. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/iterables.py +0 -0
  159. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/json.py +0 -0
  160. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/jupyter.py +0 -0
  161. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/libcst.py +0 -0
  162. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/lightweight_charts.py +0 -0
  163. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/logging.py +0 -0
  164. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/math.py +0 -0
  165. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/memory_profiler.py +0 -0
  166. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/modules.py +0 -0
  167. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/more_itertools.py +0 -0
  168. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/numpy.py +0 -0
  169. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/operator.py +0 -0
  170. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/optuna.py +0 -0
  171. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/orjson.py +0 -0
  172. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/os.py +0 -0
  173. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/parse.py +0 -0
  174. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pathlib.py +0 -0
  175. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pickle.py +0 -0
  176. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/platform.py +0 -0
  177. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/polars_ols.py +0 -0
  178. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/postgres.py +0 -0
  179. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pottery.py +0 -0
  180. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pqdm.py +0 -0
  181. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/psutil.py +0 -0
  182. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/py.typed +0 -0
  183. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pyinstrument.py +0 -0
  184. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pytest.py +0 -0
  185. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pytest_plugins/__init__.py +0 -0
  186. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
  187. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
  188. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/pytest_regressions.py +0 -0
  189. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/random.py +0 -0
  190. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/re.py +0 -0
  191. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/redis.py +0 -0
  192. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/reprlib.py +0 -0
  193. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/scipy.py +0 -0
  194. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/sentinel.py +0 -0
  195. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/shelve.py +0 -0
  196. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/slack_sdk.py +0 -0
  197. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/socket.py +0 -0
  198. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/sqlalchemy.py +0 -0
  199. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/sqlalchemy_polars.py +0 -0
  200. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/statsmodels.py +0 -0
  201. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/string.py +0 -0
  202. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/tempfile.py +0 -0
  203. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/testbook.py +0 -0
  204. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/text.py +0 -0
  205. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/threading.py +0 -0
  206. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/timer.py +0 -0
  207. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/traceback.py +0 -0
  208. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/typed_settings.py +0 -0
  209. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/types.py +0 -0
  210. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/typing.py +0 -0
  211. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/tzdata.py +0 -0
  212. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/tzlocal.py +0 -0
  213. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/uuid.py +0 -0
  214. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/version.py +0 -0
  215. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/warnings.py +0 -0
  216. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/whenever.py +0 -0
  217. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/zipfile.py +0 -0
  218. {dycw_utilities-0.166.15 → dycw_utilities-0.166.17}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.166.15
3
+ Version: 0.166.17
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -18,13 +18,13 @@ Requires-Dist: pytest-cov<6.3,>=6.2.1; extra == 'test'
18
18
  Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
19
19
  Requires-Dist: pytest-lazy-fixtures<1.4,>=1.3.4; extra == 'test'
20
20
  Requires-Dist: pytest-randomly<3.17,>=3.16.0; extra == 'test'
21
- Requires-Dist: pytest-regressions<2.9,>=2.8.2; extra == 'test'
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'
23
23
  Requires-Dist: pytest-rerunfailures<16.1,>=16.0.1; extra == 'test'
24
24
  Requires-Dist: pytest-rng<1.1,>=1.0.0; extra == 'test'
25
25
  Requires-Dist: pytest-timeout<2.5,>=2.4.0; extra == 'test'
26
26
  Requires-Dist: pytest-xdist<3.9,>=3.8.0; extra == 'test'
27
- Requires-Dist: pytest<8.5,>=8.4.1; extra == 'test'
27
+ Requires-Dist: pytest<8.5,>=8.4.2; extra == 'test'
28
28
  Requires-Dist: testbook<0.5,>=0.4.2; extra == 'test'
29
29
  Description-Content-Type: text/markdown
30
30
 
@@ -160,14 +160,14 @@ pyinstrument = [
160
160
  "pyinstrument >=5.1.0, <5.2",
161
161
  ]
162
162
  pytest = [
163
- "pytest >=8.4.1, <8.5",
163
+ "pytest >=8.4.2, <8.5",
164
164
  "pytest-asyncio >=1.1.0, <1.2",
165
165
  "pytest-randomly >=3.16.0, <3.17",
166
166
  "pytest-timeout >=2.4.0, <2.5",
167
167
  "pytest-xdist >=3.8.0, <3.9",
168
168
  ]
169
169
  pytest-regressions = [
170
- "pytest-regressions >=2.8.2, <2.9",
170
+ "pytest-regressions >=2.8.3, <2.9",
171
171
  ]
172
172
  pytest-regressions-test = [
173
173
  "orjson",
@@ -246,7 +246,7 @@ dependencies = [
246
246
  name = "dycw-utilities"
247
247
  readme = "README.md"
248
248
  requires-python = ">= 3.12"
249
- version = "0.166.15"
249
+ version = "0.166.17"
250
250
 
251
251
  [project.entry-points.pytest11]
252
252
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -259,13 +259,13 @@ logging = [
259
259
  test = [
260
260
  "dycw-pytest-only >=2.1.1, <2.2",
261
261
  "hypothesis >=6.138.13, <6.139",
262
- "pytest >=8.4.1, <8.5",
262
+ "pytest >=8.4.2, <8.5",
263
263
  "pytest-asyncio >=1.1.0, <1.2",
264
264
  "pytest-cov >=6.2.1, <6.3",
265
265
  "pytest-instafail >=0.5.0, <0.6",
266
266
  "pytest-lazy-fixtures >=1.3.4, <1.4",
267
267
  "pytest-randomly >=3.16.0, <3.17",
268
- "pytest-regressions >=2.8.2, <2.9",
268
+ "pytest-regressions >=2.8.3, <2.9",
269
269
  "pytest-repeat >=0.9.4, <0.10",
270
270
  "pytest-rerunfailures >=16.0.1, <16.1",
271
271
  "pytest-rng >=1.0.0, <1.1",
@@ -279,7 +279,7 @@ test = [
279
279
  # bump-my-version
280
280
  [tool.bumpversion]
281
281
  allow_dirty = true
282
- current_version = "0.166.15"
282
+ current_version = "0.166.17"
283
283
 
284
284
  [[tool.bumpversion.files]]
285
285
  filename = "src/utilities/__init__.py"
@@ -6,7 +6,7 @@ import itertools
6
6
  import math
7
7
  from dataclasses import dataclass, field
8
8
  from enum import auto
9
- from itertools import chain, repeat
9
+ from itertools import chain
10
10
  from math import isfinite, nan
11
11
  from random import Random
12
12
  from typing import TYPE_CHECKING, Any, ClassVar, Literal, assert_never, cast
@@ -49,6 +49,7 @@ from polars import (
49
49
  col,
50
50
  concat,
51
51
  date_range,
52
+ datetime_range,
52
53
  int_range,
53
54
  lit,
54
55
  struct,
@@ -58,7 +59,14 @@ from polars.schema import Schema
58
59
  from polars.testing import assert_frame_equal, assert_series_equal
59
60
  from pytest import mark, param, raises
60
61
  from scipy.stats import norm
61
- from whenever import DateDelta, DateTimeDelta, PlainDateTime, TimeDelta, ZonedDateTime
62
+ from whenever import (
63
+ Date,
64
+ DateDelta,
65
+ DateTimeDelta,
66
+ PlainDateTime,
67
+ TimeDelta,
68
+ ZonedDateTime,
69
+ )
62
70
 
63
71
  import tests.test_math
64
72
  import utilities.polars
@@ -168,6 +176,9 @@ from utilities.polars import (
168
176
  ensure_expr_or_series,
169
177
  ensure_expr_or_series_many,
170
178
  expr_to_series,
179
+ false_like,
180
+ filter_date,
181
+ filter_time,
171
182
  finite_ewm_mean,
172
183
  first_true_horizontal,
173
184
  get_data_type_or_series_time_zone,
@@ -208,6 +219,7 @@ from utilities.polars import (
208
219
  to_not_true,
209
220
  to_true,
210
221
  touch,
222
+ true_like,
211
223
  try_reify_expr,
212
224
  uniform,
213
225
  unique_element,
@@ -1479,6 +1491,42 @@ class TestExprToSeries:
1479
1491
  assert_series_equal(series, expected)
1480
1492
 
1481
1493
 
1494
+ class TestComputeDateFilter:
1495
+ def test_main(self) -> None:
1496
+ series = datetime_range(
1497
+ start=ZonedDateTime(2024, 1, 1, tz=UTC.key).py_datetime(),
1498
+ end=ZonedDateTime(2024, 1, 4, 12, tz=UTC.key).py_datetime(),
1499
+ interval="12h",
1500
+ eager=True,
1501
+ ).alias("datetime")
1502
+ assert len(series) == 8
1503
+ result = filter_date(series, include=[Date(2024, 1, 2), Date(2024, 1, 3)])
1504
+ expected = Series(
1505
+ name="datetime",
1506
+ values=[False, False, True, True, True, True, False, False],
1507
+ dtype=Boolean,
1508
+ )
1509
+ assert_series_equal(result, expected)
1510
+
1511
+
1512
+ class TestComputeTimeFilter:
1513
+ def test_main(self) -> None:
1514
+ series = datetime_range(
1515
+ start=ZonedDateTime(2024, 1, 1, tz=UTC.key).py_datetime(),
1516
+ end=ZonedDateTime(2024, 1, 3, 0, tz=UTC.key).py_datetime(),
1517
+ interval="6h",
1518
+ eager=True,
1519
+ ).alias("datetime")
1520
+ assert len(series) == 9
1521
+ result = filter_time(series, include=[(whenever.Time(6), whenever.Time(12))])
1522
+ expected = Series(
1523
+ name="datetime",
1524
+ values=[False, True, True, False, False, True, True, False, False],
1525
+ dtype=Boolean,
1526
+ )
1527
+ assert_series_equal(result, expected)
1528
+
1529
+
1482
1530
  class TestFiniteEWMMean:
1483
1531
  alpha_0_75_values: ClassVar[list[float]] = [
1484
1532
  -8.269850726503885,
@@ -1838,7 +1886,9 @@ class TestIsNearEvent:
1838
1886
  def test_no_exprs(self) -> None:
1839
1887
  result = self.df.with_columns(is_near_event().alias("z"))["z"]
1840
1888
  expected = Series(
1841
- name="z", values=list(repeat(object=False, times=10)), dtype=Boolean
1889
+ name="z",
1890
+ values=list(itertools.repeat(object=False, times=10)),
1891
+ dtype=Boolean,
1842
1892
  )
1843
1893
  assert_series_equal(result, expected)
1844
1894
 
@@ -2783,6 +2833,60 @@ class TestToTrueAndFalse:
2783
2833
  assert_series_equal(result, exp_series)
2784
2834
 
2785
2835
 
2836
+ class TestTrueLikeAndFalseLike:
2837
+ @given(length=hypothesis.strategies.integers(0, 10), name=text_ascii())
2838
+ def test_true_expr(self, *, length: int, name: str) -> None:
2839
+ expr = int_range(end=length).alias(name)
2840
+ result = true_like(expr)
2841
+ assert isinstance(result, Expr)
2842
+ result2 = (
2843
+ int_range(end=length, eager=True)
2844
+ .alias(f"_{name}")
2845
+ .to_frame()
2846
+ .with_columns(result)[name]
2847
+ )
2848
+ expected = pl.repeat(value=True, n=length, dtype=Boolean, eager=True).alias(
2849
+ name
2850
+ )
2851
+ assert_series_equal(result2, expected)
2852
+
2853
+ @given(length=hypothesis.strategies.integers(0, 10), name=text_ascii())
2854
+ def test_true_series(self, *, length: int, name: str) -> None:
2855
+ series = int_range(end=length, eager=True).alias(name)
2856
+ result = true_like(series)
2857
+ assert isinstance(result, Series)
2858
+ expected = pl.repeat(value=True, n=length, dtype=Boolean, eager=True).alias(
2859
+ name
2860
+ )
2861
+ assert_series_equal(result, expected)
2862
+
2863
+ @given(length=hypothesis.strategies.integers(0, 10), name=text_ascii())
2864
+ def test_false_expr(self, *, length: int, name: str) -> None:
2865
+ expr = int_range(end=length).alias(name)
2866
+ result = false_like(expr)
2867
+ assert isinstance(result, Expr)
2868
+ result2 = (
2869
+ int_range(end=length, eager=True)
2870
+ .alias(f"_{name}")
2871
+ .to_frame()
2872
+ .with_columns(result)[name]
2873
+ )
2874
+ expected = pl.repeat(value=False, n=length, dtype=Boolean, eager=True).alias(
2875
+ name
2876
+ )
2877
+ assert_series_equal(result2, expected)
2878
+
2879
+ @given(length=hypothesis.strategies.integers(0, 10), name=text_ascii())
2880
+ def test_false_series(self, *, length: int, name: str) -> None:
2881
+ series = int_range(end=length, eager=True).alias(name)
2882
+ result = false_like(series)
2883
+ assert isinstance(result, Series)
2884
+ expected = pl.repeat(value=False, n=length, dtype=Boolean, eager=True).alias(
2885
+ name
2886
+ )
2887
+ assert_series_equal(result, expected)
2888
+
2889
+
2786
2890
  class TestTryReifyExpr:
2787
2891
  # expr
2788
2892
 
@@ -8,12 +8,17 @@ import yaml
8
8
  from pydantic_settings import BaseSettings, SettingsConfigDict
9
9
 
10
10
  from utilities.os import temp_environ
11
- from utilities.pydantic_settings import CustomBaseSettings, load_settings
11
+ from utilities.pydantic_settings import (
12
+ CustomBaseSettings,
13
+ PathLikeOrWithSection,
14
+ load_settings,
15
+ )
12
16
 
13
17
  if TYPE_CHECKING:
18
+ from collections.abc import Sequence
14
19
  from pathlib import Path
15
20
 
16
- from utilities.types import MaybeIterable, PathLike
21
+ from utilities.types import PathLike
17
22
 
18
23
 
19
24
  class TestCustomBaseSettings:
@@ -22,7 +27,7 @@ class TestCustomBaseSettings:
22
27
  _ = file.write_text(json.dumps({"x": 1}))
23
28
 
24
29
  class Settings(CustomBaseSettings):
25
- json_files: ClassVar[MaybeIterable[PathLike]] = file
30
+ json_files: ClassVar[Sequence[PathLike]] = [file]
26
31
  x: int
27
32
 
28
33
  settings = load_settings(Settings)
@@ -33,7 +38,31 @@ class TestCustomBaseSettings:
33
38
  _ = file.write_text(tomlkit.dumps({"x": 1}))
34
39
 
35
40
  class Settings(CustomBaseSettings):
36
- toml_files: ClassVar[MaybeIterable[PathLike]] = file
41
+ toml_files: ClassVar[Sequence[PathLikeOrWithSection]] = [file]
42
+ x: int
43
+
44
+ settings = load_settings(Settings)
45
+ assert settings.x == 1
46
+
47
+ def test_toml_section_str(self, *, tmp_path: Path) -> None:
48
+ file = tmp_path.joinpath("settings.toml")
49
+ _ = file.write_text(tomlkit.dumps({"outer": {"x": 1}}))
50
+
51
+ class Settings(CustomBaseSettings):
52
+ toml_files: ClassVar[Sequence[PathLikeOrWithSection]] = [(file, "outer")]
53
+ x: int
54
+
55
+ settings = load_settings(Settings)
56
+ assert settings.x == 1
57
+
58
+ def test_toml_section_nested(self, *, tmp_path: Path) -> None:
59
+ file = tmp_path.joinpath("settings.toml")
60
+ _ = file.write_text(tomlkit.dumps({"outer": {"middle": {"x": 1}}}))
61
+
62
+ class Settings(CustomBaseSettings):
63
+ toml_files: ClassVar[Sequence[PathLikeOrWithSection]] = [
64
+ (file, ["outer", "middle"])
65
+ ]
37
66
  x: int
38
67
 
39
68
  settings = load_settings(Settings)
@@ -44,7 +73,7 @@ class TestCustomBaseSettings:
44
73
  _ = file.write_text(yaml.dump({"x": 1}))
45
74
 
46
75
  class Settings(CustomBaseSettings):
47
- yaml_files: ClassVar[MaybeIterable[PathLike]] = file
76
+ yaml_files: ClassVar[Sequence[PathLike]] = [file]
48
77
  x: int
49
78
 
50
79
  settings = load_settings(Settings)
@@ -13,9 +13,10 @@ from utilities.pydantic_settings_sops import SopsBaseSettings
13
13
  from utilities.re import extract_group
14
14
 
15
15
  if TYPE_CHECKING:
16
+ from collections.abc import Sequence
16
17
  from pathlib import Path
17
18
 
18
- from utilities.types import MaybeIterable, PathLike
19
+ from utilities.types import PathLike
19
20
 
20
21
 
21
22
  class TestSOPSBaseSettings:
@@ -39,7 +40,7 @@ class TestSOPSBaseSettings:
39
40
  _ = check_call(["sops", "encrypt", str(unencrypted_file)], stdout=file)
40
41
 
41
42
  class Settings(SopsBaseSettings):
42
- secret_files: ClassVar[MaybeIterable[PathLike]] = encrypted_file
43
+ secret_files: ClassVar[Sequence[PathLike]] = [encrypted_file]
43
44
  x: int
44
45
  y: int
45
46
 
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.166.15"
3
+ __version__ = "0.166.17"
@@ -70,6 +70,7 @@ from utilities.iterables import (
70
70
  check_supermapping,
71
71
  is_iterable_not_str,
72
72
  one,
73
+ resolve_include_and_exclude,
73
74
  )
74
75
  from utilities.json import write_formatted_json
75
76
  from utilities.math import (
@@ -1269,6 +1270,111 @@ def expr_to_series(expr: Expr, /) -> Series:
1269
1270
  ##
1270
1271
 
1271
1272
 
1273
+ @overload
1274
+ def filter_date(
1275
+ column: ExprLike = "datetime",
1276
+ /,
1277
+ *,
1278
+ time_zone: ZoneInfo | None = None,
1279
+ include: MaybeIterable[whenever.Date] | None = None,
1280
+ exclude: MaybeIterable[whenever.Date] | None = None,
1281
+ ) -> Expr: ...
1282
+ @overload
1283
+ def filter_date(
1284
+ column: Series,
1285
+ /,
1286
+ *,
1287
+ time_zone: ZoneInfo | None = None,
1288
+ include: MaybeIterable[whenever.Date] | None = None,
1289
+ exclude: MaybeIterable[whenever.Date] | None = None,
1290
+ ) -> Series: ...
1291
+ @overload
1292
+ def filter_date(
1293
+ column: IntoExprColumn = "datetime",
1294
+ /,
1295
+ *,
1296
+ time_zone: ZoneInfo | None = None,
1297
+ include: MaybeIterable[whenever.Date] | None = None,
1298
+ exclude: MaybeIterable[whenever.Date] | None = None,
1299
+ ) -> ExprOrSeries: ...
1300
+ def filter_date(
1301
+ column: IntoExprColumn = "datetime",
1302
+ /,
1303
+ *,
1304
+ time_zone: ZoneInfo | None = None,
1305
+ include: MaybeIterable[whenever.Date] | None = None,
1306
+ exclude: MaybeIterable[whenever.Date] | None = None,
1307
+ ) -> ExprOrSeries:
1308
+ """Compute the filter based on a set of dates."""
1309
+ column = ensure_expr_or_series(column)
1310
+ if time_zone is not None:
1311
+ column = column.dt.convert_time_zone(time_zone.key)
1312
+ keep = true_like(column)
1313
+ date = column.dt.date()
1314
+ include, exclude = resolve_include_and_exclude(include=include, exclude=exclude)
1315
+ if include is not None:
1316
+ keep &= date.is_in([d.py_date() for d in include])
1317
+ if exclude is not None:
1318
+ keep &= ~date.is_in([d.py_date() for d in exclude])
1319
+ return try_reify_expr(keep, column)
1320
+
1321
+
1322
+ @overload
1323
+ def filter_time(
1324
+ column: ExprLike = "datetime",
1325
+ /,
1326
+ *,
1327
+ time_zone: ZoneInfo | None = None,
1328
+ include: MaybeIterable[tuple[whenever.Time, whenever.Time]] | None = None,
1329
+ exclude: MaybeIterable[tuple[whenever.Time, whenever.Time]] | None = None,
1330
+ ) -> Expr: ...
1331
+ @overload
1332
+ def filter_time(
1333
+ column: Series,
1334
+ /,
1335
+ *,
1336
+ time_zone: ZoneInfo | None = None,
1337
+ include: MaybeIterable[tuple[whenever.Time, whenever.Time]] | None = None,
1338
+ exclude: MaybeIterable[tuple[whenever.Time, whenever.Time]] | None = None,
1339
+ ) -> Series: ...
1340
+ @overload
1341
+ def filter_time(
1342
+ column: IntoExprColumn = "datetime",
1343
+ /,
1344
+ *,
1345
+ time_zone: ZoneInfo | None = None,
1346
+ include: MaybeIterable[tuple[whenever.Time, whenever.Time]] | None = None,
1347
+ exclude: MaybeIterable[tuple[whenever.Time, whenever.Time]] | None = None,
1348
+ ) -> ExprOrSeries: ...
1349
+ def filter_time(
1350
+ column: IntoExprColumn = "datetime",
1351
+ /,
1352
+ *,
1353
+ time_zone: ZoneInfo | None = None,
1354
+ include: MaybeIterable[tuple[whenever.Time, whenever.Time]] | None = None,
1355
+ exclude: MaybeIterable[tuple[whenever.Time, whenever.Time]] | None = None,
1356
+ ) -> ExprOrSeries:
1357
+ """Compute the filter based on a set of times."""
1358
+ column = ensure_expr_or_series(column)
1359
+ if time_zone is not None:
1360
+ column = column.dt.convert_time_zone(time_zone.key)
1361
+ keep = true_like(column)
1362
+ time = column.dt.time()
1363
+ include, exclude = resolve_include_and_exclude(include=include, exclude=exclude)
1364
+ if include is not None:
1365
+ keep &= any_horizontal(
1366
+ time.is_between(s.py_time(), e.py_time()) for s, e in include
1367
+ )
1368
+ if exclude is not None:
1369
+ keep &= ~any_horizontal(
1370
+ time.is_between(s.py_time(), e.py_time()) for s, e in exclude
1371
+ )
1372
+ return try_reify_expr(keep, column)
1373
+
1374
+
1375
+ ##
1376
+
1377
+
1272
1378
  @overload
1273
1379
  def finite_ewm_mean(
1274
1380
  column: ExprLike,
@@ -2643,6 +2749,33 @@ def to_not_false(column: IntoExprColumn, /) -> ExprOrSeries:
2643
2749
  ##
2644
2750
 
2645
2751
 
2752
+ @overload
2753
+ def true_like(column: ExprLike, /) -> Expr: ...
2754
+ @overload
2755
+ def true_like(column: Series, /) -> Series: ...
2756
+ @overload
2757
+ def true_like(column: IntoExprColumn, /) -> ExprOrSeries: ...
2758
+ def true_like(column: IntoExprColumn, /) -> ExprOrSeries:
2759
+ """Compute a column of `True` values."""
2760
+ column = ensure_expr_or_series(column)
2761
+ return column.is_null() | column.is_not_null()
2762
+
2763
+
2764
+ @overload
2765
+ def false_like(column: ExprLike, /) -> Expr: ...
2766
+ @overload
2767
+ def false_like(column: Series, /) -> Series: ...
2768
+ @overload
2769
+ def false_like(column: IntoExprColumn, /) -> ExprOrSeries: ...
2770
+ def false_like(column: IntoExprColumn, /) -> ExprOrSeries:
2771
+ """Compute a column of `False` values."""
2772
+ column = ensure_expr_or_series(column)
2773
+ return column.is_null() & column.is_not_null()
2774
+
2775
+
2776
+ ##
2777
+
2778
+
2646
2779
  def try_reify_expr(
2647
2780
  expr: IntoExprColumn, /, *exprs: IntoExprColumn, **named_exprs: IntoExprColumn
2648
2781
  ) -> ExprOrSeries:
@@ -2798,6 +2931,9 @@ __all__ = [
2798
2931
  "ensure_expr_or_series",
2799
2932
  "ensure_expr_or_series_many",
2800
2933
  "expr_to_series",
2934
+ "false_like",
2935
+ "filter_date",
2936
+ "filter_time",
2801
2937
  "finite_ewm_mean",
2802
2938
  "first_true_horizontal",
2803
2939
  "get_data_type_or_series_time_zone",
@@ -2838,6 +2974,7 @@ __all__ = [
2838
2974
  "to_not_true",
2839
2975
  "to_true",
2840
2976
  "touch",
2977
+ "true_like",
2841
2978
  "try_reify_expr",
2842
2979
  "uniform",
2843
2980
  "unique_element",
@@ -0,0 +1,106 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import reduce
4
+ from pathlib import Path
5
+ from typing import TYPE_CHECKING, Any, ClassVar, assert_never, override
6
+
7
+ from pydantic_settings import (
8
+ BaseSettings,
9
+ JsonConfigSettingsSource,
10
+ PydanticBaseSettingsSource,
11
+ SettingsConfigDict,
12
+ TomlConfigSettingsSource,
13
+ YamlConfigSettingsSource,
14
+ )
15
+ from pydantic_settings.sources import DEFAULT_PATH
16
+
17
+ from utilities.iterables import always_iterable
18
+
19
+ if TYPE_CHECKING:
20
+ from collections.abc import Iterator, Sequence
21
+
22
+ from pydantic_settings.sources import PathType
23
+
24
+ from utilities.types import MaybeSequenceStr, PathLike
25
+
26
+
27
+ type PathLikeOrWithSection = PathLike | tuple[PathLike, MaybeSequenceStr]
28
+
29
+
30
+ class CustomBaseSettings(BaseSettings):
31
+ """Base settings for loading JSON files."""
32
+
33
+ # paths
34
+ json_files: ClassVar[Sequence[PathLike]] = []
35
+ toml_files: ClassVar[Sequence[PathLikeOrWithSection]] = []
36
+ yaml_files: ClassVar[Sequence[PathLike]] = []
37
+
38
+ # config
39
+ model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict(
40
+ env_nested_delimiter="__"
41
+ )
42
+
43
+ @classmethod
44
+ @override
45
+ def settings_customise_sources(
46
+ cls,
47
+ settings_cls: type[BaseSettings],
48
+ init_settings: PydanticBaseSettingsSource,
49
+ env_settings: PydanticBaseSettingsSource,
50
+ dotenv_settings: PydanticBaseSettingsSource,
51
+ file_secret_settings: PydanticBaseSettingsSource,
52
+ ) -> tuple[PydanticBaseSettingsSource, ...]:
53
+ _ = (init_settings, dotenv_settings, file_secret_settings)
54
+ return tuple(cls._yield_base_settings_sources(settings_cls, env_settings))
55
+
56
+ @classmethod
57
+ def _yield_base_settings_sources(
58
+ cls,
59
+ settings_cls: type[BaseSettings],
60
+ env_settings: PydanticBaseSettingsSource,
61
+ /,
62
+ ) -> Iterator[PydanticBaseSettingsSource]:
63
+ yield env_settings
64
+ for file in cls.json_files:
65
+ yield JsonConfigSettingsSource(settings_cls, json_file=file)
66
+ for path_or_pair in cls.toml_files:
67
+ match path_or_pair:
68
+ case Path() | str() as file:
69
+ yield TomlConfigSettingsSource(settings_cls, toml_file=file)
70
+ case Path() | str() as file, str() | list() | tuple() as section:
71
+ yield TomlConfigSectionSettingsSource(
72
+ settings_cls, toml_file=file, section=section
73
+ )
74
+ case never:
75
+ assert_never(never)
76
+ for file in cls.yaml_files:
77
+ yield YamlConfigSettingsSource(settings_cls, yaml_file=file)
78
+
79
+
80
+ def load_settings[T: BaseSettings](cls: type[T], /) -> T:
81
+ """Load a set of settings."""
82
+ return cls()
83
+
84
+
85
+ class TomlConfigSectionSettingsSource(TomlConfigSettingsSource):
86
+ @override
87
+ def __init__(
88
+ self,
89
+ settings_cls: type[BaseSettings],
90
+ toml_file: PathType | None = DEFAULT_PATH,
91
+ *,
92
+ section: MaybeSequenceStr,
93
+ ) -> None:
94
+ super().__init__(settings_cls, toml_file=toml_file)
95
+ self.section = section
96
+
97
+ @override
98
+ def __call__(self) -> dict[str, Any]:
99
+ return reduce(
100
+ lambda acc, el: acc.get(el, {}),
101
+ always_iterable(self.section),
102
+ super().__call__(),
103
+ )
104
+
105
+
106
+ __all__ = ["CustomBaseSettings", "TomlConfigSectionSettingsSource", "load_settings"]
@@ -4,22 +4,21 @@ from typing import TYPE_CHECKING, ClassVar, override
4
4
 
5
5
  from pydantic_settings_sops import SOPSConfigSettingsSource
6
6
 
7
- from utilities.iterables import always_iterable
8
7
  from utilities.pydantic_settings import CustomBaseSettings
9
8
 
10
9
  if TYPE_CHECKING:
11
- from collections.abc import Iterator
10
+ from collections.abc import Iterator, Sequence
12
11
 
13
12
  from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
14
13
 
15
- from utilities.types import MaybeIterable, PathLike
14
+ from utilities.types import PathLike
16
15
 
17
16
 
18
17
  class SopsBaseSettings(CustomBaseSettings):
19
18
  """Base settings for loading secrets using `sops/age`."""
20
19
 
21
20
  # paths
22
- secret_files: ClassVar[MaybeIterable[PathLike]] = ()
21
+ secret_files: ClassVar[Sequence[PathLike]] = ()
23
22
 
24
23
  @classmethod
25
24
  @override
@@ -30,7 +29,7 @@ class SopsBaseSettings(CustomBaseSettings):
30
29
  /,
31
30
  ) -> Iterator[PydanticBaseSettingsSource]:
32
31
  yield from super()._yield_base_settings_sources(settings_cls, env_settings)
33
- for file in always_iterable(cls.secret_files):
32
+ for file in cls.secret_files:
34
33
  yield SOPSConfigSettingsSource(
35
34
  settings_cls, # pyright: ignore[reportArgumentType],
36
35
  json_file=file,