Skip to content

Commit 24cb6e2

Browse files
Merge branch 'main' into feat/conform-primitive-interpret-string
2 parents ae69a16 + 42d7084 commit 24cb6e2

28 files changed

+337
-151
lines changed

.github/dependabot.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ updates:
66
schedule:
77
interval: weekly
88
time: "12:00"
9-
reviewers: [meltano/engineering]
109
labels: [Dependencies]
1110
groups:
1211
development-dependencies:
@@ -19,7 +18,6 @@ updates:
1918
schedule:
2019
interval: weekly
2120
time: "12:00"
22-
reviewers: [meltano/engineering]
2321
labels: [Dependencies]
2422
groups:
2523
ci:
@@ -29,7 +27,6 @@ updates:
2927
directory: "/"
3028
schedule:
3129
interval: weekly
32-
reviewers: [meltano/engineering]
3330
labels: [Dependencies]
3431
groups:
3532
actions:

.github/workflows/api-changes.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
with:
3838
python-version: 3.x
3939

40-
- uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
40+
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
4141
with:
4242
version: ">=0.6,<0.7"
4343

.github/workflows/codeql-analysis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
persist-credentials: false
4646

4747
# Initializes the CodeQL tools for scanning.
48-
- uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
48+
- uses: github/codeql-action/init@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
4949
with:
5050
config-file: .github/codeql-config.yml
5151
languages: ${{ matrix.language }}
@@ -59,7 +59,7 @@ jobs:
5959

6060
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
6161
# If this step fails, then you should remove it and run the build manually (see below)
62-
- uses: github/codeql-action/autobuild@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
62+
- uses: github/codeql-action/autobuild@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
6363

6464
# ℹ️ Command-line programs to run using the OS shell.
6565
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -71,4 +71,4 @@ jobs:
7171
# echo "Run, Build Application using script"
7272
# ./location_of_script_within_repo/buildscript.sh
7373

74-
- uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
74+
- uses: github/codeql-action/analyze@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17

.github/workflows/codspeed.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
architecture: x64
4949

5050
- name: Install uv
51-
uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
51+
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
5252
with:
5353
version: ">=0.6,<0.7"
5454

.github/workflows/cookiecutter-e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
with:
4343
fetch-depth: 0
4444
persist-credentials: false
45-
- uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
45+
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
4646
with:
4747
version: ">=0.6,<0.7"
4848
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
with:
3737
name: Packages
3838
path: dist
39-
- uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3
39+
- uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0
4040
id: attest
4141
with:
4242
subject-path: "./dist/singer_sdk*"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
griffe~=1.7
2-
nox==2025.2.9
2+
nox==2025.5.1
33
pre-commit==4.2.0
44
twine==6.1.0

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ jobs:
7575
python-version: ${{ matrix.python-version }}
7676
allow-prereleases: true
7777

78-
- uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
78+
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
7979
with:
8080
version: ">=0.6,<0.7"
8181

@@ -125,7 +125,7 @@ jobs:
125125
with:
126126
python-version: ${{ env.NOXPYTHON }}
127127

128-
- uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
128+
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
129129
with:
130130
version: ">=0.6,<0.7"
131131

@@ -159,7 +159,7 @@ jobs:
159159
pattern: coverage-data-*
160160
merge-multiple: true
161161

162-
- uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
162+
- uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
163163
with:
164164
version: ">=0.6,<0.7"
165165

.github/workflows/zizmor.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ jobs:
2424
persist-credentials: false
2525

2626
- name: Install the latest version of uv
27-
uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6.0.0
27+
uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6.0.1
2828
with:
2929
version: ">=0.6,<0.7"
3030

3131
- name: Run zizmor 🌈
3232
run: uvx zizmor --pedantic --format sarif .github > results.sarif
3333

3434
- name: Upload SARIF file
35-
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
35+
uses: github/codeql-action/upload-sarif@60168efe1c415ce0f5521ea06d5c2062adbeed1b # v3.28.17
3636
with:
3737
sarif_file: results.sarif
3838
category: zizmor

