Skip to content

Commit e4681d6

Browse files
author
Rafał Krupiński
committed
feat: introduce function in Tap to convert input catalog to Stream objects, without discovery.
This clarifies whether the tap should perform discovery or use the input catalog, the two being mutually exclusive.
1 parent e256dda commit e4681d6

2 files changed

Lines changed: 34 additions & 5 deletions

File tree

  • cookiecutter/tap-template/{{cookiecutter.tap_id}}/{{cookiecutter.library_name}}
  • singer_sdk

cookiecutter/tap-template/{{cookiecutter.tap_id}}/{{cookiecutter.library_name}}/tap.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
from typing import TYPE_CHECKING
6+
57
from singer_sdk import {{ 'SQL' if cookiecutter.stream_type == 'SQL' else '' }}Tap
68
from singer_sdk import typing as th # JSON schema typing helpers
79

@@ -14,6 +16,9 @@
1416
from {{ cookiecutter.library_name }} import streams
1517
{%- endif %}
1618

19+
if TYPE_CHECKING:
20+
from collections.abc import Iterable
21+
1722

1823
class Tap{{ cookiecutter.source_name }}({{ 'SQL' if cookiecutter.stream_type == 'SQL' else '' }}Tap):
1924
"""{{ cookiecutter.source_name }} tap class."""
@@ -76,6 +81,18 @@ def discover_streams(self) -> list[streams.{{ cookiecutter.source_name }}Stream]
7681
streams.GroupsStream(self),
7782
streams.UsersStream(self),
7883
]
84+
85+
def load_streams_from_catalog(self) -> Iterable[streams.{{cookiecutter.source_name}}Stream]:
86+
"""Return a list of streams based on the input catalog.
87+
88+
Returns:
89+
A list of requested streams.
90+
"""
91+
92+
if "groups" in self.input_catalog:
93+
yield streams.GroupsStream(self)
94+
if "users" in self.input_catalog:
95+
yield streams.UsersStream(self)
7996
{%- endif %}
8097

8198

singer_sdk/tap_base.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from singer_sdk.singerlib import Catalog, StateMessage
3535

3636
if t.TYPE_CHECKING:
37+
from collections.abc import Iterable
3738
from pathlib import PurePath
3839
from types import FrameType
3940

@@ -153,13 +154,14 @@ def streams(self) -> dict[str, Stream]:
153154
A mapping of names to streams, using discovery or a provided catalog.
154155
"""
155156
if self._streams is None:
156-
self._streams = {}
157157
input_catalog = self.input_catalog
158-
159-
for stream in self.load_streams():
160-
if input_catalog is not None:
158+
if input_catalog is None:
159+
self._streams = {stream.name: stream for stream in self.load_streams()}
160+
else:
161+
self._streams = {}
162+
for stream in self.load_streams_from_catalog():
161163
stream.apply_catalog(input_catalog)
162-
self._streams[stream.name] = stream
164+
self._streams[stream.name] = stream
163165
return self._streams
164166

165167
@property
@@ -408,6 +410,16 @@ def load_streams(self) -> list[Stream]:
408410
reverse=False,
409411
)
410412

413+
def load_streams_from_catalog(self) -> Iterable[Stream]:
414+
"""Recreate streams from the input catalog.
415+
416+
For backwards compatibility calls `self.load_streams()`
417+
418+
Returns:
419+
A mapping of names to streams, using provided catalog.
420+
"""
421+
return self.load_streams()
422+
411423
# Bookmarks and state management
412424

413425
def load_state(self, state: dict[str, t.Any]) -> None:

0 commit comments

Comments
 (0)