Skip to content

Commit 6a0f92c

Browse files
authored
Merge pull request #39 from CitrineInformatics/release/0.2.0
Taurus v0.2.0 is released!
2 parents 96a17dd + 7c0b9a3 commit 6a0f92c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+978
-139
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ install:
77
- pip install -U -r test_requirements.txt
88
- pip install --no-deps -e .
99
script:
10-
- pytest --flake8 --cov=taurus --cov-report term-missing --cov-report term:skip-covered
11-
--cov-fail-under=91 -s -r ./taurus
10+
- pytest --flake8 --cov=taurus --cov-report term-missing --cov-report term:skip-covered --cov-config=tox.ini
11+
--cov-fail-under=100 -s -r ./taurus
1212
- cd docs; make html; cd ..;
1313
- touch ./docs/_build/html/.nojekyll
1414
deploy:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Python binding for Citrine's nextgen data concepts (codename: taurus).
33

44

5-
Provides a framework for storing information about the processes that create materials, the materials themselves, and measurements performance on those materials.
5+
Provides a framework for storing information about the processes that create materials, the materials themselves, and measurements performed on those materials.
66
Detailed documentation of the next gen format can be found in the language-agnostic documentation.
77

88
## Installation

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def run(self):
3636

3737

3838
setup(name='taurus-citrine',
39-
version='0.1.0',
39+
version='0.2.0',
4040
url='http://github.com/CitrineInformatics/taurus',
4141
description='Python library for the Citrine Platform',
4242
author='Max Hutchinson',

taurus/client/json_encoder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def thin_dumps(obj, **kwargs):
152152
153153
"""
154154
if not isinstance(obj, BaseEntity):
155-
raise ValueError("Can only dump BaseEntities, but got {}".format(type(obj)))
155+
raise TypeError("Can only dump BaseEntities, but got {}".format(type(obj)))
156156

157157
set_uuids(obj)
158158
res = deepcopy(obj)
@@ -208,7 +208,7 @@ def _loado(d, index):
208208
obj = LinkByUID.from_dict(d)
209209
return obj
210210
else:
211-
raise ValueError("Unexpected base object type: {}".format(typ))
211+
raise TypeError("Unexpected base object type: {}".format(typ))
212212

213213
if isinstance(obj, BaseEntity):
214214
for (scope, id) in obj.uids.items():

taurus/client/tests/test_json.py

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
"""Test serialization and deserialization of taurus objects."""
2-
from taurus.client.json_encoder import dumps, loads
2+
import json
3+
import pytest
4+
5+
from taurus.client.json_encoder import dumps, loads, copy, thin_dumps
6+
from taurus.entity.dict_serializable import DictSerializable
37
from taurus.entity.case_insensitive_dict import CaseInsensitiveDict
48
from taurus.entity.attribute.condition import Condition
59
from taurus.entity.attribute.parameter import Parameter
610
from taurus.entity.link_by_uid import LinkByUID
7-
from taurus.entity.object import MeasurementRun, MaterialRun, ProcessRun
11+
from taurus.entity.object import MeasurementRun, MaterialRun, ProcessRun, MeasurementSpec
812
from taurus.entity.object.ingredient_run import IngredientRun
913
from taurus.entity.object.ingredient_spec import IngredientSpec
1014
from taurus.entity.value.nominal_real import NominalReal
1115
from taurus.entity.value.normal_real import NormalReal
12-
13-
import json
16+
from taurus.enumeration.origin import Origin
1417

1518

1619
def test_serialize():
@@ -43,10 +46,33 @@ def test_deserialize():
4346
parameter = Parameter(name="A parameter", value=NormalReal(mean=17, std=1, units=''))
4447
measurement = MeasurementRun(tags="A tag on a measurement", conditions=condition,
4548
parameters=parameter)
46-
copy = loads(dumps(measurement))
47-
assert(copy.conditions[0].value == measurement.conditions[0].value)
48-
assert(copy.parameters[0].value == measurement.parameters[0].value)
49-
assert(copy.uids["auto"] == measurement.uids["auto"])
49+
copy_meas = copy(measurement)
50+
assert(copy_meas.conditions[0].value == measurement.conditions[0].value)
51+
assert(copy_meas.parameters[0].value == measurement.parameters[0].value)
52+
assert(copy_meas.uids["auto"] == measurement.uids["auto"])
53+
54+
55+
def test_enumeration_serde():
56+
"""An enumeration should get serialized as a string."""
57+
condition = Condition(name="A condition", notes=Origin.UNKNOWN)
58+
copy_condition = copy(condition)
59+
assert copy_condition.notes == Origin.get_value(condition.notes)
60+
61+
62+
def test_thin_dumps():
63+
"""Test that thin_dumps turns pointers into links and doesn't work on non-BaseEntity."""
64+
mat = MaterialRun("The actual material")
65+
meas_spec = MeasurementSpec("measurement", uids={'my_scope': '324324'})
66+
meas = MeasurementRun("The measurement", spec=meas_spec, material=mat)
67+
68+
thin_copy = MeasurementRun.build(json.loads(thin_dumps(meas)))
69+
assert isinstance(thin_copy, MeasurementRun)
70+
assert isinstance(thin_copy.material, LinkByUID)
71+
assert isinstance(thin_copy.spec, LinkByUID)
72+
assert thin_copy.spec.id == meas_spec.uids['my_scope']
73+
74+
with pytest.raises(TypeError):
75+
thin_dumps(LinkByUID('scope', 'id'))
5076

5177

5278
def test_uid_deser():
@@ -59,6 +85,40 @@ def test_uid_deser():
5985
assert ingredient_copy.material.uids['sample id'] == material.uids['Sample ID']
6086

6187

88+
def test_dict_serialization():
89+
"""Test that a dictionary can be serialized and then deserialized as a taurus object."""
90+
process = ProcessRun("A process")
91+
mat = MaterialRun("A material", process=process)
92+
meas = MeasurementRun("A measurement", material=mat)
93+
copy = loads(dumps(meas.as_dict()))
94+
assert copy == meas
95+
96+
97+
def test_unexpected_serialization():
98+
"""Trying to serialize an unexpected class should throw a TypeError."""
99+
class DummyClass:
100+
def __init__(self, foo):
101+
self.foo = foo
102+
103+
with pytest.raises(TypeError):
104+
dumps(ProcessRun("A process", notes=DummyClass("something")))
105+
106+
107+
def test_unexpected_deserialization():
108+
"""Trying to deserialize an unexpected class should throw a TypeError."""
109+
class DummyClass(DictSerializable):
110+
typ = 'dummy_class'
111+
112+
def __init__(self, foo):
113+
self.foo = foo
114+
115+
# DummyClass can be serialized because it is a DictSerializable, but cannot be
116+
# deserialized because it is not in the _clazzes list.
117+
serialized = dumps(ProcessRun("A process", notes=DummyClass("something")))
118+
with pytest.raises(TypeError):
119+
loads(serialized)
120+
121+
62122
def test_case_insensitive_rehydration():
63123
"""
64124

taurus/demo/cake.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Bake a cake."""
22
import json
33

4-
from taurus.client.json_encoder import thin_dumps, dumps
4+
from taurus.client.json_encoder import thin_dumps
55
from taurus.entity.attribute.condition import Condition
66
from taurus.entity.attribute.parameter import Parameter
77
from taurus.entity.attribute.property import Property
@@ -27,6 +27,7 @@
2727
from taurus.entity.value.normal_real import NormalReal
2828
from taurus.enumeration.origin import Origin
2929
from taurus.util.impl import set_uuids
30+
from taurus.entity.util import complete_material_history
3031

3132

3233
def make_cake():
@@ -228,6 +229,11 @@ def make_cake():
228229

229230
if __name__ == "__main__":
230231
cake = make_cake()
232+
set_uuids(cake)
233+
234+
with open("example_taurus_material_history.json", "w") as f:
235+
context_list = complete_material_history(cake)
236+
f.write(json.dumps(context_list, indent=2))
231237

232238
with open("example_taurus_material_template.json", "w") as f:
233239
f.write(thin_dumps(cake.template, indent=2))
@@ -261,7 +267,3 @@ def make_cake():
261267

262268
with open("example_taurus_measurement_run.json", "w") as f:
263269
f.write(thin_dumps(cake.measurements[0], indent=2))
264-
265-
with open("example_taurus_material_history.json", "w") as f:
266-
context = json.loads(dumps(cake))[0]
267-
f.write(json.dumps(context, indent=2))

taurus/entity/attribute/base_attribute.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ class BaseAttribute(DictSerializable):
3131
3232
"""
3333

34-
attribute_type = None
35-
3634
def __init__(self, name=None, template=None, origin="unknown", value=None, notes=None,
3735
file_links=None):
3836
if name is None:
@@ -62,7 +60,7 @@ def value(self, value):
6260
elif isinstance(value, (BaseValue, str, bool)):
6361
self._value = value
6462
else:
65-
raise ValueError("value must be a BaseValue, string or bool")
63+
raise TypeError("value must be a BaseValue, string or bool: {}".format(value))
6664

6765
@property
6866
def template(self):
@@ -76,7 +74,8 @@ def template(self, template):
7674
elif isinstance(template, (LinkByUID, AttributeTemplate)):
7775
self._template = template
7876
else:
79-
raise ValueError("template must be a BaseAttributeTemplate or LinkByUID")
77+
raise TypeError("template must be a BaseAttributeTemplate or "
78+
"LinkByUID: {}".format(template))
8079

8180
@property
8281
def origin(self):

taurus/entity/attribute/condition.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from taurus.entity.attribute.base_attribute import BaseAttribute
2-
from taurus.enumeration import AttributeType
32

43

54
class Condition(BaseAttribute):
@@ -12,4 +11,3 @@ class Condition(BaseAttribute):
1211
"""
1312

1413
typ = "condition"
15-
attribute_type = AttributeType.CONDITION

taurus/entity/attribute/metadata.py

Lines changed: 0 additions & 16 deletions
This file was deleted.

taurus/entity/attribute/parameter.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from taurus.entity.attribute.base_attribute import BaseAttribute
2-
from taurus.enumeration import AttributeType
32

43

54
class Parameter(BaseAttribute):
@@ -13,4 +12,3 @@ class Parameter(BaseAttribute):
1312
"""
1413

1514
typ = "parameter"
16-
attribute_type = AttributeType.PARAMETER

0 commit comments

Comments
 (0)