[ARVADOS] updated: 2.1.0-1986-ga617106e4

Git user git at public.arvados.org
Thu Mar 3 14:06:56 UTC 2022


Summary of changes:
 doc/sdk/python/cookbook.html.textile.liquid | 36 +++++++++++---------
 sdk/python/arvados/vocabulary.py            | 53 +++++++++++++++++++++--------
 sdk/python/tests/test_vocabulary.py         | 28 +++++++++++----
 3 files changed, 80 insertions(+), 37 deletions(-)

       via  a617106e4baa22910292a47a1cab38b7cb7ea739 (commit)
       via  0ee9c8367c4f9545e69941058022d0092e3d4585 (commit)
      from  b6ffac07e22120b0d15d2d16fd13e2899192084b (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit a617106e4baa22910292a47a1cab38b7cb7ea739
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Thu Mar 3 11:06:13 2022 -0300

    18574: Adds key & value type checking. Improves code layout for readability.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>

diff --git a/sdk/python/arvados/vocabulary.py b/sdk/python/arvados/vocabulary.py
index 89698e20a..3bb87c48d 100644
--- a/sdk/python/arvados/vocabulary.py
+++ b/sdk/python/arvados/vocabulary.py
@@ -15,6 +15,17 @@ def load_vocabulary(api_client=None):
         api_client = api('v1')
     return Vocabulary(api_client.vocabulary())
 
+class VocabularyError(Exception):
+    """Base class for all vocabulary errors.
+    """
+    pass
+
+class VocabularyKeyError(VocabularyError):
+    pass
+
+class VocabularyValueError(VocabularyError):
+    pass
+
 class Vocabulary(object):
     def __init__(self, voc_definition={}):
         self.strict_keys = voc_definition.get('strict_tags', False)
@@ -52,27 +63,39 @@ class Vocabulary(object):
             raise ValueError("what attr must be 'preferred_label' or 'identifier'")
         r = {}
         for k, v in obj.items():
+            # Key validation & lookup
+            key_found = False
+            if not isinstance(k, str):
+                raise VocabularyKeyError("key '{}' must be a string".format(k))
             k_what, v_what = k, v
             try:
                 k_what = getattr(self[k], what)
-                if isinstance(v, list):
-                    v_what = []
-                    for x in v:
-                        try:
-                            v_what.append(getattr(self[k][x], what))
-                        except KeyError:
-                            if self[k].strict:
-                                raise ValueError("value '%s' not found for key '%s'" % (x, k))
-                            v_what.append(x)
-                else:
+                key_found = True
+            except KeyError:
+                if self.strict_keys:
+                    raise VocabularyKeyError("key '{}' not found in vocabulary".format(k))
+
+            # Value validation & lookup
+            if isinstance(v, list):
+                v_what = []
+                for x in v:
+                    if not isinstance(x, str):
+                        raise VocabularyValueError("value '{}' for key '{}' must be a string".format(x, k))
                     try:
-                        v_what = getattr(self[k][v], what)
+                        v_what.append(getattr(self[k][x], what))
                     except KeyError:
                         if self[k].strict:
-                            raise ValueError("value '%s' not found for key '%s'" % (v, k))
-            except KeyError:
-                if self.strict_keys:
-                    raise KeyError("key '%s' not found" % k)
+                            raise VocabularyValueError("value '{}' not found for key '{}'".format(x, k))
+                        v_what.append(x)
+            else:
+                if not isinstance(v, str):
+                    raise VocabularyValueError("{} value '{}' for key '{}' must be a string".format(type(v).__name__, v, k))
+                try:
+                    v_what = getattr(self[k][v], what)
+                except KeyError:
+                    if key_found and self[k].strict:
+                        raise VocabularyValueError("value '{}' not found for key '{}'".format(v, k))
+
             r[k_what] = v_what
         return r
 
diff --git a/sdk/python/tests/test_vocabulary.py b/sdk/python/tests/test_vocabulary.py
index cce2ec623..1d3d7b627 100644
--- a/sdk/python/tests/test_vocabulary.py
+++ b/sdk/python/tests/test_vocabulary.py
@@ -169,18 +169,26 @@ class VocabularyTest(unittest.TestCase):
         # Strict vocabulary
         strict_voc = arvados.vocabulary.Vocabulary(self.EXAMPLE_VOC)
         strict_voc.strict_keys = True
-        with self.assertRaises(KeyError):
+        with self.assertRaises(vocabulary.VocabularyKeyError):
             strict_voc.convert_to_identifiers({'foo': 'bar'})
 
+    def test_convert_to_identifiers_invalid_key(self):
+        with self.assertRaises(vocabulary.VocabularyKeyError):
+            self.voc.convert_to_identifiers({('f', 'o', 'o'): 'bar'})
+
     def test_convert_to_identifiers_unknown_value(self):
         # Non-strict key
         self.assertEqual(self.voc['animal'].strict, False)
         self.assertEqual(self.voc.convert_to_identifiers({'Animal': 'foo'}), {'IDTAGANIMALS': 'foo'})
         # Strict key
         self.assertEqual(self.voc['priority'].strict, True)
-        with self.assertRaises(ValueError):
+        with self.assertRaises(vocabulary.VocabularyValueError):
             self.voc.convert_to_identifiers({'Priority': 'foo'})
 
+    def test_convert_to_identifiers_invalid_value(self):
+        with self.assertRaises(vocabulary.VocabularyValueError):
+            self.voc.convert_to_identifiers({'Animal': 42})
+
     def test_convert_to_identifiers_unknown_value_list(self):
         # Non-strict key
         self.assertEqual(self.voc['animal'].strict, False)
@@ -190,7 +198,7 @@ class VocabularyTest(unittest.TestCase):
         )
         # Strict key
         self.assertEqual(self.voc['priority'].strict, True)
