From 12be781965af5b59b9f74344999c1050d91ad0c6 Mon Sep 17 00:00:00 2001 From: tcezard Date: Fri, 15 Dec 2017 16:55:49 +0000 Subject: [PATCH 1/3] Fix the Action to use ProtocolStep instead of Step --- pyclarity_lims/descriptors.py | 18 +++++++------ tests/test_descriptors.py | 50 +++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/pyclarity_lims/descriptors.py b/pyclarity_lims/descriptors.py index aad4a8e2..f0c546bd 100644 --- a/pyclarity_lims/descriptors.py +++ b/pyclarity_lims/descriptors.py @@ -272,23 +272,25 @@ class XmlAction(XmlElementAttributeDict): rework-step: The step associated with this action when the Artifact need to be requeued """ def _parse_element(self, element, **kwargs): - from pyclarity_lims.entities import Artifact, Step + from pyclarity_lims.entities import Artifact, ProtocolStep for k, v in element.attrib.items(): + if k == 'artifact-uri': k = 'artifact' v = Artifact(self.instance.lims, uri=v) - elif k == 'step-uri': - k = 'step' - v = Step(self.instance.lims, uri=v) - elif k == 'rework-step-uri': - k = 'rework-step' - v = Step(self.instance.lims, uri=v) + elif k in ('step-uri', 'rework-step-uri'): + k = k[:-(len('-uri'))] + v = ProtocolStep(self.instance.lims, uri=v) dict.__setitem__(self, k, v) def _setitem(self, key, value): if key in ['artifact', 'step', 'rework-step']: - key = key + '-uri' + key += '-uri' value = value.uri + elif key in ['action']: + pass + else: + raise KeyError('%s Is not a supported key for next action' % key) self._elems[0].attrib[key] = value def _delitem(self, key): diff --git a/tests/test_descriptors.py b/tests/test_descriptors.py index 147b081d..7cfea0a6 100644 --- a/tests/test_descriptors.py +++ b/tests/test_descriptors.py @@ -9,10 +9,10 @@ from pyclarity_lims.descriptors import StringDescriptor, StringAttributeDescriptor, StringListDescriptor, \ StringDictionaryDescriptor, IntegerDescriptor, BooleanDescriptor, UdfDictionary, EntityDescriptor, \ InputOutputMapList, EntityListDescriptor, PlacementDictionary, EntityList, SubTagDictionary, ExternalidList,\ - XmlElementAttributeDict, XmlAttributeList, XmlReagentLabelList, XmlPooledInputDict -from pyclarity_lims.entities import Artifact + XmlElementAttributeDict, XmlAttributeList, XmlReagentLabelList, XmlPooledInputDict, XmlAction +from pyclarity_lims.entities import Artifact, ProtocolStep from pyclarity_lims.lims import Lims -from tests import elements_equal +from tests import elements_equal if version_info[0] == 2: from mock import Mock @@ -94,7 +94,7 @@ def setUp(self): def test__get__(self): bd = self._make_desc(BooleanDescriptor, 'istest') - assert bd.__get__(self.instance, None) == True + assert bd.__get__(self.instance, None) def test__set__(self): bd = self._make_desc(BooleanDescriptor, 'istest') @@ -246,6 +246,7 @@ def test__set__(self): assert isinstance(res, dict) assert res['mykey1'] == 'myvalue1' + class TestUdfDictionary(TestCase): def setUp(self): et = ElementTree.fromstring(""" @@ -345,8 +346,7 @@ def test___delitem__(self): del self.dict1['test'] with pytest.raises(KeyError): self.dict1['test'] - assert self._get_udf_value(self.dict1, 'test') == None - + assert self._get_udf_value(self.dict1, 'test') is None def test_items(self): pass @@ -500,6 +500,7 @@ def test___setitem__(self): assert len(self.dict1) == 3 assert len(self.dict1.rootnode(self.dict1.instance)) == 3 + class TestEntityList(TestCase): def setUp(self): @@ -600,7 +601,6 @@ def test___get__(self): assert sorted(res[0][1].keys()) == sorted(expected_keys_ouput) - class TestExternalidList(TestCase): def setUp(self): @@ -648,7 +648,7 @@ def setUp(self): def test_get(self): al = XmlAttributeList(self.instance1, tag='test-tag', nesting=['test-tags']) assert al[0] == {'attrib1': 'value1', 'attrib2':'value2'} - assert al[1] == {'attrib1': 'value11', 'attrib2':'value12', 'attrib3':'value13'} + assert al[1] == {'attrib1': 'value11', 'attrib2': 'value12', 'attrib3':'value13'} def test_append(self): el = XmlAttributeList(self.instance1, tag='test-tag', nesting=['test-tags']) @@ -694,3 +694,37 @@ def test_append(self): rl.instance.root.findall('reagent-label')[1], ElementTree.fromstring('''''') ) + + +class TestXmlAction(TestCase): + + def setUp(self): + et = ElementTree.fromstring(''' + + + '''.format(url='http://testgenologics.com:4040')) + + et1 = ElementTree.fromstring(''' + + + '''.format(url='http://testgenologics.com:4040')) + + self.lims = Lims('http://testgenologics.com:4040', username='test', password='password') + self.instance1 = Mock(root=et, lims=self.lims) + self.instance_empty = Mock(root=et1, lims=self.lims) + + def test_parse(self): + action = XmlAction(self.instance1, tag='next-action') + assert action['action'] == 'nextstep' + assert action['step'] == ProtocolStep(self.lims, uri='http://testgenologics.com:4040/prt/1/stp/1') + assert action['artifact'] == Artifact(self.lims, uri='http://testgenologics.com:4040/arts/a1') + + def test_set(self): + action = XmlAction(self.instance_empty, tag='next-action') + action['step'] = ProtocolStep(self.lims, uri='http://testgenologics.com:4040/prt/1/stp/1') + assert action.instance.root.find('next-action').attrib['step-uri'] == 'http://testgenologics.com:4040/prt/1/stp/1' + action['action'] = 'nextstep' + assert action.instance.root.find('next-action').attrib['action'] == 'nextstep' + + with pytest.raises(KeyError): + action['whatever'] = 'youwant' From 8cd1bca255169648e453dd18d412556128b2b426 Mon Sep 17 00:00:00 2001 From: tcezard Date: Fri, 15 Dec 2017 16:59:51 +0000 Subject: [PATCH 2/3] Check the type of the value before setting it --- pyclarity_lims/descriptors.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyclarity_lims/descriptors.py b/pyclarity_lims/descriptors.py index f0c546bd..fa9913f5 100644 --- a/pyclarity_lims/descriptors.py +++ b/pyclarity_lims/descriptors.py @@ -284,7 +284,9 @@ def _parse_element(self, element, **kwargs): dict.__setitem__(self, k, v) def _setitem(self, key, value): - if key in ['artifact', 'step', 'rework-step']: + from pyclarity_lims.entities import Artifact, ProtocolStep + if (key in ['artifact'] and isinstance(value, Artifact)) or \ + (key in ['step', 'rework-step'] and isinstance(value, ProtocolStep)): key += '-uri' value = value.uri elif key in ['action']: From c50857d5909a9106f82370e9b629000057c82e19 Mon Sep 17 00:00:00 2001 From: tcezard Date: Fri, 15 Dec 2017 20:54:59 +0000 Subject: [PATCH 3/3] Add documentation --- pyclarity_lims/descriptors.py | 1 + pyclarity_lims/entities.py | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pyclarity_lims/descriptors.py b/pyclarity_lims/descriptors.py index fa9913f5..b8a2502c 100644 --- a/pyclarity_lims/descriptors.py +++ b/pyclarity_lims/descriptors.py @@ -270,6 +270,7 @@ class XmlAction(XmlElementAttributeDict): artifact: The Artifact associated with this Action step: The next step associated with this action rework-step: The step associated with this action when the Artifact need to be requeued + action: The type of action to perform. (leave, repeat, remove, review, complete, store, nextstep, rework, completerepeat, unknown) """ def _parse_element(self, element, **kwargs): from pyclarity_lims.entities import Artifact, ProtocolStep diff --git a/pyclarity_lims/entities.py b/pyclarity_lims/entities.py index 4dd35fa5..0bc1af84 100644 --- a/pyclarity_lims/entities.py +++ b/pyclarity_lims/entities.py @@ -655,19 +655,32 @@ def get_selected_containers(self): class StepActions(Entity): - """Actions associated with a step""" + """Actions associated with the end of the step""" _escalation = None next_actions = MutableDescriptor(XmlActionList) """ List of dict that representing an action for an artifact. They keys of the dict are: - artifact: The :py:class:`artifact ` associated with this Action - step: The next :py:class:`step ` associated with this action - - rework-step: The :py:class:`step ` associated with this action when the Artifact need to be requeued""" + - rework-step: The :py:class:`step ` associated with this action when the Artifact need to be requeued + - action: The type of action to perform. + - leave: Leave the sample in the QC protocol. + - repeat: Repeat this step. + - remove: Remove from workflow. + - review: Request manager review. + - complete: Mark protocol as complete. + - store: Store for later. + - nextstep: Continue to the next step. + - rework: Rework from an earlier step. + - completerepeat: Complete and Repeat + - unknown: The action is unknown. + """ step = None # See bottom of the file """:py:class:`Step ` associated with the actions.""" @property def escalation(self): + # TODO: Convert to using descriptor and document if not self._escalation: self.get() self._escalation = {}