altimate-datapilot-cli 0.0.11__py3-none-any.whl → 0.0.13__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: altimate-datapilot-cli
3
- Version: 0.0.11
3
+ Version: 0.0.13
4
4
  Summary: Assistant for Data Teams
5
5
  Home-page: https://github.com/AltimateAI/datapilot-cli
6
6
  Author: Altimate Inc
@@ -31,7 +31,7 @@ Requires-Python: >=3.8
31
31
  License-File: LICENSE
32
32
  License-File: AUTHORS.rst
33
33
  Requires-Dist: click (==8.1.7)
34
- Requires-Dist: dbt-artifacts-parser (==0.5.1)
34
+ Requires-Dist: dbt-artifacts-parser (==0.6.0)
35
35
  Requires-Dist: ruamel.yaml (==0.18.6)
36
36
  Requires-Dist: tabulate (==0.9.0)
37
37
  Requires-Dist: requests (==2.31.0)
@@ -1,11 +1,11 @@
1
- datapilot/__init__.py,sha256=OaIl7v-6zEWEY90Jlh6yoBjO3zWX1oX7RsvqrK3o1TU,23
1
+ datapilot/__init__.py,sha256=SxvRes_80c-42zwvn5BXPvpGVs_EZ69FUEtUBF1k9Ts,23
2
2
  datapilot/__main__.py,sha256=I9USmeNnK-cAHb6LZfydJC0LeNSE8enieeY55wpR6uw,380
3
3
  datapilot/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  datapilot/cli/main.py,sha256=VSdqlkCiu8GSG9qQh8q0BzyocsQc4lKWxZAPEsjXF18,181
5
5
  datapilot/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  datapilot/clients/altimate/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- datapilot/clients/altimate/client.py,sha256=ayTvegsQKOj0EocIWeB03ys1PlGLJFB5k8zDs8oxPBo,3107
8
- datapilot/clients/altimate/utils.py,sha256=cDYR-6J4SDaOBMOtkOlaP_j0TkCgCyYLFVDjVCEiCLY,2629
7
+ datapilot/clients/altimate/client.py,sha256=DHPG2y7r1gFph80TVp7zozd_Hl05mzxtNFQ4JYEN1Jk,3260
8
+ datapilot/clients/altimate/utils.py,sha256=IyS4iY5nE5KF9bivHKVzioUitQnmgVVIZjqPNFoeUwY,3547
9
9
  datapilot/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  datapilot/config/config.py,sha256=kyj53Qsb85V4iGQsX0vSwULOjscMOSFrJDJ3tnagJpo,403
11
11
  datapilot/config/utils.py,sha256=DIAVX-OZ5Lc0Ky_A7dvdbPcD1QSg2DRxZcuaIIZ2rhw,1146
@@ -26,11 +26,11 @@ datapilot/core/platforms/dbt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
26
26
  datapilot/core/platforms/dbt/constants.py,sha256=N9Ovo9100iOAeRu8pPZLYg3_11O5QKgs3dW0VMU6jR8,502
27
27
  datapilot/core/platforms/dbt/exceptions.py,sha256=IC5BgcU90gjYYwPcfTlPNtn0_p8fYjavDRMpKZQ0OnY,110
28
28
  datapilot/core/platforms/dbt/executor.py,sha256=hvdh0qJjalWJN8ElJjIUvUiLrMIcvGvoQfrysMTqa-Y,6562
29
- datapilot/core/platforms/dbt/factory.py,sha256=fsk8XWXiSq22t5BH5jGQMASWIJ-eUNqOh5x551cbnLw,1331
29
+ datapilot/core/platforms/dbt/factory.py,sha256=YIQtb-FQQAJsifJ3KiLjjk0WIKTHtEPTNu2MeKHdMG8,1590
30
30
  datapilot/core/platforms/dbt/formatting.py,sha256=bpfa7XmVghTq4WnGDGYC6DruwOwH8YmjFHghoo5cPD8,1638
31
31
  datapilot/core/platforms/dbt/utils.py,sha256=ozFHprR6LTLXQdrGyaRoyIBTua4P1NkP8T7LGgN-9c0,18577
32
32
  datapilot/core/platforms/dbt/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- datapilot/core/platforms/dbt/cli/cli.py,sha256=sEPOoYL7lVy4G5Y4HNi6yeQqMtknxIh1EzobiisBL6c,4146
33
+ datapilot/core/platforms/dbt/cli/cli.py,sha256=qzeJU8ALoo-VykKeqPT0O5pheMMH9noBh7S42099p7w,5563
34
34
  datapilot/core/platforms/dbt/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  datapilot/core/platforms/dbt/hooks/executor_hook.py,sha256=gSM50vAO7C-f1rdnHogWbqc87aCXPXysZepjp5L2qzw,2966
