diff --git a/pyproject.toml b/pyproject.toml index eb17d2d83..72e906ce0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -234,6 +234,7 @@ parquet = "singer_sdk.contrib.batch_encoder_parquet:ParquetBatcher" [tool.ruff] line-length = 88 +preview = true src = ["samples", "singer_sdk", "tests"] target-version = "py37" @@ -243,11 +244,12 @@ exclude = [ "*simpleeval*", ] ignore = [ - "ANN101", # Missing type annotation for `self` in method - "ANN102", # Missing type annotation for `cls` in class method - "N818", # Exception name should be named with an Error suffix - "COM812", # missing-trailing-comma - "ISC001", # single-line-implicit-string-concatenation + "ANN101", # Missing type annotation for `self` in method + "ANN102", # Missing type annotation for `cls` in class method + "N818", # Exception name should be named with an Error suffix + "COM812", # missing-trailing-comma + "ISC001", # single-line-implicit-string-concatenation + "PLR6301", # Method {method_name} could be a function, class method, or static method ] select = [ "F", # Pyflakes @@ -294,6 +296,8 @@ select = [ "PLR", # pylint (refactor) "PLW", # pylint (warning) "PERF", # perflint + "FURB", # refurb + "LOG", # flake8-logging "RUF", # ruff ] unfixable = [ diff --git a/samples/sample_custom_sql_adapter/connector.py b/samples/sample_custom_sql_adapter/connector.py index 6f7745a73..74af81bb4 100644 --- a/samples/sample_custom_sql_adapter/connector.py +++ b/samples/sample_custom_sql_adapter/connector.py @@ -19,7 +19,7 @@ def __init__(self, *args, **kwargs): @classmethod def import_dbapi(cls): """Import the sqlite3 DBAPI.""" - import sqlite3 + import sqlite3 # noqa: PLC0415 return sqlite3 diff --git a/samples/sample_target_parquet/__init__.py b/samples/sample_target_parquet/__init__.py index 748f22665..2837ad3d2 100644 --- a/samples/sample_target_parquet/__init__.py +++ b/samples/sample_target_parquet/__init__.py @@ -1,6 +1,5 @@ """Module test for target-parquet functionality.""" - from __future__ import annotations # Reuse the tap connection rather than create a new target connection: diff --git a/singer_sdk/about.py b/singer_sdk/about.py index e5bbf60de..ac14184ed 100644 --- a/singer_sdk/about.py +++ b/singer_sdk/about.py @@ -68,7 +68,6 @@ def format_about(self, about_info: AboutInfo) -> str: Args: about_info: About information. """ - ... class TextFormatter(AboutFormatter, format_name="text"): diff --git a/singer_sdk/authenticators.py b/singer_sdk/authenticators.py index fcba67e7b..3c2639182 100644 --- a/singer_sdk/authenticators.py +++ b/singer_sdk/authenticators.py @@ -223,7 +223,7 @@ def __init__( super().__init__(stream=stream) auth_credentials = {key: value} - if location not in ["header", "params"]: + if location not in {"header", "params"}: msg = "`type` must be one of 'header' or 'params'." raise ValueError(msg) diff --git a/singer_sdk/batch.py b/singer_sdk/batch.py index 4545285e4..1d194ddc7 100644 --- a/singer_sdk/batch.py +++ b/singer_sdk/batch.py @@ -1,4 +1,5 @@ """Batching utilities for Singer SDK.""" + from __future__ import annotations import itertools @@ -22,7 +23,9 @@ def __getattr__(name: str) -> t.Any: # noqa: ANN401 # pragma: no cover stacklevel=2, ) - from singer_sdk.contrib.batch_encoder_jsonl import JSONLinesBatcher + from singer_sdk.contrib.batch_encoder_jsonl import ( # noqa: PLC0415 + JSONLinesBatcher, + ) return JSONLinesBatcher diff --git a/singer_sdk/connectors/sql.py b/singer_sdk/connectors/sql.py index c4ddba880..7ee89a9c4 100644 --- a/singer_sdk/connectors/sql.py +++ b/singer_sdk/connectors/sql.py @@ -24,7 +24,7 @@ from sqlalchemy.engine.reflection import Inspector -class SQLConnector: +class SQLConnector: # noqa: PLR0904 """Base class for SQLAlchemy-based connectors. The connector class serves as a wrapper around the SQL connection. diff --git a/singer_sdk/contrib/batch_encoder_parquet.py b/singer_sdk/contrib/batch_encoder_parquet.py index 1d5ad9cc1..47b46385e 100644 --- a/singer_sdk/contrib/batch_encoder_parquet.py +++ b/singer_sdk/contrib/batch_encoder_parquet.py @@ -25,8 +25,8 @@ def get_batches( Yields: A list of file paths (called a manifest). """ - import pyarrow as pa - import pyarrow.parquet as pq + import pyarrow as pa # noqa: PLC0415 + import pyarrow.parquet as pq # noqa: PLC0415 sync_id = f"{self.tap_name}--{self.stream_name}-{uuid4()}" prefix = self.batch_config.storage.prefix or "" diff --git a/singer_sdk/helpers/_conformers.py b/singer_sdk/helpers/_conformers.py index 0ca70e85c..1b234f9d9 100644 --- a/singer_sdk/helpers/_conformers.py +++ b/singer_sdk/helpers/_conformers.py @@ -1,4 +1,5 @@ """Helper functions for conforming identifiers.""" + from __future__ import annotations import re diff --git a/singer_sdk/helpers/_flattening.py b/singer_sdk/helpers/_flattening.py index 3cf1f172e..ad4978313 100644 --- a/singer_sdk/helpers/_flattening.py +++ b/singer_sdk/helpers/_flattening.py @@ -33,7 +33,7 @@ def get_flattening_options( Returns: A new FlatteningOptions object or None if flattening is disabled. """ - if "flattening_enabled" in plugin_config and plugin_config["flattening_enabled"]: + if plugin_config.get("flattening_enabled"): return FlatteningOptions(max_level=int(plugin_config["flattening_max_depth"])) return None diff --git a/singer_sdk/io_base.py b/singer_sdk/io_base.py index f7c2ed668..ebe919d27 100644 --- a/singer_sdk/io_base.py +++ b/singer_sdk/io_base.py @@ -111,24 +111,19 @@ def _process_lines(self, file_input: t.IO[str]) -> t.Counter[str]: return Counter(**stats) @abc.abstractmethod - def _process_schema_message(self, message_dict: dict) -> None: - ... + def _process_schema_message(self, message_dict: dict) -> None: ... @abc.abstractmethod - def _process_record_message(self, message_dict: dict) -> None: - ... + def _process_record_message(self, message_dict: dict) -> None: ... @abc.abstractmethod - def _process_state_message(self, message_dict: dict) -> None: - ... + def _process_state_message(self, message_dict: dict) -> None: ... @abc.abstractmethod - def _process_activate_version_message(self, message_dict: dict) -> None: - ... + def _process_activate_version_message(self, message_dict: dict) -> None: ... @abc.abstractmethod - def _process_batch_message(self, message_dict: dict) -> None: - ... + def _process_batch_message(self, message_dict: dict) -> None: ... def _process_unknown_message(self, message_dict: dict) -> None: """Internal method to process unknown message types from a Singer tap. diff --git a/singer_sdk/mapper_base.py b/singer_sdk/mapper_base.py index 2cc943a46..76b86b9ff 100644 --- a/singer_sdk/mapper_base.py +++ b/singer_sdk/mapper_base.py @@ -56,7 +56,6 @@ def map_schema_message(self, message_dict: dict) -> t.Iterable[singer.Message]: Args: message_dict: A SCHEMA message JSON dictionary. """ - ... @abc.abstractmethod def map_record_message(self, message_dict: dict) -> t.Iterable[singer.Message]: @@ -65,7 +64,6 @@ def map_record_message(self, message_dict: dict) -> t.Iterable[singer.Message]: Args: message_dict: A RECORD message JSON dictionary. """ - ... @abc.abstractmethod def map_state_message(self, message_dict: dict) -> t.Iterable[singer.Message]: @@ -74,7 +72,6 @@ def map_state_message(self, message_dict: dict) -> t.Iterable[singer.Message]: Args: message_dict: A STATE message JSON dictionary. """ - ... @abc.abstractmethod def map_activate_version_message( @@ -86,7 +83,6 @@ def map_activate_version_message( Args: message_dict: An ACTIVATE_VERSION message JSON dictionary. """ - ... def map_batch_message( self, diff --git a/singer_sdk/metrics.py b/singer_sdk/metrics.py index e4191eadf..f6bb8e242 100644 --- a/singer_sdk/metrics.py +++ b/singer_sdk/metrics.py @@ -138,7 +138,6 @@ def context(self, value: dict | None) -> None: @abc.abstractmethod def __enter__(self) -> Meter: """Enter the meter context.""" - ... @abc.abstractmethod def __exit__( @@ -154,7 +153,6 @@ def __exit__( exc_val: The exception value. exc_tb: The exception traceback. """ - ... class Counter(Meter): diff --git a/singer_sdk/pagination.py b/singer_sdk/pagination.py index f00bb0920..1a5dd0f88 100644 --- a/singer_sdk/pagination.py +++ b/singer_sdk/pagination.py @@ -146,7 +146,6 @@ def get_next(self, response: Response) -> TPageToken | None: The next page token or index. Return `None` from this method to indicate the end of pagination. """ - ... class SinglePagePaginator(BaseAPIPaginator[None]): @@ -234,7 +233,6 @@ def get_next_url(self, response: Response) -> str | None: Args: response: API response object. """ - ... def get_next(self, response: Response) -> ParseResult | None: """Get the next pagination token or index from the API response. @@ -347,7 +345,6 @@ def has_more(self, response: Response) -> bool: Boolean flag used to indicate if the endpoint has more pages. """ - ... def get_next(self, response: Response) -> int | None: # noqa: ARG002 """Get the next page number. @@ -392,7 +389,6 @@ def has_more(self, response: Response) -> bool: Returns: Boolean flag used to indicate if the endpoint has more pages. """ - ... def get_next(self, response: Response) -> int | None: # noqa: ARG002 """Get the next page offset. @@ -420,7 +416,6 @@ def get_next_page_token( response: API response object. previous_token: Previous page token. """ - ... # pragma: no cover class LegacyStreamPaginator( diff --git a/singer_sdk/plugin_base.py b/singer_sdk/plugin_base.py index b4e82296b..68f68f5e4 100644 --- a/singer_sdk/plugin_base.py +++ b/singer_sdk/plugin_base.py @@ -109,7 +109,7 @@ def invoke(self, ctx: click.Context) -> t.Any: # noqa: ANN401 sys.exit(1) -class PluginBase(metaclass=abc.ABCMeta): +class PluginBase(metaclass=abc.ABCMeta): # noqa: PLR0904 """Abstract base class for taps.""" #: The executable name of the tap or target plugin. e.g. tap-foo diff --git a/singer_sdk/sinks/core.py b/singer_sdk/sinks/core.py index 735bd3a58..642bb4edf 100644 --- a/singer_sdk/sinks/core.py +++ b/singer_sdk/sinks/core.py @@ -42,7 +42,7 @@ JSONSchemaValidator = Draft7Validator -class Sink(metaclass=abc.ABCMeta): +class Sink(metaclass=abc.ABCMeta): # noqa: PLR0904 """Abstract base class for target sinks.""" # max timestamp/datetime supported, used to reset invalid dates @@ -550,7 +550,7 @@ def process_batch_files( importlib.util.find_spec("pyarrow") and encoding.format == BatchFileFormat.PARQUET ): - import pyarrow.parquet as pq + import pyarrow.parquet as pq # noqa: PLC0415 with storage.fs(create=False) as batch_fs, batch_fs.open( tail, diff --git a/singer_sdk/streams/core.py b/singer_sdk/streams/core.py index d235987a7..f732b92f0 100644 --- a/singer_sdk/streams/core.py +++ b/singer_sdk/streams/core.py @@ -64,7 +64,7 @@ FactoryType = t.TypeVar("FactoryType", bound="Stream") -class Stream(metaclass=abc.ABCMeta): +class Stream(metaclass=abc.ABCMeta): # noqa: PLR0904 """Abstract base class for tap streams.""" STATE_MSG_FREQUENCY = 10000 diff --git a/singer_sdk/streams/rest.py b/singer_sdk/streams/rest.py index 378b32c73..7ad590255 100644 --- a/singer_sdk/streams/rest.py +++ b/singer_sdk/streams/rest.py @@ -46,7 +46,7 @@ _Auth: TypeAlias = t.Callable[[requests.PreparedRequest], requests.PreparedRequest] -class RESTStream(Stream, t.Generic[_TToken], metaclass=abc.ABCMeta): +class RESTStream(Stream, t.Generic[_TToken], metaclass=abc.ABCMeta): # noqa: PLR0904 """Abstract base class for REST API streams.""" _page_size: int = DEFAULT_PAGE_SIZE @@ -99,7 +99,7 @@ def __init__( self._next_page_token_compiled_jsonpath = None @staticmethod - def _url_encode(val: str | datetime | bool | int | list[str]) -> str: + def _url_encode(val: str | datetime | bool | int | list[str]) -> str: # noqa: FBT001 """Encode the val argument as url-compatible string. Args: diff --git a/singer_sdk/tap_base.py b/singer_sdk/tap_base.py index 2f0f5874d..548af597a 100644 --- a/singer_sdk/tap_base.py +++ b/singer_sdk/tap_base.py @@ -1,6 +1,5 @@ """Tap abstract class.""" - from __future__ import annotations import abc @@ -46,7 +45,7 @@ class CliTestOptionValue(Enum): Disabled = "disabled" -class Tap(PluginBase, SingerWriter, metaclass=abc.ABCMeta): +class Tap(PluginBase, SingerWriter, metaclass=abc.ABCMeta): # noqa: PLR0904 """Abstract base class for taps. The Tap class governs configuration, validation, and stream discovery for tap diff --git a/singer_sdk/testing/__init__.py b/singer_sdk/testing/__init__.py index 83ca9aacc..ee8905fb5 100644 --- a/singer_sdk/testing/__init__.py +++ b/singer_sdk/testing/__init__.py @@ -27,7 +27,7 @@ def __getattr__(name: str) -> t.Any: # noqa: ANN401 stacklevel=2, ) - from .legacy import get_standard_tap_tests + from .legacy import get_standard_tap_tests # noqa: PLC0415 return get_standard_tap_tests @@ -40,7 +40,7 @@ def __getattr__(name: str) -> t.Any: # noqa: ANN401 stacklevel=2, ) - from .legacy import get_standard_target_tests + from .legacy import get_standard_target_tests # noqa: PLC0415 return get_standard_target_tests diff --git a/singer_sdk/testing/factory.py b/singer_sdk/testing/factory.py index 30740b6ef..f19d056de 100644 --- a/singer_sdk/testing/factory.py +++ b/singer_sdk/testing/factory.py @@ -1,4 +1,5 @@ """Test Class Factory.""" + from __future__ import annotations import typing as t diff --git a/singer_sdk/testing/runners.py b/singer_sdk/testing/runners.py index 71f294335..46d90cd34 100644 --- a/singer_sdk/testing/runners.py +++ b/singer_sdk/testing/runners.py @@ -149,7 +149,7 @@ def sync_all(self, **kwargs: t.Any) -> None: # noqa: ARG002 Args: kwargs: Unused keyword arguments. """ - stdout, stderr = self._execute_sync() + stdout, _stderr = self._execute_sync() messages = self._clean_sync_output(stdout) self._parse_records(messages) diff --git a/singer_sdk/typing.py b/singer_sdk/typing.py index 37c1f40c1..df2031b77 100644 --- a/singer_sdk/typing.py +++ b/singer_sdk/typing.py @@ -524,7 +524,7 @@ def __init__( required: bool = False, # noqa: FBT001, FBT002 default: T | None = None, description: str | None = None, - secret: bool | None = False, # noqa: FBT002 + secret: bool | None = False, # noqa: FBT002, FBT001 allowed_values: list[T] | None = None, examples: list[T] | None = None, ) -> None: diff --git a/tests/core/test_connector_sql.py b/tests/core/test_connector_sql.py index c07188ff7..3bdc66e30 100644 --- a/tests/core/test_connector_sql.py +++ b/tests/core/test_connector_sql.py @@ -19,7 +19,7 @@ def stringify(in_dict): return {k: str(v) for k, v in in_dict.items()} -class TestConnectorSQL: +class TestConnectorSQL: # noqa: PLR0904 """Test the SQLConnector class.""" @pytest.fixture diff --git a/tests/core/test_plugin_config.py b/tests/core/test_plugin_config.py index d0df1d69f..cc037652e 100644 --- a/tests/core/test_plugin_config.py +++ b/tests/core/test_plugin_config.py @@ -1,6 +1,5 @@ """Test plugin config functions.""" - from __future__ import annotations import typing as t diff --git a/tests/core/test_testing.py b/tests/core/test_testing.py index 5715cd1e1..28f792ef3 100644 --- a/tests/core/test_testing.py +++ b/tests/core/test_testing.py @@ -9,12 +9,12 @@ def test_module_deprecations(): with pytest.deprecated_call(): - from singer_sdk.testing import get_standard_tap_tests # noqa: F401 + from singer_sdk.testing import get_standard_tap_tests # noqa: F401, PLC0415 with pytest.deprecated_call(): - from singer_sdk.testing import get_standard_target_tests # noqa: F401 + from singer_sdk.testing import get_standard_target_tests # noqa: F401, PLC0415 - from singer_sdk import testing + from singer_sdk import testing # noqa: PLC0415 with pytest.raises( AttributeError, diff --git a/tests/samples/test_tap_sqlite.py b/tests/samples/test_tap_sqlite.py index b5ed7b549..5b6e6365d 100644 --- a/tests/samples/test_tap_sqlite.py +++ b/tests/samples/test_tap_sqlite.py @@ -116,7 +116,7 @@ def test_sqlite_tap_standard_tests(sqlite_sample_tap: SQLTap): def test_sync_sqlite_to_csv(sqlite_sample_tap: SQLTap, tmp_path: Path): _discover_and_select_all(sqlite_sample_tap) - orig_stdout, _, _, _ = tap_to_target_sync_test( + _orig_stdout, _, _, _ = tap_to_target_sync_test( sqlite_sample_tap, SampleTargetCSV(config={"target_folder": f"{tmp_path}/"}), ) diff --git a/tests/samples/test_target_csv.py b/tests/samples/test_target_csv.py index e55aa3cbc..704c1b98b 100644 --- a/tests/samples/test_target_csv.py +++ b/tests/samples/test_target_csv.py @@ -1,4 +1,5 @@ """Test tap-to-target sync.""" + from __future__ import annotations import datetime diff --git a/tests/samples/test_target_parquet.py b/tests/samples/test_target_parquet.py index 7f53036a4..4be4782d5 100644 --- a/tests/samples/test_target_parquet.py +++ b/tests/samples/test_target_parquet.py @@ -1,4 +1,5 @@ """Test class creation.""" + from __future__ import annotations import shutil