ae03ef42db7c0349eff35ea3d627f0873b4a8489
[arvados.git] / sdk / python / arvados / vocabulary.py
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: Apache-2.0
4
5 import logging
6
7 from . import api
8
9 _logger = logging.getLogger('arvados.vocabulary')
10
11 def load_vocabulary(api_client=None):
12     """Load the Arvados vocabulary from the API.
13     """
14     if api_client is None:
15         api_client = api('v1')
16     return Vocabulary(api_client.vocabulary())
17
18 class Vocabulary(object):
19     def __init__(self, voc_definition={}):
20         self.strict_keys = voc_definition.get('strict_tags', False)
21         self.key_aliases = {}
22
23         for key_id, val in voc_definition.get('tags', {}).items():
24             strict = val.get('strict', False)
25             key_labels = [l['label'] for l in val.get('labels', [])]
26             values = {}
27             for v_id, v_val in val.get('values', {}).items():
28                 labels = [l['label'] for l in v_val.get('labels', [])]
29                 values[v_id] = VocabularyValue(v_id, labels)
30             vk = VocabularyKey(key_id, key_labels, values, strict)
31             self.key_aliases[key_id.lower()] = vk
32             for alias in vk.aliases:
33                 self.key_aliases[alias.lower()] = vk
34
35     def __getitem__(self, key):
36         return self.key_aliases[key.lower()]
37
38     def convert_to_identifiers(self, obj={}):
39         """Translate key/value pairs to machine readable identifiers.
40         """
41         return self._convert_to_what(obj, 'identifier')
42
43     def convert_to_labels(self, obj={}):
44         """Translate key/value pairs to human readable labels.
45         """
46         return self._convert_to_what(obj, 'preferred_label')
47
48     def _convert_to_what(self, obj={}, what=None):
49         if not isinstance(obj, dict):
50             raise ValueError("obj must be a dict")
51         if what not in ['preferred_label', 'identifier']:
52             raise ValueError("what attr must be 'preferred_label' or 'identifier'")
53         r = {}
54         for k, v in obj.items():
55             k_what, v_what = k, v
56             try:
57                 k_what = getattr(self[k], what)
58                 if isinstance(v, list):
59                     v_what = []
60                     for x in v:
61                         try:
62                             v_what.append(getattr(self[k][x], what))
63                         except KeyError:
64                             if self[k].strict:
65                                 raise ValueError("value '%s' not found for key '%s'" % (x, k))
66                             v_what.append(x)
67                 else:
68                     try:
69                         v_what = getattr(self[k][v], what)
70                     except KeyError:
71                         if self[k].strict:
72                             raise ValueError("value '%s' not found for key '%s'" % (v, k))
73             except KeyError:
74                 if self.strict_keys:
75                     raise KeyError("key '%s' not found" % k)
76             r[k_what] = v_what
77         return r
78
79 class VocabularyData(object):
80     def __init__(self, identifier, aliases=[]):
81         self.identifier = identifier
82         self.aliases = aliases
83
84     def __getattribute__(self, name):
85         if name == 'preferred_label':
86             return self.aliases[0]
87         return super(VocabularyData, self).__getattribute__(name)
88
89 class VocabularyValue(VocabularyData):
90     def __init__(self, identifier, aliases=[]):
91         super(VocabularyValue, self).__init__(identifier, aliases)
92
93 class VocabularyKey(VocabularyData):
94     def __init__(self, identifier, aliases=[], values={}, strict=False):
95         super(VocabularyKey, self).__init__(identifier, aliases)
96         self.strict = strict
97         self.value_aliases = {}
98         for v_id, v_val in values.items():
99             self.value_aliases[v_id.lower()] = v_val
100             for v_alias in v_val.aliases:
101                 self.value_aliases[v_alias.lower()] = v_val
102
103     def __getitem__(self, key):
104         return self.value_aliases[key.lower()]