ucon 0.6.1__py3-none-any.whl → 0.6.3__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.
ucon/units.py CHANGED
@@ -204,6 +204,15 @@ def have(name: str) -> bool:
204
204
  _UNIT_REGISTRY: Dict[str, Unit] = {}
205
205
  _UNIT_REGISTRY_CASE_SENSITIVE: Dict[str, Unit] = {}
206
206
 
207
+ # Priority aliases that must match exactly before prefix decomposition.
208
+ # Prevents ambiguous parses like "min" -> milli-inch instead of minute.
209
+ _PRIORITY_ALIASES: set = {'min'}
210
+
211
+ # Priority scaled aliases that map to a specific (unit, scale) tuple.
212
+ # Used for medical conventions like "mcg" -> (gram, Scale.micro).
213
+ # Populated by _build_registry() after units are defined.
214
+ _PRIORITY_SCALED_ALIASES: Dict[str, Tuple[Unit, Scale]] = {}
215
+
207
216
  # Scale prefix mapping (shorthand -> Scale)
208
217
  # Sorted by length descending for greedy matching
209
218
  _SCALE_PREFIXES: Dict[str, Scale] = {
@@ -256,6 +265,9 @@ def _build_registry() -> None:
256
265
  _UNIT_REGISTRY[alias.lower()] = obj
257
266
  _UNIT_REGISTRY_CASE_SENSITIVE[alias] = obj
258
267
 
268
+ # Register priority scaled aliases (medical conventions)
269
+ _PRIORITY_SCALED_ALIASES['mcg'] = (gram, Scale.micro) # microgram
270
+
259
271
 
260
272
  def _parse_exponent(s: str) -> Tuple[str, float]:
261
273
  """
@@ -294,7 +306,10 @@ def _lookup_factor(s: str) -> Tuple[Unit, Scale]:
294
306
  """
295
307
  Look up a single unit factor, handling scale prefixes.
296
308
 
297
- Prioritizes prefix+unit interpretation over direct unit lookup.
309
+ Prioritizes prefix+unit interpretation over direct unit lookup,
310
+ except for priority aliases (like 'min', 'mcg') which are checked first
311
+ to avoid ambiguous parses or to handle domain-specific conventions.
312
+
298
313
  This means "kg" returns (gram, Scale.kilo) rather than (kilogram, Scale.one).
299
314
 
300
315
  Examples:
@@ -303,6 +318,8 @@ def _lookup_factor(s: str) -> Tuple[Unit, Scale]:
303
318
  - 'km' -> (meter, Scale.kilo)
304
319
  - 'kg' -> (gram, Scale.kilo)
305
320
  - 'mL' -> (liter, Scale.milli)
321
+ - 'min' -> (minute, Scale.one) # priority alias, not milli-inch
322
+ - 'mcg' -> (gram, Scale.micro) # medical convention for microgram
306
323
 
307
324
  Returns:
308
325
  Tuple of (unit, scale).
@@ -310,7 +327,19 @@ def _lookup_factor(s: str) -> Tuple[Unit, Scale]:
310
327
  Raises:
311
328
  UnknownUnitError: If the unit cannot be resolved.
312
329
  """
313
- # Try scale prefix + unit first (prioritize decomposition)
330
+ # Check priority scaled aliases first (e.g., "mcg" -> microgram)
331
+ if s in _PRIORITY_SCALED_ALIASES:
332
+ return _PRIORITY_SCALED_ALIASES[s]
333
+
334
+ # Check priority aliases (prevents "min" -> milli-inch)
335
+ if s in _PRIORITY_ALIASES:
336
+ if s in _UNIT_REGISTRY_CASE_SENSITIVE:
337
+ return _UNIT_REGISTRY_CASE_SENSITIVE[s], Scale.one
338
+ s_lower = s.lower()
339
+ if s_lower in _UNIT_REGISTRY:
340
+ return _UNIT_REGISTRY[s_lower], Scale.one
341
+
342
+ # Try scale prefix + unit (prioritize decomposition)
314
343
  # Only case-sensitive matching for remainder (e.g., "fT" = femto-tesla, "ft" = foot)
315
344
  for prefix in _SCALE_PREFIXES_SORTED:
316
345
  if s.startswith(prefix) and len(s) > len(prefix):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ucon
3
- Version: 0.6.1
3
+ Version: 0.6.3
4
4
  Summary: A tool for dimensional analysis: a 'Unit CONverter'
5
5
  Home-page: https://github.com/withtwoemms/ucon
6
6
  Author: Emmanuel I. Obi
@@ -5,13 +5,13 @@ ucon/graph.py,sha256=vBIKwppYCAu5sw6R_3zTBlnOk2WmYMClIb6j5kDvJHI,21342
5
5
  ucon/maps.py,sha256=-rPMOHylcQYUn62R9IU23bXdCRCRNBhdH3UD4G5IUEk,9123
6
6
  ucon/pydantic.py,sha256=64ZR1EYFRnBGHj3VIF5pc3swdAiR2ZlYrgcntdbKN4k,5189
7
7
  ucon/quantity.py,sha256=GBxZ_96nocx-8F-usNWGbPvWHRhRgdZzqfH9Sx69iC4,465
8
- ucon/units.py,sha256=49Xart5orKUKOKs0vIIWoEs9n4jrJBLdyomi9Y4dvqY,16006
8
+ ucon/units.py,sha256=vKHGf5UX-g9t8dKy2IXgutHZD7W9frYdXSef_aPgZgo,17329
9
9
  ucon/mcp/__init__.py,sha256=WoFOQ7JeDIzbjjkFIJ0Uv53VVLu-4lrjzG5vpVGGfT4,123
10
10
  ucon/mcp/server.py,sha256=uUrdevEaR65Qjh9xn8Q-_IusNjPGxdkLF9iQmiSTs0g,7016
11
- ucon-0.6.1.dist-info/licenses/LICENSE,sha256=LtimSYBSw1L_X6n1-VEdZRdwuROzPumrMUNX21asFuI,11356
12
- ucon-0.6.1.dist-info/licenses/NOTICE,sha256=bh4fBOItio3kM4hSNYhqfFpcaAvOoixjD7Du8im-sYA,1079
13
- ucon-0.6.1.dist-info/METADATA,sha256=IxzC5b5a8THVSZFfx9nr-vtU534Atj5vVT5lruQKdgQ,17397
14
- ucon-0.6.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
- ucon-0.6.1.dist-info/entry_points.txt,sha256=jbfLf0FbOulgGa0nM_sRiTNfiCAkJcHnSSK_oj3g0cQ,50
16
- ucon-0.6.1.dist-info/top_level.txt,sha256=Vv3KDuZ86fmH5yOYLbYap9DbBblK1YUkmlThffF71jA,5
17
- ucon-0.6.1.dist-info/RECORD,,
11
+ ucon-0.6.3.dist-info/licenses/LICENSE,sha256=LtimSYBSw1L_X6n1-VEdZRdwuROzPumrMUNX21asFuI,11356
12
+ ucon-0.6.3.dist-info/licenses/NOTICE,sha256=bh4fBOItio3kM4hSNYhqfFpcaAvOoixjD7Du8im-sYA,1079
13
+ ucon-0.6.3.dist-info/METADATA,sha256=8GNTOLltkPWCt68V7-dauFzK_e-XngBhCNlVXpBz_rw,17397
14
+ ucon-0.6.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
+ ucon-0.6.3.dist-info/entry_points.txt,sha256=jbfLf0FbOulgGa0nM_sRiTNfiCAkJcHnSSK_oj3g0cQ,50
16
+ ucon-0.6.3.dist-info/top_level.txt,sha256=Vv3KDuZ86fmH5yOYLbYap9DbBblK1YUkmlThffF71jA,5
17
+ ucon-0.6.3.dist-info/RECORD,,
File without changes