Skip to content

Commit

Permalink
Merge pull request #279 from juliamcclellan/project_builder
Browse files Browse the repository at this point in the history
Attribute mapping spec
  • Loading branch information
pcattori committed Aug 16, 2019
2 parents 6cafaf7 + f94b04a commit 337f775
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [#275](https://github.com/Datatamer/unify-client-python/issues/275) Create a category with a category spec
- [#273](https://github.com/Datatamer/unify-client-python/issues/273) Attribute type spec to allow for attribute creation
- [#219](https://github.com/Datatamer/tamr-client/issues/219) Delete a resource from collection.
- [#277](https://github.com/Datatamer/unify-client-python/issues/277) Attribute mapping spec

**BUG FIXES**
- [#235](https://github.com/Datatamer/unify-client-python/issues/235) Making `AttributeCollection` retrieve attributes directly instead of by streaming
Expand Down
6 changes: 6 additions & 0 deletions docs/developer-interface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ Attribute Mapping
.. autoclass:: tamr_unify_client.project.attribute_mapping.resource.AttributeMapping
:members:

Attribute Mapping Spec
""""""""""""""""""""""

.. autoclass:: tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec
:members:

Attribute Mapping Collection
""""""""""""""""""""""""""""

Expand Down
133 changes: 112 additions & 21 deletions tamr_unify_client/project/attribute_mapping/resource.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from copy import deepcopy


class AttributeMapping:
"""see https://docs.tamr.com/reference#retrieve-projects-mappings
AttributeMapping and AttributeMappingCollection do not inherit from BaseResource and BaseCollection.
Expand Down Expand Up @@ -64,6 +67,14 @@ def resource_id(self):
spliced = self.relative_id.split("attributeMappings/")[1]
return spliced

def spec(self):
"""Returns a spec representation of this attribute mapping.
:return: The attribute mapping spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec.of(self)

def __repr__(self):
return (
f"{self.__class__.__module__}."
Expand All @@ -82,61 +93,141 @@ def __repr__(self):


class AttributeMappingSpec:
def __init__(self, client, data, api_path):
self.client = client
"""A representation of the server view of an attribute mapping"""

def __init__(self, data):
self._data = data
self.api_path = api_path

def from_data(self, data):
return AttributeMappingSpec(self.client, data, self.api_path)
@staticmethod
def of(resource):
"""Creates an attribute mapping spec from a attribute mapping.
:param resource: The existing attribute mapping.
:type resource: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMapping`
:return: The corresponding attribute mapping spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(deepcopy(resource._data))

@staticmethod
def new():
"""Creates a blank spec that could be used to construct a new attribute mapping.
:return: The empty spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec({})

def to_dict(self):
"""Returns a version of this spec that conforms to the API representation.
:returns: The spec's dict.
:rtype: dict
"""
return deepcopy(self._data)

def with_input_attribute_id(self, new_input_attribute_id):
""":type: str"""
return self.from_data(
"""Creates a new spec with the same properties, updating the input attribute id.
:param new_input_attribute_id: The new input attribute id.
:type new_input_attribute_id: str
:return: The new spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(
{**self._data, "inputAttributeId": new_input_attribute_id}
)

def with_relative_input_attribute_id(self, new_relative_input_attribute_id):
""":type: str"""
return self.from_data(
"""Creates a new spec with the same properties, updating the relative input attribute id.
:param new_relative_input_attribute_id: The new relative input attribute Id.
:type new_relative_input_attribute_id: str
:return: The new spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(
{**self._data, "relativeInputAttributeId": new_relative_input_attribute_id}
)

def with_input_dataset_name(self, new_input_dataset_name):
""":type: str"""
return self.from_data(
"""Creates a new spec with the same properties, updating the input dataset name.
:param new_input_dataset_name: The new input dataset name.
:type new_input_dataset_name: str
:return: The new spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(
{**self._data, "inputDatasetName": new_input_dataset_name}
)

def with_input_attribute_name(self, new_input_attribute_name):
""":type: str"""
return self.from_data(
"""Creates a new spec with the same properties, updating the input attribute name.
:param new_input_attribute_name: The new input attribute name.
:type new_input_attribute_name: str
:return: The new spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(
{**self._data, "inputAttributeName": new_input_attribute_name}
)

def with_unified_attribute_id(self, new_unified_attribute_id):
""":type: str"""
return self.from_data(
"""Creates a new spec with the same properties, updating the unified attribute id.
:param new_unified_attribute_id: The new unified attribute id.
:type new_unified_attribute_id: str
:return: The new spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(
{**self._data, "unifiedAttributeId": new_unified_attribute_id}
)

def with_relative_unified_attribute_id(self, new_relative_unified_attribute_id):
""":type: str"""
return self.from_data(
"""Creates a new spec with the same properties, updating the relative unified attribute id.
:param new_relative_unified_attribute_id: The new relative unified attribute id.
:type new_relative_unified_attribute_id: str
:return: The new spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(
{
**self._data,
"relativeUnifiedAttributeId": new_relative_unified_attribute_id,
}
)

def with_unified_dataset_name(self, new_unified_dataset_name):
""":type: str"""
return self.from_data(
"""Creates a new spec with the same properties, updating the unified dataset name.
:param new_unified_dataset_name: The new unified dataset name.
:type new_unified_dataset_name: str
:return: The new spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(
{**self._data, "unifiedDatasetName": new_unified_dataset_name}
)

def with_unified_attribute_name(self, new_unified_attribute_name):
""":type: str"""
return self.from_data(
"""Creates a new spec with the same properties, updating the unified attribute name.
:param new_unified_attribute_name: The new unified attribute name.
:type new_unified_attribute_name: str
:return: The new spec.
:rtype: :class:`~tamr_unify_client.project.attribute_mapping.resource.AttributeMappingSpec`
"""
return AttributeMappingSpec(
{**self._data, "unifiedAttributeName": new_unified_attribute_name}
)

def __repr__(self):
return (
f"{self.__class__.__module__}."
f"{self.__class__.__qualname__}("
f"dict={self._data})"
)
46 changes: 42 additions & 4 deletions tests/unit/test_attribute_mapping_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from tamr_unify_client.project.attribute_mapping.collection import (
AttributeMappingCollection,
)
from tamr_unify_client.project.attribute_mapping.resource import AttributeMappingSpec


class TestAttributeMappingCollection(TestCase):
Expand Down Expand Up @@ -57,19 +58,56 @@ def create_callback(request, snoop):
self.assertEqual(test.input_dataset_name, self.create_json["inputDatasetName"])
self.assertEqual(json.loads(snoop_dict["payload"]), self.create_json)

@responses.activate
def test_create_from_spec(self):
def create_callback(request, snoop):
snoop["payload"] = json.loads(request.body)
return 200, {}, json.dumps(self.mappings_json[0])

url = "http://localhost:9100/api/versioned/v1/projects/4/attributeMappings"
responses.add(responses.GET, url, json=self.mappings_json)
snoop_dict = {}
responses.add_callback(
responses.POST, url, partial(create_callback, snoop=snoop_dict)
)

map_collection = AttributeMappingCollection(
self.tamr, "projects/4/attributeMappings"
)
spec = (
AttributeMappingSpec.new()
.with_relative_input_attribute_id(
self.create_json["relativeInputAttributeId"]
)
.with_input_dataset_name(self.create_json["inputDatasetName"])
.with_input_attribute_name(self.create_json["inputAttributeName"])
.with_relative_unified_attribute_id(
self.create_json["relativeUnifiedAttributeId"]
)
.with_unified_dataset_name(self.create_json["unifiedDatasetName"])
.with_unified_attribute_name(self.create_json["unifiedAttributeName"])
)
map_collection.create(spec.to_dict())

self.assertEqual(snoop_dict["payload"], self.create_json)

create_json = {
"id": "unify://unified-data/v1/projects/1/attributeMappings/19594-14",
"relativeId": "projects/1/attributeMappings/19594-14",
"inputAttributeId": "unify://unified-data/v1/datasets/6/attributes/suburb",
"relativeInputAttributeId": "datasets/6/attributes/suburb",
"inputDatasetName": "febrl_sample_2k.csv",
"inputAttributeName": "suburb",
"unifiedAttributeId": "unify://unified-data/v1/datasets/8/attributes/suburb",
"relativeUnifiedAttributeId": "datasets/8/attributes/suburb",
"unifiedDatasetName": "Project_1_unified_dataset",
"unifiedAttributeName": "suburb",
}

created_json = {
**create_json,
"id": "unify://unified-data/v1/projects/1/attributeMappings/19594-14",
"relativeId": "projects/1/attributeMappings/19594-14",
"inputAttributeId": "unify://unified-data/v1/datasets/6/attributes/suburb",
"unifiedAttributeId": "unify://unified-data/v1/datasets/8/attributes/suburb",
}

mappings_json = [
{
"id": "unify://unified-data/v1/projects/4/attributeMappings/19629-12",
Expand Down

0 comments on commit 337f775

Please sign in to comment.