labfreed 1.0.0a24__py3-none-any.whl → 1.0.0b26__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. labfreed/__init__.py +1 -1
  2. labfreed/labfreed_extended/app/app_infrastructure.py +2 -5
  3. labfreed/labfreed_extended/app/pac_info/pac_info.py +6 -8
  4. labfreed/labfreed_extended/pac_issuer_lib/lib/attribute.py +9 -6
  5. labfreed/labfreed_extended/pac_issuer_lib/static/external-link.svg +6 -6
  6. labfreed/labfreed_extended/pac_issuer_lib/static/logo.svg +44 -44
  7. labfreed/labfreed_extended/pac_issuer_lib/templates/main.jinja.html +4 -3
  8. labfreed/pac_attributes/api_data_models/request.py +78 -30
  9. labfreed/pac_attributes/api_data_models/response.py +107 -136
  10. labfreed/pac_attributes/client/client.py +30 -36
  11. labfreed/pac_attributes/client/client_attribute_group.py +18 -0
  12. labfreed/pac_attributes/pythonic/attribute_server_factory.py +39 -13
  13. labfreed/pac_attributes/pythonic/excel_attribute_data_source.py +1 -1
  14. labfreed/pac_attributes/pythonic/py_attributes.py +97 -125
  15. labfreed/pac_attributes/server/attribute_data_sources.py +9 -8
  16. labfreed/pac_attributes/server/server.py +33 -37
  17. labfreed/pac_id_resolver/resolver_config.py +2 -1
  18. {labfreed-1.0.0a24.dist-info → labfreed-1.0.0b26.dist-info}/METADATA +1 -1
  19. {labfreed-1.0.0a24.dist-info → labfreed-1.0.0b26.dist-info}/RECORD +21 -27
  20. labfreed/labfreed_extended/app/pac_info/html_renderer/external-link.svg +0 -7
  21. labfreed/labfreed_extended/app/pac_info/html_renderer/macros.jinja.html +0 -188
  22. labfreed/labfreed_extended/app/pac_info/html_renderer/pac-info-style.css +0 -176
  23. labfreed/labfreed_extended/app/pac_info/html_renderer/pac_info.jinja.html +0 -46
  24. labfreed/labfreed_extended/app/pac_info/html_renderer/pac_info_card.jinja.html +0 -7
  25. labfreed/pac_attributes/client/__init__.py +0 -0
  26. labfreed/pac_attributes/client/attribute_cache.py +0 -65
  27. {labfreed-1.0.0a24.dist-info → labfreed-1.0.0b26.dist-info}/WHEEL +0 -0
  28. {labfreed-1.0.0a24.dist-info → labfreed-1.0.0b26.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,18 @@
1
1
 
2
2
  from datetime import UTC, date, datetime, time
3
3
  import json
4
+ import logging
4
5
  from typing import Literal
5
6
  from enum import Enum
6
7
  import warnings
7
- from pydantic import RootModel, field_validator
8
+ from pydantic import RootModel, field_validator, model_validator
8
9
 
9
10
  from labfreed.labfreed_infrastructure import LabFREED_BaseModel
10
- from labfreed.pac_attributes.api_data_models.response import AttributeBase, AttributeGroup, BoolAttribute, BoolListAttribute, DateTimeAttribute, DateTimeListAttribute, NumericAttribute, NumericListAttribute, NumericValue, ObjectAttribute,ObjectListAttribute, ReferenceAttribute, ReferenceListAttribute, ResourceAttribute, ResourceListAttribute, TextAttribute, TextListAttribute
11
- from labfreed.pac_attributes.client.attribute_cache import CacheableAttributeGroup
11
+ from labfreed.pac_attributes.api_data_models.response import (Attribute, AttributeItemsElementBase, AttributeGroup,
12
+ BoolAttributeItemsElement, DateTimeAttributeItemsElement, NumericAttributeItemsElement,
13
+ ObjectAttributeItemsElement, ReferenceAttributeItemsElement, ResourceAttributeItemsElement,
14
+ TextAttributeItemsElement)
15
+ from labfreed.pac_attributes.client.client_attribute_group import ClientAttributeGroup
12
16
  from labfreed.pac_id.pac_id import PAC_ID
13
17
  from labfreed.trex.pythonic.quantity import Quantity
14
18
 
@@ -33,15 +37,21 @@ AllowedList = list[AllowedValue]
33
37
  class pyAttribute(LabFREED_BaseModel):
34
38
  key:str
35
39
  label:str = ""
36
- value: AllowedValue | AllowedList
40
+ values: AllowedValue | AllowedList
37
41
 
38
42
  @property
39
43
  def value_list(self):
40
44
  '''helper function to more conveniently iterate over value elements, even if it's scalar'''
41
- return self.value if isinstance(self.value, list) else [self.value]
45
+ return self.values if isinstance(self.values, list) else [self.values]
42
46
 
47
+ @model_validator(mode='before')
48
+ def value_to_values(cls, d:dict):
49
+ value =d.pop('value', None)
50
+ if value is not None:
51
+ d['values'] = value
52
+ return d
43
53
 
44
- @field_validator('value', mode='before')
54
+ @field_validator('values', mode='before')
45
55
  def handle_one_element_list(v):
46
56
  if isinstance(v, list) and len(v)==1:
47
57
  return v[0]
@@ -58,147 +68,109 @@ class pyAttribute(LabFREED_BaseModel):
58
68
 
59
69
 
60
70
  class pyAttributes(RootModel[list[pyAttribute]]):
61
- def to_payload_attributes(self) -> list[AttributeBase]:
62
- out = []
71
+ def to_payload_attributes(self) -> dict[str, Attribute]:
72
+ out = {}
63
73
  for e in self.root:
64
- apt = self._attribute_to_attribute_payload_type(e)
65
- if isinstance(apt.value, list) and len(apt.value) ==1:
66
- apt.value = apt.value[0]
67
- out.append(apt)
74
+ payload_attr = self._attribute_to_attribute_payload_type(e)
75
+ out.update({e.key: payload_attr})
68
76
  return out
69
77
 
70
78
 
71
79
  @staticmethod
72
- def _attribute_to_attribute_payload_type(attribute:pyAttribute) -> AttributeBase:
73
- common_args = {
74
- "key": attribute.key,
75
- "label": attribute.label,
76
- }
77
- value_list = attribute.value_list
78
- first_value = value_list[0]
79
- if isinstance(first_value, bool):
80
- if len(value_list) == 1:
81
- return BoolAttribute(value=value_list[0], **common_args)
82
- else:
83
- return BoolListAttribute(value=value_list, **common_args)
84
-
80
+ def _attribute_to_attribute_payload_type(attribute:pyAttribute) -> AttributeItemsElementBase:
81
+ items = []
82
+ for value in attribute.value_list:
85
83
 
86
- elif isinstance(first_value, datetime | date | time):
87
- for v in value_list:
88
- if not v.tzinfo:
89
- warnings.warn(f'No timezone given for {v}. Assuming it is in UTC.')
90
- v.replace(tzinfo=UTC)
91
- if len(value_list) == 1:
92
- return DateTimeAttribute(value=value_list[0], **common_args)
93
- else:
94
- return DateTimeListAttribute(value=value_list, **common_args)
95
- # return DateTimeAttribute(value =_date_value_from_python_type(value).value, **common_args)
96
-
97
-
98
- elif isinstance(first_value, Quantity|int|float):
99
- values = []
100
- for v in value_list:
101
- if not isinstance(v, Quantity):
102
- v = Quantity(value=v, unit='dimensionless')
103
- values.append(NumericValue(numerical_value=v.value_as_str(),
104
- unit = v.unit))
105
- if len(values) == 1:
106
- num_attr = NumericAttribute(value=values[0], **common_args)
107
- else:
108
- num_attr = NumericListAttribute(value=values, **common_args)
109
- num_attr.print_validation_messages()
110
-
111
- return num_attr
112
-
113
- elif isinstance(first_value, str):
114
- # capture quantities in the form of "100.0e5 g/L"
115
- if Quantity.can_convert_to_quantity(first_value):
116
- values = []
117
- for v in value_list:
118
- q = Quantity.from_str_with_unit(v)
119
- values.append( NumericValue(numerical_value=q.value_as_str(), unit = q.unit) )
120
- if len(values) == 1:
121
- return NumericAttribute(value=values[0], **common_args)
84
+ if isinstance(value, bool):
85
+ items.append(BoolAttributeItemsElement(value=value))
86
+
87
+ elif isinstance(value, datetime | date | time):
88
+ if not value.tzinfo:
89
+ warnings.warn(f'No timezone given for {value}. Assuming it is in UTC.')
90
+ value.replace(tzinfo=UTC)
91
+ items.append(DateTimeAttributeItemsElement(value=value))
92
+
93
+ elif isinstance(value, Quantity|int|float):
94
+ if not isinstance(value, Quantity):
95
+ value = Quantity(value=value, unit='dimensionless')
96
+ v = f"{value.value_as_str()} {value.unit}"
97
+ items.append(NumericAttributeItemsElement(value=v))
98
+
99
+ elif isinstance(value, str):
100
+ # capture quantities in the form of "100.0e5 g/L"
101
+ if Quantity.can_convert_to_quantity(value):
102
+ q = Quantity.from_str_with_unit(value)
103
+ v = f"{q.value_as_str()} {q.unit}"
104
+ items.append(NumericAttributeItemsElement(value=v))
122
105
  else:
123
- return NumericListAttribute(value=values, **common_args)
106
+ items.append(TextAttributeItemsElement(value=value))
124
107
 
125
- else:
126
- if len(value_list) == 1:
127
- return TextAttribute(value=value_list[0], **common_args)
128
- else:
129
- return TextListAttribute(value=value_list, **common_args)
130
-
131
- elif isinstance(first_value, pyReference):
132
- values = [v.root for v in value_list]
133
- if len(values) == 1:
134
- return ReferenceAttribute(value=values[0], **common_args)
135
- else:
136
- return ReferenceListAttribute(value=values, **common_args)
137
-
138
- elif isinstance(first_value, pyResource):
139
- values = [v.root for v in value_list]
140
- if len(values) == 1:
141
- return ResourceAttribute(value=values[0], **common_args)
142
- else:
143
- return ResourceListAttribute(value=values, **common_args)
144
-
145
- elif isinstance(first_value, PAC_ID):
146
- values = [v.to_url(include_extensions=False) for v in value_list]
147
- if len(values) == 1:
148
- return ReferenceAttribute(value=values[0], **common_args)
149
- else:
150
- return ReferenceListAttribute(value=values, **common_args)
151
-
152
- else: #this covers the last resort case of arbitrary objects. Must be json serializable.
153
- try :
154
- values = [json.loads(json.dumps(v)) for v in value_list]
155
- if len(values) == 1:
156
- return ObjectAttribute(value=values[0], **common_args)
157
- else:
158
- return ObjectListAttribute(value=values, **common_args)
159
- except TypeError as e: # noqa: F841
160
- raise ValueError(f'Invalid Type: {type(first_value)} cannot be converted to attribute. You may want to use ObjectAttribute, but would have to implement the conversion from your python type yourself.')
108
+ elif isinstance(value, pyReference):
109
+ items.append(ReferenceAttributeItemsElement(value=value.root))
110
+
111
+ elif isinstance(value, pyResource):
112
+ items.append(ResourceAttributeItemsElement(value=value.root))
113
+
114
+ elif isinstance(value, PAC_ID):
115
+ v = value.to_url(include_extensions=False)
116
+ items.append(ReferenceAttributeItemsElement(value=v))
117
+
118
+ else: #this covers the last resort case of arbitrary objects. Must be json serializable.
119
+ try :
120
+ v = json.loads(json.dumps(value))
121
+ items.append(ObjectAttributeItemsElement(value=v))
122
+ except TypeError as e: # noqa: F841
123
+ raise ValueError(f'Invalid Type: {type(value)} cannot be converted to attribute. You may want to use ObjectAttribute, but would have to implement the conversion from your python type yourself.')
161
124
 
125
+
126
+ if not all(type(e) is type(items[0]) for e in items):
127
+ logging.warning("Not all elements in items have the same type. This might cause unexpected behaviour in clients.")
162
128
 
129
+ attr = Attribute(key=attribute.key,
130
+ label= attribute.label,
131
+ items=items)
132
+ return attr
133
+
134
+
163
135
 
164
136
  @staticmethod
165
- def from_payload_attributes(attributes:list[AttributeBase]) -> 'pyAttributes':
137
+ def from_payload_attributes(attributes:dict[str, Attribute]) -> 'pyAttributes':
166
138
  out = list()
167
- for a in attributes:
168
- value_list = a.value if isinstance(a.value, list) else [a.value]
169
- match a:
170
- case ReferenceAttribute() | ReferenceListAttribute():
171
- values = [pyReference(v) for v in value_list]
172
-
173
- case ResourceAttribute() | ResourceListAttribute():
174
- values = [pyResource(v) for v in value_list]
175
-
176
- case NumericAttribute() | NumericListAttribute():
177
- values = [ Quantity.from_str_value(value=v.numerical_value, unit=v.unit) for v in value_list]
139
+ for a in attributes.values():
140
+ values = []
141
+ for v in a.items:
142
+ match v:
143
+ case ReferenceAttributeItemsElement() :
144
+ values.append(pyReference(v.value))
145
+
146
+ case ResourceAttributeItemsElement() :
147
+ values.append(pyResource(v.value))
148
+
149
+ case NumericAttributeItemsElement() :
150
+ values.append(Quantity.from_str_value(value=v._numerical_value, unit=v._unit))
178
151
 
179
- case BoolAttribute() | BoolListAttribute():
180
- values = value_list
152
+ case BoolAttributeItemsElement() :
153
+ values.append(v.value)
154
+
155
+ case TextAttributeItemsElement() :
156
+ values.append(v.value)
157
+
158
+ case DateTimeAttributeItemsElement() :
159
+ values.append(v.value)
181
160
 
182
- case TextAttribute() | TextListAttribute():
183
- values = value_list
184
-
185
- case DateTimeAttribute() | DateTimeListAttribute():
186
- values = value_list
187
-
188
- case ObjectAttribute() | ObjectListAttribute():
189
- values = value_list
190
-
191
-
161
+ case ObjectAttributeItemsElement() :
162
+ values.append(v.value)
163
+
192
164
  attr = pyAttribute(key=a.key,
193
- label=a.label,
194
- value=values
165
+ label=a.label,
166
+ values=values
195
167
  )
196
168
  out.append(attr )
197
169
  return out
198
170
 
199
171
 
200
172
 
201
- class pyAttributeGroup(CacheableAttributeGroup):
173
+ class pyAttributeGroup(ClientAttributeGroup):
202
174
  attributes:dict[str,pyAttribute]
203
175
 
204
176
  @staticmethod
@@ -1,8 +1,6 @@
1
1
  from abc import ABC, abstractmethod, abstractproperty
2
- from datetime import datetime, timezone
3
- from labfreed.pac_attributes.api_data_models.response import AttributeBase, AttributeGroup
2
+ from labfreed.pac_attributes.api_data_models.response import Attribute, AttributeGroup
4
3
  from labfreed.pac_cat.pac_cat import PAC_CAT
5
- from labfreed.pac_id.pac_id import PAC_ID
6
4
 
7
5
 
8
6
  class AttributeGroupDataSource(ABC):
@@ -31,8 +29,8 @@ class AttributeGroupDataSource(ABC):
31
29
 
32
30
 
33
31
  class Dict_DataSource(AttributeGroupDataSource):
34
- def __init__(self, data:dict[str, list[AttributeBase]], uses_pac_cat_short_form=True, pac_to_key: callable = None, *args, **kwargs):
35
- if not all([isinstance(e, list) for e in data.values()]):
32
+ def __init__(self, data:dict[str, dict[str, Attribute]], uses_pac_cat_short_form=True, pac_to_key: callable = None, *args, **kwargs):
33
+ if not all([isinstance(e, dict) for e in data.values()]):
36
34
  raise ValueError('Invalid data')
37
35
 
38
36
  self._data = data
@@ -44,7 +42,7 @@ class Dict_DataSource(AttributeGroupDataSource):
44
42
 
45
43
  @property
46
44
  def provides_attributes(self):
47
- return list(set([a.key for attributes in self._data.values() for a in attributes]))
45
+ return list(set([a.key for attributes in self._data.values() for a in attributes.values()]))
48
46
 
49
47
 
50
48
  def attributes(self, pac_url: str) -> AttributeGroup:
@@ -58,9 +56,12 @@ class Dict_DataSource(AttributeGroupDataSource):
58
56
  lookup_key = self._pac_to_key(pac_url) if self._pac_to_key else pac_url
59
57
  attributes = self._data.get(lookup_key)
60
58
  if not attributes:
61
- return None
59
+ if 'default' in self._data.keys():
60
+ attributes = self._data.get('default', None)
61
+ else:
62
+ return None
62
63
 
63
- return AttributeGroup(key=self._attribute_group_key,
64
+ return AttributeGroup(group_key=self._attribute_group_key,
64
65
  attributes=attributes)
65
66
 
66
67
 
@@ -4,9 +4,10 @@ import traceback
4
4
  import warnings
5
5
 
6
6
  import rich
7
+ from werkzeug.datastructures.accept import LanguageAccept
7
8
 
8
- from labfreed.pac_attributes.api_data_models.request import AttributeRequestPayload
9
- from labfreed.pac_attributes.api_data_models.response import AttributeResponsePayload, AttributesOfPACID, ReferenceAttribute
9
+ from labfreed.pac_attributes.api_data_models.request import AttributeRequestData
10
+ from labfreed.pac_attributes.api_data_models.response import AttributeResponsePayload, AttributesOfPACID, ReferenceAttributeItemsElement
10
11
  from labfreed.pac_attributes.api_data_models.server_capabilities_response import ServerCapabilities
11
12
  from labfreed.pac_attributes.server.attribute_data_sources import AttributeGroupDataSource
12
13
  from labfreed.pac_attributes.server.translation_data_sources import TranslationDataSource
@@ -55,23 +56,25 @@ class AttributeServerRequestHandler():
55
56
 
56
57
 
57
58
 
58
- def handle_attribute_request(self, json_request_body:str) -> str:
59
+ def handle_attribute_request(self, request_data:AttributeRequestData) -> str:
60
+ if not isinstance(request_data, AttributeRequestData):
61
+ raise ValueError('request_data most be of AttributeRequestData')
59
62
  try:
60
- r = AttributeRequestPayload.model_validate_json(json_request_body)
61
- except Exception:
63
+ r = AttributeRequestData.model_validate(request_data)
64
+ except Exception as e:
65
+ print(e)
62
66
  raise InvalidRequestError
63
67
  attributes_for_pac_id = []
64
68
  referenced_pac_ids = set()
65
- for pac_url in r.pac_ids:
66
- attributes_for_pac = self._get_attributes_for_pac_id(pac_url=pac_url,
67
- restrict_to_attribute_groups = r.restrict_to_attribute_groups)
68
- attributes_for_pac_id.append(attributes_for_pac)
69
- ref = self._get_referenced_pac_ids(attributes_for_pac)
70
- if ref:
71
- referenced_pac_ids.update(ref)
69
+ attributes_for_pac = self._get_attributes_for_pac_id(pac_url=r.pac_id,
70
+ restrict_to_attribute_groups = r.restrict_to_attribute_groups)
71
+ attributes_for_pac_id.append(attributes_for_pac)
72
+ ref = self._get_referenced_pac_ids(attributes_for_pac)
73
+ if ref:
74
+ referenced_pac_ids.update(ref)
72
75
 
73
76
  # also find attributes of referenced pac-ids
74
- if not r.suppress_forward_lookup:
77
+ if r.do_forward_lookup:
75
78
  for pac_url in referenced_pac_ids:
76
79
  attributes_for_pac = self._get_attributes_for_pac_id(pac_url=pac_url,
77
80
  restrict_to_attribute_groups = r.restrict_to_attribute_groups)
@@ -82,7 +85,7 @@ class AttributeServerRequestHandler():
82
85
  for e in attributes_for_pac_id:
83
86
  self._add_display_names(e, response_language)
84
87
 
85
- response = AttributeResponsePayload(pac_attributes=attributes_for_pac_id, language=response_language
88
+ response = AttributeResponsePayload(data=attributes_for_pac_id, language=response_language
86
89
  ).to_json()
87
90
  return response
88
91
 
@@ -113,13 +116,14 @@ class AttributeServerRequestHandler():
113
116
  def _get_referenced_pac_ids(self, attributes_for_pac:AttributesOfPACID):
114
117
  referenced_pacs = []
115
118
  for ag in attributes_for_pac.attribute_groups:
116
- for a in ag.attributes :
117
- if isinstance(a, ReferenceAttribute):
118
- try:
119
- PAC_ID.from_url(a.value)
120
- referenced_pacs.append(a.value)
121
- except Exception:
122
- pass
119
+ for a in ag.attributes.values() :
120
+ for e in a.items:
121
+ if isinstance(e, ReferenceAttributeItemsElement):
122
+ try:
123
+ PAC_ID.from_url(e.value)
124
+ referenced_pacs.append(e.value)
125
+ except Exception:
126
+ pass
123
127
  return referenced_pacs
124
128
 
125
129
 
@@ -131,12 +135,12 @@ class AttributeServerRequestHandler():
131
135
  this function should never get into the situation not to find translations.
132
136
  '''
133
137
  for ag in attributes_of_pac.attribute_groups:
134
- if dn := self._get_display_name_for_key(ag.key, language):
135
- ag.label = dn
138
+ if dn := self._get_display_name_for_key(ag.group_key, language):
139
+ ag.group_label = dn
136
140
  else:
137
- ag.label = self.fallback_label(ag.key)
138
- rich.print(f"[yellow]WARNING:[/yellow] No translation for '{ag.key}' in '{language}'. Falling back to '{ag.label}'")
139
- for a in ag.attributes:
141
+ ag.group_label = self.fallback_label(ag.group_key)
142
+ rich.print(f"[yellow]WARNING:[/yellow] No translation for '{ag.group_key}' in '{language}'. Falling back to '{ag.group_label}'")
143
+ for a in ag.attributes.values():
140
144
  if dn := self._get_display_name_for_key(a.key, language):
141
145
  a.label = dn
142
146
  else:
@@ -161,21 +165,13 @@ class AttributeServerRequestHandler():
161
165
  return None
162
166
 
163
167
 
164
- def _find_response_language(self, requested_languages):
168
+ def _find_response_language(self, requested_languages:LanguageAccept):
165
169
  '''finds the language the server will respond in'''
166
170
  if not requested_languages:
167
171
  return self._default_language
168
-
169
- for language in requested_languages:
170
- if language in self._supported_languages:
171
- return language
172
-
173
- # remove the country codes and try the again
174
- for l_fallback in [lang.split('-')[0] for lang in requested_languages]:
175
- if language in self._supported_languages:
176
- return l_fallback
172
+ best_match = requested_languages.best_match(self._supported_languages, default="en")
173
+ return best_match
177
174
 
178
- return self._default_language
179
175
 
180
176
 
181
177
 
@@ -299,7 +299,8 @@ class ResolverConfig(LabFREED_BaseModel):
299
299
  for placeholder in placeholders:
300
300
  expanded_placeholder = self._apply_convenience_substitutions(placeholder)
301
301
  res = self._evaluate_jsonpath(pac_id_json, expanded_placeholder) or ['']
302
- url = url.replace(f'{{{placeholder}}}', str(res[0]))
302
+ url:str = url.replace(f'{{{placeholder}}}', str(res[0]))
303
+ url = url.strip()
303
304
  # res = self.substitute_jsonpath_expressions(expanded_placeholder, Patterns.jsonpath.value, as_bool=False)
304
305
  # url = url.replace(f'{{{placeholder}}}', res)
305
306
  return url
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labfreed
3
- Version: 1.0.0a24
3
+ Version: 1.0.0b26
4
4
  Summary: Python implementation of LabFREED building blocks
5
5
  Author-email: Reto Thürer <thuerer.r@buchi.com>
6
6
  Requires-Python: >=3.11
@@ -1,15 +1,10 @@
1
- labfreed/__init__.py,sha256=YJ0OVJt08uSlo0RzxUJM71nyql81qOyOpLqVVSxh_o4,339
1
+ labfreed/__init__.py,sha256=K7LpEGI6O9AnTM4dJgUI30LchIO5KnqPUh3gpWhhY4Q,339
2
2
  labfreed/labfreed_infrastructure.py,sha256=ss1PyJl-7Es-lEcxptmdYI9kDAHmh7HB_tAGkPC6UVs,10173
3
- labfreed/labfreed_extended/app/app_infrastructure.py,sha256=z3pxqYPgH8MFZJB2pR2mblpB7VrawQbXWJmz2nrZ6ZA,4581
3
+ labfreed/labfreed_extended/app/app_infrastructure.py,sha256=1867Nq40c8Q4bFyRv48vTIFDXoPeZTfYij9PSog6fkE,4427
4
4
  labfreed/labfreed_extended/app/formatted_print.py,sha256=DcwWP0ix1e_wYNIdceIp6cETkJdG2DqpU8Gs3aZAL40,1930
5
- labfreed/labfreed_extended/app/pac_info/pac_info.py,sha256=4yu_LwFKFdExA2bOIR9NxAMiOaxkkdtdoZ9SjhT5HtU,9071
6
- labfreed/labfreed_extended/app/pac_info/html_renderer/external-link.svg,sha256=KXVLyywqSOhBV4xAiCLsK6yJPUPj8O08M2__qSceM3M,1164
7
- labfreed/labfreed_extended/app/pac_info/html_renderer/macros.jinja.html,sha256=1S-dxibPwJshtdelsmyA4LpgOm84L6RTXPNO93gmPfg,5964
8
- labfreed/labfreed_extended/app/pac_info/html_renderer/pac-info-style.css,sha256=C5pyD956fd6pJgUBjGxvxgL0Wbgq0v7ZLY4Vr-sJZ7A,4169
9
- labfreed/labfreed_extended/app/pac_info/html_renderer/pac_info.jinja.html,sha256=njXE9xexFdMlX65eDiwqE8PzbMATUOJAbwBCh5JvahY,1293
10
- labfreed/labfreed_extended/app/pac_info/html_renderer/pac_info_card.jinja.html,sha256=6UdsZtqJ3soSAYTKN43OB1Onm93WYz23TfM2GBYzJ-U,152
5
+ labfreed/labfreed_extended/app/pac_info/pac_info.py,sha256=HWTYA20cIBpwUl4eRs5cNghCHs3_SOS9yARt11YN0XY,9078
11
6
  labfreed/labfreed_extended/pac_issuer_lib/app_factory.py,sha256=eeIaiCTXV7_aWwDgWhGVjDY4O9uSQoyDQl7YSXVhmA0,20072
12
- labfreed/labfreed_extended/pac_issuer_lib/lib/attribute.py,sha256=BH6yJNFrfEK6dcn7GSPKbfz-0wcJ0NEXrku1e18hVuQ,6797
7
+ labfreed/labfreed_extended/pac_issuer_lib/lib/attribute.py,sha256=Nu2NpaPbFIzDMa17oESJK9pZ3Qv86H3fMmuY5kWre7M,7182
13
8
  labfreed/labfreed_extended/pac_issuer_lib/lib/bp_landing_page.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
9
  labfreed/labfreed_extended/pac_issuer_lib/lib/utils.py,sha256=aUdJGFLx1HDDXGRqMVJuGn7uqzNXHrEb7cCA-nX920Y,651
15
10
  labfreed/labfreed_extended/pac_issuer_lib/static/cancel.svg,sha256=pLsrB5Jm5OtG2JXk4jXv7D9z9RmPsNz1eVKrsQT_6zI,1201
@@ -22,8 +17,8 @@ labfreed/labfreed_extended/pac_issuer_lib/static/cat-MC.svg,sha256=p9r3_N7yDYFDU
22
17
  labfreed/labfreed_extended/pac_issuer_lib/static/cat-MD.svg,sha256=aBtWtcxbkKkYtzjVfs1koLo6lKdi-mwHYQq0BUACsVQ,1829
23
18
  labfreed/labfreed_extended/pac_issuer_lib/static/cat-MS.svg,sha256=ZuFKjoyoDf_69XpYnA-1BhV01vUisPZ2lBDCphXOFGU,740
24
19
  labfreed/labfreed_extended/pac_issuer_lib/static/cat-MX.svg,sha256=26wATJTEjIS9jGBHDC9UIHjQL7xvVTLm0YK2gPs9Kr8,816
25
- labfreed/labfreed_extended/pac_issuer_lib/static/external-link.svg,sha256=H5z9s4VvHq09UnHdqfrYNsx-Whljc0gE4qKJ6-3kfgQ,1158
26
- labfreed/labfreed_extended/pac_issuer_lib/static/logo.svg,sha256=GtxzNn1_TTz57PymPf4RHq_qH6KVtELHN-dvbkbCeE0,2252
20
+ labfreed/labfreed_extended/pac_issuer_lib/static/external-link.svg,sha256=KXVLyywqSOhBV4xAiCLsK6yJPUPj8O08M2__qSceM3M,1164
21
+ labfreed/labfreed_extended/pac_issuer_lib/static/logo.svg,sha256=T-uPnEI8ylQAg7t4avCWIcvtybImrwkir8_R3cnzGI4,2296
27
22
  labfreed/labfreed_extended/pac_issuer_lib/static/menu.svg,sha256=_gvLbHEGigZKlSRU1VpD67sRpNlXUAB_HtJUQVfXOgc,1251
28
23
  labfreed/labfreed_extended/pac_issuer_lib/static/search.svg,sha256=lYyQaukECdUnf3nusxSm5RG_6PdPDknCr6y4Fqs7CWg,577
29
24
  labfreed/labfreed_extended/pac_issuer_lib/static/styles.css,sha256=o1rz7bL1z4IoQowS9Lf_umfFZgOe-mYuECSDveIvPWE,7603
@@ -31,7 +26,7 @@ labfreed/labfreed_extended/pac_issuer_lib/static/styles_brand.css,sha256=0O8lt8z
31
26
  labfreed/labfreed_extended/pac_issuer_lib/static/styles_pac_info.css,sha256=uARZ5o36O4K3hGDv6WNEqrTd5M-lUBdF-FwYj4iEuIA,5341
32
27
  labfreed/labfreed_extended/pac_issuer_lib/templates/flash_error_messages.jinja.html,sha256=qt5HNdDwfpvOVel6SQUAv9EukN6lpCXyL0fDz6sMorw,235
33
28
  labfreed/labfreed_extended/pac_issuer_lib/templates/footer.jinja.html,sha256=kt8ifovVWI8ccXrXyzijHZ0Rb4Xj5KhWgXx8wrccNsY,118
34
- labfreed/labfreed_extended/pac_issuer_lib/templates/main.jinja.html,sha256=0B3akxzwjBGG6v0bzoyYLS3zbRxb4rIaRORYqPT7eeE,2417
29
+ labfreed/labfreed_extended/pac_issuer_lib/templates/main.jinja.html,sha256=WJDz-Sqa4TnGPb4yxFslffIc3YB3tWJ1QRpIMj6uOPA,2536
35
30
  labfreed/labfreed_extended/pac_issuer_lib/templates/navbar.jinja.html,sha256=RXZqyQi8D6Ik17s1-P31GyaEr8Et-3FSbl9RUR68TLM,1751
36
31
  labfreed/labfreed_extended/pac_issuer_lib/templates/pac_issuer_error.jinja.html,sha256=WGAEVOTmsUqG2_wi6xkR8Cpof4EnCChwmsw6k1LPqtE,108
37
32
  labfreed/labfreed_extended/pac_issuer_lib/templates/pac_issuer_landing_page.jinja.html,sha256=8Rv1_Azxy3BskdEWBvmXr-nRYh3xXngjsGgfRCvOOLM,205
@@ -41,19 +36,18 @@ labfreed/labfreed_extended/pac_issuer_lib/templates/pac_info/card.jinja.html,sha
41
36
  labfreed/labfreed_extended/pac_issuer_lib/templates/pac_info/pac_info.jinja.html,sha256=xK0yM_ovRE8QS6N7hiXhGv-ya8C-s19YWhhMqJKYxFM,1518
42
37
  labfreed/pac_attributes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
38
  labfreed/pac_attributes/well_knonw_attribute_keys.py,sha256=Z_QcQdbIil_EMpFqQcBnivEGMDauyoCMW8r62-EN2KM,547
44
- labfreed/pac_attributes/api_data_models/request.py,sha256=N-kXlJWYqh-F1TzNunCwHUPhme3bSLJMgb9aAHWGOy4,1880
45
- labfreed/pac_attributes/api_data_models/response.py,sha256=-oiRn_NifnnQ464NlDDPhp_SrU1ZIK9p7fhXCNI0iSY,8519
39
+ labfreed/pac_attributes/api_data_models/request.py,sha256=64BCChFKXA8Z91r5IxAtcVZ6XiCKcw9RQErok2b91cc,4045
40
+ labfreed/pac_attributes/api_data_models/response.py,sha256=Hglfcvb7gC7uZrLsGfPewC290vp4qq4WsuM9S3UHQFI,8188
46
41
  labfreed/pac_attributes/api_data_models/server_capabilities_response.py,sha256=ypDm4f8xZZl036fp8PuIe6lJHNW5Zg1fItgUlnV75V0,178
47
- labfreed/pac_attributes/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- labfreed/pac_attributes/client/attribute_cache.py,sha256=ThUadWqQ5oM8DnAnvZuY4jeA3Mg06ePNEcRP5wCsadc,2222
49
- labfreed/pac_attributes/client/client.py,sha256=AgOrk4tnn5txO50LCmJlhniazxkfeH8U-8yytGB58AM,7527
50
- labfreed/pac_attributes/pythonic/attribute_server_factory.py,sha256=t3ARmsXdbdQ0QAgRkdHT_ScmpZhXzz3lZkN0WovzygQ,6174
51
- labfreed/pac_attributes/pythonic/excel_attribute_data_source.py,sha256=VEYrSb2r62GJeECc42ppTwZXsYJ-1oHoHQz7HbcM-_Y,8461
52
- labfreed/pac_attributes/pythonic/py_attributes.py,sha256=SsZfrCjd6FJFDe_pmpKJQ2PGrpDfNacHlUzFDBxjWwc,8712
42
+ labfreed/pac_attributes/client/client.py,sha256=5d-G-1tHOx2PXW7KP366tWr4k4F1ykGHX9e-bauF6_w,7149
43
+ labfreed/pac_attributes/client/client_attribute_group.py,sha256=lZXbMU_Yp7Q1iKc5WRqS6pzEz_mtwZaQ5fYZqJA6784,375
44
+ labfreed/pac_attributes/pythonic/attribute_server_factory.py,sha256=8OeWuHpJSW1mA0gWKLWPBZvq0n3VEfVOPQSmXNnp5dw,7673
45
+ labfreed/pac_attributes/pythonic/excel_attribute_data_source.py,sha256=IBBGpHgt-HiZeB6dsLcjtqUPP2JdViLz2QMIDMjzmME,8467
46
+ labfreed/pac_attributes/pythonic/py_attributes.py,sha256=VkkgKupJcM-kf0I5qRc5AiLSfi0vwnNgQv6neNtdRR8,7394
53
47
  labfreed/pac_attributes/pythonic/py_dict_data_source.py,sha256=nAz6GA7Xx_0IORPPpt_Wl3sFJa1Q5Fnq5vdf1uQiJF8,531
54
48
  labfreed/pac_attributes/server/__init__.py,sha256=JvQ2kpQx62OUwP18bGhOWYU9an_nQW59Y8Lh7HyfVxY,301
55
- labfreed/pac_attributes/server/attribute_data_sources.py,sha256=Jx7hFFoiMZmGcSHMEYv5PVf7PFn6iiGIz6uAAjsxswI,2348
56
- labfreed/pac_attributes/server/server.py,sha256=tPOPezRC3YEE0i-MJIc23Me6EARaSqzyFdUNjUzqtdI,9117
49
+ labfreed/pac_attributes/server/attribute_data_sources.py,sha256=92BiQ2QC00PSXeeb6XI0KNcD7ZF7bdOSZZcOrOwPr_o,2406
50
+ labfreed/pac_attributes/server/server.py,sha256=Q5rjWCT6ZicLTMyR59bIC4bCIr8p50kS5p6cwv_wjtw,9114
57
51
  labfreed/pac_attributes/server/translation_data_sources.py,sha256=axALOqfP840sOSdVCRYtrens97mm-hpfONMUyuVlCrY,2145
58
52
  labfreed/pac_cat/__init__.py,sha256=KNPtQzBD1XVohvG_ucOs7RJj-oi6biUTGB1k-T2o6pk,568
59
53
  labfreed/pac_cat/category_base.py,sha256=XAuvfJSCsQ3Ypi5WujtaCmt5isj7Qsx7-zJa9Sm0XVY,2530
@@ -68,7 +62,7 @@ labfreed/pac_id/url_serializer.py,sha256=01LB30pNMBtv2rYHsiE_4Ga2iVA515Boj4ikOIY
68
62
  labfreed/pac_id_resolver/__init__.py,sha256=RNBlrDOSR42gmSNH9wJVhK_xwEX45cvTKVgWW2bjh7Q,113
69
63
  labfreed/pac_id_resolver/cit_v1.py,sha256=JGlEH2d9awEu3HxPW7vu0uj4ZC3B02IdmFg7aJ4axQw,9833
70
64
  labfreed/pac_id_resolver/resolver.py,sha256=anqteWexD7w78wzd1TjT06enkDIU-P-7NVKNWiASXLU,4127
71
- labfreed/pac_id_resolver/resolver_config.py,sha256=hvi9x2o-1323FCRsUg6RG_ZuQRVLgTlYQ7owBTXhjW4,12422
65
+ labfreed/pac_id_resolver/resolver_config.py,sha256=M52v2ps_dGTxQ6x-AV16m5eCbjg_vzwQARxzGTucdaU,12457
72
66
  labfreed/pac_id_resolver/resolver_config_common.py,sha256=JGbgT2YSBc3NQ5x9CV3diqYZgpDGWygGPd5flk4-hWk,2958
73
67
  labfreed/pac_id_resolver/services.py,sha256=IGEueWh2UeXKh6dIOs_ZNTvzguHPVuNB7SmV-FHPYns,2650
74
68
  labfreed/qr/__init__.py,sha256=fdKwP6W2Js--yMbBUdn-g_2uq2VqPpfQJeDLHsMDO-Y,61
@@ -96,7 +90,7 @@ labfreed/well_known_keys/labfreed/well_known_keys.py,sha256=p-hXwEEIs7p2SKn9DQeL
96
90
  labfreed/well_known_keys/unece/UneceUnits.json,sha256=kwfQSp_nTuWbADfBBgqTWrvPl6XtM5SedEVLbMJrM7M,898953
97
91
  labfreed/well_known_keys/unece/__init__.py,sha256=MSP9lmjg9_D9iqG9Yq2_ajYfQSNS9wIT7FXA1c--59M,122
98
92
  labfreed/well_known_keys/unece/unece_units.py,sha256=J20d64H69qKDE3XlGdJoXIIh0G-d0jKoiIDsg9an5pk,1655
99
- labfreed-1.0.0a24.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
100
- labfreed-1.0.0a24.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
101
- labfreed-1.0.0a24.dist-info/METADATA,sha256=EczsCKycg7KL5b5uX61-3KzgTpZl_bg1hkn2gb1GLL0,19858
102
- labfreed-1.0.0a24.dist-info/RECORD,,
93
+ labfreed-1.0.0b26.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
94
+ labfreed-1.0.0b26.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
95
+ labfreed-1.0.0b26.dist-info/METADATA,sha256=K8z2-hmoKb-cimYESItpZrexeEKNvSkvQkReD_W5wD8,19858
96
+ labfreed-1.0.0b26.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
- <title>icons/external-link</title>
4
- <g id="icons/external-link" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
5
- <path d="M5.10570888,18.8942911 C4.83722343,18.6258057 4.81484965,18.204406 5.03858752,17.9104349 L5.10570888,17.8336309 L15.9992174,6.94117952 L10.8105793,6.93942074 L10.7088087,6.93257412 C10.3427331,6.8829117 10.0605793,6.5691165 10.0605793,6.18942074 C10.0605793,5.81286295 10.3380887,5.50112097 10.6997498,5.44755266 L10.8105793,5.43942074 L18.5605793,5.43942074 L18.5605793,13.1894207 L18.5537326,13.2911913 C18.5090365,13.6206593 18.2503927,13.8821507 17.9223127,13.9311544 L17.8105793,13.9394207 L17.7088087,13.9325741 C17.3793407,13.8878779 17.1178493,13.6292342 17.0688456,13.3011542 L17.0605793,13.1894207 L17.0598776,8.00183969 L6.16636906,18.8942911 C5.87347584,19.1871843 5.3986021,19.1871843 5.10570888,18.8942911 Z" id="Icons/Navigation/External-Link/Dark" fill="#1C1847" fill-rule="nonzero"></path>
6
- </g>
7
- </svg>