Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Dropped support for Python 3.8 #2751

Merged
merged 2 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,15 @@ jobs:
session: [tests]
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
python-version:
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
include:
- { session: doctest, python-version: "3.13", os: "ubuntu-latest" }
- { session: mypy, python-version: "3.12", os: "ubuntu-latest" }
- { session: deps, python-version: "3.12", os: "ubuntu-latest" }
- { session: mypy, python-version: "3.13", os: "ubuntu-latest" }
- { session: deps, python-version: "3.13", os: "ubuntu-latest" }

steps:
- uses: actions/checkout@v4
Expand Down
3 changes: 1 addition & 2 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@
"3.11",
"3.10",
"3.9",
"3.8",
]
main_python_version = "3.12"
main_python_version = "3.13"
locations = "singer_sdk", "tests", "noxfile.py", "docs/conf.py"
nox.options.sessions = (
"mypy",
Expand Down
968 changes: 414 additions & 554 deletions poetry.lock

Large diffs are not rendered by default.

31 changes: 12 additions & 19 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Typing :: Typed",
Expand All @@ -38,7 +38,7 @@ license = "Apache-2.0"
"Youtube" = "https://www.youtube.com/meltano"

[tool.poetry.dependencies]
python = ">=3.8"
python = ">=3.9"
backoff = { version = ">=2.0.0", python = "<4" }
backports-datetime-fromisoformat = { version = ">=2.0.1", python = "<3.11" }
click = "~=8.0"
Expand All @@ -58,23 +58,20 @@ requests = ">=2.25.1"
# TODO: remove this constraint once we get rid of the `fs` dependency
# newer setuptools versions are incompatible with some dependencies (fs)
setuptools = "<=70.3.0"
simpleeval = [
{ version = ">=0.9.13,<1", python = "<3.9" },
{ version = ">=0.9.13,!=1.0.1", python = ">=3.9" },
]
simpleeval = ">=0.9.13,!=1.0.1"
simplejson = ">=3.17.6"
sqlalchemy = ">=1.4,<3.0"
typing-extensions = ">=4.5.0"

# Sphinx dependencies installed as optional 'docs' extras
# https://github.com/readthedocs/readthedocs.org/issues/4912#issuecomment-664002569
furo = {version = ">=2024.5.6", python = ">=3.9", optional = true}
myst-parser = {version = ">=3", python = ">=3.9", optional = true}
sphinx = {version = ">=7", python = ">=3.9", optional = true}
sphinx-copybutton = {version = ">=0.5.2", python = ">=3.9", optional = true}
sphinx-inline-tabs = {version = ">=2023.4.21", python = ">=3.9", optional = true}
sphinx-notfound-page = {version = ">=1.0.0", python = ">=3.9", optional = true}
sphinx-reredirects = {version = ">=0.1.5", python = ">=3.9", optional = true}
furo = {version = ">=2024.5.6", optional = true}
myst-parser = {version = ">=3", optional = true}
sphinx = {version = ">=7", optional = true}
sphinx-copybutton = {version = ">=0.5.2", optional = true}
sphinx-inline-tabs = {version = ">=2023.4.21", optional = true}
sphinx-notfound-page = {version = ">=1.0.0", optional = true}
sphinx-reredirects = {version = ">=0.1.5", optional = true}

# File storage dependencies installed as optional 'filesystem' extras
fs-s3fs = {version = ">=1.1.1", optional = true}
Expand All @@ -86,14 +83,10 @@ s3fs = { version = ">=2024.9.0", optional = true }
# the version of Numpy that is compatible with the earliest Python version supported
# by this project, but that may not be compatible with the latest Python version.
numpy = [
{ version = ">=1.22,<1.25", python = "==3.8", optional = true },
{ version = ">=1.22,<2.1", python = "==3.9", optional = true },
{ version = ">=1.22", python = ">=3.10", optional = true },
]
pyarrow = [
{ version = ">=13,<18", python = "==3.8", optional = true },
{ version = ">=13", python = ">=3.9", optional = true },
]
pyarrow = { version = ">=13", optional = true }

# Testing dependencies installed as optional 'testing' extras
pytest = {version=">=7.2.1", optional = true}
Expand Down Expand Up @@ -318,7 +311,7 @@ extend-exclude = [
"cookiecutter/*",
]
line-length = 88
target-version = "py38"
target-version = "py39"

[tool.ruff.format]
docstring-code-format = true
Expand Down
9 changes: 2 additions & 7 deletions samples/aapl/aapl.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@

from __future__ import annotations

import importlib.resources
import json
import sys

from singer_sdk import Stream, Tap

if sys.version_info < (3, 9):
import importlib_resources
else:
import importlib.resources as importlib_resources

PROJECT_DIR = importlib_resources.files("samples.aapl")
PROJECT_DIR = importlib.resources.files("samples.aapl")


class AAPL(Stream):
Expand Down
10 changes: 2 additions & 8 deletions samples/sample_tap_countries/countries_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,15 @@
from __future__ import annotations

import abc
import sys
import importlib.resources
import typing as t

from requests_cache.session import CachedSession

from singer_sdk import typing as th
from singer_sdk.streams.graphql import GraphQLStream

if sys.version_info < (3, 9):
import importlib_resources
else:
from importlib import resources as importlib_resources


SCHEMAS_DIR = importlib_resources.files(__package__) / "schemas"
SCHEMAS_DIR = importlib.resources.files(__package__) / "schemas"


class CountriesAPIStream(GraphQLStream, metaclass=abc.ABCMeta):
Expand Down
10 changes: 2 additions & 8 deletions samples/sample_tap_gitlab/gitlab_graphql_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,13 @@

from __future__ import annotations

import sys
import importlib.resources

from singer_sdk.streams import GraphQLStream

if sys.version_info < (3, 9):
import importlib_resources
else:
from importlib import resources as importlib_resources


SITE_URL = "https://gitlab.com/graphql"

SCHEMAS_DIR = importlib_resources.files(__package__) / "schemas"
SCHEMAS_DIR = importlib.resources.files(__package__) / "schemas"


class GitlabGraphQLStream(GraphQLStream):
Expand Down
10 changes: 2 additions & 8 deletions samples/sample_tap_gitlab/gitlab_rest_streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

import sys
import importlib.resources
import typing as t

from singer_sdk.authenticators import SimpleAuthenticator
Expand All @@ -19,13 +19,7 @@
StringType,
)

