castor-extractor 0.25.6__py3-none-any.whl → 0.25.7__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 castor-extractor might be problematic. Click here for more details.

CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.25.7 - 2025-10-07
4
+
5
+ * SqlServer: Ensure database consistency between query and engine
6
+
3
7
  ## 0.25.6 - 2025-10-06
4
8
 
5
9
  * PowerBi: Support additional authentication methods
@@ -11,7 +11,6 @@ def main():
11
11
 
12
12
  parser.add_argument("-H", "--host", help="MSSQL Host")
13
13
  parser.add_argument("-P", "--port", help="MSSQL Port")
14
- parser.add_argument("-d", "--database", help="MSSQL Database")
15
14
  parser.add_argument("-u", "--user", help="MSSQL User")
16
15
  parser.add_argument("-p", "--password", help="MSSQL Password")
17
16
 
@@ -47,7 +46,6 @@ def main():
47
46
 
48
47
  sqlserver.extract_all(
49
48
  host=args.host,
50
- database=args.database,
51
49
  port=args.port,
52
50
  user=args.user,
53
51
  password=args.password,
@@ -26,17 +26,6 @@ class AbstractSourceClient(ABC):
26
26
  def execute(self, query: ExtractionQuery) -> Iterator[dict]:
27
27
  pass
28
28
 
29
- def set_database(self, database: Optional[str]) -> None:
30
- """
31
- Set the active database for this client.
32
-
33
- Some source technologies require establishing a new connection
34
- or using a different connection URI when switching databases.
35
-
36
- Default behaviour is to do nothing.
37
- """
38
- pass
39
-
40
29
 
41
30
  class SqlalchemyClient(AbstractSourceClient, ABC):
42
31
  def __init__(self, credentials: dict):
@@ -1,6 +1,20 @@
1
+ from typing import Optional
2
+
3
+
1
4
  class ExtractionQuery:
2
- """contains both statement and parameters for the query"""
5
+ """
6
+ Contains useful context to run the query:
7
+ - the sql statement itself
8
+ - parameters { ... }
9
+ - optionally, the target database (can be used to change the engine's URI)
10
+ """
3
11
 
4
- def __init__(self, statement: str, params: dict):
12
+ def __init__(
13
+ self,
14
+ statement: str,
15
+ params: dict,
16
+ database: Optional[str] = None,
17
+ ):
5
18
  self.statement = statement
6
19
  self.params = params
20
+ self.database = database
@@ -268,3 +268,7 @@ class SigmaClient(APIClient):
268
268
 
269
269
  else:
270
270
  raise ValueError(f"This asset {asset} is unknown")
271
+
272
+ def test_connection(self) -> None:
273
+ """Use credentials & verify requesting the API doesn't raise an error"""
274
+ self._auth.refresh_token()
@@ -51,7 +51,6 @@ class SQLExtractionProcessor:
51
51
  def _fetch(self, query: ExtractionQuery) -> Iterator[dict]:
52
52
  default: Callable[[], Iterator] = lambda: iter(()) # type: ignore
53
53
  decorator = safe_mode(self._safe_mode, default)
54
- self._client.set_database(query.database)
55
54
  decorated_execute = decorator(self._client.execute)
56
55
  return decorated_execute(query)
57
56
 
@@ -3,6 +3,7 @@ import os
3
3
  from abc import ABC, abstractmethod
4
4
  from typing import Optional
5
5
 
6
+ from ...utils import ExtractionQuery
6
7
  from .asset import WarehouseAsset
7
8
  from .time_filter import TimeFilter
8
9
 
@@ -20,25 +21,6 @@ class AssetNotSupportedError(NotImplementedError):
20
21
  super().__init__(msg)
21
22
 
22
23
 
23
- class ExtractionQuery:
24
- """
25
- Contains useful context to run the query:
26
- - the sql statement itself
27
- - parameters { ... }
28
- - optionally, the target database (can be used to change the engine's URI)
29
- """
30
-
31
- def __init__(
32
- self,
33
- statement: str,
34
- params: dict,
35
- database: Optional[str] = None,
36
- ):
37
- self.statement = statement
38
- self.params = params
39
- self.database = database
40
-
41
-
42
24
  class AbstractQueryBuilder(ABC):
43
25
  """
44
26
  Build queries necessary to extract warehouse assets.
@@ -4,7 +4,8 @@ from typing import Optional
4
4
 
5
5
  from sqlalchemy import create_engine, text
6
6
 
7
- from ...utils import ExtractionQuery, SqlalchemyClient, uri_encode
7
+ from ...utils import SqlalchemyClient, uri_encode
8
+ from ..abstract import ExtractionQuery
8
9
 
9
10
  logger = logging.getLogger(__name__)
10
11
 
@@ -50,12 +51,25 @@ class MSSQLClient(SqlalchemyClient):
50
51
  )
51
52
  return uri
52
53
 
54
+ def _set_database(self, database: Optional[str]) -> None:
55
+ """
56
+ To support SQL Server running on Azure, we must change the engine's
57
+ URI depending on the case:
58
+ - URI/database for database-scoped queries
59
+ - URI otherwise
60
+ https://learn.microsoft.com/en-us/sql/t-sql/language-elements/use-transact-sql?view=sql-server-2017#database_name
61
+ https://github.com/dbeaver/dbeaver/issues/5258
62
+ """
63
+ database_uri = f"{self._uri}/{database}" if database else self._uri
64
+ self._engine = create_engine(database_uri, **self._options)
65
+
53
66
  def execute(self, query: ExtractionQuery) -> Iterator[dict]:
54
67
  """
55
68
  Re-implements the SQLAlchemyClient execute function to ensure we consume
56
69
  the cursor before calling connection.close() as it wipes out the data
57
70
  otherwise
58
71
  """
72
+ self._set_database(query.database)
59
73
  connection = self.connect()
60
74
  try:
61
75
  proxy = connection.execute(text(query.statement), query.params)
@@ -64,18 +78,6 @@ class MSSQLClient(SqlalchemyClient):
64
78
  finally:
65
79
  self.close()
66
80
 
67
- def set_database(self, database: Optional[str]) -> None:
68
- """
69
- To support SQL Server running on Azure, we must change the engine's
70
- URI for each database-scoped query
71
- https://chatgpt.com/share/68de93c3-9550-8001-9d54-c5da86faa43c
72
- """
73
- if not database:
74
- return
75
- self.close()
76
- database_uri = f"{self._uri}/{database}"
77
- self._engine = create_engine(database_uri, **self._options)
78
-
79
81
  def get_databases(self) -> list[str]:
80
82
  result = self.execute(
81
83
  ExtractionQuery("SELECT name FROM sys.databases", {})
@@ -128,7 +130,11 @@ class MSSQLClient(SqlalchemyClient):
128
130
  FROM
129
131
  [{database}].sys.database_query_store_options
130
132
  """
131
- query = ExtractionQuery(sql, {})
133
+ query = ExtractionQuery(
134
+ statement=sql,
135
+ params={},
136
+ database=database,
137
+ )
132
138
  # 2 = READ_WRITE, which means the Query Store is activated
133
139
  return next(self.execute(query))["desired_state"] == 2
134
140
 
@@ -32,7 +32,6 @@ MSSQL_USER = "CASTOR_MSSQL_USER"
32
32
  MSSQL_PASSWORD = "CASTOR_MSSQL_PASSWORD" # noqa: S105
33
33
  MSSQL_HOST = "CASTOR_MSSQL_HOST"
34
34
  MSSQL_PORT = "CASTOR_MSSQL_PORT"
35
- MSSQL_DATABASE = "CASTOR_MSSQL_DATABASE"
36
35
 
37
36
 
38
37
  def _credentials(params: dict) -> dict:
@@ -43,7 +42,6 @@ def _credentials(params: dict) -> dict:
43
42
  "password": params.get("password") or from_env(MSSQL_PASSWORD),
44
43
  "host": params.get("host") or from_env(MSSQL_HOST),
45
44
  "port": params.get("port") or from_env(MSSQL_PORT),
46
- "database": params.get("database") or from_env(MSSQL_DATABASE),
47
45
  }
