[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