docs/implementation/logging.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,27 @@ This will send metrics to a `metrics.log`:
8080
8181
## For package developers
8282
83-
If you're developing a tap or target package and would like to customize its logging configuration, you can put a `default_loggging.yml` file in the package root to set the default logging configuration for your package. This file will be used if the `SINGER_SDK_LOG_CONFIG` environment variable is not set:
83+
If you're developing a tap or target package and would like to customize its logging, you can call [`logging.config.dictConfig`](inv:python:py:function:#logging.config.dictConfig) with a logging [configuration dictionary](inv:python:std:label:#logging-config-dictschema)
84+
in the main plugin module:
8485
85-
```
86-
.
87-
├── README.md
88-
├── pyproject.toml
89-
├── uv.lock
90-
└── tap_example
91-
    ├── __init__.py
92-
    ├── __main__.py
93-
    ├── default_logging.yml # <-- This file will be used if SINGER_SDK_LOG_CONFIG is not set
94-
    ├── client.py
95-
    ├── streams.py
96-
    └── tap.py
86+
```python
87+
# tap_example/tap.py
88+
89+
import logging.config
90+
91+
logging.config.dictConfig(
92+
{
93+
"version": 1,
94+
"disable_existing_loggers": False,
95+
"loggers": {
96+
"some_package.some_module": {
97+
"level": "WARNING",
98+
},
99+
},
100+
},
101+
)
102+
103+
104+
class MyTap(Tap):
105+
...
97106
```

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ DEP002 = [
261261
"paramiko",
262262
"fs-s3fs",
263263
"s3fs",
264+
# Legacy dependencies
265+
"importlib-resources",
264266
]
265267
DEP004 = [
266268
# TODO: Make pytest a runtime dependency?

singer_sdk/about.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import dataclasses
77
import json
88
import typing as t
9-
from collections import OrderedDict
109
from textwrap import dedent
1110

1211
from packaging.specifiers import SpecifierSet
@@ -164,17 +163,15 @@ def format_about(self, about_info: AboutInfo) -> str:
164163
Returns:
165164
A formatted string.
166165
"""
167-
data = OrderedDict(
168-
[
169-
("name", about_info.name),
170-
("description", about_info.description),
171-
("version", about_info.version),
172-
("sdk_version", about_info.sdk_version),
173-
("supported_python_versions", about_info.supported_python_versions),
174-
("capabilities", [c.value for c in about_info.capabilities]),
175-
("settings", about_info.settings),
176-
],
177-
)
166+
data = {
167+
"name": about_info.name,
168+
"description": about_info.description,
169+
"version": about_info.version,
170+
"sdk_version": about_info.sdk_version,
171+
"supported_python_versions": about_info.supported_python_versions,
172+
"capabilities": [c.value for c in about_info.capabilities],
173+
"settings": about_info.settings,
174+
}
178175
return json.dumps(data, indent=self.indent, default=self.default)
179176

180177

singer_sdk/default_logging.yml

Lines changed: 0 additions & 14 deletions
This file was deleted.

singer_sdk/helpers/_resources.py

Lines changed: 0 additions & 27 deletions
This file was deleted.

singer_sdk/helpers/_typing.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ def to_json_compatible(val: t.Any) -> t.Any: # noqa: ANN401
4545
"""Return as string if datetime. JSON does not support proper datetime types."""
4646
if isinstance(val, (datetime.datetime,)):
4747
# Make naive datetimes UTC
48-
return (val.replace(tzinfo=UTC) if val.tzinfo is None else val).isoformat("T")
48+
return (val.replace(tzinfo=UTC) if val.tzinfo is None else val).isoformat(
49+
"T",
50+
timespec="microseconds",
51+
)
4952
if isinstance(val, (uuid.UUID,)):
5053
return str(val)
5154
return val

singer_sdk/metrics.py

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,12 @@
88
import logging
99
import logging.config
1010
import os
11+
import sys
1112
import typing as t
1213
from dataclasses import dataclass, field
1314
from pathlib import Path
1415
from time import time
1516

16-
import yaml
17-
18-
from singer_sdk.helpers._resources import get_package_files
19-
2017
if t.TYPE_CHECKING:
2118
from types import TracebackType
2219

@@ -388,7 +385,7 @@ def sync_timer(stream: str, **tags: t.Any) -> Timer:
388385
return Timer(Metric.SYNC_DURATION, tags)
389386

390387

391-
def _load_yaml_logging_config(path: Traversable | Path) -> t.Any: # noqa: ANN401
388+
def _load_yaml_logging_config(path: Traversable | Path) -> t.Any: # noqa: ANN401 # pragma: no cover
392389
"""Load the logging config from the YAML file.
393390
394391
Args:
@@ -397,33 +394,42 @@ def _load_yaml_logging_config(path: Traversable | Path) -> t.Any: # noqa: ANN40
397394
Returns:
398395
The logging config.
399396
"""
397+
import yaml # noqa: PLC0415
398+
400399
with path.open() as f:
401400
return yaml.safe_load(f)
402401

403402

404-
def _get_default_config_path(package: str) -> Traversable:
405-
"""Get a logging configuration.
406-
407-
Args:
408-
package: The package name to get the logging configuration for.
409-
410-
Returns:
411-
A logging configuration.
412-
"""
413-
filename = "default_logging.yml"
414-
path = get_package_files(package) / filename
415-
return path if path.is_file() else get_package_files("singer_sdk") / filename
416-
417-
418-
def _setup_logging(config: t.Mapping[str, t.Any], *, package: str) -> None:
403+
def _setup_logging(config: t.Mapping[str, t.Any]) -> None:
419404
"""Setup logging.
420405
421406
Args:
422407
package: The package name to get the logging configuration for.
423408
config: A plugin configuration dictionary.
424409
"""
425-
path = _get_default_config_path(package)
426-
logging.config.dictConfig(_load_yaml_logging_config(path))
410+
logging.config.dictConfig(
411+
{
412+
"version": 1,
413+
"disable_existing_loggers": False,
414+
"formatters": {
415+
"console": {
416+
"format": "{asctime:23s} | {levelname:8s} | {name:20s} | {message}",
417+
"style": "{",
418+
}
419+
},
420+
"handlers": {
421+
"default": {
422+
"()": logging.StreamHandler,
423+
"formatter": "console",
424+
"stream": sys.stderr,
425+
},
426+
},
427+
"root": {
428+
"level": logging.INFO,
429+
"handlers": ["default"],
430+
},
431+
},
432+
)
427433

428434
config = config or {}
429435
metrics_log_level = config.get(METRICS_LOG_LEVEL_SETTING, "INFO").upper()

singer_sdk/pagination.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ def __repr__(self) -> str:
9393
"""
9494
return str(self)
9595

96+
def continue_if_empty(self, response: requests.Response) -> bool: # noqa: ARG002, PLR6301
97+
"""Check if pagination should continue even if the response is empty.
98+
99+
Override this method to keep the pagination going even if the page retrieved
100+
from the API is empty but the next one may have records.
101+
102+
Args:
103+
response: API response object.
104+
105+
Returns:
106+
Boolean flag used to indicate if the endpoint has more pages.
107+
"""
108+
return False
109+
96110
def advance(self, response: requests.Response) -> None:
97111
"""Get a new page value and advance the current one.
98112

singer_sdk/plugin_base.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,7 @@ def __init__(
208208
if self._is_secret_config(k):
209209
config_dict[k] = SecretString(v)
210210
self._config = config_dict
211-
metrics._setup_logging( # noqa: SLF001
212-
self.config,
213-
package=self.__module__.split(".", maxsplit=1)[0],
214-
)
211+
metrics._setup_logging(self.config) # noqa: SLF001
215212
self.metrics_logger = metrics.get_metrics_logger()
216213

217214
self._validate_config(raise_errors=validate_config)

0 commit comments

Comments
 (0)