labfreed 0.0.9__py2.py3-none-any.whl → 0.0.11__py2.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/TREX/parse.py CHANGED
@@ -51,78 +51,10 @@ def _from_trex_string(trex_str, name=None, enforce_type=True) -> TREX:
51
51
 
52
52
  data = d.get('data')
53
53
 
54
- segment_strings = data.split('+')
55
- out_segments = list()
56
- for s in segment_strings:
57
- # there are only two valid options. The segment is a scalar or a table.
58
- # Constructors do the parsing anyways and raise exceptions if invalid data
59
- # try both options and then let it fail
60
- segment = _deserialize_table_segment_from_trex_segment_str(s)
61
- if not segment:
62
- segment = _deserialize_value_segment_from_trex_segment_str(s)
63
- if not segment:
64
- raise ValueError('TREX contains neither valid value segment nor table')
65
-
66
- out_segments.append(segment)
67
- trex = TREX(name_= name, segments=out_segments)
68
- trex._trex_str = trex_str
54
+ trex = TREX.from_spec_fields(name=name, data=data)
69
55
 
70
56
  return trex
71
57
 
72
58
 
73
59
 
74
- def _deserialize_value_segment_from_trex_segment_str(trex_segment_str) -> ValueSegment:
75
- #re_scalar_pattern = re.compile(f"(?P<name>[\w\.-]*?)\$(?P<unit>[\w\.]*?):(?P<value>.*)")
76
- re_scalar_pattern = re.compile(f"(?P<name>.+?)\$(?P<unit>.+?):(?P<value>.+)")
77
- matches = re_scalar_pattern.match(trex_segment_str)
78
- if not matches:
79
- return None
80
-
81
- name, type_, value = matches.groups()
82
- out = ValueSegment.get_subclass(type=type_, value=value, key=name)
83
- return out
84
-
85
-
86
- def _deserialize_table_segment_from_trex_segment_str(trex_segment_str) -> TREX_Table:
87
- # re_table_pattern = re.compile(f"(?P<tablename>[\w\.-]*?)\$\$(?P<header>[\w\.,\$:]*?)::(?P<body>.*)")
88
- # re_col_head_pattern = re.compile(f"(?P<name>[\w\.-]*?)\$(?P<unit>[\w\.]*)")
89
- re_table_pattern = re.compile(r"(?P<tablename>.+?)\$\$(?P<header>.+?)::(?P<body>.+)")
90
-
91
- matches = re_table_pattern.match(trex_segment_str)
92
- if not matches:
93
- return None
94
- name, header, body = matches.groups()
95
-
96
- column_headers_str = header.split(':')
97
-
98
- headers = []
99
- for colum_header in column_headers_str:
100
- ch = colum_header.split('$')
101
- col_key = ch[0]
102
- col_type = ch[1] if len(ch) > 1 else ''
103
- headers.append(ColumnHeader(key=col_key, type=col_type))
104
-
105
- data = [row.split(':') for row in body.split('::') ]
106
- col_types = [h.type for h in headers]
107
- # convert to correct value types
108
- data_with_types = [[str_to_value_type(c,t) for c, t in zip(r, col_types)] for r in data]
109
- data = [ TableRow(r) for r in data_with_types]
110
-
111
- out = TREX_Table(column_headers=headers, data=data_with_types, key=name)
112
- return out
113
-
114
-
115
- def str_to_value_type(s:str, t:str):
116
- match t:
117
- case 'T.D': v = DateValue(value=s)
118
- case 'T.B': v = BoolValue(value=s)
119
- case 'T.A': v = AlphanumericValue(value=s)
120
- case 'T.T': v = TextValue(value=s)
121
- case 'T.X': v = BinaryValue(value=s)
122
- case 'E' : v = ErrorValue(value=s)
123
- case _ : v = NumericValue(value=s)
124
- return v
125
-
126
-
127
-
128
60
 
@@ -3,7 +3,6 @@ import json
3
3
  from pathlib import Path
4
4
 
5
5
 
