Feature: Personalize (Schemas) (#5398)
This commit is contained in:
parent
dffd817a37
commit
c2d07e04b8
@ -4199,6 +4199,72 @@
|
||||
- [X] update_policy
|
||||
</details>
|
||||
|
||||
## personalize
|
||||
<details>
|
||||
<summary>6% implemented</summary>
|
||||
|
||||
- [ ] create_batch_inference_job
|
||||
- [ ] create_batch_segment_job
|
||||
- [ ] create_campaign
|
||||
- [ ] create_dataset
|
||||
- [ ] create_dataset_export_job
|
||||
- [ ] create_dataset_group
|
||||
- [ ] create_dataset_import_job
|
||||
- [ ] create_event_tracker
|
||||
- [ ] create_filter
|
||||
- [ ] create_recommender
|
||||
- [X] create_schema
|
||||
- [ ] create_solution
|
||||
- [ ] create_solution_version
|
||||
- [ ] delete_campaign
|
||||
- [ ] delete_dataset
|
||||
- [ ] delete_dataset_group
|
||||
- [ ] delete_event_tracker
|
||||
- [ ] delete_filter
|
||||
- [ ] delete_recommender
|
||||
- [X] delete_schema
|
||||
- [ ] delete_solution
|
||||
- [ ] describe_algorithm
|
||||
- [ ] describe_batch_inference_job
|
||||
- [ ] describe_batch_segment_job
|
||||
- [ ] describe_campaign
|
||||
- [ ] describe_dataset
|
||||
- [ ] describe_dataset_export_job
|
||||
- [ ] describe_dataset_group
|
||||
- [ ] describe_dataset_import_job
|
||||
- [ ] describe_event_tracker
|
||||
- [ ] describe_feature_transformation
|
||||
- [ ] describe_filter
|
||||
- [ ] describe_recipe
|
||||
- [ ] describe_recommender
|
||||
- [X] describe_schema
|
||||
- [ ] describe_solution
|
||||
- [ ] describe_solution_version
|
||||
- [ ] get_solution_metrics
|
||||
- [ ] list_batch_inference_jobs
|
||||
- [ ] list_batch_segment_jobs
|
||||
- [ ] list_campaigns
|
||||
- [ ] list_dataset_export_jobs
|
||||
- [ ] list_dataset_groups
|
||||
- [ ] list_dataset_import_jobs
|
||||
- [ ] list_datasets
|
||||
- [ ] list_event_trackers
|
||||
- [ ] list_filters
|
||||
- [ ] list_recipes
|
||||
- [ ] list_recommenders
|
||||
- [X] list_schemas
|
||||
- [ ] list_solution_versions
|
||||
- [ ] list_solutions
|
||||
- [ ] list_tags_for_resource
|
||||
- [ ] start_recommender
|
||||
- [ ] stop_recommender
|
||||
- [ ] stop_solution_version_creation
|
||||
- [ ] tag_resource
|
||||
- [ ] untag_resource
|
||||
- [ ] update_campaign
|
||||
- [ ] update_recommender
|
||||
</details>
|
||||
|
||||
## pinpoint
|
||||
<details>
|
||||
<summary>10% implemented</summary>
|
||||
@ -6268,7 +6334,6 @@
|
||||
- opsworkscm
|
||||
- outposts
|
||||
- panorama
|
||||
- personalize
|
||||
- personalize-events
|
||||
- personalize-runtime
|
||||
- pi
|
||||
|
94
docs/docs/services/personalize.rst
Normal file
94
docs/docs/services/personalize.rst
Normal file
@ -0,0 +1,94 @@
|
||||
.. _implementedservice_personalize:
|
||||
|
||||
.. |start-h3| raw:: html
|
||||
|
||||
<h3>
|
||||
|
||||
.. |end-h3| raw:: html
|
||||
|
||||
</h3>
|
||||
|
||||
===========
|
||||
personalize
|
||||
===========
|
||||
|
||||
.. autoclass:: moto.personalize.models.PersonalizeBackend
|
||||
|
||||
|start-h3| Example usage |end-h3|
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
@mock_personalize
|
||||
def test_personalize_behaviour:
|
||||
boto3.client("personalize")
|
||||
...
|
||||
|
||||
|
||||
|
||||
|start-h3| Implemented features for this service |end-h3|
|
||||
|
||||
- [ ] create_batch_inference_job
|
||||
- [ ] create_batch_segment_job
|
||||
- [ ] create_campaign
|
||||
- [ ] create_dataset
|
||||
- [ ] create_dataset_export_job
|
||||
- [ ] create_dataset_group
|
||||
- [ ] create_dataset_import_job
|
||||
- [ ] create_event_tracker
|
||||
- [ ] create_filter
|
||||
- [ ] create_recommender
|
||||
- [X] create_schema
|
||||
- [ ] create_solution
|
||||
- [ ] create_solution_version
|
||||
- [ ] delete_campaign
|
||||
- [ ] delete_dataset
|
||||
- [ ] delete_dataset_group
|
||||
- [ ] delete_event_tracker
|
||||
- [ ] delete_filter
|
||||
- [ ] delete_recommender
|
||||
- [X] delete_schema
|
||||
- [ ] delete_solution
|
||||
- [ ] describe_algorithm
|
||||
- [ ] describe_batch_inference_job
|
||||
- [ ] describe_batch_segment_job
|
||||
- [ ] describe_campaign
|
||||
- [ ] describe_dataset
|
||||
- [ ] describe_dataset_export_job
|
||||
- [ ] describe_dataset_group
|
||||
- [ ] describe_dataset_import_job
|
||||
- [ ] describe_event_tracker
|
||||
- [ ] describe_feature_transformation
|
||||
- [ ] describe_filter
|
||||
- [ ] describe_recipe
|
||||
- [ ] describe_recommender
|
||||
- [X] describe_schema
|
||||
- [ ] describe_solution
|
||||
- [ ] describe_solution_version
|
||||
- [ ] get_solution_metrics
|
||||
- [ ] list_batch_inference_jobs
|
||||
- [ ] list_batch_segment_jobs
|
||||
- [ ] list_campaigns
|
||||
- [ ] list_dataset_export_jobs
|
||||
- [ ] list_dataset_groups
|
||||
- [ ] list_dataset_import_jobs
|
||||
- [ ] list_datasets
|
||||
- [ ] list_event_trackers
|
||||
- [ ] list_filters
|
||||
- [ ] list_recipes
|
||||
- [ ] list_recommenders
|
||||
- [X] list_schemas
|
||||
|
||||
Pagination is not yet implemented
|
||||
|
||||
|
||||
- [ ] list_solution_versions
|
||||
- [ ] list_solutions
|
||||
- [ ] list_tags_for_resource
|
||||
- [ ] start_recommender
|
||||
- [ ] stop_recommender
|
||||
- [ ] stop_solution_version_creation
|
||||
- [ ] tag_resource
|
||||
- [ ] untag_resource
|
||||
- [ ] update_campaign
|
||||
- [ ] update_recommender
|
||||
|
@ -107,6 +107,7 @@ mock_mediastoredata = lazy_load(
|
||||
mock_mq = lazy_load(".mq", "mock_mq", boto3_name="mq")
|
||||
mock_opsworks = lazy_load(".opsworks", "mock_opsworks")
|
||||
mock_organizations = lazy_load(".organizations", "mock_organizations")
|
||||
mock_personalize = lazy_load(".personalize", "mock_personalize")
|
||||
mock_pinpoint = lazy_load(".pinpoint", "mock_pinpoint")
|
||||
mock_polly = lazy_load(".polly", "mock_polly")
|
||||
mock_quicksight = lazy_load(".quicksight", "mock_quicksight")
|
||||
|
@ -103,6 +103,7 @@ backend_url_patterns = [
|
||||
("mq", re.compile("https?://mq\\.(.+)\\.amazonaws\\.com")),
|
||||
("opsworks", re.compile("https?://opsworks\\.us-east-1\\.amazonaws.com")),
|
||||
("organizations", re.compile("https?://organizations\\.(.+)\\.amazonaws\\.com")),
|
||||
("personalize", re.compile("https?://personalize\\.(.+)\\.amazonaws\\.com")),
|
||||
("pinpoint", re.compile("https?://pinpoint\\.(.+)\\.amazonaws\\.com")),
|
||||
("polly", re.compile("https?://polly\\.(.+)\\.amazonaws.com")),
|
||||
("quicksight", re.compile("https?://quicksight\\.(.+)\\.amazonaws\\.com")),
|
||||
|
5
moto/personalize/__init__.py
Normal file
5
moto/personalize/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
"""personalize module initialization; sets value for base decorator."""
|
||||
from .models import personalize_backends
|
||||
from ..core.models import base_decorator
|
||||
|
||||
mock_personalize = base_decorator(personalize_backends)
|
13
moto/personalize/exceptions.py
Normal file
13
moto/personalize/exceptions.py
Normal file
@ -0,0 +1,13 @@
|
||||
"""Exceptions raised by the personalize service."""
|
||||
from moto.core.exceptions import JsonRESTError
|
||||
|
||||
|
||||
class PersonalizeException(JsonRESTError):
|
||||
pass
|
||||
|
||||
|
||||
class ResourceNotFoundException(PersonalizeException):
|
||||
def __init__(self, arn):
|
||||
super().__init__(
|
||||
"ResourceNotFoundException", f"Resource Arn {arn} does not exist."
|
||||
)
|
64
moto/personalize/models.py
Normal file
64
moto/personalize/models.py
Normal file
@ -0,0 +1,64 @@
|
||||
"""PersonalizeBackend class with methods for supported APIs."""
|
||||
|
||||
from .exceptions import ResourceNotFoundException
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import BackendDict, unix_time
|
||||
|
||||
|
||||
class Schema(BaseModel):
|
||||
def __init__(self, account_id, region, name, schema, domain):
|
||||
self.name = name
|
||||
self.schema = schema
|
||||
self.domain = domain
|
||||
self.arn = f"arn:aws:personalize:{region}:{account_id}:schema/{name}"
|
||||
self.created = unix_time()
|
||||
|
||||
def to_dict(self, full=True):
|
||||
d = {
|
||||
"name": self.name,
|
||||
"schemaArn": self.arn,
|
||||
"domain": self.domain,
|
||||
"creationDateTime": self.created,
|
||||
"lastUpdatedDateTime": self.created,
|
||||
}
|
||||
if full:
|
||||
d["schema"] = self.schema
|
||||
return d
|
||||
|
||||
|
||||
class PersonalizeBackend(BaseBackend):
|
||||
"""Implementation of Personalize APIs."""
|
||||
|
||||
def __init__(self, region_name, account_id):
|
||||
super().__init__(region_name, account_id)
|
||||
self.schemas: [str, Schema] = dict()
|
||||
|
||||
def create_schema(self, name, schema, domain):
|
||||
schema = Schema(
|
||||
region=self.region_name,
|
||||
account_id=self.account_id,
|
||||
name=name,
|
||||
schema=schema,
|
||||
domain=domain,
|
||||
)
|
||||
self.schemas[schema.arn] = schema
|
||||
return schema.arn
|
||||
|
||||
def delete_schema(self, schema_arn):
|
||||
if schema_arn not in self.schemas:
|
||||
raise ResourceNotFoundException(schema_arn)
|
||||
self.schemas.pop(schema_arn, None)
|
||||
|
||||
def describe_schema(self, schema_arn):
|
||||
if schema_arn not in self.schemas:
|
||||
raise ResourceNotFoundException(schema_arn)
|
||||
return self.schemas[schema_arn]
|
||||
|
||||
def list_schemas(self) -> [Schema]:
|
||||
"""
|
||||
Pagination is not yet implemented
|
||||
"""
|
||||
return self.schemas.values()
|
||||
|
||||
|
||||
personalize_backends = BackendDict(PersonalizeBackend, "personalize")
|
48
moto/personalize/responses.py
Normal file
48
moto/personalize/responses.py
Normal file
@ -0,0 +1,48 @@
|
||||
"""Handles incoming personalize requests, invokes methods, returns responses."""
|
||||
import json
|
||||
|
||||
from moto.core.responses import BaseResponse
|
||||
from .models import personalize_backends
|
||||
|
||||
|
||||
class PersonalizeResponse(BaseResponse):
|
||||
"""Handler for Personalize requests and responses."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(service_name="personalize")
|
||||
|
||||
@property
|
||||
def personalize_backend(self):
|
||||
"""Return backend instance specific for this region."""
|
||||
return personalize_backends[self.current_account][self.region]
|
||||
|
||||
# add methods from here
|
||||
|
||||
def create_schema(self):
|
||||
params = json.loads(self.body)
|
||||
name = params.get("name")
|
||||
schema = params.get("schema")
|
||||
domain = params.get("domain")
|
||||
schema_arn = self.personalize_backend.create_schema(
|
||||
name=name,
|
||||
schema=schema,
|
||||
domain=domain,
|
||||
)
|
||||
return json.dumps(dict(schemaArn=schema_arn))
|
||||
|
||||
def delete_schema(self):
|
||||
params = json.loads(self.body)
|
||||
schema_arn = params.get("schemaArn")
|
||||
self.personalize_backend.delete_schema(schema_arn=schema_arn)
|
||||
return "{}"
|
||||
|
||||
def describe_schema(self):
|
||||
params = json.loads(self.body)
|
||||
schema_arn = params.get("schemaArn")
|
||||
schema = self.personalize_backend.describe_schema(schema_arn=schema_arn)
|
||||
return json.dumps(dict(schema=schema.to_dict()))
|
||||
|
||||
def list_schemas(self):
|
||||
schemas = self.personalize_backend.list_schemas()
|
||||
resp = {"schemas": [s.to_dict(full=False) for s in schemas]}
|
||||
return json.dumps(resp)
|
11
moto/personalize/urls.py
Normal file
11
moto/personalize/urls.py
Normal file
@ -0,0 +1,11 @@
|
||||
"""personalize base URL and path."""
|
||||
from .responses import PersonalizeResponse
|
||||
|
||||
url_bases = [
|
||||
r"https?://personalize\.(.+)\.amazonaws\.com",
|
||||
]
|
||||
|
||||
|
||||
url_paths = {
|
||||
"{0}/$": PersonalizeResponse.dispatch,
|
||||
}
|
0
tests/test_personalize/__init__.py
Normal file
0
tests/test_personalize/__init__.py
Normal file
121
tests/test_personalize/test_personalize_schema.py
Normal file
121
tests/test_personalize/test_personalize_schema.py
Normal file
@ -0,0 +1,121 @@
|
||||
"""Unit tests for personalize-supported APIs."""
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa # pylint: disable=unused-import
|
||||
import pytest
|
||||
from botocore.exceptions import ClientError
|
||||
from moto import mock_personalize
|
||||
from moto.core import DEFAULT_ACCOUNT_ID
|
||||
|
||||
# See our Development Tips on writing tests for hints on how to write good tests:
|
||||
# http://docs.getmoto.org/en/latest/docs/contributing/development_tips/tests.html
|
||||
|
||||
|
||||
@mock_personalize
|
||||
def test_create_schema():
|
||||
client = boto3.client("personalize", region_name="ap-southeast-1")
|
||||
schema = {
|
||||
"type": "record",
|
||||
"name": "Interactions",
|
||||
"namespace": "com.amazonaws.personalize.schema",
|
||||
"fields": [
|
||||
{"name": "USER_ID", "type": "string"},
|
||||
{"name": "ITEM_ID", "type": "string"},
|
||||
{"name": "TIMESTAMP", "type": "long"},
|
||||
],
|
||||
"version": "1.0",
|
||||
}
|
||||
|
||||
create_schema_response = client.create_schema(
|
||||
name="personalize-demo-schema", schema=json.dumps(schema)
|
||||
)
|
||||
create_schema_response.should.have.key("schemaArn").equals(
|
||||
f"arn:aws:personalize:ap-southeast-1:{DEFAULT_ACCOUNT_ID}:schema/personalize-demo-schema"
|
||||
)
|
||||
|
||||
|
||||
@mock_personalize
|
||||
def test_delete_schema():
|
||||
client = boto3.client("personalize", region_name="us-east-1")
|
||||
schema_arn = client.create_schema(name="myname", schema=json.dumps("sth"))[
|
||||
"schemaArn"
|
||||
]
|
||||
client.delete_schema(schemaArn=schema_arn)
|
||||
|
||||
client.list_schemas().should.have.key("schemas").equals([])
|
||||
|
||||
|
||||
@mock_personalize
|
||||
def test_delete_schema__unknown():
|
||||
arn = f"arn:aws:personalize:ap-southeast-1:{DEFAULT_ACCOUNT_ID}:schema/personalize-demo-schema"
|
||||
client = boto3.client("personalize", region_name="us-east-2")
|
||||
with pytest.raises(ClientError) as exc:
|
||||
client.delete_schema(schemaArn=arn)
|
||||
err = exc.value.response["Error"]
|
||||
err["Code"].should.equal("ResourceNotFoundException")
|
||||
err["Message"].should.equal(f"Resource Arn {arn} does not exist.")
|
||||
|
||||
|
||||
@mock_personalize
|
||||
def test_describe_schema():
|
||||
client = boto3.client("personalize", region_name="us-east-2")
|
||||
schema_arn = client.create_schema(name="myname", schema="sth")["schemaArn"]
|
||||
resp = client.describe_schema(schemaArn=schema_arn)
|
||||
resp.should.have.key("schema")
|
||||
schema = resp["schema"]
|
||||
|
||||
schema.should.have.key("name").equals("myname")
|
||||
schema.should.have.key("schemaArn").match("schema/myname")
|
||||
schema.should.have.key("schema").equals("sth")
|
||||
schema.should.have.key("creationDateTime")
|
||||
schema.should.have.key("lastUpdatedDateTime")
|
||||
|
||||
|
||||
@mock_personalize
|
||||
def test_describe_schema__with_domain():
|
||||
client = boto3.client("personalize", region_name="us-east-2")
|
||||
schema_arn = client.create_schema(name="myname", schema="sth", domain="ECOMMERCE")[
|
||||
"schemaArn"
|
||||
]
|
||||
resp = client.describe_schema(schemaArn=schema_arn)
|
||||
resp.should.have.key("schema")
|
||||
schema = resp["schema"]
|
||||
|
||||
schema.should.have.key("domain").equals("ECOMMERCE")
|
||||
|
||||
|
||||
@mock_personalize
|
||||
def test_describe_schema__unknown():
|
||||
arn = (
|
||||
"arn:aws:personalize:ap-southeast-1:486285699788:schema/personalize-demo-schema"
|
||||
)
|
||||
client = boto3.client("personalize", region_name="us-east-2")
|
||||
with pytest.raises(ClientError) as exc:
|
||||
client.describe_schema(schemaArn=arn)
|
||||
err = exc.value.response["Error"]
|
||||
err["Code"].should.equal("ResourceNotFoundException")
|
||||
err["Message"].should.equal(f"Resource Arn {arn} does not exist.")
|
||||
|
||||
|
||||
@mock_personalize
|
||||
def test_list_schemas__initial():
|
||||
client = boto3.client("personalize", region_name="us-east-2")
|
||||
resp = client.list_schemas()
|
||||
|
||||
resp.should.have.key("schemas").equals([])
|
||||
|
||||
|
||||
@mock_personalize
|
||||
def test_list_schema():
|
||||
client = boto3.client("personalize", region_name="us-east-2")
|
||||
schema_arn = client.create_schema(name="myname", schema="sth")["schemaArn"]
|
||||
|
||||
resp = client.list_schemas()
|
||||
resp.should.have.key("schemas").length_of(1)
|
||||
schema = resp["schemas"][0]
|
||||
|
||||
schema.should.have.key("name").equals("myname")
|
||||
schema.should.have.key("schemaArn").equals(schema_arn)
|
||||
schema.shouldnt.have.key("schema")
|
||||
schema.should.have.key("creationDateTime")
|
||||
schema.should.have.key("lastUpdatedDateTime")
|
Loading…
Reference in New Issue
Block a user