dycw-utilities 0.148.4__tar.gz → 0.149.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.
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/PKG-INFO +1 -1
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/pyproject.toml +2 -2
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_postgres.py +42 -51
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/postgres.py +217 -110
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/.gitignore +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/LICENSE +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/README.md +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/conftest.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_asyncio.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_gzip.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_inflect.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_json.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_logging.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_objects/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_objects/objects.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_pottery.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_psutil.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_pytest_randomly.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_sqlalchemy.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_statsmodels.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_string.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_typed_settings.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_whenever.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_yield_access/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_yield_access/script.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_yield_access/script.sh +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/asyncio.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/click.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/gzip.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/http.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/inflect.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/json.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/math.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/os.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/period.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pottery.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/psutil.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pytest_plugins/__init__.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/random.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/re.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/string.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/text.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/typed_settings.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/types.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/version.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/utilities/zoneinfo.py +0 -0
@@ -102,7 +102,7 @@ dependencies = [
|
|
102
102
|
name = "dycw-utilities"
|
103
103
|
readme = "README.md"
|
104
104
|
requires-python = ">= 3.12"
|
105
|
-
version = "0.
|
105
|
+
version = "0.149.0"
|
106
106
|
|
107
107
|
[project.entry-points.pytest11]
|
108
108
|
pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
|
@@ -135,7 +135,7 @@ test = [
|
|
135
135
|
# bump-my-version
|
136
136
|
[tool.bumpversion]
|
137
137
|
allow_dirty = true
|
138
|
-
current_version = "0.
|
138
|
+
current_version = "0.149.0"
|
139
139
|
|
140
140
|
[[tool.bumpversion.files]]
|
141
141
|
filename = "src/utilities/__init__.py"
|
@@ -9,15 +9,15 @@ from sqlalchemy import URL, Column, Integer, MetaData, Table
|
|
9
9
|
|
10
10
|
from utilities.hypothesis import integers, temp_paths, text_ascii
|
11
11
|
from utilities.postgres import (
|
12
|
-
|
12
|
+
_build_pg_dump,
|
13
|
+
_build_pg_restore_or_psql,
|
14
|
+
_extract_url,
|
15
|
+
_ExtractURLDatabaseError,
|
16
|
+
_ExtractURLHostError,
|
17
|
+
_ExtractURLPortError,
|
13
18
|
_PGDumpFormat,
|
14
|
-
_PGDumpHostError,
|
15
|
-
_PGDumpPortError,
|
16
|
-
_PGRestoreDatabaseError,
|
17
|
-
_PGRestoreHostError,
|
18
|
-
_PGRestorePortError,
|
19
19
|
pg_dump,
|
20
|
-
|
20
|
+
restore,
|
21
21
|
)
|
22
22
|
from utilities.typing import get_literal_elements
|
23
23
|
|
@@ -53,10 +53,13 @@ def urls(draw: DrawFn, /) -> URL:
|
|
53
53
|
|
54
54
|
|
55
55
|
class TestPGDump:
|
56
|
+
@given(url=urls(), path=temp_paths(), logger=text_ascii(min_size=1) | none())
|
57
|
+
async def test_main(self, *, url: URL, path: Path, logger: str | None) -> None:
|
58
|
+
_ = await pg_dump(url, path, dry_run=True, logger=logger)
|
59
|
+
|
56
60
|
@given(
|
57
61
|
url=urls(),
|
58
62
|
path=temp_paths(),
|
59
|
-
docker=text_ascii(min_size=1) | none(),
|
60
63
|
format_=sampled_from(get_literal_elements(_PGDumpFormat)),
|
61
64
|
jobs=integers(min_value=0) | none(),
|
62
65
|
schemas=lists(text_ascii(min_size=1)) | none(),
|
@@ -64,14 +67,14 @@ class TestPGDump:
|
|
64
67
|
tables=tables() | none(),
|
65
68
|
tables_exc=tables() | none(),
|
66
69
|
inserts=booleans(),
|
67
|
-
|
70
|
+
on_conflict_do_nothing=booleans(),
|
71
|
+
docker=text_ascii(min_size=1) | none(),
|
68
72
|
)
|
69
|
-
|
73
|
+
def test_build(
|
70
74
|
self,
|
71
75
|
*,
|
72
76
|
url: URL,
|
73
77
|
path: Path,
|
74
|
-
docker: str | None,
|
75
78
|
format_: _PGDumpFormat,
|
76
79
|
jobs: int | None,
|
77
80
|
schemas: list[str] | None,
|
@@ -79,12 +82,12 @@ class TestPGDump:
|
|
79
82
|
tables: list[Table | str] | None,
|
80
83
|
tables_exc: list[Table | str] | None,
|
81
84
|
inserts: bool,
|
82
|
-
|
85
|
+
on_conflict_do_nothing: bool,
|
86
|
+
docker: str | None,
|
83
87
|
) -> None:
|
84
|
-
_ =
|
88
|
+
_ = _build_pg_dump(
|
85
89
|
url,
|
86
90
|
path,
|
87
|
-
docker=docker,
|
88
91
|
format_=format_,
|
89
92
|
jobs=jobs,
|
90
93
|
schemas=schemas,
|
@@ -92,87 +95,75 @@ class TestPGDump:
|
|
92
95
|
tables=tables,
|
93
96
|
tables_exc=tables_exc,
|
94
97
|
inserts=inserts,
|
95
|
-
|
96
|
-
|
98
|
+
on_conflict_do_nothing=on_conflict_do_nothing,
|
99
|
+
docker=docker,
|
97
100
|
)
|
98
101
|
|
99
|
-
async def test_error_database(self, *, tmp_path: Path) -> None:
|
100
|
-
url = URL.create("postgres")
|
101
|
-
with raises(
|
102
|
-
_PGDumpDatabaseError, match="Expected URL to contain a 'database'; got .*"
|
103
|
-
):
|
104
|
-
_ = await pg_dump(url, tmp_path, dry_run=True)
|
105
102
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
103
|
+
class TestRestore:
|
104
|
+
@given(url=urls(), path=temp_paths(), logger=text_ascii(min_size=1) | none())
|
105
|
+
async def test_main(self, *, url: URL, path: Path, logger: str | None) -> None:
|
106
|
+
_ = await restore(url, path, dry_run=True, logger=logger)
|
110
107
|
|
111
|
-
async def test_error_port(self, *, tmp_path: Path) -> None:
|
112
|
-
url = URL.create("postgres", database="database", host="host")
|
113
|
-
with raises(_PGDumpPortError, match="Expected URL to contain a 'port'; got .*"):
|
114
|
-
_ = await pg_dump(url, tmp_path, dry_run=True)
|
115
|
-
|
116
|
-
|
117
|
-
class TestPGRestore:
|
118
108
|
@given(
|
119
109
|
url=urls(),
|
120
110
|
path=temp_paths(),
|
111
|
+
psql=booleans(),
|
121
112
|
database=text_ascii(min_size=1) | none(),
|
122
|
-
docker=text_ascii(min_size=1) | none(),
|
123
113
|
data_only=booleans(),
|
124
114
|
jobs=integers(min_value=0) | none(),
|
125
115
|
schemas=lists(text_ascii(min_size=1)) | none(),
|
126
116
|
schemas_exc=lists(text_ascii(min_size=1)) | none(),
|
127
117
|
tables=tables() | none(),
|
128
|
-
|
118
|
+
docker=text_ascii(min_size=1) | none(),
|
129
119
|
)
|
130
|
-
|
120
|
+
def test_build(
|
131
121
|
self,
|
132
122
|
*,
|
133
123
|
url: URL,
|
134
124
|
path: Path,
|
125
|
+
psql: bool,
|
135
126
|
database: str | None,
|
136
|
-
docker: str | None,
|
137
127
|
data_only: bool,
|
138
128
|
jobs: int | None,
|
139
129
|
schemas: list[str] | None,
|
140
130
|
schemas_exc: list[str] | None,
|
141
131
|
tables: list[Table | str] | None,
|
142
|
-
|
132
|
+
docker: str | None,
|
143
133
|
) -> None:
|
144
|
-
_ =
|
134
|
+
_ = _build_pg_restore_or_psql(
|
145
135
|
url,
|
146
136
|
path,
|
137
|
+
psql=psql,
|
147
138
|
database=database,
|
148
|
-
docker=docker,
|
149
139
|
data_only=data_only,
|
150
140
|
jobs=jobs,
|
151
141
|
schemas=schemas,
|
152
142
|
schemas_exc=schemas_exc,
|
153
143
|
tables=tables,
|
154
|
-
|
155
|
-
dry_run=True,
|
144
|
+
docker=docker,
|
156
145
|
)
|
157
146
|
|
158
|
-
|
147
|
+
|
148
|
+
class TestExtractURL:
|
149
|
+
def test_database(self) -> None:
|
159
150
|
url = URL.create("postgres")
|
160
151
|
with raises(
|
161
|
-
|
152
|
+
_ExtractURLDatabaseError,
|
162
153
|
match="Expected URL to contain a 'database'; got .*",
|
163
154
|
):
|
164
|
-
_ =
|
155
|
+
_ = _extract_url(url)
|
165
156
|
|
166
|
-
|
157
|
+
def test_host(self) -> None:
|
167
158
|
url = URL.create("postgres", database="database")
|
168
159
|
with raises(
|
169
|
-
|
160
|
+
_ExtractURLHostError, match="Expected URL to contain a 'host'; got .*"
|
170
161
|
):
|
171
|
-
_ =
|
162
|
+
_ = _extract_url(url)
|
172
163
|
|
173
|
-
|
164
|
+
def test_port(self) -> None:
|
174
165
|
url = URL.create("postgres", database="database", host="host")
|
175
166
|
with raises(
|
176
|
-
|
167
|
+
_ExtractURLPortError, match="Expected URL to contain a 'port'; got .*"
|
177
168
|
):
|
178
|
-
_ =
|
169
|
+
_ = _extract_url(url)
|
@@ -12,6 +12,7 @@ from utilities.asyncio import stream_command
|
|
12
12
|
from utilities.iterables import always_iterable
|
13
13
|
from utilities.logging import get_logger
|
14
14
|
from utilities.os import temp_environ
|
15
|
+
from utilities.pathlib import ensure_suffix
|
15
16
|
from utilities.sqlalchemy import get_table_name
|
16
17
|
from utilities.timer import Timer
|
17
18
|
from utilities.types import PathLike
|
@@ -31,7 +32,6 @@ async def pg_dump(
|
|
31
32
|
path: PathLike,
|
32
33
|
/,
|
33
34
|
*,
|
34
|
-
docker: str | None = None,
|
35
35
|
format_: _PGDumpFormat = "plain",
|
36
36
|
jobs: int | None = None,
|
37
37
|
schemas: MaybeListStr | None = None,
|
@@ -39,26 +39,93 @@ async def pg_dump(
|
|
39
39
|
tables: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
|
40
40
|
tables_exc: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
|
41
41
|
inserts: bool = False,
|
42
|
-
|
42
|
+
on_conflict_do_nothing: bool = False,
|
43
|
+
docker: str | None = None,
|
43
44
|
dry_run: bool = False,
|
45
|
+
logger: LoggerOrName | None = None,
|
44
46
|
) -> None:
|
45
47
|
"""Run `pg_dump`."""
|
46
48
|
path = Path(path)
|
47
49
|
path.parent.mkdir(parents=True, exist_ok=True)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
cmd = _build_pg_dump(
|
51
|
+
url,
|
52
|
+
path,
|
53
|
+
format_=format_,
|
54
|
+
jobs=jobs,
|
55
|
+
schemas=schemas,
|
56
|
+
schemas_exc=schemas_exc,
|
57
|
+
tables=tables,
|
58
|
+
tables_exc=tables_exc,
|
59
|
+
inserts=inserts,
|
60
|
+
on_conflict_do_nothing=on_conflict_do_nothing,
|
61
|
+
docker=docker,
|
62
|
+
)
|
63
|
+
if dry_run:
|
64
|
+
if logger is not None:
|
65
|
+
get_logger(logger=logger).info("Would run %r", str(cmd))
|
66
|
+
return
|
67
|
+
with temp_environ(PGPASSWORD=url.password), Timer() as timer: # pragma: no cover
|
68
|
+
try:
|
69
|
+
output = await stream_command(cmd)
|
70
|
+
except KeyboardInterrupt:
|
71
|
+
if logger is not None:
|
72
|
+
get_logger(logger=logger).info(
|
73
|
+
"Cancelled backup to %r after %s", str(path), timer
|
74
|
+
)
|
75
|
+
rmtree(path, ignore_errors=True)
|
76
|
+
else:
|
77
|
+
match output.return_code:
|
78
|
+
case 0:
|
79
|
+
if logger is not None:
|
80
|
+
get_logger(logger=logger).info(
|
81
|
+
"Backup to %r finished after %s", str(path), timer
|
82
|
+
)
|
83
|
+
case _:
|
84
|
+
if logger is not None:
|
85
|
+
get_logger(logger=logger).exception(
|
86
|
+
"Backup to %r failed after %s\nstderr:\n%s",
|
87
|
+
str(path),
|
88
|
+
timer,
|
89
|
+
output.stderr,
|
90
|
+
)
|
91
|
+
rmtree(path, ignore_errors=True)
|
92
|
+
|
93
|
+
|
94
|
+
def _build_pg_dump(
|
95
|
+
url: URL,
|
96
|
+
path: PathLike,
|
97
|
+
/,
|
98
|
+
*,
|
99
|
+
format_: _PGDumpFormat = "plain",
|
100
|
+
jobs: int | None = None,
|
101
|
+
schemas: MaybeListStr | None = None,
|
102
|
+
schemas_exc: MaybeListStr | None = None,
|
103
|
+
tables: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
|
104
|
+
tables_exc: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
|
105
|
+
inserts: bool = False,
|
106
|
+
on_conflict_do_nothing: bool = False,
|
107
|
+
docker: str | None = None,
|
108
|
+
) -> str:
|
109
|
+
database, host, port = _extract_url(url)
|
110
|
+
match format_:
|
111
|
+
case "plain":
|
112
|
+
suffix = ".sql"
|
113
|
+
case "custom":
|
114
|
+
suffix = ".pgdump"
|
115
|
+
case "directory":
|
116
|
+
suffix = None
|
117
|
+
case "tar":
|
118
|
+
suffix = ".tar"
|
119
|
+
case _ as never:
|
120
|
+
assert_never(never)
|
121
|
+
file = Path(path)
|
122
|
+
if suffix is not None:
|
123
|
+
file = ensure_suffix(file, suffix)
|
124
|
+
parts: list[str] = [
|
58
125
|
"pg_dump",
|
59
126
|
# general options
|
60
|
-
f"--dbname={
|
61
|
-
f"--file={str(
|
127
|
+
f"--dbname={database}",
|
128
|
+
f"--file={str(file)!r}",
|
62
129
|
f"--format={format_}",
|
63
130
|
"--verbose",
|
64
131
|
# output options
|
@@ -68,10 +135,10 @@ async def pg_dump(
|
|
68
135
|
"--no-privileges",
|
69
136
|
"--if-exists",
|
70
137
|
# connection options
|
71
|
-
f"--host={
|
72
|
-
f"--port={
|
138
|
+
f"--host={host}",
|
139
|
+
f"--port={port}",
|
73
140
|
"--no-password",
|
74
|
-
]
|
141
|
+
]
|
75
142
|
if (format_ == "directory") and (jobs is not None):
|
76
143
|
parts.append(f"--jobs={jobs}")
|
77
144
|
if schemas is not None:
|
@@ -86,9 +153,47 @@ async def pg_dump(
|
|
86
153
|
])
|
87
154
|
if inserts:
|
88
155
|
parts.append("--inserts")
|
156
|
+
if on_conflict_do_nothing:
|
157
|
+
parts.append("--on-conflict-do-nothing")
|
89
158
|
if url.username is not None:
|
90
159
|
parts.append(f"--username={url.username}")
|
91
|
-
|
160
|
+
if docker is not None:
|
161
|
+
parts = _wrap_docker(parts, docker)
|
162
|
+
return " ".join(parts)
|
163
|
+
|
164
|
+
|
165
|
+
##
|
166
|
+
|
167
|
+
|
168
|
+
async def restore(
|
169
|
+
url: URL,
|
170
|
+
path: PathLike,
|
171
|
+
/,
|
172
|
+
*,
|
173
|
+
psql: bool = False,
|
174
|
+
database: str | None = None,
|
175
|
+
data_only: bool = False,
|
176
|
+
jobs: int | None = None,
|
177
|
+
schemas: MaybeListStr | None = None,
|
178
|
+
schemas_exc: MaybeListStr | None = None,
|
179
|
+
tables: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
|
180
|
+
docker: str | None = None,
|
181
|
+
dry_run: bool = False,
|
182
|
+
logger: LoggerOrName | None = None,
|
183
|
+
) -> None:
|
184
|
+
"""Run `pg_restore`/`psql`."""
|
185
|
+
cmd = _build_pg_restore_or_psql(
|
186
|
+
url,
|
187
|
+
path,
|
188
|
+
psql=psql,
|
189
|
+
database=database,
|
190
|
+
data_only=data_only,
|
191
|
+
jobs=jobs,
|
192
|
+
schemas=schemas,
|
193
|
+
schemas_exc=schemas_exc,
|
194
|
+
tables=tables,
|
195
|
+
docker=docker,
|
196
|
+
)
|
92
197
|
if dry_run:
|
93
198
|
if logger is not None:
|
94
199
|
get_logger(logger=logger).info("Would run %r", str(cmd))
|
@@ -99,89 +204,75 @@ async def pg_dump(
|
|
99
204
|
except KeyboardInterrupt:
|
100
205
|
if logger is not None:
|
101
206
|
get_logger(logger=logger).info(
|
102
|
-
"Cancelled
|
207
|
+
"Cancelled restore from %r after %s", str(path), timer
|
103
208
|
)
|
104
|
-
rmtree(path, ignore_errors=True)
|
105
209
|
else:
|
106
210
|
match output.return_code:
|
107
211
|
case 0:
|
108
212
|
if logger is not None:
|
109
213
|
get_logger(logger=logger).info(
|
110
|
-
"
|
214
|
+
"Restore from %r finished after %s", str(path), timer
|
111
215
|
)
|
112
216
|
case _:
|
113
217
|
if logger is not None:
|
114
218
|
get_logger(logger=logger).exception(
|
115
|
-
"
|
219
|
+
"Restore from %r failed after %s\nstderr:\n%s",
|
116
220
|
str(path),
|
117
221
|
timer,
|
118
222
|
output.stderr,
|
119
223
|
)
|
120
|
-
rmtree(path, ignore_errors=True)
|
121
|
-
|
122
|
-
|
123
|
-
@dataclass(kw_only=True, slots=True)
|
124
|
-
class PGDumpError(Exception):
|
125
|
-
url: URL
|
126
|
-
|
127
|
-
|
128
|
-
@dataclass(kw_only=True, slots=True)
|
129
|
-
class _PGDumpDatabaseError(PGDumpError):
|
130
|
-
@override
|
131
|
-
def __str__(self) -> str:
|
132
|
-
return f"Expected URL to contain a 'database'; got {self.url}"
|
133
|
-
|
134
|
-
|
135
|
-
@dataclass(kw_only=True, slots=True)
|
136
|
-
class _PGDumpHostError(PGDumpError):
|
137
|
-
@override
|
138
|
-
def __str__(self) -> str:
|
139
|
-
return f"Expected URL to contain a 'host'; got {self.url}"
|
140
|
-
|
141
|
-
|
142
|
-
@dataclass(kw_only=True, slots=True)
|
143
|
-
class _PGDumpPortError(PGDumpError):
|
144
|
-
@override
|
145
|
-
def __str__(self) -> str:
|
146
|
-
return f"Expected URL to contain a 'port'; got {self.url}"
|
147
224
|
|
148
225
|
|
149
226
|
##
|
150
227
|
|
151
228
|
|
152
|
-
|
229
|
+
def _build_pg_restore_or_psql(
|
153
230
|
url: URL,
|
154
231
|
path: PathLike,
|
155
232
|
/,
|
156
233
|
*,
|
234
|
+
psql: bool = False,
|
157
235
|
database: str | None = None,
|
236
|
+
data_only: bool = False,
|
237
|
+
jobs: int | None = None,
|
238
|
+
schemas: MaybeListStr | None = None,
|
239
|
+
schemas_exc: MaybeListStr | None = None,
|
240
|
+
tables: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
|
158
241
|
docker: str | None = None,
|
242
|
+
) -> str:
|
243
|
+
path = Path(path)
|
244
|
+
if (path.suffix == ".sql") or psql:
|
245
|
+
return _build_psql(url, path, database=database, docker=docker)
|
246
|
+
return _build_pg_restore(
|
247
|
+
url,
|
248
|
+
path,
|
249
|
+
database=database,
|
250
|
+
data_only=data_only,
|
251
|
+
jobs=jobs,
|
252
|
+
schemas=schemas,
|
253
|
+
schemas_exc=schemas_exc,
|
254
|
+
tables=tables,
|
255
|
+
docker=docker,
|
256
|
+
)
|
257
|
+
|
258
|
+
|
259
|
+
def _build_pg_restore(
|
260
|
+
url: URL,
|
261
|
+
path: PathLike,
|
262
|
+
/,
|
263
|
+
*,
|
264
|
+
database: str | None = None,
|
159
265
|
data_only: bool = False,
|
160
266
|
jobs: int | None = None,
|
161
267
|
schemas: MaybeListStr | None = None,
|
162
268
|
schemas_exc: MaybeListStr | None = None,
|
163
269
|
tables: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
|
164
|
-
|
165
|
-
|
166
|
-
) -> None:
|
270
|
+
docker: str | None = None,
|
271
|
+
) -> str:
|
167
272
|
"""Run `pg_restore`."""
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
case None, str() as database_use:
|
172
|
-
...
|
173
|
-
case None, None:
|
174
|
-
raise _PGRestoreDatabaseError(url=url)
|
175
|
-
case _ as never:
|
176
|
-
assert_never(never)
|
177
|
-
if url.host is None:
|
178
|
-
raise _PGRestoreHostError(url=url)
|
179
|
-
if url.port is None:
|
180
|
-
raise _PGRestorePortError(url=url)
|
181
|
-
parts: list[str] = []
|
182
|
-
if docker is not None:
|
183
|
-
parts.extend(["docker", "exec", "-it", docker])
|
184
|
-
parts.extend([
|
273
|
+
url_database, host, port = _extract_url(url)
|
274
|
+
database_use = url_database if database is None else database
|
275
|
+
parts: list[str] = [
|
185
276
|
"pg_restore",
|
186
277
|
# general options
|
187
278
|
f"--dbname={database_use}",
|
@@ -191,10 +282,10 @@ async def pg_restore(
|
|
191
282
|
"--no-owner",
|
192
283
|
"--no-privileges",
|
193
284
|
# connection options
|
194
|
-
f"--host={
|
195
|
-
f"--port={
|
285
|
+
f"--host={host}",
|
286
|
+
f"--port={port}",
|
196
287
|
"--no-password",
|
197
|
-
]
|
288
|
+
]
|
198
289
|
if data_only:
|
199
290
|
parts.append("--data-only")
|
200
291
|
else:
|
@@ -209,68 +300,80 @@ async def pg_restore(
|
|
209
300
|
parts.extend([f"--table={_get_table_name(t)}" for t in always_iterable(tables)])
|
210
301
|
if url.username is not None:
|
211
302
|
parts.append(f"--username={url.username}")
|
303
|
+
if docker is not None:
|
304
|
+
parts = _wrap_docker(parts, docker)
|
212
305
|
parts.append(str(path))
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
306
|
+
return " ".join(parts)
|
307
|
+
|
308
|
+
|
309
|
+
def _build_psql(
|
310
|
+
url: URL,
|
311
|
+
path: PathLike,
|
312
|
+
/,
|
313
|
+
*,
|
314
|
+
database: str | None = None,
|
315
|
+
docker: str | None = None,
|
316
|
+
) -> str:
|
317
|
+
"""Run `psql`."""
|
318
|
+
url_database, host, port = _extract_url(url)
|
319
|
+
database_use = url_database if database is None else database
|
320
|
+
parts: list[str] = [
|
321
|
+
"psql",
|
322
|
+
# general options
|
323
|
+
f"--dbname={database_use}",
|
324
|
+
f"--file={str(path)!r}",
|
325
|
+
# connection options
|
326
|
+
f"--host={host}",
|
327
|
+
f"--port={port}",
|
328
|
+
"--no-password",
|
329
|
+
]
|
330
|
+
if url.username is not None:
|
331
|
+
parts.append(f"--username={url.username}")
|
332
|
+
if docker is not None:
|
333
|
+
parts = _wrap_docker(parts, docker)
|
334
|
+
return " ".join(parts)
|
335
|
+
|
336
|
+
|
337
|
+
##
|
338
|
+
|
339
|
+
|
340
|
+
def _extract_url(url: URL, /) -> tuple[str, str, int]:
|
341
|
+
if url.database is None:
|
342
|
+
raise _ExtractURLDatabaseError(url=url)
|
343
|
+
if url.host is None:
|
344
|
+
raise _ExtractURLHostError(url=url)
|
345
|
+
if url.port is None:
|
346
|
+
raise _ExtractURLPortError(url=url)
|
347
|
+
return url.database, url.host, url.port
|
241
348
|
|
242
349
|
|
243
350
|
@dataclass(kw_only=True, slots=True)
|
244
|
-
class
|
351
|
+
class ExtractURLError(Exception):
|
245
352
|
url: URL
|
246
353
|
|
247
354
|
|
248
355
|
@dataclass(kw_only=True, slots=True)
|
249
|
-
class
|
356
|
+
class _ExtractURLDatabaseError(ExtractURLError):
|
250
357
|
@override
|
251
358
|
def __str__(self) -> str:
|
252
359
|
return f"Expected URL to contain a 'database'; got {self.url}"
|
253
360
|
|
254
361
|
|
255
362
|
@dataclass(kw_only=True, slots=True)
|
256
|
-
class
|
363
|
+
class _ExtractURLHostError(ExtractURLError):
|
257
364
|
@override
|
258
365
|
def __str__(self) -> str:
|
259
366
|
return f"Expected URL to contain a 'host'; got {self.url}"
|
260
367
|
|
261
368
|
|
262
369
|
@dataclass(kw_only=True, slots=True)
|
263
|
-
class
|
370
|
+
class _ExtractURLPortError(ExtractURLError):
|
264
371
|
@override
|
265
372
|
def __str__(self) -> str:
|
266
373
|
return f"Expected URL to contain a 'port'; got {self.url}"
|
267
374
|
|
268
375
|
|
269
|
-
##
|
270
|
-
|
271
|
-
|
272
376
|
def _get_table_name(obj: TableOrORMInstOrClass | str, /) -> str:
|
273
|
-
"""Get the table name from a Table or mapped class."""
|
274
377
|
match obj:
|
275
378
|
case Table() | DeclarativeBase() | type() as table_or_orm:
|
276
379
|
return get_table_name(table_or_orm)
|
@@ -280,4 +383,8 @@ def _get_table_name(obj: TableOrORMInstOrClass | str, /) -> str:
|
|
280
383
|
assert_never(never)
|
281
384
|
|
282
385
|
|
283
|
-
|
386
|
+
def _wrap_docker(parts: list[str], container: str, /) -> list[str]:
|
387
|
+
return ["docker", "exec", "-it", container, *parts]
|
388
|
+
|
389
|
+
|
390
|
+
__all__ = ["ExtractURLError", "pg_dump", "restore"]
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{dycw_utilities-0.148.4 → dycw_utilities-0.149.0}/src/tests/modules/package_missing/__init__.py
RENAMED
File without changes
|