1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
from __future__ import annotations
import re
import typing as ty
from dataclasses import dataclass
import flexparser.flexparser as fp
from . import common, plain
@dataclass(frozen=True)
class BeginGroup(fp.ParsedStatement):
"""Being of a group directive.
@group <name> [using <group 1>, ..., <group N>]
"""
#: Regex to match the header parts of a definition.
_header_re = re.compile(r"@group\s+(?P<name>\w+)\s*(using\s(?P<used_groups>.*))*")
name: str
using_group_names: ty.Tuple[str, ...]
@classmethod
def from_string(cls, s: str) -> fp.NullableParsedResult[BeginGroup]:
if not s.startswith("@group"):
return None
r = cls._header_re.search(s)
if r is None:
raise ValueError("Invalid Group header syntax: '%s'" % s)
name = r.groupdict()["name"].strip()
groups = r.groupdict()["used_groups"]
if groups:
parent_group_names = tuple(a.strip() for a in groups.split(","))
else:
parent_group_names = ()
return cls(name, parent_group_names)
@dataclass(frozen=True)
class GroupDefinition(common.DirectiveBlock):
"""Definition of a group.
@group <name> [using <group 1>, ..., <group N>]
<definition 1>
...
<definition N>
@end
See UnitDefinition and Comment for more parsing related information.
Example::
@group AvoirdupoisUS using Avoirdupois
US_hundredweight = hundredweight = US_cwt
US_ton = ton
US_force_ton = force_ton = _ = US_ton_force
@end
"""
@property
def unit_names(self) -> ty.Tuple[str, ...]:
return tuple(
el.name for el in self.body if isinstance(el, plain.UnitDefinition)
)
|