48
46
 
49
47
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: castor-extractor
3
- Version: 0.25.6
3
+ Version: 0.25.7
4
4
  Summary: Extract your metadata assets.
5
5
  Home-page: https://www.castordoc.com/
6
6
  License: EULA
@@ -216,6 +216,10 @@ For any questions or bug report, contact us at [support@coalesce.io](mailto:supp
216
216
 
217
217
  # Changelog
218
218
 
219
+ ## 0.25.7 - 2025-10-07
220
+
221
+ * SqlServer: Ensure database consistency between query and engine
222
+
219
223
  ## 0.25.6 - 2025-10-06
220
224
 
221
225
  * PowerBi: Support additional authentication methods
@@ -1,4 +1,4 @@
1
- CHANGELOG.md,sha256=_zH2Mm-Bn_xdVUaseScAbBos3i0Ae_MspceXsG-5vjc,21437
1
+ CHANGELOG.md,sha256=59CuAENUDPUzehj5T9VIKCbS3bG-HGUQ-7U_QtegrvA,21528
2
2
  Dockerfile,sha256=xQ05-CFfGShT3oUqaiumaldwA288dj9Yb_pxofQpufg,301
3
3
  DockerfileUsage.md,sha256=2hkJQF-5JuuzfPZ7IOxgM6QgIQW7l-9oRMFVwyXC4gE,998
4
4
  LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
@@ -25,7 +25,7 @@ castor_extractor/commands/extract_salesforce.py,sha256=3j3YTmMkPAwocR-B1ozJQai0U
25
25
  castor_extractor/commands/extract_salesforce_reporting.py,sha256=FdANTNiLkIPdm80XMYxWReHjdycLsIa61pyeCD-sUDk,962
26
26
  castor_extractor/commands/extract_sigma.py,sha256=sxewHcZ1Doq35V2qnpX_zCKKXkrb1_9bYjUMg7BOW-k,643
27
27
  castor_extractor/commands/extract_snowflake.py,sha256=GwlrRxwEBjHqGs_3bs5vM9fzmv61_iwvBr1KcIgFgWM,2161
28
- castor_extractor/commands/extract_sqlserver.py,sha256=zwPITImztIIyIbZJyE1SioGraVrlRfxgLq_vHX6l5l0,1664
28
+ castor_extractor/commands/extract_sqlserver.py,sha256=NNYfAOG-NJX0F_q0yBD-msIiwyp04Ne3fJs8hggv6YQ,1565
29
29
  castor_extractor/commands/extract_strategy.py,sha256=Q-pUymatPrBFGXobhyUPzFph0-t774-XOpjdCFF1dYo,821
30
30
  castor_extractor/commands/extract_tableau.py,sha256=cfH-b0Hq9LGrQSJv02Yr_4d6oNqhxwDqUcKraE-5fRc,2134
31
31
  castor_extractor/commands/extract_thoughtspot.py,sha256=caAYJlH-vK7u5IUB6OKXxcaWfLgc7d_XqnFDWK6YNS4,639
@@ -102,7 +102,7 @@ castor_extractor/utils/argument_parser_test.py,sha256=wnyLFJ74iEiPxxLSbwFtckR7FI
102
102
  castor_extractor/utils/batch.py,sha256=SFlLmJgVjV2nVhIrjVIEp8wJ9du4dKKHq8YVYubnwQQ,448
103
103
  castor_extractor/utils/batch_test.py,sha256=84JYXOxiTkZFAceVh0mzN6VtKxcqoFPbxkZfIDyLGlg,606
104
104
  castor_extractor/utils/client/__init__.py,sha256=h5gm8UNNCCkAqhjYK5f6BY7k0cHFOyAvkmlktqwpir0,392
105
- castor_extractor/utils/client/abstract.py,sha256=OyTpb_SBgxaZd-4QFUV3n7yTzszAbyxY89fHsdAGKS8,2410
105
+ castor_extractor/utils/client/abstract.py,sha256=CWF7_afNpEZ3jor-22wXbKIvM20ukHkaDy_uknKz8B0,2075
106
106
  castor_extractor/utils/client/api/__init__.py,sha256=vlG7WXznYgLTn3XyMGsyUkgRkup8FbKM14EXJ8mv-b0,264
107
107
  castor_extractor/utils/client/api/auth.py,sha256=lq0K3UEl1vwIIa_vKTdlpIQPdE5K1-5DXmCwO4dKzng,1890
108
108
  castor_extractor/utils/client/api/auth_test.py,sha256=LlyXytnatg6ZzR4Zkvzk0BH99FYhHX7qn_nyr2MSnDI,1305
@@ -115,7 +115,7 @@ castor_extractor/utils/client/api/safe_request_test.py,sha256=LqS5FBxs6lLLcTkcgx
115
115
  castor_extractor/utils/client/api/utils.py,sha256=jr8CWf48cIp8QP1P7oZ1zg9WaGlDO3mqCWgQKdEcpyc,238
116
116
  castor_extractor/utils/client/api/utils_test.py,sha256=a5aL-pCwa74C8Ne7OT169Bjp8WPDV5Fl8MxNxAllHJg,514
117
117
  castor_extractor/utils/client/postgres.py,sha256=n6ulaT222WWPY0_6qAZ0MHF0m91HtI9mMqL71nyygo0,866
118
- castor_extractor/utils/client/query.py,sha256=O6D5EjD1KmBlwa786Uw4D4kzxx97_HH50xIIeSWt0B8,205
118
+ castor_extractor/utils/client/query.py,sha256=Ucbv8dq5xRziV4HusleY2eJE3Whp8fHsVeQlPeVTuLs,473
119
119
  castor_extractor/utils/client/uri.py,sha256=jmP9hY-6PRqdc3-vAOdtll_U6q9VCqSqmBAN6QRs3ZI,150
120
120
  castor_extractor/utils/client/uri_test.py,sha256=1XKF6qSseCeD4G4ckaNO07JXfGbt7XUVinOZdpEYrDQ,259
121
121
  castor_extractor/utils/collection.py,sha256=g2HmB0ievvYHWaZ8iEzkcPPkrBFsh6R6b_liBqcsMjc,3044
@@ -285,7 +285,7 @@ castor_extractor/visualization/sigma/__init__.py,sha256=GINql4yJLtjfOJgjHaWNpE13
285
285
  castor_extractor/visualization/sigma/assets.py,sha256=iVZqi7XtNgSOVXy0jgeHZonVOeXi7jyikor8ztbECBc,398
286
286
  castor_extractor/visualization/sigma/client/__init__.py,sha256=YQv06FBBQHvBMFg_tN0nUcmUp2NCL2s-eFTXG8rXaBg,74
287
287
  castor_extractor/visualization/sigma/client/authentication.py,sha256=gHukrpfboIjZc_O9CcuDtrl6U-StH0J73VY2J74Bm9o,2279
288
- castor_extractor/visualization/sigma/client/client.py,sha256=SxSf5OjdDr8x-WZDezm8YNOw01R6CCoYIgW0od0ZgN8,8907
288
+ castor_extractor/visualization/sigma/client/client.py,sha256=bYlOwtb6ftASb9onUSAHCdEiyfsY5H_KHWkQB4y2Y-o,9063
289
289
  castor_extractor/visualization/sigma/client/client_test.py,sha256=ae0ZOvKutCm44jnrJ-0_A5Y6ZGyDkMf9Ml3eEP8dNkY,581
290
290
  castor_extractor/visualization/sigma/client/credentials.py,sha256=XddAuQSmCKpxJ70TQgRnOj0vMPYVtiStk_lMMQ1AiNM,693
291
291
  castor_extractor/visualization/sigma/client/endpoints.py,sha256=by9VIFml2whlzQT66f2m56RYBsqPrWdAmIP4JkTaBV4,1799
@@ -326,8 +326,8 @@ castor_extractor/warehouse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
326
326
  castor_extractor/warehouse/abstract/__init__.py,sha256=Fdfa026tgOo64MvzVRLHM_F2G-JmcehrF0mh3dHgb7s,419
327
327
  castor_extractor/warehouse/abstract/asset.py,sha256=wR5mJxAHBcqJ86HRb_Y8x3mDN4uUgSg8jMToLNu0jTM,2740
328
328
  castor_extractor/warehouse/abstract/asset_test.py,sha256=_kd4ybNlWSAdSdEgJKC-jhJTa1nMRa9i8RO3YbqKLM4,758
329
- castor_extractor/warehouse/abstract/extract.py,sha256=T_GwXO4_IFSVdBuMmnKvsftl549y43nzE5uN4He4G80,2974
330
- castor_extractor/warehouse/abstract/query.py,sha256=MSOou0F5BlTths1TsAxv9tcyOB013aJc1TegN4q7jfM,2852
329
+ castor_extractor/warehouse/abstract/extract.py,sha256=9Y2fUn3y2-2WjiHnrabjvAvOA8UETJeTYr18zcM7bdI,2924
330
+ castor_extractor/warehouse/abstract/query.py,sha256=h1VvSo6TpyS1myRqmPtoIFY1fVgbthsHOkkajUz-PKA,2444
331
331
  castor_extractor/warehouse/abstract/time_filter.py,sha256=bggIONfMmUxffkA6TwM3BsjfS2l9WFxPq8krfsau5pw,935
332
332
  castor_extractor/warehouse/abstract/time_filter_test.py,sha256=PIkegB7KOKBdpc6zIvmyl_CeQyADeFDplyQ8HTNU5LA,448
333
333
  castor_extractor/warehouse/bigquery/__init__.py,sha256=PCGNYdi7dHv-SyanUWzRuBp-ypuQ01PkDaQjVnaNhbM,170
@@ -431,8 +431,8 @@ castor_extractor/warehouse/snowflake/queries/user.sql,sha256=88V8eRj1NDaD_ufclsK
431
431
  castor_extractor/warehouse/snowflake/queries/view_ddl.sql,sha256=eWsci_50cxiYIv3N7BKkbXVM3RoIzqSDtohqRnE5kg4,673
432
432
  castor_extractor/warehouse/snowflake/query.py,sha256=C2LTdPwBzMQ_zMncg0Kq4_WkoY7K9as5tvxBDrIOlwI,1763
433
433
  castor_extractor/warehouse/sqlserver/__init__.py,sha256=PdOuYznmvKAbfWAm8UdN47MfEsd9jqPi_dDi3WEo1KY,116
434
- castor_extractor/warehouse/sqlserver/client.py,sha256=umxTNZ92S2ImtxkPwzXdTzGvym-bjv5xSNK29vawL-8,5549
435
- castor_extractor/warehouse/sqlserver/extract.py,sha256=HEJFDM1a4OeQH7OWhYhCOjhkHfGW6qf_qvjFAeMGPYg,2623
434
+ castor_extractor/warehouse/sqlserver/client.py,sha256=ggqcOtGeDk9OMyqx7fO3p-2NsbFG8vT-GoHdRx5Iy_Q,5833
435
+ castor_extractor/warehouse/sqlserver/extract.py,sha256=PlYANeqCUrw3uy3HnMxkPT1W3WyRt-qxY9ECK3Sc2lM,2510
436
436
  castor_extractor/warehouse/sqlserver/queries/.sqlfluff,sha256=yy0KQdz8I_67vnXyX8eeWwOWkxTXvHyVKSVwhURktd8,48
437
437
  castor_extractor/warehouse/sqlserver/queries/column.sql,sha256=ojiUQQnHXdWMbgaYOcxKBiwfi7rtu_tyamK6r4t4IBM,2929
438
438
  castor_extractor/warehouse/sqlserver/queries/database.sql,sha256=4dPeBCn85MEOXr1f-DPXxiI3RvvoE_1n8lsbTs26E0I,150
@@ -443,8 +443,8 @@ castor_extractor/warehouse/sqlserver/queries/user.sql,sha256=MAlnTis43E3Amu1e1Oz
443
443
  castor_extractor/warehouse/sqlserver/queries/view_ddl.sql,sha256=9rynvx6MWg3iZzrWPB7haZfVKEPkxulzryE2g19x804,315
444
444
  castor_extractor/warehouse/sqlserver/query.py,sha256=gr5lnZSUm-wSYuVnJlg6fc7jXWirbL-sCiQN9RnAiPQ,1789
445
445
  castor_extractor/warehouse/synapse/queries/column.sql,sha256=lNcFoIW3Y0PFOqoOzJEXmPvZvfAsY0AP63Mu2LuPzPo,1351
446
- castor_extractor-0.25.6.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
447
- castor_extractor-0.25.6.dist-info/METADATA,sha256=ayaVswDaw-D2Zele6ewtVK5inUm9fBOuDik-AGY7yAY,28939
448
- castor_extractor-0.25.6.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
449
- castor_extractor-0.25.6.dist-info/entry_points.txt,sha256=qyTrKNByoq2HYi1xbA79OU7qxg-OWPvle8VwDqt-KnE,1869
450
- castor_extractor-0.25.6.dist-info/RECORD,,
446
+ castor_extractor-0.25.7.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
447
+ castor_extractor-0.25.7.dist-info/METADATA,sha256=omciSlMhL8CWEtzosDWL1hj0SP2C8DiI4z0CeMb-nTs,29030
448
+ castor_extractor-0.25.7.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
449
+ castor_extractor-0.25.7.dist-info/entry_points.txt,sha256=qyTrKNByoq2HYi1xbA79OU7qxg-OWPvle8VwDqt-KnE,1869
450
+ castor_extractor-0.25.7.dist-info/RECORD,,