labfreed 0.3.1a6__py3-none-any.whl → 1.0.0a2__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.
- labfreed/__init__.py +1 -1
- labfreed/labfreed_extended/app/app_infrastructure.py +2 -2
- labfreed/labfreed_extended/app/pac_info.py +21 -6
- labfreed/pac_attributes/api_data_models/request.py +3 -3
- labfreed/pac_attributes/api_data_models/response.py +3 -3
- labfreed/pac_attributes/client/client.py +23 -3
- labfreed/pac_attributes/pythonic/attribute_server_factory.py +40 -6
- labfreed/pac_attributes/pythonic/py_attributes.py +3 -3
- labfreed/pac_attributes/server/server.py +4 -45
- labfreed/pac_attributes/well_knonw_attribute_keys.py +1 -1
- labfreed/pac_cat/category_base.py +2 -2
- labfreed/pac_id/url_parser.py +1 -1
- labfreed/pac_id_resolver/cit_v2.py +1 -0
- labfreed/trex/pythonic/pyTREX.py +1 -1
- labfreed/trex/pythonic/quantity.py +5 -3
- {labfreed-0.3.1a6.dist-info → labfreed-1.0.0a2.dist-info}/METADATA +1 -1
- {labfreed-0.3.1a6.dist-info → labfreed-1.0.0a2.dist-info}/RECORD +19 -19
- {labfreed-0.3.1a6.dist-info → labfreed-1.0.0a2.dist-info}/WHEEL +0 -0
- {labfreed-0.3.1a6.dist-info → labfreed-1.0.0a2.dist-info}/licenses/LICENSE +0 -0
labfreed/__init__.py
CHANGED
|
@@ -5,7 +5,7 @@ import requests
|
|
|
5
5
|
|
|
6
6
|
from labfreed.labfreed_extended.app.pac_info import PacInfo
|
|
7
7
|
from labfreed.pac_attributes.client.attribute_cache import MemoryAttributeCache
|
|
8
|
-
from labfreed.pac_attributes.client.client import AttributeClient,
|
|
8
|
+
from labfreed.pac_attributes.client.client import AttributeClient, http_attribute_request_default_callback_factory
|
|
9
9
|
from labfreed.pac_attributes.pythonic.py_attributes import pyAttributeGroup
|
|
10
10
|
from labfreed.pac_attributes.well_knonw_attribute_keys import MetaAttributeKeys
|
|
11
11
|
from labfreed.well_known_extensions.display_name_extension import DisplayNameExtension
|
|
@@ -30,7 +30,7 @@ class Labfreed_App_Infrastructure():
|
|
|
30
30
|
if not http_client:
|
|
31
31
|
http_client = requests.Session()
|
|
32
32
|
self._http_client= http_client
|
|
33
|
-
callback =
|
|
33
|
+
callback = http_attribute_request_default_callback_factory(http_client)
|
|
34
34
|
|
|
35
35
|
self._attribute_client = AttributeClient(http_post_callback=callback, cache_store=MemoryAttributeCache())
|
|
36
36
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
+
from functools import cached_property
|
|
3
4
|
from pydantic import BaseModel, Field
|
|
4
5
|
from labfreed.pac_attributes.pythonic.py_attributes import pyAttribute, pyAttributeGroup, pyAttributes
|
|
5
6
|
from labfreed.pac_attributes.well_knonw_attribute_keys import MetaAttributeKeys
|
|
@@ -7,6 +8,7 @@ from labfreed.pac_cat.pac_cat import PAC_CAT
|
|
|
7
8
|
from labfreed.pac_id.pac_id import PAC_ID
|
|
8
9
|
from labfreed.pac_id_resolver.services import ServiceGroup
|
|
9
10
|
from labfreed.labfreed_extended.app.formatted_print import StringIOLineBreak
|
|
11
|
+
from labfreed.trex.pythonic.pyTREX import pyTREX
|
|
10
12
|
from labfreed.well_known_extensions.display_name_extension import DisplayNameExtension
|
|
11
13
|
|
|
12
14
|
|
|
@@ -29,7 +31,8 @@ class PacInfo(BaseModel):
|
|
|
29
31
|
|
|
30
32
|
@property
|
|
31
33
|
def attached_data(self):
|
|
32
|
-
return self.pac_id.get_extension_of_type('TREX')
|
|
34
|
+
return { trex_ext.name: pyTREX.from_trex(trex=trex_ext.trex) for trex_ext in self.pac_id.get_extension_of_type('TREX')}
|
|
35
|
+
|
|
33
36
|
|
|
34
37
|
@property
|
|
35
38
|
def summary(self):
|
|
@@ -50,13 +53,25 @@ class PacInfo(BaseModel):
|
|
|
50
53
|
dn = DisplayNameExtension.from_extension(dn)
|
|
51
54
|
display_name = dn.display_name or ""
|
|
52
55
|
# there can be a display name in attributes, too
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
display_name += f' ( aka {dn} )'
|
|
56
|
+
|
|
57
|
+
if dn_attr := self._all_attributes.get(MetaAttributeKeys.DISPLAYNAME.value):
|
|
58
|
+
dn = dn_attr.value
|
|
59
|
+
display_name = dn + f' ( aka {display_name} )' if display_name else dn
|
|
58
60
|
return display_name
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def safety_pictograms(self) -> dict[str, pyAttribute]:
|
|
65
|
+
pictogram_attributes = {k: a for k, a in self._all_attributes.items() if "https://labfreed.org/ghs/pictogram/" in a.key}
|
|
66
|
+
return pictogram_attributes
|
|
59
67
|
|
|
68
|
+
|
|
69
|
+
@cached_property
|
|
70
|
+
def _all_attributes(self) -> dict[str, pyAttribute]:
|
|
71
|
+
out = {}
|
|
72
|
+
for ag in self.attributes.values():
|
|
73
|
+
out.update(ag.attributes)
|
|
74
|
+
return out
|
|
60
75
|
|
|
61
76
|
|
|
62
77
|
|
|
@@ -7,7 +7,7 @@ from labfreed.pac_id.pac_id import PAC_ID
|
|
|
7
7
|
class AttributeRequestPayload(LabFREED_BaseModel):
|
|
8
8
|
model_config = ConfigDict(frozen=True)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
pac_ids: list[str]
|
|
11
11
|
language_preferences: list[str]
|
|
12
12
|
restrict_to_attribute_groups: list[str]|None = None
|
|
13
13
|
suppress_forward_lookup: bool = False
|
|
@@ -29,14 +29,14 @@ class AttributeRequestPayload(LabFREED_BaseModel):
|
|
|
29
29
|
|
|
30
30
|
@model_validator(mode="after")
|
|
31
31
|
def _validate_pacs(self) -> Self:
|
|
32
|
-
if len(self.
|
|
32
|
+
if len(self.pac_ids) > 100:
|
|
33
33
|
self._add_validation_message(
|
|
34
34
|
source="pacs",
|
|
35
35
|
level = ValidationMsgLevel.ERROR,
|
|
36
36
|
msg='The number of pac-ids must be limited to 100'
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
-
for pac_url in self.
|
|
39
|
+
for pac_url in self.pac_ids:
|
|
40
40
|
try:
|
|
41
41
|
PAC_ID.from_url(pac_url)
|
|
42
42
|
except LabFREED_ValidationError:
|
|
@@ -70,12 +70,12 @@ class TextAttribute(AttributeBase):
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
class NumericValue(LabFREED_BaseModel):
|
|
73
|
-
|
|
73
|
+
numerical_value: str
|
|
74
74
|
unit: str
|
|
75
75
|
|
|
76
76
|
@model_validator(mode='after')
|
|
77
77
|
def _validate_value(self):
|
|
78
|
-
value = self.
|
|
78
|
+
value = self.numerical_value
|
|
79
79
|
if not_allowed_chars := set(re.sub(r'[0-9\.\-\+Ee]', '', value)):
|
|
80
80
|
self._add_validation_message(
|
|
81
81
|
source="Numeric Attribute",
|
|
@@ -160,7 +160,7 @@ class AttributeGroup(LabFREED_BaseModel):
|
|
|
160
160
|
|
|
161
161
|
|
|
162
162
|
class AttributesOfPACID(LabFREED_BaseModel):
|
|
163
|
-
|
|
163
|
+
pac_id: str
|
|
164
164
|
attribute_groups: list[AttributeGroup]
|
|
165
165
|
|
|
166
166
|
|
|
@@ -10,6 +10,7 @@ from pydantic import ValidationError
|
|
|
10
10
|
from labfreed.pac_attributes.api_data_models.request import AttributeRequestPayload
|
|
11
11
|
from labfreed.pac_attributes.api_data_models.response import AttributeResponsePayload
|
|
12
12
|
from labfreed.pac_attributes.client.attribute_cache import AttributeCache, CacheableAttributeGroup
|
|
13
|
+
from labfreed.pac_attributes.server.server import AttributeServerRequestHandler
|
|
13
14
|
from labfreed.pac_id.pac_id import PAC_ID
|
|
14
15
|
|
|
15
16
|
|
|
@@ -35,7 +36,7 @@ class AttributeRequestCallback(Protocol):
|
|
|
35
36
|
...
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
def
|
|
39
|
+
def http_attribute_request_default_callback_factory(session: requests.Session = None) -> AttributeRequestCallback:
|
|
39
40
|
""" Returns a default implementation of AttributeRequestCallback using `requests` package.
|
|
40
41
|
|
|
41
42
|
Args:
|
|
@@ -55,6 +56,25 @@ def attribute_request_default_callback_factory(session: requests.Session = None)
|
|
|
55
56
|
return 500, str(e)
|
|
56
57
|
return callback
|
|
57
58
|
|
|
59
|
+
|
|
60
|
+
def local_attribute_request_callback_factory(request_handler:AttributeServerRequestHandler) -> AttributeRequestCallback:
|
|
61
|
+
""" Returns a default implementation of AttributeRequestCallback using `requests` package.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
request_handler: The request handler
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
AttributeRequestCallback: a callback following the AttributeRequestCallback protocol.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def callback(url: str, attribute_request_body: str) -> tuple[int, str]:
|
|
71
|
+
try:
|
|
72
|
+
resp = request_handler.handle_attribute_request(attribute_request_body)
|
|
73
|
+
return 200, resp
|
|
74
|
+
except requests.exceptions.RequestException as e:
|
|
75
|
+
return 500, str(e)
|
|
76
|
+
return callback
|
|
77
|
+
|
|
58
78
|
|
|
59
79
|
|
|
60
80
|
|
|
@@ -104,7 +124,7 @@ class AttributeClient():
|
|
|
104
124
|
return attribute_groups
|
|
105
125
|
|
|
106
126
|
# no valid data found in cache > request to server
|
|
107
|
-
attribute_request_body = AttributeRequestPayload(
|
|
127
|
+
attribute_request_body = AttributeRequestPayload(pac_ids=[pac_id.to_url()],
|
|
108
128
|
restrict_to_attribute_groups=restrict_to_attribute_groups,
|
|
109
129
|
language_preferences=language_preferences
|
|
110
130
|
)
|
|
@@ -125,7 +145,7 @@ class AttributeClient():
|
|
|
125
145
|
|
|
126
146
|
# update cache
|
|
127
147
|
for ag_for_pac in r.pac_attributes:
|
|
128
|
-
pac = PAC_ID.from_url(ag_for_pac.
|
|
148
|
+
pac = PAC_ID.from_url(ag_for_pac.pac_id)
|
|
129
149
|
ags = [
|
|
130
150
|
CacheableAttributeGroup(
|
|
131
151
|
key= ag.key,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
from typing import Any, Protocol
|
|
3
3
|
|
|
4
|
-
from flask import Blueprint
|
|
4
|
+
from flask import Blueprint, current_app
|
|
5
|
+
from labfreed.pac_attributes.api_data_models.request import AttributeRequestPayload
|
|
5
6
|
from labfreed.pac_attributes.server.server import AttributeGroupDataSource, AttributeServerRequestHandler, InvalidRequestError, TranslationDataSource
|
|
6
7
|
|
|
7
8
|
try:
|
|
@@ -30,7 +31,8 @@ class AttributeServerFactory():
|
|
|
30
31
|
default_language:str,
|
|
31
32
|
translation_data_sources:list[TranslationDataSource],
|
|
32
33
|
authenticator: Authenticator|None,
|
|
33
|
-
framework:Webframework=Webframework.FLASK
|
|
34
|
+
framework:Webframework=Webframework.FLASK,
|
|
35
|
+
doc_text:str=""
|
|
34
36
|
):
|
|
35
37
|
|
|
36
38
|
if not authenticator:
|
|
@@ -43,7 +45,7 @@ class AttributeServerFactory():
|
|
|
43
45
|
|
|
44
46
|
match(framework):
|
|
45
47
|
case Webframework.FLASK:
|
|
46
|
-
app = AttributeFlaskApp(request_handler,authenticator=authenticator)
|
|
48
|
+
app = AttributeFlaskApp(request_handler,authenticator=authenticator, doc_text=doc_text)
|
|
47
49
|
return app
|
|
48
50
|
case Webframework.FASTAPI:
|
|
49
51
|
raise NotImplementedError('FastAPI webapp not implemented')
|
|
@@ -53,10 +55,11 @@ class AttributeServerFactory():
|
|
|
53
55
|
|
|
54
56
|
|
|
55
57
|
class AttributeFlaskApp(Flask):
|
|
56
|
-
def __init__(self, request_handler: AttributeServerRequestHandler, authenticator: Authenticator | None = None, **kwargs: Any):
|
|
58
|
+
def __init__(self, request_handler: AttributeServerRequestHandler, authenticator: Authenticator | None = None, doc_text:str="", **kwargs: Any):
|
|
57
59
|
super().__init__(__name__, **kwargs)
|
|
58
60
|
self.config['ATTRIBUTE_REQUEST_HANDLER'] = request_handler
|
|
59
61
|
self.config['AUTHENTICATOR'] = authenticator
|
|
62
|
+
self.config['DOC_TEXT'] = doc_text
|
|
60
63
|
|
|
61
64
|
bp = self.create_attribute_blueprint(request_handler, authenticator)
|
|
62
65
|
self.register_blueprint(bp)
|
|
@@ -86,9 +89,40 @@ class AttributeFlaskApp(Flask):
|
|
|
86
89
|
return "The request was valid, but the server encountered an error", 500
|
|
87
90
|
return response_body
|
|
88
91
|
|
|
89
|
-
@bp.route("/
|
|
92
|
+
@bp.route("/", methods=["GET"], strict_slashes=False)
|
|
90
93
|
def capabilities():
|
|
91
|
-
|
|
94
|
+
doc_text = current_app.config.get('DOC_TEXT', "")
|
|
95
|
+
capabilities = request_handler.capabilities()
|
|
96
|
+
authentication_required = bool(current_app.config['AUTHENTICATOR'])
|
|
97
|
+
example_request = AttributeRequestPayload(pac_ids=['HTTPS://PAC.METTORIUS.COM/EXAMPLE'], language_preferences=['fr', 'de']).model_dump_json(indent=2, exclude_none=True, exclude_unset=True)
|
|
98
|
+
server_address = request.url.rstrip('/')
|
|
99
|
+
response = f'''
|
|
100
|
+
<body>
|
|
101
|
+
This is a <h1>LabFREED attribute server </h1>
|
|
102
|
+
<h2>Capabilities</h2>
|
|
103
|
+
Available Attribute Groups: {', '.join([f'<a href="{ag}"> {ag} </a>' for ag in capabilities.available_attribute_groups])} <br>
|
|
104
|
+
|
|
105
|
+
Supported Languages: {', '.join([f'<b> {l} </b>' for l in capabilities.supported_languages])} <br>
|
|
106
|
+
Default Language: <b>{capabilities.default_language}</b> <br>
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
<h2>How to use</h2>
|
|
110
|
+
Make a <b>POST</b> request to <a href="{server_address}">{server_address}</a> with the following body:
|
|
111
|
+
<pre>{example_request}</pre>
|
|
112
|
+
Consult {'<a href="https://github.com/ApiniLabs/PAC-Attributes"> the specification </a>' if doc_text else ""} for details. <br>
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
{'This server <b> requires authentication </b> ' if authentication_required else ''}
|
|
116
|
+
<br>
|
|
117
|
+
|
|
118
|
+
{"<h2>Further Information</h2>"if doc_text else ""}
|
|
119
|
+
{doc_text or ""}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
</body>
|
|
123
|
+
'''
|
|
124
|
+
|
|
125
|
+
return response
|
|
92
126
|
|
|
93
127
|
return bp
|
|
94
128
|
|
|
@@ -55,7 +55,7 @@ class pyAttributes(RootModel[list[pyAttribute]]):
|
|
|
55
55
|
elif isinstance(attribute.value, Quantity|int|float):
|
|
56
56
|
if not isinstance(attribute.value, Quantity):
|
|
57
57
|
value = Quantity(value=attribute.value, unit='dimensionless')
|
|
58
|
-
num_attribute = NumericAttribute(value = NumericValue(
|
|
58
|
+
num_attribute = NumericAttribute(value = NumericValue(numerical_value=value.value_as_str(),
|
|
59
59
|
unit = value.unit),
|
|
60
60
|
**common_args)
|
|
61
61
|
num_attribute.print_validation_messages()
|
|
@@ -64,7 +64,7 @@ class pyAttributes(RootModel[list[pyAttribute]]):
|
|
|
64
64
|
elif isinstance(value, str):
|
|
65
65
|
# capture quantities in the form of "100.0e5 g/L"
|
|
66
66
|
if q := Quantity.from_str_with_unit(value):
|
|
67
|
-
return NumericAttribute(value = NumericValue(
|
|
67
|
+
return NumericAttribute(value = NumericValue(numerical_value=q.value_as_str(),
|
|
68
68
|
unit = q.unit),
|
|
69
69
|
**common_args)
|
|
70
70
|
else:
|
|
@@ -96,7 +96,7 @@ class pyAttributes(RootModel[list[pyAttribute]]):
|
|
|
96
96
|
value = pyReference(a.value)
|
|
97
97
|
|
|
98
98
|
case NumericAttribute():
|
|
99
|
-
value = Quantity.from_str_value(value=a.value.
|
|
99
|
+
value = Quantity.from_str_value(value=a.value.numerical_value, unit=a.value.unit)
|
|
100
100
|
|
|
101
101
|
case BoolAttribute():
|
|
102
102
|
value = a.value
|
|
@@ -60,7 +60,7 @@ class AttributeServerRequestHandler():
|
|
|
60
60
|
raise InvalidRequestError
|
|
61
61
|
attributes_for_pac_id = []
|
|
62
62
|
referenced_pac_ids = set()
|
|
63
|
-
for pac_url in r.
|
|
63
|
+
for pac_url in r.pac_ids:
|
|
64
64
|
attributes_for_pac = self._get_attributes_for_pac_id(pac_url=pac_url,
|
|
65
65
|
restrict_to_attribute_groups = r.restrict_to_attribute_groups)
|
|
66
66
|
attributes_for_pac_id.append(attributes_for_pac)
|
|
@@ -103,7 +103,7 @@ class AttributeServerRequestHandler():
|
|
|
103
103
|
traceback.print_exc()
|
|
104
104
|
raise e
|
|
105
105
|
|
|
106
|
-
return AttributesOfPACID(
|
|
106
|
+
return AttributesOfPACID(pac_id=pac_url, # return the pac_url as given, i.e. with the extension if there was one
|
|
107
107
|
attribute_groups=attribute_groups)
|
|
108
108
|
|
|
109
109
|
|
|
@@ -120,44 +120,6 @@ class AttributeServerRequestHandler():
|
|
|
120
120
|
pass
|
|
121
121
|
return referenced_pacs
|
|
122
122
|
|
|
123
|
-
# def get_translations(self, attributes_for_pac_id):
|
|
124
|
-
# ontology_map = {} # ontology name → list of TermTranslations
|
|
125
|
-
|
|
126
|
-
# for ag_for_pac in attributes_for_pac_id:
|
|
127
|
-
# for ag in ag_for_pac.attribute_groups:
|
|
128
|
-
# ag: AttributeGroup
|
|
129
|
-
# ontology_name = ag.ontology
|
|
130
|
-
# translation_data_source: TranslationDataSource = self._translation_data_sources.get(ontology_name, {})
|
|
131
|
-
|
|
132
|
-
# attribute_keys = [a.key for a in ag.attributes]
|
|
133
|
-
# all_keys = set([ag.key] + attribute_keys)
|
|
134
|
-
|
|
135
|
-
# for k in all_keys:
|
|
136
|
-
# t = translation_data_source.get_translations_for(k)
|
|
137
|
-
# if t:
|
|
138
|
-
# ontology_map.setdefault(ontology_name, []).append(t)
|
|
139
|
-
|
|
140
|
-
# translations_by_ontology = [ TranslationsForOntology(ontology=name, terms=terms) for name, terms in ontology_map.items()
|
|
141
|
-
# ]
|
|
142
|
-
# return translations_by_ontology
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
# def _get_display_name_for_key(self, key, requested_languages:str):
|
|
146
|
-
# for tds in self._translation_data_sources:
|
|
147
|
-
# if term := tds.get_translations_for(key):
|
|
148
|
-
# # try the languages requested by the user
|
|
149
|
-
# for l in requested_languages:
|
|
150
|
-
# if dn := term.in_language(l):
|
|
151
|
-
# return dn
|
|
152
|
-
# # remove the country codes and try the again
|
|
153
|
-
# for l_fallback in [l.split('-')[0] for l in requested_languages]:
|
|
154
|
-
# if dn := term.in_language(l_fallback):
|
|
155
|
-
# return dn
|
|
156
|
-
# # use the server fallback language
|
|
157
|
-
# if dn := term.in_language(self._default_language):
|
|
158
|
-
# return
|
|
159
|
-
# warnings.warn(f'No translation for {key}')
|
|
160
|
-
# return None
|
|
161
123
|
|
|
162
124
|
def _add_display_names(self, attributes_of_pac:AttributesOfPACID, language:str) -> str:
|
|
163
125
|
'''
|
|
@@ -181,9 +143,6 @@ class AttributeServerRequestHandler():
|
|
|
181
143
|
|
|
182
144
|
|
|
183
145
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
146
|
def _get_display_name_for_key(self, key, language:str):
|
|
188
147
|
'''call this only with a language you know there is a translation for'''
|
|
189
148
|
for tds in self._translation_data_sources:
|
|
@@ -211,10 +170,10 @@ class AttributeServerRequestHandler():
|
|
|
211
170
|
|
|
212
171
|
|
|
213
172
|
|
|
214
|
-
def capabilities(self):
|
|
173
|
+
def capabilities(self) -> ServerCapabilities:
|
|
215
174
|
return ServerCapabilities(supported_languages=self._supported_languages,
|
|
216
175
|
default_language=self._default_language,
|
|
217
|
-
available_attribute_groups= [ds.attribute_group_key for ds in self._attribute_group_data_sources])
|
|
176
|
+
available_attribute_groups= [ds.attribute_group_key for ds in self._attribute_group_data_sources])
|
|
218
177
|
|
|
219
178
|
|
|
220
179
|
|
|
@@ -6,6 +6,6 @@ class MetaAttributeKeys(Enum):
|
|
|
6
6
|
IMAGE = "https://schema.org/image"
|
|
7
7
|
ALIAS = "https://schema.org/alternateName"
|
|
8
8
|
DESCRIPTION = "https://schema.org/description"
|
|
9
|
-
GROUPKEY = "https://labfreed.org/
|
|
9
|
+
GROUPKEY = "https://labfreed.org/terms/attribute_group_metadata"
|
|
10
10
|
|
|
11
11
|
|
|
@@ -44,14 +44,14 @@ class Category(LabFREED_BaseModel):
|
|
|
44
44
|
s = '\n'.join( [f"{field_name} \t ({field_info.alias or ''}): \t {getattr(self, field_name)}" for field_name, field_info in self.model_fields.items() if getattr(self, field_name)])
|
|
45
45
|
return s
|
|
46
46
|
|
|
47
|
-
def segments_as_dict(self):
|
|
47
|
+
def segments_as_dict(self, include_alias=False):
|
|
48
48
|
''' returns the segments in a dict, with nice keys and values'''
|
|
49
49
|
out = dict()
|
|
50
50
|
for field_name, field_info in self.model_fields.items():
|
|
51
51
|
if field_name =='additional_segments':
|
|
52
52
|
continue
|
|
53
53
|
if v := getattr(self, field_name):
|
|
54
|
-
if field_info.alias:
|
|
54
|
+
if field_info.alias and include_alias:
|
|
55
55
|
k = f"{field_name} ({ field_info.alias})"
|
|
56
56
|
else:
|
|
57
57
|
k = f"{field_name}"
|
labfreed/pac_id/url_parser.py
CHANGED
|
@@ -82,7 +82,7 @@ class PAC_Parser():
|
|
|
82
82
|
@classmethod
|
|
83
83
|
def _parse_pac_id(cls,id_str:str) -> "PAC_ID":
|
|
84
84
|
# m = re.match('(HTTPS://)?(PAC.)?(?P<issuer>.+?\..+?)/(?P<identifier>.*)', id_str)
|
|
85
|
-
m = re.match('(HTTPS://)?(PAC.)?(?P<issuer>.+?)/(?P<identifier>.*)', id_str)
|
|
85
|
+
m = re.match('(HTTPS://)?(PAC.)?(?P<issuer>.+?)/(?P<identifier>.*)', id_str, re.IGNORECASE)
|
|
86
86
|
if not m:
|
|
87
87
|
raise LabFREED_ValidationError(f'{id_str} does not match the pattern expected for PAC-ID')
|
|
88
88
|
d = m.groupdict()
|
labfreed/trex/pythonic/pyTREX.py
CHANGED
|
@@ -215,7 +215,7 @@ def _trex_value_to_python_type(v):
|
|
|
215
215
|
|
|
216
216
|
elif isinstance(v,DateValue):
|
|
217
217
|
d = v._date_time_dict
|
|
218
|
-
if d.get('year') and d.get('hour'): # input is only a time
|
|
218
|
+
if d.get('year') and d.get('hour') is not None: # input is only a time
|
|
219
219
|
return datetime(**d)
|
|
220
220
|
elif d.get('year'):
|
|
221
221
|
return date(**d)
|
|
@@ -24,11 +24,12 @@ class Quantity(BaseModel):
|
|
|
24
24
|
#dimensionless_unit
|
|
25
25
|
unit:str= d.get('unit')
|
|
26
26
|
if unit and unit in ['1', '', 'dimensionless']:
|
|
27
|
-
|
|
27
|
+
unit = None
|
|
28
|
+
d['unit'] = unit
|
|
28
29
|
|
|
29
30
|
#try to coerce to ucum. catch the two most likely mistakes to use blanks for multiplication and ^ for exponents.
|
|
30
31
|
if unit:
|
|
31
|
-
unit = unit.replace('/ ', '/').replace(' /', '/').replace(' ', '.').replace('^', '')
|
|
32
|
+
unit = unit.replace('/ ', '/').replace(' /', '/').replace(' ', '.').replace('^', '').replace('·','.')
|
|
32
33
|
d['unit'] = unit
|
|
33
34
|
|
|
34
35
|
return d
|
|
@@ -122,8 +123,9 @@ class Quantity(BaseModel):
|
|
|
122
123
|
|
|
123
124
|
def __str__(self):
|
|
124
125
|
unit_symbol = self.unit
|
|
125
|
-
if self.unit
|
|
126
|
+
if self.unit in [ "1", "dimensionless"] or not self.unit:
|
|
126
127
|
unit_symbol = ""
|
|
128
|
+
unit_symbol = unit_symbol.replace('.', '·')
|
|
127
129
|
val = self.value_as_str()
|
|
128
130
|
return f"{val} {unit_symbol}"
|
|
129
131
|
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
labfreed/__init__.py,sha256=
|
|
1
|
+
labfreed/__init__.py,sha256=o2qxE39XObi_KwNFEMO1fKgVTLltzbQn3tl5YQnhFXg,338
|
|
2
2
|
labfreed/labfreed_infrastructure.py,sha256=YZmU-kgopyB1tvpTR_k_uIt1Q2ezexMrWvu-HaP65IE,10104
|
|
3
|
-
labfreed/labfreed_extended/app/app_infrastructure.py,sha256=
|
|
3
|
+
labfreed/labfreed_extended/app/app_infrastructure.py,sha256=1VMc_Vtjwof9hwzSG95KuIUjT1h7uNsWf_lTORYFFuQ,3981
|
|
4
4
|
labfreed/labfreed_extended/app/formatted_print.py,sha256=DcwWP0ix1e_wYNIdceIp6cETkJdG2DqpU8Gs3aZAL40,1930
|
|
5
|
-
labfreed/labfreed_extended/app/pac_info.py,sha256=
|
|
5
|
+
labfreed/labfreed_extended/app/pac_info.py,sha256=oiU940sUJiV3yfNLOmkCsn7Go4qui_jijULeHTOFgrg,4163
|
|
6
6
|
labfreed/pac_attributes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
labfreed/pac_attributes/well_knonw_attribute_keys.py,sha256=
|
|
8
|
-
labfreed/pac_attributes/api_data_models/request.py,sha256
|
|
9
|
-
labfreed/pac_attributes/api_data_models/response.py,sha256=
|
|
7
|
+
labfreed/pac_attributes/well_knonw_attribute_keys.py,sha256=axE81MeJ3G_Wy1PbmNAXH6SfPtl96NXvQJMyrvK10t4,324
|
|
8
|
+
labfreed/pac_attributes/api_data_models/request.py,sha256=-CI3rU_Bzw2DZGSS06Jl4zajrxMkfPGhKHWmIfnmWlk,1868
|
|
9
|
+
labfreed/pac_attributes/api_data_models/response.py,sha256=4VliJuKM_r-J-xaLEqfcdW3JTe2BGG_hQSCaHPG3-xM,5726
|
|
10
10
|
labfreed/pac_attributes/api_data_models/server_capabilities_response.py,sha256=ypDm4f8xZZl036fp8PuIe6lJHNW5Zg1fItgUlnV75V0,178
|
|
11
11
|
labfreed/pac_attributes/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
labfreed/pac_attributes/client/attribute_cache.py,sha256=eWFy7h-T6gd25ENj9pLvSadNFRrzzIineqBoov2cGyw,2688
|
|
13
|
-
labfreed/pac_attributes/client/client.py,sha256=
|
|
14
|
-
labfreed/pac_attributes/pythonic/attribute_server_factory.py,sha256=
|
|
13
|
+
labfreed/pac_attributes/client/client.py,sha256=Sfvbr8WMW8NOL6_tkWFvU0IybKnzyC0XydmcEFUyb5s,7102
|
|
14
|
+
labfreed/pac_attributes/pythonic/attribute_server_factory.py,sha256=_wasafjBlwvzOaM6-uPgqPethsDQHEpaXoiRW7w9aV0,5759
|
|
15
15
|
labfreed/pac_attributes/pythonic/excel_attribute_data_source.py,sha256=mS310M3UOKuv00mJsRAK7acfTdyOw9c-_9UHXKuAqvs,6923
|
|
16
|
-
labfreed/pac_attributes/pythonic/py_attributes.py,sha256=
|
|
16
|
+
labfreed/pac_attributes/pythonic/py_attributes.py,sha256=LoPSH5DWdPTKq-3d2CT-7tTfkqYN9s53sNEeSq_6fHg,5615
|
|
17
17
|
labfreed/pac_attributes/pythonic/py_dict_data_source.py,sha256=nAz6GA7Xx_0IORPPpt_Wl3sFJa1Q5Fnq5vdf1uQiJF8,531
|
|
18
18
|
labfreed/pac_attributes/server/__init__.py,sha256=JvQ2kpQx62OUwP18bGhOWYU9an_nQW59Y8Lh7HyfVxY,301
|
|
19
19
|
labfreed/pac_attributes/server/attribute_data_sources.py,sha256=bCFqozKBEVdR8etRJjG9RCE5Uea9SMudPN4Mwh-iQr4,2083
|
|
20
|
-
labfreed/pac_attributes/server/server.py,sha256=
|
|
20
|
+
labfreed/pac_attributes/server/server.py,sha256=_Rzi_vzX02o0g03lbm-fdg5AJHJnESDWD7cJEKRFs8w,8841
|
|
21
21
|
labfreed/pac_attributes/server/translation_data_sources.py,sha256=axALOqfP840sOSdVCRYtrens97mm-hpfONMUyuVlCrY,2145
|
|
22
22
|
labfreed/pac_cat/__init__.py,sha256=KNPtQzBD1XVohvG_ucOs7RJj-oi6biUTGB1k-T2o6pk,568
|
|
23
|
-
labfreed/pac_cat/category_base.py,sha256=
|
|
23
|
+
labfreed/pac_cat/category_base.py,sha256=wVejYgDnUIUQ71q05ctophtZY2w9fD-PZ0xk3wUAEkQ,2522
|
|
24
24
|
labfreed/pac_cat/pac_cat.py,sha256=wcb_fhvgjS2xmqTsxS8_Oibvr1nsQt5zr8aUajLfK1E,5578
|
|
25
25
|
labfreed/pac_cat/predefined_categories.py,sha256=5wnMCj-CrACV2W4lH13w7qynWIwi506G3uLNcxuJQGg,8832
|
|
26
26
|
labfreed/pac_id/__init__.py,sha256=NGMbzkwQ4txKeT5pxdIZordwHO8J3_q84jzPanjKoHg,675
|
|
27
27
|
labfreed/pac_id/extension.py,sha256=NgLexs1LbRMMm4ETrn5m4EY2iWoMDgOTb0UV556jatQ,2227
|
|
28
28
|
labfreed/pac_id/id_segment.py,sha256=r5JU1SJuRXhZJJxy5T3xjrb598wIDTLpivSJhIUAzjQ,4526
|
|
29
29
|
labfreed/pac_id/pac_id.py,sha256=DDcSYJ8DBWqIoW_usOT7eDjHZ9700cTYxeUgenHluOA,5378
|
|
30
|
-
labfreed/pac_id/url_parser.py,sha256=
|
|
30
|
+
labfreed/pac_id/url_parser.py,sha256=F3SPiscfbPwZ0uMzgirJ1vwgaXclN546lBW46Ywo3nk,5979
|
|
31
31
|
labfreed/pac_id/url_serializer.py,sha256=01LB30pNMBtv2rYHsiE_4Ga2iVA515Boj4ikOIYhiBQ,3511
|
|
32
32
|
labfreed/pac_id_resolver/__init__.py,sha256=RNBlrDOSR42gmSNH9wJVhK_xwEX45cvTKVgWW2bjh7Q,113
|
|
33
33
|
labfreed/pac_id_resolver/cit_common.py,sha256=jzoDOxog8YW68q7vyvDGCZcVcgIzJHXlMt8KwgVnx6o,2885
|
|
34
34
|
labfreed/pac_id_resolver/cit_v1.py,sha256=TVvOWJA6-wmBkwzoHBqNuwV-tndRTSKAK07k56eoJBU,9326
|
|
35
|
-
labfreed/pac_id_resolver/cit_v2.py,sha256=
|
|
35
|
+
labfreed/pac_id_resolver/cit_v2.py,sha256=iDEvUb9A3ocX_ijewTIK3p951CIESnKyI7upjrd3Vjw,11842
|
|
36
36
|
labfreed/pac_id_resolver/resolver.py,sha256=IxI57XRZfGHZigym6_f5tnt3ycwU5LnfXs5n1D9pPDs,3077
|
|
37
37
|
labfreed/pac_id_resolver/services.py,sha256=vtnxLm38t4PNOf73cXh6UZOtWZZOGxfBCfXUDRxGHog,2592
|
|
38
38
|
labfreed/qr/__init__.py,sha256=fdKwP6W2Js--yMbBUdn-g_2uq2VqPpfQJeDLHsMDO-Y,61
|
|
@@ -44,8 +44,8 @@ labfreed/trex/trex_base_models.py,sha256=591559BISc82fyIoEP_dq_GHDbPCVzApx7FM3TR
|
|
|
44
44
|
labfreed/trex/value_segments.py,sha256=_fbDHDRfo7pxIWpzcbyjppv1VNd8Tnd-VXhbd6igI8g,3698
|
|
45
45
|
labfreed/trex/pythonic/__init__.py,sha256=dyAQG7t-uYN6VfGXbWIq2bHxGcGI63l7FS2-VPYs2RQ,137
|
|
46
46
|
labfreed/trex/pythonic/data_table.py,sha256=KGyA5hRdDOOkJB0EOyjmzbbMusgYkBB_2SIFzrJ25yI,3148
|
|
47
|
-
labfreed/trex/pythonic/pyTREX.py,sha256=
|
|
48
|
-
labfreed/trex/pythonic/quantity.py,sha256=
|
|
47
|
+
labfreed/trex/pythonic/pyTREX.py,sha256=wWYYb9pyZB01ObGOHf8gXzvMyAGzuCTduHzP03yvKj8,10157
|
|
48
|
+
labfreed/trex/pythonic/quantity.py,sha256=jmhHfmEclYBQ1cLmOtmV7Ull4S0qHKIYVE0uhtNFFz0,5441
|
|
49
49
|
labfreed/utilities/base36.py,sha256=_yX8aQ1OwrK5tnJU1NUEzQSFGr9xAVnNvPObpNzCPYs,2895
|
|
50
50
|
labfreed/utilities/ensure_utc_time.py,sha256=1ZTTzyIt7IimQ4ArTzdgw5hxiabkkplltbQe3Wdt2ZQ,307
|
|
51
51
|
labfreed/utilities/translations.py,sha256=XY4Wud_BfXswUOpebdh0U_D2bMzb2vqluuGWzFK-3uU,1851
|
|
@@ -59,7 +59,7 @@ labfreed/well_known_keys/labfreed/well_known_keys.py,sha256=p-hXwEEIs7p2SKn9DQeL
|
|
|
59
59
|
labfreed/well_known_keys/unece/UneceUnits.json,sha256=kwfQSp_nTuWbADfBBgqTWrvPl6XtM5SedEVLbMJrM7M,898953
|
|
60
60
|
labfreed/well_known_keys/unece/__init__.py,sha256=MSP9lmjg9_D9iqG9Yq2_ajYfQSNS9wIT7FXA1c--59M,122
|
|
61
61
|
labfreed/well_known_keys/unece/unece_units.py,sha256=J20d64H69qKDE3XlGdJoXIIh0G-d0jKoiIDsg9an5pk,1655
|
|
62
|
-
labfreed-0.
|
|
63
|
-
labfreed-0.
|
|
64
|
-
labfreed-0.
|
|
65
|
-
labfreed-0.
|
|
62
|
+
labfreed-1.0.0a2.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
|
|
63
|
+
labfreed-1.0.0a2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
64
|
+
labfreed-1.0.0a2.dist-info/METADATA,sha256=5puhyvihc2xCJlVdQjfPAXbwsllH_x4LmYBz-xzgM-E,19740
|
|
65
|
+
labfreed-1.0.0a2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|