unitx 0.6.3__tar.gz → 0.7.0__tar.gz
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.
- {unitx-0.6.3 → unitx-0.7.0}/CHANGELOG.md +64 -0
- {unitx-0.6.3 → unitx-0.7.0}/PKG-INFO +88 -12
- {unitx-0.6.3 → unitx-0.7.0}/README.md +87 -11
- {unitx-0.6.3 → unitx-0.7.0}/pyproject.toml +1 -1
- {unitx-0.6.3 → unitx-0.7.0}/pyrightconfig.json +3 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/_unicode.py +5 -4
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/quantity.py +7 -2
- unitx-0.7.0/src/unitx/si/bases.py +91 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/si/constants.py +57 -71
- unitx-0.7.0/src/unitx/si/units.py +178 -0
- unitx-0.7.0/src/unitx/singleunit.py +160 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/unit.py +23 -14
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/unitparser.py +47 -16
- unitx-0.7.0/src/unitx/unitregistry.py +305 -0
- unitx-0.6.3/tests/test_unit_data.py → unitx-0.7.0/tests/test_builtin_definitions.py +21 -21
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_quantity.py +2 -1
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_si.py +60 -1
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_singleunit.py +35 -15
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_unit_definition.py +51 -44
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_unitparser.py +78 -0
- unitx-0.7.0/tests/test_unitregistry.py +204 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/typing/check_quantity.py +19 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/typing/check_si.py +4 -0
- unitx-0.6.3/src/unitx/_unit_data.py +0 -193
- unitx-0.6.3/src/unitx/si/units.py +0 -193
- unitx-0.6.3/src/unitx/singleunit.py +0 -208
- {unitx-0.6.3 → unitx-0.7.0}/.github/workflows/ci.yml +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/.github/workflows/release.yml +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/.gitignore +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/LICENSE +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/conftest.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/__init__.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/_constclass.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/_numerics.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/dimension.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/exceptions.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/factor.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/monomial.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/py.typed +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/src/unitx/si/__init__.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/__init__.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_dimension.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_factor.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_import.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_monomial.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_numeric.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_typing.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_unicode.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_unit.py +0 -0
- {unitx-0.6.3 → unitx-0.7.0}/tests/test_warnings.py +0 -0
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.0] - 2026-10-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Add `[registered name]` references as single factors in unit expressions,
|
|
8
|
+
including products, reciprocals, parentheses, and rational powers. References
|
|
9
|
+
resolve names and name aliases only, with whitespace normalization and no
|
|
10
|
+
expression evaluation or nested quoting.
|
|
11
|
+
- Support standalone hyphenated names and adjacent Unicode integer superscripts
|
|
12
|
+
such as `m²`, `s⁻¹²`, and `[metre]²`.
|
|
13
|
+
- Extend `prefixable: PrefixPolicy = True` on all `.define()` entry points to
|
|
14
|
+
accept a tuple of exact registered symbols, names, or aliases. Only those
|
|
15
|
+
spellings accept prefixes; True enables all spellings and False or () disables
|
|
16
|
+
all spellings. `PrefixPolicy` is `bool | tuple[str, ...]`.
|
|
17
|
+
- Enable prefixes on `arcsec` and `arcsecond` while keeping angle punctuation
|
|
18
|
+
unprefixable. Register unprefixable are (`a`) and hectare (`ha`), and reactive
|
|
19
|
+
power (`var`, name `volt-ampere reactive`). Keep `as` as attosecond and `yr`
|
|
20
|
+
as a 365-day year.
|
|
21
|
+
- Add the Julian year `a_j` (exactly 31,557,600 seconds) and its twelfth,
|
|
22
|
+
`mo`, as a fixed month interval distinct from variable calendar months.
|
|
23
|
+
- Add light year (`ly`), unified atomic mass unit (`u`), and common prefixed
|
|
24
|
+
namespace attributes, including attosecond (`as_`) and petaelectronvolt (`PeV`).
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Move definitions, spelling resolution, and registration validation into
|
|
29
|
+
`unitx.unitregistry`, shared by SingleUnit and UnitParser. Preserve formal identities,
|
|
30
|
+
exact SI factors, existing `.define()` defaults, and validation before mutation.
|
|
31
|
+
- Remove the superseded private `_unit_data` module. Name definition records
|
|
32
|
+
`PrefixDefinition` and `UnitDefinition`, with explicit definition indexes and
|
|
33
|
+
alias-to-symbol mappings.
|
|
34
|
+
- Select permitted canonical output spellings after applying binding policies.
|
|
35
|
+
When only a name permits a prefix, expressions use `[name]` so repr and pickle
|
|
36
|
+
preserve the prefixed identity. Expose `PrefixPolicy` for type annotations.
|
|
37
|
+
- Use the finite spelling exceptions `megohm` and `kilohm` in preferred names,
|
|
38
|
+
retaining `megaohm` and `kiloohm` as accepted inputs.
|
|
39
|
+
- Reuse Unicode superscript tables, handle malformed name brackets through
|
|
40
|
+
the common lexical error path, and simplify definition initialization,
|
|
41
|
+
preferred spelling selection, and generated prefix-name validation.
|
|
42
|
+
- Share coherent SI units and the seven defining constants through private
|
|
43
|
+
bases. Derive `ly` from `c` and the Julian year, and `eV` from `e` and `V`,
|
|
44
|
+
preserving the public `si` and `SI` namespaces and constant magnitude types.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- Register metre of mercury (`mHg`) as the prefixable unit and construct `mmHg`
|
|
49
|
+
from its milli prefix. Preserve `760 mmHg = 1 atm` and the existing Torr scale,
|
|
50
|
+
keep the definition exact, and reject stacked prefixes such as `kmmHg`.
|
|
51
|
+
|
|
52
|
+
### Migration
|
|
53
|
+
|
|
54
|
+
- Square brackets and `⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻` are now reserved grammar characters and can
|
|
55
|
+
no longer occur in registered symbols or names. Rename custom spellings that
|
|
56
|
+
previously used them before rebuilding or unpickling those definitions.
|
|
57
|
+
- Long names remain whole-input lookups unless explicitly referenced in brackets.
|
|
58
|
+
`str()` remains readable display and is not a general serialization format;
|
|
59
|
+
use `expression()` for formal unit products and repr for ScaledUnit state.
|
|
60
|
+
- `mmHg` now has the formal identity of milli-prefixed `mHg`; rebuild stored
|
|
61
|
+
units when moving between versions. Its pressure conversion scale is unchanged.
|
|
62
|
+
`kmmHg` and names with repeated prefixes are no longer accepted.
|
|
63
|
+
- Registering `u` makes ASCII micro spellings such as `um` issue the existing
|
|
64
|
+
ambiguity warning. Their meaning is unchanged; use `µm`, `μm`, or `micrometre`
|
|
65
|
+
to avoid the warning. `kt` remains a knot alias and tonne stays unprefixable.
|
|
66
|
+
|
|
3
67
|
## [0.6.3] - 2026-10-18
|
|
4
68
|
|
|
5
69
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: unitx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: A modern, intuitive Python library for units, quantities, and dimensional analysis.
|
|
5
5
|
Project-URL: Homepage, https://github.com/DaitTHU/unitx
|
|
6
6
|
Project-URL: Issues, https://github.com/DaitTHU/unitx/issues
|
|
@@ -246,14 +246,25 @@ False
|
|
|
246
246
|
token: `ms` is a millisecond, while `m s` is metre times second.
|
|
247
247
|
- Powers can use adjacent numbers, `^`, or `**`. Exponents written as ratios
|
|
248
248
|
require parentheses, as in `m^(1/2)`; decimal exponents such as `m^0.5` are exact.
|
|
249
|
+
Adjacent integer superscripts are also accepted: `m²`, `s⁻¹²`, and `(m/s)²`.
|
|
250
|
+
Superscript fractions and mixed exponent notations are not supported.
|
|
249
251
|
- Multiplication and division associate left to right. Use `m/(s A)` to put
|
|
250
252
|
both `s` and `A` in the denominator; `m/s A` means `(m/s)*A`.
|
|
251
253
|
- Unit symbols and names are case-sensitive. `u`, `µ`, and `μ` are accepted
|
|
252
254
|
micro prefixes. Use lowercase `k` for kilo; `K` denotes kelvin.
|
|
253
|
-
- A registered multiword name is recognized before implicit multiplication
|
|
255
|
+
- A registered multiword or hyphenated name is recognized before implicit multiplication
|
|
254
256
|
when it occupies the entire input. Whitespace between its words is treated
|
|
255
|
-
as a single space. Inside
|
|
256
|
-
|
|
257
|
+
as a single space. Inside expressions, use `[name]` to make a name one factor,
|
|
258
|
+
for example `[astronomical unit] / s` or `[volt-ampere reactive]**2`.
|
|
259
|
+
Symbols and `Unit` object composition remain available.
|
|
260
|
+
|
|
261
|
+
Square brackets reference registered names and name aliases only: `[metre]`
|
|
262
|
+
works, while `[m]` and `[m/s]` do not. The contents are never evaluated as an
|
|
263
|
+
expression. Empty, nested, and unmatched brackets are errors. Put permitted
|
|
264
|
+
name prefixes inside the brackets, as in `[kiloastronomical unit]`; `k[name]`
|
|
265
|
+
does not apply a prefix. Single and double quotes retain their angle-unit
|
|
266
|
+
meaning rather than acting as string delimiters. Bare compound names are
|
|
267
|
+
not guessed from adjacent words, and ordinary parentheses still group products.
|
|
257
268
|
|
|
258
269
|
The unit table contains `s`, `m`, `g`, `A`, `K`, `mol`, and `cd`, plus the
|
|
259
270
|
dimensionless identity. Importing unitx also initializes the common units in
|
|
@@ -303,9 +314,10 @@ aliases gives an empty tuple. `symbol_aliases` accepts a string or tuple of
|
|
|
303
314
|
strings; it and `prefixable` must be passed by keyword.
|
|
304
315
|
Symbols and symbol aliases must each be a single printable unit token.
|
|
305
316
|
Names and name aliases may contain multiple such tokens separated by single
|
|
306
|
-
ASCII spaces, without leading or trailing
|
|
307
|
-
operators are not allowed in any token. The primary symbol and `name` are
|
|
308
|
-
required and must be nonempty; empty aliases are ignored.
|
|
317
|
+
ASCII spaces or hyphens, without leading or trailing separators. Decimal digits
|
|
318
|
+
and parser operators are not allowed in any token. The primary symbol and `name` are
|
|
319
|
+
required and must be nonempty; empty aliases are ignored. Square brackets and
|
|
320
|
+
the superscript characters `⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻` are reserved for parser syntax.
|
|
309
321
|
|
|
310
322
|
```pycon
|
|
311
323
|
>>> span = (2 * si.m).define('span', 'survey span', 'survey distance')
|
|
@@ -315,22 +327,86 @@ True
|
|
|
315
327
|
True
|
|
316
328
|
>>> Unit('survey span') / si.s == Unit('span / s')
|
|
317
329
|
True
|
|
330
|
+
>>> Unit('[survey span] / [second]') == Unit('span / s')
|
|
331
|
+
True
|
|
318
332
|
|
|
319
333
|
```
|
|
320
334
|
|
|
321
|
-
|
|
335
|
+
Bare multiword names are recognized only as complete inputs. For example,
|
|
322
336
|
`Unit('astronomical unit / arcsec')` does not recognize `astronomical unit`
|
|
323
|
-
as a factor; use
|
|
337
|
+
as a factor; use `[astronomical unit] / arcsec`, symbols, or Unit objects instead.
|
|
338
|
+
|
|
339
|
+
SI prefixes are enabled by default. `prefixable: PrefixPolicy = True` accepts
|
|
340
|
+
`True` for all spellings, `False` for none, or a tuple of exact symbols, names,
|
|
341
|
+
and aliases supplied in that definition. With a tuple, only the listed
|
|
342
|
+
spellings accept prefixes; an empty tuple disables prefixes. Unknown spellings
|
|
343
|
+
and non-string entries are errors. For example,
|
|
344
|
+
`prefixable=('arcsec', 'arcsecond')` enables all SI prefixes on those two
|
|
345
|
+
spellings, while other spellings of that unit remain unprefixable.
|
|
346
|
+
|
|
347
|
+
The tuple selects **unit spellings**, not prefix symbols. Prefix names attach
|
|
348
|
+
directly to the first word of a multiword name, as in `kiloastronomical unit`;
|
|
349
|
+
a separate `kilo astronomical unit` is not accepted. `PrefixPolicy` is available
|
|
350
|
+
from `unitx.unitregistry` for annotations and means `bool | tuple[str, ...]`.
|
|
351
|
+
|
|
352
|
+
```pycon
|
|
353
|
+
>>> tick = si.s.define(
|
|
354
|
+
... 'demoTick',
|
|
355
|
+
... 'survey interval',
|
|
356
|
+
... symbol_aliases='demoT',
|
|
357
|
+
... prefixable=('demoT', 'survey interval'),
|
|
358
|
+
... )
|
|
359
|
+
>>> Unit('[millisurvey interval]') == Unit('mdemoT')
|
|
360
|
+
True
|
|
361
|
+
>>> Quantity(1000, 'mdemoT').to(tick).value
|
|
362
|
+
Fraction(1, 1)
|
|
363
|
+
>>> Unit('mdemoT').expression()
|
|
364
|
+
'mdemoT'
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
Prefix permissions are checked before alias normalization. Canonical identity
|
|
369
|
+
still uses the original registered unit and canonical prefix, independent of
|
|
370
|
+
the input alias. Preferred spellings use the first permitted symbol or alias;
|
|
371
|
+
if only a name supports a prefix, `SingleUnit.symbol` falls back to that name
|
|
372
|
+
and `Unit.expression()` emits a `[name]` reference. Conversely, `SingleUnit.name`
|
|
373
|
+
falls back to a symbol if no name allows that prefix. Repr and pickle preserve
|
|
374
|
+
the same formal unit, rather than replacing the prefix with an extra scale.
|
|
375
|
+
|
|
376
|
+
`arcsec` and `arcsecond` accept prefixes, for example `marcsec` and
|
|
377
|
+
`milliarcsecond`; `″` and `"` do not. `as` continues to mean attosecond,
|
|
378
|
+
and `mas` is not an arcsecond alias. `a` (are) and `ha` (hectare) are separate
|
|
379
|
+
unprefixable units; `Pa` remains pascal. `yr` remains exactly 365 days.
|
|
380
|
+
`a_j` is the Julian year of exactly 365.25 days (31,557,600 seconds), while
|
|
381
|
+
`mo` is one twelfth of that interval, rather than a variable calendar month.
|
|
382
|
+
The name exceptions `megohm` and `kilohm` are supported alongside the older
|
|
383
|
+
`megaohm` and `kiloohm` spellings; `gigaohm` retains both vowels. No general
|
|
384
|
+
vowel-elision rule is applied.
|
|
385
|
+
|
|
386
|
+
`ly` is defined using the speed of light and the Julian year; `eV` uses the
|
|
387
|
+
elementary charge and volt. Both reuse the defining constants exposed by `SI`.
|
|
388
|
+
`mHg` is the registered metre-of-mercury unit and `mmHg` is its milli-prefixed
|
|
389
|
+
form; `760 * si.mmHg` converts to `si.atm` with value 1 under the library's
|
|
390
|
+
existing pressure convention. Prefixes do not stack: `mmmHg` and `kmmHg` are
|
|
391
|
+
invalid. `kt` retains its meaning as a knot alias; tonne remains unprefixable.
|
|
392
|
+
|
|
393
|
+
The newly registered `u` denotes the unified atomic mass unit. ASCII micro
|
|
394
|
+
spellings such as `um` still mean micrometres, but now issue `UnitSymbolWarning`
|
|
395
|
+
because `u m` has a separate meaning. Use `µm`, `μm`, or `micrometre` to avoid
|
|
396
|
+
this warning.
|
|
324
397
|
|
|
325
|
-
SI prefixes are enabled by default; set `prefixable=False` to disable them.
|
|
326
|
-
Prefix names attach directly to the first word of a multiword name, as in
|
|
327
|
-
`kiloastronomical unit`; a separate `kilo astronomical unit` is not accepted.
|
|
328
398
|
Registration raises `UnitRegistryError` if a new spelling, including a generated
|
|
329
399
|
prefixed form, already resolves to a unit or conflicts with another spelling
|
|
330
400
|
in the same definition. A multiword spelling must not replace an existing
|
|
331
401
|
implicit product such as `metre second`. Validation finishes before the
|
|
332
402
|
registry changes.
|
|
333
403
|
|
|
404
|
+
The registry and spelling rules live in `unitx.unitregistry`; parsing expressions
|
|
405
|
+
does not change unit definitions. A parser instance caches only a successful
|
|
406
|
+
result; failed parses may be retried after a definition is added. Registration
|
|
407
|
+
preserves existing valid spellings and validates before updating its indexes.
|
|
408
|
+
Concurrent registry writes and isolated registry contexts are not supported.
|
|
409
|
+
|
|
334
410
|
Quantity definitions require positive finite `int`, `Fraction`, `Decimal`, or
|
|
335
411
|
`float` magnitudes. Prefer `Fraction` or `Decimal` for exact scales. Floats use
|
|
336
412
|
Factor's denominator limit and can warn or round to zero and fail, for example
|
|
@@ -224,14 +224,25 @@ False
|
|
|
224
224
|
token: `ms` is a millisecond, while `m s` is metre times second.
|
|
225
225
|
- Powers can use adjacent numbers, `^`, or `**`. Exponents written as ratios
|
|
226
226
|
require parentheses, as in `m^(1/2)`; decimal exponents such as `m^0.5` are exact.
|
|
227
|
+
Adjacent integer superscripts are also accepted: `m²`, `s⁻¹²`, and `(m/s)²`.
|
|
228
|
+
Superscript fractions and mixed exponent notations are not supported.
|
|
227
229
|
- Multiplication and division associate left to right. Use `m/(s A)` to put
|
|
228
230
|
both `s` and `A` in the denominator; `m/s A` means `(m/s)*A`.
|
|
229
231
|
- Unit symbols and names are case-sensitive. `u`, `µ`, and `μ` are accepted
|
|
230
232
|
micro prefixes. Use lowercase `k` for kilo; `K` denotes kelvin.
|
|
231
|
-
- A registered multiword name is recognized before implicit multiplication
|
|
233
|
+
- A registered multiword or hyphenated name is recognized before implicit multiplication
|
|
232
234
|
when it occupies the entire input. Whitespace between its words is treated
|
|
233
|
-
as a single space. Inside
|
|
234
|
-
|
|
235
|
+
as a single space. Inside expressions, use `[name]` to make a name one factor,
|
|
236
|
+
for example `[astronomical unit] / s` or `[volt-ampere reactive]**2`.
|
|
237
|
+
Symbols and `Unit` object composition remain available.
|
|
238
|
+
|
|
239
|
+
Square brackets reference registered names and name aliases only: `[metre]`
|
|
240
|
+
works, while `[m]` and `[m/s]` do not. The contents are never evaluated as an
|
|
241
|
+
expression. Empty, nested, and unmatched brackets are errors. Put permitted
|
|
242
|
+
name prefixes inside the brackets, as in `[kiloastronomical unit]`; `k[name]`
|
|
243
|
+
does not apply a prefix. Single and double quotes retain their angle-unit
|
|
244
|
+
meaning rather than acting as string delimiters. Bare compound names are
|
|
245
|
+
not guessed from adjacent words, and ordinary parentheses still group products.
|
|
235
246
|
|
|
236
247
|
The unit table contains `s`, `m`, `g`, `A`, `K`, `mol`, and `cd`, plus the
|
|
237
248
|
dimensionless identity. Importing unitx also initializes the common units in
|
|
@@ -281,9 +292,10 @@ aliases gives an empty tuple. `symbol_aliases` accepts a string or tuple of
|
|
|
281
292
|
strings; it and `prefixable` must be passed by keyword.
|
|
282
293
|
Symbols and symbol aliases must each be a single printable unit token.
|
|
283
294
|
Names and name aliases may contain multiple such tokens separated by single
|
|
284
|
-
ASCII spaces, without leading or trailing
|
|
285
|
-
operators are not allowed in any token. The primary symbol and `name` are
|
|
286
|
-
required and must be nonempty; empty aliases are ignored.
|
|
295
|
+
ASCII spaces or hyphens, without leading or trailing separators. Decimal digits
|
|
296
|
+
and parser operators are not allowed in any token. The primary symbol and `name` are
|
|
297
|
+
required and must be nonempty; empty aliases are ignored. Square brackets and
|
|
298
|
+
the superscript characters `⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻` are reserved for parser syntax.
|
|
287
299
|
|
|
288
300
|
```pycon
|
|
289
301
|
>>> span = (2 * si.m).define('span', 'survey span', 'survey distance')
|
|
@@ -293,22 +305,86 @@ True
|
|
|
293
305
|
True
|
|
294
306
|
>>> Unit('survey span') / si.s == Unit('span / s')
|
|
295
307
|
True
|
|
308
|
+
>>> Unit('[survey span] / [second]') == Unit('span / s')
|
|
309
|
+
True
|
|
296
310
|
|
|
297
311
|
```
|
|
298
312
|
|
|
299
|
-
|
|
313
|
+
Bare multiword names are recognized only as complete inputs. For example,
|
|
300
314
|
`Unit('astronomical unit / arcsec')` does not recognize `astronomical unit`
|
|
301
|
-
as a factor; use
|
|
315
|
+
as a factor; use `[astronomical unit] / arcsec`, symbols, or Unit objects instead.
|
|
316
|
+
|
|
317
|
+
SI prefixes are enabled by default. `prefixable: PrefixPolicy = True` accepts
|
|
318
|
+
`True` for all spellings, `False` for none, or a tuple of exact symbols, names,
|
|
319
|
+
and aliases supplied in that definition. With a tuple, only the listed
|
|
320
|
+
spellings accept prefixes; an empty tuple disables prefixes. Unknown spellings
|
|
321
|
+
and non-string entries are errors. For example,
|
|
322
|
+
`prefixable=('arcsec', 'arcsecond')` enables all SI prefixes on those two
|
|
323
|
+
spellings, while other spellings of that unit remain unprefixable.
|
|
324
|
+
|
|
325
|
+
The tuple selects **unit spellings**, not prefix symbols. Prefix names attach
|
|
326
|
+
directly to the first word of a multiword name, as in `kiloastronomical unit`;
|
|
327
|
+
a separate `kilo astronomical unit` is not accepted. `PrefixPolicy` is available
|
|
328
|
+
from `unitx.unitregistry` for annotations and means `bool | tuple[str, ...]`.
|
|
329
|
+
|
|
330
|
+
```pycon
|
|
331
|
+
>>> tick = si.s.define(
|
|
332
|
+
... 'demoTick',
|
|
333
|
+
... 'survey interval',
|
|
334
|
+
... symbol_aliases='demoT',
|
|
335
|
+
... prefixable=('demoT', 'survey interval'),
|
|
336
|
+
... )
|
|
337
|
+
>>> Unit('[millisurvey interval]') == Unit('mdemoT')
|
|
338
|
+
True
|
|
339
|
+
>>> Quantity(1000, 'mdemoT').to(tick).value
|
|
340
|
+
Fraction(1, 1)
|
|
341
|
+
>>> Unit('mdemoT').expression()
|
|
342
|
+
'mdemoT'
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Prefix permissions are checked before alias normalization. Canonical identity
|
|
347
|
+
still uses the original registered unit and canonical prefix, independent of
|
|
348
|
+
the input alias. Preferred spellings use the first permitted symbol or alias;
|
|
349
|
+
if only a name supports a prefix, `SingleUnit.symbol` falls back to that name
|
|
350
|
+
and `Unit.expression()` emits a `[name]` reference. Conversely, `SingleUnit.name`
|
|
351
|
+
falls back to a symbol if no name allows that prefix. Repr and pickle preserve
|
|
352
|
+
the same formal unit, rather than replacing the prefix with an extra scale.
|
|
353
|
+
|
|
354
|
+
`arcsec` and `arcsecond` accept prefixes, for example `marcsec` and
|
|
355
|
+
`milliarcsecond`; `″` and `"` do not. `as` continues to mean attosecond,
|
|
356
|
+
and `mas` is not an arcsecond alias. `a` (are) and `ha` (hectare) are separate
|
|
357
|
+
unprefixable units; `Pa` remains pascal. `yr` remains exactly 365 days.
|
|
358
|
+
`a_j` is the Julian year of exactly 365.25 days (31,557,600 seconds), while
|
|
359
|
+
`mo` is one twelfth of that interval, rather than a variable calendar month.
|
|
360
|
+
The name exceptions `megohm` and `kilohm` are supported alongside the older
|
|
361
|
+
`megaohm` and `kiloohm` spellings; `gigaohm` retains both vowels. No general
|
|
362
|
+
vowel-elision rule is applied.
|
|
363
|
+
|
|
364
|
+
`ly` is defined using the speed of light and the Julian year; `eV` uses the
|
|
365
|
+
elementary charge and volt. Both reuse the defining constants exposed by `SI`.
|
|
366
|
+
`mHg` is the registered metre-of-mercury unit and `mmHg` is its milli-prefixed
|
|
367
|
+
form; `760 * si.mmHg` converts to `si.atm` with value 1 under the library's
|
|
368
|
+
existing pressure convention. Prefixes do not stack: `mmmHg` and `kmmHg` are
|
|
369
|
+
invalid. `kt` retains its meaning as a knot alias; tonne remains unprefixable.
|
|
370
|
+
|
|
371
|
+
The newly registered `u` denotes the unified atomic mass unit. ASCII micro
|
|
372
|
+
spellings such as `um` still mean micrometres, but now issue `UnitSymbolWarning`
|
|
373
|
+
because `u m` has a separate meaning. Use `µm`, `μm`, or `micrometre` to avoid
|
|
374
|
+
this warning.
|
|
302
375
|
|
|
303
|
-
SI prefixes are enabled by default; set `prefixable=False` to disable them.
|
|
304
|
-
Prefix names attach directly to the first word of a multiword name, as in
|
|
305
|
-
`kiloastronomical unit`; a separate `kilo astronomical unit` is not accepted.
|
|
306
376
|
Registration raises `UnitRegistryError` if a new spelling, including a generated
|
|
307
377
|
prefixed form, already resolves to a unit or conflicts with another spelling
|
|
308
378
|
in the same definition. A multiword spelling must not replace an existing
|
|
309
379
|
implicit product such as `metre second`. Validation finishes before the
|
|
310
380
|
registry changes.
|
|
311
381
|
|
|
382
|
+
The registry and spelling rules live in `unitx.unitregistry`; parsing expressions
|
|
383
|
+
does not change unit definitions. A parser instance caches only a successful
|
|
384
|
+
result; failed parses may be retried after a definition is added. Registration
|
|
385
|
+
preserves existing valid spellings and validates before updating its indexes.
|
|
386
|
+
Concurrent registry writes and isolated registry contexts are not supported.
|
|
387
|
+
|
|
312
388
|
Quantity definitions require positive finite `int`, `Fraction`, `Decimal`, or
|
|
313
389
|
`float` magnitudes. Prefer `Fraction` or `Decimal` for exact scales. Floats use
|
|
314
390
|
Factor's denominator limit and can warn or round to zero and fail, for example
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
"""Unicode utilities for unitx."""
|
|
2
2
|
|
|
3
3
|
from fractions import Fraction
|
|
4
|
-
from typing import Literal
|
|
4
|
+
from typing import Literal
|
|
5
5
|
|
|
6
6
|
__all__ = ['DOT', 'DotType', 'superscript']
|
|
7
7
|
|
|
8
8
|
DOT = '⋅' # chr(0x22C5)
|
|
9
|
-
DotType
|
|
9
|
+
type DotType = Literal['⋅']
|
|
10
10
|
|
|
11
|
-
DIGITS = '0123456789
|
|
12
|
-
SUPERSCRIPTS = '
|
|
11
|
+
DIGITS = '0123456789+-'
|
|
12
|
+
SUPERSCRIPTS = '⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻'
|
|
13
13
|
DIGIT_TO_SUP = str.maketrans(DIGITS, SUPERSCRIPTS)
|
|
14
|
+
SUP_TO_DIGIT = str.maketrans(SUPERSCRIPTS, DIGITS)
|
|
14
15
|
SUPERSCRIPT_SLASH = 'ᐟ' # Canadian Syllabics Final Acute, chr(0x141F)
|
|
15
16
|
|
|
16
17
|
|
|
@@ -14,6 +14,7 @@ from .dimension import DIMENSIONLESS, Dimension
|
|
|
14
14
|
from .exceptions import DimensionError
|
|
15
15
|
from .factor import ONE, Factor, SymbolicConstant
|
|
16
16
|
from .unit import Unit
|
|
17
|
+
from .unitregistry import PrefixPolicy
|
|
17
18
|
|
|
18
19
|
# Magnitudes are exposed read-only; operations construct new quantities.
|
|
19
20
|
T = TypeVar('T', bound=Magnitude, covariant=True)
|
|
@@ -208,7 +209,7 @@ class Quantity(Generic[T]):
|
|
|
208
209
|
name: str,
|
|
209
210
|
*name_aliases: str,
|
|
210
211
|
symbol_aliases: str | tuple[str, ...] = (),
|
|
211
|
-
prefixable:
|
|
212
|
+
prefixable: PrefixPolicy = True,
|
|
212
213
|
) -> Unit:
|
|
213
214
|
"""Register a unit equal to this quantity, using Unit.define's name rules.
|
|
214
215
|
|
|
@@ -222,7 +223,11 @@ class Quantity(Generic[T]):
|
|
|
222
223
|
"""
|
|
223
224
|
scale = Factor(self.value)
|
|
224
225
|
return (scale * self.unit).define(
|
|
225
|
-
symbol,
|
|
226
|
+
symbol,
|
|
227
|
+
name,
|
|
228
|
+
*name_aliases,
|
|
229
|
+
symbol_aliases=symbol_aliases,
|
|
230
|
+
prefixable=prefixable,
|
|
226
231
|
)
|
|
227
232
|
|
|
228
233
|
def _comparison_pair(self) -> tuple[Magnitude, Factor]:
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Shared coherent SI units and the seven defining constants."""
|
|
2
|
+
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
from .._constclass import ConstClass
|
|
6
|
+
from ..factor import ONE
|
|
7
|
+
from ..quantity import Quantity, quantity
|
|
8
|
+
from ..unit import Unit
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class _si(ConstClass):
|
|
12
|
+
# SI base unit
|
|
13
|
+
|
|
14
|
+
one: Final = Unit()
|
|
15
|
+
"""unitless"""
|
|
16
|
+
s: Final = Unit('s')
|
|
17
|
+
"""second, time"""
|
|
18
|
+
m: Final = Unit('m')
|
|
19
|
+
"""metre/meter, length"""
|
|
20
|
+
kg: Final = Unit('kg')
|
|
21
|
+
"""kilogram, mass"""
|
|
22
|
+
A: Final = Unit('A')
|
|
23
|
+
"""ampere, electric current"""
|
|
24
|
+
K: Final = Unit('K')
|
|
25
|
+
"""kelvin, thermodynamic temperature"""
|
|
26
|
+
mol: Final = Unit('mol')
|
|
27
|
+
"""mole, amount of substance"""
|
|
28
|
+
cd: Final = Unit('cd')
|
|
29
|
+
"""candela, luminous intensity"""
|
|
30
|
+
|
|
31
|
+
# SI derived unit
|
|
32
|
+
|
|
33
|
+
rad: Final = one.define('rad', name='radian')
|
|
34
|
+
"""radian, plane angle"""
|
|
35
|
+
sr: Final = one.define('sr', name='steradian')
|
|
36
|
+
"""steradian, solid angle"""
|
|
37
|
+
Hz: Final = (ONE / s).define('Hz', name='hertz')
|
|
38
|
+
"""hertz, frequency"""
|
|
39
|
+
N: Final = (kg * m / s**2).define('N', name='newton')
|
|
40
|
+
"""newton, force/weight"""
|
|
41
|
+
Pa: Final = (N / m**2).define('Pa', name='pascal')
|
|
42
|
+
"""pascal, pressure/stress"""
|
|
43
|
+
J: Final = (N * m).define('J', name='joule')
|
|
44
|
+
"""joule, energy/work/heat"""
|
|
45
|
+
W: Final = (J / s).define('W', name='watt')
|
|
46
|
+
"""watt, power/radiant flux"""
|
|
47
|
+
C: Final = (A * s).define('C', name='coulomb')
|
|
48
|
+
"""coulomb, electric charge"""
|
|
49
|
+
V: Final = (W / A).define('V', name='volt')
|
|
50
|
+
"""volt, electric potential/voltage/emf"""
|
|
51
|
+
F: Final = (C / V).define('F', name='farad')
|
|
52
|
+
"""farad, capacitance"""
|
|
53
|
+
ohm: Final = (V / A).define('Ω', name='ohm')
|
|
54
|
+
"""ohm, resistance/impedance/reactance"""
|
|
55
|
+
S: Final = (A / V).define('S', name='siemens')
|
|
56
|
+
"""siemens, electrical conductance"""
|
|
57
|
+
Wb: Final = (V * s).define('Wb', name='weber')
|
|
58
|
+
"""weber, magnetic flux"""
|
|
59
|
+
T: Final = (Wb / m**2).define('T', name='tesla')
|
|
60
|
+
"""tesla, magnetic flux density"""
|
|
61
|
+
H: Final = (Wb / A).define('H', name='henry')
|
|
62
|
+
"""henry, inductance"""
|
|
63
|
+
lm: Final = (cd * sr).define('lm', name='lumen')
|
|
64
|
+
"""lumen, luminous flux"""
|
|
65
|
+
lx: Final = (lm / m**2).define('lx', name='lux')
|
|
66
|
+
"""lux, illuminance"""
|
|
67
|
+
Bq: Final = (ONE / s).define('Bq', name='becquerel')
|
|
68
|
+
"""becquerel, activity referred to a radionuclide"""
|
|
69
|
+
Gy: Final = (J / kg).define('Gy', name='gray')
|
|
70
|
+
"""gray, absorbed dose"""
|
|
71
|
+
Sv: Final = (J / kg).define('Sv', name='sievert')
|
|
72
|
+
"""sievert, equivalent dose"""
|
|
73
|
+
kat: Final = (mol / s).define('kat', name='katal')
|
|
74
|
+
"""katal, catalytic activity"""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class _SI(ConstClass):
|
|
78
|
+
DeltanuCs: Final = Quantity(9_192_631_770, _si.Hz)
|
|
79
|
+
"""hyperfine transition frequency of Cs-133, definition of second."""
|
|
80
|
+
c: Final = Quantity(299_792_458, _si.m / _si.s)
|
|
81
|
+
"""speed of light in vacuum"""
|
|
82
|
+
h: Final = quantity(6.626_070_15e-34, _si.J * _si.s)
|
|
83
|
+
"""Planck constant"""
|
|
84
|
+
e: Final = quantity(1.602_176_634e-19, _si.C)
|
|
85
|
+
"""elementary charge"""
|
|
86
|
+
kB: Final = quantity(1.380_649e-23, _si.J / _si.K)
|
|
87
|
+
"""Boltzmann constant"""
|
|
88
|
+
NA: Final = quantity(6.022_140_76e23, _si.mol**-1)
|
|
89
|
+
"""Avogadro constant"""
|
|
90
|
+
Kcd: Final = Quantity(683, _si.lm / _si.W)
|
|
91
|
+
"""luminous efficacy of 540 THz radiation, definition of candela"""
|