Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QuantityKinds #1967

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions pint/default_en.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,15 @@ count = []

@import constants_en.txt


#### UNITS ####
# Common and less common, grouped by quantity.
# Conversion factors are exact (except when noted),
# although floating-point conversion may introduce inaccuracies

# Angle
[arc_length] = [length]
[radius] = [length]
[angle] = [arc_length] / [radius]
turn = 2 * π * radian = _ = revolution = cycle = circle
degree = π / 180 * radian = deg = arcdeg = arcdegree = angular_degree
arcminute = degree / 60 = arcmin = arc_minute = angular_minute
Expand Down Expand Up @@ -212,6 +214,9 @@ degree_Reaumur = 4 / 5 * kelvin; offset: 273.15 = °Re = reaumur = degRe = degre
atomic_unit_of_temperature = E_h / k = a_u_temp
planck_temperature = (hbar * c ** 5 / gravitational_constant / k ** 2) ** 0.5

# Specific heat capacity
# [specific_heat_capacity] = [energy] / [temperature] / [mass] = J / kg / K

# Area
[area] = [length] ** 2
are = 100 * meter ** 2
Expand All @@ -229,6 +234,7 @@ stere = meter ** 3
# Frequency
[frequency] = 1 / [time]
hertz = 1 / second = Hz
[angular_frequency] = [angle] / [time]
revolutions_per_minute = revolution / minute = rpm
revolutions_per_second = revolution / second = rps
counts_per_second = count / second = cps
Expand Down Expand Up @@ -256,7 +262,7 @@ sverdrup = 1e6 * meter ** 3 / second = sv
galileo = centimeter / second ** 2 = Gal

# Force
[force] = [mass] * [acceleration]
[force] = [mass] * [acceleration] = N
newton = kilogram * meter / second ** 2 = N
dyne = gram * centimeter / second ** 2 = dyn
force_kilogram = g_0 * kilogram = kgf = kilogram_force = pond
Expand All @@ -265,7 +271,7 @@ force_metric_ton = g_0 * metric_ton = tf = metric_ton_force = force_t = t_force
atomic_unit_of_force = E_h / a_0 = a_u_force

# Energy
[energy] = [force] * [length]
[energy] = [force] * [length] = J
joule = newton * meter = J
erg = dyne * centimeter
watt_hour = watt * hour = Wh = watthour
Expand All @@ -285,8 +291,13 @@ ton_TNT = 1e9 * calorie = tTNT
tonne_of_oil_equivalent = 1e10 * international_calorie = toe
atmosphere_liter = atmosphere * liter = atm_l

# Torque
[moment_arm] = [length] = m
[torque] = [force] * [moment_arm] = N m
foot_pound = foot * force_pound = ft_lb = footpound

# Power
[power] = [energy] / [time]
[power] = [energy] / [time] = [torque] * [angular_frequency] = [volumetric_flow_rate] * [pressure] = W
watt = joule / second = W
volt_ampere = volt * ampere = VA
horsepower = 550 * foot * force_pound / second = hp = UK_horsepower = hydraulic_horsepower
Expand All @@ -299,7 +310,7 @@ standard_liter_per_minute = atmosphere * liter / minute = slpm = slm
conventional_watt_90 = K_J90 ** 2 * R_K90 / (K_J ** 2 * R_K) * watt = W_90

# Momentum
[momentum] = [length] * [mass] / [time]
[momentum] = [velocity] * [mass]

# Density (as auxiliary for pressure)
[density] = [mass] / [volume]
Expand Down Expand Up @@ -328,9 +339,6 @@ foot_H2O = foot * water * g_0 = ftH2O = feet_H2O
centimeter_H2O = centimeter * water * g_0 = cmH2O = cm_H2O
sound_pressure_level = 20e-6 * pascal = SPL

# Torque
[torque] = [force] * [length]
foot_pound = foot * force_pound = ft_lb = footpound

# Viscosity
[viscosity] = [pressure] * [time]
Expand Down
27 changes: 27 additions & 0 deletions pint/delegates/formatter/full.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

