hotglue-singer-sdk 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hotglue_singer_sdk/__init__.py +34 -0
- hotglue_singer_sdk/authenticators.py +554 -0
- hotglue_singer_sdk/cli/__init__.py +1 -0
- hotglue_singer_sdk/cli/common_options.py +37 -0
- hotglue_singer_sdk/configuration/__init__.py +1 -0
- hotglue_singer_sdk/configuration/_dict_config.py +101 -0
- hotglue_singer_sdk/exceptions.py +52 -0
- hotglue_singer_sdk/helpers/__init__.py +1 -0
- hotglue_singer_sdk/helpers/_catalog.py +122 -0
- hotglue_singer_sdk/helpers/_classproperty.py +18 -0
- hotglue_singer_sdk/helpers/_compat.py +15 -0
- hotglue_singer_sdk/helpers/_flattening.py +374 -0
- hotglue_singer_sdk/helpers/_schema.py +100 -0
- hotglue_singer_sdk/helpers/_secrets.py +41 -0
- hotglue_singer_sdk/helpers/_simpleeval.py +678 -0
- hotglue_singer_sdk/helpers/_singer.py +280 -0
- hotglue_singer_sdk/helpers/_state.py +282 -0
- hotglue_singer_sdk/helpers/_typing.py +231 -0
- hotglue_singer_sdk/helpers/_util.py +27 -0
- hotglue_singer_sdk/helpers/capabilities.py +240 -0
- hotglue_singer_sdk/helpers/jsonpath.py +39 -0
- hotglue_singer_sdk/io_base.py +134 -0
- hotglue_singer_sdk/mapper.py +691 -0
- hotglue_singer_sdk/mapper_base.py +156 -0
- hotglue_singer_sdk/plugin_base.py +415 -0
- hotglue_singer_sdk/py.typed +0 -0
- hotglue_singer_sdk/sinks/__init__.py +14 -0
- hotglue_singer_sdk/sinks/batch.py +90 -0
- hotglue_singer_sdk/sinks/core.py +412 -0
- hotglue_singer_sdk/sinks/record.py +66 -0
- hotglue_singer_sdk/sinks/sql.py +299 -0
- hotglue_singer_sdk/streams/__init__.py +14 -0
- hotglue_singer_sdk/streams/core.py +1294 -0
- hotglue_singer_sdk/streams/graphql.py +74 -0
- hotglue_singer_sdk/streams/rest.py +611 -0
- hotglue_singer_sdk/streams/sql.py +1023 -0
- hotglue_singer_sdk/tap_base.py +580 -0
- hotglue_singer_sdk/target_base.py +554 -0
- hotglue_singer_sdk/target_sdk/__init__.py +0 -0
- hotglue_singer_sdk/target_sdk/auth.py +124 -0
- hotglue_singer_sdk/target_sdk/client.py +286 -0
- hotglue_singer_sdk/target_sdk/common.py +13 -0
- hotglue_singer_sdk/target_sdk/lambda.py +121 -0
- hotglue_singer_sdk/target_sdk/rest.py +108 -0
- hotglue_singer_sdk/target_sdk/sinks.py +16 -0
- hotglue_singer_sdk/target_sdk/target.py +570 -0
- hotglue_singer_sdk/target_sdk/target_base.py +627 -0
- hotglue_singer_sdk/testing.py +198 -0
- hotglue_singer_sdk/typing.py +603 -0
- hotglue_singer_sdk-1.0.2.dist-info/METADATA +53 -0
- hotglue_singer_sdk-1.0.2.dist-info/RECORD +53 -0
- hotglue_singer_sdk-1.0.2.dist-info/WHEEL +4 -0
- hotglue_singer_sdk-1.0.2.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""Pre-built test functions which can be applied to multiple taps."""
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
from contextlib import redirect_stderr, redirect_stdout
|
|
5
|
+
from typing import Callable, List, Optional, Tuple, Type, cast
|
|
6
|
+
|
|
7
|
+
from hotglue_singer_sdk.helpers import _singer
|
|
8
|
+
from hotglue_singer_sdk.mapper_base import InlineMapper
|
|
9
|
+
from hotglue_singer_sdk.tap_base import Tap
|
|
10
|
+
from hotglue_singer_sdk.target_base import Target
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_standard_tap_tests(tap_class: Type[Tap], config: dict = None) -> List[Callable]:
|
|
14
|
+
"""Return callable pytest which executes simple discovery and connection tests.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
tap_class: TODO
|
|
18
|
+
config: TODO
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
TODO
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def _test_cli_prints() -> None:
|
|
25
|
+
# Initialize with basic config
|
|
26
|
+
tap1: Tap = tap_class(config=config, parse_env_config=True)
|
|
27
|
+
# Test CLI prints
|
|
28
|
+
tap1.print_version()
|
|
29
|
+
tap1.print_about()
|
|
30
|
+
tap1.print_about(format="json")
|
|
31
|
+
|
|
32
|
+
def _test_discovery() -> None:
|
|
33
|
+
catalog1 = _get_tap_catalog(tap_class, config or {})
|
|
34
|
+
# Reset and re-initialize with an input catalog
|
|
35
|
+
tap2: Tap = tap_class(config=config, parse_env_config=True, catalog=catalog1)
|
|
36
|
+
assert tap2
|
|
37
|
+
|
|
38
|
+
def _test_stream_connections() -> None:
|
|
39
|
+
# Initialize with basic config
|
|
40
|
+
tap1: Tap = tap_class(config=config, parse_env_config=True)
|
|
41
|
+
tap1.run_connection_test()
|
|
42
|
+
|
|
43
|
+
return [_test_cli_prints, _test_discovery, _test_stream_connections]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_standard_target_tests(
|
|
47
|
+
target_class: Type[Target],
|
|
48
|
+
config: dict = None,
|
|
49
|
+
) -> List[Callable]:
|
|
50
|
+
"""Return callable pytest which executes simple discovery and connection tests.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
target_class: The target class to test.
|
|
54
|
+
config: A config dictionary for the tests.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
A list of callable tests.
|
|
58
|
+
"""
|
|
59
|
+
return []
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def tap_sync_test(tap: Tap) -> Tuple[io.StringIO, io.StringIO]:
|
|
63
|
+
"""Invokes a Tap object and return STDOUT and STDERR results in StringIO buffers.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
tap: Any Tap object.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
A 2-item tuple with StringIO buffers from the Tap's output: (stdout, stderr)
|
|
70
|
+
"""
|
|
71
|
+
stdout_buf = io.StringIO()
|
|
72
|
+
stderr_buf = io.StringIO()
|
|
73
|
+
with redirect_stdout(stdout_buf), redirect_stderr(stderr_buf):
|
|
74
|
+
tap.sync_all()
|
|
75
|
+
stdout_buf.seek(0)
|
|
76
|
+
stderr_buf.seek(0)
|
|
77
|
+
return stdout_buf, stderr_buf
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _get_tap_catalog(
|
|
81
|
+
tap_class: Type[Tap], config: dict, select_all: bool = False
|
|
82
|
+
) -> dict:
|
|
83
|
+
"""Return a catalog dict by running discovery.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
tap_class: the tap class to create.
|
|
87
|
+
config: the config dict.
|
|
88
|
+
select_all: True to automatically select all streams in the catalog.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Catalog dict created by discovery.
|
|
92
|
+
"""
|
|
93
|
+
# Initialize with basic config
|
|
94
|
+
tap: Tap = tap_class(config=config, parse_env_config=True)
|
|
95
|
+
# Test discovery
|
|
96
|
+
tap.run_discovery()
|
|
97
|
+
catalog_dict = tap.catalog_dict
|
|
98
|
+
if select_all:
|
|
99
|
+
return _select_all(catalog_dict)
|
|
100
|
+
|
|
101
|
+
return catalog_dict
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _select_all(catalog_dict: dict) -> dict:
|
|
105
|
+
"""Return the catalog dict with all streams selected.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
catalog_dict (dict): [description]
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
dict: [description]
|
|
112
|
+
"""
|
|
113
|
+
catalog = _singer.Catalog.from_dict(catalog_dict)
|
|
114
|
+
for catalog_entry in catalog.streams:
|
|
115
|
+
catalog_entry.metadata.root.selected = True
|
|
116
|
+
|
|
117
|
+
return cast(dict, catalog.to_dict())
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def target_sync_test(
|
|
121
|
+
target: Target, input: Optional[io.StringIO], finalize: bool = True
|
|
122
|
+
) -> Tuple[io.StringIO, io.StringIO]:
|
|
123
|
+
"""Invoke the target with the provided input.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
target: Any Target object.
|
|
127
|
+
input: The input to process as if from STDIN.
|
|
128
|
+
finalize: True to process as the end of stream as a completion signal; False to
|
|
129
|
+
keep the sink operation open for further records.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
A 2-item tuple with StringIO buffers from the Target's output: (stdout, stderr)
|
|
133
|
+
"""
|
|
134
|
+
stdout_buf = io.StringIO()
|
|
135
|
+
stderr_buf = io.StringIO()
|
|
136
|
+
|
|
137
|
+
with redirect_stdout(stdout_buf), redirect_stderr(stderr_buf):
|
|
138
|
+
if input is not None:
|
|
139
|
+
target._process_lines(input)
|
|
140
|
+
if finalize:
|
|
141
|
+
target._process_endofpipe()
|
|
142
|
+
|
|
143
|
+
stdout_buf.seek(0)
|
|
144
|
+
stderr_buf.seek(0)
|
|
145
|
+
return stdout_buf, stderr_buf
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def tap_to_target_sync_test(
|
|
149
|
+
tap: Tap, target: Target
|
|
150
|
+
) -> Tuple[io.StringIO, io.StringIO, io.StringIO, io.StringIO]:
|
|
151
|
+
"""Test and end-to-end sink from the tap to the target.
|
|
152
|
+
|
|
153
|
+
Note: This method buffers all output from the tap in memory and should not be
|
|
154
|
+
used with larger datasets. Also note that the target will physically write out the
|
|
155
|
+
data. Cleanup afterwards should be handled by the caller, if necessary.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
tap: Any Tap object.
|
|
159
|
+
target: Any Target object.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
A 4-item tuple with the StringIO buffers:
|
|
163
|
+
(tap_stdout, tap_stderr, target_stdout, target_stderr)
|
|
164
|
+
"""
|
|
165
|
+
tap_stdout, tap_stderr = tap_sync_test(tap)
|
|
166
|
+
target_stdout, target_stderr = target_sync_test(target, tap_stdout, finalize=True)
|
|
167
|
+
|
|
168
|
+
# Reset the tap's stdout buffer before returning
|
|
169
|
+
tap_stdout.seek(0)
|
|
170
|
+
|
|
171
|
+
return tap_stdout, tap_stderr, target_stdout, target_stderr
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def sync_end_to_end(tap: Tap, target: Target, *mappers: InlineMapper) -> None:
|
|
175
|
+
"""Test and end-to-end sink from the tap to the target.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
tap: Singer tap.
|
|
179
|
+
target: Singer target.
|
|
180
|
+
mappers: Zero or more inline mapper to apply in between the tap and target, in
|
|
181
|
+
order.
|
|
182
|
+
"""
|
|
183
|
+
buf = io.StringIO()
|
|
184
|
+
with redirect_stdout(buf):
|
|
185
|
+
tap.sync_all()
|
|
186
|
+
|
|
187
|
+
buf.seek(0)
|
|
188
|
+
mapper_output = buf
|
|
189
|
+
|
|
190
|
+
for mapper in mappers:
|
|
191
|
+
buf = io.StringIO()
|
|
192
|
+
with redirect_stdout(buf):
|
|
193
|
+
mapper.listen(mapper_output)
|
|
194
|
+
|
|
195
|
+
buf.seek(0)
|
|
196
|
+
mapper_output = buf
|
|
197
|
+
|
|
198
|
+
target.listen(mapper_output)
|