diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7a04798f3..22a0b74c7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -50,7 +50,7 @@ repos: - id: check-readthedocs - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.3 + rev: v0.6.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix, --show-fixes] diff --git a/cookiecutter/mapper-template/{{cookiecutter.mapper_id}}/.pre-commit-config.yaml b/cookiecutter/mapper-template/{{cookiecutter.mapper_id}}/.pre-commit-config.yaml index 29308ec2d..9e35a5cbe 100644 --- a/cookiecutter/mapper-template/{{cookiecutter.mapper_id}}/.pre-commit-config.yaml +++ b/cookiecutter/mapper-template/{{cookiecutter.mapper_id}}/.pre-commit-config.yaml @@ -18,19 +18,19 @@ repos: - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.1 + rev: 0.29.2 hooks: - id: check-dependabot - id: check-github-workflows - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.6 + rev: v0.6.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix, --show-fixes] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.1 + rev: v1.11.2 hooks: - id: mypy diff --git a/cookiecutter/tap-template/{{cookiecutter.tap_id}}/.pre-commit-config.yaml b/cookiecutter/tap-template/{{cookiecutter.tap_id}}/.pre-commit-config.yaml index ced959bcc..45093ce09 100644 --- a/cookiecutter/tap-template/{{cookiecutter.tap_id}}/.pre-commit-config.yaml +++ b/cookiecutter/tap-template/{{cookiecutter.tap_id}}/.pre-commit-config.yaml @@ -18,20 +18,20 @@ repos: - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.1 + rev: 0.29.2 hooks: - id: check-dependabot - id: check-github-workflows - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.6 + rev: v0.6.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix, --show-fixes] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.1 + rev: v1.11.2 hooks: - id: mypy additional_dependencies: diff --git a/cookiecutter/target-template/{{cookiecutter.target_id}}/.pre-commit-config.yaml b/cookiecutter/target-template/{{cookiecutter.target_id}}/.pre-commit-config.yaml index 3cab6f92b..ee72f1515 100644 --- a/cookiecutter/target-template/{{cookiecutter.target_id}}/.pre-commit-config.yaml +++ b/cookiecutter/target-template/{{cookiecutter.target_id}}/.pre-commit-config.yaml @@ -18,20 +18,20 @@ repos: - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.29.1 + rev: 0.29.2 hooks: - id: check-dependabot - id: check-github-workflows - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.6 + rev: v0.6.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix, --show-fixes] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.1 + rev: v1.11.2 hooks: - id: mypy additional_dependencies: diff --git a/poetry.lock b/poetry.lock index cbe1d81a5..453b391a9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -471,38 +471,38 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "43.0.0" +version = "43.0.1" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = true python-versions = ">=3.7" files = [ - {file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"}, - {file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"}, - {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"}, - {file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"}, - {file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"}, - {file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"}, - {file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"}, - {file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"}, - {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"}, - {file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"}, - {file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"}, - {file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"}, - {file = "cryptography-43.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70"}, - {file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66"}, - {file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f"}, - {file = "cryptography-43.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f"}, - {file = "cryptography-43.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2"}, - {file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947"}, - {file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069"}, - {file = "cryptography-43.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1"}, - {file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"}, + {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, + {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, + {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, + {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, + {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, + {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, + {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, + {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, + {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, + {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, + {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, + {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, + {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, ] [package.dependencies] @@ -515,7 +515,7 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.0)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 3d4d12787..d13255b57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -146,7 +146,15 @@ types-PyYAML = ">=6.0.12" pytest-codspeed = ">=2.2.0" [tool.pytest.ini_options] -addopts = '--durations=10 --ignore=singer_sdk/helpers/_simpleeval.py -m "not external"' +addopts = [ + "--durations=10", + "--ignore=singer_sdk/helpers/_simpleeval.py", + "-m", + "not external", + "-ra", + "--strict-config", + "--strict-markers", +] filterwarnings = [ "error", "ignore:Could not configure external gitlab tests:UserWarning", @@ -167,13 +175,16 @@ filterwarnings = [ # https://github.com/joblib/joblib/pull/1518 "ignore:Attribute n is deprecated:DeprecationWarning:joblib._utils", ] +log_cli_level = "INFO" markers = [ "external: Tests relying on external resources", "windows: Tests that only run on Windows", "snapshot: Tests that use pytest-snapshot", ] +minversion = "7" testpaths = ["tests"] norecursedirs = "cookiecutter" +xfail_strict = false [tool.commitizen] name = "cz_version_bump" @@ -257,11 +268,14 @@ DEP002 = [ ] [tool.mypy] +enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] exclude = "tests" files = "singer_sdk" local_partial_types = true +strict = false warn_redundant_casts = true warn_return_any = true +warn_unreachable = true warn_unused_configs = true warn_unused_ignores = true @@ -295,7 +309,6 @@ extend-exclude = [ "*simpleeval*", ] line-length = 88 -src = ["samples", "singer_sdk", "tests"] target-version = "py38" [tool.ruff.format] diff --git a/singer_sdk/_singerlib/encoding/_simple.py b/singer_sdk/_singerlib/encoding/_simple.py index 7ce148fc3..5c8fec549 100644 --- a/singer_sdk/_singerlib/encoding/_simple.py +++ b/singer_sdk/_singerlib/encoding/_simple.py @@ -161,9 +161,9 @@ def __post_init__(self) -> None: self.type = SingerMessageType.SCHEMA if isinstance(self.bookmark_properties, (str, bytes)): - self.bookmark_properties = [self.bookmark_properties] + self.bookmark_properties = [self.bookmark_properties] # type: ignore[unreachable] if self.bookmark_properties and not isinstance(self.bookmark_properties, list): - msg = "bookmark_properties must be a string or list of strings" + msg = "bookmark_properties must be a string or list of strings" # type: ignore[unreachable] raise ValueError(msg) diff --git a/singer_sdk/authenticators.py b/singer_sdk/authenticators.py index c6478cb92..3a7fd8833 100644 --- a/singer_sdk/authenticators.py +++ b/singer_sdk/authenticators.py @@ -5,8 +5,8 @@ import base64 import datetime import math +import sys import typing as t -import warnings from types import MappingProxyType from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit @@ -14,6 +14,11 @@ from singer_sdk.helpers._util import utc_now +if sys.version_info < (3, 13): + from typing_extensions import deprecated +else: + from warnings import deprecated + if t.TYPE_CHECKING: import logging @@ -71,7 +76,7 @@ def __call__(cls, *args: t.Any, **kwargs: t.Any) -> t.Any: # noqa: ANN401 A singleton instance of the derived class. """ if cls.__single_instance: - return cls.__single_instance + return cls.__single_instance # type: ignore[unreachable] single_obj = cls.__new__(cls, None) # type: ignore[call-overload] single_obj.__init__(*args, **kwargs) cls.__single_instance = single_obj @@ -165,7 +170,7 @@ def __init__( """ super().__init__(stream=stream) if self.auth_headers is None: - self.auth_headers = {} + self.auth_headers = {} # type: ignore[unreachable] if auth_headers: self.auth_headers.update(auth_headers) @@ -206,11 +211,11 @@ def __init__( if location == "header": if self.auth_headers is None: - self.auth_headers = {} + self.auth_headers = {} # type: ignore[unreachable] self.auth_headers.update(auth_credentials) elif location == "params": if self.auth_params is None: - self.auth_params = {} + self.auth_params = {} # type: ignore[unreachable] self.auth_params.update(auth_credentials) @classmethod @@ -255,7 +260,7 @@ def __init__(self, stream: RESTStream, token: str) -> None: auth_credentials = {"Authorization": f"Bearer {token}"} if self.auth_headers is None: - self.auth_headers = {} + self.auth_headers = {} # type: ignore[unreachable] self.auth_headers.update(auth_credentials) @classmethod @@ -277,6 +282,10 @@ def create_for_stream( return cls(stream=stream, token=token) +@deprecated( + "BasicAuthenticator is deprecated. Use requests.auth.HTTPBasicAuth instead.", + category=DeprecationWarning, +) class BasicAuthenticator(APIAuthenticatorBase): """Implements basic authentication for REST Streams. @@ -302,19 +311,13 @@ def __init__( password: API password. """ super().__init__(stream=stream) - warnings.warn( - "BasicAuthenticator is deprecated. Use " - "requests.auth.HTTPBasicAuth instead.", - DeprecationWarning, - stacklevel=2, - ) credentials = f"{username}:{password}".encode() auth_token = base64.b64encode(credentials).decode("ascii") auth_credentials = {"Authorization": f"Basic {auth_token}"} if self.auth_headers is None: - self.auth_headers = {} + self.auth_headers = {} # type: ignore[unreachable] self.auth_headers.update(auth_credentials) @classmethod diff --git a/singer_sdk/connectors/sql.py b/singer_sdk/connectors/sql.py index c455bbaaa..53ba1f8dc 100644 --- a/singer_sdk/connectors/sql.py +++ b/singer_sdk/connectors/sql.py @@ -4,6 +4,7 @@ import functools import logging +import sys import typing as t import warnings from collections import UserString @@ -19,6 +20,11 @@ from singer_sdk.helpers._util import dump_json, load_json from singer_sdk.helpers.capabilities import TargetLoadMethods +if sys.version_info < (3, 13): + from typing_extensions import deprecated +else: + from warnings import deprecated + if t.TYPE_CHECKING: from sqlalchemy.engine import Engine from sqlalchemy.engine.reflection import Inspector @@ -250,6 +256,14 @@ def _connect(self) -> t.Iterator[sa.engine.Connection]: with self._engine.connect().execution_options(stream_results=True) as conn: yield conn + @deprecated( + "`SQLConnector.create_sqlalchemy_connection` is deprecated. " + "If you need to execute something that isn't available " + "on the connector currently, make a child class and " + "add your required method on that connector.", + category=DeprecationWarning, + stacklevel=1, + ) def create_sqlalchemy_connection(self) -> sa.engine.Connection: """(DEPRECATED) Return a new SQLAlchemy connection using the provided config. @@ -269,16 +283,14 @@ def create_sqlalchemy_connection(self) -> sa.engine.Connection: Returns: A newly created SQLAlchemy engine object. """ - warnings.warn( - "`SQLConnector.create_sqlalchemy_connection` is deprecated. " - "If you need to execute something that isn't available " - "on the connector currently, make a child class and " - "add your required method on that connector.", - DeprecationWarning, - stacklevel=2, - ) return self._engine.connect().execution_options(stream_results=True) + @deprecated( + "`SQLConnector.create_sqlalchemy_engine` is deprecated. Override " + "`_engine` or `sqlalchemy_url` instead.", + category=DeprecationWarning, + stacklevel=1, + ) def create_sqlalchemy_engine(self) -> Engine: """(DEPRECATED) Return a new SQLAlchemy engine using the provided config. @@ -288,12 +300,6 @@ def create_sqlalchemy_engine(self) -> Engine: Returns: A newly created SQLAlchemy engine object. """ - warnings.warn( - "`SQLConnector.create_sqlalchemy_engine` is deprecated. Override" - "`_engine` or sqlalchemy_url` instead.", - DeprecationWarning, - stacklevel=2, - ) return self._engine @property @@ -600,7 +606,7 @@ def discover_catalog_entry( # Detect key properties possible_primary_keys: list[list[str]] = [] pk_def = inspected.get_pk_constraint(table_name, schema=schema_name) - if pk_def and "constrained_columns" in pk_def: + if pk_def and "constrained_columns" in pk_def: # type: ignore[redundant-expr] possible_primary_keys.append(pk_def["constrained_columns"]) # An element of the columns list is ``None`` if it's an expression and is @@ -1057,7 +1063,7 @@ def merge_sql_types( # Get the generic type class for opt in sql_types: # Get the length - opt_len: int = getattr(opt, "length", 0) + opt_len: int | None = getattr(opt, "length", 0) generic_type = type(opt.as_generic()) if isinstance(generic_type, type): diff --git a/singer_sdk/helpers/_batch.py b/singer_sdk/helpers/_batch.py index b57002e1d..2e4ae4615 100644 --- a/singer_sdk/helpers/_batch.py +++ b/singer_sdk/helpers/_batch.py @@ -232,7 +232,7 @@ def __post_init__(self) -> None: self.storage = StorageTarget.from_dict(self.storage) if self.batch_size is None: - self.batch_size = DEFAULT_BATCH_SIZE + self.batch_size = DEFAULT_BATCH_SIZE # type: ignore[unreachable] def asdict(self) -> dict[str, t.Any]: """Return a dictionary representation of the message. diff --git a/singer_sdk/helpers/_catalog.py b/singer_sdk/helpers/_catalog.py index 90eec4c5e..a8747d30c 100644 --- a/singer_sdk/helpers/_catalog.py +++ b/singer_sdk/helpers/_catalog.py @@ -43,7 +43,7 @@ def _pop_deselected_schema( schema_at_breadcrumb = schema_at_breadcrumb.get(crumb, {}) if not isinstance(schema_at_breadcrumb, dict): # pragma: no cover - msg = ( + msg = ( # type: ignore[unreachable] "Expected dictionary type instead of " f"'{type(schema_at_breadcrumb).__name__}' '{schema_at_breadcrumb}' for " f"'{stream_name}' bookmark '{breadcrumb!s}' in '{schema}'" @@ -123,7 +123,7 @@ def set_catalog_stream_selected( """ breadcrumb = breadcrumb or () if not isinstance(breadcrumb, tuple): # pragma: no cover - msg = ( + msg = ( # type: ignore[unreachable] f"Expected tuple value for breadcrumb '{breadcrumb}'. Got " f"{type(breadcrumb).__name__}" ) diff --git a/singer_sdk/helpers/_state.py b/singer_sdk/helpers/_state.py index a910bb71e..fd7dee377 100644 --- a/singer_sdk/helpers/_state.py +++ b/singer_sdk/helpers/_state.py @@ -118,7 +118,7 @@ def get_writeable_state_dict( ValueError: Raise an error if duplicate entries are found. """ if tap_state is None: - msg = "Cannot write state to missing state dictionary." + msg = "Cannot write state to missing state dictionary." # type: ignore[unreachable] raise ValueError(msg) if "bookmarks" not in tap_state: diff --git a/singer_sdk/mapper.py b/singer_sdk/mapper.py index a2e7bc956..0214fe9e9 100644 --- a/singer_sdk/mapper.py +++ b/singer_sdk/mapper.py @@ -377,7 +377,7 @@ def _eval_type( ValueError: If the expression is ``None``. """ if expr is None: - msg = "Expression should be str, not None" + msg = "Expression should be str, not None" # type: ignore[unreachable] raise ValueError(msg) default = default or th.StringType() @@ -564,7 +564,7 @@ def always_true(record: dict) -> bool: elif filter_rule is None: filter_fn = always_true else: - msg = ( + msg = ( # type: ignore[unreachable] f"Unexpected filter rule type '{type(filter_rule).__name__}' in " f"expression {filter_rule!s}. Expected 'str' or 'None'." ) @@ -783,9 +783,7 @@ def register_raw_stream_schema( # noqa: PLR0912, C901 key_properties=key_properties, flattening_options=self.flattening_options, ) - elif stream_def is None or ( - isinstance(stream_def, str) and stream_def == NULL_STRING - ): + elif stream_def is None or (stream_def == NULL_STRING): mapper = RemoveRecordTransform( stream_alias=stream_alias, raw_schema=schema, @@ -800,7 +798,7 @@ def register_raw_stream_schema( # noqa: PLR0912, C901 raise StreamMapConfigError(msg) else: - msg = ( + msg = ( # type: ignore[unreachable] f"Unexpected stream definition type. Expected str, dict, or None. " f"Got '{type(stream_def).__name__}'." ) diff --git a/singer_sdk/plugin_base.py b/singer_sdk/plugin_base.py index eb5b39de3..ed37bfb3f 100644 --- a/singer_sdk/plugin_base.py +++ b/singer_sdk/plugin_base.py @@ -153,7 +153,7 @@ def __init__( elif isinstance(config, dict): config_dict = config else: - msg = f"Error parsing config of type '{type(config).__name__}'." + msg = f"Error parsing config of type '{type(config).__name__}'." # type: ignore[unreachable] raise ValueError(msg) if parse_env_config: self.logger.info("Parsing env var for settings config...") diff --git a/singer_sdk/streams/core.py b/singer_sdk/streams/core.py index 51a968313..e65f577f2 100644 --- a/singer_sdk/streams/core.py +++ b/singer_sdk/streams/core.py @@ -162,7 +162,7 @@ def __init__( elif isinstance(schema, singer.Schema): self._schema = schema.to_dict() else: - msg = f"Unexpected type {type(schema).__name__} for arg 'schema'." + msg = f"Unexpected type {type(schema).__name__} for arg 'schema'." # type: ignore[unreachable] raise ValueError(msg) if self.schema_filepath: @@ -187,7 +187,7 @@ def stream_maps(self) -> list[StreamMap]: if self._stream_maps: return self._stream_maps - if self._tap.mapper: + if self._tap.mapper: # type: ignore[truthy-bool] self._stream_maps = self._tap.mapper.stream_maps[self.name] self.logger.info( "Tap has custom mapper. Using %d provided map(s).", diff --git a/singer_sdk/streams/graphql.py b/singer_sdk/streams/graphql.py index 4e5455bc3..22a5fb0cc 100644 --- a/singer_sdk/streams/graphql.py +++ b/singer_sdk/streams/graphql.py @@ -71,7 +71,7 @@ def prepare_request_payload( query = self.query if query is None: - msg = "Graphql `query` property not set." + msg = "Graphql `query` property not set." # type: ignore[unreachable] raise ValueError(msg) if not query.lstrip().startswith("query"): diff --git a/singer_sdk/tap_base.py b/singer_sdk/tap_base.py index d69fa5f38..d246a2790 100644 --- a/singer_sdk/tap_base.py +++ b/singer_sdk/tap_base.py @@ -148,7 +148,7 @@ def state(self) -> dict: RuntimeError: If state has not been initialized. """ if self._state is None: - msg = "Could not read from uninitialized state." + msg = "Could not read from uninitialized state." # type: ignore[unreachable] raise RuntimeError(msg) return self._state @@ -398,7 +398,7 @@ def load_state(self, state: dict[str, t.Any]) -> None: initialized. """ if self.state is None: - msg = "Cannot write to uninitialized state dictionary." + msg = "Cannot write to uninitialized state dictionary." # type: ignore[unreachable] raise ValueError(msg) for stream_name, stream_state in state.get("bookmarks", {}).items(): diff --git a/singer_sdk/testing/legacy.py b/singer_sdk/testing/legacy.py index a47d3e770..eae4c5b5d 100644 --- a/singer_sdk/testing/legacy.py +++ b/singer_sdk/testing/legacy.py @@ -40,7 +40,7 @@ def _test_discovery() -> None: catalog1 = _get_tap_catalog(tap_class, config or {}) # Reset and re-initialize with an input catalog tap2: Tap = tap_class(config=config, parse_env_config=True, catalog=catalog1) - assert tap2 + assert tap2 # type: ignore[truthy-bool] def _test_stream_connections() -> None: # Initialize with basic config diff --git a/singer_sdk/testing/tap_tests.py b/singer_sdk/testing/tap_tests.py index 5839e0cea..92e0b13e1 100644 --- a/singer_sdk/testing/tap_tests.py +++ b/singer_sdk/testing/tap_tests.py @@ -48,7 +48,7 @@ def test(self) -> None: catalog=catalog, **kwargs, ) - assert tap2 + assert tap2 # type: ignore[truthy-bool] class TapStreamConnectionTest(TapTestTemplate): @@ -218,7 +218,7 @@ def test(self) -> None: try: for v in self.non_null_attribute_values: error_message = f"Unable to parse value ('{v}') with datetime parser." - assert datetime_fromisoformat(v), error_message + assert datetime_fromisoformat(v), error_message # type: ignore[truthy-bool] except ValueError as e: raise AssertionError(error_message) from e diff --git a/singer_sdk/typing.py b/singer_sdk/typing.py index e1b270ebe..31788989b 100644 --- a/singer_sdk/typing.py +++ b/singer_sdk/typing.py @@ -194,7 +194,7 @@ def __get__(self, instance: P, owner: type[P]) -> t.Any: # noqa: ANN401 The property value. """ if instance is None: - instance = owner() + instance = owner() # type: ignore[unreachable] return self.fget(instance) @@ -1132,13 +1132,10 @@ def to_jsonschema_type( type_name = from_type elif isinstance(from_type, sa.types.TypeEngine): # pragma: no cover type_name = type(from_type).__name__ - elif isinstance(from_type, type) and issubclass( - from_type, - sa.types.TypeEngine, - ): + elif issubclass(from_type, sa.types.TypeEngine): type_name = from_type.__name__ else: # pragma: no cover - msg = "Expected `str` or a SQLAlchemy `TypeEngine` object or type." + msg = "Expected `str` or a SQLAlchemy `TypeEngine` object or type." # type: ignore[unreachable] # TODO: this should be a TypeError, but it's a breaking change. raise ValueError(msg) # noqa: TRY004 diff --git a/tests/core/test_connector_sql.py b/tests/core/test_connector_sql.py index 8ab0f07b7..5b866366a 100644 --- a/tests/core/test_connector_sql.py +++ b/tests/core/test_connector_sql.py @@ -160,7 +160,7 @@ def test_engine_creates_and_returns_cached_engine(self, connector): engine2 = connector._cached_engine assert engine1 is engine2 - def test_deprecated_functions_warn(self, connector): + def test_deprecated_functions_warn(self, connector: SQLConnector): with pytest.deprecated_call(): connector.create_sqlalchemy_engine() with pytest.deprecated_call():