mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Vendor Pint and test on Python 3.13, refs #2434
This commit is contained in:
parent
5cac74c4ac
commit
a104554dfc
79 changed files with 16901 additions and 4 deletions
224
datasette/vendored/pint/facets/group/objects.py
Normal file
224
datasette/vendored/pint/facets/group/objects.py
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
"""
|
||||
pint.facets.group.objects
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:copyright: 2022 by Pint Authors, see AUTHORS for more details.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable, Generator, Iterable
|
||||
from typing import TYPE_CHECKING, Any, Generic
|
||||
|
||||
from ...util import SharedRegistryObject, getattr_maybe_raise
|
||||
from ..plain import MagnitudeT, PlainQuantity, PlainUnit
|
||||
from .definitions import GroupDefinition
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..plain import UnitDefinition
|
||||
|
||||
DefineFunc = Callable[
|
||||
[
|
||||
Any,
|
||||
],
|
||||
None,
|
||||
]
|
||||
AddUnitFunc = Callable[
|
||||
[
|
||||
UnitDefinition,
|
||||
],
|
||||
None,
|
||||
]
|
||||
|
||||
|
||||
class GroupQuantity(Generic[MagnitudeT], PlainQuantity[MagnitudeT]):
|
||||
pass
|
||||
|
||||
|
||||
class GroupUnit(PlainUnit):
|
||||
pass
|
||||
|
||||
|
||||
class Group(SharedRegistryObject):
|
||||
"""A group is a set of units.
|
||||
|
||||
Units can be added directly or by including other groups.
|
||||
|
||||
Members are computed dynamically, that is if a unit is added to a group X
|
||||
all groups that include X are affected.
|
||||
|
||||
The group belongs to one Registry.
|
||||
|
||||
See GroupDefinition for the definition file syntax.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name
|
||||
If not given, a root Group will be created.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str):
|
||||
# The name of the group.
|
||||
self.name = name
|
||||
|
||||
#: Names of the units in this group.
|
||||
#: :type: set[str]
|
||||
self._unit_names: set[str] = set()
|
||||
|
||||
#: Names of the groups in this group.
|
||||
self._used_groups: set[str] = set()
|
||||
|
||||
#: Names of the groups in which this group is contained.
|
||||
self._used_by: set[str] = set()
|
||||
|
||||
# Add this group to the group dictionary
|
||||
self._REGISTRY._groups[self.name] = self
|
||||
|
||||
if name != "root":
|
||||
# All groups are added to root group
|
||||
self._REGISTRY._groups["root"].add_groups(name)
|
||||
|
||||
#: A cache of the included units.
|
||||
#: None indicates that the cache has been invalidated.
|
||||
self._computed_members: frozenset[str] | None = None
|
||||
|
||||
@property
|
||||
def members(self) -> frozenset[str]:
|
||||
"""Names of the units that are members of the group.
|
||||
|
||||
Calculated to include to all units in all included _used_groups.
|
||||
|
||||
"""
|
||||
if self._computed_members is None:
|
||||
tmp = set(self._unit_names)
|
||||
|
||||
for _, group in self.iter_used_groups():
|
||||
tmp |= group.members
|
||||
|
||||
self._computed_members = frozenset(tmp)
|
||||
|
||||
return self._computed_members
|
||||
|
||||
def invalidate_members(self) -> None:
|
||||
"""Invalidate computed members in this Group and all parent nodes."""
|
||||
self._computed_members = None
|
||||
d = self._REGISTRY._groups
|
||||
for name in self._used_by:
|
||||
d[name].invalidate_members()
|
||||
|
||||
def iter_used_groups(self) -> Generator[tuple[str, Group], None, None]:
|
||||
pending = set(self._used_groups)
|
||||
d = self._REGISTRY._groups
|
||||
while pending:
|
||||
name = pending.pop()
|
||||
group = d[name]
|
||||
pending |= group._used_groups
|
||||
yield name, d[name]
|
||||
|
||||
def is_used_group(self, group_name: str) -> bool:
|
||||
for name, _ in self.iter_used_groups():
|
||||
if name == group_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_units(self, *unit_names: str) -> None:
|
||||
"""Add units to group."""
|
||||
for unit_name in unit_names:
|
||||
self._unit_names.add(unit_name)
|
||||
|
||||
self.invalidate_members()
|
||||
|
||||
@property
|
||||
def non_inherited_unit_names(self) -> frozenset[str]:
|
||||
return frozenset(self._unit_names)
|
||||
|
||||
def remove_units(self, *unit_names: str) -> None:
|
||||
"""Remove units from group."""
|
||||
for unit_name in unit_names:
|
||||
self._unit_names.remove(unit_name)
|
||||
|
||||
self.invalidate_members()
|
||||
|
||||
def add_groups(self, *group_names: str) -> None:
|
||||
"""Add groups to group."""
|
||||
d = self._REGISTRY._groups
|
||||
for group_name in group_names:
|
||||
grp = d[group_name]
|
||||
|
||||
if grp.is_used_group(self.name):
|
||||
raise ValueError(
|
||||
"Cyclic relationship found between %s and %s"
|
||||
% (self.name, group_name)
|
||||
)
|
||||
|
||||
self._used_groups.add(group_name)
|
||||
grp._used_by.add(self.name)
|
||||
|
||||
self.invalidate_members()
|
||||
|
||||
def remove_groups(self, *group_names: str) -> None:
|
||||
"""Remove groups from group."""
|
||||
d = self._REGISTRY._groups
|
||||
for group_name in group_names:
|
||||
grp = d[group_name]
|
||||
|
||||
self._used_groups.remove(group_name)
|
||||
grp._used_by.remove(self.name)
|
||||
|
||||
self.invalidate_members()
|
||||
|
||||
@classmethod
|
||||
def from_lines(
|
||||
cls, lines: Iterable[str], define_func: DefineFunc, non_int_type: type = float
|
||||
) -> Group:
|
||||
"""Return a Group object parsing an iterable of lines.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lines : list[str]
|
||||
iterable
|
||||
define_func : callable
|
||||
Function to define a unit in the registry; it must accept a single string as
|
||||
a parameter.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
"""
|
||||
group_definition = GroupDefinition.from_lines(lines, non_int_type)
|
||||
|
||||
if group_definition is None:
|
||||
raise ValueError(f"Could not define group from {lines}")
|
||||
|
||||
return cls.from_definition(group_definition, define_func)
|
||||
|
||||
@classmethod
|
||||
def from_definition(
|
||||
cls,
|
||||
group_definition: GroupDefinition,
|
||||
add_unit_func: AddUnitFunc | None = None,
|
||||
) -> Group:
|
||||
grp = cls(group_definition.name)
|
||||
|
||||
add_unit_func = add_unit_func or grp._REGISTRY._add_unit
|
||||
|
||||
# We first add all units defined within the group
|
||||
# to the registry.
|
||||
for definition in group_definition.definitions:
|
||||
add_unit_func(definition)
|
||||
|
||||
# Then we add all units defined within the group
|
||||
# to this group (by name)
|
||||
grp.add_units(*group_definition.unit_names)
|
||||
|
||||
# Finally, we add all grou0ps used by this group
|
||||
# tho this group (by name)
|
||||
if group_definition.using_group_names:
|
||||
grp.add_groups(*group_definition.using_group_names)
|
||||
|
||||
return grp
|
||||
|
||||
def __getattr__(self, item: str):
|
||||
getattr_maybe_raise(self, item)
|
||||
return self._REGISTRY
|
||||
Loading…
Add table
Add a link
Reference in a new issue