Skip to content

Commit

Permalink
refactor: Drop support for Python 3.7
Browse files Browse the repository at this point in the history
Backport from the V1 branch to maybe release this earlier?
  • Loading branch information
edgarrmondragon committed Jan 11, 2024
1 parent 2fe3e8d commit c4c6b65
Show file tree
Hide file tree
Showing 18 changed files with 211 additions and 703 deletions.
3 changes: 1 addition & 2 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ body:
description: Version of Python you are using
options:
- "3.6 (deprecated)"
- "3.7"
- "3.8"
- "3.9"
- "3.10"
Expand Down Expand Up @@ -76,6 +75,6 @@ body:
attributes:
label: Code
description: Paste the failing code and/or traceback, if applicable
render: python
render: Python
validations:
required: false
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
matrix:
session: [tests]
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
sqlalchemy: ["2"]
include:
- { session: tests, python-version: "3.11", os: "ubuntu-latest", sqlalchemy: "1" }
Expand Down
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
COOKIECUTTER_REPLAY_FILES = list(Path("./e2e-tests/cookiecutters").glob("*.json"))

package = "singer_sdk"
python_versions = ["3.12", "3.11", "3.10", "3.9", "3.8", "3.7"]
python_versions = ["3.12", "3.11", "3.10", "3.9", "3.8"]
main_python_version = "3.11"
locations = "singer_sdk", "tests", "noxfile.py", "docs/conf.py"
nox.options.sessions = (
Expand Down
778 changes: 167 additions & 611 deletions poetry.lock

Large diffs are not rendered by default.

46 changes: 11 additions & 35 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand All @@ -39,7 +38,7 @@ license = "Apache-2.0"
"Youtube" = "https://www.youtube.com/meltano"

[tool.poetry.dependencies]
python = ">=3.7.1"
python = ">=3.8"
backoff = { version = ">=2.0.0", python = "<4" }
backports-datetime-fromisoformat = { version = ">=2.0.1", python = "<3.11" }
click = "~=8.0"
Expand All @@ -50,16 +49,10 @@ importlib-resources = {version = ">=5.12.0", python = "<3.9"}
inflection = ">=0.5.1"
joblib = ">=1.0.1"
jsonpath-ng = ">=1.5.3"
jsonschema = [
{ version = ">=4.16.0,<4.18", python = "<3.8" },
{ version = ">=4.16.0", python = ">=3.8" },
]
jsonschema = ">=4.16.0"
memoization = { version = ">=0.3.2,<0.5.0", python = "<4" }
packaging = ">=23.1"
pendulum = [
{ version = ">=2.1.0,<3", python = "<3.8" },
{ version = ">=2.1.0,<4", python = ">=3.8" },
]
pendulum = ">=2.1.0,<4"
PyJWT = "~=2.4"
python-dateutil = ">=2.8.2"
python-dotenv = ">=0.20"
Expand All @@ -80,23 +73,19 @@ furo = {version = ">=2022.12.7", optional = true}
sphinx-copybutton = {version = ">=0.3.1", optional = true}
myst-parser = {version = ">=1", optional = true}
sphinx-autobuild = {version = ">=2021.3.14", optional = true}
sphinx-inline-tabs = {version = ">=2023.4.21", optional = true, markers = "python_version >= \"3.8\""}
sphinx-notfound-page = {version = ">=1.0.0", optional = true, python = ">=3.8"}
sphinx-inline-tabs = {version = ">=2023.4.21", optional = true }
sphinx-notfound-page = {version = ">=1.0.0", optional = true }
sphinx-reredirects = {version = ">=0.1.1", optional = true}

# File storage dependencies installed as optional 'filesystem' extras
fs-s3fs = {version = ">=1.1.1", optional = true}

# Parquet file dependencies installed as optional 'parquet' extras
numpy = [
{ version = "<1.22", python = "<3.8", optional = true },
{ version = ">=1.22,<1.25", python = ">=3.8,<3.9", optional = true },
{ version = ">=1.22", python = ">=3.9", optional = true },
]
pyarrow = [
{ version = ">=11,<13", python = "<3.8", optional = true },
{ version = ">=13", python = ">=3.8", optional = true }
]
pyarrow = { version = ">=13", optional = true }

# Testing dependencies installed as optional 'testing' extras
pytest = {version=">=7.2.1", optional = true}
Expand All @@ -121,31 +110,18 @@ testing = [
parquet = ["numpy", "pyarrow"]

[tool.poetry.group.dev.dependencies]
coverage = [
{extras = ["toml"], version = ">=7.2,<7.3", python = "<3.8"},
{extras = ["toml"], version = ">=7.2", python = ">=3.8,<3.12"},
{extras = ["toml"], version = ">=7.4", python = ">=3.12"},
]
coverage = {extras = ["toml"], version = ">=7.4"}

# TODO: Remove the Python 3.12 marker when DuckDB supports it
duckdb = { version = ">=0.8.0", python = "<3.12" }
duckdb-engine = { version = ">=0.9.4", python = "<3.12" }

mypy = [
{ version = ">=1.0,<1.5", python = "<3.8" },
{ version = ">=1.0", python = ">=3.8" },
]
mypy = ">=1.0"
pytest-benchmark = ">=4.0.0"
pytest-snapshot = ">=0.9.0"
requests-mock = ">=1.10.0"
time-machine = [
{ version = ">=2.10.0,<2.11", python = "<3.8" },
{ version = ">=2.10.0", python = ">=3.8" },
]
types-jsonschema = [
{ version = ">=4.17.0.6,<4.18", python = "<3.8" },
{ version = ">=4.17.0.6", python = ">=3.8" },
]
time-machine = ">=2.10.0"
types-jsonschema = ">=4.17.0.6"
types-python-dateutil = ">=2.8.19"
types-pytz = ">=2022.7.1.2"
types-requests = ">=2.28.11"
Expand Down Expand Up @@ -247,7 +223,7 @@ parquet = "singer_sdk.contrib.batch_encoder_parquet:ParquetBatcher"
[tool.ruff]
line-length = 88
src = ["samples", "singer_sdk", "tests"]
target-version = "py37"
target-version = "py38"

[tool.ruff.format]
docstring-code-format = true
Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/connectors/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ def quote(self, name: str) -> str:
],
)

