ingestr 0.13.65__py3-none-any.whl → 0.13.67__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.
- ingestr/src/buildinfo.py +1 -1
- ingestr/src/destinations.py +73 -63
- ingestr/src/sources.py +4 -3
- {ingestr-0.13.65.dist-info → ingestr-0.13.67.dist-info}/METADATA +3 -3
- {ingestr-0.13.65.dist-info → ingestr-0.13.67.dist-info}/RECORD +8 -8
- {ingestr-0.13.65.dist-info → ingestr-0.13.67.dist-info}/WHEEL +0 -0
- {ingestr-0.13.65.dist-info → ingestr-0.13.67.dist-info}/entry_points.txt +0 -0
- {ingestr-0.13.65.dist-info → ingestr-0.13.67.dist-info}/licenses/LICENSE.md +0 -0
ingestr/src/buildinfo.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
version = "v0.13.
|
1
|
+
version = "v0.13.67"
|
ingestr/src/destinations.py
CHANGED
@@ -18,14 +18,6 @@ from dlt.common.storages.configuration import FileSystemCredentials
|
|
18
18
|
from dlt.destinations.impl.clickhouse.configuration import (
|
19
19
|
ClickHouseCredentials,
|
20
20
|
)
|
21
|
-
from dlt.destinations.impl.mssql.configuration import MsSqlClientConfiguration
|
22
|
-
from dlt.destinations.impl.mssql.mssql import (
|
23
|
-
HINT_TO_MSSQL_ATTR,
|
24
|
-
MsSqlJobClient,
|
25
|
-
)
|
26
|
-
from dlt.destinations.impl.mssql.sql_client import (
|
27
|
-
PyOdbcMsSqlClient,
|
28
|
-
)
|
29
21
|
|
30
22
|
from ingestr.src.errors import MissingValueError
|
31
23
|
from ingestr.src.loader import load_dlt_file
|
@@ -172,72 +164,90 @@ def handle_datetimeoffset(dto_value: bytes) -> datetime.datetime:
|
|
172
164
|
)
|
173
165
|
|
174
166
|
|
175
|
-
|
176
|
-
|
177
|
-
|
167
|
+
# MSSQL_COPT_SS_ACCESS_TOKEN is a connection attribute used to pass
|
168
|
+
# an Azure Active Directory access token to the SQL Server ODBC driver.
|
169
|
+
MSSQL_COPT_SS_ACCESS_TOKEN = 1256
|
178
170
|
|
179
|
-
def open_connection(self):
|
180
|
-
cfg = self.credentials._get_odbc_dsn_dict()
|
181
|
-
if (
|
182
|
-
cfg.get("AUTHENTICATION", "").strip().lower()
|
183
|
-
!= "activedirectoryaccesstoken"
|
184
|
-
):
|
185
|
-
return super().open_connection()
|
186
171
|
|
187
|
-
|
172
|
+
def serialize_azure_token(token):
|
173
|
+
# https://github.com/mkleehammer/pyodbc/issues/228#issuecomment-494773723
|
174
|
+
encoded = token.encode("utf_16_le")
|
175
|
+
return struct.pack("<i", len(encoded)) + encoded
|
188
176
|
|
189
|
-
dsn = ";".join(
|
190
|
-
[f"{k}={v}" for k, v in cfg.items() if k not in self.SKIP_CREDENTIALS]
|
191
|
-
)
|
192
177
|
|
193
|
-
|
194
|
-
|
195
|
-
timeout=self.credentials.connect_timeout,
|
196
|
-
attrs_before={
|
197
|
-
self.SQL_COPT_SS_ACCESS_TOKEN: self.serialize_token(cfg["PWD"]),
|
198
|
-
},
|
199
|
-
)
|
178
|
+
def build_mssql_dest():
|
179
|
+
# https://github.com/bruin-data/ingestr/issues/293
|
200
180
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
return struct.pack("<i", len(encoded)) + encoded
|
210
|
-
|
211
|
-
|
212
|
-
class MsSqlClient(MsSqlJobClient):
|
213
|
-
def __init__(
|
214
|
-
self,
|
215
|
-
schema: Schema,
|
216
|
-
config: MsSqlClientConfiguration,
|
217
|
-
capabilities: DestinationCapabilitiesContext,
|
218
|
-
) -> None:
|
219
|
-
sql_client = OdbcMsSqlClient(
|
220
|
-
config.normalize_dataset_name(schema),
|
221
|
-
config.normalize_staging_dataset_name(schema),
|
222
|
-
config.credentials,
|
223
|
-
capabilities,
|
224
|
-
)
|
225
|
-
super(MsSqlJobClient, self).__init__(schema, config, sql_client)
|
226
|
-
self.config: MsSqlClientConfiguration = config
|
227
|
-
self.sql_client = sql_client
|
228
|
-
self.active_hints = HINT_TO_MSSQL_ATTR if self.config.create_indexes else {}
|
229
|
-
self.type_mapper = capabilities.get_type_mapper()
|
181
|
+
from dlt.destinations.impl.mssql.configuration import MsSqlClientConfiguration
|
182
|
+
from dlt.destinations.impl.mssql.mssql import (
|
183
|
+
HINT_TO_MSSQL_ATTR,
|
184
|
+
MsSqlJobClient,
|
185
|
+
)
|
186
|
+
from dlt.destinations.impl.mssql.sql_client import (
|
187
|
+
PyOdbcMsSqlClient,
|
188
|
+
)
|
230
189
|
|
190
|
+
class OdbcMsSqlClient(PyOdbcMsSqlClient):
|
191
|
+
SKIP_CREDENTIALS = {"PWD", "AUTHENTICATION", "UID"}
|
231
192
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
193
|
+
def open_connection(self):
|
194
|
+
cfg = self.credentials._get_odbc_dsn_dict()
|
195
|
+
if (
|
196
|
+
cfg.get("AUTHENTICATION", "").strip().lower()
|
197
|
+
!= "activedirectoryaccesstoken"
|
198
|
+
):
|
199
|
+
return super().open_connection()
|
200
|
+
|
201
|
+
import pyodbc # type: ignore
|
202
|
+
|
203
|
+
dsn = ";".join(
|
204
|
+
[f"{k}={v}" for k, v in cfg.items() if k not in self.SKIP_CREDENTIALS]
|
205
|
+
)
|
206
|
+
|
207
|
+
self._conn = pyodbc.connect(
|
208
|
+
dsn,
|
209
|
+
timeout=self.credentials.connect_timeout,
|
210
|
+
attrs_before={
|
211
|
+
MSSQL_COPT_SS_ACCESS_TOKEN: serialize_azure_token(cfg["PWD"]),
|
212
|
+
},
|
213
|
+
)
|
214
|
+
|
215
|
+
# https://github.com/mkleehammer/pyodbc/wiki/Using-an-Output-Converter-function
|
216
|
+
self._conn.add_output_converter(-155, handle_datetimeoffset)
|
217
|
+
self._conn.autocommit = True
|
218
|
+
return self._conn
|
219
|
+
|
220
|
+
class MsSqlClient(MsSqlJobClient):
|
221
|
+
def __init__(
|
222
|
+
self,
|
223
|
+
schema: Schema,
|
224
|
+
config: MsSqlClientConfiguration,
|
225
|
+
capabilities: DestinationCapabilitiesContext,
|
226
|
+
) -> None:
|
227
|
+
sql_client = OdbcMsSqlClient(
|
228
|
+
config.normalize_dataset_name(schema),
|
229
|
+
config.normalize_staging_dataset_name(schema),
|
230
|
+
config.credentials,
|
231
|
+
capabilities,
|
232
|
+
)
|
233
|
+
super(MsSqlJobClient, self).__init__(schema, config, sql_client)
|
234
|
+
self.config: MsSqlClientConfiguration = config
|
235
|
+
self.sql_client = sql_client
|
236
|
+
self.active_hints = HINT_TO_MSSQL_ATTR if self.config.create_indexes else {}
|
237
|
+
self.type_mapper = capabilities.get_type_mapper()
|
238
|
+
|
239
|
+
class MsSqlDestImpl(dlt.destinations.mssql):
|
240
|
+
@property
|
241
|
+
def client_class(self):
|
242
|
+
return MsSqlClient
|
243
|
+
|
244
|
+
return MsSqlDestImpl
|
236
245
|
|
237
246
|
|
238
247
|
class MsSQLDestination(GenericSqlDestination):
|
239
248
|
def dlt_dest(self, uri: str, **kwargs):
|
240
|
-
|
249
|
+
cls = build_mssql_dest()
|
250
|
+
return cls(credentials=uri, **kwargs)
|
241
251
|
|
242
252
|
|
243
253
|
class DatabricksDestination(GenericSqlDestination):
|
ingestr/src/sources.py
CHANGED
@@ -268,8 +268,9 @@ class SqlSource:
|
|
268
268
|
from sqlalchemy import create_engine
|
269
269
|
|
270
270
|
from ingestr.src.destinations import (
|
271
|
-
|
271
|
+
MSSQL_COPT_SS_ACCESS_TOKEN,
|
272
272
|
handle_datetimeoffset,
|
273
|
+
serialize_azure_token,
|
273
274
|
)
|
274
275
|
|
275
276
|
cfg = {
|
@@ -283,7 +284,7 @@ class SqlSource:
|
|
283
284
|
if k.lower() not in ["driver", "authentication", "connect_timeout"]:
|
284
285
|
cfg[k.upper()] = v[0]
|
285
286
|
|
286
|
-
token =
|
287
|
+
token = serialize_azure_token(parsed_uri.password)
|
287
288
|
dsn = ";".join([f"{k}={v}" for k, v in cfg.items()])
|
288
289
|
|
289
290
|
def creator():
|
@@ -292,7 +293,7 @@ class SqlSource:
|
|
292
293
|
autocommit=True,
|
293
294
|
timeout=kwargs.get("connect_timeout", 30),
|
294
295
|
attrs_before={
|
295
|
-
|
296
|
+
MSSQL_COPT_SS_ACCESS_TOKEN: token,
|
296
297
|
},
|
297
298
|
)
|
298
299
|
connection.add_output_converter(-155, handle_datetimeoffset)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ingestr
|
3
|
-
Version: 0.13.
|
3
|
+
Version: 0.13.67
|
4
4
|
Summary: ingestr is a command-line application that ingests data from various sources and stores them in any database.
|
5
5
|
Project-URL: Homepage, https://github.com/bruin-data/ingestr
|
6
6
|
Project-URL: Issues, https://github.com/bruin-data/ingestr/issues
|
@@ -179,7 +179,7 @@ Requires-Dist: snowflake-connector-python==3.14.0
|
|
179
179
|
Requires-Dist: snowflake-sqlalchemy==1.6.1
|
180
180
|
Requires-Dist: sortedcontainers==2.4.0
|
181
181
|
Requires-Dist: sqlalchemy-bigquery==1.12.1
|
182
|
-
Requires-Dist: sqlalchemy-cratedb==0.
|
182
|
+
Requires-Dist: sqlalchemy-cratedb==0.41.0
|
183
183
|
Requires-Dist: sqlalchemy-hana==2.0.0
|
184
184
|
Requires-Dist: sqlalchemy-redshift==0.8.14
|
185
185
|
Requires-Dist: sqlalchemy-spanner==1.11.0
|
@@ -202,7 +202,7 @@ Requires-Dist: tzdata==2025.1
|
|
202
202
|
Requires-Dist: tzlocal==5.3
|
203
203
|
Requires-Dist: uritemplate==4.1.1
|
204
204
|
Requires-Dist: urllib3==2.3.0
|
205
|
-
Requires-Dist: verlib2==0.
|
205
|
+
Requires-Dist: verlib2==0.2.0
|
206
206
|
Requires-Dist: wrapt==1.17.2
|
207
207
|
Requires-Dist: yarl==1.18.3
|
208
208
|
Requires-Dist: zeep==4.3.1
|
@@ -2,8 +2,8 @@ ingestr/conftest.py,sha256=Q03FIJIZpLBbpj55cfCHIKEjc1FCvWJhMF2cidUJKQU,1748
|
|
2
2
|
ingestr/main.py,sha256=taDyHyaVSpB17iNLl8zA0gmr4CqDO-MSTQX1CaRBB9U,26364
|
3
3
|
ingestr/src/.gitignore,sha256=8cX1AZTSI0TcdZFGTmS_oyBjpfCzhOEt0DdAo2dFIY8,203
|
4
4
|
ingestr/src/blob.py,sha256=UUWMjHUuoR9xP1XZQ6UANQmnMVyDx3d0X4-2FQC271I,2138
|
5
|
-
ingestr/src/buildinfo.py,sha256=
|
6
|
-
ingestr/src/destinations.py,sha256=
|
5
|
+
ingestr/src/buildinfo.py,sha256=sLhX7e2Ae9uo6JOAie2f4CiqQivKOIkv83SFKQF-YU8,21
|
6
|
+
ingestr/src/destinations.py,sha256=rNKtrfWlH7tk4kXZlEpzIgZm1tG8fV-BimBlJ4CJG4E,22216
|
7
7
|
ingestr/src/errors.py,sha256=Ufs4_DfE77_E3vnA1fOQdi6cmuLVNm7_SbFLkL1XPGk,686
|
8
8
|
ingestr/src/factory.py,sha256=AJCvlK4M1sIpAAks1K-xsR_uxziIxru74mj572zixhg,6546
|
9
9
|
ingestr/src/filters.py,sha256=LLecXe9QkLFkFLUZ92OXNdcANr1a8edDxrflc2ko_KA,1452
|
@@ -11,7 +11,7 @@ ingestr/src/http_client.py,sha256=bxqsk6nJNXCo-79gW04B53DQO-yr25vaSsqP0AKtjx4,73
|
|
11
11
|
ingestr/src/loader.py,sha256=9NaWAyfkXdqAZSS-N72Iwo36Lbx4PyqIfaaH1dNdkFs,1712
|
12
12
|
ingestr/src/partition.py,sha256=BrIP6wFJvyR7Nus_3ElnfxknUXeCipK_E_bB8kZowfc,969
|
13
13
|
ingestr/src/resource.py,sha256=ZqmZxFQVGlF8rFPhBiUB08HES0yoTj8sZ--jKfaaVps,1164
|
14
|
-
ingestr/src/sources.py,sha256=
|
14
|
+
ingestr/src/sources.py,sha256=gNayvEcWHppb5SLs2QFMxwXxPlUpbmoJTX6cwl9_dkk,103384
|
15
15
|
ingestr/src/table_definition.py,sha256=REbAbqdlmUMUuRh8nEQRreWjPVOQ5ZcfqGkScKdCrmk,390
|
16
16
|
ingestr/src/time.py,sha256=H_Fk2J4ShXyUM-EMY7MqCLZQhlnZMZvO952bmZPc4yE,254
|
17
17
|
ingestr/src/version.py,sha256=J_2xgZ0mKlvuHcjdKCx2nlioneLH0I47JiU_Slr_Nwc,189
|
@@ -147,8 +147,8 @@ ingestr/testdata/merge_expected.csv,sha256=DReHqWGnQMsf2PBv_Q2pfjsgvikYFnf1zYcQZ
|
|
147
147
|
ingestr/testdata/merge_part1.csv,sha256=Pw8Z9IDKcNU0qQHx1z6BUf4rF_-SxKGFOvymCt4OY9I,185
|
148
148
|
ingestr/testdata/merge_part2.csv,sha256=T_GiWxA81SN63_tMOIuemcvboEFeAmbKc7xRXvL9esw,287
|
149
149
|
ingestr/tests/unit/test_smartsheets.py,sha256=eiC2CCO4iNJcuN36ONvqmEDryCA1bA1REpayHpu42lk,5058
|
150
|
-
ingestr-0.13.
|
151
|
-
ingestr-0.13.
|
152
|
-
ingestr-0.13.
|
153
|
-
ingestr-0.13.
|
154
|
-
ingestr-0.13.
|
150
|
+
ingestr-0.13.67.dist-info/METADATA,sha256=97obKQ7ltYvn_6SfwmBV3QrSH5mit8GbE9uQiJenqCY,15022
|
151
|
+
ingestr-0.13.67.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
152
|
+
ingestr-0.13.67.dist-info/entry_points.txt,sha256=oPJy0KBnPWYjDtP1k8qwAihcTLHSZokSQvRAw_wtfJM,46
|
153
|
+
ingestr-0.13.67.dist-info/licenses/LICENSE.md,sha256=cW8wIhn8HFE-KLStDF9jHQ1O_ARWP3kTpk_-eOccL24,1075
|
154
|
+
ingestr-0.13.67.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|