diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 74240b91..00000000 --- a/.flake8 +++ /dev/null @@ -1,5 +0,0 @@ -[flake8] -ignore = D105,D203,D213,W503 -docstring-convention = google -max-line-length = 88 -max-complexity = 10 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 69f4a698..585d0601 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,33 +17,12 @@ repos: exclude: (copier_template/.*|docs/.*|samples/.*\.json) - id: trailing-whitespace -- repo: https://github.com/psf/black - rev: 23.12.1 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.14 hooks: - - id: black - exclude: | - (?x)^( - copier_template/.* - )$ - -- repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - exclude: (copier_template/.*) - -- repo: https://github.com/pycqa/flake8 - rev: 7.0.0 - hooks: - - id: flake8 - additional_dependencies: - - flake8-docstrings==1.6.0 - -- repo: https://github.com/asottile/pyupgrade - rev: v3.15.0 - hooks: - - id: pyupgrade - args: [--py37-plus] + - id: ruff + args: [--fix] + - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy rev: 'v1.8.0' diff --git a/poetry.lock b/poetry.lock index 20195933..895130a0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -148,52 +148,6 @@ files = [ tests = ["pytest (>=3.2.1,!=3.3.0)"] typecheck = ["mypy"] -[[package]] -name = "black" -version = "23.12.1" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, - {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, - {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, - {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, - {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, - {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, - {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, - {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, - {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, - {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, - {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, - {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, - {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, - {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, - {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, - {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, - {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, - {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, - {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, - {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, - {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, - {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "cachetools" version = "5.3.2" @@ -501,22 +455,6 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] -[[package]] -name = "flake8" -version = "7.0.0" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, - {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.2.0,<3.3.0" - [[package]] name = "fs" version = "2.4.16" @@ -677,20 +615,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - [[package]] name = "joblib" version = "1.3.2" @@ -754,17 +678,6 @@ files = [ importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} referencing = ">=0.31.0" -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - [[package]] name = "memoization" version = "0.4.0" @@ -865,17 +778,6 @@ all = ["gssapi (>=1.4.1)", "invoke (>=2.0)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1 gssapi = ["gssapi (>=1.4.1)", "pyasn1 (>=0.1.7)", "pywin32 (>=2.1.8)"] invoke = ["invoke (>=2.0)"] -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - [[package]] name = "pendulum" version = "3.0.0" @@ -1110,17 +1012,6 @@ files = [ {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, ] -[[package]] -name = "pycodestyle" -version = "2.11.1" -description = "Python style guide checker" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, -] - [[package]] name = "pycparser" version = "2.21" @@ -1132,17 +1023,6 @@ files = [ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] -[[package]] -name = "pyflakes" -version = "3.2.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, - {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, -] - [[package]] name = "pyjwt" version = "2.8.0" @@ -1481,6 +1361,32 @@ files = [ {file = "rpds_py-0.15.2.tar.gz", hash = "sha256:373b76eeb79e8c14f6d82cb1d4d5293f9e4059baec6c1b16dca7ad13b6131b39"}, ] +[[package]] +name = "ruff" +version = "0.1.14" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:96f76536df9b26622755c12ed8680f159817be2f725c17ed9305b472a757cdbb"}, + {file = "ruff-0.1.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab3f71f64498c7241123bb5a768544cf42821d2a537f894b22457a543d3ca7a9"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7060156ecc572b8f984fd20fd8b0fcb692dd5d837b7606e968334ab7ff0090ab"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a53d8e35313d7b67eb3db15a66c08434809107659226a90dcd7acb2afa55faea"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bea9be712b8f5b4ebed40e1949379cfb2a7d907f42921cf9ab3aae07e6fba9eb"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2270504d629a0b064247983cbc495bed277f372fb9eaba41e5cf51f7ba705a6a"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80258bb3b8909b1700610dfabef7876423eed1bc930fe177c71c414921898efa"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:653230dd00aaf449eb5ff25d10a6e03bc3006813e2cb99799e568f55482e5cae"}, + {file = "ruff-0.1.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b3acc6c4e6928459ba9eb7459dd4f0c4bf266a053c863d72a44c33246bfdbf"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6b3dadc9522d0eccc060699a9816e8127b27addbb4697fc0c08611e4e6aeb8b5"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1c8eca1a47b4150dc0fbec7fe68fc91c695aed798532a18dbb1424e61e9b721f"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:62ce2ae46303ee896fc6811f63d6dabf8d9c389da0f3e3f2bce8bc7f15ef5488"}, + {file = "ruff-0.1.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b2027dde79d217b211d725fc833e8965dc90a16d0d3213f1298f97465956661b"}, + {file = "ruff-0.1.14-py3-none-win32.whl", hash = "sha256:722bafc299145575a63bbd6b5069cb643eaa62546a5b6398f82b3e4403329cab"}, + {file = "ruff-0.1.14-py3-none-win_amd64.whl", hash = "sha256:e3d241aa61f92b0805a7082bd89a9990826448e4d0398f0e2bc8f05c75c63d99"}, + {file = "ruff-0.1.14-py3-none-win_arm64.whl", hash = "sha256:269302b31ade4cde6cf6f9dd58ea593773a37ed3f7b97e793c8594b262466b67"}, + {file = "ruff-0.1.14.tar.gz", hash = "sha256:ad3f8088b2dfd884820289a06ab718cde7d38b94972212cc4ba90d5fbc9955f3"}, +] + [[package]] name = "setuptools" version = "69.0.2" @@ -1939,5 +1845,5 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" -python-versions = "<3.13,>=3.8.1" -content-hash = "efbd5e458335df5d4ed374277ad76543e9af322fc6331240656b33c25d909b29" +python-versions = "<3.13,>=3.8" +content-hash = "f0194f959176c2b190ab350f2cc107fbb6676a00b61a3d5ad469c42a1c8f8e0d" diff --git a/pyproject.toml b/pyproject.toml index fc1a0ea4..d81affaf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ packages = [ ] [tool.poetry.dependencies] -python = "<3.13,>=3.8.1" +python = "<3.13,>=3.8" requests = "^2.25.1" singer-sdk = ">=0.28,<0.35" psycopg2-binary = "2.9.9" @@ -42,9 +42,7 @@ sshtunnel = "0.4.0" pytest = "^7.4.2" mypy = "^1.6.1" remote-pdb="2.1.0" -black = "^23.1.0" -flake8 = ">=6,<8" -isort = "^5.10.1" +ruff = "^0.1.14" tox = "^4" types-paramiko = "^3.3.0.0" types-simplejson = "^3.19.0.2" @@ -58,11 +56,6 @@ exclude = "tests" module = ["sshtunnel"] ignore_missing_imports = true -[tool.isort] -profile = "black" -multi_line_output = 3 # Vertical Hanging Indent -src_paths = "target_postgres" - [build-system] requires = ["poetry-core==1.8.1", "poetry-dynamic-versioning==1.2.0"] build-backend = "poetry_dynamic_versioning.backend" @@ -80,3 +73,17 @@ pythonpath = [ enable = true vcs = "git" style = "semver" + +[tool.ruff] +select = [ + "F", # Pyflakes + "W", # pycodestyle warnings + "E", # pycodestyle errors + "I", # isort + "N", # pep8-naming + "D", # pydocsyle +] +target-version = "py38" + +[tool.ruff.pydocstyle] +convention = "google" diff --git a/target_postgres/connector.py b/target_postgres/connector.py index 27e5b03e..c3b721ee 100644 --- a/target_postgres/connector.py +++ b/target_postgres/connector.py @@ -229,12 +229,11 @@ def to_sql_type(jsonschema_type: dict) -> sqlalchemy.types.TypeEngine: json_type_array = [] if jsonschema_type.get("type", False): - if type(jsonschema_type["type"]) is str: + if isinstance(jsonschema_type["type"], str): json_type_array.append(jsonschema_type) - elif type(jsonschema_type["type"]) is list: + elif isinstance(jsonschema_type["type"], list): for entry in jsonschema_type["type"]: - json_type_dict = {} - json_type_dict["type"] = entry + json_type_dict = {"type": entry} if jsonschema_type.get("format", False): json_type_dict["format"] = jsonschema_type["format"] json_type_array.append(json_type_dict) @@ -242,8 +241,7 @@ def to_sql_type(jsonschema_type: dict) -> sqlalchemy.types.TypeEngine: msg = "Invalid format for jsonschema type: not str or list." raise RuntimeError(msg) elif jsonschema_type.get("anyOf", False): - for entry in jsonschema_type["anyOf"]: - json_type_array.append(entry) + json_type_array.extend(iter(jsonschema_type["anyOf"])) else: msg = ( "Neither type nor anyOf are present. Unable to determine type. " @@ -329,12 +327,17 @@ def create_empty_table( # type: ignore[override] """Create an empty target table. Args: - full_table_name: the target table name. + table_name: the target table name. + meta: the SQLAchemy metadata object. schema: the JSON schema for the new table. + connection: the database connection. primary_keys: list of key properties. partition_keys: list of partition keys. as_temp_table: True to create a temp table. + Returns: + The new table object. + Raises: NotImplementedError: if temp tables are unsupported and as_temp_table=True. RuntimeError: if a variant schema is passed with no properties defined. @@ -429,9 +432,11 @@ def _create_empty_column( # type: ignore[override] """Create a new column. Args: - full_table_name: The target table name. + schema_name: The schema name. + table_name: The table name. column_name: The name of the new column. sql_type: SQLAlchemy type engine to be used in creating the new column. + connection: The database connection. Raises: NotImplementedError: if adding columns is not supported. @@ -493,9 +498,12 @@ def _adapt_column_type( # type: ignore[override] """Adapt table column type to support the new JSON schema type. Args: - full_table_name: The target table name. + schema_name: The schema name. + table_name: The table name. column_name: The target column name. sql_type: The new SQLAlchemy type. + connection: The database connection. + column_object: The existing column object. Raises: NotImplementedError: if altering columns is not supported. @@ -560,6 +568,7 @@ def get_column_alter_ddl( # type: ignore[override] Override this if your database uses a different syntax for altering columns. Args: + schema_name: Schema name. table_name: Fully qualified table name of column to alter. column_name: Column name to alter. column_type: New column type string. @@ -724,8 +733,10 @@ def _get_column_type( # type: ignore[override] """Get the SQL type of the declared column. Args: - full_table_name: The name of the table. + schema_name: The schema name. + table_name: The table name. column_name: The name of the column. + connection: The database connection. Returns: The type of the column. @@ -762,6 +773,7 @@ def get_table_columns( # type: ignore[override] Args: schema_name: schema name. table_name: table name to get columns for. + connection: database connection. column_names: A list of column names to filter to. Returns: @@ -792,6 +804,7 @@ def column_exists( # type: ignore[override] Args: full_table_name: the target table name. column_name: the target column name. + connection: the database connection. Returns: True if table exists, False if not. diff --git a/target_postgres/sinks.py b/target_postgres/sinks.py index 6a505ec2..d29bee91 100644 --- a/target_postgres/sinks.py +++ b/target_postgres/sinks.py @@ -132,10 +132,12 @@ def bulk_insert_records( # type: ignore[override] faster, native bulk uploads. Args: - full_table_name: the target table name. + table: the target table object. schema: the JSON schema for the new table, to be used when inferring column names. records: the input records. + primary_keys: the primary key columns for the table. + connection: the database connection. Returns: True if table exists, False if not, None if unsure or undetectable. @@ -265,7 +267,7 @@ def generate_insert_statement( Args: full_table_name: the target table name. - schema: the JSON schema for the new table. + columns: the target table columns. Returns: An insert statement. diff --git a/tox.ini b/tox.ini index 0c287e8f..75c49720 100644 --- a/tox.ini +++ b/tox.ini @@ -8,18 +8,10 @@ isolated_build = true [testenv] allowlist_externals = poetry -commands = - poetry install -v - poetry run pytest - poetry run black --check target_postgres/ - poetry run flake8 target_postgres - poetry run pydocstyle target_postgres - poetry run mypy target_postgres --exclude='target_postgres/tests' - [testenv:pytest] # Run the python tests. # To execute, run `tox -e pytest` -envlist = py37, py38, py39 +envlist = py38, py39, py310, py311, py312 commands = poetry install -v poetry run pytest @@ -29,23 +21,14 @@ commands = # To execute, run `tox -e format` commands = poetry install -v - poetry run black target_postgres/ - poetry run isort target_postgres + poetry run ruff check target_postgres/ + poetry run ruff format target_postgres/ [testenv:lint] # Raise an error if lint and style standards are not met. # To execute, run `tox -e lint` commands = poetry install -v - poetry run black --check --diff target_postgres/ - poetry run isort --check target_postgres - poetry run flake8 target_postgres + poetry run ruff check --diff target_postgres/ + poetry run ruff format --check target_postgres/ poetry run mypy . - -[flake8] -ignore = W503 -max-line-length = 88 -max-complexity = 10 - -[pydocstyle] -convention = google