dycw-utilities 0.166.36__tar.gz → 0.167.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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.166.36 → dycw_utilities-0.167.0}/PKG-INFO +2 -2
  2. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/pyproject.toml +4 -4
  3. dycw_utilities-0.167.0/src/tests/test_docker.py +22 -0
  4. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_jinja2.py +27 -1
  5. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_postgres.py +6 -6
  6. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/__init__.py +1 -1
  7. dycw_utilities-0.167.0/src/utilities/docker.py +24 -0
  8. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/jinja2.py +29 -1
  9. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/postgres.py +28 -29
  10. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/.gitignore +0 -0
  11. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/LICENSE +0 -0
  12. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/README.md +0 -0
  13. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/__init__.py +0 -0
  14. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/conftest.py +0 -0
  15. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/__init__.py +0 -0
  16. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_missing/__init__.py +0 -0
  17. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_missing/module.py +0 -0
  18. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_with/__init__.py +0 -0
  19. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_with/outer_1.py +0 -0
  20. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_with/outer_2.py +0 -0
  21. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  22. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  23. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  24. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  25. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_without/__init__.py +0 -0
  26. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_without/module_1.py +0 -0
  27. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/package_without/module_2.py +0 -0
  28. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/standalone.py +0 -0
  29. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/modules/with_imports.py +0 -0
  30. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  31. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  32. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  33. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  34. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  35. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  36. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  37. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  38. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_aeventkit.py +0 -0
  39. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_altair.py +0 -0
  40. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_asyncio.py +0 -0
  41. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_atomicwrites.py +0 -0
  42. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_atools.py +0 -0
  43. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_cachetools.py +0 -0
  44. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_click.py +0 -0
  45. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_concurrent.py +0 -0
  46. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_contextlib.py +0 -0
  47. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_contextvars.py +0 -0
  48. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_cryptography.py +0 -0
  49. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_cvxpy.py +0 -0
  50. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_dataclasses.py +0 -0
  51. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_enum.py +0 -0
  52. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_errors.py +0 -0
  53. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_fastapi.py +0 -0
  54. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_fpdf2.py +0 -0
  55. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_functions.py +0 -0
  56. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_functools.py +0 -0
  57. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_getpass.py +0 -0
  58. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_git.py +0 -0
  59. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_gzip.py +0 -0
  60. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_hashlib.py +0 -0
  61. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_http.py +0 -0
  62. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_hypothesis.py +0 -0
  63. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_importlib.py +0 -0
  64. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_inflect.py +0 -0
  65. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_ipython.py +0 -0
  66. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_iterables.py +0 -0
  67. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_json.py +0 -0
  68. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_jupyter.py +0 -0
  69. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_libcst.py +0 -0
  70. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_lightweight_charts.py +0 -0
  71. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_logging.py +0 -0
  72. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_math.py +0 -0
  73. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_memory_profiler.py +0 -0
  74. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_modules.py +0 -0
  75. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_more_itertools.py +0 -0
  76. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_numpy.py +0 -0
  77. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_objects/__init__.py +0 -0
  78. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_objects/objects.py +0 -0
  79. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_operator.py +0 -0
  80. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_optuna.py +0 -0
  81. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_orjson.py +0 -0
  82. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_os.py +0 -0
  83. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_parse.py +0 -0
  84. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pathlib.py +0 -0
  85. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pickle.py +0 -0
  86. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_platform.py +0 -0
  87. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_polars.py +0 -0
  88. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_polars_ols.py +0 -0
  89. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pottery.py +0 -0
  90. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pqdm.py +0 -0
  91. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_psutil.py +0 -0
  92. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pydantic_settings.py +0 -0
  93. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pydantic_settings_sops.py +0 -0
  94. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pyinstrument.py +0 -0
  95. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pytest.py +0 -0
  96. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pytest_randomly.py +0 -0
  97. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_pytest_regressions.py +0 -0
  98. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_random.py +0 -0
  99. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_re.py +0 -0
  100. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_redis.py +0 -0
  101. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_reprlib.py +0 -0
  102. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_scipy.py +0 -0
  103. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_sentinel.py +0 -0
  104. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_shelve.py +0 -0
  105. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_slack_sdk.py +0 -0
  106. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_socket.py +0 -0
  107. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_sqlalchemy.py +0 -0
  108. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_sqlalchemy_polars.py +0 -0
  109. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_statsmodels.py +0 -0
  110. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_string.py +0 -0
  111. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_tempfile.py +0 -0
  112. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_testbook.py +0 -0
  113. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_text.py +0 -0
  114. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_threading.py +0 -0
  115. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_timer.py +0 -0
  116. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_traceback.py +0 -0
  117. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_typed_settings.py +0 -0
  118. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_types.py +0 -0
  119. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_typing.py +0 -0
  120. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_typing_funcs/__init__.py +0 -0
  121. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_typing_funcs/no_future.py +0 -0
  122. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_typing_funcs/with_future.py +0 -0
  123. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_tzdata.py +0 -0
  124. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_tzlocal.py +0 -0
  125. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_uuid.py +0 -0
  126. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_version.py +0 -0
  127. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_warnings.py +0 -0
  128. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_whenever.py +0 -0
  129. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_zipfile.py +0 -0
  130. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/tests/test_zoneinfo.py +0 -0
  131. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/aeventkit.py +0 -0
  132. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/altair.py +0 -0
  133. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/asyncio.py +0 -0
  134. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/atomicwrites.py +0 -0
  135. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/atools.py +0 -0
  136. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/cachetools.py +0 -0
  137. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/click.py +0 -0
  138. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/concurrent.py +0 -0
  139. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/contextlib.py +0 -0
  140. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/contextvars.py +0 -0
  141. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/cryptography.py +0 -0
  142. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/cvxpy.py +0 -0
  143. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/dataclasses.py +0 -0
  144. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/enum.py +0 -0
  145. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/errors.py +0 -0
  146. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/fastapi.py +0 -0
  147. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/fpdf2.py +0 -0
  148. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/functions.py +0 -0
  149. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/functools.py +0 -0
  150. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/getpass.py +0 -0
  151. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/git.py +0 -0
  152. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/gzip.py +0 -0
  153. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/hashlib.py +0 -0
  154. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/http.py +0 -0
  155. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/hypothesis.py +0 -0
  156. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/importlib.py +0 -0
  157. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/inflect.py +0 -0
  158. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/ipython.py +0 -0
  159. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/iterables.py +0 -0
  160. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/json.py +0 -0
  161. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/jupyter.py +0 -0
  162. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/libcst.py +0 -0
  163. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/lightweight_charts.py +0 -0
  164. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/logging.py +0 -0
  165. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/math.py +0 -0
  166. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/memory_profiler.py +0 -0
  167. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/modules.py +0 -0
  168. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/more_itertools.py +0 -0
  169. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/numpy.py +0 -0
  170. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/operator.py +0 -0
  171. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/optuna.py +0 -0
  172. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/orjson.py +0 -0
  173. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/os.py +0 -0
  174. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/parse.py +0 -0
  175. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pathlib.py +0 -0
  176. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pickle.py +0 -0
  177. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/platform.py +0 -0
  178. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/polars.py +0 -0
  179. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/polars_ols.py +0 -0
  180. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pottery.py +0 -0
  181. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pqdm.py +0 -0
  182. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/psutil.py +0 -0
  183. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/py.typed +0 -0
  184. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pydantic_settings.py +0 -0
  185. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pydantic_settings_sops.py +0 -0
  186. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pyinstrument.py +0 -0
  187. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pytest.py +0 -0
  188. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pytest_plugins/__init__.py +0 -0
  189. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
  190. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
  191. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/pytest_regressions.py +0 -0
  192. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/random.py +0 -0
  193. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/re.py +0 -0
  194. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/redis.py +0 -0
  195. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/reprlib.py +0 -0
  196. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/scipy.py +0 -0
  197. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/sentinel.py +0 -0
  198. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/shelve.py +0 -0
  199. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/slack_sdk.py +0 -0
  200. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/socket.py +0 -0
  201. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/sqlalchemy.py +0 -0
  202. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/sqlalchemy_polars.py +0 -0
  203. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/statsmodels.py +0 -0
  204. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/string.py +0 -0
  205. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/tempfile.py +0 -0
  206. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/testbook.py +0 -0
  207. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/text.py +0 -0
  208. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/threading.py +0 -0
  209. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/timer.py +0 -0
  210. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/traceback.py +0 -0
  211. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/typed_settings.py +0 -0
  212. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/types.py +0 -0
  213. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/typing.py +0 -0
  214. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/tzdata.py +0 -0
  215. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/tzlocal.py +0 -0
  216. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/uuid.py +0 -0
  217. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/version.py +0 -0
  218. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/warnings.py +0 -0
  219. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/whenever.py +0 -0
  220. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/zipfile.py +0 -0
  221. {dycw_utilities-0.166.36 → dycw_utilities-0.167.0}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.166.36
