Skip to content

Commit 93002e8

Browse files
authored
Feat: Refactor schema classes to subclass from _Resource (#1536)
* feat: Refactor code to make shema type classes a subclass of Artifact, Execution and Context * reinstantiate schema class using resouce_name * fix typo in resource_name * change resouce_name to artifact_name * Change constructor to internal method * refactor execution. * refactor context. * fix spelling * fix unit tests * fix sample tests.
1 parent d913e1d commit 93002e8

File tree

12 files changed

+249
-176
lines changed

12 files changed

+249
-176
lines changed

google/cloud/aiplatform/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ def __repr__(self) -> str:
727727

728728
def to_dict(self) -> Dict[str, Any]:
729729
"""Returns the resource proto as a dictionary."""
730-
return json_format.MessageToDict(self.gca_resource._pb)
730+
return json_format.MessageToDict(self._gca_resource._pb)
731731

732732
@classmethod
733733
def _generate_display_name(cls, prefix: Optional[str] = None) -> str:

google/cloud/aiplatform/metadata/artifact.py

+6-52
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from google.cloud.aiplatform.metadata import metadata_store
3232
from google.cloud.aiplatform.metadata import resource
3333
from google.cloud.aiplatform.metadata import utils as metadata_utils
34-
from google.cloud.aiplatform.metadata.schema import base_artifact
3534
from google.cloud.aiplatform.utils import rest_utils
3635

3736

@@ -327,60 +326,15 @@ def create(
327326
credentials=credentials,
328327
)
329328

330-
@classmethod
331-
def create_from_base_artifact_schema(
332-
cls,
333-
*,
334-
base_artifact_schema: "base_artifact.BaseArtifactSchema",
335-
metadata_store_id: Optional[str] = "default",
336-
project: Optional[str] = None,
337-
location: Optional[str] = None,
338-
credentials: Optional[auth_credentials.Credentials] = None,
339-
) -> "Artifact":
340-
"""Creates a new Metadata Artifact from a BaseArtifactSchema class instance.
341-
342-
Args:
343-
base_artifact_schema (BaseArtifactSchema):
344-
Required. An instance of the BaseArtifactType class that can be
345-
provided instead of providing artifact specific parameters.
346-
metadata_store_id (str):
347-
Optional. The <metadata_store_id> portion of the resource name with
348-
the format:
349-
projects/123/locations/us-central1/metadataStores/<metadata_store_id>/artifacts/<resource_id>
350-
If not provided, the MetadataStore's ID will be set to "default".
351-
project (str):
352-
Optional. Project used to create this Artifact. Overrides project set in
353-
aiplatform.init.
354-
location (str):
355-
Optional. Location used to create this Artifact. Overrides location set in
356-
aiplatform.init.
357-
credentials (auth_credentials.Credentials):
358-
Optional. Custom credentials used to create this Artifact. Overrides
359-
credentials set in aiplatform.init.
360-
361-
Returns:
362-
Artifact: Instantiated representation of the managed Metadata Artifact.
363-
"""
364-
365-
return cls.create(
366-
resource_id=base_artifact_schema.artifact_id,
367-
schema_title=base_artifact_schema.schema_title,
368-
uri=base_artifact_schema.uri,
369-
display_name=base_artifact_schema.display_name,
370-
schema_version=base_artifact_schema.schema_version,
371-
description=base_artifact_schema.description,
372-
metadata=base_artifact_schema.metadata,
373-
state=base_artifact_schema.state,
374-
metadata_store_id=metadata_store_id,
375-
project=project,
376-
location=location,
377-
credentials=credentials,
378-
)
379-
380329
@property
381330
def uri(self) -> Optional[str]:
382331
"Uri for this Artifact."
383-
return self.gca_resource.uri
332+
return self._gca_resource.uri
333+
334+
@property
335+
def state(self) -> Optional[gca_artifact.Artifact.State]:
336+
"The State for this Artifact."
337+
return self._gca_resource.state
384338

385339
@classmethod
386340
def get_with_uri(

google/cloud/aiplatform/metadata/execution.py

-52
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from google.cloud.aiplatform.metadata import artifact
3232
from google.cloud.aiplatform.metadata import metadata_store
3333
from google.cloud.aiplatform.metadata import resource
34-
from google.cloud.aiplatform.metadata.schema import base_execution
3534

3635

3736
class Execution(resource._Resource):
@@ -167,57 +166,6 @@ def create(
167166

168167
return self
169168

170-
@classmethod
171-
def create_from_base_execution_schema(
172-
cls,
173-
*,
174-
base_execution_schema: "base_execution.BaseExecutionSchema",
175-
metadata_store_id: Optional[str] = "default",
176-
project: Optional[str] = None,
177-
location: Optional[str] = None,
178-
credentials: Optional[auth_credentials.Credentials] = None,
179-
) -> "Execution":
180-
"""
181-
Creates a new Metadata Execution.
182-
183-
Args:
184-
base_execution_schema (BaseExecutionSchema):
185-
An instance of the BaseExecutionSchema class that can be
186-
provided instead of providing schema specific parameters.
187-
metadata_store_id (str):
188-
Optional. The <metadata_store_id> portion of the resource name with
189-
the format:
190-
projects/123/locations/us-central1/metadataStores/<metadata_store_id>/artifacts/<resource_id>
191-
If not provided, the MetadataStore's ID will be set to "default".
192-
project (str):
193-
Optional. Project used to create this Execution. Overrides project set in
194-
aiplatform.init.
195-
location (str):
196-
Optional. Location used to create this Execution. Overrides location set in
197-
aiplatform.init.
198-
credentials (auth_credentials.Credentials):
199-
Optional. Custom credentials used to create this Execution. Overrides
200-
credentials set in aiplatform.init.
201-
202-
Returns:
203-
Execution: Instantiated representation of the managed Metadata Execution.
204-
205-
"""
206-
resource = Execution.create(
207-
state=base_execution_schema.state,
208-
schema_title=base_execution_schema.schema_title,
209-
resource_id=base_execution_schema.execution_id,
210-
display_name=base_execution_schema.display_name,
211-
schema_version=base_execution_schema.schema_version,
212-
metadata=base_execution_schema.metadata,
213-
description=base_execution_schema.description,
214-
metadata_store_id=metadata_store_id,
215-
project=project,
216-
location=location,
217-
credentials=credentials,
218-
)
219-
return resource
220-
221169
def __enter__(self):
222170
if self.state is not gca_execution.Execution.State.RUNNING:
223171
self.update(state=gca_execution.Execution.State.RUNNING)

google/cloud/aiplatform/metadata/resource.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ def schema_title(self) -> str:
114114
def description(self) -> str:
115115
return self._gca_resource.description
116116

117+
@property
118+
def display_name(self) -> str:
119+
return self._gca_resource.display_name
120+
121+
@property
122+
def schema_version(self) -> str:
123+
return self._gca_resource.schema_version
124+
117125
@classmethod
118126
def get_or_create(
119127
cls,
@@ -221,7 +229,7 @@ def get(
221229
222230
Returns:
223231
resource (_Resource):
224-
Instantiated representation of the managed Metadata resource or None if no resouce was found.
232+
Instantiated representation of the managed Metadata resource or None if no resource was found.
225233
226234
"""
227235
resource = cls._get(

google/cloud/aiplatform/metadata/schema/base_artifact.py

+53-9
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from google.cloud.aiplatform.metadata import constants
2727

2828

29-
class BaseArtifactSchema(metaclass=abc.ABCMeta):
29+
class BaseArtifactSchema(artifact.Artifact):
3030
"""Base class for Metadata Artifact types."""
3131

3232
@property
@@ -81,13 +81,40 @@ def __init__(
8181
Pipelines), and the system does not prescribe or
8282
check the validity of state transitions.
8383
"""
84+
# resource_id is not stored in the proto. Create method uses the
85+
# resource_id along with project_id and location to construct an
86+
# resource_name which is stored in the proto message.
8487
self.artifact_id = artifact_id
85-
self.uri = uri
86-
self.display_name = display_name
87-
self.schema_version = schema_version or constants._DEFAULT_SCHEMA_VERSION
88-
self.description = description
89-
self.metadata = metadata
90-
self.state = state
88+
89+
# Store all other attributes using the proto structure.
90+
self._gca_resource = gca_artifact.Artifact()
91+
self._gca_resource.uri = uri
92+
self._gca_resource.display_name = display_name
93+
self._gca_resource.schema_version = (
94+
schema_version or constants._DEFAULT_SCHEMA_VERSION
95+
)
96+
self._gca_resource.description = description
97+
98+
# If metadata is None covert to {}
99+
metadata = metadata if metadata else {}
100+
self._nested_update_metadata(self._gca_resource, metadata)
101+
self._gca_resource.state = state
102+
103+
# TODO() Switch to @singledispatchmethod constructor overload after py>=3.8
104+
def _init_with_resource_name(
105+
self,
106+
*,
107+
artifact_name: str,
108+
):
109+
110+
"""Initializes the Artifact instance using an existing resource.
111+
112+
Args:
113+
artifact_name (str):
114+
Artifact name with the following format, this is globally unique in a metadataStore:
115+
projects/123/locations/us-central1/metadataStores/<metadata_store_id>/artifacts/<resource_id>.
116+
"""
117+
super(BaseArtifactSchema, self).__init__(artifact_name=artifact_name)
91118

92119
def create(
93120
self,
@@ -117,10 +144,27 @@ def create(
117144
Returns:
118145
Artifact: Instantiated representation of the managed Metadata Artifact.
119146
"""
120-
return artifact.Artifact.create_from_base_artifact_schema(
121-
base_artifact_schema=self,
147+
148+
# Check if metadata exists to avoid proto read error
149+
metadata = None
150+
if self._gca_resource.metadata:
151+
metadata = self.metadata
152+
153+
new_artifact_instance = artifact.Artifact.create(
154+
resource_id=self.artifact_id,
155+
schema_title=self.schema_title,
156+
uri=self.uri,
157+
display_name=self.display_name,
158+
schema_version=self.schema_version,
159+
description=self.description,
160+
metadata=metadata,
161+
state=self.state,
122162
metadata_store_id=metadata_store_id,
123163
project=project,
124164
location=location,
125165
credentials=credentials,
126166
)
167+
168+
# Reinstantiate this class using the newly created resource.
169+
self._init_with_resource_name(artifact_name=new_artifact_instance.resource_name)
170+
return self

google/cloud/aiplatform/metadata/schema/base_context.py

+41-7
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121

2222
from google.auth import credentials as auth_credentials
2323

24+
from google.cloud.aiplatform.compat.types import context as gca_context
2425
from google.cloud.aiplatform.metadata import constants
2526
from google.cloud.aiplatform.metadata import context
2627

2728

28-
class BaseContextSchema(metaclass=abc.ABCMeta):
29+
class BaseContextSchema(context.Context):
2930
"""Base class for Metadata Context schema."""
3031

3132
@property
@@ -62,11 +63,35 @@ def __init__(
6263
description (str):
6364
Optional. Describes the purpose of the Context to be created.
6465
"""
66+
# resource_id is not stored in the proto. Create method uses the
67+
# resource_id along with project_id and location to construct an
68+
# resource_name which is stored in the proto message.
6569
self.context_id = context_id
66-
self.display_name = display_name
67-
self.schema_version = schema_version or constants._DEFAULT_SCHEMA_VERSION
68-
self.metadata = metadata
69-
self.description = description
70+
71+
# Store all other attributes using the proto structure.
72+
self._gca_resource = gca_context.Context()
73+
self._gca_resource.display_name = display_name
74+
self._gca_resource.schema_version = (
75+
schema_version or constants._DEFAULT_SCHEMA_VERSION
76+
)
77+
# If metadata is None covert to {}
78+
metadata = metadata if metadata else {}
79+
self._nested_update_metadata(self._gca_resource, metadata)
80+
self._gca_resource.description = description
81+
82+
# TODO() Switch to @singledispatchmethod constructor overload after py>=3.8
83+
def _init_with_resource_name(
84+
self,
85+
*,
86+
context_name: str,
87+
):
88+
"""Initializes the Artifact instance using an existing resource.
89+
Args:
90+
context_name (str):
91+
Context name with the following format, this is globally unique in a metadataStore:
92+
projects/123/locations/us-central1/metadataStores/<metadata_store_id>/contexts/<resource_id>.
93+
"""
94+
super(BaseContextSchema, self).__init__(resource_name=context_name)
7095

7196
def create(
7297
self,
@@ -97,15 +122,24 @@ def create(
97122
Context: Instantiated representation of the managed Metadata Context.
98123
99124
"""
100-
return context.Context.create(
125+
# Check if metadata exists to avoid proto read error
126+
metadata = None
127+
if self._gca_resource.metadata:
128+
metadata = self.metadata
129+
130+
new_context = context.Context.create(
101131
resource_id=self.context_id,
102132
schema_title=self.schema_title,
103133
display_name=self.display_name,
104134
schema_version=self.schema_version,
105135
description=self.description,
106-
metadata=self.metadata,
136+
metadata=metadata,
107137
metadata_store_id=metadata_store_id,
108138
project=project,
109139
location=location,
110140
credentials=credentials,
111141
)
142+
143+
# Reinstantiate this class using the newly created resource.
144+
self._init_with_resource_name(context_name=new_context.resource_name)
145+
return self

0 commit comments

Comments
 (0)