unitx 0.6.3__tar.gz → 0.7.1__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.1}/CHANGELOG.md +88 -0
- {unitx-0.6.3 → unitx-0.7.1}/PKG-INFO +115 -18
- {unitx-0.6.3 → unitx-0.7.1}/README.md +114 -17
- {unitx-0.6.3 → unitx-0.7.1}/pyproject.toml +1 -1
- {unitx-0.6.3 → unitx-0.7.1}/pyrightconfig.json +3 -0
- unitx-0.7.1/src/unitx/_constnamespace.py +33 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/_unicode.py +5 -4
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/quantity.py +7 -2
- unitx-0.7.1/src/unitx/si/bases.py +93 -0
- unitx-0.7.1/src/unitx/si/constants.py +178 -0
- unitx-0.7.1/src/unitx/si/units.py +233 -0
- unitx-0.7.1/src/unitx/singleunit.py +160 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/unit.py +24 -14
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/unitparser.py +47 -16
- unitx-0.7.1/src/unitx/unitregistry.py +305 -0
- unitx-0.6.3/tests/test_unit_data.py → unitx-0.7.1/tests/test_builtin_definitions.py +21 -21
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_quantity.py +2 -1
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_si.py +121 -1
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_singleunit.py +39 -15
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_unit_definition.py +51 -44
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_unitparser.py +78 -0
- unitx-0.7.1/tests/test_unitregistry.py +228 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/typing/check_quantity.py +25 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/typing/check_si.py +13 -1
- unitx-0.6.3/src/unitx/_constclass.py +0 -34
- unitx-0.6.3/src/unitx/_unit_data.py +0 -193
- unitx-0.6.3/src/unitx/si/constants.py +0 -200
- 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.1}/.github/workflows/ci.yml +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/.github/workflows/release.yml +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/.gitignore +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/LICENSE +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/conftest.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/__init__.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/_numerics.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/dimension.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/exceptions.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/factor.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/monomial.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/py.typed +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/src/unitx/si/__init__.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/__init__.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_dimension.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_factor.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_import.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_monomial.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_numeric.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_typing.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_unicode.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_unit.py +0 -0
- {unitx-0.6.3 → unitx-0.7.1}/tests/test_warnings.py +0 -0
|
@@ -1,5 +1,93 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.1] - 2026-10-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Accept a single exact spelling string for `prefixable`, equivalent to a
|
|
8
|
+
one-element tuple, with the same spelling validation before registration.
|
|
9
|
+
- Expand the `si` namespace's prefixed shortcuts and common units, including
|
|
10
|
+
percent, permille, permyriad, rotational frequency (`rpm`), speed of light
|
|
11
|
+
(`c`), gram-force, volt-ampere, ampere-hour, mho, and nit. Enable Torr prefixes.
|
|
12
|
+
- Add `SI.kappa` and the wavelength and frequency Wien displacement constants,
|
|
13
|
+
`SI.b` and `SI.b_`.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Use fixed Decimal approximations with about 50 significant digits for pi and
|
|
18
|
+
the positive roots in the Wien displacement laws. Derived constants still use
|
|
19
|
+
the Decimal context active at import.
|
|
20
|
+
- Treat `u` and `Da` as spellings of one formal unit, with prefixes enabled only
|
|
21
|
+
on `Da`. Rebuild stored units when migrating from the separate `u` identity;
|
|
22
|
+
the mass conversion scale is unchanged. Use `kDa` rather than `kilodalton`.
|
|
23
|
+
- Keep ASCII micro spellings such as `um` and `us` convenient to type without
|
|
24
|
+
warnings. The explicit product `u m` retains its separate mass-times-length
|
|
25
|
+
meaning.
|
|
26
|
+
|
|
27
|
+
## [0.7.0] - 2026-10-19
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- Add `[registered name]` references as single factors in unit expressions,
|
|
32
|
+
including products, reciprocals, parentheses, and rational powers. References
|
|
33
|
+
resolve names and name aliases only, with whitespace normalization and no
|
|
34
|
+
expression evaluation or nested quoting.
|
|
35
|
+
- Support standalone hyphenated names and adjacent Unicode integer superscripts
|
|
36
|
+
such as `m²`, `s⁻¹²`, and `[metre]²`.
|
|
37
|
+
- Extend `prefixable: PrefixPolicy = True` on all `.define()` entry points to
|
|
38
|
+
accept a tuple of exact registered symbols, names, or aliases. Only those
|
|
39
|
+
spellings accept prefixes; True enables all spellings and False or () disables
|
|
40
|
+
all spellings. `PrefixPolicy` is `bool | tuple[str, ...]`.
|
|
41
|
+
- Enable prefixes on `arcsec` and `arcsecond` while keeping angle punctuation
|
|
42
|
+
unprefixable. Register unprefixable are (`a`) and hectare (`ha`), and reactive
|
|
43
|
+
power (`var`, name `volt-ampere reactive`). Keep `as` as attosecond and `yr`
|
|
44
|
+
as a 365-day year.
|
|
45
|
+
- Add the Julian year `a_j` (exactly 31,557,600 seconds) and its twelfth,
|
|
46
|
+
`mo`, as a fixed month interval distinct from variable calendar months.
|
|
47
|
+
- Add light year (`ly`), unified atomic mass unit (`u`), and common prefixed
|
|
48
|
+
namespace attributes, including attosecond (`as_`) and petaelectronvolt (`PeV`).
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Move definitions, spelling resolution, and registration validation into
|
|
53
|
+
`unitx.unitregistry`, shared by SingleUnit and UnitParser. Preserve formal identities,
|
|
54
|
+
exact SI factors, existing `.define()` defaults, and validation before mutation.
|
|
55
|
+
- Remove the superseded private `_unit_data` module. Name definition records
|
|
56
|
+
`PrefixDefinition` and `UnitDefinition`, with explicit definition indexes and
|
|
57
|
+
alias-to-symbol mappings.
|
|
58
|
+
- Select permitted canonical output spellings after applying binding policies.
|
|
59
|
+
When only a name permits a prefix, expressions use `[name]` so repr and pickle
|
|
60
|
+
preserve the prefixed identity. Expose `PrefixPolicy` for type annotations.
|
|
61
|
+
- Use the finite spelling exceptions `megohm` and `kilohm` in preferred names,
|
|
62
|
+
retaining `megaohm` and `kiloohm` as accepted inputs.
|
|
63
|
+
- Reuse Unicode superscript tables, handle malformed name brackets through
|
|
64
|
+
the common lexical error path, and simplify definition initialization,
|
|
65
|
+
preferred spelling selection, and generated prefix-name validation.
|
|
66
|
+
- Share coherent SI units and the seven defining constants through private
|
|
67
|
+
bases. Derive `ly` from `c` and the Julian year, and `eV` from `e` and `V`,
|
|
68
|
+
preserving the public `si` and `SI` namespaces and constant magnitude types.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
|
|
72
|
+
- Register metre of mercury (`mHg`) as the prefixable unit and construct `mmHg`
|
|
73
|
+
from its milli prefix. Preserve `760 mmHg = 1 atm` and the existing Torr scale,
|
|
74
|
+
keep the definition exact, and reject stacked prefixes such as `kmmHg`.
|
|
75
|
+
|
|
76
|
+
### Migration
|
|
77
|
+
|
|
78
|
+
- Square brackets and `⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻` are now reserved grammar characters and can
|
|
79
|
+
no longer occur in registered symbols or names. Rename custom spellings that
|
|
80
|
+
previously used them before rebuilding or unpickling those definitions.
|
|
81
|
+
- Long names remain whole-input lookups unless explicitly referenced in brackets.
|
|
82
|
+
`str()` remains readable display and is not a general serialization format;
|
|
83
|
+
use `expression()` for formal unit products and repr for ScaledUnit state.
|
|
84
|
+
- `mmHg` now has the formal identity of milli-prefixed `mHg`; rebuild stored
|
|
85
|
+
units when moving between versions. Its pressure conversion scale is unchanged.
|
|
86
|
+
`kmmHg` and names with repeated prefixes are no longer accepted.
|
|
87
|
+
- Registering `u` makes ASCII micro spellings such as `um` issue the existing
|
|
88
|
+
ambiguity warning. Their meaning is unchanged; use `µm`, `μm`, or `micrometre`
|
|
89
|
+
to avoid the warning. `kt` remains a knot alias and tonne stays unprefixable.
|
|
90
|
+
|
|
3
91
|
## [0.6.3] - 2026-10-18
|
|
4
92
|
|
|
5
93
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: unitx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
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
|
|
@@ -22,11 +22,15 @@ Description-Content-Type: text/markdown
|
|
|
22
22
|
|
|
23
23
|
# unitx
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
[](https://pypi.org/project/unitx/)
|
|
26
|
+
[](https://pypi.org/project/unitx/)
|
|
27
|
+
[](LICENSE)
|
|
28
|
+
|
|
29
|
+
Write Python formulas with ready-to-use units and physical constants. `unitx`
|
|
26
30
|
handles scalar quantities, unit conversion, and dimensional analysis, with
|
|
27
31
|
exact rational unit scales and exponents.
|
|
28
32
|
|
|
29
|
-
unitx is in early development. Public APIs may change during the 0.x series.
|
|
33
|
+
`unitx` is in early development. Public APIs may change during the 0.x series.
|
|
30
34
|
|
|
31
35
|
## Installation
|
|
32
36
|
|
|
@@ -101,15 +105,17 @@ astronomical units are included. Units and constants can be combined directly:
|
|
|
101
105
|
|
|
102
106
|
Both namespaces are read-only and do not need to be instantiated. `si` exposes
|
|
103
107
|
a selection of convenient attributes; other registered prefix combinations
|
|
104
|
-
remain available through `Unit`, for example `Unit('Tm')`. Importing unitx
|
|
108
|
+
remain available through `Unit`, for example `Unit('Tm')`. Importing `unitx`
|
|
105
109
|
initializes the predefined unit catalogue. Defining a custom unit registers its
|
|
106
110
|
text spellings without adding an attribute to `si`.
|
|
107
111
|
|
|
108
112
|
SI defining constants retain their exact decimal values. Measured constants
|
|
109
113
|
are stored nominal values; measurement uncertainties are not propagated.
|
|
110
114
|
Derived Decimal constants are evaluated in the Decimal context active at
|
|
111
|
-
import.
|
|
112
|
-
|
|
115
|
+
import. Pi and the positive roots used by the Wien displacement constants
|
|
116
|
+
(`SI.b` for wavelength and `SI.b_` for frequency) use fixed Decimal
|
|
117
|
+
approximations with about 50 significant digits. Raising the context precision
|
|
118
|
+
does not add accuracy beyond those stored approximations.
|
|
113
119
|
|
|
114
120
|
## Constructing units and quantities
|
|
115
121
|
|
|
@@ -246,17 +252,28 @@ False
|
|
|
246
252
|
token: `ms` is a millisecond, while `m s` is metre times second.
|
|
247
253
|
- Powers can use adjacent numbers, `^`, or `**`. Exponents written as ratios
|
|
248
254
|
require parentheses, as in `m^(1/2)`; decimal exponents such as `m^0.5` are exact.
|
|
255
|
+
Adjacent integer superscripts are also accepted: `m²`, `s⁻¹²`, and `(m/s)²`.
|
|
256
|
+
Superscript fractions and mixed exponent notations are not supported.
|
|
249
257
|
- Multiplication and division associate left to right. Use `m/(s A)` to put
|
|
250
258
|
both `s` and `A` in the denominator; `m/s A` means `(m/s)*A`.
|
|
251
259
|
- Unit symbols and names are case-sensitive. `u`, `µ`, and `μ` are accepted
|
|
252
260
|
micro prefixes. Use lowercase `k` for kilo; `K` denotes kelvin.
|
|
253
|
-
- A registered multiword name is recognized before implicit multiplication
|
|
261
|
+
- A registered multiword or hyphenated name is recognized before implicit multiplication
|
|
254
262
|
when it occupies the entire input. Whitespace between its words is treated
|
|
255
|
-
as a single space. Inside
|
|
256
|
-
|
|
263
|
+
as a single space. Inside expressions, use `[name]` to make a name one factor,
|
|
264
|
+
for example `[astronomical unit] / s` or `[volt-ampere reactive]**2`.
|
|
265
|
+
Symbols and `Unit` object composition remain available.
|
|
266
|
+
|
|
267
|
+
Square brackets reference registered names and name aliases only: `[metre]`
|
|
268
|
+
works, while `[m]` and `[m/s]` do not. The contents are never evaluated as an
|
|
269
|
+
expression. Empty, nested, and unmatched brackets are errors. Put permitted
|
|
270
|
+
name prefixes inside the brackets, as in `[kiloastronomical unit]`; `k[name]`
|
|
271
|
+
does not apply a prefix. Single and double quotes retain their angle-unit
|
|
272
|
+
meaning rather than acting as string delimiters. Bare compound names are
|
|
273
|
+
not guessed from adjacent words, and ordinary parentheses still group products.
|
|
257
274
|
|
|
258
275
|
The unit table contains `s`, `m`, `g`, `A`, `K`, `mol`, and `cd`, plus the
|
|
259
|
-
dimensionless identity. Importing unitx also initializes the common units in
|
|
276
|
+
dimensionless identity. Importing `unitx` also initializes the common units in
|
|
260
277
|
`unitx.si`, including named derived units such as `N`. Mass scales are referenced
|
|
261
278
|
to kilograms: `g` has factor `1/1000`, and `kg` has factor `1`.
|
|
262
279
|
|
|
@@ -303,9 +320,10 @@ aliases gives an empty tuple. `symbol_aliases` accepts a string or tuple of
|
|
|
303
320
|
strings; it and `prefixable` must be passed by keyword.
|
|
304
321
|
Symbols and symbol aliases must each be a single printable unit token.
|
|
305
322
|
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.
|
|
323
|
+
ASCII spaces or hyphens, without leading or trailing separators. Decimal digits
|
|
324
|
+
and parser operators are not allowed in any token. The primary symbol and `name` are
|
|
325
|
+
required and must be nonempty; empty aliases are ignored. Square brackets and
|
|
326
|
+
the superscript characters `⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻` are reserved for parser syntax.
|
|
309
327
|
|
|
310
328
|
```pycon
|
|
311
329
|
>>> span = (2 * si.m).define('span', 'survey span', 'survey distance')
|
|
@@ -315,22 +333,101 @@ True
|
|
|
315
333
|
True
|
|
316
334
|
>>> Unit('survey span') / si.s == Unit('span / s')
|
|
317
335
|
True
|
|
336
|
+
>>> Unit('[survey span] / [second]') == Unit('span / s')
|
|
337
|
+
True
|
|
318
338
|
|
|
319
339
|
```
|
|
320
340
|
|
|
321
|
-
|
|
341
|
+
Bare multiword names are recognized only as complete inputs. For example,
|
|
322
342
|
`Unit('astronomical unit / arcsec')` does not recognize `astronomical unit`
|
|
323
|
-
as a factor; use
|
|
343
|
+
as a factor; use `[astronomical unit] / arcsec`, symbols, or Unit objects instead.
|
|
344
|
+
|
|
345
|
+
SI prefixes are enabled by default. `prefixable: PrefixPolicy = True` accepts
|
|
346
|
+
`True` for all spellings, `False` for none, a single spelling string, or a tuple
|
|
347
|
+
of exact symbols, names, and aliases supplied in that definition. A string such
|
|
348
|
+
as `prefixable='Da'` is equivalent to `prefixable=('Da',)`. Only the selected
|
|
349
|
+
spellings accept prefixes; an empty tuple disables prefixes. Unknown spellings
|
|
350
|
+
and non-string entries are errors. For example,
|
|
351
|
+
`prefixable=('arcsec', 'arcsecond')` enables all SI prefixes on those two
|
|
352
|
+
spellings, while other spellings of that unit remain unprefixable.
|
|
353
|
+
|
|
354
|
+
The tuple selects **unit spellings**, not prefix symbols. Prefix names attach
|
|
355
|
+
directly to the first word of a multiword name, as in `kiloastronomical unit`;
|
|
356
|
+
a separate `kilo astronomical unit` is not accepted. `PrefixPolicy` is available
|
|
357
|
+
from `unitx.unitregistry` for annotations and means `bool | str | tuple[str, ...]`.
|
|
358
|
+
|
|
359
|
+
```pycon
|
|
360
|
+
>>> tick = si.s.define(
|
|
361
|
+
... 'demoTick',
|
|
362
|
+
... 'survey interval',
|
|
363
|
+
... symbol_aliases='demoT',
|
|
364
|
+
... prefixable=('demoT', 'survey interval'),
|
|
365
|
+
... )
|
|
366
|
+
>>> Unit('[millisurvey interval]') == Unit('mdemoT')
|
|
367
|
+
True
|
|
368
|
+
>>> Quantity(1000, 'mdemoT').to(tick).value
|
|
369
|
+
Fraction(1, 1)
|
|
370
|
+
>>> Unit('mdemoT').expression()
|
|
371
|
+
'mdemoT'
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Prefix permissions are checked before alias normalization. Canonical identity
|
|
376
|
+
still uses the original registered unit and canonical prefix, independent of
|
|
377
|
+
the input alias. Preferred spellings use the first permitted symbol or alias;
|
|
378
|
+
if only a name supports a prefix, `SingleUnit.symbol` falls back to that name
|
|
379
|
+
and `Unit.expression()` emits a `[name]` reference. Conversely, `SingleUnit.name`
|
|
380
|
+
falls back to a symbol if no name allows that prefix. Repr and pickle preserve
|
|
381
|
+
the same formal unit, rather than replacing the prefix with an extra scale.
|
|
382
|
+
|
|
383
|
+
`arcsec` and `arcsecond` accept prefixes, for example `marcsec` and
|
|
384
|
+
`milliarcsecond`; `″` and `"` do not. `as` continues to mean attosecond,
|
|
385
|
+
and `mas` is not an arcsecond alias. `a` (are) and `ha` (hectare) are separate
|
|
386
|
+
unprefixable units; `Pa` remains pascal. `yr` remains exactly 365 days.
|
|
387
|
+
`a_j` is the Julian year of exactly 365.25 days (31,557,600 seconds), while
|
|
388
|
+
`mo` is one twelfth of that interval, rather than a variable calendar month.
|
|
389
|
+
The name exceptions `megohm` and `kilohm` are supported alongside the older
|
|
390
|
+
`megaohm` and `kiloohm` spellings; `gigaohm` retains both vowels. No general
|
|
391
|
+
vowel-elision rule is applied.
|
|
392
|
+
|
|
393
|
+
`ly` is defined using the speed of light and the Julian year; `eV` uses the
|
|
394
|
+
elementary charge and volt. Both reuse the defining constants exposed by `SI`.
|
|
395
|
+
`mHg` is the registered metre-of-mercury unit and `mmHg` is its milli-prefixed
|
|
396
|
+
form; `760 * si.mmHg` converts to `si.atm` with value 1 under the library's
|
|
397
|
+
existing pressure convention. Prefixes do not stack: `mmmHg` and `kmmHg` are
|
|
398
|
+
invalid. `kt` retains its meaning as a knot alias; tonne remains unprefixable.
|
|
399
|
+
|
|
400
|
+
`si.mas` and `si.uas` provide milli- and microarcseconds as namespace shortcuts;
|
|
401
|
+
their registered expressions are `marcsec` and `µarcsec`. The strings `mas`
|
|
402
|
+
and `uas` are not registered aliases. `si.Da` and `si.u` now share one formal
|
|
403
|
+
unit identity; only the spelling `Da` accepts prefixes, such as `kDa`.
|
|
404
|
+
`si.mTorr` is available, and Torr accepts SI prefixes. Tonne uses `t` or
|
|
405
|
+
`tonne`; the ambiguous spelling `ton` is not registered.
|
|
406
|
+
|
|
407
|
+
`si.rpm` represents rotational frequency: `60 * si.rpm` converts to `si.Hz`
|
|
408
|
+
with value 1. For angular velocity, multiply that frequency by `2 * PI` and
|
|
409
|
+
convert to `si.rad / si.s`; directly converting frequency to `rad/s` does
|
|
410
|
+
not insert the physical factor of 2π. `si.c` is a speed unit equal to the
|
|
411
|
+
speed of light, while `SI.c` is the corresponding physical quantity.
|
|
412
|
+
|
|
413
|
+
The spelling `u` denotes the unified atomic mass unit when used on its own.
|
|
414
|
+
ASCII micro spellings such as `um` and `us` remain supported without warnings,
|
|
415
|
+
so entering non-ASCII characters is optional. `um`, `µm`, `μm`, and
|
|
416
|
+
`micrometre` all mean micrometres; the explicit product `u m` instead means
|
|
417
|
+
unified atomic mass unit times metre.
|
|
324
418
|
|
|
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
419
|
Registration raises `UnitRegistryError` if a new spelling, including a generated
|
|
329
420
|
prefixed form, already resolves to a unit or conflicts with another spelling
|
|
330
421
|
in the same definition. A multiword spelling must not replace an existing
|
|
331
422
|
implicit product such as `metre second`. Validation finishes before the
|
|
332
423
|
registry changes.
|
|
333
424
|
|
|
425
|
+
The registry and spelling rules live in `unitx.unitregistry`; parsing expressions
|
|
426
|
+
does not change unit definitions. A parser instance caches only a successful
|
|
427
|
+
result; failed parses may be retried after a definition is added. Registration
|
|
428
|
+
preserves existing valid spellings and validates before updating its indexes.
|
|
429
|
+
Concurrent registry writes and isolated registry contexts are not supported.
|
|
430
|
+
|
|
334
431
|
Quantity definitions require positive finite `int`, `Fraction`, `Decimal`, or
|
|
335
432
|
`float` magnitudes. Prefer `Fraction` or `Decimal` for exact scales. Floats use
|
|
336
433
|
Factor's denominator limit and can warn or round to zero and fail, for example
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# unitx
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://pypi.org/project/unitx/)
|
|
4
|
+
[](https://pypi.org/project/unitx/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Write Python formulas with ready-to-use units and physical constants. `unitx`
|
|
4
8
|
handles scalar quantities, unit conversion, and dimensional analysis, with
|
|
5
9
|
exact rational unit scales and exponents.
|
|
6
10
|
|
|
7
|
-
unitx is in early development. Public APIs may change during the 0.x series.
|
|
11
|
+
`unitx` is in early development. Public APIs may change during the 0.x series.
|
|
8
12
|
|
|
9
13
|
## Installation
|
|
10
14
|
|
|
@@ -79,15 +83,17 @@ astronomical units are included. Units and constants can be combined directly:
|
|
|
79
83
|
|
|
80
84
|
Both namespaces are read-only and do not need to be instantiated. `si` exposes
|
|
81
85
|
a selection of convenient attributes; other registered prefix combinations
|
|
82
|
-
remain available through `Unit`, for example `Unit('Tm')`. Importing unitx
|
|
86
|
+
remain available through `Unit`, for example `Unit('Tm')`. Importing `unitx`
|
|
83
87
|
initializes the predefined unit catalogue. Defining a custom unit registers its
|
|
84
88
|
text spellings without adding an attribute to `si`.
|
|
85
89
|
|
|
86
90
|
SI defining constants retain their exact decimal values. Measured constants
|
|
87
91
|
are stored nominal values; measurement uncertainties are not propagated.
|
|
88
92
|
Derived Decimal constants are evaluated in the Decimal context active at
|
|
89
|
-
import.
|
|
90
|
-
|
|
93
|
+
import. Pi and the positive roots used by the Wien displacement constants
|
|
94
|
+
(`SI.b` for wavelength and `SI.b_` for frequency) use fixed Decimal
|
|
95
|
+
approximations with about 50 significant digits. Raising the context precision
|
|
96
|
+
does not add accuracy beyond those stored approximations.
|
|
91
97
|
|
|
92
98
|
## Constructing units and quantities
|
|
93
99
|
|
|
@@ -224,17 +230,28 @@ False
|
|
|
224
230
|
token: `ms` is a millisecond, while `m s` is metre times second.
|
|
225
231
|
- Powers can use adjacent numbers, `^`, or `**`. Exponents written as ratios
|
|
226
232
|
require parentheses, as in `m^(1/2)`; decimal exponents such as `m^0.5` are exact.
|
|
233
|
+
Adjacent integer superscripts are also accepted: `m²`, `s⁻¹²`, and `(m/s)²`.
|
|
234
|
+
Superscript fractions and mixed exponent notations are not supported.
|
|
227
235
|
- Multiplication and division associate left to right. Use `m/(s A)` to put
|
|
228
236
|
both `s` and `A` in the denominator; `m/s A` means `(m/s)*A`.
|
|
229
237
|
- Unit symbols and names are case-sensitive. `u`, `µ`, and `μ` are accepted
|
|
230
238
|
micro prefixes. Use lowercase `k` for kilo; `K` denotes kelvin.
|
|
231
|
-
- A registered multiword name is recognized before implicit multiplication
|
|
239
|
+
- A registered multiword or hyphenated name is recognized before implicit multiplication
|
|
232
240
|
when it occupies the entire input. Whitespace between its words is treated
|
|
233
|
-
as a single space. Inside
|
|
234
|
-
|
|
241
|
+
as a single space. Inside expressions, use `[name]` to make a name one factor,
|
|
242
|
+
for example `[astronomical unit] / s` or `[volt-ampere reactive]**2`.
|
|
243
|
+
Symbols and `Unit` object composition remain available.
|
|
244
|
+
|
|
245
|
+
Square brackets reference registered names and name aliases only: `[metre]`
|
|
246
|
+
works, while `[m]` and `[m/s]` do not. The contents are never evaluated as an
|
|
247
|
+
expression. Empty, nested, and unmatched brackets are errors. Put permitted
|
|
248
|
+
name prefixes inside the brackets, as in `[kiloastronomical unit]`; `k[name]`
|
|
249
|
+
does not apply a prefix. Single and double quotes retain their angle-unit
|
|
250
|
+
meaning rather than acting as string delimiters. Bare compound names are
|
|
251
|
+
not guessed from adjacent words, and ordinary parentheses still group products.
|
|
235
252
|
|
|
236
253
|
The unit table contains `s`, `m`, `g`, `A`, `K`, `mol`, and `cd`, plus the
|
|
237
|
-
dimensionless identity. Importing unitx also initializes the common units in
|
|
254
|
+
dimensionless identity. Importing `unitx` also initializes the common units in
|
|
238
255
|
`unitx.si`, including named derived units such as `N`. Mass scales are referenced
|
|
239
256
|
to kilograms: `g` has factor `1/1000`, and `kg` has factor `1`.
|
|
240
257
|
|
|
@@ -281,9 +298,10 @@ aliases gives an empty tuple. `symbol_aliases` accepts a string or tuple of
|
|
|
281
298
|
strings; it and `prefixable` must be passed by keyword.
|
|
282
299
|
Symbols and symbol aliases must each be a single printable unit token.
|
|
283
300
|
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.
|
|
301
|
+
ASCII spaces or hyphens, without leading or trailing separators. Decimal digits
|
|
302
|
+
and parser operators are not allowed in any token. The primary symbol and `name` are
|
|
303
|
+
required and must be nonempty; empty aliases are ignored. Square brackets and
|
|
304
|
+
the superscript characters `⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻` are reserved for parser syntax.
|
|
287
305
|
|
|
288
306
|
```pycon
|
|
289
307
|
>>> span = (2 * si.m).define('span', 'survey span', 'survey distance')
|
|
@@ -293,22 +311,101 @@ True
|
|
|
293
311
|
True
|
|
294
312
|
>>> Unit('survey span') / si.s == Unit('span / s')
|
|
295
313
|
True
|
|
314
|
+
>>> Unit('[survey span] / [second]') == Unit('span / s')
|
|
315
|
+
True
|
|
296
316
|
|
|
297
317
|
```
|
|
298
318
|
|
|
299
|
-
|
|
319
|
+
Bare multiword names are recognized only as complete inputs. For example,
|
|
300
320
|
`Unit('astronomical unit / arcsec')` does not recognize `astronomical unit`
|
|
301
|
-
as a factor; use
|
|
321
|
+
as a factor; use `[astronomical unit] / arcsec`, symbols, or Unit objects instead.
|
|
322
|
+
|
|
323
|
+
SI prefixes are enabled by default. `prefixable: PrefixPolicy = True` accepts
|
|
324
|
+
`True` for all spellings, `False` for none, a single spelling string, or a tuple
|
|
325
|
+
of exact symbols, names, and aliases supplied in that definition. A string such
|
|
326
|
+
as `prefixable='Da'` is equivalent to `prefixable=('Da',)`. Only the selected
|
|
327
|
+
spellings accept prefixes; an empty tuple disables prefixes. Unknown spellings
|
|
328
|
+
and non-string entries are errors. For example,
|
|
329
|
+
`prefixable=('arcsec', 'arcsecond')` enables all SI prefixes on those two
|
|
330
|
+
spellings, while other spellings of that unit remain unprefixable.
|
|
331
|
+
|
|
332
|
+
The tuple selects **unit spellings**, not prefix symbols. Prefix names attach
|
|
333
|
+
directly to the first word of a multiword name, as in `kiloastronomical unit`;
|
|
334
|
+
a separate `kilo astronomical unit` is not accepted. `PrefixPolicy` is available
|
|
335
|
+
from `unitx.unitregistry` for annotations and means `bool | str | tuple[str, ...]`.
|
|
336
|
+
|
|
337
|
+
```pycon
|
|
338
|
+
>>> tick = si.s.define(
|
|
339
|
+
... 'demoTick',
|
|
340
|
+
... 'survey interval',
|
|
341
|
+
... symbol_aliases='demoT',
|
|
342
|
+
... prefixable=('demoT', 'survey interval'),
|
|
343
|
+
... )
|
|
344
|
+
>>> Unit('[millisurvey interval]') == Unit('mdemoT')
|
|
345
|
+
True
|
|
346
|
+
>>> Quantity(1000, 'mdemoT').to(tick).value
|
|
347
|
+
Fraction(1, 1)
|
|
348
|
+
>>> Unit('mdemoT').expression()
|
|
349
|
+
'mdemoT'
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Prefix permissions are checked before alias normalization. Canonical identity
|
|
354
|
+
still uses the original registered unit and canonical prefix, independent of
|
|
355
|
+
the input alias. Preferred spellings use the first permitted symbol or alias;
|
|
356
|
+
if only a name supports a prefix, `SingleUnit.symbol` falls back to that name
|
|
357
|
+
and `Unit.expression()` emits a `[name]` reference. Conversely, `SingleUnit.name`
|
|
358
|
+
falls back to a symbol if no name allows that prefix. Repr and pickle preserve
|
|
359
|
+
the same formal unit, rather than replacing the prefix with an extra scale.
|
|
360
|
+
|
|
361
|
+
`arcsec` and `arcsecond` accept prefixes, for example `marcsec` and
|
|
362
|
+
`milliarcsecond`; `″` and `"` do not. `as` continues to mean attosecond,
|
|
363
|
+
and `mas` is not an arcsecond alias. `a` (are) and `ha` (hectare) are separate
|
|
364
|
+
unprefixable units; `Pa` remains pascal. `yr` remains exactly 365 days.
|
|
365
|
+
`a_j` is the Julian year of exactly 365.25 days (31,557,600 seconds), while
|
|
366
|
+
`mo` is one twelfth of that interval, rather than a variable calendar month.
|
|
367
|
+
The name exceptions `megohm` and `kilohm` are supported alongside the older
|
|
368
|
+
`megaohm` and `kiloohm` spellings; `gigaohm` retains both vowels. No general
|
|
369
|
+
vowel-elision rule is applied.
|
|
370
|
+
|
|
371
|
+
`ly` is defined using the speed of light and the Julian year; `eV` uses the
|
|
372
|
+
elementary charge and volt. Both reuse the defining constants exposed by `SI`.
|
|
373
|
+
`mHg` is the registered metre-of-mercury unit and `mmHg` is its milli-prefixed
|
|
374
|
+
form; `760 * si.mmHg` converts to `si.atm` with value 1 under the library's
|
|
375
|
+
existing pressure convention. Prefixes do not stack: `mmmHg` and `kmmHg` are
|
|
376
|
+
invalid. `kt` retains its meaning as a knot alias; tonne remains unprefixable.
|
|
377
|
+
|
|
378
|
+
`si.mas` and `si.uas` provide milli- and microarcseconds as namespace shortcuts;
|
|
379
|
+
their registered expressions are `marcsec` and `µarcsec`. The strings `mas`
|
|
380
|
+
and `uas` are not registered aliases. `si.Da` and `si.u` now share one formal
|
|
381
|
+
unit identity; only the spelling `Da` accepts prefixes, such as `kDa`.
|
|
382
|
+
`si.mTorr` is available, and Torr accepts SI prefixes. Tonne uses `t` or
|
|
383
|
+
`tonne`; the ambiguous spelling `ton` is not registered.
|
|
384
|
+
|
|
385
|
+
`si.rpm` represents rotational frequency: `60 * si.rpm` converts to `si.Hz`
|
|
386
|
+
with value 1. For angular velocity, multiply that frequency by `2 * PI` and
|
|
387
|
+
convert to `si.rad / si.s`; directly converting frequency to `rad/s` does
|
|
388
|
+
not insert the physical factor of 2π. `si.c` is a speed unit equal to the
|
|
389
|
+
speed of light, while `SI.c` is the corresponding physical quantity.
|
|
390
|
+
|
|
391
|
+
The spelling `u` denotes the unified atomic mass unit when used on its own.
|
|
392
|
+
ASCII micro spellings such as `um` and `us` remain supported without warnings,
|
|
393
|
+
so entering non-ASCII characters is optional. `um`, `µm`, `μm`, and
|
|
394
|
+
`micrometre` all mean micrometres; the explicit product `u m` instead means
|
|
395
|
+
unified atomic mass unit times metre.
|
|
302
396
|
|
|
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
397
|
Registration raises `UnitRegistryError` if a new spelling, including a generated
|
|
307
398
|
prefixed form, already resolves to a unit or conflicts with another spelling
|
|
308
399
|
in the same definition. A multiword spelling must not replace an existing
|
|
309
400
|
implicit product such as `metre second`. Validation finishes before the
|
|
310
401
|
registry changes.
|
|
311
402
|
|
|
403
|
+
The registry and spelling rules live in `unitx.unitregistry`; parsing expressions
|
|
404
|
+
does not change unit definitions. A parser instance caches only a successful
|
|
405
|
+
result; failed parses may be retried after a definition is added. Registration
|
|
406
|
+
preserves existing valid spellings and validates before updating its indexes.
|
|
407
|
+
Concurrent registry writes and isolated registry contexts are not supported.
|
|
408
|
+
|
|
312
409
|
Quantity definitions require positive finite `int`, `Fraction`, `Decimal`, or
|
|
313
410
|
`float` magnitudes. Prefer `Fraction` or `Decimal` for exact scales. Floats use
|
|
314
411
|
Factor's denominator limit and can warn or round to zero and fail, for example
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Class-based namespaces for constants accessed directly as class attributes.
|
|
2
|
+
|
|
3
|
+
Namespaces cannot be instantiated, and their attributes cannot be rebound or
|
|
4
|
+
deleted. Objects referenced by those attributes are not recursively frozen.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, NoReturn
|
|
8
|
+
|
|
9
|
+
__all__ = ['ConstNamespace']
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _ConstNamespaceMeta(type):
|
|
13
|
+
def __call__(metacls, *args: Any, **kwds: Any) -> NoReturn:
|
|
14
|
+
"""
|
|
15
|
+
This namespace cannot be instantiated; access constants via class attributes.
|
|
16
|
+
"""
|
|
17
|
+
raise TypeError(metacls.__call__.__doc__)
|
|
18
|
+
|
|
19
|
+
def __setattr__(cls, name, value) -> NoReturn:
|
|
20
|
+
"""
|
|
21
|
+
Constant namespace attributes cannot be assigned.
|
|
22
|
+
"""
|
|
23
|
+
raise AttributeError(cls.__class__.__setattr__.__doc__)
|
|
24
|
+
|
|
25
|
+
def __delattr__(cls, name) -> NoReturn:
|
|
26
|
+
"""
|
|
27
|
+
Constant namespace attributes cannot be deleted.
|
|
28
|
+
"""
|
|
29
|
+
raise AttributeError(cls.__class__.__delattr__.__doc__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ConstNamespace(metaclass=_ConstNamespaceMeta):
|
|
33
|
+
"""Base for constant namespaces with protected class attribute bindings."""
|
|
@@ -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]:
|