if TYPE_CHECKING:
from ...compat import Locale
from ...facets.kind import KindKind, QuantityKind
from ...facets.measurement import Measurement
from ...facets.plain import (
MagnitudeT,
Expand Down Expand Up @@ -130,6 +131,19 @@ def format_unit(
unit, uspec, sort_func=sort_func, **babel_kwds
)

def format_kind(
self,
kind: KindKind | Iterable[tuple[str, Any]],
uspec: str = "",
sort_func: SortFunc | None = None,
**babel_kwds: Unpack[BabelKwds],
) -> str:
uspec = uspec or self.default_format
sort_func = sort_func or self.default_sort_func
return self.get_formatter(uspec).format_kind(
kind, uspec, sort_func=sort_func, **babel_kwds
)

def format_quantity(
self,
quantity: PlainQuantity[MagnitudeT],
Expand Down Expand Up @@ -167,6 +181,19 @@ def format_quantity(
locale=locale,
)

def format_quantitykind(
self,
quantitykind: QuantityKind | Iterable[tuple[str, Any]],
uspec: str = "",
sort_func: SortFunc | None = None,
**babel_kwds: Unpack[BabelKwds],
) -> str:
uspec = uspec or self.default_format
sort_func = sort_func or self.default_sort_func
return self.get_formatter(uspec).format_quantitykind(
quantitykind, uspec, sort_func=sort_func, **babel_kwds
)

def format_measurement(
self,
measurement: Measurement,
Expand Down
36 changes: 36 additions & 0 deletions pint/delegates/formatter/plain.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
)

if TYPE_CHECKING:
from ...facets.kind import KindKind, QuantityKind
from ...facets.measurement import Measurement
from ...facets.plain import MagnitudeT, PlainQuantity, PlainUnit
from ...registry import UnitRegistry
Expand All @@ -51,6 +52,41 @@ class BaseFormatter:
def __init__(self, registry: UnitRegistry | None = None):
self._registry = registry

def format_kind(
self,
kind: KindKind | Iterable[tuple[str, Any]],
uspec: str = "",
sort_func: SortFunc | None = None,
**babel_kwds: Unpack[BabelKwds],
) -> str:
"""Format a unit (can be compound) into string
given a string formatting specification and locale related arguments.
"""
kind = kind._kinds
return self.format_unit(kind, uspec, sort_func, **babel_kwds)

def format_quantitykind(
self,
quantitykind: QuantityKind,
qspec: str = "",
sort_func: SortFunc | None = None,
**babel_kwds: Unpack[BabelKwds],
) -> str:
"""Format a quantitykind into string
given a string formatting specification and locale related arguments.
"""
quantity = quantitykind.quantity

registry = self._registry

mspec, uspec = split_format(
qspec, registry.formatter.default_format, registry.separate_format_defaults
)

mu = self.format_quantity(quantity, qspec, sort_func, **babel_kwds)
k = self.format_kind(quantitykind.kinds, uspec, sort_func, **babel_kwds)
return mu + " " + k


class DefaultFormatter(BaseFormatter):
"""Simple, localizable plain text formatter.
Expand Down
38 changes: 23 additions & 15 deletions pint/delegates/txt_defparser/plain.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,11 @@ class DerivedDimensionDefinition(
):
"""Definition of a derived dimension::

[dimension name] = <relation to other dimensions>
[dimension name] = <relation to other dimensions> [= <preferred unit>]

Example::

[density] = [mass] / [volume]
[density] = [mass] / [volume] = kilogram / meter ** 3
"""

@classmethod
Expand All @@ -235,23 +235,31 @@ def from_string_and_config(
if not (s.startswith("[") and "=" in s):
return None

name, value, *aliases = s.split("=")
name, value, *alt_refs = (p.strip() for p in s.split("="))

if aliases:
return common.DefinitionSyntaxError(
"Derived dimensions cannot have aliases."
)
preferred_unit = None
if alt_refs:
if "[" not in alt_refs[-1]:
preferred_unit = alt_refs[-1]
alt_refs = alt_refs[:-1]
else:
alt_refs = []

try:
reference = config.to_dimension_container(value)
except common.DefinitionSyntaxError as exc:
return common.DefinitionSyntaxError(
f"In {name} derived dimensions must only be referenced "
f"to dimensions. {exc}"
)
def to_dim_container(string):
try:
reference = config.to_dimension_container(string)
except common.DefinitionSyntaxError as exc:
return common.DefinitionSyntaxError(
f"In {name} derived dimensions must only be referenced "
f"to dimensions. {exc}"
)
return reference

reference = to_dim_container(value)
alternate_references = tuple([to_dim_container(ref) for ref in alt_refs])

try:
return cls(name.strip(), reference)
return cls(name.strip(), reference, preferred_unit, alternate_references)
except Exception as exc:
return common.DefinitionSyntaxError(str(exc))

Expand Down
3 changes: 3 additions & 0 deletions pint/facets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class that belongs to a registry that has NumpyRegistry as one of its bases.
from .context import ContextRegistry, GenericContextRegistry
from .dask import DaskRegistry, GenericDaskRegistry
from .group import GenericGroupRegistry, GroupRegistry
from .kind import GenericKindRegistry, KindRegistry
from .measurement import GenericMeasurementRegistry, MeasurementRegistry
from .nonmultiplicative import (
GenericNonMultiplicativeRegistry,
Expand Down Expand Up @@ -103,4 +104,6 @@ class that belongs to a registry that has NumpyRegistry as one of its bases.
"QuantityT",
"UnitT",
"MagnitudeT",
"GenericKindRegistry",
"KindRegistry",
]
21 changes: 21 additions & 0 deletions pint/facets/kind/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
pint.facets.Kind
~~~~~~~~~~~~~~~~~~~~~~~

Adds pint the capability to handle Kinds (quantities with uncertainties).

:copyright: 2022 by Pint Authors, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""

from __future__ import annotations

from .objects import KindKind, KindQuantity
from .registry import GenericKindRegistry, KindRegistry

__all__ = [
"KindKind",
"KindQuantity",
"KindRegistry",
"GenericKindRegistry",
]
Loading
Loading