Skip to content

Commit

Permalink
replace feature_utils.validate_*_name with GAPIC parse_*_path, import…
Browse files Browse the repository at this point in the history
… pandas to try
  • Loading branch information
morgandu committed Nov 22, 2021
1 parent 73d6739 commit 8437b58
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 114 deletions.
8 changes: 7 additions & 1 deletion google/cloud/aiplatform/_featurestores/entity_type.py
Expand Up @@ -18,7 +18,6 @@
from typing import Dict, List, Optional, Sequence, Tuple, Union

import datetime
import pandas as pd

from google.auth import credentials as auth_credentials
from google.protobuf import field_mask_pb2
Expand All @@ -29,6 +28,13 @@
from google.cloud.aiplatform import utils
from google.cloud.aiplatform.utils import featurestore_utils

try:
import pandas as pd
except ImportError:
raise ImportError(
"Pandas is not installed. Please install pandas to use Vertex Feature Store"
)

_LOGGER = base.Logger(__name__)
_ALL_FEATURE_IDS = "*"

Expand Down
24 changes: 10 additions & 14 deletions google/cloud/aiplatform/_featurestores/featurestore.py
Expand Up @@ -17,8 +17,6 @@

from typing import Dict, List, Optional, Sequence, Tuple, Union

import pandas as pd

from google.auth import credentials as auth_credentials
from google.protobuf import field_mask_pb2

Expand All @@ -29,6 +27,13 @@
from google.cloud.aiplatform import utils
from google.cloud.aiplatform.utils import featurestore_utils

try:
import pandas as pd
except ImportError:
raise ImportError(
"Pandas is not installed. Please install pandas to use Vertex Feature Store"
)

_LOGGER = base.Logger(__name__)