36
36
  datapilot/core/platforms/dbt/insights/__init__.py,sha256=vnNOqP6lJ-r1SqmxQbeTEphL-omj466OanqQY1WNrUA,7547
@@ -121,6 +121,9 @@ datapilot/core/platforms/dbt/wrappers/manifest/v10/wrapper.py,sha256=vch6X_sCF3k
121
121
  datapilot/core/platforms/dbt/wrappers/manifest/v11/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
122
122
  datapilot/core/platforms/dbt/wrappers/manifest/v11/schemas.py,sha256=Mb0N48czcwQTz5mxQx2QlVINzz50A5FUm0kMJ-Nzs6A,1523
123
123
  datapilot/core/platforms/dbt/wrappers/manifest/v11/wrapper.py,sha256=z-KGORZHaQLdLzl8lVw7jYrK6t_rEhQI8horw65j1pY,17360
124
+ datapilot/core/platforms/dbt/wrappers/manifest/v12/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
+ datapilot/core/platforms/dbt/wrappers/manifest/v12/schemas.py,sha256=Muu2CVkTKbOtPrOcitysh6bxDrdLVw-Cu6HZT8J7Si8,1248
126
+ datapilot/core/platforms/dbt/wrappers/manifest/v12/wrapper.py,sha256=cRXA5k7psPlK7zsUp1z2Zuqh-QvPc2uIHTUBm4Wj7GI,17591
124
127
  datapilot/core/platforms/dbt/wrappers/run_results/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
128
  datapilot/core/platforms/dbt/wrappers/run_results/run_results.py,sha256=3E_y1gAF491WmXt-Z_Fqhr5BU-kVnzjHpZZv5UpOx-s,1267
126
129
  datapilot/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -130,13 +133,13 @@ datapilot/schemas/constants.py,sha256=-eyLQvpB3ut2cQ8Cx-xGpCa9lOHBUATA8s-FXEkBoF
130
133
  datapilot/schemas/nodes.py,sha256=bm2ui0rx46UTzlI-Fbvh0BkGWNqnUBPBz-uNL5XAzPI,319
131
134
  datapilot/schemas/sql.py,sha256=swvQKX0E2t9K48zB7NiqmPl8yZgfzILMHwBdzAwe1hQ,193
132
135
  datapilot/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
- datapilot/utils/utils.py,sha256=XGi0jn030M2Cp_WJ-cIOZzdzRewEOQrPldzcaDj7uPw,11150
136
+ datapilot/utils/utils.py,sha256=MY8q6ZBJ0hkrTuH7gWMxAlEAQGrajXFMabEhtGtT7sc,11524
134
137
  datapilot/utils/formatting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
135
138
  datapilot/utils/formatting/utils.py,sha256=rAVmIYuldvw9VvCSwG2kMTEgiT7cEconp_F1sAWVyCo,1377
136
- altimate_datapilot_cli-0.0.11.dist-info/AUTHORS.rst,sha256=S4H4zw_v3GVyz5_55jF5Gf_YNG3s5Y0VgbQaEov9PFk,50
137
- altimate_datapilot_cli-0.0.11.dist-info/LICENSE,sha256=Mf7VqpsmU2QR5_s2Cb_ZeeMB2Q9KW7YXJENZPFZRK1k,1100
138
- altimate_datapilot_cli-0.0.11.dist-info/METADATA,sha256=SrnqpDmfjXLnWqbED7P3SCMLBrjDCi_F3DNk0JHKBPI,2365
139
- altimate_datapilot_cli-0.0.11.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
140
- altimate_datapilot_cli-0.0.11.dist-info/entry_points.txt,sha256=0zwgKxN40RLVB5jSmlJz7IH_FBqRtpFdbrdZn-xuQIY,141
141
- altimate_datapilot_cli-0.0.11.dist-info/top_level.txt,sha256=gAOFOdwB00vcxv74y4M1J-nQtPvEatU8-mYViEBcToo,10
142
- altimate_datapilot_cli-0.0.11.dist-info/RECORD,,
139
+ altimate_datapilot_cli-0.0.13.dist-info/AUTHORS.rst,sha256=S4H4zw_v3GVyz5_55jF5Gf_YNG3s5Y0VgbQaEov9PFk,50
140
+ altimate_datapilot_cli-0.0.13.dist-info/LICENSE,sha256=Mf7VqpsmU2QR5_s2Cb_ZeeMB2Q9KW7YXJENZPFZRK1k,1100
141
+ altimate_datapilot_cli-0.0.13.dist-info/METADATA,sha256=9kqZg1dwHio3pbYe54J9_Fpi22zGXS6XWzxCWa3HLto,2365
142
+ altimate_datapilot_cli-0.0.13.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
143
+ altimate_datapilot_cli-0.0.13.dist-info/entry_points.txt,sha256=0zwgKxN40RLVB5jSmlJz7IH_FBqRtpFdbrdZn-xuQIY,141
144
+ altimate_datapilot_cli-0.0.13.dist-info/top_level.txt,sha256=gAOFOdwB00vcxv74y4M1J-nQtPvEatU8-mYViEBcToo,10
145
+ altimate_datapilot_cli-0.0.13.dist-info/RECORD,,
datapilot/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.0.11"
1
+ __version__ = "0.0.13"
@@ -62,7 +62,7 @@ class APIClient:
62
62
  response = requests.post(url, headers=headers, json=data, timeout=timeout)