@lru_cache() # noqa: B019
@lru_cache # noqa: B019
def _warn_no_view_detection(self) -> None:
"""Print a warning, but only the first time."""
self.logger.warning(
Expand Down
9 changes: 0 additions & 9 deletions singer_sdk/helpers/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@
import datetime
import sys

if sys.version_info < (3, 8):
import importlib_metadata as metadata
from typing_extensions import final
else:
from importlib import metadata
from typing import final # noqa: ICN003

if sys.version_info < (3, 9):
import importlib_resources
else:
Expand Down Expand Up @@ -39,8 +32,6 @@
time_fromisoformat = datetime.time.fromisoformat

__all__ = [
"metadata",
"final",
"entry_points",
"datetime_fromisoformat",
"date_fromisoformat",
Expand Down
6 changes: 4 additions & 2 deletions singer_sdk/helpers/_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,10 @@ def get_writeable_state_dict(
if "partitions" not in stream_state:
stream_state["partitions"] = []
stream_state_partitions: list[dict] = stream_state["partitions"]
found = _find_in_partitions_list(stream_state_partitions, state_partition_context)
if found:
if found := _find_in_partitions_list(
stream_state_partitions,
state_partition_context,
):
return found

return _create_in_partitions_list(stream_state_partitions, state_partition_context)
Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/helpers/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def is_number_type(property_schema: dict) -> bool | None:
return False


@lru_cache()
@lru_cache
def _warn_unmapped_properties(
stream_name: str,
property_names: tuple[str],
Expand Down
3 changes: 1 addition & 2 deletions singer_sdk/io_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
from singer_sdk._singerlib.messages import Message, SingerMessageType
from singer_sdk._singerlib.messages import format_message as singer_format_message
from singer_sdk._singerlib.messages import write_message as singer_write_message
from singer_sdk.helpers._compat import final

logger = logging.getLogger(__name__)


class SingerReader(metaclass=abc.ABCMeta):
"""Interface for all plugins reading Singer messages from stdin."""

@final
@t.final
def listen(self, file_input: t.IO[str] | None = None) -> None:
"""Read from input until all messages are processed.
Expand Down
8 changes: 1 addition & 7 deletions singer_sdk/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@

from __future__ import annotations

import sys
import typing as t
from abc import ABCMeta, abstractmethod
from urllib.parse import ParseResult, urlparse

from singer_sdk.helpers.jsonpath import extract_jsonpath

if sys.version_info >= (3, 8):
from typing import Protocol # noqa: ICN003
else:
from typing_extensions import Protocol

if t.TYPE_CHECKING:
from requests import Response

Expand Down Expand Up @@ -382,7 +376,7 @@ def get_next(self, response: Response) -> int | None: # noqa: ARG002
return self._value + self._page_size


class LegacyPaginatedStreamProtocol(Protocol[TPageToken]):
class LegacyPaginatedStreamProtocol(t.Protocol[TPageToken]):
"""Protocol for legacy paginated streams classes."""

def get_next_page_token(
Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/plugin_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import sys
import time
import typing as t
from importlib import metadata
from pathlib import Path, PurePath
from types import MappingProxyType

Expand All @@ -23,7 +24,6 @@
)
from singer_sdk.exceptions import ConfigValidationError
from singer_sdk.helpers._classproperty import classproperty
from singer_sdk.helpers._compat import metadata
from singer_sdk.helpers._secrets import SecretString, is_common_secret_key
from singer_sdk.helpers._util import read_json_file
from singer_sdk.helpers.capabilities import (
Expand Down
7 changes: 3 additions & 4 deletions singer_sdk/sinks/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from singer_sdk.helpers._compat import (
date_fromisoformat,
datetime_fromisoformat,
final,
time_fromisoformat,
)
from singer_sdk.helpers._typing import (
Expand Down Expand Up @@ -144,7 +143,7 @@ def is_full(self) -> bool:

# Tally methods

@final
@t.final
def tally_record_read(self, count: int = 1) -> None:
"""Increment the records read tally.
Expand All @@ -156,7 +155,7 @@ def tally_record_read(self, count: int = 1) -> None:
self._total_records_read += count
self._batch_records_read += count

@final
@t.final
def tally_record_written(self, count: int = 1) -> None:
"""Increment the records written tally.
Expand All @@ -169,7 +168,7 @@ def tally_record_written(self, count: int = 1) -> None:
"""
self._total_records_written += count

@final
@t.final
def tally_duplicate_merged(self, count: int = 1) -> None:
"""Increment the records merged tally.
Expand Down
6 changes: 3 additions & 3 deletions singer_sdk/sinks/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from __future__ import annotations

import abc
import typing as t

from singer_sdk.helpers._compat import final
from singer_sdk.sinks.core import Sink


Expand All @@ -23,7 +23,7 @@ def _after_process_record(self, context: dict) -> None: # noqa: ARG002
"""
self.tally_record_written()

@final
@t.final
def process_batch(self, context: dict) -> None:
"""Do nothing and return immediately.
Expand All @@ -35,7 +35,7 @@ def process_batch(self, context: dict) -> None:
context: Stream partition or context dictionary.
"""

@final
@t.final
def start_batch(self, context: dict) -> None:
"""Do nothing and return immediately.
Expand Down
7 changes: 3 additions & 4 deletions singer_sdk/streams/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
SDKBatchMessage,
)
from singer_sdk.helpers._catalog import pop_deselected_record_properties
from singer_sdk.helpers._compat import final
from singer_sdk.helpers._flattening import get_flattening_options
from singer_sdk.helpers._state import (
finalize_state_progress_markers,
Expand Down Expand Up @@ -303,7 +302,7 @@ def selected(self, value: bool | None) -> None:
self.metadata.root.selected = value
self._mask = self.metadata.resolve_selection()

@final
@t.final
@property
def has_selected_descendents(self) -> bool:
"""Check descendents.
Expand All @@ -316,7 +315,7 @@ def has_selected_descendents(self) -> bool:
for child in self.child_streams or []
)

@final
@t.final
@property
def descendent_streams(self) -> list[Stream]:
"""Get child streams.
Expand Down Expand Up @@ -1157,7 +1156,7 @@ def _sync_batches(

# Public methods ("final", not recommended to be overridden)

@final
@t.final
def sync(self, context: dict | None = None) -> None:
"""Sync this stream.
Expand Down
11 changes: 3 additions & 8 deletions singer_sdk/streams/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import abc
import typing as t
from functools import cached_property

import sqlalchemy as sa

Expand Down Expand Up @@ -78,7 +79,7 @@ def metadata(self) -> MetadataMapping:
"""
return self._singer_catalog_entry.metadata

@property # TODO: Investigate @cached_property after py > 3.7
@cached_property
def schema(self) -> dict:
"""Return metadata object (dict) as specified in the Singer spec.
Expand All @@ -87,13 +88,7 @@ def schema(self) -> dict:
Returns:
The schema object.
"""
if not self._cached_schema:
self._cached_schema = t.cast(
dict,
self._singer_catalog_entry.schema.to_dict(),
)

return self._cached_schema
return self._singer_catalog_entry.schema.to_dict()

@property
def tap_stream_id(self) -> str:
Expand Down
Loading

0 comments on commit c4c6b65

Please sign in to comment.