Expand Down Expand Up @@ -76,19 +81,10 @@ def __init__(
credentials (auth_credentials.Credentials):
Optional. Custom credentials to use to retrieve this Featurestore. Overrides
credentials set in aiplatform.init.
Raises:
ValueError if the provided featurestore_name is not in form of a fully-qualified
featurestore resource name nor a featurestore ID.
"""
if not (
featurestore_utils.validate_featurestore_name(featurestore_name)
or featurestore_utils.validate_id(featurestore_name)
):
raise ValueError(
f"{featurestore_name} is not in form of a fully-qualified "
f"featurestore resource name nor a featurestore ID."
)
_ = featurestore_utils.validate_and_get_featurestore_resource_id(
featurestore_name
)

super().__init__(
project=project,
Expand Down
64 changes: 17 additions & 47 deletions google/cloud/aiplatform/utils/featurestore_utils.py
Expand Up @@ -16,53 +16,19 @@
#

import re
from typing import Dict, Optional, Tuple
from typing import Optional, Tuple

from google.cloud.aiplatform.compat.services import featurestore_service_client

CompatFeaturestoreServiceClient = featurestore_service_client.FeaturestoreServiceClient
RESOURCE_ID_PATTERN_REGEX = r"[a-z_][a-z0-9_]{0,59}"
FEATURESTORE_NAME_PATTERN_REGEX = (
r"projects\/(?P<project>[\w-]+)"
r"\/locations\/(?P<location>[\w-]+)"
r"\/featurestores\/(?P<featurestore_id>" + RESOURCE_ID_PATTERN_REGEX + r")"
)
ENTITY_TYPE_NAME_PATTERN_REGEX = (
FEATURESTORE_NAME_PATTERN_REGEX
+ r"\/entityTypes\/(?P<entity_type_id>"
+ RESOURCE_ID_PATTERN_REGEX
+ r")"
)
FEATURE_NAME_PATTERN_REGEX = (
ENTITY_TYPE_NAME_PATTERN_REGEX
+ r"\/features\/(?P<feature_id>"
+ RESOURCE_ID_PATTERN_REGEX
+ r")"
)


def validate_id(resource_id: str) -> bool:
"""Validates feature store resource ID pattern."""
return bool(re.compile(r"^" + RESOURCE_ID_PATTERN_REGEX + r"$").match(resource_id))


def validate_featurestore_name(featurestore_name: str) -> Dict[str, str]:
"""Validates featurestore name pattern."""
m = re.compile(r"^" + FEATURESTORE_NAME_PATTERN_REGEX + r"$").match(
featurestore_name
)
return m.groupdict() if m else {}


def validate_entity_type_name(entity_type_name: str) -> Dict[str, str]:
"""Validates entity type name pattern."""
m = re.compile(r"^" + ENTITY_TYPE_NAME_PATTERN_REGEX + r"$").match(entity_type_name)
return m.groupdict() if m else {}


def validate_feature_name(feature_name: str) -> Dict[str, str]:
"""Validates feature name pattern."""
m = re.compile(r"^" + FEATURE_NAME_PATTERN_REGEX + r"$").match(feature_name)
return m.groupdict() if m else {}


def get_entity_type_resource_noun(featurestore_id: str) -> str:
"""Gets composite resource noun for entity_type resource."""
return f"featurestores/{featurestore_id}/entityTypes"
Expand All @@ -89,10 +55,12 @@ def validate_and_get_featurestore_resource_id(featurestore_name: str) -> str:
ValueError if the provided featurestore_name is not in form of a fully-qualified
featurestore resource name nor an featurestore ID.
"""
match = validate_featurestore_name(featurestore_name)
match = CompatFeaturestoreServiceClient.parse_featurestore_path(
path=featurestore_name
)

if match:
featurestore_id = match["featurestore_id"]
featurestore_id = match["featurestore"]
elif validate_id(featurestore_name):
featurestore_id = featurestore_name
else:
Expand Down Expand Up @@ -123,11 +91,13 @@ def validate_and_get_entity_type_resource_ids(
ValueError if the provided entity_type_name is not in form of a fully-qualified
entityType resource name nor an entity_type ID with featurestore_id passed.
"""
match = validate_entity_type_name(entity_type_name)
match = CompatFeaturestoreServiceClient.parse_entity_type_path(
path=entity_type_name
)

if match:
featurestore_id = match["featurestore_id"]
entity_type_id = match["entity_type_id"]
featurestore_id = match["featurestore"]
entity_type_id = match["entity_type"]
elif (
validate_id(entity_type_name)
and featurestore_id
Expand Down Expand Up @@ -166,12 +136,12 @@ def validate_and_get_feature_resource_ids(
feature resource name nor a feature ID with featurestore_id and entity_type_id passed.
"""

match = validate_feature_name(feature_name)
match = CompatFeaturestoreServiceClient.parse_feature_path(path=feature_name)

if match:
featurestore_id = match["featurestore_id"]
entity_type_id = match["entity_type_id"]
feature_id = match["feature_id"]
featurestore_id = match["featurestore"]
entity_type_id = match["entity_type"]
feature_id = match["feature"]
elif (
validate_id(feature_name)
and featurestore_id
Expand Down
52 changes: 0 additions & 52 deletions tests/unit/aiplatform/test_featurestores.py
Expand Up @@ -272,58 +272,6 @@ class TestFeaturestoreUtils:
def test_validate_resource_id(self, resource_id: str, expected: bool):
assert expected == featurestore_utils.validate_id(resource_id)

@pytest.mark.parametrize(
"featurestore_name, expected",
[
(
"projects/123456/locations/us-central1/featurestores/featurestore_id1",
True,
),
(
"projects/123456/locations/us-central1/feature_stores/featurestore_id1",
False,
),
],
)
def test_validate_featurestore_name(self, featurestore_name: str, expected: bool):
assert expected == bool(
featurestore_utils.validate_featurestore_name(featurestore_name)
)

@pytest.mark.parametrize(
"entity_type_name, expected",
[
(
"projects/123456/locations/us-central1/featurestores/featurestore_id1/entityTypes/entity_type_id1",
True,
),
(
"projects/123456/locations/us-central1/featurestores/featurestore_id1/entitytypes/entity_type_id1",
False,
),
],
)
def test_validate_entity_type_name(self, entity_type_name: str, expected: bool):
assert expected == bool(
featurestore_utils.validate_entity_type_name(entity_type_name)
)

@pytest.mark.parametrize(
"feature_name, expected",
[
(
"projects/123456/locations/us-central1/featurestores/featurestore_id1/entityTypes/entity_type_id1/features/feature_id1",
True,
),
(
"projects/123456/locations/us-central1/featurestores/featurestore_id1/entityTypes/entity_type_id1/feature/feature_id1",
False,
),
],
)
def test_validate_feature_name(self, feature_name: str, expected: bool):
assert expected == bool(featurestore_utils.validate_feature_name(feature_name))

def test_get_entity_type_resource_noun(self):
assert (
featurestore_utils.get_entity_type_resource_noun(
Expand Down

0 comments on commit 8437b58

Please sign in to comment.