63
63
  self.logger.debug(f"Received POST response with status: {response.status_code }")
64
64
 
65
- return response
65
+ return response.json()
66
66
 
67
67
  def put(self, endpoint, data, timeout=None):
68
68
  url = f"{self.base_url}{endpoint}"
@@ -83,3 +83,7 @@ class APIClient:
83
83
  def validate_credentials(self):
84
84
  endpoint = "/dbt/v3/validate-credentials"
85
85
  return self.get(endpoint)
86
+
87
+ def start_dbt_ingestion(self, params=None):
88
+ endpoint = "/dbt/v1/start_dbt_ingestion"
89
+ return self.post(endpoint, data=params)
@@ -46,10 +46,14 @@ def validate_credentials(
46
46
  return api_client.validate_credentials()
47
47
 
48
48
 
49
- def onboard_manifest(api_token, tenant, dbt_core_integration_id, manifest_path, backend_url) -> Dict:
49
+ def onboard_file(api_token, tenant, dbt_core_integration_id, dbt_core_integration_environment, file_type, file_path, backend_url) -> Dict:
50
50
  api_client = APIClient(api_token, base_url=backend_url, tenant=tenant)
51
51
 
52
- params = {"dbt_core_integration_id": dbt_core_integration_id, "file_type": "manifest"}
52
+ params = {
53
+ "dbt_core_integration_id": dbt_core_integration_id,
54
+ "dbt_core_integration_environment_type": dbt_core_integration_environment,
55
+ "file_type": file_type,
56
+ }
53
57
  signed_url_data = api_client.get_signed_url(params)
54
58
  if signed_url_data:
55
59
  signed_url = signed_url_data.get("url")
@@ -57,7 +61,7 @@ def onboard_manifest(api_token, tenant, dbt_core_integration_id, manifest_path,
57
61
  api_client.log(f"Received signed URL: {signed_url}")
58
62
  api_client.log(f"Received File ID: {file_id}")
59
63
 
60
- upload_response = upload_content_to_signed_url(manifest_path, signed_url)
64
+ upload_response = upload_content_to_signed_url(file_path, signed_url)
61
65
 
62
66
  if upload_response:
63
67
  verify_params = {"dbt_core_integration_file_id": file_id}
@@ -73,3 +77,20 @@ def onboard_manifest(api_token, tenant, dbt_core_integration_id, manifest_path,
73
77
  "ok": False,
74
78
  "message": "Error in uploading the manifest. ",
75
79
  }
80
+
81
+
82
+ def start_dbt_ingestion(api_token, tenant, dbt_core_integration_id, dbt_core_integration_environment, backend_url):
83
+ api_client = APIClient(api_token, base_url=backend_url, tenant=tenant)
84
+ params = {
85
+ "dbt_core_integration_id": dbt_core_integration_id,
86
+ "dbt_core_integration_environment_type": dbt_core_integration_environment,
87
+ }
88
+ data = api_client.start_dbt_ingestion(params)
89
+ if data and data.get("ok"):
90
+ return {"ok": True}
91
+ else:
92
+ api_client.log("Error starting dbt ingestion worker")
93
+ return {
94
+ "ok": False,
95
+ "message": "Error starting dbt ingestion worker. ",
96
+ }
@@ -3,7 +3,8 @@ import logging
3
3
  import click
4
4
 
5
5
  from datapilot.clients.altimate.utils import check_token_and_instance
6
- from datapilot.clients.altimate.utils import onboard_manifest
6
+ from datapilot.clients.altimate.utils import onboard_file
7
+ from datapilot.clients.altimate.utils import start_dbt_ingestion
7
8
  from datapilot.clients.altimate.utils import validate_credentials
8
9
  from datapilot.config.config import load_config
9
10
  from datapilot.core.platforms.dbt.constants import MODEL
@@ -14,6 +15,7 @@ from datapilot.core.platforms.dbt.formatting import generate_project_insights_ta
14
15
  from datapilot.core.platforms.dbt.utils import load_catalog
15
16
  from datapilot.core.platforms.dbt.utils import load_manifest
16
17
  from datapilot.utils.formatting.utils import tabulate_data
18
+ from datapilot.utils.utils import map_url_to_instance
17
19
 
18
20
  logging.basicConfig(level=logging.INFO)
19
21
 
@@ -87,9 +89,21 @@ def project_health(manifest_path, catalog_path, config_path=None, select=None):
87
89
  @click.option("--token", prompt="API Token", help="Your API token for authentication.")
88
90
  @click.option("--instance-name", prompt="Instance Name", help="Your tenant ID.")
89
91
  @click.option("--dbt_core_integration_id", prompt="DBT Core Integration ID", help="DBT Core Integration ID")
92
+ @click.option(
93
+ "--dbt_core_integration_environment", default="PROD", prompt="DBT Core Integration Environment", help="DBT Core Integration Environment"
94
+ )
90
95
  @click.option("--manifest-path", required=True, prompt="Manifest Path", help="Path to the manifest file.")
96
+ @click.option("--catalog-path", required=False, prompt=False, help="Path to the catalog file.")
91
97
  @click.option("--backend-url", required=False, help="Altimate's Backend URL", default="https://api.myaltimate.com")
92
- def onboard(token, instance_name, dbt_core_integration_id, manifest_path, backend_url="https://api.myaltimate.com", env=None):
98
+ def onboard(
99
+ token,
100
+ instance_name,
101
+ dbt_core_integration_id,
102
+ dbt_core_integration_environment,
103
+ manifest_path,
104
+ catalog_path,
105
+ backend_url="https://api.myaltimate.com",
106
+ ):
93
107
  """Onboard a manifest file to DBT."""
94
108
  check_token_and_instance(token, instance_name)
95
109
 
@@ -104,9 +118,32 @@ def onboard(token, instance_name, dbt_core_integration_id, manifest_path, backen
104
118
  click.echo(f"Error: {e}")
105
119
  return
106
120
 
107
- response = onboard_manifest(token, instance_name, dbt_core_integration_id, manifest_path, backend_url)
108
-
121
+ response = onboard_file(
122
+ token, instance_name, dbt_core_integration_id, dbt_core_integration_environment, "manifest", manifest_path, backend_url
123
+ )
109
124
  if response["ok"]:
110
125
  click.echo("Manifest onboarded successfully!")
111
126
  else:
112
127
  click.echo(f"{response['message']}")
128
+
129
+ if not catalog_path:
130
+ return
131
+
132
+ response = onboard_file(
133
+ token, instance_name, dbt_core_integration_id, dbt_core_integration_environment, "catalog", catalog_path, backend_url
134
+ )
135
+ if response["ok"]:
136
+ click.echo("Catalog onboarded successfully!")
137
+ else:
138
+ click.echo(f"{response['message']}")
139
+
140
+ response = start_dbt_ingestion(token, instance_name, dbt_core_integration_id, dbt_core_integration_environment, backend_url)
141
+ if response["ok"]:
142
+ url = map_url_to_instance(backend_url, instance_name)
143
+ if not url:
144
+ click.echo("Manifest and catalog ingestion has started.")
145
+ else:
146
+ url = f"{url}/settings/integrations/{dbt_core_integration_id}/{dbt_core_integration_environment}"
147
+ click.echo(f"Manifest and catalog ingestion has started. You can check the status at {url}")
148
+ else:
149
+ click.echo(f"{response['message']}")
@@ -1,18 +1,22 @@
1
1
  from dbt_artifacts_parser.parsers.catalog.catalog_v1 import CatalogV1
2
2
  from dbt_artifacts_parser.parsers.manifest.manifest_v10 import ManifestV10
3
3
  from dbt_artifacts_parser.parsers.manifest.manifest_v11 import ManifestV11
4
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import ManifestV12
4
5
 
5
6
  from datapilot.core.platforms.dbt.schemas.manifest import Catalog
6
7
  from datapilot.core.platforms.dbt.schemas.manifest import Manifest
7
8
  from datapilot.core.platforms.dbt.wrappers.catalog.v1.wrapper import CatalogV1Wrapper
8
9
  from datapilot.core.platforms.dbt.wrappers.manifest.v10.wrapper import ManifestV10Wrapper
9
10
  from datapilot.core.platforms.dbt.wrappers.manifest.v11.wrapper import ManifestV11Wrapper
11
+ from datapilot.core.platforms.dbt.wrappers.manifest.v12.wrapper import ManifestV12Wrapper
10
12
  from datapilot.exceptions.exceptions import AltimateNotSupportedError
11
13
 
12
14
 
13
15
  class DBTFactory:
14
16
  @classmethod
15
17
  def get_manifest_wrapper(cls, manifest: Manifest):
18
+ if isinstance(manifest, ManifestV12):
19
+ return ManifestV12Wrapper(manifest)
16
20
  if isinstance(manifest, ManifestV11):
17
21
  return ManifestV11Wrapper(manifest)
18
22
  if isinstance(manifest, ManifestV10):
@@ -0,0 +1,36 @@
1
+ from typing import Dict
2
+ from typing import Type
3
+ from typing import Union
4
+
5
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Exposures
6
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Macros
7
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node
8
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node1
9
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node2
10
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node3
11
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node4
12
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node5
13
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node6
14
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node7
15
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Sources
16
+
17
+ from datapilot.core.platforms.dbt.constants import GENERIC
18
+ from datapilot.core.platforms.dbt.constants import SINGULAR
19
+
20
+ ManifestNode = Union[Node, Node1, Node2, Node3, Node4, Node5, Node6, Node7]
21
+
22
+ SourceNode = Sources
23
+
24
+ ExposureNode = Exposures
25
+
26
+ TestNode = Union[Node6, Node2]
27
+
28
+ MacroNode = Macros
29
+
30
+ TEST_TYPE_TO_NODE_MAP: Dict[str, Type] = {
31
+ GENERIC: [Node6],
32
+ SINGULAR: [Node2],
33
+ }
34
+
35
+
36
+ SeedNodeMap = Node
@@ -0,0 +1,409 @@
1
+ from typing import Dict
2
+ from typing import Set
3
+
4
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import ManifestV12
5
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node2
6
+ from dbt_artifacts_parser.parsers.manifest.manifest_v12 import Node6
7
+
8
+ from datapilot.core.platforms.dbt.constants import GENERIC
9
+ from datapilot.core.platforms.dbt.constants import OTHER_TEST_NODE
10
+ from datapilot.core.platforms.dbt.constants import SEED
11
+ from datapilot.core.platforms.dbt.constants import SINGULAR
12
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateDBTContract
13
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateDependsOn
14
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateExposureType
15
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateExternalTable
16
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateFileHash
17
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateFreshnessThreshold
18
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateMacroArgument
19
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateManifestColumnInfo
20
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateManifestExposureNode
21
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateManifestMacroNode
22
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateManifestNode
23
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateManifestSourceNode
24
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateManifestTestNode
25
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateMaturityEnum
26
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateNodeConfig
27
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateOwner
28
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateQuoting
29
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateRefArgs
30
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateResourceType
31
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateSeedConfig
32
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateSeedNode
33
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateSourceConfig
34
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateTestConfig
35
+ from datapilot.core.platforms.dbt.schemas.manifest import AltimateTestMetadata
36
+ from datapilot.core.platforms.dbt.wrappers.manifest.v12.schemas import TEST_TYPE_TO_NODE_MAP
37
+ from datapilot.core.platforms.dbt.wrappers.manifest.v12.schemas import ExposureNode
38
+ from datapilot.core.platforms.dbt.wrappers.manifest.v12.schemas import MacroNode
39
+ from datapilot.core.platforms.dbt.wrappers.manifest.v12.schemas import ManifestNode
40
+ from datapilot.core.platforms.dbt.wrappers.manifest.v12.schemas import SeedNodeMap
41
+ from datapilot.core.platforms.dbt.wrappers.manifest.v12.schemas import SourceNode
42
+ from datapilot.core.platforms.dbt.wrappers.manifest.v12.schemas import TestNode
43
+ from datapilot.core.platforms.dbt.wrappers.manifest.wrapper import BaseManifestWrapper
44
+
45
+
46
+ class ManifestV12Wrapper(BaseManifestWrapper):
47
+ def __init__(self, manifest: ManifestV12):
48
+ self.manifest = manifest
49
+
50
+ def _get_node(self, node: ManifestNode) -> AltimateManifestNode:
51
+ (
52
+ sources,
53
+ metrics,
54
+ compiled_path,
55
+ compiled,
56
+ compiled_code,
57
+ depends_on_nodes,
58
+ depends_on_macros,
59
+ raw_code,
60
+ language,
61
+ contract,
62
+ ) = ([], [], None, None, None, None, None, "", "", None)
63
+ if node.resource_type != SEED:
64
+ sources = node.sources
65
+ metrics = node.metrics
66
+ depends_on_nodes = node.depends_on.nodes if node.depends_on else None
67
+ depends_on_macros = node.depends_on.macros if node.depends_on else None
68
+ compiled_path = node.compiled_path
69
+ compiled = node.compiled
70
+ raw_code = node.raw_code
71
+ language = node.language
72
+ contract = AltimateDBTContract(**node.contract.__dict__) if node.contract else None
73
+
74
+ return AltimateManifestNode(
75
+ database=node.database,
76
+ schema_name=node.schema_,
77
+ name=node.name,
78
+ resource_type=AltimateResourceType(node.resource_type),
79
+ package_name=node.package_name,
80
+ path=node.path,
81
+ description=node.description,
82
+ original_file_path=node.original_file_path,
83
+ unique_id=node.unique_id,
84
+ fqn=node.fqn,
85
+ alias=node.alias,
86
+ raw_code=raw_code,
87
+ language=language,
88
+ config=AltimateNodeConfig(**node.config.__dict__) if node.config else None,
89
+ checksum=AltimateFileHash(
90
+ name=node.checksum.name if node.checksum else None,
91
+ checksum=node.checksum.checksum if node.checksum else None,
92
+ ),
93
+ columns={
94
+ name: AltimateManifestColumnInfo(
95
+ name=column.name,
96
+ description=column.description,
97
+ meta=column.meta,
98
+ data_type=column.data_type,
99
+ quote=column.quote,
100
+ tags=column.tags,
101
+ )
102
+ for name, column in node.columns.items()
103
+ },
104
+ relation_name=node.relation_name,
105
+ sources=sources,
106
+ metrics=metrics,
107
+ depends_on=AltimateDependsOn(
108
+ nodes=depends_on_nodes,
109
+ macros=depends_on_macros,
110
+ ),
111
+ compiled_path=compiled_path,
112
+ compiled=compiled,
113
+ compiled_code=compiled_code,
114
+ contract=contract,
115
+ meta=node.meta,
116
+ patch_path=node.patch_path,
117
+ )
118
+
119
+ def _get_source(self, source: SourceNode) -> AltimateManifestSourceNode:
120
+ return AltimateManifestSourceNode(
121
+ database=source.database,
122
+ resource_type=AltimateResourceType(source.resource_type),
123
+ schema_name=source.schema_,
124
+ name=source.name,
125
+ package_name=source.package_name,
126
+ path=source.path,
127
+ original_file_path=source.original_file_path,
128
+ unique_id=source.unique_id,
129
+ fqn=source.fqn,
130
+ source_name=source.source_name,
131
+ source_description=source.source_description,
132
+ loader=source.loader,
133
+ identifier=source.identifier,
134
+ quoting=AltimateQuoting(**source.quoting.dict()) if source.quoting else None,
135
+ loaded_at_field=source.loaded_at_field,
136
+ freshness=AltimateFreshnessThreshold(**source.freshness.dict()) if source.freshness else None,
137
+ external=AltimateExternalTable(**source.external.dict()) if source.external else None,
138
+ description=source.description,
139
+ columns={
140
+ name: AltimateManifestColumnInfo(
141
+ name=column.name,
142
+ description=column.description,
143
+ meta=column.meta,
144
+ data_type=column.data_type,
145
+ quote=column.quote,
146
+ tags=column.tags,
147
+ )
148
+ for name, column in source.columns.items()
149
+ },
150
+ meta=source.meta,
151
+ relation_name=source.relation_name,
152
+ source_meta=source.source_meta,
153
+ tags=source.tags,
154
+ config=AltimateSourceConfig(**source.config.dict()) if source.config else None,
155
+ patch_path=source.patch_path,
156
+ unrendered_config=source.unrendered_config,
157
+ created_at=source.created_at,
158
+ )
159
+
160
+ def _get_macro(self, macro: MacroNode) -> AltimateManifestMacroNode:
161
+ return AltimateManifestMacroNode(
162
+ name=macro.name,
163
+ resource_type=AltimateResourceType(macro.resource_type),
164
+ package_name=macro.package_name,
165
+ path=macro.path,
166
+ original_file_path=macro.original_file_path,
167
+ unique_id=macro.unique_id,
168
+ macro_sql=macro.macro_sql,
169
+ depends_on=(
170
+ AltimateDependsOn(
171
+ macros=macro.depends_on.macros,
172
+ )
173
+ if macro.depends_on
174
+ else None
175
+ ),
176
+ description=macro.description,
177
+ meta=macro.meta,
178
+ docs=macro.docs,
179
+ patch_path=macro.patch_path,
180
+ arguments=[AltimateMacroArgument(**arg.dict()) for arg in macro.arguments] if macro.arguments else None,
181
+ created_at=macro.created_at,
182
+ supported_languages=macro.supported_languages,
183
+ )
184
+
185
+ def _get_exposure(self, exposure: ExposureNode) -> AltimateManifestExposureNode:
186
+ return AltimateManifestExposureNode(
187
+ name=exposure.name,
188
+ resource_type=AltimateResourceType(exposure.resource_type),
189
+ package_name=exposure.package_name,
190
+ path=exposure.path,
191
+ original_file_path=exposure.original_file_path,
192
+ unique_id=exposure.unique_id,
193
+ fqn=exposure.fqn,
194
+ type=AltimateExposureType(exposure.type.value) if exposure.type else None,
195
+ owner=AltimateOwner(**exposure.owner.dict()) if exposure.owner else None,
196
+ description=exposure.description,
197
+ label=exposure.label,
198
+ maturity=AltimateMaturityEnum(exposure.maturity.value) if exposure.maturity else None,
199
+ meta=exposure.meta,
200
+ tags=exposure.tags,
201
+ config=AltimateSourceConfig(**exposure.config.dict()) if exposure.config else None,
202
+ unrendered_config=exposure.unrendered_config,
203
+ url=exposure.url,
204
+ depends_on=(
205
+ AltimateDependsOn(
206
+ nodes=exposure.depends_on.nodes,
207
+ macros=exposure.depends_on.macros,
208
+ )
209
+ if exposure.depends_on
210
+ else None
211
+ ),
212
+ refs=[AltimateRefArgs(**ref.dict()) for ref in exposure.refs] if exposure.refs else None,
213
+ sources=exposure.sources,
214
+ metrics=exposure.metrics,
215
+ created_at=exposure.created_at,
216
+ )
217
+
218
+ def _get_tests(self, test: TestNode) -> AltimateManifestTestNode:
219
+ test_metadata = None
220
+ if isinstance(test, Node6):
221
+ test_type = GENERIC
222
+ test_metadata = AltimateTestMetadata(**test.test_metadata.dict()) if test.test_metadata else None
223
+ elif isinstance(test, Node2):
224
+ test_type = SINGULAR
225
+ else:
226
+ test_type = OTHER_TEST_NODE
227
+ return AltimateManifestTestNode(
228
+ test_metadata=test_metadata,
229
+ test_type=test_type,
230
+ name=test.name,
231
+ resource_type=AltimateResourceType(test.resource_type),
232
+ package_name=test.package_name,
233
+ path=test.path,
234
+ original_file_path=test.original_file_path,
235
+ unique_id=test.unique_id,
236
+ fqn=test.fqn,
237
+ alias=test.alias,
238
+ checksum=(
239
+ AltimateFileHash(
240
+ name=test.checksum.name,
241
+ checksum=test.checksum.checksum,
242
+ )
243
+ if test.checksum
244
+ else None
245
+ ),
246
+ config=AltimateTestConfig(**test.config.dict()) if test.config else None,
247
+ description=test.description,
248
+ tags=test.tags,
249
+ columns=(
250
+ {
251
+ name: AltimateManifestColumnInfo(
252
+ name=column.name,
253
+ description=column.description,
254
+ meta=column.meta,
255
+ data_type=column.data_type,
256
+ quote=column.quote,
257
+ tags=column.tags,
258
+ )
259
+ for name, column in test.columns.items()
260
+ }
261
+ if test.columns
262
+ else None
263
+ ),
264
+ meta=test.meta,
265
+ relation_name=test.relation_name,
266
+ group=test.group,
267
+ raw_code=test.raw_code,
268
+ language=test.language,
269
+ refs=[AltimateRefArgs(**ref.dict()) for ref in test.refs] if test.refs else None,
270
+ sources=test.sources,
271
+ metrics=test.metrics,
272
+ depends_on=(
273
+ AltimateDependsOn(
274
+ nodes=test.depends_on.nodes,
275
+ macros=test.depends_on.macros,
276
+ )
277
+ if test.depends_on
278
+ else None
279
+ ),
280
+ compiled_path=test.compiled_path,
281
+ compiled=test.compiled,
282
+ compiled_code=test.compiled_code,
283
+ )
284
+
285
+ def _get_seed(self, seed: SeedNodeMap) -> AltimateSeedNode:
286
+ return AltimateSeedNode(
287
+ database=seed.database,
288
+ schema_name=seed.schema_,
289
+ name=seed.name,
290
+ resource_type=AltimateResourceType(seed.resource_type),
291
+ package_name=seed.package_name,
292
+ path=seed.path,
293
+ original_file_path=seed.original_file_path,
294
+ unique_id=seed.unique_id,
295
+ fqn=seed.fqn,
296
+ alias=seed.alias,
297
+ checksum=(
298
+ AltimateFileHash(
299
+ name=seed.checksum.name,
300
+ checksum=seed.checksum.checksum,
301
+ )
302
+ if seed.checksum
303
+ else None
304
+ ),
305
+ config=AltimateSeedConfig(**seed.config.dict()) if seed.config else None,
306
+ description=seed.description,
307
+ tags=seed.tags,
308
+ columns=(
309
+ {
310
+ name: AltimateManifestColumnInfo(
311
+ name=column.name,
312
+ description=column.description,
313
+ meta=column.meta,
314
+ data_type=column.data_type,
315
+ quote=column.quote,
316
+ tags=column.tags,
317
+ )
318
+ for name, column in seed.columns.items()
319
+ }
320
+ if seed.columns
321
+ else None
322
+ ),
323
+ meta=seed.meta,
324
+ group=seed.group,
325
+ docs=seed.docs.dict() if seed.docs else None,
326
+ patch_path=seed.patch_path,
327
+ build_path=seed.build_path,
328
+ deferred=False,
329
+ unrendered_config=seed.unrendered_config,
330
+ created_at=seed.created_at,
331
+ config_call_dict=seed.config_call_dict,
332
+ )
333
+
334
+ def get_nodes(
335
+ self,
336
+ ) -> Dict[str, AltimateManifestNode]:
337
+ nodes = {}
338
+ for node in self.manifest.nodes.values():
339
+ if (
340
+ node.resource_type
341
+ in [
342
+ AltimateResourceType.seed.value,
343
+ AltimateResourceType.test.value,
344
+ ]
345
+ or node.package_name != self.get_package()
346
+ ):
347
+ continue
348
+ nodes[node.unique_id] = self._get_node(node)
349
+ return nodes
350
+
351
+ def get_package(self) -> str:
352
+ return self.manifest.metadata.project_name
353
+
354
+ def get_sources(self) -> Dict[str, AltimateManifestSourceNode]:
355
+ sources = {}
356
+ for source in self.manifest.sources.values():
357
+ sources[source.unique_id] = self._get_source(source)
358
+ return sources
359
+
360
+ def get_macros(self) -> Dict[str, AltimateManifestMacroNode]:
361
+ macros = {}
362
+ for macro in self.manifest.macros.values():
363
+ if macro.resource_type == AltimateResourceType.macro.value and macro.package_name == self.get_package():
364
+ macros[macro.unique_id] = self._get_macro(macro)
365
+ return macros
366
+
367
+ def get_exposures(self) -> Dict[str, AltimateManifestExposureNode]:
368
+ exposures = {}
369
+ for exposure in self.manifest.exposures.values():
370
+ exposures[exposure.unique_id] = self._get_exposure(exposure)
371
+ return exposures
372
+
373
+ def get_tests(self, type=None) -> Dict[str, AltimateManifestTestNode]:
374
+ tests = {}
375
+ # Initialize types_union with TestNode
376
+ types = [Node2, Node6]
377
+
378
+ # Add other types to the union if provided
379
+ if type:
380
+ types = TEST_TYPE_TO_NODE_MAP.get(type)
381
+
382
+ for node in self.manifest.nodes.values():
383
+ # Check if the node is a test and of the correct type
384
+ if node.resource_type == AltimateResourceType.test.value:
385
+ if any(isinstance(node, t) for t in types):
386
+ tests[node.unique_id] = self._get_tests(node)
387
+ return tests
388
+
389
+ def get_seeds(self) -> Dict[str, AltimateSeedNode]:
390
+ seeds = {}
391
+ for seed in self.manifest.nodes.values():
392
+ if seed.resource_type == AltimateResourceType.seed.value:
393
+ seeds[seed.unique_id] = self._get_seed(seed)
394
+ return seeds
395
+
396
+ def parent_to_child_map(self, nodes: Dict[str, AltimateManifestNode]) -> Dict[str, Set[str]]:
397
+ """
398
+ Current manifest contains information about parents
399
+ THis gives an information of node to childre
400
+ :param nodes: A dictionary of nodes in a manifest.
401
+ :return: A dictionary of all the children of a node.
402
+ """
403
+ children_map = {}
404
+ for node_id, node in nodes.items():
405
+ if node_id not in children_map:
406
+ children_map[node_id] = set()
407
+ for parent in node.depends_on.nodes or []:
408
+ children_map.setdefault(parent, set()).add(node_id)
409
+ return children_map
datapilot/utils/utils.py CHANGED
@@ -311,7 +311,14 @@ def generate_partial_manifest_catalog(changed_files, base_path: str = "./"):
311
311
  raise Exception("Unable to generate partial manifest and catalog") from e
312
312
 
313
313
 
314
- if __name__ == "__main__":
315
- print("Running main")
316
- print(generate_partial_manifest_catalog([], "/Users/gaurp/Desktop/manifest.json", ""))
317
- print("Done running main")
314
+ def map_url_to_instance(url, instance):
315
+ # Base URLs and their corresponding patterns
316
+ url_mapping = {
317
+ "https://api.tryaltimate.com": f"https://{instance}.demo.tryaltimate.com",
318
+ "https://api.myaltimate.com": f"https://{instance}.app.myaltimate.com",
319
+ "https://api.getaltimate.com": f"https://{instance}.app.getaltimate.com",
320
+ "http://localhost:8000": f"http://{instance}.localhost:3000",
321
+ }
322
+
323
+ # Check if the URL is in the dictionary and return the corresponding instance URL
324
+ return url_mapping.get(url)