acryl-datahub 1.1.1rc3__py3-none-any.whl → 1.2.0__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 acryl-datahub might be problematic. Click here for more details.

Files changed (226) hide show
  1. {acryl_datahub-1.1.1rc3.dist-info → acryl_datahub-1.2.0.dist-info}/METADATA +2559 -2532
  2. {acryl_datahub-1.1.1rc3.dist-info → acryl_datahub-1.2.0.dist-info}/RECORD +226 -190
  3. {acryl_datahub-1.1.1rc3.dist-info → acryl_datahub-1.2.0.dist-info}/WHEEL +1 -1
  4. {acryl_datahub-1.1.1rc3.dist-info → acryl_datahub-1.2.0.dist-info}/entry_points.txt +2 -0
  5. datahub/_version.py +1 -1
  6. datahub/api/entities/dataset/dataset.py +2 -1
  7. datahub/api/entities/external/__init__.py +0 -0
  8. datahub/api/entities/external/external_entities.py +239 -0
  9. datahub/api/entities/external/external_tag.py +145 -0
  10. datahub/api/entities/external/lake_formation_external_entites.py +161 -0
  11. datahub/api/entities/external/restricted_text.py +247 -0
  12. datahub/api/entities/external/unity_catalog_external_entites.py +173 -0
  13. datahub/cli/check_cli.py +88 -7
  14. datahub/cli/cli_utils.py +63 -0
  15. datahub/cli/container_cli.py +5 -0
  16. datahub/cli/delete_cli.py +124 -27
  17. datahub/cli/docker_check.py +107 -12
  18. datahub/cli/docker_cli.py +149 -227
  19. datahub/cli/exists_cli.py +0 -2
  20. datahub/cli/get_cli.py +0 -2
  21. datahub/cli/iceberg_cli.py +5 -0
  22. datahub/cli/ingest_cli.py +12 -16
  23. datahub/cli/migrate.py +2 -0
  24. datahub/cli/put_cli.py +1 -4
  25. datahub/cli/quickstart_versioning.py +50 -7
  26. datahub/cli/specific/assertions_cli.py +0 -4
  27. datahub/cli/specific/datacontract_cli.py +0 -3
  28. datahub/cli/specific/dataproduct_cli.py +0 -11
  29. datahub/cli/specific/dataset_cli.py +1 -8
  30. datahub/cli/specific/forms_cli.py +0 -4
  31. datahub/cli/specific/group_cli.py +0 -2
  32. datahub/cli/specific/structuredproperties_cli.py +1 -4
  33. datahub/cli/specific/user_cli.py +0 -2
  34. datahub/cli/state_cli.py +0 -2
  35. datahub/cli/timeline_cli.py +0 -2
  36. datahub/emitter/response_helper.py +86 -1
  37. datahub/emitter/rest_emitter.py +71 -13
  38. datahub/entrypoints.py +4 -3
  39. datahub/ingestion/api/decorators.py +15 -3
  40. datahub/ingestion/api/report.py +332 -3
  41. datahub/ingestion/api/sink.py +3 -0
  42. datahub/ingestion/api/source.py +48 -44
  43. datahub/ingestion/autogenerated/__init__.py +0 -0
  44. datahub/ingestion/autogenerated/capability_summary.json +3449 -0
  45. datahub/ingestion/autogenerated/lineage.json +401 -0
  46. datahub/ingestion/autogenerated/lineage_helper.py +177 -0
  47. datahub/ingestion/extractor/schema_util.py +13 -4
  48. datahub/ingestion/glossary/classification_mixin.py +5 -0
  49. datahub/ingestion/graph/client.py +100 -15
  50. datahub/ingestion/graph/config.py +1 -0
  51. datahub/ingestion/reporting/datahub_ingestion_run_summary_provider.py +20 -10
  52. datahub/ingestion/run/pipeline.py +54 -2
  53. datahub/ingestion/sink/datahub_rest.py +13 -0
  54. datahub/ingestion/source/abs/source.py +1 -1
  55. datahub/ingestion/source/aws/aws_common.py +4 -0
  56. datahub/ingestion/source/aws/glue.py +489 -244
  57. datahub/ingestion/source/aws/tag_entities.py +292 -0
  58. datahub/ingestion/source/azure/azure_common.py +2 -2
  59. datahub/ingestion/source/bigquery_v2/bigquery.py +50 -23
  60. datahub/ingestion/source/bigquery_v2/bigquery_config.py +1 -1
  61. datahub/ingestion/source/bigquery_v2/bigquery_queries.py +1 -0
  62. datahub/ingestion/source/bigquery_v2/bigquery_schema_gen.py +2 -0
  63. datahub/ingestion/source/bigquery_v2/common.py +1 -1
  64. datahub/ingestion/source/bigquery_v2/profiler.py +4 -2
  65. datahub/ingestion/source/bigquery_v2/queries.py +3 -3
  66. datahub/ingestion/source/cassandra/cassandra.py +1 -1
  67. datahub/ingestion/source/cassandra/cassandra_profiling.py +6 -5
  68. datahub/ingestion/source/common/subtypes.py +45 -0
  69. datahub/ingestion/source/data_lake_common/object_store.py +115 -27
  70. datahub/ingestion/source/data_lake_common/path_spec.py +10 -21
  71. datahub/ingestion/source/datahub/config.py +11 -0
  72. datahub/ingestion/source/datahub/datahub_database_reader.py +187 -35
  73. datahub/ingestion/source/datahub/datahub_source.py +1 -1
  74. datahub/ingestion/source/dbt/dbt_cloud.py +10 -2
  75. datahub/ingestion/source/dbt/dbt_common.py +6 -2
  76. datahub/ingestion/source/dbt/dbt_core.py +3 -0
  77. datahub/ingestion/source/debug/__init__.py +0 -0
  78. datahub/ingestion/source/debug/datahub_debug.py +300 -0
  79. datahub/ingestion/source/dremio/dremio_api.py +114 -73
  80. datahub/ingestion/source/dremio/dremio_config.py +2 -0
  81. datahub/ingestion/source/dremio/dremio_reporting.py +23 -2
  82. datahub/ingestion/source/dremio/dremio_source.py +94 -81
  83. datahub/ingestion/source/dremio/dremio_sql_queries.py +82 -21
  84. datahub/ingestion/source/file.py +3 -0
  85. datahub/ingestion/source/fivetran/fivetran.py +34 -26
  86. datahub/ingestion/source/gcs/gcs_source.py +13 -2
  87. datahub/ingestion/source/ge_data_profiler.py +76 -28
  88. datahub/ingestion/source/ge_profiling_config.py +11 -0
  89. datahub/ingestion/source/hex/api.py +26 -1
  90. datahub/ingestion/source/iceberg/iceberg.py +3 -1
  91. datahub/ingestion/source/identity/azure_ad.py +1 -1
  92. datahub/ingestion/source/identity/okta.py +1 -14
  93. datahub/ingestion/source/kafka/kafka.py +16 -0
  94. datahub/ingestion/source/kafka_connect/sink_connectors.py +156 -47
  95. datahub/ingestion/source/kafka_connect/source_connectors.py +59 -4
  96. datahub/ingestion/source/looker/looker_source.py +1 -0
  97. datahub/ingestion/source/mlflow.py +11 -1
  98. datahub/ingestion/source/mock_data/__init__.py +0 -0
  99. datahub/ingestion/source/mock_data/datahub_mock_data.py +472 -0
  100. datahub/ingestion/source/mock_data/datahub_mock_data_report.py +12 -0
  101. datahub/ingestion/source/mock_data/table_naming_helper.py +91 -0
  102. datahub/ingestion/source/nifi.py +1 -1
  103. datahub/ingestion/source/openapi.py +12 -0
  104. datahub/ingestion/source/openapi_parser.py +56 -37
  105. datahub/ingestion/source/powerbi/powerbi.py +1 -5
  106. datahub/ingestion/source/powerbi/rest_api_wrapper/powerbi_api.py +0 -1
  107. datahub/ingestion/source/powerbi_report_server/report_server.py +0 -23
  108. datahub/ingestion/source/preset.py +2 -2
  109. datahub/ingestion/source/qlik_sense/qlik_sense.py +1 -0
  110. datahub/ingestion/source/redshift/redshift.py +21 -1
  111. datahub/ingestion/source/redshift/usage.py +4 -3
  112. datahub/ingestion/source/s3/report.py +4 -2
  113. datahub/ingestion/source/s3/source.py +367 -115
  114. datahub/ingestion/source/sac/sac.py +3 -1
  115. datahub/ingestion/source/salesforce.py +6 -3
  116. datahub/ingestion/source/sigma/sigma.py +7 -1
  117. datahub/ingestion/source/slack/slack.py +2 -1
  118. datahub/ingestion/source/snowflake/snowflake_config.py +43 -7
  119. datahub/ingestion/source/snowflake/snowflake_queries.py +348 -82
  120. datahub/ingestion/source/snowflake/snowflake_summary.py +5 -0
  121. datahub/ingestion/source/snowflake/snowflake_usage_v2.py +8 -2
  122. datahub/ingestion/source/snowflake/snowflake_utils.py +2 -7
  123. datahub/ingestion/source/snowflake/snowflake_v2.py +33 -8
  124. datahub/ingestion/source/snowflake/stored_proc_lineage.py +143 -0
  125. datahub/ingestion/source/sql/athena.py +119 -11
  126. datahub/ingestion/source/sql/athena_properties_extractor.py +777 -0
  127. datahub/ingestion/source/sql/clickhouse.py +3 -1
  128. datahub/ingestion/source/sql/cockroachdb.py +0 -1
  129. datahub/ingestion/source/sql/hana.py +3 -1
  130. datahub/ingestion/source/sql/hive_metastore.py +3 -11
  131. datahub/ingestion/source/sql/mariadb.py +0 -1
  132. datahub/ingestion/source/sql/mssql/source.py +239 -34
  133. datahub/ingestion/source/sql/mysql.py +0 -1
  134. datahub/ingestion/source/sql/oracle.py +1 -1
  135. datahub/ingestion/source/sql/postgres.py +0 -1
  136. datahub/ingestion/source/sql/sql_common.py +121 -34
  137. datahub/ingestion/source/sql/sql_generic_profiler.py +2 -1
  138. datahub/ingestion/source/sql/teradata.py +997 -235
  139. datahub/ingestion/source/sql/vertica.py +10 -6
  140. datahub/ingestion/source/sql_queries.py +2 -2
  141. datahub/ingestion/source/state/stateful_ingestion_base.py +1 -1
  142. datahub/ingestion/source/superset.py +58 -3
  143. datahub/ingestion/source/tableau/tableau.py +58 -37
  144. datahub/ingestion/source/tableau/tableau_common.py +4 -2
  145. datahub/ingestion/source/tableau/tableau_constant.py +0 -4
  146. datahub/ingestion/source/unity/config.py +5 -0
  147. datahub/ingestion/source/unity/proxy.py +118 -0
  148. datahub/ingestion/source/unity/source.py +195 -17
  149. datahub/ingestion/source/unity/tag_entities.py +295 -0
  150. datahub/ingestion/source/usage/clickhouse_usage.py +4 -1
  151. datahub/ingestion/source/usage/starburst_trino_usage.py +3 -0
  152. datahub/ingestion/transformer/add_dataset_ownership.py +18 -2
  153. datahub/integrations/assertion/snowflake/compiler.py +4 -3
  154. datahub/metadata/_internal_schema_classes.py +1446 -559
  155. datahub/metadata/_urns/urn_defs.py +1721 -1553
  156. datahub/metadata/com/linkedin/pegasus2avro/application/__init__.py +19 -0
  157. datahub/metadata/com/linkedin/pegasus2avro/identity/__init__.py +2 -0
  158. datahub/metadata/com/linkedin/pegasus2avro/logical/__init__.py +15 -0
  159. datahub/metadata/com/linkedin/pegasus2avro/metadata/key/__init__.py +4 -0
  160. datahub/metadata/com/linkedin/pegasus2avro/module/__init__.py +27 -0
  161. datahub/metadata/com/linkedin/pegasus2avro/settings/global/__init__.py +4 -0
  162. datahub/metadata/com/linkedin/pegasus2avro/template/__init__.py +25 -0
  163. datahub/metadata/schema.avsc +18055 -17802
  164. datahub/metadata/schemas/ApplicationKey.avsc +31 -0
  165. datahub/metadata/schemas/ApplicationProperties.avsc +72 -0
  166. datahub/metadata/schemas/Applications.avsc +38 -0
  167. datahub/metadata/schemas/ChartKey.avsc +1 -0
  168. datahub/metadata/schemas/ContainerKey.avsc +1 -0
  169. datahub/metadata/schemas/ContainerProperties.avsc +8 -0
  170. datahub/metadata/schemas/CorpUserSettings.avsc +41 -0
  171. datahub/metadata/schemas/DashboardKey.avsc +1 -0
  172. datahub/metadata/schemas/DataFlowInfo.avsc +8 -0
  173. datahub/metadata/schemas/DataFlowKey.avsc +1 -0
  174. datahub/metadata/schemas/DataHubPageModuleKey.avsc +21 -0
  175. datahub/metadata/schemas/DataHubPageModuleProperties.avsc +200 -0
  176. datahub/metadata/schemas/DataHubPageTemplateKey.avsc +21 -0
  177. datahub/metadata/schemas/DataHubPageTemplateProperties.avsc +175 -0
  178. datahub/metadata/schemas/DataHubPolicyInfo.avsc +12 -1
  179. datahub/metadata/schemas/DataJobInfo.avsc +8 -0
  180. datahub/metadata/schemas/DataJobKey.avsc +1 -0
  181. datahub/metadata/schemas/DataProcessKey.avsc +8 -0
  182. datahub/metadata/schemas/DataProductKey.avsc +1 -0
  183. datahub/metadata/schemas/DataProductProperties.avsc +1 -1
  184. datahub/metadata/schemas/DatasetKey.avsc +11 -1
  185. datahub/metadata/schemas/ExecutionRequestInput.avsc +5 -0
  186. datahub/metadata/schemas/GlobalSettingsInfo.avsc +62 -0
  187. datahub/metadata/schemas/GlossaryTermKey.avsc +1 -0
  188. datahub/metadata/schemas/IcebergWarehouseInfo.avsc +8 -0
  189. datahub/metadata/schemas/LogicalParent.avsc +140 -0
  190. datahub/metadata/schemas/MLFeatureKey.avsc +1 -0
  191. datahub/metadata/schemas/MLFeatureTableKey.avsc +1 -0
  192. datahub/metadata/schemas/MLModelDeploymentKey.avsc +8 -0
  193. datahub/metadata/schemas/MLModelGroupKey.avsc +9 -0
  194. datahub/metadata/schemas/MLModelKey.avsc +9 -0
  195. datahub/metadata/schemas/MLPrimaryKeyKey.avsc +1 -0
  196. datahub/metadata/schemas/MetadataChangeEvent.avsc +20 -1
  197. datahub/metadata/schemas/NotebookKey.avsc +1 -0
  198. datahub/metadata/schemas/QuerySubjects.avsc +1 -12
  199. datahub/metadata/schemas/SchemaFieldKey.avsc +2 -1
  200. datahub/sdk/__init__.py +6 -0
  201. datahub/sdk/_all_entities.py +11 -0
  202. datahub/sdk/_shared.py +118 -1
  203. datahub/sdk/chart.py +315 -0
  204. datahub/sdk/container.py +7 -0
  205. datahub/sdk/dashboard.py +432 -0
  206. datahub/sdk/dataflow.py +309 -0
  207. datahub/sdk/datajob.py +367 -0
  208. datahub/sdk/dataset.py +8 -2
  209. datahub/sdk/entity_client.py +90 -2
  210. datahub/sdk/lineage_client.py +683 -82
  211. datahub/sdk/main_client.py +46 -16
  212. datahub/sdk/mlmodel.py +101 -38
  213. datahub/sdk/mlmodelgroup.py +7 -0
  214. datahub/sdk/search_client.py +4 -3
  215. datahub/specific/chart.py +1 -1
  216. datahub/specific/dataproduct.py +4 -0
  217. datahub/sql_parsing/sql_parsing_aggregator.py +29 -17
  218. datahub/sql_parsing/sqlglot_lineage.py +62 -13
  219. datahub/telemetry/telemetry.py +17 -11
  220. datahub/testing/sdk_v2_helpers.py +7 -1
  221. datahub/upgrade/upgrade.py +46 -13
  222. datahub/utilities/server_config_util.py +8 -0
  223. datahub/utilities/sqlalchemy_query_combiner.py +5 -2
  224. datahub/utilities/stats_collections.py +4 -0
  225. {acryl_datahub-1.1.1rc3.dist-info → acryl_datahub-1.2.0.dist-info}/licenses/LICENSE +0 -0
  226. {acryl_datahub-1.1.1rc3.dist-info → acryl_datahub-1.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,432 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from typing import Dict, List, Optional, Type, Union
5
+
6
+ from typing_extensions import Self
7
+
8
+ import datahub.metadata.schema_classes as models
9
+ from datahub.metadata.urns import ChartUrn, DashboardUrn, DatasetUrn, Urn
10
+ from datahub.sdk._shared import (
11
+ ChartUrnOrStr,
12
+ DashboardUrnOrStr,
13
+ DataPlatformInstanceUrnOrStr,
14
+ DataPlatformUrnOrStr,
15
+ DatasetUrnOrStr,
16
+ DomainInputType,
17
+ HasContainer,
18
+ HasDomain,
19
+ HasInstitutionalMemory,
20
+ HasOwnership,
21
+ HasPlatformInstance,
22
+ HasSubtype,
23
+ HasTags,
24
+ HasTerms,
25
+ LinksInputType,
26
+ OwnersInputType,
27
+ TagsInputType,
28
+ TermsInputType,
29
+ )
30
+ from datahub.sdk.chart import Chart
31
+ from datahub.sdk.dataset import Dataset
32
+ from datahub.sdk.entity import Entity, ExtraAspectsType
33
+
34
+
35
+ class Dashboard(
36
+ HasPlatformInstance,
37
+ HasSubtype,
38
+ HasOwnership,
39
+ HasContainer,
40
+ HasInstitutionalMemory,
41
+ HasTags,
42
+ HasTerms,
43
+ HasDomain,
44
+ Entity,
45
+ ):
46
+ """Represents a dashboard in DataHub."""
47
+
48
+ __slots__ = ()
49
+
50
+ @classmethod
51
+ def get_urn_type(cls) -> Type[DashboardUrn]:
52
+ """Get the URN type for dashboards.
53
+ Returns:
54
+ The DashboardUrn class.
55
+ """
56
+ return DashboardUrn
57
+
58
+ def __init__(
59
+ self,
60
+ *,
61
+ # Identity.
62
+ name: str,
63
+ platform: DataPlatformUrnOrStr,
64
+ display_name: Optional[str] = None,
65
+ platform_instance: Optional[DataPlatformInstanceUrnOrStr] = None,
66
+ # Dashboard properties.
67
+ description: str = "",
68
+ external_url: Optional[str] = None,
69
+ dashboard_url: Optional[str] = None,
70
+ custom_properties: Optional[Dict[str, str]] = None,
71
+ last_modified: Optional[datetime] = None,
72
+ last_refreshed: Optional[datetime] = None,
73
+ input_datasets: Optional[List[Union[DatasetUrnOrStr, Dataset]]] = None,
74
+ charts: Optional[List[Union[ChartUrnOrStr, Chart]]] = None,
75
+ dashboards: Optional[List[Union[DashboardUrnOrStr, Dashboard]]] = None,
76
+ # Standard aspects.
77
+ subtype: Optional[str] = None,
78
+ owners: Optional[OwnersInputType] = None,
79
+ links: Optional[LinksInputType] = None,
80
+ tags: Optional[TagsInputType] = None,
81
+ terms: Optional[TermsInputType] = None,
82
+ domain: Optional[DomainInputType] = None,
83
+ extra_aspects: ExtraAspectsType = None,
84
+ ):
85
+ """Initialize a new Dashboard instance."""
86
+ urn = DashboardUrn.create_from_ids(
87
+ platform=str(platform),
88
+ name=name,
89
+ platform_instance=str(platform_instance) if platform_instance else None,
90
+ )
91
+ super().__init__(urn)
92
+ self._set_extra_aspects(extra_aspects)
93
+
94
+ self._set_platform_instance(platform, platform_instance)
95
+
96
+ # Initialize DashboardInfoClass with default values
97
+ dashboard_info = models.DashboardInfoClass(
98
+ title=display_name or name,
99
+ description=description or "",
100
+ lastModified=models.ChangeAuditStampsClass(
101
+ lastModified=None,
102
+ ),
103
+ customProperties={},
104
+ chartEdges=[],
105
+ datasetEdges=[],
106
+ dashboards=[],
107
+ )
108
+
109
+ if last_modified:
110
+ dashboard_info.lastModified = models.ChangeAuditStampsClass(
111
+ lastModified=models.AuditStampClass(
112
+ time=int(last_modified.timestamp()),
113
+ actor="urn:li:corpuser:datahub",
114
+ ),
115
+ )
116
+
117
+ # Set additional properties
118
+ if description is not None:
119
+ self.set_description(description)
120
+ if display_name is not None:
121
+ self.set_display_name(display_name)
122
+ if external_url is not None:
123
+ self.set_external_url(external_url)
124
+ if dashboard_url is not None:
125
+ self.set_dashboard_url(dashboard_url)
126
+ if custom_properties is not None:
127
+ self.set_custom_properties(custom_properties)
128
+ if last_modified is not None:
129
+ self.set_last_modified(last_modified)
130
+ if last_refreshed is not None:
131
+ self.set_last_refreshed(last_refreshed)
132
+ if subtype is not None:
133
+ self.set_subtype(subtype)
134
+ if owners is not None:
135
+ self.set_owners(owners)
136
+ if links is not None:
137
+ self.set_links(links)
138
+ if tags is not None:
139
+ self.set_tags(tags)
140
+ if terms is not None:
141
+ self.set_terms(terms)
142
+ if domain is not None:
143
+ self.set_domain(domain)
144
+ if input_datasets is not None:
145
+ self.set_input_datasets(input_datasets)
146
+ if charts is not None:
147
+ self.set_charts(charts)
148
+ if dashboards is not None:
149
+ self.set_dashboards(dashboards)
150
+
151
+ @classmethod
152
+ def _new_from_graph(cls, urn: Urn, current_aspects: models.AspectBag) -> Self:
153
+ assert isinstance(urn, DashboardUrn)
154
+ entity = cls(
155
+ platform=urn.dashboard_tool,
156
+ name=urn.dashboard_id,
157
+ )
158
+ return entity._init_from_graph(current_aspects)
159
+
160
+ @property
161
+ def urn(self) -> DashboardUrn:
162
+ assert isinstance(self._urn, DashboardUrn)
163
+ return self._urn
164
+
165
+ def _ensure_dashboard_props(self) -> models.DashboardInfoClass:
166
+ """Get the dashboard properties safely."""
167
+ return self._setdefault_aspect(
168
+ models.DashboardInfoClass(
169
+ title=self.urn.dashboard_id,
170
+ description="",
171
+ lastModified=models.ChangeAuditStampsClass(
172
+ lastModified=models.AuditStampClass(
173
+ time=0, actor="urn:li:corpuser:unknown"
174
+ )
175
+ ),
176
+ customProperties={},
177
+ chartEdges=[],
178
+ datasetEdges=[],
179
+ dashboards=[],
180
+ )
181
+ )
182
+
183
+ @property
184
+ def name(self) -> str:
185
+ """Get the name of the dashboard."""
186
+ return self.urn.dashboard_id
187
+
188
+ @property
189
+ def title(self) -> str:
190
+ """Get the title of the dashboard."""
191
+ return self._ensure_dashboard_props().title
192
+
193
+ def set_title(self, title: str) -> None:
194
+ """Set the title of the dashboard."""
195
+ props = self._ensure_dashboard_props()
196
+ props.title = title
197
+ self._set_aspect(props)
198
+
199
+ @property
200
+ def description(self) -> Optional[str]:
201
+ """Get the description of the dashboard."""
202
+ props = self._ensure_dashboard_props()
203
+ return props.description
204
+
205
+ def set_description(self, description: str) -> None:
206
+ """Set the description of the dashboard."""
207
+ props = self._ensure_dashboard_props()
208
+ props.description = description
209
+ self._set_aspect(props)
210
+
211
+ @property
212
+ def display_name(self) -> Optional[str]:
213
+ """Get the display name of the dashboard."""
214
+ return self.title
215
+
216
+ def set_display_name(self, display_name: str) -> None:
217
+ """Set the display name of the dashboard."""
218
+ self.set_title(display_name)
219
+
220
+ @property
221
+ def external_url(self) -> Optional[str]:
222
+ """Get the external URL of the dashboard."""
223
+ props = self._ensure_dashboard_props()
224
+ return props.externalUrl
225
+
226
+ def set_external_url(self, external_url: str) -> None:
227
+ """Set the external URL of the dashboard."""
228
+ props = self._ensure_dashboard_props()
229
+ props.externalUrl = external_url
230
+ self._set_aspect(props)
231
+
232
+ @property
233
+ def dashboard_url(self) -> Optional[str]:
234
+ """Get the dashboard URL."""
235
+ props = self._ensure_dashboard_props()
236
+ return props.dashboardUrl
237
+
238
+ def set_dashboard_url(self, dashboard_url: str) -> None:
239
+ """Set the dashboard URL."""
240
+ props = self._ensure_dashboard_props()
241
+ props.dashboardUrl = dashboard_url
242
+ self._set_aspect(props)
243
+
244
+ @property
245
+ def custom_properties(self) -> Dict[str, str]:
246
+ """Get the custom properties of the dashboard."""
247
+ props = self._ensure_dashboard_props()
248
+ return props.customProperties or {}
249
+
250
+ def set_custom_properties(self, custom_properties: Dict[str, str]) -> None:
251
+ """Set the custom properties of the dashboard."""
252
+ props = self._ensure_dashboard_props()
253
+ props.customProperties = custom_properties
254
+ self._set_aspect(props)
255
+
256
+ @property
257
+ def last_modified(self) -> Optional[datetime]:
258
+ """Get the last modification timestamp of the dashboard."""
259
+ props = self._ensure_dashboard_props()
260
+ if props.lastModified.lastModified.time == 0:
261
+ return None
262
+ return datetime.fromtimestamp(props.lastModified.lastModified.time)
263
+
264
+ def set_last_modified(self, last_modified: datetime) -> None:
265
+ """Set the last modification timestamp of the dashboard."""
266
+ props = self._ensure_dashboard_props()
267
+ props.lastModified = models.ChangeAuditStampsClass(
268
+ lastModified=models.AuditStampClass(
269
+ time=int(last_modified.timestamp()),
270
+ actor="urn:li:corpuser:datahub",
271
+ ),
272
+ )
273
+ self._set_aspect(props)
274
+
275
+ @property
276
+ def last_refreshed(self) -> Optional[datetime]:
277
+ """Get the last refresh timestamp of the dashboard."""
278
+ props = self._ensure_dashboard_props()
279
+ return (
280
+ datetime.fromtimestamp(props.lastRefreshed)
281
+ if props.lastRefreshed is not None
282
+ else None
283
+ )
284
+
285
+ def set_last_refreshed(self, last_refreshed: datetime) -> None:
286
+ """Set the last refresh timestamp of the dashboard."""
287
+ props = self._ensure_dashboard_props()
288
+ props.lastRefreshed = int(last_refreshed.timestamp())
289
+ self._set_aspect(props)
290
+
291
+ @property
292
+ def input_datasets(self) -> List[DatasetUrn]:
293
+ """Get the input datasets of the dashboard."""
294
+ props = self._ensure_dashboard_props()
295
+ return [
296
+ DatasetUrn.from_string(edge.destinationUrn)
297
+ for edge in (props.datasetEdges or [])
298
+ ]
299
+
300
+ def set_input_datasets(
301
+ self, input_datasets: List[Union[DatasetUrnOrStr, Dataset]]
302
+ ) -> None:
303
+ """Set the input datasets of the dashboard."""
304
+ props = self._ensure_dashboard_props()
305
+ dataset_edges = props.datasetEdges or []
306
+ for dataset in input_datasets:
307
+ if isinstance(dataset, Dataset):
308
+ dataset_urn = dataset.urn
309
+ else:
310
+ dataset_urn = DatasetUrn.from_string(dataset)
311
+ dataset_edges.append(models.EdgeClass(destinationUrn=str(dataset_urn)))
312
+ props.datasetEdges = dataset_edges
313
+ self._set_aspect(props)
314
+
315
+ def add_input_dataset(self, input_dataset: Union[DatasetUrnOrStr, Dataset]) -> None:
316
+ """Add an input dataset to the dashboard."""
317
+ if isinstance(input_dataset, Dataset):
318
+ input_dataset_urn = input_dataset.urn
319
+ else:
320
+ input_dataset_urn = DatasetUrn.from_string(input_dataset)
321
+ props = self._ensure_dashboard_props()
322
+ dataset_edges = props.datasetEdges or []
323
+ existing_urns = [edge.destinationUrn for edge in dataset_edges]
324
+ if str(input_dataset_urn) not in existing_urns:
325
+ dataset_edges.append(
326
+ models.EdgeClass(destinationUrn=str(input_dataset_urn))
327
+ )
328
+ props.datasetEdges = dataset_edges
329
+ self._set_aspect(props)
330
+
331
+ def remove_input_dataset(
332
+ self, input_dataset: Union[DatasetUrnOrStr, Dataset]
333
+ ) -> None:
334
+ """Remove an input dataset from the dashboard."""
335
+ if isinstance(input_dataset, Dataset):
336
+ input_dataset_urn = input_dataset.urn
337
+ else:
338
+ input_dataset_urn = DatasetUrn.from_string(input_dataset)
339
+ props = self._ensure_dashboard_props()
340
+ props.datasetEdges = [
341
+ edge
342
+ for edge in (props.datasetEdges or [])
343
+ if edge.destinationUrn != str(input_dataset_urn)
344
+ ]
345
+ self._set_aspect(props)
346
+
347
+ @property
348
+ def charts(self) -> List[ChartUrn]:
349
+ """Get the charts of the dashboard."""
350
+ chart_edges = self._ensure_dashboard_props().chartEdges
351
+ if chart_edges is None:
352
+ return []
353
+ return [ChartUrn.from_string(edge.destinationUrn) for edge in chart_edges]
354
+
355
+ def set_charts(self, charts: List[Union[ChartUrnOrStr, Chart]]) -> None:
356
+ """Set the charts of the dashboard."""
357
+ props = self._ensure_dashboard_props()
358
+ chart_edges = props.chartEdges or []
359
+ for chart in charts:
360
+ if isinstance(chart, Chart):
361
+ chart_urn = chart.urn
362
+ else:
363
+ chart_urn = ChartUrn.from_string(chart)
364
+ chart_edges.append(models.EdgeClass(destinationUrn=str(chart_urn)))
365
+ props.chartEdges = chart_edges
366
+ self._set_aspect(props)
367
+
368
+ def add_chart(self, chart: Union[ChartUrnOrStr, Chart]) -> None:
369
+ """Add a chart to the dashboard."""
370
+ if isinstance(chart, Chart):
371
+ chart_urn = chart.urn
372
+ else:
373
+ chart_urn = ChartUrn.from_string(chart)
374
+ props = self._ensure_dashboard_props()
375
+ chart_edges = props.chartEdges or []
376
+ existing_urns = [
377
+ edge.destinationUrn
378
+ for edge in chart_edges
379
+ if edge.destinationUrn is not None
380
+ ]
381
+ if str(chart_urn) not in existing_urns:
382
+ chart_edges.append(models.EdgeClass(destinationUrn=str(chart_urn)))
383
+ props.chartEdges = chart_edges
384
+ self._set_aspect(props)
385
+
386
+ def remove_chart(self, chart: Union[ChartUrnOrStr, Chart]) -> None:
387
+ """Remove a chart from the dashboard."""
388
+ if isinstance(chart, Chart):
389
+ chart_urn = chart.urn
390
+ else:
391
+ chart_urn = ChartUrn.from_string(chart)
392
+ props = self._ensure_dashboard_props()
393
+ props.chartEdges = [
394
+ edge
395
+ for edge in (props.chartEdges or [])
396
+ if edge.destinationUrn != str(chart_urn)
397
+ ]
398
+ self._set_aspect(props)
399
+
400
+ @property
401
+ def dashboards(self) -> List[DashboardUrn]:
402
+ """Get the dashboards of the dashboard."""
403
+ props = self._ensure_dashboard_props()
404
+ return [
405
+ DashboardUrn.from_string(dashboard.destinationUrn)
406
+ for dashboard in (props.dashboards or [])
407
+ ]
408
+
409
+ def set_dashboards(
410
+ self, dashboards: List[Union[DashboardUrnOrStr, Dashboard]]
411
+ ) -> None:
412
+ """Set the dashboards of the dashboard."""
413
+ props = self._ensure_dashboard_props()
414
+ for dashboard in dashboards:
415
+ if isinstance(dashboard, Dashboard):
416
+ dashboard_urn = dashboard.urn
417
+ else:
418
+ dashboard_urn = DashboardUrn.from_string(dashboard)
419
+ props.dashboards.append(models.EdgeClass(destinationUrn=str(dashboard_urn)))
420
+ self._set_aspect(props)
421
+
422
+ def add_dashboard(self, dashboard: Union[DashboardUrnOrStr, Dashboard]) -> None:
423
+ """Add a dashboard to the dashboard."""
424
+ if isinstance(dashboard, Dashboard):
425
+ dashboard_urn = dashboard.urn
426
+ else:
427
+ dashboard_urn = DashboardUrn.from_string(dashboard)
428
+ props = self._ensure_dashboard_props()
429
+ dashboards = props.dashboards or []
430
+ existing_urns = [dashboard.destinationUrn for dashboard in dashboards]
431
+ if str(dashboard_urn) not in existing_urns:
432
+ dashboards.append(models.EdgeClass(destinationUrn=str(dashboard_urn)))