labfreed 1.0.0a25__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.
- labfreed/__init__.py +1 -1
- labfreed/labfreed_extended/app/app_infrastructure.py +2 -5
- labfreed/labfreed_extended/app/pac_info/pac_info.py +6 -8
- labfreed/labfreed_extended/pac_issuer_lib/lib/attribute.py +9 -6
- labfreed/labfreed_extended/pac_issuer_lib/static/external-link.svg +6 -6
- labfreed/labfreed_extended/pac_issuer_lib/static/logo.svg +44 -44
- labfreed/pac_attributes/api_data_models/request.py +78 -30
- labfreed/pac_attributes/api_data_models/response.py +107 -136
- labfreed/pac_attributes/client/client.py +30 -36
- labfreed/pac_attributes/client/client_attribute_group.py +18 -0
- labfreed/pac_attributes/pythonic/attribute_server_factory.py +39 -13
- labfreed/pac_attributes/pythonic/excel_attribute_data_source.py +1 -1
- labfreed/pac_attributes/pythonic/py_attributes.py +97 -125
- labfreed/pac_attributes/server/attribute_data_sources.py +9 -8
- labfreed/pac_attributes/server/server.py +33 -37
- labfreed/pac_id_resolver/resolver_config.py +2 -1
- {labfreed-1.0.0a25.dist-info → labfreed-1.0.0b26.dist-info}/METADATA +1 -1
- {labfreed-1.0.0a25.dist-info → labfreed-1.0.0b26.dist-info}/RECORD +20 -26
- labfreed/labfreed_extended/app/pac_info/html_renderer/external-link.svg +0 -7
- labfreed/labfreed_extended/app/pac_info/html_renderer/macros.jinja.html +0 -188
- labfreed/labfreed_extended/app/pac_info/html_renderer/pac-info-style.css +0 -176
- labfreed/labfreed_extended/app/pac_info/html_renderer/pac_info.jinja.html +0 -46
- labfreed/labfreed_extended/app/pac_info/html_renderer/pac_info_card.jinja.html +0 -7
- labfreed/pac_attributes/client/__init__.py +0 -0
- labfreed/pac_attributes/client/attribute_cache.py +0 -65
- {labfreed-1.0.0a25.dist-info → labfreed-1.0.0b26.dist-info}/WHEEL +0 -0
- {labfreed-1.0.0a25.dist-info → labfreed-1.0.0b26.dist-info}/licenses/LICENSE +0 -0
labfreed/__init__.py
CHANGED
|
@@ -4,7 +4,6 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
|
4
4
|
import requests
|
|
5
5
|
|
|
6
6
|
from labfreed.labfreed_extended.app.pac_info.pac_info import PacInfo
|
|
7
|
-
from labfreed.pac_attributes.client.attribute_cache import MemoryAttributeCache
|
|
8
7
|
from labfreed.pac_attributes.client.client import AttributeClient, http_attribute_request_default_callback_factory
|
|
9
8
|
from labfreed.pac_attributes.pythonic.py_attributes import pyAttributeGroup
|
|
10
9
|
|
|
@@ -14,8 +13,6 @@ from labfreed.pac_id_resolver.services import ServiceGroup
|
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
16
|
class Labfreed_App_Infrastructure():
|
|
20
17
|
def __init__(self, markup = 'rich', language_preferences:list[str]|str='en', http_client:requests.Session|None=None, use_issuer_resolver_config=True):
|
|
21
18
|
if isinstance(language_preferences, str):
|
|
@@ -30,7 +27,7 @@ class Labfreed_App_Infrastructure():
|
|
|
30
27
|
self._http_client= http_client
|
|
31
28
|
callback = http_attribute_request_default_callback_factory(http_client)
|
|
32
29
|
|
|
33
|
-
self._attribute_client = AttributeClient(http_post_callback=callback
|
|
30
|
+
self._attribute_client = AttributeClient(http_post_callback=callback)
|
|
34
31
|
|
|
35
32
|
|
|
36
33
|
def add_resolver_config(self, cit:str):
|
|
@@ -79,7 +76,7 @@ class Labfreed_App_Infrastructure():
|
|
|
79
76
|
for sg in service_groups:
|
|
80
77
|
attributes_urls = [s.url for s in sg.services if s.service_type == 'attributes-generic']
|
|
81
78
|
for url in attributes_urls:
|
|
82
|
-
ags = {ag.
|
|
79
|
+
ags = {ag.group_key: pyAttributeGroup.from_attribute_group(ag) for ag in self._attribute_client.get_attributes(url, pac_id=pac.to_url(include_extensions=False), language_preferences=self._language_preferences)}
|
|
83
80
|
if ags:
|
|
84
81
|
attribute_groups.update(ags)
|
|
85
82
|
pac_info.attribute_groups = attribute_groups
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
from functools import cached_property
|
|
4
2
|
from pathlib import Path
|
|
5
3
|
from urllib.parse import urlparse
|
|
@@ -164,10 +162,10 @@ class PacInfo(BaseModel):
|
|
|
164
162
|
@cached_property
|
|
165
163
|
def image_url(self) -> str:
|
|
166
164
|
image_attr = self._all_attributes.get(MetaAttributeKeys.IMAGE.value)
|
|
167
|
-
if isinstance(image_attr.
|
|
168
|
-
return image_attr.
|
|
169
|
-
if isinstance(image_attr.
|
|
170
|
-
return image_attr.
|
|
165
|
+
if isinstance(image_attr.values, pyResource):
|
|
166
|
+
return image_attr.values.root
|
|
167
|
+
if isinstance(image_attr.values, str):
|
|
168
|
+
return image_attr.values
|
|
171
169
|
|
|
172
170
|
|
|
173
171
|
@cached_property
|
|
@@ -180,7 +178,7 @@ class PacInfo(BaseModel):
|
|
|
180
178
|
# there can be a display name in attributes, too
|
|
181
179
|
|
|
182
180
|
if dn_attr := self._all_attributes.get(MetaAttributeKeys.DISPLAYNAME.value):
|
|
183
|
-
dn = dn_attr.
|
|
181
|
+
dn = dn_attr.values
|
|
184
182
|
display_name = dn + f' ( aka {display_name} )' if display_name else dn
|
|
185
183
|
|
|
186
184
|
if not display_name and self.main_category:
|
|
@@ -244,7 +242,7 @@ class PacInfo(BaseModel):
|
|
|
244
242
|
|
|
245
243
|
printout.title1("Attributes")
|
|
246
244
|
for ag in self.attribute_groups.values():
|
|
247
|
-
printout.title2(f'{ag.
|
|
245
|
+
printout.title2(f'{ag.group_label} (from {ag.origin})')
|
|
248
246
|
for v in ag.attributes.values():
|
|
249
247
|
v:pyAttribute
|
|
250
248
|
#print(f'{k}: ({v.label}) :: {v.value} ')
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import logging
|
|
3
3
|
from flask import render_template, request
|
|
4
|
+
from labfreed.pac_attributes.api_data_models.request import AttributeRequestData
|
|
4
5
|
from labfreed.pac_attributes.api_data_models.response import AttributeGroup
|
|
5
6
|
from labfreed.pac_cat.pac_cat import PAC_CAT
|
|
6
7
|
from labfreed.pac_cat.predefined_categories import Material_Device, Material_Consumable, Material_Substance
|
|
@@ -75,7 +76,7 @@ class DynamicDemoAttributeGroup(AttributeGroupDataSource):
|
|
|
75
76
|
return None
|
|
76
77
|
|
|
77
78
|
attributes = pyAttributes( [pyAttribute(key=d[0], value=d[1]) for d in self._data] ).to_payload_attributes()
|
|
78
|
-
return AttributeGroup(
|
|
79
|
+
return AttributeGroup(group_key=self._attribute_group_key,
|
|
79
80
|
attributes=attributes)
|
|
80
81
|
|
|
81
82
|
|
|
@@ -106,7 +107,7 @@ class SessionLocalDirectCall(requests.Session):
|
|
|
106
107
|
self._request_handlers = request_handlers
|
|
107
108
|
|
|
108
109
|
|
|
109
|
-
def
|
|
110
|
+
def get(self, url, *args, **kwargs):
|
|
110
111
|
|
|
111
112
|
if is_self_request(url):
|
|
112
113
|
# Case: server calls itself
|
|
@@ -122,11 +123,15 @@ class SessionLocalDirectCall(requests.Session):
|
|
|
122
123
|
# Example: directly call the Flask view function instead of HTTP
|
|
123
124
|
# You could map URLs to functions if you know your routing
|
|
124
125
|
# For now, just return a mock response
|
|
125
|
-
|
|
126
|
+
path, pac = path.strip("/").rsplit("/", 1)
|
|
127
|
+
rh = self._request_handlers.get(path)
|
|
126
128
|
|
|
127
129
|
r = Response()
|
|
128
130
|
if rh:
|
|
129
|
-
|
|
131
|
+
request_data = AttributeRequestData.from_http_request(pac_id = pac,
|
|
132
|
+
params = kwargs.get('params'),
|
|
133
|
+
headers = kwargs.get('headers'))
|
|
134
|
+
body = rh.handle_attribute_request(request_data=request_data)
|
|
130
135
|
r.status_code = 200
|
|
131
136
|
r._content = body.encode("utf-8")
|
|
132
137
|
r.encoding = "utf-8"
|
|
@@ -161,8 +166,6 @@ def is_self_request(url: str) -> bool:
|
|
|
161
166
|
target_ip = resolve_ip(parsed.hostname.lower())
|
|
162
167
|
current_ip = resolve_ip(request.host.split(":")[0].lower())
|
|
163
168
|
|
|
164
|
-
|
|
165
|
-
|
|
166
169
|
return target_ip == current_ip
|
|
167
170
|
|
|
168
171
|
|
|
@@ -1,7 +1,7 @@
|
|
|
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>
|
|
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
7
|
</svg>
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<svg id="LabfreedLogo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 233" width="200" height="116.5">
|
|
3
|
-
<defs>
|
|
4
|
-
<style>
|
|
5
|
-
.cls-1 { fill: #51a1d7; }
|
|
6
|
-
.cls-2 { fill: #438ad7; }
|
|
7
|
-
.cls-3 { fill: #94d5e4; }
|
|
8
|
-
.cls-4 { fill: #4db9d2; }
|
|
9
|
-
.cls-5 { fill: #2b63bc; }
|
|
10
|
-
.brand-text {
|
|
11
|
-
font-family: Arial, sans-serif;
|
|
12
|
-
font-size: 24px;
|
|
13
|
-
font-weight: bold;
|
|
14
|
-
fill: #51a1d7;
|
|
15
|
-
}
|
|
16
|
-
</style>
|
|
17
|
-
</defs>
|
|
18
|
-
|
|
19
|
-
<!-- Half-size dove -->
|
|
20
|
-
<g transform="scale(0.5)">
|
|
21
|
-
<g>
|
|
22
|
-
<g>
|
|
23
|
-
<polygon class="cls-3" points="115.8 143.51 115.8 143.55 115.77 143.51 115.8 143.51"/>
|
|
24
|
-
<polygon class="cls-1" points="208.4 97.2 141.5 164.1 138.93 158.95 115.78 112.63 108.05 97.2 208.4 97.2"/>
|
|
25
|
-
<polygon class="cls-2" points="208.4 97.19 108.05 97.19 138.93 27.74 169.8 58.61 208.4 97.19"/>
|
|
26
|
-
<polygon class="cls-5" points="208.4 43.17 208.4 97.2 169.81 58.62 208.4 43.17"/>
|
|
27
|
-
<polygon class="cls-2" points="247 74.05 208.4 74.05 208.4 43.17 247 74.05"/>
|
|
28
|
-
</g>
|
|
29
|
-
<path class="cls-4" d="M108.05,189.82h.02v-7.72h-.02v7.72ZM108.06,143.51v7.72h.02v-7.72h-.02ZM108.06,158.93v15.45h.02v-15.45h-.02Z"/>
|
|
30
|
-
<path class="cls-2" d="M141.5,164.1l-2.57-5.15-23.15-46.32-7.72-15.43v46.3h.02v7.72h-.02v7.71h.02v15.45h-.02v7.72h.02v7.72h-.02v30.87l38.6-46.32-5.15-10.27ZM115.8,143.55l-.03-.05h.03v.05Z"/>
|
|
31
|
-
<rect class="cls-2" x="30.88" y="43.16" width="15.43" height="15.45"/>
|
|
32
|
-
<rect class="cls-2" x="15.43" y="27.73" width="15.44" height="15.44"/>
|
|
33
|
-
<rect class="cls-1" y="12.3" width="15.44" height="15.44"/>
|
|
34
|
-
<rect class="cls-2" x="61.75" y="74.04" width="15.43" height="15.45"/>
|
|
35
|
-
<rect class="cls-1" x="46.32" y="74.05" width="15.44" height="15.44"/>
|
|
36
|
-
<rect class="cls-1" x="30.87" y="89.49" width="15.44" height="15.44"/>
|
|
37
|
-
<rect class="cls-1" y="58.61" width="15.44" height="15.44"/>
|
|
38
|
-
</g>
|
|
39
|
-
<polygon class="cls-5" points="138.93 27.74 108.05 97.19 92.63 97.19 92.63 89.48 77.18 89.48 77.18 74.04 61.75 74.04 61.75 58.61 46.31 58.61 46.31 43.16 30.88 43.16 30.88 27.75 30.86 27.74 138.93 27.74"/>
|
|
40
|
-
</g>
|
|
41
|
-
|
|
42
|
-
<!-- Branding text -->
|
|
43
|
-
<text class="brand-text" x="0" y="130">Powered by LabFREED </text>
|
|
44
|
-
</svg>
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg id="LabfreedLogo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 233" width="200" height="116.5">
|
|
3
|
+
<defs>
|
|
4
|
+
<style>
|
|
5
|
+
.cls-1 { fill: #51a1d7; }
|
|
6
|
+
.cls-2 { fill: #438ad7; }
|
|
7
|
+
.cls-3 { fill: #94d5e4; }
|
|
8
|
+
.cls-4 { fill: #4db9d2; }
|
|
9
|
+
.cls-5 { fill: #2b63bc; }
|
|
10
|
+
.brand-text {
|
|
11
|
+
font-family: Arial, sans-serif;
|
|
12
|
+
font-size: 24px;
|
|
13
|
+
font-weight: bold;
|
|
14
|
+
fill: #51a1d7;
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</defs>
|
|
18
|
+
|
|
19
|
+
<!-- Half-size dove -->
|
|
20
|
+
<g transform="scale(0.5)">
|
|
21
|
+
<g>
|
|
22
|
+
<g>
|
|
23
|
+
<polygon class="cls-3" points="115.8 143.51 115.8 143.55 115.77 143.51 115.8 143.51"/>
|
|
24
|
+
<polygon class="cls-1" points="208.4 97.2 141.5 164.1 138.93 158.95 115.78 112.63 108.05 97.2 208.4 97.2"/>
|
|
25
|
+
<polygon class="cls-2" points="208.4 97.19 108.05 97.19 138.93 27.74 169.8 58.61 208.4 97.19"/>
|
|
26
|
+
<polygon class="cls-5" points="208.4 43.17 208.4 97.2 169.81 58.62 208.4 43.17"/>
|
|
27
|
+
<polygon class="cls-2" points="247 74.05 208.4 74.05 208.4 43.17 247 74.05"/>
|
|
28
|
+
</g>
|
|
29
|
+
<path class="cls-4" d="M108.05,189.82h.02v-7.72h-.02v7.72ZM108.06,143.51v7.72h.02v-7.72h-.02ZM108.06,158.93v15.45h.02v-15.45h-.02Z"/>
|
|
30
|
+
<path class="cls-2" d="M141.5,164.1l-2.57-5.15-23.15-46.32-7.72-15.43v46.3h.02v7.72h-.02v7.71h.02v15.45h-.02v7.72h.02v7.72h-.02v30.87l38.6-46.32-5.15-10.27ZM115.8,143.55l-.03-.05h.03v.05Z"/>
|
|
31
|
+
<rect class="cls-2" x="30.88" y="43.16" width="15.43" height="15.45"/>
|
|
32
|
+
<rect class="cls-2" x="15.43" y="27.73" width="15.44" height="15.44"/>
|
|
33
|
+
<rect class="cls-1" y="12.3" width="15.44" height="15.44"/>
|
|
34
|
+
<rect class="cls-2" x="61.75" y="74.04" width="15.43" height="15.45"/>
|
|
35
|
+
<rect class="cls-1" x="46.32" y="74.05" width="15.44" height="15.44"/>
|
|
36
|
+
<rect class="cls-1" x="30.87" y="89.49" width="15.44" height="15.44"/>
|
|
37
|
+
<rect class="cls-1" y="58.61" width="15.44" height="15.44"/>
|
|
38
|
+
</g>
|
|
39
|
+
<polygon class="cls-5" points="138.93 27.74 108.05 97.19 92.63 97.19 92.63 89.48 77.18 89.48 77.18 74.04 61.75 74.04 61.75 58.61 46.31 58.61 46.31 43.16 30.88 43.16 30.88 27.75 30.86 27.74 138.93 27.74"/>
|
|
40
|
+
</g>
|
|
41
|
+
|
|
42
|
+
<!-- Branding text -->
|
|
43
|
+
<text class="brand-text" x="0" y="130">Powered by LabFREED </text>
|
|
44
|
+
</svg>
|
|
@@ -1,56 +1,104 @@
|
|
|
1
|
-
from typing import Self
|
|
2
|
-
from
|
|
1
|
+
from typing import Any, Self
|
|
2
|
+
from urllib.parse import unquote
|
|
3
|
+
from werkzeug.datastructures import LanguageAccept
|
|
4
|
+
from werkzeug.http import parse_accept_header
|
|
5
|
+
from pydantic import ConfigDict, field_validator, model_validator
|
|
3
6
|
from labfreed.labfreed_infrastructure import LabFREED_BaseModel, LabFREED_ValidationError, ValidationMsgLevel
|
|
4
7
|
from labfreed.pac_id.pac_id import PAC_ID
|
|
5
8
|
|
|
9
|
+
ATTR_GROUPS = 'attr_grps'
|
|
10
|
+
ATTR_GROUPS_FWD_LKP= 'attr_fwd_lkp'
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
|
|
13
|
+
class AttributeRequestData(LabFREED_BaseModel):
|
|
14
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
9
15
|
|
|
10
|
-
|
|
11
|
-
language_preferences:
|
|
16
|
+
pac_id: str
|
|
17
|
+
language_preferences: LanguageAccept|None = None
|
|
12
18
|
restrict_to_attribute_groups: list[str]|None = None
|
|
13
|
-
|
|
19
|
+
do_forward_lookup: bool = True
|
|
14
20
|
|
|
15
21
|
def as_json(self):
|
|
16
22
|
return self.model_dump_json()
|
|
17
23
|
|
|
18
24
|
@classmethod
|
|
19
|
-
def from_json(cls, json):
|
|
25
|
+
def from_json(cls, json) -> Self:
|
|
20
26
|
return cls.model_validate_json(json)
|
|
21
27
|
|
|
28
|
+
@classmethod
|
|
29
|
+
def from_http_request(cls, pac_id:str, params:dict, headers:dict):
|
|
30
|
+
restrict_to_attribute_groups = params.get(ATTR_GROUPS)
|
|
31
|
+
if restrict_to_attribute_groups == '':
|
|
32
|
+
restrict_to_attribute_groups = None
|
|
33
|
+
if restrict_to_attribute_groups:
|
|
34
|
+
restrict_to_attribute_groups = restrict_to_attribute_groups.split(',')
|
|
35
|
+
|
|
36
|
+
fwd_lkp = params.get(ATTR_GROUPS_FWD_LKP,'true')
|
|
37
|
+
do_forward_lookup = fwd_lkp.lower() not in ['false', 'no', '0', 'n', 'off']
|
|
38
|
+
lang_hdr = headers.get('Accept-Language')
|
|
39
|
+
language_preferences: LanguageAccept = parse_accept_header(lang_hdr, LanguageAccept)
|
|
40
|
+
out = cls(pac_id=pac_id,
|
|
41
|
+
restrict_to_attribute_groups = restrict_to_attribute_groups,
|
|
42
|
+
do_forward_lookup = do_forward_lookup,
|
|
43
|
+
language_preferences=language_preferences
|
|
44
|
+
)
|
|
45
|
+
return out
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
22
49
|
@model_validator(mode="before")
|
|
23
50
|
@classmethod
|
|
24
|
-
def
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
51
|
+
def _scalars_to_list(cls, d):
|
|
52
|
+
if isinstance(lp:= d.get("language_preferences"), str):
|
|
53
|
+
d["language_preferences"] = [lp]
|
|
54
|
+
if isinstance(rag := d.get("restrict_to_attribute_groups"), str):
|
|
55
|
+
d["restrict_to_attribute_groups"] = [rag]
|
|
56
|
+
return d
|
|
57
|
+
|
|
29
58
|
|
|
59
|
+
@field_validator('language_preferences', mode='before')
|
|
60
|
+
@classmethod
|
|
61
|
+
def convert_language_preferences(cls,lp):
|
|
62
|
+
if isinstance(lp, LanguageAccept):
|
|
63
|
+
return lp
|
|
64
|
+
lq = [(lng, 1-i/len(lp)) for i, lng in enumerate(lp)]
|
|
65
|
+
return LanguageAccept(lq)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@model_validator(mode="after")
|
|
69
|
+
def _revert_url_encoding(self):
|
|
70
|
+
self.pac_id = unquote(self.pac_id)
|
|
71
|
+
if self.restrict_to_attribute_groups:
|
|
72
|
+
self.restrict_to_attribute_groups = [unquote(g) for g in self.restrict_to_attribute_groups]
|
|
73
|
+
return self
|
|
74
|
+
|
|
30
75
|
@model_validator(mode="after")
|
|
31
|
-
def _validate_pacs(self) -> Self:
|
|
32
|
-
|
|
76
|
+
def _validate_pacs(self) -> Self:
|
|
77
|
+
try:
|
|
78
|
+
PAC_ID.from_url(self.pac_id)
|
|
79
|
+
except LabFREED_ValidationError:
|
|
33
80
|
self._add_validation_message(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
for pac_url in self.pac_ids:
|
|
40
|
-
try:
|
|
41
|
-
PAC_ID.from_url(pac_url)
|
|
42
|
-
except LabFREED_ValidationError:
|
|
43
|
-
self._add_validation_message(
|
|
44
|
-
source="pacs",
|
|
45
|
-
level = ValidationMsgLevel.ERROR,
|
|
46
|
-
msg='{pac_url} is not a valid PAC-ID'
|
|
47
|
-
)
|
|
81
|
+
source="pac_id",
|
|
82
|
+
level = ValidationMsgLevel.ERROR,
|
|
83
|
+
msg='{self.pac_id} is not a valid PAC-ID'
|
|
84
|
+
)
|
|
48
85
|
|
|
49
86
|
if not self.is_valid:
|
|
50
87
|
raise LabFREED_ValidationError(message='Invalid request', validation_msgs=self.validation_messages())
|
|
51
88
|
|
|
52
89
|
return self
|
|
53
90
|
|
|
91
|
+
def language_preference_http_header(self) -> dict[str, str]:
|
|
92
|
+
if not self.language_preferences:
|
|
93
|
+
return {}
|
|
94
|
+
headers={'Accept-Language': LanguageAccept(lq).to_header()}
|
|
95
|
+
return headers
|
|
96
|
+
|
|
97
|
+
def request_params(self) -> dict[str, Any]:
|
|
98
|
+
params = {ATTR_GROUPS_FWD_LKP: self.do_forward_lookup}
|
|
99
|
+
if self.restrict_to_attribute_groups:
|
|
100
|
+
params.update({ATTR_GROUPS: ','.join(self.restrict_to_attribute_groups)})
|
|
101
|
+
return params
|
|
102
|
+
|
|
54
103
|
|
|
55
104
|
|
|
56
|
-
|