-        with self.assertRaises(ValueError):
+        with self.assertRaises(vocabulary.VocabularyValueError):
             self.voc.convert_to_identifiers({'Priority': ['foo', 'bar']})
 
     def test_convert_to_labels(self):
@@ -242,18 +250,26 @@ class VocabularyTest(unittest.TestCase):
         # Strict vocabulary
         strict_voc = arvados.vocabulary.Vocabulary(self.EXAMPLE_VOC)
         strict_voc.strict_keys = True
-        with self.assertRaises(KeyError):
+        with self.assertRaises(vocabulary.VocabularyKeyError):
             strict_voc.convert_to_labels({'foo': 'bar'})
 
+    def test_convert_to_labels_invalid_key(self):
+        with self.assertRaises(vocabulary.VocabularyKeyError):
+            self.voc.convert_to_labels({42: 'bar'})
+
     def test_convert_to_labels_unknown_value(self):
         # Non-strict key
         self.assertEqual(self.voc['animal'].strict, False)
         self.assertEqual(self.voc.convert_to_labels({'IDTAGANIMALS': 'foo'}), {'Animal': 'foo'})
         # Strict key
         self.assertEqual(self.voc['priority'].strict, True)
-        with self.assertRaises(ValueError):
+        with self.assertRaises(vocabulary.VocabularyValueError):
             self.voc.convert_to_labels({'IDTAGIMPORTANCES': 'foo'})
 
+    def test_convert_to_labels_invalid_value(self):
+        with self.assertRaises(vocabulary.VocabularyValueError):
+            self.voc.convert_to_labels({'IDTAGIMPORTANCES': {'high': True}})
+
     def test_convert_to_labels_unknown_value_list(self):
         # Non-strict key
         self.assertEqual(self.voc['animal'].strict, False)
@@ -263,7 +279,7 @@ class VocabularyTest(unittest.TestCase):
         )
         # Strict key
         self.assertEqual(self.voc['priority'].strict, True)
