tap-belvo 0.3.1__py3-none-any.whl → 0.3.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.
Potentially problematic release.
This version of tap-belvo might be problematic. Click here for more details.
- tap_belvo/client.py +29 -91
- tap_belvo/{openapi/BelvoOpenFinanceApiSpec.json → openapi.json} +27522 -18666
- tap_belvo/streams/banking.py +10 -12
- tap_belvo/streams/core.py +14 -16
- tap_belvo/tap.py +11 -7
- {tap_belvo-0.3.1.dist-info → tap_belvo-0.3.2.dist-info}/METADATA +3 -2
- tap_belvo-0.3.2.dist-info/RECORD +15 -0
- tap_belvo/openapi/__init__.py +0 -24
- tap_belvo-0.3.1.dist-info/RECORD +0 -16
- {tap_belvo-0.3.1.dist-info → tap_belvo-0.3.2.dist-info}/WHEEL +0 -0
- {tap_belvo-0.3.1.dist-info → tap_belvo-0.3.2.dist-info}/entry_points.txt +0 -0
- {tap_belvo-0.3.1.dist-info → tap_belvo-0.3.2.dist-info}/licenses/LICENSE +0 -0
tap_belvo/client.py
CHANGED
|
@@ -2,31 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import sys
|
|
6
6
|
from abc import ABCMeta, abstractmethod
|
|
7
7
|
from copy import deepcopy
|
|
8
|
+
from importlib import resources
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
8
10
|
from urllib.parse import ParseResult, parse_qsl
|
|
9
11
|
|
|
10
12
|
from requests.auth import HTTPBasicAuth
|
|
11
13
|
from requests_cache import install_cache
|
|
12
|
-
from singer_sdk import RESTStream
|
|
13
|
-
from singer_sdk.helpers._typing import is_date_or_datetime_type
|
|
14
|
+
from singer_sdk import OpenAPISchema, RESTStream
|
|
14
15
|
from singer_sdk.pagination import BaseHATEOASPaginator
|
|
15
|
-
from singer_sdk.singerlib import resolve_schema_references
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
if sys.version_info >= (3, 12):
|
|
18
|
+
from typing import override
|
|
19
|
+
else:
|
|
20
|
+
from typing_extensions import override
|
|
18
21
|
|
|
19
|
-
if
|
|
22
|
+
if TYPE_CHECKING:
|
|
20
23
|
from requests import Response
|
|
21
24
|
from singer_sdk.helpers.types import Context
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
PAGE_SIZE = 1000
|
|
28
|
+
OPENAPI = OpenAPISchema(resources.files("tap_belvo") / "openapi.json")
|
|
25
29
|
|
|
26
30
|
install_cache("tap_belvo_cache", backend="sqlite", expire_after=3600)
|
|
27
31
|
|
|
28
32
|
|
|
29
|
-
def _handle_schema_nullable(schema: dict[str,
|
|
33
|
+
def _handle_schema_nullable(schema: dict[str, Any]) -> dict[str, Any]:
|
|
30
34
|
"""Resolve x-nullable properties to standard JSON Schema nullable type.
|
|
31
35
|
|
|
32
36
|
Args:
|
|
@@ -60,15 +64,9 @@ def _handle_schema_nullable(schema: dict[str, t.Any]) -> dict[str, t.Any]:
|
|
|
60
64
|
class BelvoPaginator(BaseHATEOASPaginator):
|
|
61
65
|
"""Belvo API paginator class."""
|
|
62
66
|
|
|
67
|
+
@override
|
|
63
68
|
def get_next_url(self, response: Response) -> str | None:
|
|
64
|
-
"""Get the next URL from the response.
|
|
65
|
-
|
|
66
|
-
Args:
|
|
67
|
-
response: The response object.
|
|
68
|
-
|
|
69
|
-
Returns:
|
|
70
|
-
The next URL.
|
|
71
|
-
"""
|
|
69
|
+
"""Get the next URL from the response."""
|
|
72
70
|
return response.json().get("next") # type: ignore[no-any-return]
|
|
73
71
|
|
|
74
72
|
|
|
@@ -77,58 +75,28 @@ class BelvoStream(RESTStream[ParseResult], metaclass=ABCMeta):
|
|
|
77
75
|
|
|
78
76
|
records_jsonpath = "$.results[*]" # Or override `parse_response`.
|
|
79
77
|
|
|
78
|
+
@override
|
|
80
79
|
@property
|
|
81
80
|
def url_base(self) -> str:
|
|
82
|
-
"""Return the URL base property.
|
|
83
|
-
|
|
84
|
-
Returns:
|
|
85
|
-
str: The URL base.
|
|
86
|
-
"""
|
|
87
81
|
return self.config["base_url"] # type: ignore[no-any-return]
|
|
88
82
|
|
|
83
|
+
@override
|
|
89
84
|
@property
|
|
90
85
|
def authenticator(self) -> HTTPBasicAuth:
|
|
91
|
-
"""Get an authenticator object.
|
|
92
|
-
|
|
93
|
-
Returns:
|
|
94
|
-
The authenticator instance for this REST stream.
|
|
95
|
-
"""
|
|
96
86
|
return HTTPBasicAuth(self.config["secret_id"], self.config["password"])
|
|
97
87
|
|
|
98
|
-
@
|
|
99
|
-
def http_headers(self) -> dict[str, str]:
|
|
100
|
-
"""Return the http headers needed.
|
|
101
|
-
|
|
102
|
-
Returns:
|
|
103
|
-
A dictionary of HTTP headers.
|
|
104
|
-
"""
|
|
105
|
-
headers = {}
|
|
106
|
-
headers["User-Agent"] = f"{self.tap_name}/{self._tap.plugin_version}"
|
|
107
|
-
return headers
|
|
108
|
-
|
|
88
|
+
@override
|
|
109
89
|
def get_new_paginator(self) -> BelvoPaginator:
|
|
110
|
-
"""Get a new paginator instance.
|
|
111
|
-
|
|
112
|
-
Returns:
|
|
113
|
-
A new paginator instance.
|
|
114
|
-
"""
|
|
115
90
|
return BelvoPaginator()
|
|
116
91
|
|
|
92
|
+
@override
|
|
117
93
|
def get_url_params(
|
|
118
94
|
self,
|
|
119
95
|
context: Context | None,
|
|
120
96
|
next_page_token: ParseResult | None,
|
|
121
|
-
) -> dict[str,
|
|
122
|
-
"""Get URL query parameters.
|
|
123
|
-
|
|
124
|
-
Args:
|
|
125
|
-
context: Stream sync context.
|
|
126
|
-
next_page_token: Next offset.
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
Mapping of URL query parameters.
|
|
130
|
-
"""
|
|
131
|
-
params: dict[str, t.Any] = {
|
|
97
|
+
) -> dict[str, Any]:
|
|
98
|
+
"""Get URL query parameters."""
|
|
99
|
+
params: dict[str, Any] = {
|
|
132
100
|
"page": 1,
|
|
133
101
|
"page_size": PAGE_SIZE,
|
|
134
102
|
}
|
|
@@ -136,50 +104,20 @@ class BelvoStream(RESTStream[ParseResult], metaclass=ABCMeta):
|
|
|
136
104
|
if next_page_token:
|
|
137
105
|
params.update(parse_qsl(next_page_token.query))
|
|
138
106
|
|
|
139
|
-
if
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
107
|
+
if (
|
|
108
|
+
self.replication_key # Only if the stream is running incrementally
|
|
109
|
+
and (start_date := self.get_starting_timestamp(context))
|
|
110
|
+
):
|
|
111
|
+
params[f"{self.replication_key}__gte"] = start_date.date().isoformat()
|
|
143
112
|
|
|
144
113
|
return params
|
|
145
114
|
|
|
115
|
+
@override
|
|
146
116
|
@property
|
|
147
|
-
def
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
Developers can override to `True` in order to force this value, although this
|
|
151
|
-
should not be required in most use cases since the type can generally be
|
|
152
|
-
accurately detected from the JSON Schema.
|
|
153
|
-
|
|
154
|
-
Returns:
|
|
155
|
-
True if the stream uses a timestamp-based replication key.
|
|
156
|
-
"""
|
|
157
|
-
if not self.replication_key:
|
|
158
|
-
return False
|
|
159
|
-
type_dict = self.schema.get("properties", {}).get(self.replication_key)
|
|
160
|
-
return is_date_or_datetime_type(type_dict)
|
|
161
|
-
|
|
162
|
-
def _resolve_openapi_ref(self) -> dict[str, t.Any]:
|
|
163
|
-
schema = {"$ref": f"#/components/schemas/{self.openapi_ref}"}
|
|
164
|
-
openapi = load_openapi()
|
|
165
|
-
schema["components"] = openapi["components"]
|
|
166
|
-
return resolve_schema_references(schema)
|
|
167
|
-
|
|
168
|
-
@property
|
|
169
|
-
def schema(self) -> dict[str, t.Any]:
|
|
170
|
-
"""Return the schema for this stream.
|
|
171
|
-
|
|
172
|
-
Returns:
|
|
173
|
-
The schema for this stream.
|
|
174
|
-
"""
|
|
175
|
-
return _handle_schema_nullable(self._resolve_openapi_ref())
|
|
117
|
+
def schema(self) -> dict[str, Any]:
|
|
118
|
+
return _handle_schema_nullable(OPENAPI.fetch_schema(self.openapi_ref))
|
|
176
119
|
|
|
177
120
|
@property
|
|
178
121
|
@abstractmethod
|
|
179
122
|
def openapi_ref(self) -> str:
|
|
180
|
-
"""
|
|
181
|
-
|
|
182
|
-
Returns:
|
|
183
|
-
The OpenAPI reference for this stream.
|
|
184
|
-
"""
|
|
185
|
-
...
|
|
123
|
+
"""OpenAPI component name for this stream."""
|