6
-
7
6
  @cache
8
7
  def unece_units() -> list[dict]:
9
8
  p = Path(__file__).parent / 'UneceUnits.json'
@@ -17,6 +16,23 @@ def unece_unit_codes():
17
16
  return codes
18
17
 
19
18
 
19
+ def unece_unit(unit_code):
20
+ unit = [u for u in unece_units() if u['commonCode'] == unit_code]
21
+ if len(unit) == 0:
22
+ return None
23
+ else:
24
+ return unit[0]
25
+
26
+ def unit_symbol(unit:dict) ->str:
27
+ return unit.get('symbol')
28
+
29
+ def unit_name(unit:dict) ->str:
30
+ return unit.get('name')
31
+
32
+
33
+
34
+
35
+
20
36
  # def quantity_from_UN_CEFACT(value:str, unit_UN_CEFACT) -> UnitQuantity:
21
37
  # """
22
38
  # Maps units from https://unece.org/trade/documents/revision-17-annexes-i-iii
labfreed/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
  Python implementation of LabFREED building blocks
3
3
  '''
4
4
 
5
- __version__ = "0.0.9"
5
+ __version__ = "0.0.11"
@@ -2,36 +2,92 @@
2
2
 
3
3
  import re
4
4
  from types import MappingProxyType
5
- from .data_model import *
6
5
 
7
- from ..validation import ValidationMessage, LabFREEDValidationError
6
+ from labfreed.DisplayNameExtension.DisplayNameExtension import DisplayNames
7
+ from labfreed.PAC_CAT.data_model import PAC_CAT
8
+ from labfreed.PAC_ID.extensions import Extension, UnknownExtension
9
+ from labfreed.TREX.data_model import TREX
10
+
11
+
12
+ from .PAC_ID.data_model import *
13
+
14
+ from .validation import ValidationMessage, LabFREEDValidationError
15
+
16
+
17
+
18
+
19
+
20
+
21
+ class PACID_With_Extensions(BaseModelWithValidationMessages):
22
+ pac_id: PACID
23
+ extensions: list[Extension] = Field(default_factory=list)
24
+
25
+ def __str__(self):
26
+ out = str(self.pac_id)
27
+ out += '*'.join(str(e) for e in self.extensions)
28
+
29
+ def get_extension_of_type(self, type:str) -> list[Extension]:
30
+ return [e for e in self.extensions if e.type == type]
31
+
32
+ def get_extension(self, name:str) -> Extension|None:
33
+ out = [e for e in self.extensions if e.name == name]
34
+ if not out:
35
+ return None
36
+ return out[0]
37
+
38
+
39
+ def serialize(self, use_short_notation_for_extensions=False, uppercase_only=False):
40
+ extensions_str = self._serialize_extensions(self.extensions, use_short_notation_for_extensions)
41
+ out = self.pac_id.serialize() + extensions_str
42
+ if uppercase_only:
43
+ out = out.upper()
44
+ return out
45
+
46
+ def to_url(self, use_short_notation_for_extensions=False, uppercase_only=False) -> str:
47
+ return self.serialize(use_short_notation_for_extensions, uppercase_only)
48
+
49
+ @classmethod
50
+ def deserialize(cls, url, extension_interpreters ):
51
+ parser = PAC_Parser(extension_interpreters)
52
+ return parser.parse_pac_with_extensions(url)
53
+
54
+
55
+
56
+
57
+ def _serialize_extensions(self, extensions:list[Extension], use_short_notation_for_extensions):
58
+ out = ''
59
+ short_notation = use_short_notation_for_extensions
60
+ for i, e in enumerate(extensions):
61
+
62
+ if short_notation and i==0:
63
+ if e.name=='N':
64
+ out += f'*{e.data}'
65
+ continue
66
+ else:
67
+ short_notation = False
68
+ if short_notation and i==1:
69
+ if e.name=='SUM':
70
+ out += f'*{e.data}'
71
+ continue
72
+ else:
73
+ short_notation = False
74
+
75
+ out += f'*{e.name}${e.type}/{e.data}'
76
+ return out
77
+
8
78
 
9
79
 
10
- category_conventions = MappingProxyType(
11
- {
12
- '-MD': ['240', '21'],
13
- '-MS': ['240', '10', '20', '21', '250'],
14
- '-MC': ['240', '10', '20', '21', '250'],
15
- '-MM': ['240', '10', '20', '21', '250']
16
- }
17
- )
18
80
 
19
81
 
20
- extension_convention = MappingProxyType(
21
- {
22
- 0: { 'name': 'N', 'type': 'N'},
23
- 1: { 'name': 'SUM', 'type': 'TREX'}
24
- }
25
- )
26
82
 
27
83
 
28
84
 
29
85
  class PAC_Parser():
30
86
 
31
87
  def __init__(self, extension_interpreters:dict[str, Extension]=None):
32
- self.extension_interpreters = extension_interpreters or {}
88
+ self.extension_interpreters = extension_interpreters or {'TREX': TREX, 'N': DisplayNames}
33
89
 
34
- def parse_pac_url(self, pac_url:str) -> tuple[PACID_With_Extensions, list[ValidationMessage] ]:
90
+ def parse_pac_with_extensions(self, pac_url:str) -> PACID_With_Extensions:
35
91
  if '*' in pac_url:
36
92
  id_str, ext_str = pac_url.split('*', 1)
37
93
  else:
@@ -42,14 +98,34 @@ class PAC_Parser():
42
98
  extensions = self.parse_extensions(ext_str)
43
99
 
44
100
  pac_with_extension = PACID_With_Extensions(pac_id=pac_id, extensions=extensions)
45
- pac_with_extension.print_validation_messages(pac_url)
46
101
  if not pac_with_extension.is_valid():
47
102
  raise LabFREEDValidationError(validation_msgs = pac_with_extension.get_nested_validation_messages())
48
103
 
49
104
  return pac_with_extension
50
105
 
51
106
 
52
- def parse_id_segments(self, identifier:str):
107
+ def parse_pac_id(self,id_str:str) -> PACID:
108
+ m = re.match(f'(HTTPS://)?(PAC.)?(?P<issuer>.+?\..+?)/(?P<identifier>.*)', id_str)
109
+ d = m.groupdict()
110
+
111
+ id_segments = list()
112
+ default_keys = None
113
+ id_segments = self._parse_id_segments(d.get('identifier'))
114
+
115
+ pac = PACID(issuer= d.get('issuer'),
116
+ identifier=id_segments
117
+ )
118
+
119
+ # if a segment starts with '-' the pac is interpreted as category
120
+ if any([s for s in pac.identifier if '-' in s.value]):
121
+ pac = PAC_CAT.from_pac_id(pac)
122
+
123
+ return pac
124
+
125
+
126
+
127
+
128
+ def _parse_id_segments(self, identifier:str):
53
129
  if not identifier:
54
130
  return []
55
131
 
@@ -70,45 +146,21 @@ class PAC_Parser():
70
146
  return id_segments
71
147
 
72
148
 
73
- def _apply_category_defaults(self, segments_in: list[IDSegment]):
74
-
75
- segments = segments_in.copy()
76
- default_keys = None
77
- for s in segments:
78
- if not s.key and default_keys:
79
- s.key = default_keys.pop(0)
80
- else:
81
- default_keys = None
82
-
83
- # category starts: start with new defaults.
84
- if s.value in category_conventions.keys():
85
- default_keys = category_conventions.get(s.value).copy() #copy, so the entries can be popped when used
86
- return segments
87
-
88
-
89
-
90
- def parse_pac_id(self,id_str:str) -> PACID:
91
- m = re.match(f'(HTTPS://)?(PAC.)?(?P<issuer>.+?\..+?)/(?P<identifier>.*)', id_str)
92
- d = m.groupdict()
93
-
94
- id_segments = list()
95
- default_keys = None
96
- id_segments = self.parse_id_segments(d.get('identifier'))
97
- id_segments = self._apply_category_defaults(id_segments)
98
-
99
- pac = PACID(issuer= d.get('issuer'),
100
- identifier=Identifier(segments=id_segments)
101
- )
102
- return pac
103
149
 
104
150
 
105
151
  def parse_extensions(self, extensions_str:str|None) -> list[Extension]:
152
+
106
153
  extensions = list()
107
154
 
108
155
  if not extensions_str:
109
156
  return extensions
110
157
 
111
- defaults = extension_convention
158
+ defaults = MappingProxyType(
159
+ {
160
+ 0: { 'name': 'N', 'type': 'N'},
161
+ 1: { 'name': 'SUM', 'type': 'TREX'}
162
+ }
163
+ )
112
164
  for i, e in enumerate(extensions_str.split('*')):
113
165
  if e == '': #this will happen if first extension starts with *
114
166
  continue
@@ -134,11 +186,4 @@ class PAC_Parser():
134
186
 
135
187
  return extensions
136
188
 
137
-
138
-
139
-
140
-
141
- if __name__ == "__main__":
142
- pacid_str = 'HTTPS://PAC.METTORIUS.COM/-DR/AB378/-MD/B-500/1235/-MS/AB/X:88/WWW/-MS/240:11/BB*ABCFD*A$HUR:25+B$CEL:99*BLUBB$TREX/A$HUR:25+B$CEL:99'
143
-
144
- pac = PAC_Parser().parse_pac(pacid_str)
189
+
@@ -1,31 +1,37 @@
1
+ import re
1
2
  import string
2
3
 
3
- def alphabet(base):
4
- """ returns an alphabet, which corresponds to what pythons int(s:str, base:int=10) function used.
5
- """
6
- if base < 2 or base > 36:
7
- ValueError('base can only be between 2 and 36')
8
- alphabet = (string.digits + string.ascii_uppercase)[0:base]
9
- return alphabet
4
+ from pydantic import field_validator, RootModel
5
+
6
+ class base36(RootModel[str]):
7
+ @field_validator('root')
8
+ @classmethod
9
+ def validate_format(cls, v: str) -> str:
10
+ if not re.fullmatch(r'[A-Z0-9]*', v):
11
+ raise ValueError("Value must only contain uppercase letters and digits (A-Z, 0-9)")
12
+ return v
13
+
10
14
 
11
- def to_base36(s:str):
15
+ def to_base36(s:str) -> base36:
12
16
  """Takes a string, encodes it in UTF-8 and then as base36 string."""
13
17
  utf8_encoded = s.encode('utf-8')
14
18
  num = int.from_bytes(utf8_encoded, byteorder='big', signed=False)
15
19
 
16
20
  # note: this cannot be arbitrarily chosen. The choice here corresponds to what pythons int(s:str, base:int=10) function used.
17
- base36_chars = alphabet(base=36)
21
+ base36_chars = _alphabet(base=36)
18
22
  if num == 0:
19
23
  return base36_chars[0]
20
- base36 = []
24
+ base_36 = []
21
25
  _num = num
22
26
  while _num:
23
27
  _num, i = divmod(_num, 36)
24
- base36.append(base36_chars[i])
25
- return ''.join(reversed(base36))
28
+ base_36.append(base36_chars[i])
29
+ b36_str = ''.join(reversed(base_36))
30
+ b36_str = base36(b36_str)
31
+ return b36_str
26
32
 
27
33
 
28
- def from_base36(s36:str):
34
+ def from_base36(s36:base36) -> str:
29
35
  """inverse of to_base36"""
30
36
  # this built in function interprets each character as number in a base represented by the standartd alphabet [0-9 (A-Z|a-z)][0:base] it is case INsensitive.
31
37
  num = int(s36, 36)
@@ -34,6 +40,16 @@ def from_base36(s36:str):
34
40
  s = _bytes.decode('utf-8')
35
41
  return s
36
42
 
43
+
44
+ def _alphabet(base):
45
+ """ returns an alphabet, which corresponds to what pythons int(s:str, base:int=10) function used.
46
+ """
47
+ if base < 2 or base > 36:
48
+ ValueError('base can only be between 2 and 36')
49
+ alphabet = (string.digits + string.ascii_uppercase)[0:base]
50
+ return alphabet
51
+
52
+
37
53
  if __name__ == "__main__":
38
54
  ss = ["A",
39
55
  "B-500 B",
@@ -0,0 +1,4 @@
1
+ from labfreed.DisplayNameExtension.DisplayNameExtension import DisplayNames
2
+ from labfreed.TREX.data_model import TREX
3
+
4
+
@@ -0,0 +1,103 @@
1
+ from functools import cache
2
+ import json
3
+ from pathlib import Path
4
+
5
+ from rich import print
6
+
7
+ from typing import Any, Tuple
8
+ from typing_extensions import Annotated
9
+ from pydantic import BaseModel, AfterValidator
10
+ import quantities as pq
11
+ from quantities import units
12
+
13
+ from labfreed.TREX.unece_units import unece_units
14
+
15
+ def validate_unit(unit_name:str) -> str :
16
+ """
17
+ Pydantic validator function for the unit.
18
+ Checks if the unit is a valid unit.
19
+
20
+
21
+ Args:
22
+ unit (str): unit symbol, e.g. 'kg'
23
+
24
+ Returns:
25
+ str: the input unit.
26
+
27
+ Errors:
28
+ raises an AssertionError if validation fails
29
+ """
30
+ if hasattr(pq, unit_name):
31
+ return unit_name
32
+ else:
33
+ assert False
34
+
35
+
36
+ class Unit(BaseModel):
37
+ name: str
38
+ symbol: str
39
+
40
+
41
+ class Quantity(BaseModel):
42
+ value:int|float
43
+ unit: Unit
44
+
45
+ def __str__(self):
46
+ unit_symbol = self.unit.symbol
47
+ if unit_symbol == "dimensionless":
48
+ unit_symbol = ""
49
+
50
+ s = f"{str(self.value)} {unit_symbol}"
51
+ return s
52
+
53
+
54
+ def unece_unit_code_from_quantity(q:Quantity):
55
+ by_name = [ u['commonCode'] for u in unece_units() if u.get('name','') == q.unit.name]
56
+ by_symbol = [ u['commonCode'] for u in unece_units() if u.get('symbol','') == q.unit.symbol]
57
+ code = list(set(by_name) | set(by_symbol))
58
+ if len(code) != 1:
59
+ raise ValueError(f'No UNECE unit code found for Quantity {str(q)}' )
60
+ return code[0]
61
+
62
+
63
+ # class DataTable(list):
64
+ # def __init__(self, headers:tuple[str, Any]):
65
+ # for h in headers:
66
+ # if len(h) != 2:
67
+ # raise ValueError(f'Headers must be tuples of length two. With a column name and type.')
68
+ # if not isinstance(h[0], str):
69
+ # raise ValueError(f'Invalid type of header name {h[0]}. Must be str')
70
+ # if not (h[1]):
71
+ # raise ValueError(f'Header type cannot be None')
72
+ # self.headers = headers
73
+ # super().__init__()
74
+
75
+ # def append(self, row:list):
76
+ # if len(row) != len(self.headers):
77
+ # raise ValueError(f'Row has different length than headers')
78
+ # super().append(row)
79
+
80
+ class DataTable(list):
81
+ def __init__(self, col_names:list[str]=None):
82
+ self.col_names = col_names
83
+ self.row_template = None
84
+ super().__init__()
85
+
86
+ def append(self, row:list):
87
+ if not self.row_template:
88
+ self.row_template = row.copy()
89
+ super().append(row)
90
+
91
+ def extend(self, iterable):
92
+ for item in iterable:
93
+ self.append(item)
94
+
95
+
96
+
97
+
98
+ if __name__ == "__main__":
99
+ pass
100
+
101
+
102
+
103
+
@@ -1,7 +1,7 @@
1
1
  from enum import Enum
2
2
 
3
3
 
4
- class WellKnownSegmentKeys(Enum):
4
+ class WellKnownKeys(Enum):
5
5
  GTIN = '01'
6
6
  BATCH = '10'
7
7
  SERIAL = '21'
labfreed/validation.py CHANGED
@@ -113,7 +113,9 @@ class BaseModelWithValidationMessages(BaseModel):
113
113
  return filter_warnings(self.get_nested_validation_messages())
114
114
 
115
115
 
116
- def print_validation_messages(self, str_to_highlight_in):
116
+ def print_validation_messages(self, str_to_highlight_in=None):
117
+ if not str_to_highlight_in:
118
+ str_to_highlight_in = str(self)
117
119
  msgs = self.get_nested_validation_messages()
118
120
  print('\n'.join(['\n',
119
121
  '=======================================',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labfreed
3
- Version: 0.0.9
3
+ Version: 0.0.11
4
4
  Summary: Python implementation of LabFREED building blocks
5
5
  Author-email: Reto Thürer <thuerer.r@buchi.com>
6
6
  License-Expression: MIT
@@ -0,0 +1,22 @@
1
+ labfreed/__init__.py,sha256=tRirlmqlRWmM41CGkaBq1os_KepqXPPCnouvqpWHAvg,88
2
+ labfreed/parse_pac.py,sha256=HA3-jAnw2crsXMW_D7Tw-z99qnUWL5MBQVXEzdYP2m4,6287
3
+ labfreed/validation.py,sha256=QwkZWJhAjWbPUZtJJwjVYsw9TxeFhdbZaKjrPPIpuAA,5937
4
+ labfreed/DisplayNameExtension/DisplayNameExtension.py,sha256=l9JZY2eRS0V-H5h3-WXIHiiBJuljns-_e_t9Bp84_CU,1155
5
+ labfreed/PAC_CAT/__init__.py,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
6
+ labfreed/PAC_CAT/data_model copy.py,sha256=JWMVkwkX9vWZayOLOzdTHk3VZVYBuyupumNqL-cWCxU,9611
7
+ labfreed/PAC_CAT/data_model.py,sha256=pcib1lEQuqejWP7dfmPUtLakz-y-zeDb9CIe94Jmz0A,13677
8
+ labfreed/PAC_ID/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ labfreed/PAC_ID/data_model.py,sha256=g09qgC-TV6fjJw9VyDF6mTJ6co2i2RKZc0Z-BmiiUIQ,7483
10
+ labfreed/PAC_ID/extensions.py,sha256=bvuZnlNKUdwsDLrPm8fyifqPn_PR4wCVkkScFnvRiuM,1158
11
+ labfreed/TREX/UneceUnits.json,sha256=kwfQSp_nTuWbADfBBgqTWrvPl6XtM5SedEVLbMJrM7M,898953
12
+ labfreed/TREX/data_model.py,sha256=_xhnYGMcMPa0uf_020epq88zqHT1wdsUPC2ELJcSRWE,29684
13
+ labfreed/TREX/parse.py,sha256=86962VEJpkrTcT436iFIB5dNed5WHABzpjxRjkA3PXo,2043
14
+ labfreed/TREX/unece_units.py,sha256=scPKdsPzY1neAdFOhA08_tRZaR-yplM8mBhIzzDqZBk,3006
15
+ labfreed/utilities/base36.py,sha256=_yX8aQ1OwrK5tnJU1NUEzQSFGr9xAVnNvPObpNzCPYs,2895
16
+ labfreed/utilities/extension_intertpreters.py,sha256=B3IFJLfVMJQuPfBBtX6ywlDUZEi7_x6tY4g8V7SpWSs,124
17
+ labfreed/utilities/utility_types.py,sha256=Zhk8Mu4hHjkn1gs8oh7vOxxaT7L7wLMVG40ZOWCKGK4,2865
18
+ labfreed/utilities/well_known_keys.py,sha256=nqk66kHdSwJTJfMKlP-xQbBglS8F_NoWsGkfOVITFN0,331
19
+ labfreed-0.0.11.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
20
+ labfreed-0.0.11.dist-info/WHEEL,sha256=BXjIu84EnBiZ4HkNUBN93Hamt5EPQMQ6VkF7-VZ_Pu0,100
21
+ labfreed-0.0.11.dist-info/METADATA,sha256=G-lDt39hiUI8Sup2HPxXxuyPmrLZCvDXxQCXrFNpU_Y,207
22
+ labfreed-0.0.11.dist-info/RECORD,,
@@ -1,60 +0,0 @@
1
-
2
- from .data_model import *
3
-
4
-
5
-
6
- class PAC_Serializer():
7
- def to_url(self, pac:PACID|PACID_With_Extensions, extensions:list[Extension]=None, use_short_notation_for_extensions=False, uppercase_only=False) -> str:
8
- if isinstance(pac, PACID_With_Extensions):
9
- if extensions:
10
- raise ValueError('Extensions were given twice, as part of PACID_With_Extension and as method parameter.')
11
- extensions = pac.extensions
12
- pac = pac.pac_id
13
- issuer = pac.issuer
14
- extensions_str = self._serialize_extensions(extensions, use_short_notation_for_extensions)
15
- id_segments = self._serialize_id_segments(pac.identifier.segments)
16
- out = f"HTTPS://PAC.{issuer}{id_segments}{extensions_str}"
17
- if uppercase_only:
18
- out = out.upper()
19
- return out
20
-
21
-
22
- def _serialize_id_segments(self, segments):
23
- out = ''
24
- for s in segments:
25
- if s.key:
26
- out += f'/{s.key}:{s.value}'
27
- else:
28
- out += f'/{s.value}'
29
- return out
30
-
31
-
32
- def _serialize_extensions(self, extensions:list[Extension], use_short_notation_for_extensions):
33
- out = ''
34
- short_notation = use_short_notation_for_extensions
35
- for i, e in enumerate(extensions):
36
-
37
- if short_notation and i==0:
38
- if e.name=='N':
39
- out += f'*{e.data}'
40
- continue
41
- else:
42
- short_notation = False
43
- if short_notation and i==1:
44
- if e.name=='SUM':
45
- out += f'*{e.data}'
46
- continue
47
- else:
48
- short_notation = False
49
-
50
- out += f'*{e.name}${e.type}/{e.data}'
51
- return out
52
-
53
-
54
-
55
- def main():
56
- pass
57
-
58
-
59
- if __name__ == "__main__":
60
- main()
@@ -1,3 +0,0 @@
1
- from .data_model import TREX
2
- def serialize_as_trex_str(trex:TREX):
3
- return trex.data
@@ -1,32 +0,0 @@
1
- from math import floor, log10, pow
2
-
3
- def to_significant_digits_str(x:int|float, uncertainty:float|int) -> str:
4
- if uncertainty == None:
5
- if isinstance(x, float):
6
- Warning(f'Uncertainty was given as none. Returning unrounded number')
7
- return str(x)
8
- else:
9
- uncertainty = 1
10
-
11
-
12
- log_least_significant_digit = floor(log10(uncertainty))
13
- digits = -log_least_significant_digit
14
-
15
- x_significant = round(x, digits)
16
-
17
- if digits <= 0:
18
- return str(int(x_significant))
19
- else:
20
- return str(x_significant)
21
-
22
-
23
-
24
- if __name__ == "__main__":
25
- print(to_significant_digits_str(111111.1111111, 1000))
26
- print(to_significant_digits_str(111111.1111111, 100))
27
- print(to_significant_digits_str(111111.1111111, 10))
28
- print(to_significant_digits_str(111111.1111111, 1))
29
- print(to_significant_digits_str(111111.1111111, 0.1))
30
- print(to_significant_digits_str(111111.1111111, 0.01))
31
- print(to_significant_digits_str(111111.1111111, 0.001))
32
- print(to_significant_digits_str(111111.1111111, 0.0001))