if sys.version_info < (3, 9):
import importlib_resources
else:
from importlib import resources as importlib_resources


SCHEMAS_DIR = importlib_resources.files(__package__) / "schemas"
SCHEMAS_DIR = importlib.resources.files(__package__) / "schemas"

DEFAULT_URL_BASE = "https://gitlab.com/api/v4"

Expand Down
8 changes: 4 additions & 4 deletions singer_sdk/_singerlib/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
from typing_extensions import TypeAlias


Breadcrumb = t.Tuple[str, ...]
Breadcrumb = tuple[str, ...]

logger = logging.getLogger(__name__)


class SelectionMask(t.Dict[Breadcrumb, bool]):
class SelectionMask(dict[Breadcrumb, bool]):
"""Boolean mask for property selection in schemas and records."""

def __missing__(self, breadcrumb: Breadcrumb) -> bool:
Expand Down Expand Up @@ -95,7 +95,7 @@ class StreamMetadata(Metadata):
AnyMetadata: TypeAlias = t.Union[Metadata, StreamMetadata]


class MetadataMapping(t.Dict[Breadcrumb, AnyMetadata]):
class MetadataMapping(dict[Breadcrumb, AnyMetadata]):
"""Stream metadata mapping."""

@classmethod
Expand Down Expand Up @@ -352,7 +352,7 @@ def to_dict(self) -> dict[str, t.Any]: # noqa: C901
return result


class Catalog(t.Dict[str, CatalogEntry]):
class Catalog(dict[str, CatalogEntry]):
"""Singer catalog mapping of stream entries."""

@classmethod
Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
]

# Keep these in sync with the supported Python versions in pyproject.toml
_PY_MIN_VERSION = 8
_PY_MIN_VERSION = 9
_PY_MAX_VERSION = 13


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 @@ -197,8 +197,8 @@
return th.BooleanType.type_dict # type: ignore[no-any-return]


JSONtoSQLHandler: TypeAlias = t.Union[

Check warning on line 200 in singer_sdk/connectors/sql.py

View workflow job for this annotation

GitHub Actions / Check API Changes

JSONtoSQLHandler

Attribute value was changed: `t.Union[t.Type[sa.types.TypeEngine], t.Callable[[dict], sa.types.TypeEngine]]` -> `t.Union[type[sa.types.TypeEngine], t.Callable[[dict], sa.types.TypeEngine]]`
t.Type[sa.types.TypeEngine],
type[sa.types.TypeEngine],
t.Callable[[dict], sa.types.TypeEngine],
]

