labfreed 1.0.0a2__py3-none-any.whl → 1.0.0a4__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.

Potentially problematic release.


This version of labfreed might be problematic. Click here for more details.

labfreed/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  Python implementation of LabFREED building blocks
3
3
  '''
4
4
 
5
- __version__ = "1.0.0a2"
5
+ __version__ = "1.0.0a4"
6
6
 
7
7
  from labfreed.pac_id import * # noqa: F403
8
8
  from labfreed.pac_cat import * # noqa: F403
@@ -3,7 +3,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed
3
3
 
4
4
  import requests
5
5
 
6
- from labfreed.labfreed_extended.app.pac_info import PacInfo
6
+ from labfreed.labfreed_extended.app.pac_info.pac_info import PacInfo
7
7
  from labfreed.pac_attributes.client.attribute_cache import MemoryAttributeCache
8
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
@@ -0,0 +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>
7
+ </svg>
@@ -0,0 +1,188 @@
1
+ {# ---------- PAC-INFO MACROS ---------- #}
2
+ {# These macros render semantic HTML with light class hooks. #}
3
+
4
+ {%- macro info_card(pac_info) -%}
5
+ <section class="lf-info-card">
6
+ <div class="lf-info-title">{{ pac_info.display_name }}</div>
7
+ <div class="lf-info-grid">
8
+ {% if pac_info.image_url %}
9
+ <img src="{{ pac_info.image_url }}" class="prod_img lf-info-item" alt="">
10
+ {% endif %}
11
+
12
+ {% if pac_info.main_category %}
13
+ {% for c in pac_info.pac_id.categories %}
14
+ {% for k, v in c.segments_as_dict().items() %}
15
+ {% if k != "key" %}
16
+ <div class="lf-info-item">
17
+ {% if k %}
18
+ <div class="lf-info-key">{{ k }}</div>
19
+ {% else %}
20
+ <div class="lf-info-key"> <i>{{"No Key" }}</i></div>
21
+ {% endif %}
22
+ <div class="lf-info-val">{{ v }}</div>
23
+ </div>
24
+ {% endif %}
25
+ {% endfor %}
26
+ {% endfor %}
27
+ {% endif %}
28
+
29
+ </div>
30
+ {% if pac_info.safety_pictograms %}
31
+ {% for p in pac_info.safety_pictograms.values() %}
32
+ <figure class="lf-figure lf-figure--image">
33
+ <img src="{{ p.value|e }}" alt="{{ p.label|e }}" class="lf-attr-image">
34
+ <figcaption class="lf-figure__caption sr-only">{{ p.label }}</figcaption>
35
+ </figure>
36
+ {% endfor %}
37
+ {% endif %}
38
+
39
+ </section>
40
+ {%- endmacro -%}
41
+
42
+
43
+ {%- macro key_value_table(pairs) -%}
44
+ {# pairs: dict-like object #}
45
+ <table class="lf-table lf-table--kv">
46
+ <tbody>
47
+ {%- for k, v in pairs.items() -%}
48
+ {%- if k != "key" -%}
49
+ <tr>
50
+ <th class="lf-th lf-th--key">{{ k }}</th>
51
+ <td class="lf-td lf-td--val">{{ v }}</td>
52
+ </tr>
53
+ {%- endif -%}
54
+ {%- endfor -%}
55
+ </tbody>
56
+ </table>
57
+ {%- endmacro -%}
58
+
59
+
60
+ {%- macro category_block(category) -%}
61
+ <div class="lf-section lf-section--category">
62
+ <h5 class="lf-section__title">{{ category.__class__.__name__ }}</h5>
63
+ {{ key_value_table(category.segments_as_dict()) }}
64
+ </div>
65
+ {%- endmacro -%}
66
+
67
+
68
+ {%- macro services_table(user_handover_group) -%}
69
+ <div class="lf-section lf-section--services">
70
+ <div class="lf-origin-hint">from {{ user_handover_group.origin }}</div>
71
+ <div class="lf-services">
72
+ {%- for s in user_handover_group.services -%}
73
+ <a href="{{ s.url }}" target="_blank" rel="noopener" class="lf-service">
74
+ <span class="lf-service__icon">
75
+ {% include "external-link.svg" %}
76
+ </span>
77
+ <span class="lf-service__name">{{ s.service_name }}</span>
78
+ </a>
79
+ {%- endfor -%}
80
+ </div>
81
+ </div>
82
+ {%- endmacro -%}
83
+
84
+
85
+ {%- macro reference_value(value) -%}
86
+ <span class="lf-reference">{{ value }}</span>
87
+ {%- endmacro -%}
88
+
89
+
90
+ {%- macro attribute_row(a) -%}
91
+ <tr>
92
+ <th class="lf-th lf-th--key">{{ a.label }}</th>
93
+ <td class="lf-td lf-td--val">
94
+ {% set value = a.value %}
95
+ {%- if is_image(value) -%}
96
+ <figure class="lf-figure lf-figure--image">
97
+ <img src="{{ value|e }}" alt="{{ label|e }}" class="lf-attr-image">
98
+ <figcaption class="lf-figure__caption sr-only">{{ label }}</figcaption>
99
+ </figure>
100
+ {%- elif is_url(value) -%}
101
+ <a href="{{ value|e }}" target="_blank" rel="noopener" class="lf-link">{{ value }}</a>
102
+ {%- elif is_reference(value) -%}
103
+ {{ reference_value(value)}}
104
+ {%- else -%}
105
+ <span class="lf-text">{{ value }}</span>
106
+ {%- endif -%}
107
+ </td>
108
+ </tr>
109
+ {%- endmacro -%}
110
+
111
+
112
+ {%- macro attribute_group_block(ag) -%}
113
+ <div class="lf-section lf-section--attributes">
114
+ <h5 class="lf-section__title">
115
+ {{ ag.label }} <span class="lf-origin-hint">(from {{ ag.origin }})</span>
116
+ </h5>
117
+ <table class="lf-table lf-table--kv">
118
+ <tbody>
119
+ {%- for a in ag.attributes.values() -%}
120
+ {{ attribute_row(a) }}
121
+ {%- endfor -%}
122
+ </tbody>
123
+ </table>
124
+ </div>
125
+ {%- endmacro -%}
126
+
127
+
128
+ {%- macro data_table_inline(dt) -%}
129
+ {# Renders your DataTable structure; expects filters: is_data_table(dt) #}
130
+ {%- if dt.data | length == 1 -%}
131
+ <table class="lf-table lf-table--kv">
132
+ <tbody>
133
+ {%- for i in range(dt.col_names | length) -%}
134
+ <tr>
135
+ <th class="lf-th lf-th--key">{{ dt.col_names[i] }}</th>
136
+ <td class="lf-td lf-td--val">{{ dt.data[0][i] }}</td>
137
+ </tr>
138
+ {%- endfor -%}
139
+ </tbody>
140
+ </table>
141
+ {%- else -%}
142
+ <table class="lf-table lf-table--grid">
143
+ <thead>
144
+ <tr>
145
+ {%- for rn in dt.col_names -%}
146
+ <th class="lf-th">{{ rn }}</th>
147
+ {%- endfor -%}
148
+ </tr>
149
+ </thead>
150
+ <tbody>
151
+ {%- for row in dt.data -%}
152
+ <tr>
153
+ {%- for e in row -%}
154
+ <td class="lf-td">{{ e }}</td>
155
+ {%- endfor -%}
156
+ </tr>
157
+ {%- endfor -%}
158
+ </tbody>
159
+ </table>
160
+ {%- endif -%}
161
+ {%- endmacro -%}
162
+
163
+
164
+ {%- macro attached_data_block(attached_data) -%}
165
+ <div class="lf-section lf-section--attached">
166
+ {%- for name, trex in attached_data.items() -%}
167
+ <div class="lf-subsection">
168
+ <h5 class="lf-subsection__title">{{ name }}</h5>
169
+ <table class="lf-table lf-table--kv">
170
+ <tbody>
171
+ {%- for k, v in trex.items() -%}
172
+ <tr>
173
+ <th class="lf-th lf-th--key">{{ k }}</th>
174
+ <td class="lf-td lf-td--val">
175
+ {%- if is_data_table(v) -%}
176
+ {{ data_table_inline(v) }}
177
+ {%- else -%}
178
+ {{ v }}
179
+ {%- endif -%}
180
+ </td>
181
+ </tr>
182
+ {%- endfor -%}
183
+ </tbody>
184
+ </table>
185
+ </div>
186
+ {%- endfor -%}
187
+ </div>
188
+ {%- endmacro -%}
@@ -0,0 +1,176 @@
1
+
2
+ .lf-section {
3
+ margin-top: 0.5rem;
4
+ }
5
+
6
+ .lf-origin-hint {
7
+ font-style: italic; /* cursive */
8
+ font-size: 1rem; /* reset to regular text size */
9
+ font-weight: normal; /* not bold, even if inside a heading */
10
+ }
11
+
12
+
13
+ .lf-results {
14
+ display: grid;
15
+ gap: 1.5rem;
16
+ padding: 1rem; /* space around the whole grid */
17
+ }
18
+
19
+ .lf-info-card {
20
+ width:100%;
21
+ border: solid 1px #ccc;
22
+ border-radius: 8px;
23
+ }
24
+
25
+ .lf-info-card {
26
+ padding: 1rem;
27
+ border: 1px solid #e5e7eb;
28
+ border-radius: 8px;
29
+ background: #fff;
30
+ }
31
+
32
+ /* title as "slightly bigger text" */
33
+ .lf-info-title {
34
+ font-size: 1.25rem; /* a bit larger than normal text */
35
+ font-weight: 600;
36
+ margin-bottom: 1rem;
37
+ }
38
+
39
+ /* responsive grid for key/value */
40
+ .lf-info-grid {
41
+ display: grid;
42
+ gap: 1rem;
43
+ grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
44
+ }
45
+
46
+ .lf-info-item {
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: 0.25rem;
50
+ padding: 0.5rem;
51
+ }
52
+
53
+ .lf-info-key {
54
+ font-size: 0.875rem;
55
+ font-weight: 600;
56
+ color: #374151; /* slate-700 */
57
+ }
58
+
59
+ .lf-info-val {
60
+ font-size: 1rem;
61
+ color: #111827; /* slate-900 */
62
+ }
63
+
64
+
65
+
66
+ .prod_img {
67
+ height: 10vw;
68
+ width: auto;
69
+ }
70
+
71
+
72
+ /* Apply to all PAC macro tables */
73
+ .lf-table {
74
+ width: 100%;
75
+ border-collapse: collapse;
76
+ table-layout: fixed; /* ensures consistent column widths */
77
+ }
78
+
79
+ .lf-table th,
80
+ .lf-table td {
81
+ border: 1px solid #ccc;
82
+ padding: 0.4rem 0.6rem;
83
+ vertical-align: top;
84
+ text-align: left;
85
+ }
86
+
87
+ /* Key/value style: 1/3 vs 2/3 columns */
88
+ .lf-table--kv th.lf-th--key {
89
+ width: 33%;
90
+ font-weight: 600;
91
+ }
92
+ .lf-table--kv td.lf-td--val {
93
+ width: 67%;
94
+ }
95
+
96
+ .lf-attr-image {
97
+ width: 30px;
98
+ }
99
+
100
+ /* Services laid out as equal-width grid columns */
101
+ .lf-services {
102
+ display: grid;
103
+ gap: 0.75rem;
104
+
105
+ /* 2 columns on small, 3 on md, 4 on lg — tweak as you like */
106
+ grid-template-columns: repeat(2, 1fr);
107
+ }
108
+
109
+ @media (min-width: 640px) {
110
+ .lf-services { grid-template-columns: repeat(3, 1fr); }
111
+ }
112
+ @media (min-width: 1024px) {
113
+ .lf-services { grid-template-columns: repeat(4, 1fr); }
114
+ }
115
+
116
+ /* Each service card fills its grid cell */
117
+ .lf-service {
118
+ display: flex; /* still use flex inside for icon + text */
119
+ align-items: center;
120
+ gap: 0.4rem;
121
+ padding: 0.4rem 0.6rem;
122
+ height: 100%; /* same height across a row (since your content height is uniform) */
123
+ width: 100%; /* ensure full cell width */
124
+ text-decoration: none;
125
+ color: var(--lf-link, #2563eb);
126
+ }
127
+
128
+ .lf-service:hover {
129
+ font-size: 1.05em; /* ~5% larger */
130
+ text-decoration: none;
131
+ }
132
+
133
+ .lf-service__icon { width: 1rem; height: 1rem; flex-shrink: 0; }
134
+ .lf-service__name {
135
+ flex: 1;
136
+ overflow: hidden;
137
+ text-overflow: ellipsis;
138
+ white-space: nowrap;
139
+ }
140
+
141
+
142
+
143
+ /* Position context */
144
+ .lf-ref-card-wrap {
145
+ position: relative;
146
+ display: inline-block;
147
+ }
148
+
149
+ /* The floating card is hidden by default */
150
+ .lf-ref-card {
151
+ display: none;
152
+ position: absolute;
153
+ top: 100%; /* appear below the reference text */
154
+ left: 0;
155
+ z-index: 1000;
156
+ width: min(420px, 90vw);
157
+ margin-top: .5rem;
158
+ padding: 1rem;
159
+ background: #fff;
160
+ border: 1px solid #e5e7eb;
161
+ border-radius: 8px;
162
+ box-shadow: 0 10px 20px rgba(0,0,0,.08);
163
+ }
164
+
165
+ /* Show on hover */
166
+ .lf-ref-card-wrap:hover .lf-ref-card {
167
+ display: block;
168
+ }
169
+
170
+ /* Style the inline reference */
171
+ .lf-reference {
172
+ color: var(--lf-link, #2563eb);
173
+ }
174
+
175
+
176
+
@@ -0,0 +1,46 @@
1
+ {% import "macros.jinja.html" as pac with context %}
2
+
3
+ <style>
4
+ {% include "pac-info-style.css" %}
5
+ </style>
6
+
7
+
8
+ {% if pac_info %}
9
+ <section class="lf-results">
10
+ {# ----- Info Card ---- #}
11
+ {{ pac.info_card(pac_info) }}
12
+
13
+ {# ---- Services ---- #}
14
+ {% if pac_info.user_handovers %}
15
+ <section>
16
+ <!--<h4>Services</h4>-->
17
+ {% for sg in pac_info.user_handovers %}
18
+ {{ pac.services_table(sg) }}
19
+ {% endfor %}
20
+ </section>
21
+ {% endif %}
22
+
23
+ {# ---- Attributes ---- #}
24
+ {% if pac_info.attributes %}
25
+ <section>
26
+ <!--<h4>Attributes</h4>-->
27
+ {% for ag in pac_info.attributes.values() %}
28
+ {% if ag.key not in hide_attribute_groups %}
29
+ {{ pac.attribute_group_block(ag) }}
30
+ {% endif %}
31
+ {% endfor %}
32
+ </section>
33
+
34
+ {% endif %}
35
+
36
+ {# ---- Attached Data ---- #}
37
+ {% if pac_info.attached_data %}
38
+ <section>
39
+ <!--<h4 class="lf-section__title">Attached Data</h4>-->
40
+ {{ pac.attached_data_block(pac_info.attached_data) }}
41
+ </section>
42
+ {% endif %}
43
+
44
+ </section>
45
+
46
+ {% endif %}
@@ -0,0 +1,7 @@
1
+ {% import "macros.jinja.html" as macros with context %}
2
+
3
+
4
+ <style>
5
+ {% include "pac-info-style.css" %}
6
+ </style>
7
+ {{ macros.info_card(pac_info) }}
@@ -1,13 +1,17 @@
1
1
 
2
2
 
3
3
  from functools import cached_property
4
+ from pathlib import Path
5
+ from urllib.parse import urlparse
6
+ from jinja2 import Environment, FileSystemLoader, select_autoescape
4
7
  from pydantic import BaseModel, Field
5
- from labfreed.pac_attributes.pythonic.py_attributes import pyAttribute, pyAttributeGroup, pyAttributes
8
+ from labfreed.pac_attributes.pythonic.py_attributes import pyAttribute, pyAttributeGroup, pyAttributes, pyReference
6
9
  from labfreed.pac_attributes.well_knonw_attribute_keys import MetaAttributeKeys
7
10
  from labfreed.pac_cat.pac_cat import PAC_CAT
8
11
  from labfreed.pac_id.pac_id import PAC_ID
9
12
  from labfreed.pac_id_resolver.services import ServiceGroup
10
13
  from labfreed.labfreed_extended.app.formatted_print import StringIOLineBreak
14
+ from labfreed.trex.pythonic.data_table import DataTable
11
15
  from labfreed.trex.pythonic.pyTREX import pyTREX
12
16
  from labfreed.well_known_extensions.display_name_extension import DisplayNameExtension
13
17
 
@@ -112,6 +116,39 @@ class PacInfo(BaseModel):
112
116
 
113
117
  return out
114
118
 
119
+
120
+
121
+ def render_html(self, hide_attribute_groups:list[str]=[]) -> str:
122
+ return PACInfo_HTMLRenderer.render_template('pac_info_main.jinja.html',
123
+ pac_info = self,
124
+ hide_attribute_groups=hide_attribute_groups
125
+ )
115
126
 
127
+ def render_html_card(self) -> str:
128
+ return PACInfo_HTMLRenderer.render_template('pac_info_card.jinja.html',
129
+ pac_info = self
130
+ )
131
+
116
132
 
133
+ class PACInfo_HTMLRenderer():
134
+ TEMPLATES_DIR = Path(__file__).parent / "html_renderer"
135
+ jinja_env = Environment(
136
+ loader=FileSystemLoader(str(TEMPLATES_DIR), encoding="utf-8"),
137
+ autoescape=select_autoescape(enabled_extensions=("html", "jinja", "jinja2", "jinja.html")),
138
+ )
139
+
140
+ @classmethod
141
+ def render_template(cls, template_name:str, pac_info:PacInfo, hide_attribute_groups):
142
+ # --- Jinja env pointing at /html_renderer ---
143
+ template = cls.jinja_env.get_template("pac_info.jinja.html")
144
+ html = template.render(
145
+ pac=pac_info.pac_id,
146
+ pac_info=pac_info, # your object
147
+ hide_attribute_groups=hide_attribute_groups,
148
+ is_data_table = lambda value: isinstance(value, DataTable),
149
+ is_url = lambda s: isinstance(s, str) and urlparse(s).scheme in ('http', 'https') and bool(urlparse(s).netloc),
150
+ is_image = lambda s: isinstance(s, str) and s.lower().startswith('http') and s.lower().endswith(('.jpg','.jpeg','.png','.gif','.bmp','.webp','.svg','.tif','.tiff')),
151
+ is_reference = lambda s: isinstance(s, pyReference) ,
152
+ )
153
+ return html
117
154
 
@@ -144,8 +144,9 @@ class AttributeClient():
144
144
 
145
145
 
146
146
  # update cache
147
+ attribute_groups_out = []
147
148
  for ag_for_pac in r.pac_attributes:
148
- pac = PAC_ID.from_url(ag_for_pac.pac_id)
149
+ pac_from_response = PAC_ID.from_url(ag_for_pac.pac_id)
149
150
  ags = [
150
151
  CacheableAttributeGroup(
151
152
  key= ag.key,
@@ -156,13 +157,15 @@ class AttributeClient():
156
157
  state_of=ag.state_of)
157
158
  for ag in ag_for_pac.attribute_groups
158
159
  ]
159
- self.cache_store.update(server_url, pac, ags)
160
+ self.cache_store.update(server_url, pac_from_response, ags)
160
161
 
161
- if pac_id == pac:
162
+ # compare pac_id from response with pac_id we need attributes for.
163
+ # if identical this is the part of the response we care about. other PAC-ID are just for the cache
164
+ if pac_id.to_url() == pac_from_response.to_url():
162
165
  attribute_groups_out = ags
163
- return attribute_groups_out
164
- else:
165
- return []
166
+
167
+ return attribute_groups_out
168
+
166
169
 
167
170
 
168
171
 
@@ -10,6 +10,7 @@ from cachetools import TTLCache, cached
10
10
  from labfreed.pac_attributes.api_data_models.response import AttributeGroup
11
11
  from labfreed.pac_attributes.pythonic.py_attributes import pyAttribute, pyAttributes
12
12
  from labfreed.pac_attributes.server.server import AttributeGroupDataSource
13
+ from labfreed.pac_cat.pac_cat import PAC_CAT
13
14
 
14
15
  try:
15
16
  from openpyxl import load_workbook
@@ -74,8 +75,9 @@ class _BaseExcelAttributeDataSource(AttributeGroupDataSource):
74
75
  Subclasses implement `_read_rows_and_last_changed()`.
75
76
  """
76
77
 
77
- def __init__(self, *, base_url: str = "", cache_duration_seconds: int = 0, **kwargs):
78
+ def __init__(self, *, base_url: str = "", cache_duration_seconds: int = 0, uses_pac_cat_short_form:bool=True, **kwargs):
78
79
  self._base_url = base_url
80
+ self._uses_pac_cat_short_form = uses_pac_cat_short_form
79
81
  # allow instance-level TTL override
80
82
  try:
81
83
  _cache.ttl = int(cache_duration_seconds)
@@ -96,9 +98,14 @@ class _BaseExcelAttributeDataSource(AttributeGroupDataSource):
96
98
  return []
97
99
  return [self._base_url + r for r in rows[0][1:]]
98
100
 
99
- def attributes(self, pac_url: str) -> Optional[AttributeGroup]:
100
- if not self._include_extensions:
101
- pac_url = pac_url.split('*')[0]
101
+ def attributes(self, pac_url:str) -> Optional[AttributeGroup]:
102
+ try:
103
+ p = PAC_CAT.from_url(pac_url)
104
+ pac_url = p.to_url(use_short_notation=self._uses_pac_cat_short_form, include_extensions=self._include_extensions)
105
+ print(f'Lookup in Excel of {pac_url}')
106
+ except:
107
+ ... # might as well try to match the original input
108
+
102
109
  rows, last_changed = self._read_rows_and_last_changed()
103
110
  d = _get_row_by_first_cell(rows, pac_url, self._base_url)
104
111
  if not d:
@@ -1,6 +1,8 @@
1
1
  from abc import ABC, abstractmethod, abstractproperty
2
2
  from datetime import datetime, timezone
3
3
  from labfreed.pac_attributes.api_data_models.response import VALID_FOREVER, AttributeBase, AttributeGroup
4
+ from labfreed.pac_cat.pac_cat import PAC_CAT
5
+ from labfreed.pac_id.pac_id import PAC_ID
4
6
 
5
7
 
6
8
  class AttributeGroupDataSource(ABC):
@@ -29,12 +31,13 @@ class AttributeGroupDataSource(ABC):
29
31
 
30
32
 
31
33
  class Dict_DataSource(AttributeGroupDataSource):
32
- def __init__(self, data:dict[str, list[AttributeBase]], *args, **kwargs):
34
+ def __init__(self, data:dict[str, list[AttributeBase]], uses_pac_cat_short_form=True, *args, **kwargs):
33
35
  if not all([isinstance(e, list) for e in data.values()]):
34
36
  raise ValueError('Invalid data')
35
37
 
36
38
  self._data = data
37
39
  self._state_of = datetime.now(tz=timezone.utc)
40
+ self.uses_pac_cat_short_form = uses_pac_cat_short_form
38
41
 
39
42
  super().__init__(*args, **kwargs)
40
43
 
@@ -45,9 +48,12 @@ class Dict_DataSource(AttributeGroupDataSource):
45
48
 
46
49
 
47
50
  def attributes(self, pac_url: str) -> AttributeGroup:
48
- if not self._include_extensions:
49
- pac_url = pac_url.split('*')[0]
50
-
51
+ try:
52
+ p = PAC_CAT.from_url(pac_url)
53
+ pac_url = p.to_url(use_short_notation=self.uses_pac_cat_short_form, include_extensions=self._include_extensions)
54
+ except:
55
+ ... # might as well try to match the original input
56
+
51
57
  attributes = self._data.get(pac_url)
52
58
  if not attributes:
53
59
  return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labfreed
3
- Version: 1.0.0a2
3
+ Version: 1.0.0a4
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,8 +1,13 @@
1
- labfreed/__init__.py,sha256=o2qxE39XObi_KwNFEMO1fKgVTLltzbQn3tl5YQnhFXg,338
1
+ labfreed/__init__.py,sha256=KvTe62tzFkrePSSCB795dWb5vRFo6eLISovRwLNjT50,338
2
2
  labfreed/labfreed_infrastructure.py,sha256=YZmU-kgopyB1tvpTR_k_uIt1Q2ezexMrWvu-HaP65IE,10104
3
- labfreed/labfreed_extended/app/app_infrastructure.py,sha256=1VMc_Vtjwof9hwzSG95KuIUjT1h7uNsWf_lTORYFFuQ,3981
3
+ labfreed/labfreed_extended/app/app_infrastructure.py,sha256=qn6KesHiOrhTPgXwMZNqFArKlWluxFbk5bgp5u8KDb8,3990
4
4
  labfreed/labfreed_extended/app/formatted_print.py,sha256=DcwWP0ix1e_wYNIdceIp6cETkJdG2DqpU8Gs3aZAL40,1930
5
- labfreed/labfreed_extended/app/pac_info.py,sha256=oiU940sUJiV3yfNLOmkCsn7Go4qui_jijULeHTOFgrg,4163
5
+ labfreed/labfreed_extended/app/pac_info/pac_info.py,sha256=hAMKalOs-v5_5DawtTn63-OZILDJpmFpgw-H6uow5qA,6097
6
+ labfreed/labfreed_extended/app/pac_info/html_renderer/external-link.svg,sha256=H5z9s4VvHq09UnHdqfrYNsx-Whljc0gE4qKJ6-3kfgQ,1158
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
6
11
  labfreed/pac_attributes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
12
  labfreed/pac_attributes/well_knonw_attribute_keys.py,sha256=axE81MeJ3G_Wy1PbmNAXH6SfPtl96NXvQJMyrvK10t4,324
8
13
  labfreed/pac_attributes/api_data_models/request.py,sha256=-CI3rU_Bzw2DZGSS06Jl4zajrxMkfPGhKHWmIfnmWlk,1868
@@ -10,13 +15,13 @@ labfreed/pac_attributes/api_data_models/response.py,sha256=4VliJuKM_r-J-xaLEqfcd
10
15
  labfreed/pac_attributes/api_data_models/server_capabilities_response.py,sha256=ypDm4f8xZZl036fp8PuIe6lJHNW5Zg1fItgUlnV75V0,178
11
16
  labfreed/pac_attributes/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
17
  labfreed/pac_attributes/client/attribute_cache.py,sha256=eWFy7h-T6gd25ENj9pLvSadNFRrzzIineqBoov2cGyw,2688
13
- labfreed/pac_attributes/client/client.py,sha256=Sfvbr8WMW8NOL6_tkWFvU0IybKnzyC0XydmcEFUyb5s,7102
18
+ labfreed/pac_attributes/client/client.py,sha256=J606oYqcJ98NI0w1bSoahys5t7Wxy4CXjJVGUXyj2Zs,7347
14
19
  labfreed/pac_attributes/pythonic/attribute_server_factory.py,sha256=_wasafjBlwvzOaM6-uPgqPethsDQHEpaXoiRW7w9aV0,5759
15
- labfreed/pac_attributes/pythonic/excel_attribute_data_source.py,sha256=mS310M3UOKuv00mJsRAK7acfTdyOw9c-_9UHXKuAqvs,6923
20
+ labfreed/pac_attributes/pythonic/excel_attribute_data_source.py,sha256=Mvn-uIMWZjQJfSOMVY244yCKpnYeR4btc9Pe4BL8_4M,7313
16
21
  labfreed/pac_attributes/pythonic/py_attributes.py,sha256=LoPSH5DWdPTKq-3d2CT-7tTfkqYN9s53sNEeSq_6fHg,5615
17
22
  labfreed/pac_attributes/pythonic/py_dict_data_source.py,sha256=nAz6GA7Xx_0IORPPpt_Wl3sFJa1Q5Fnq5vdf1uQiJF8,531
18
23
  labfreed/pac_attributes/server/__init__.py,sha256=JvQ2kpQx62OUwP18bGhOWYU9an_nQW59Y8Lh7HyfVxY,301
19
- labfreed/pac_attributes/server/attribute_data_sources.py,sha256=bCFqozKBEVdR8etRJjG9RCE5Uea9SMudPN4Mwh-iQr4,2083
24
+ labfreed/pac_attributes/server/attribute_data_sources.py,sha256=gfaERhFrn3SIoSNRiVzchuxpt2ttoe3gw0-fMmv12hU,2448
20
25
  labfreed/pac_attributes/server/server.py,sha256=_Rzi_vzX02o0g03lbm-fdg5AJHJnESDWD7cJEKRFs8w,8841
21
26
  labfreed/pac_attributes/server/translation_data_sources.py,sha256=axALOqfP840sOSdVCRYtrens97mm-hpfONMUyuVlCrY,2145
22
27
  labfreed/pac_cat/__init__.py,sha256=KNPtQzBD1XVohvG_ucOs7RJj-oi6biUTGB1k-T2o6pk,568
@@ -59,7 +64,7 @@ labfreed/well_known_keys/labfreed/well_known_keys.py,sha256=p-hXwEEIs7p2SKn9DQeL
59
64
  labfreed/well_known_keys/unece/UneceUnits.json,sha256=kwfQSp_nTuWbADfBBgqTWrvPl6XtM5SedEVLbMJrM7M,898953
60
65
  labfreed/well_known_keys/unece/__init__.py,sha256=MSP9lmjg9_D9iqG9Yq2_ajYfQSNS9wIT7FXA1c--59M,122
61
66
  labfreed/well_known_keys/unece/unece_units.py,sha256=J20d64H69qKDE3XlGdJoXIIh0G-d0jKoiIDsg9an5pk,1655
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,,
67
+ labfreed-1.0.0a4.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
68
+ labfreed-1.0.0a4.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
69
+ labfreed-1.0.0a4.dist-info/METADATA,sha256=Qn-9eoDdKw6CvJjtaMHWsfShqNI1iqYQkA65GM8A1UA,19740
70
+ labfreed-1.0.0a4.dist-info/RECORD,,