-        with self.assertRaises(ValueError):
+        with self.assertRaises(vocabulary.VocabularyValueError):
             self.voc.convert_to_labels({'IDTAGIMPORTANCES': ['foo', 'bar']})
 
     def test_convert_roundtrip(self):

commit 0ee9c8367c4f9545e69941058022d0092e3d4585
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Wed Mar 2 18:44:34 2022 -0300

    18574: Fixes documentation formatting.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>

diff --git a/doc/sdk/python/cookbook.html.textile.liquid b/doc/sdk/python/cookbook.html.textile.liquid
index cce25f1a3..f3186ebbb 100644
--- a/doc/sdk/python/cookbook.html.textile.liquid
+++ b/doc/sdk/python/cookbook.html.textile.liquid
@@ -304,18 +304,19 @@ h2. Querying the vocabulary definition
 The Python SDK provides facilities to interact with the "active metadata vocabulary":{{ site.baseurl }}/admin/metadata-vocabulary.html in the system. The developer can do key and value lookups in a case-insensitive manner:
 
 {% codeblock as python %}
->>> from arvados import api, vocabulary
->>> voc = vocabulary.load_vocabulary(api('v1'))
->>> [k.identifier for k in set(voc.key_aliases.values())]
-['IDTAGCOLORS', 'IDTAGFRUITS', 'IDTAGCOMMENT', 'IDTAGIMPORTANCES', 'IDTAGCATEGORIES', 'IDTAGSIZES', 'IDTAGANIMALS']
->>> voc['IDTAGSIZES'].preferred_label
-'Size'
->>> [v.preferred_label for v in set(voc['size'].value_aliases.values())]
-['S', 'M', 'L', 'XL', 'XS']
->>> voc['size']['s'].aliases
-['S', 'small']
->>> voc['size']['Small'].identifier
-'IDVALSIZES2'
+from arvados import api, vocabulary
+voc = vocabulary.load_vocabulary(api('v1'))
+
+[k.identifier for k in set(voc.key_aliases.values())]
+# Example output: ['IDTAGCOLORS', 'IDTAGFRUITS', 'IDTAGCOMMENT', 'IDTAGIMPORTANCES', 'IDTAGCATEGORIES', 'IDTAGSIZES', 'IDTAGANIMALS']
+voc['IDTAGSIZES'].preferred_label
+# Example output: 'Size'
+[v.preferred_label for v in set(voc['size'].value_aliases.values())]
+# Example output: ['S', 'M', 'L', 'XL', 'XS']
+voc['size']['s'].aliases
+# Example output: ['S', 'small']
+voc['size']['Small'].identifier
+# Example output: 'IDVALSIZES2'
 {% endcodeblock %}
 
 h2. Translating between vocabulary identifiers and labels
@@ -323,8 +324,11 @@ h2. Translating between vocabulary identifiers and labels
 Client software might need to present properties to the user in a human-readable form or take input from the user without requiring them to remember identifiers. For these cases, there're a couple of conversion methods that take a dictionary as input like this:
 
 {% codeblock as python %}
->>> voc.convert_to_labels({'IDTAGIMPORTANCES': 'IDVALIMPORTANCES1'})
-{'Importance': 'Critical'}
->>> voc.convert_to_identifiers({'creature': 'elephant'})
-{'IDTAGANIMALS': 'IDVALANIMALS3'}
+from arvados import api, vocabulary
+voc = vocabulary.load_vocabulary(api('v1'))
+
+voc.convert_to_labels({'IDTAGIMPORTANCES': 'IDVALIMPORTANCES1'})
+# Example output: {'Importance': 'Critical'}
+voc.convert_to_identifiers({'creature': 'elephant'})
+# Example output: {'IDTAGANIMALS': 'IDVALANIMALS3'}
 {% endcodeblock %}
\ No newline at end of file

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list