Expand Down
8 changes: 4 additions & 4 deletions singer_sdk/contrib/batch_encoder_jsonl.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ def get_batches(
filename = f"{prefix}{sync_id}-{i}.json.gz"
with self.batch_config.storage.fs(create=True) as fs:
# TODO: Determine compression from config.
with fs.open(filename, "wb") as f, gzip.GzipFile(
fileobj=f,
mode="wb",
) as gz:
with (
fs.open(filename, "wb") as f,
gzip.GzipFile(fileobj=f, mode="wb") as gz,
):
gz.writelines(
(serialize_json(record) + "\n").encode() for record in chunk
)
Expand Down
10 changes: 2 additions & 8 deletions singer_sdk/helpers/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,9 @@

import datetime
import sys
from importlib import resources as importlib_resources

if sys.version_info < (3, 9):
import importlib_resources
else:
from importlib import resources as importlib_resources

if sys.version_info < (3, 9):
from importlib_resources.abc import Traversable
elif sys.version_info < (3, 12):
if sys.version_info < (3, 12):
from importlib.abc import Traversable
else:
from importlib.resources.abc import Traversable
Expand Down
8 changes: 2 additions & 6 deletions singer_sdk/helpers/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@

import sys
import typing as t
from collections.abc import Mapping

import requests

if sys.version_info < (3, 9):
from typing import Mapping # noqa: ICN003
else:
from collections.abc import Mapping

if sys.version_info < (3, 10):
from typing_extensions import TypeAlias
else:
Expand All @@ -24,5 +20,5 @@
]

Context: TypeAlias = Mapping[str, t.Any]
Record: TypeAlias = t.Dict[str, t.Any]
Record: TypeAlias = dict[str, t.Any]

Check warning on line 23 in singer_sdk/helpers/types.py

View workflow job for this annotation

GitHub Actions / Check API Changes

Record

Attribute value was changed: `t.Dict[str, t.Any]` -> `dict[str, t.Any]`
Auth: TypeAlias = t.Callable[[requests.PreparedRequest], requests.PreparedRequest]
2 changes: 1 addition & 1 deletion singer_sdk/mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
return hashlib.md5(string.encode("utf-8")).hexdigest() # noqa: S324


StreamMapsDict: TypeAlias = t.Dict[str, t.Union[str, dict, None]]
StreamMapsDict: TypeAlias = dict[str, t.Union[str, dict, None]]

Check warning on line 66 in singer_sdk/mapper.py

View workflow job for this annotation

GitHub Actions / Check API Changes

StreamMapsDict

Attribute value was changed: `t.Dict[str, t.Union[str, dict, None]]` -> `dict[str, t.Union[str, dict, None]]`


class StreamMap(metaclass=abc.ABCMeta):
Expand Down
16 changes: 8 additions & 8 deletions singer_sdk/sinks/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,10 +739,10 @@ def process_batch_files(
storage = StorageTarget.from_url(head)

if encoding.format == BatchFileFormat.JSONL:
with storage.fs(create=False) as batch_fs, batch_fs.open(
tail,
mode="rb",
) as file:
with (
storage.fs(create=False) as batch_fs,
batch_fs.open(tail, mode="rb") as file,
):
if encoding.compression == "gzip":
with gzip_open(file) as context_file:
context = {
Expand All @@ -759,10 +759,10 @@ def process_batch_files(
):
import pyarrow.parquet as pq # noqa: PLC0415

with storage.fs(create=False) as batch_fs, batch_fs.open(
tail,
mode="rb",
) as file:
with (
storage.fs(create=False) as batch_fs,
batch_fs.open(tail, mode="rb") as file,
):
table = pq.read_table(file)
context = {"records": table.to_pylist()}
self.process_batch(context)
Expand Down
2 changes: 1 addition & 1 deletion singer_sdk/testing/tap_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test(self) -> None:
catalog = tap1.catalog_dict
# Reset and re-initialize with discovered catalog
kwargs = {k: v for k, v in self.runner.default_kwargs.items() if k != "catalog"}
tap2: Tap = t.cast(t.Type[Tap], self.runner.singer_class)(
tap2: Tap = t.cast(type[Tap], self.runner.singer_class)(
config=self.runner.config,
catalog=catalog,
**kwargs,
Expand Down
5 changes: 3 additions & 2 deletions tests/core/configuration/test_dict_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ def test_get_env_var_config(
assert not set.intersection(missing_props, env_config)

m.setenv("PLUGIN_TEST_PROP3", "val1,val2")
with subtests.test(msg="Legacy array parsing"), caplog.at_level(
logging.WARNING,
with (
subtests.test(msg="Legacy array parsing"),
caplog.at_level(logging.WARNING),
):
parsed = parse_environment_config(CONFIG_JSONSCHEMA, "PLUGIN_TEST_")
assert parsed["prop3"] == ["val1", "val2"]
Expand Down
Loading
Loading