3
+ Version: 0.167.0
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -12,7 +12,7 @@ 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.140,>=6.139.1; extra == 'test'
15
+ Requires-Dist: hypothesis<6.140,>=6.139.2; 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'
@@ -71,7 +71,7 @@ http-test = [
71
71
  "orjson",
72
72
  ]
73
73
  hypothesis = [
74
- "hypothesis >=6.139.1, <6.140",
74
+ "hypothesis >=6.139.2, <6.140",
75
75
  ]
76
76
  hypothesis-test = [
77
77
  "libcst",
@@ -249,7 +249,7 @@ dependencies = [
249
249
  name = "dycw-utilities"
250
250
  readme = "README.md"
251
251
  requires-python = ">= 3.12"
252
- version = "0.166.36"
252
+ version = "0.167.0"
253
253
 
254
254
  [project.entry-points.pytest11]
255
255
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -261,7 +261,7 @@ logging = [
261
261
  ]
262
262
  test = [
263
263
  "dycw-pytest-only >=2.1.1, <2.2",
264
- "hypothesis >=6.139.1, <6.140",
264
+ "hypothesis >=6.139.2, <6.140",
265
265
  "pytest >=8.4.2, <8.5",
266
266
  "pytest-asyncio >=1.2.0, <1.3",
267
267
  "pytest-cov >=7.0.0, <7.1",
@@ -282,7 +282,7 @@ test = [
282
282
  # bump-my-version
283
283
  [tool.bumpversion]
284
284
  allow_dirty = true
285
- current_version = "0.166.36"
285
+ current_version = "0.167.0"
286
286
 
287
287
  [[tool.bumpversion.files]]
288
288
  filename = "src/utilities/__init__.py"
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from utilities.docker import docker_exec
4
+
5
+
6
+ class TestDockerExec:
7
+ def test_main(self) -> None:
8
+ result = docker_exec("container", "pg_dump")
9
+ expected = ["docker", "exec", "--interactive", "container", "pg_dump"]
10
+ assert result == expected
11
+
12
+ def test_env(self) -> None:
13
+ result = docker_exec("container", "pg_dump", KEY="value")
14
+ expected = [
15
+ "docker",
16
+ "exec",
17
+ "--env=KEY=value",
18
+ "--interactive",
19
+ "container",
20
+ "pg_dump",
21
+ ]
22
+ assert result == expected
@@ -3,8 +3,14 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from jinja2 import DictLoader
6
+ from pytest import raises
6
7
 
7
- from utilities.jinja2 import EnhancedEnvironment, TemplateJob
8
+ from utilities.jinja2 import (
9
+ EnhancedEnvironment,
10
+ TemplateJob,
11
+ _TemplateJobTargetDoesNotExistError,
12
+ _TemplateJobTemplateDoesNotExistError,
13
+ )
8
14
  from utilities.text import strip_and_dedent
9
15
 
10
16
  if TYPE_CHECKING:
@@ -85,3 +91,23 @@ class TestTemplateJob:
85
91
  old = 'old text'
86
92
  new = 'new text'
87
93
  """)
94
+
95
+ def test_error_template(self, *, tmp_path: Path) -> None:
96
+ path_template = tmp_path.joinpath("template.j2")
97
+ path_target = tmp_path.joinpath("target.txt")
98
+ with raises(
99
+ _TemplateJobTemplateDoesNotExistError,
100
+ match=r"^Template '.*' does not exist$",
101
+ ):
102
+ _ = TemplateJob(template=path_template, kwargs={}, target=path_target)
103
+
104
+ def test_error_target(self, *, tmp_path: Path) -> None:
105
+ path_template = tmp_path.joinpath("template.j2")
106
+ path_template.touch()
107
+ path_target = tmp_path.joinpath("target.txt")
108
+ with raises(
109
+ _TemplateJobTargetDoesNotExistError, match=r"^Target '.*' does not exist$"
110
+ ):
111
+ _ = TemplateJob(
112
+ template=path_template, kwargs={}, target=path_target, mode="append"
113
+ )
@@ -56,7 +56,7 @@ class TestPGDump:
56
56
  inserts=booleans(),
57
57
  on_conflict_do_nothing=booleans(),
58
58
  role=text_ascii(min_size=1) | none(),
59
- docker=text_ascii(min_size=1) | none(),
59
+ docker_container=text_ascii(min_size=1) | none(),
60
60
  )
61
61
  def test_build(
62
62
  self,
@@ -75,7 +75,7 @@ class TestPGDump:
75
75
  inserts: bool,
76
76
  on_conflict_do_nothing: bool,
77
77
  role: str | None,
78
- docker: str | None,
78
+ docker_container: str | None,
79
79
  ) -> None:
80
80
  _ = _build_pg_dump(
81
81
  url,
@@ -92,7 +92,7 @@ class TestPGDump:
92
92
  inserts=inserts,
93
93
  on_conflict_do_nothing=on_conflict_do_nothing,
94
94
  role=role,
95
- docker=docker,
95
+ docker_container=docker_container,
96
96
  )
97
97
 
98
98
  @given(path=temp_paths(), format_=sampled_from(get_literal_elements(_PGDumpFormat)))
@@ -132,7 +132,7 @@ class TestRestore:
132
132
  schema_exc=lists(text_ascii(min_size=1)) | none(),
133
133
  table=tables() | none(),
134
134
  role=text_ascii(min_size=1) | none(),
135
- docker=text_ascii(min_size=1) | none(),
135
+ docker_container=text_ascii(min_size=1) | none(),
136
136
  )
137
137
  def test_build(
138
138
  self,
@@ -146,7 +146,7 @@ class TestRestore:
146
146
  schema_exc: list[str] | None,
147
147
  table: list[Table | str] | None,
148
148
  role: str | None,
149
- docker: str | None,
149
+ docker_container: str | None,
150
150
  ) -> None:
151
151
  _ = _build_pg_restore_or_psql(
152
152
  url,
@@ -158,5 +158,5 @@ class TestRestore:
158
158
  schema_exc=schema_exc,
159
159
  table=table,
160
160
  role=role,
161
- docker=docker,
161
+ docker_container=docker_container,
162
162
  )
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.166.36"
3
+ __version__ = "0.167.0"
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from collections.abc import Mapping
7
+
8
+
9
+ def docker_exec(
10
+ container: str,
11
+ /,
12
+ *cmd: str,
13
+ env: Mapping[str, str] | None = None,
14
+ **env_kwargs: str | None,
15
+ ) -> list[str]:
16
+ """Run a command through `docker exec`."""
17
+ full = ["docker", "exec"]
18
+ mapping: dict[str, str | None] = ({} if env is None else dict(env)) | env_kwargs
19
+ for key, value in mapping.items():
20
+ full.append(f"--env={key}={value}")
21
+ return [*full, "--interactive", container, *cmd]
22
+
23
+
24
+ __all__ = ["docker_exec"]
@@ -98,6 +98,12 @@ class TemplateJob:
98
98
  target: Path
99
99
  mode: Literal["write", "append"] = "write"
100
100
 
101
+ def __post_init__(self) -> None:
102
+ if not self.template.exists():
103
+ raise _TemplateJobTemplateDoesNotExistError(path=self.template)
104
+ if (self.mode == "append") and not self.target.exists():
105
+ raise _TemplateJobTargetDoesNotExistError(path=self.template)
106
+
101
107
  def run(self) -> None:
102
108
  """Run the job."""
103
109
  match self.mode:
@@ -117,4 +123,26 @@ class TemplateJob:
117
123
  return env.get_template(self.template.name).render(self.kwargs)
118
124
 
119
125
 
120
- __all__ = ["EnhancedEnvironment", "TemplateJob"]
126
+ @dataclass(kw_only=True, slots=True)
127
+ class TemplateJobError(Exception): ...
128
+
129
+
130
+ @dataclass(kw_only=True, slots=True)
131
+ class _TemplateJobTemplateDoesNotExistError(TemplateJobError):
132
+ path: Path
133
+
134
+ @override
135
+ def __str__(self) -> str:
136
+ return f"Template {str(self.path)!r} does not exist"
137
+
138
+
139
+ @dataclass(kw_only=True, slots=True)
140
+ class _TemplateJobTargetDoesNotExistError(TemplateJobError):
141
+ path: Path
142
+
143
+ @override
144
+ def __str__(self) -> str:
145
+ return f"Target {str(self.path)!r} does not exist"
146
+
147
+
148
+ __all__ = ["EnhancedEnvironment", "TemplateJob", "TemplateJobError"]
@@ -9,6 +9,7 @@ from sqlalchemy import Table
9
9
  from sqlalchemy.orm import DeclarativeBase
10
10
 
11
11
  from utilities.asyncio import stream_command
12
+ from utilities.docker import docker_exec
12
13
  from utilities.iterables import always_iterable
13
14
  from utilities.logging import to_logger
14
15
  from utilities.os import temp_environ
@@ -37,6 +38,7 @@ async def pg_dump(
37
38
  path: PathLike,
38
39
  /,
39
40
  *,
41
+ docker_container: str | None = None,
40
42
  format_: _PGDumpFormat = "plain",
41
43
  jobs: int | None = None,
42
44
  data_only: bool = False,
@@ -51,7 +53,6 @@ async def pg_dump(
51
53
  inserts: bool = False,
52
54
  on_conflict_do_nothing: bool = False,
53
55
  role: str | None = None,
54
- docker: str | None = None,
55
56
  dry_run: bool = False,
56
57
  logger: LoggerLike | None = None,
57
58
  ) -> bool:
@@ -61,6 +62,7 @@ async def pg_dump(
61
62
  cmd = _build_pg_dump(
62
63
  url,
63
64
  path,
65
+ docker_container=docker_container,
64
66
  format_=format_,
65
67
  jobs=jobs,
66
68
  data_only=data_only,
@@ -75,7 +77,6 @@ async def pg_dump(
75
77
  inserts=inserts,
76
78
  on_conflict_do_nothing=on_conflict_do_nothing,
77
79
  role=role,
78
- docker=docker,
79
80
  )
80
81
  if dry_run:
81
82
  if logger is not None:
@@ -111,6 +112,7 @@ def _build_pg_dump(
111
112
  path: PathLike,
112
113
  /,
113
114
  *,
115
+ docker_container: str | None = None,
114
116
  format_: _PGDumpFormat = "plain",
115
117
  jobs: int | None = None,
116
118
  data_only: bool = False,
@@ -125,12 +127,13 @@ def _build_pg_dump(
125
127
  inserts: bool = False,
126
128
  on_conflict_do_nothing: bool = False,
127
129
  role: str | None = None,
128
- docker: str | None = None,
129
130
  ) -> str:
130
131
  extracted = extract_url(url)
131
132
  path = _path_pg_dump(path, format_=format_)
132
- parts: list[str] = [
133
- "pg_dump",
133
+ parts: list[str] = ["pg_dump"]
134
+ if docker_container is not None:
135
+ parts = docker_exec(docker_container, *parts, PGPASSWORD=extracted.password)
136
+ parts.extend([
134
137
  # general options
135
138
  f"--file={str(path)!r}",
136
139
  f"--format={format_}",
@@ -146,7 +149,7 @@ def _build_pg_dump(
146
149
  f"--port={extracted.port}",
147
150
  f"--username={extracted.username}",
148
151
  "--no-password",
149
- ]
152
+ ])
150
153
  if (format_ == "directory") and (jobs is not None):
151
154
  parts.append(f"--jobs={jobs}")
152
155
  if create:
@@ -173,8 +176,6 @@ def _build_pg_dump(
173
176
  parts.append("--on-conflict-do-nothing")
174
177
  if role is not None:
175
178
  parts.append(f"--role={role}")
176
- if docker is not None:
177
- parts = _wrap_docker(parts, docker)
178
179
  return " ".join(parts)
179
180
 
180
181
 
@@ -213,7 +214,7 @@ async def restore(
213
214
  schema_exc: MaybeCollectionStr | None = None,
214
215
  table: MaybeCollection[TableOrORMInstOrClass | str] | None = None,
215
216
  role: str | None = None,
216
- docker: str | None = None,
217
+ docker_container: str | None = None,
217
218
  dry_run: bool = False,
218
219
  logger: LoggerLike | None = None,
219
220
  ) -> bool:
@@ -230,7 +231,7 @@ async def restore(
230
231
  schema_exc=schema_exc,
231
232
  table=table,
232
233
  role=role,
233
- docker=docker,
234
+ docker_container=docker_container,
234
235
  )
235
236
  if dry_run:
236
237
  if logger is not None:
@@ -276,11 +277,11 @@ def _build_pg_restore_or_psql(
276
277
  schema_exc: MaybeCollectionStr | None = None,
277
278
  table: MaybeCollection[TableOrORMInstOrClass | str] | None = None,
278
279
  role: str | None = None,
279
- docker: str | None = None,
280
+ docker_container: str | None = None,
280
281
  ) -> str:
281
282
  path = Path(path)
282
283
  if (path.suffix == ".sql") or psql:
283
- return _build_psql(url, path, docker=docker)
284
+ return _build_psql(url, path, docker_container=docker_container)
284
285
  return _build_pg_restore(
285
286
  url,
286
287
  path,
@@ -292,7 +293,7 @@ def _build_pg_restore_or_psql(
292
293
  schemas_exc=schema_exc,
293
294
  tables=table,
294
295
  role=role,
295
- docker=docker,
296
+ docker_container=docker_container,
296
297
  )
297
298
 
298
299
 
@@ -309,12 +310,14 @@ def _build_pg_restore(
309
310
  schemas_exc: MaybeCollectionStr | None = None,
310
311
  tables: MaybeCollection[TableOrORMInstOrClass | str] | None = None,
311
312
  role: str | None = None,
312
- docker: str | None = None,
313
+ docker_container: str | None = None,
313
314
  ) -> str:
314
315
  """Run `pg_restore`."""
315
316
  extracted = extract_url(url)
316
- parts: list[str] = [
317
- "pg_restore",
317
+ parts: list[str] = ["pg_restore"]
318
+ if docker_container is not None:
319
+ parts = docker_exec(docker_container, *parts, PGPASSWORD=extracted.password)
320
+ parts.extend([
318
321
  # general options
319
322
  "--verbose",
320
323
  # restore options
@@ -328,7 +331,7 @@ def _build_pg_restore(
328
331
  f"--username={extracted.username}",
329
332
  f"--dbname={extracted.database}",
330
333
  "--no-password",
331
- ]
334
+ ])
332
335
  if create:
333
336
  parts.append("--create")
334
337
  if jobs is not None:
@@ -341,17 +344,19 @@ def _build_pg_restore(
341
344
  parts.extend([f"--table={_get_table_name(t)}" for t in always_iterable(tables)])
342
345
  if role is not None:
343
346
  parts.append(f"--role={role}")
344
- if docker is not None:
345
- parts = _wrap_docker(parts, docker)
346
347
  parts.append(str(path))
347
348
  return " ".join(parts)
348
349
 
349
350
 
350
- def _build_psql(url: URL, path: PathLike, /, *, docker: str | None = None) -> str:
351
+ def _build_psql(
352
+ url: URL, path: PathLike, /, *, docker_container: str | None = None
353
+ ) -> str:
351
354
  """Run `psql`."""
352
355
  extracted = extract_url(url)
353
- parts: list[str] = [
354
- "psql",
356
+ parts: list[str] = ["psql"]
357
+ if docker_container is not None:
358
+ parts = docker_exec(docker_container, *parts, PGPASSWORD=extracted.password)
359
+ parts.extend([
355
360
  # general options
356
361
  f"--dbname={extracted.database}",
357
362
  f"--file={str(path)!r}",
@@ -360,9 +365,7 @@ def _build_psql(url: URL, path: PathLike, /, *, docker: str | None = None) -> st
360
365
  f"--port={extracted.port}",
361
366
  f"--username={extracted.username}",
362
367
  "--no-password",
363
- ]
364
- if docker is not None:
365
- parts = _wrap_docker(parts, docker)
368
+ ])
366
369
  return " ".join(parts)
367
370
 
368
371
 
@@ -402,8 +405,4 @@ class _ResolveDataOnlyAndCleanError(Exception):
402
405
  return "Cannot use '--data-only' and '--clean' together"
403
406
 
404
407
 
405
- def _wrap_docker(parts: list[str], container: str, /) -> list[str]:
406
- return ["docker", "exec", "-it", container, *parts]
407
-
408
-
409
408
  __all__ = ["pg_dump", "restore"]