From bdb767ddfd7bedaa1c3858c04ffbcd2b77603ca4 Mon Sep 17 00:00:00 2001 From: Gavin Medley <7018964+medley56@users.noreply.github.com> Date: Fri, 3 Apr 2026 05:39:46 +0000 Subject: [PATCH] Fix Typehinting - For lxml classes like ElementTree --- meta.yaml | 1 + pyproject.toml | 3 +- space_packet_parser/common.py | 20 ++--- space_packet_parser/xtce/calibrators.py | 99 +++++++++++---------- space_packet_parser/xtce/comparisons.py | 92 +++++++++---------- space_packet_parser/xtce/containers.py | 30 +++---- space_packet_parser/xtce/definitions.py | 16 ++-- space_packet_parser/xtce/encodings.py | 81 ++++++++--------- space_packet_parser/xtce/parameter_types.py | 87 +++++++++--------- space_packet_parser/xtce/parameters.py | 17 ++-- space_packet_parser/xtce/validation.py | 16 ++-- 11 files changed, 236 insertions(+), 226 deletions(-) diff --git a/meta.yaml b/meta.yaml index d1775a0..ab2e7d6 100644 --- a/meta.yaml +++ b/meta.yaml @@ -41,6 +41,7 @@ test: - tomli - xarray - numpy + - lxml-stubs source_files: - tests commands: diff --git a/pyproject.toml b/pyproject.toml index 9f0869f..5fbedfe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,7 +77,8 @@ test = [ "ruff", "tomli", # for support of python<3.11 toml parsing in check_metadata.py "xarray", # for testing extra - "numpy" # for testing extra + "numpy", # for testing extra + "lxml-stubs" # for type checking of lxml in tests ] docs = [ "pyyaml", diff --git a/space_packet_parser/common.py b/space_packet_parser/common.py index d6f95c3..868bd0d 100644 --- a/space_packet_parser/common.py +++ b/space_packet_parser/common.py @@ -6,7 +6,7 @@ import logging import warnings from abc import ABCMeta, abstractmethod -from typing import Protocol +from typing import Any, Protocol import lxml.etree as ElementTree from lxml.builder import ElementMaker @@ -150,12 +150,12 @@ class XmlObject(metaclass=ABCMeta): @abstractmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.ElementTree | None, - parameter_lookup: dict[str, any] | None, - parameter_type_lookup: dict[str, any] | None, - container_lookup: dict[str, any] | None, + tree: ElementTree._ElementTree | None, + parameter_lookup: dict[str, Any] | None, + parameter_type_lookup: dict[str, Any] | None, + container_lookup: dict[str, Any] | None, ) -> XmlObject: """Create an object from an XML element @@ -167,9 +167,9 @@ def from_xml( Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element from which to parse the object - tree: Optional[ElementTree.ElementTree] + tree: Optional[ElementTree._ElementTree] Full XML tree for parsing that requires access to other elements parameter_lookup: Optional[dict[str, parameters.ParameterType]] Parameters dict for parsing that requires knowledge of existing parameters @@ -185,7 +185,7 @@ def from_xml( raise NotImplementedError() @abstractmethod - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create an XML element from the object self Parameters @@ -195,7 +195,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element XML Element object """ raise NotImplementedError() diff --git a/space_packet_parser/xtce/calibrators.py b/space_packet_parser/xtce/calibrators.py index a880de4..7ad2026 100644 --- a/space_packet_parser/xtce/calibrators.py +++ b/space_packet_parser/xtce/calibrators.py @@ -4,6 +4,7 @@ from abc import ABCMeta, abstractmethod from collections import namedtuple +from typing import Any import lxml.etree as ElementTree from lxml.builder import ElementMaker @@ -19,20 +20,20 @@ class Calibrator(common.AttrComparable, common.XmlObject, metaclass=ABCMeta): @abstractmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> Calibrator: """Abstract classmethod to create a default_calibrator object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -96,20 +97,20 @@ def __init__(self, points: list, order: int = 0, extrapolate: bool = False): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> SplineCalibrator: """Create a spline default_calibrator object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element The XML element from which to create the object. - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -130,7 +131,7 @@ def from_xml( extrapolate = element.attrib["extrapolate"].lower() == "true" if "extrapolate" in element.attrib else False return cls(order=order, points=spline_points, extrapolate=extrapolate) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a SplineCalibrator XML element Parameters @@ -140,7 +141,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ return elmaker.SplineCalibrator( *(elmaker.SplinePoint(raw=str(p.raw), calibrated=str(p.calibrated)) for p in self.points), @@ -266,20 +267,20 @@ def __init__(self, coefficients: list[PolynomialCoefficient]): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> PolynomialCalibrator: """Create a polynomial default_calibrator object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -298,7 +299,7 @@ def from_xml( ] return cls(coefficients=coefficients) - def to_xml(self, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, elmaker: ElementMaker) -> ElementTree._Element: """Create a PolynomialCalibrator XML element Parameters @@ -308,7 +309,7 @@ def to_xml(self, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ return elmaker.PolynomialCalibrator( *( @@ -348,20 +349,20 @@ def __init__(self): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> MathOperationCalibrator: """Create a math operation default_calibrator from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element The XML element from which to create the object. - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -376,7 +377,7 @@ def from_xml( """ raise NotImplementedError(cls.err_msg) - def to_xml(self, elmaker: dict) -> ElementTree.Element: + def to_xml(self, elmaker: dict) -> ElementTree._Element: """Create a MathOperationsCalibrator XML element Parameters @@ -386,7 +387,7 @@ def to_xml(self, elmaker: dict) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ raise NotImplementedError(self.err_msg) @@ -423,12 +424,12 @@ def __init__(self, match_criteria: list, calibrator: Calibrator): self.calibrator = calibrator @staticmethod - def get_context_match_criteria(element: ElementTree.Element) -> list[comparisons.MatchCriteria]: + def get_context_match_criteria(element: ElementTree._Element) -> list[comparisons.MatchCriteria]: """Parse contextual requirements from a Comparison, ComparisonList, or BooleanExpression Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element from which to parse the ContextCalibrator object. Returns @@ -437,6 +438,10 @@ def get_context_match_criteria(element: ElementTree.Element) -> list[comparisons List of Comparisons that can be evaluated to determine whether this calibrator should be used. """ context_match_element = element.find("ContextMatch") + if not context_match_element: + raise ValueError( + f"ContextCalibrator XML element {element.tag} {element.attrib} must contain a ContextMatch element" + ) if (comparison_list_element := context_match_element.find("ComparisonList")) is not None: return [comparisons.Comparison.from_xml(el) for el in comparison_list_element.iterfind("Comparison")] if (comparison_element := context_match_element.find("Comparison")) is not None: @@ -452,20 +457,20 @@ def get_context_match_criteria(element: ElementTree.Element) -> list[comparisons @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> ContextCalibrator: """Create a ContextCalibrator object from an XML element Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element from which to parse the ContextCalibrator object. - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -481,9 +486,9 @@ def from_xml( match_criteria = cls.get_context_match_criteria(element) if (cal_element := element.find("Calibrator/SplineCalibrator")) is not None: - calibrator = SplineCalibrator.from_xml(cal_element) + calibrator: Calibrator = SplineCalibrator.from_xml(cal_element) elif (cal_element := element.find("Calibrator/PolynomialCalibrator")) is not None: - calibrator = PolynomialCalibrator.from_xml(cal_element) + calibrator: Calibrator = PolynomialCalibrator.from_xml(cal_element) else: raise NotImplementedError( "Unsupported default_calibrator type. space_packet_parser only supports Polynomial and Spline" @@ -492,7 +497,7 @@ def from_xml( return cls(match_criteria=match_criteria, calibrator=calibrator) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a MathOperationsCalibrator XML element Parameters @@ -502,7 +507,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ context_match_element = elmaker.ContextMatch() diff --git a/space_packet_parser/xtce/comparisons.py b/space_packet_parser/xtce/comparisons.py index 99fef94..5f1e4a2 100644 --- a/space_packet_parser/xtce/comparisons.py +++ b/space_packet_parser/xtce/comparisons.py @@ -51,7 +51,7 @@ def evaluate(self, packet: spp.SpacePacket, current_parsed_value: int | float | ---------- packet : space_packet_parser.SpacePacket Packet data used to evaluate truthyness of the match criteria. - current_parsed_value : any, Optional + current_parsed_value : Any, Optional Uncalibrated value that is currently being matched (e.g. as a candidate for calibration). Used to resolve comparisons that reference their own raw value as a condition. @@ -107,20 +107,20 @@ def _validate(self): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> Comparison: """Create Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -146,7 +146,7 @@ def from_xml( return cls(value, parameter_name, operator=operator, use_calibrated_value=use_calibrated_value) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a Comparison XML element Parameters @@ -156,7 +156,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ return elmaker.Comparison( parameterRef=self.referenced_parameter, @@ -273,12 +273,12 @@ def _validate(self): raise ComparisonError(f"Unable to use calibrated form of a fixed value in Condition {self}.") @staticmethod - def _parse_parameter_instance_ref(element: ElementTree.Element): + def _parse_parameter_instance_ref(element: ElementTree._Element): """Parse an xtce:ParameterInstanceRef element Parameters ---------- - element: ElementTree.Element + element: ElementTree._Element xtce:ParameterInstanceRef element Returns @@ -297,20 +297,20 @@ def _parse_parameter_instance_ref(element: ElementTree.Element): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> Condition: """Classmethod to create a Condition object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -350,7 +350,7 @@ def from_xml( f"Failed to parse a Condition element {element}. See 3.4.3.4.2 of XTCE Green Book CCSDS 660.1-G-2" ) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a Condition XML element Parameters @@ -360,7 +360,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ condition = elmaker.Condition( elmaker.ParameterInstanceRef( @@ -444,20 +444,20 @@ def __repr__(self): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> BooleanExpression: """Abstract classmethod to create a match criteria object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -471,12 +471,12 @@ def from_xml( : BooleanExpression """ - def _parse_anded(anded_el: ElementTree.Element) -> Anded: + def _parse_anded(anded_el: ElementTree._Element) -> Anded: """Create an Anded object from an xtce:ANDedConditions element Parameters ---------- - anded_el: ElementTree.Element + anded_el: ElementTree._Element xtce:ANDedConditions element Returns @@ -487,12 +487,12 @@ def _parse_anded(anded_el: ElementTree.Element) -> Anded: anded_ors = [_parse_ored(anded_or) for anded_or in anded_el.iterfind("ORedConditions")] return Anded(conditions, anded_ors) - def _parse_ored(ored_el: ElementTree.Element) -> Ored: + def _parse_ored(ored_el: ElementTree._Element) -> Ored: """Create an Ored object from an xtce:ARedConditions element Parameters ---------- - ored_el: ElementTree.Element + ored_el: ElementTree._Element xtce:ORedConditions element Returns @@ -555,7 +555,7 @@ def _and(anded: Anded): raise ValueError(f"Error evaluating an unknown expression {self.expression}.") - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a Condition XML element Parameters @@ -565,16 +565,16 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ - def _serialize_anded(anded: Anded) -> ElementTree.Element: + def _serialize_anded(anded: Anded) -> ElementTree._Element: return elmaker.ANDedConditions( *(cond.to_xml(elmaker=elmaker) for cond in anded.conditions), *(_serialize_ored(ored) for ored in anded.ors), ) - def _serialize_ored(ored: Ored) -> ElementTree.Element: + def _serialize_ored(ored: Ored) -> ElementTree._Element: return elmaker.ORedConditions( *(cond.to_xml(elmaker=elmaker) for cond in ored.conditions), *(_serialize_anded(anded) for anded in ored.ands), @@ -611,20 +611,20 @@ def __init__(self, match_criteria: list[Comparison], lookup_value: int | float): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.ElementTree | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> DiscreteLookup: """Create a DiscreteLookup object from an XML element Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element from which to parse the DiscreteLookup object. - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -647,7 +647,7 @@ def from_xml( return cls(match_criteria, lookup_value) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a DiscreteLookup XML element Parameters @@ -657,7 +657,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ match_criteria = (c.to_xml(elmaker=elmaker) for c in self.match_criteria) @@ -681,7 +681,7 @@ def evaluate(self, packet: spp.SpacePacket, current_parsed_value: int | float | Returns ------- - : any + : Any Return the lookup value if the match criteria evaluate true. Return None otherwise. """ if all(criterion.evaluate(packet, current_parsed_value) for criterion in self.match_criteria): diff --git a/space_packet_parser/xtce/containers.py b/space_packet_parser/xtce/containers.py index e12d1e8..78515f6 100644 --- a/space_packet_parser/xtce/containers.py +++ b/space_packet_parser/xtce/containers.py @@ -61,9 +61,9 @@ def parse(self, packet: spp.SpacePacket) -> None: @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.ElementTree, + tree: ElementTree._ElementTree, parameter_lookup: dict[str, parameters.Parameter], container_lookup: dict[str, Any] | None, parameter_type_lookup: dict[str, parameter_types.ParameterType] | None = None, @@ -75,9 +75,9 @@ def from_xml( Parameters ---------- - tree : ElementTree.ElementTree + tree : ElementTree._ElementTree Full XTCE tree - element : ElementTree.Element + element : ElementTree._Element The SequenceContainer element to parse. parameter_lookup : dict[str, parameters.Parameter] Parameters contained in the entry lists of sequence containers @@ -147,7 +147,7 @@ def from_xml( long_description=long_description, ) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a SequenceContainer XML element Parameters @@ -157,7 +157,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ em = elmaker sc_attrib = {"abstract": str(self.abstract).lower(), "name": self.name} @@ -201,7 +201,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: return sc @staticmethod - def _get_container_element(tree: ElementTree.ElementTree, name: str) -> ElementTree.Element: + def _get_container_element(tree: ElementTree._ElementTree, name: str) -> ElementTree._Element: """Finds an XTCE container by name. Parameters @@ -211,7 +211,7 @@ def _get_container_element(tree: ElementTree.ElementTree, name: str) -> ElementT Returns ------- - : ElementTree.Element + : ElementTree._Element """ containers = tree.getroot().find("TelemetryMetaData/ContainerSet").findall(f"SequenceContainer[@name='{name}']") if len(containers) != 1: @@ -223,21 +223,21 @@ def _get_container_element(tree: ElementTree.ElementTree, name: str) -> ElementT @staticmethod def _get_base_container_element( - tree: ElementTree.Element, container_element: ElementTree.Element - ) -> tuple[ElementTree.Element, list[comparisons.MatchCriteria]]: + tree: ElementTree._ElementTree, container_element: ElementTree._Element + ) -> tuple[ElementTree._Element, list[comparisons.MatchCriteria]]: """Finds the referenced base container of an existing XTCE container element, including its inheritance restrictions. Parameters ---------- - tree : ElementTree.ElementTree + tree : ElementTree._ElementTree Full XML tree object, for finding additional referenced containers if necessary. - container_element : ElementTree.Element + container_element : ElementTree._Element The container element for which to find its base container. Returns ------- - : tuple[ElementTree.Element, list[comparisons.MatchCriteria]] + : tuple[ElementTree._Element, list[comparisons.MatchCriteria]] The base container element of the input container_element. The restriction criteria for the inheritance. """ @@ -273,12 +273,12 @@ def _get_base_container_element( ) @staticmethod - def _is_abstract_container(container_element: ElementTree.Element) -> bool: + def _is_abstract_container(container_element: ElementTree._Element) -> bool: """Determine in a SequenceContainer element is abstract Parameters ---------- - container_element : ElementTree.Element + container_element : ElementTree._Element SequenceContainer element to examine Returns diff --git a/space_packet_parser/xtce/definitions.py b/space_packet_parser/xtce/definitions.py index 8d23386..285ca61 100644 --- a/space_packet_parser/xtce/definitions.py +++ b/space_packet_parser/xtce/definitions.py @@ -149,12 +149,12 @@ def write_xml(self, filepath: str | Path) -> None: """ self.to_xml_tree().write(Path(filepath).absolute(), pretty_print=True, xml_declaration=True, encoding="utf-8") - def to_xml_tree(self) -> ElementTree.ElementTree: + def to_xml_tree(self) -> ElementTree._ElementTree: """Initializes and returns an ElementTree object based on parameter type, parameter, and container information Returns ------- - : ElementTree.ElementTree + : ElementTree._ElementTree """ if self.xtce_ns_uri not in self.ns.values(): warnings.warn( @@ -288,13 +288,13 @@ def from_xtce( @staticmethod def _parse_container_set( - tree: ElementTree.Element, parameter_lookup: dict[str, parameters.Parameter] + tree: ElementTree._ElementTree, parameter_lookup: dict[str, parameters.Parameter] ) -> dict[str, containers.SequenceContainer]: """Parse the element into a dictionary of SequenceContainer objects Parameters ---------- - tree : ElementTree.Element + tree : ElementTree._ElementTree Full XTCE tree parameter_lookup : dict[str, parameters.Parameter] Parameters that are contained in container entry lists @@ -333,12 +333,12 @@ def _parse_container_set( return container_lookup @staticmethod - def _parse_parameter_type_set(tree: ElementTree.ElementTree) -> dict[str, parameter_types.ParameterType]: + def _parse_parameter_type_set(tree: ElementTree._ElementTree) -> dict[str, parameter_types.ParameterType]: """Parse the into a dictionary of ParameterType objects Parameters ---------- - tree : ElementTree.ElementTree + tree : ElementTree._ElementTree Full XTCE tree Returns @@ -381,13 +381,13 @@ def _parse_parameter_type_set(tree: ElementTree.ElementTree) -> dict[str, parame @staticmethod def _parse_parameter_set( - tree: ElementTree.ElementTree, parameter_type_lookup: dict[str, parameter_types.ParameterType] + tree: ElementTree._ElementTree, parameter_type_lookup: dict[str, parameter_types.ParameterType] ) -> dict[str, parameters.Parameter]: """Parse an object into a dictionary of Parameter objects Parameters ---------- - tree : ElementTree.ElementTree + tree : ElementTree._ElementTree Full XTCE tree parameter_type_lookup : dict[str, parameter_types.ParameterType] Parameter types referenced by parameters. diff --git a/space_packet_parser/xtce/encodings.py b/space_packet_parser/xtce/encodings.py index 50b3504..8dd43f0 100644 --- a/space_packet_parser/xtce/encodings.py +++ b/space_packet_parser/xtce/encodings.py @@ -7,6 +7,7 @@ import warnings from abc import ABCMeta, abstractmethod from collections.abc import Callable +from typing import Any import lxml.etree as ElementTree from lxml.builder import ElementMaker @@ -22,12 +23,12 @@ class DataEncoding(common.AttrComparable, common.XmlObject, metaclass=ABCMeta): """Abstract base class for XTCE data encodings""" @staticmethod - def get_default_calibrator(data_encoding_element: ElementTree.Element) -> calibrators.Calibrator | None: + def get_default_calibrator(data_encoding_element: ElementTree._Element) -> calibrators.Calibrator | None: """Gets the default_calibrator for the data encoding element Parameters ---------- - data_encoding_element : ElementTree.Element + data_encoding_element : ElementTree._Element The data encoding element which should contain the default_calibrator Returns @@ -47,13 +48,13 @@ def get_default_calibrator(data_encoding_element: ElementTree.Element) -> calibr @staticmethod def get_context_calibrators( - data_encoding_element: ElementTree.Element, + data_encoding_element: ElementTree._Element, ) -> list[calibrators.ContextCalibrator] | None: """Get the context default_calibrator(s) for the data encoding element Parameters ---------- - data_encoding_element : ElementTree.Element + data_encoding_element : ElementTree._Element XML element Returns @@ -66,13 +67,13 @@ def get_context_calibrators( return None @staticmethod - def _get_linear_adjuster(parent_element: ElementTree.Element) -> Callable | None: + def _get_linear_adjuster(parent_element: ElementTree._Element) -> Callable | None: """Examine a parent (e.g. a ) element and find a LinearAdjustment if present, creating and returning a function that evaluates the adjustment. Parameters ---------- - parent_element : ElementTree.Element + parent_element : ElementTree._Element Parent element which may contain a LinearAdjustment Returns @@ -374,12 +375,12 @@ def parse_value(self, packet: spp.SpacePacket) -> common.StrParameter: @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> StringDataEncoding: """Create a data encoding object from an XML element. @@ -402,9 +403,9 @@ def from_xml( Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -470,7 +471,7 @@ def from_xml( return cls(**init_kwargs) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a data encoding XML element Parameters @@ -480,7 +481,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ element = elmaker.StringDataEncoding(encoding=self.encoding) @@ -627,7 +628,7 @@ def parse_value( # No calibrations applied, we need to determine if it's an int or a float encoding calling this routine return self._data_return_class(parsed_value) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a data encoding XML element Parameters @@ -637,7 +638,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ element = getattr(elmaker, self.__class__.__name__)( sizeInBits=str(self.size_in_bits), @@ -720,20 +721,20 @@ def _get_raw_value(self, packet: spp.SpacePacket) -> int: @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> IntegerDataEncoding: """Create a data encoding object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -887,20 +888,20 @@ def _get_raw_value(self, packet): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> FloatDataEncoding: """Create a data encoding object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -1025,20 +1026,20 @@ def parse_value(self, packet: spp.SpacePacket) -> common.BinaryParameter: @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> BinaryDataEncoding: """Create a data encoding object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored @@ -1078,7 +1079,7 @@ def from_xml( "but failed. See 3.4.5 of the XTCE Green Book CCSDS 660.1-G-2." ) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a data encoding XML element Parameters @@ -1088,7 +1089,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ if self.fixed_size_in_bits: return elmaker.BinaryDataEncoding(elmaker.SizeInBits(elmaker.FixedValue(str(self.fixed_size_in_bits)))) diff --git a/space_packet_parser/xtce/parameter_types.py b/space_packet_parser/xtce/parameter_types.py index 15ba3ac..02f0a43 100644 --- a/space_packet_parser/xtce/parameter_types.py +++ b/space_packet_parser/xtce/parameter_types.py @@ -4,6 +4,7 @@ import warnings from abc import ABCMeta +from typing import Any from lxml import etree as ElementTree from lxml.builder import ElementMaker @@ -44,26 +45,26 @@ def __repr__(self): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, + tree: ElementTree._ElementTree | None = None, parameter_lookup: dict | None = None, parameter_type_lookup: dict | None = None, - container_lookup: dict[str, any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> ParameterType: """Create a *ParameterType* from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element The XML element from which to create the object. - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored parameter_type_lookup: Optional[dict] Ignored - container_lookup : Optional[dict[str, any]] + container_lookup : Optional[dict[str, Any]] Ignored Returns @@ -80,7 +81,7 @@ def from_xml( encoding = cls.get_data_encoding(element) return cls(name, encoding, unit) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a parameter type XML element Parameters @@ -90,7 +91,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ # This looks funny because it's creating a dynamically named XML element from the ElementMaker API param_type_element = getattr(elmaker, self.__class__.__name__)(name=self.name) @@ -102,14 +103,14 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: return param_type_element @staticmethod - def get_units(parameter_type_element: ElementTree.Element) -> str | None: + def get_units(parameter_type_element: ElementTree._Element) -> str | None: """Finds the units associated with a parameter type element and parsed them to return a unit string. We assume only one but this could be extended to support multiple units. See section 4.3.2.2.4 of CCSDS 660.1-G-1 Parameters ---------- - parameter_type_element : ElementTree.Element + parameter_type_element : ElementTree._Element The parameter type element Returns @@ -131,13 +132,13 @@ def get_units(parameter_type_element: ElementTree.Element) -> str | None: return None @staticmethod - def get_data_encoding(parameter_type_element: ElementTree.Element) -> encodings.DataEncoding | None: + def get_data_encoding(parameter_type_element: ElementTree._Element) -> encodings.DataEncoding | None: """Finds the data encoding XML element associated with a parameter type XML element and parses it, returning an object representation of the data encoding. Parameters ---------- - parameter_type_element : ElementTree.Element + parameter_type_element : ElementTree._Element The parameter type element Returns @@ -237,27 +238,27 @@ def __repr__(self): @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.Element | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> EnumeratedParameterType: """Create an EnumeratedParameterType from an XML element. Overrides ParameterType.from_parameter_type_xml_element Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element The XML element from which to create the object. - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored parameter_type_lookup: Optional[dict] Ignored - container_lookup: Optional[dict[str, any]] + container_lookup: Optional[dict[str, Any]] Ignored Returns @@ -270,7 +271,7 @@ def from_xml( enumeration = cls.get_enumeration_list_contents(element, encoding) return cls(name, encoding, enumeration=enumeration, unit=unit) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a parameter type XML element Parameters @@ -280,7 +281,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ param_type_element = getattr(elmaker, self.__class__.__name__)(name=self.name) @@ -306,7 +307,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: return param_type_element @staticmethod - def get_enumeration_list_contents(element: ElementTree.Element, encoding: encodings.DataEncoding) -> dict: + def get_enumeration_list_contents(element: ElementTree._Element, encoding: encodings.DataEncoding) -> dict: """Finds the element child of an and parses it, returning a dict. This method is confusingly named as if it might return a list. Sorry, XML and python semantics are not always compatible. It's called an enumeration list because the XML element is called @@ -314,7 +315,7 @@ def get_enumeration_list_contents(element: ElementTree.Element, encoding: encodi Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element The XML element from which to search for EnumerationList tags encoding: encodings.DataEncoding The data encoding informs how to interpret the keys in the enumeration list (int, float, or str). @@ -478,26 +479,26 @@ def __init__( @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, - tree: ElementTree.ElementTree | None = None, - parameter_lookup: dict[str, any] | None = None, - parameter_type_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, - ) -> ElementTree.Element: + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + parameter_type_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, + ) -> TimeParameterType: """Create a *TimeParameterType* from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element The XML element from which to create the object. - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._ElementTree] Ignored parameter_lookup: Optional[dict] Ignored parameter_type_lookup: Optional[dict] Ignored - container_lookup: Optional[dict[str, any]] + container_lookup: Optional[dict[str, Any]] Returns ------- @@ -513,7 +514,7 @@ def from_xml( offset_from = cls.get_offset_from(element) return cls(name, encoding, unit=unit, epoch=epoch, offset_from=offset_from) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a TimeParameterType XML element For some reason, Time types have a really different structure than other parameter types so we @@ -526,7 +527,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ if not isinstance(self.encoding, encodings.NumericDataEncoding): raise ValueError("Only NumericDataEncodings are supported for TimeParameterTypes.") @@ -566,14 +567,14 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: return element @staticmethod - def get_units(parameter_type_element: ElementTree.Element) -> str | None: + def get_units(parameter_type_element: ElementTree._Element) -> str | None: """Finds the units associated with a parameter type element and parsed them to return a unit string. We assume only one but this could be extended to support multiple units. See section 4.3.2.2.4 of CCSDS 660.1-G-1 Parameters ---------- - parameter_type_element : ElementTree.Element + parameter_type_element : ElementTree._Element The parameter type element Returns @@ -588,14 +589,14 @@ def get_units(parameter_type_element: ElementTree.Element) -> str | None: @staticmethod def get_time_unit_linear_scaler( - parameter_type_element: ElementTree.Element, + parameter_type_element: ElementTree._Element, ) -> calibrators.PolynomialCalibrator | None: """Finds the linear calibrator associated with the Encoding element for the parameter type element. See section 4.3.2.4.8.3 of CCSDS 660.1-G-2 Parameters ---------- - parameter_type_element : ElementTree.Element + parameter_type_element : ElementTree._Element The parameter type element Returns @@ -626,13 +627,13 @@ def get_time_unit_linear_scaler( return None @staticmethod - def get_epoch(parameter_type_element: ElementTree.Element) -> str | None: + def get_epoch(parameter_type_element: ElementTree._Element) -> str | None: """Finds the epoch associated with a parameter type element and parses them to return an epoch string. See section 4.3.2.4.9 of CCSDS 660.1-G-2 Parameters ---------- - parameter_type_element : ElementTree.Element + parameter_type_element : ElementTree._Element The parameter type element Returns @@ -647,14 +648,14 @@ def get_epoch(parameter_type_element: ElementTree.Element) -> str | None: return None @staticmethod - def get_offset_from(parameter_type_element: ElementTree.Element) -> str | None: + def get_offset_from(parameter_type_element: ElementTree._Element) -> str | None: """Finds the parameter referenced in OffsetFrom in a parameter type element and returns the name of the referenced parameter (which must be of type TimeParameterType). See section 4.3.2.4.9 of CCSDS 660.1-G-1 Parameters ---------- - parameter_type_element : ElementTree.Element + parameter_type_element : ElementTree._Element The parameter type element Returns diff --git a/space_packet_parser/xtce/parameters.py b/space_packet_parser/xtce/parameters.py index da1fbe4..7a003e9 100644 --- a/space_packet_parser/xtce/parameters.py +++ b/space_packet_parser/xtce/parameters.py @@ -3,6 +3,7 @@ from __future__ import annotations from dataclasses import dataclass +from typing import Any import lxml.etree as ElementTree from lxml.builder import ElementMaker @@ -43,20 +44,20 @@ def parse(self, packet: spp.SpacePacket) -> None: @classmethod def from_xml( cls, - element: ElementTree.Element, + element: ElementTree._Element, *, parameter_type_lookup: dict[str, parameter_types.ParameterType], - tree: ElementTree.ElementTree | None = None, - parameter_lookup: dict[str, any] | None = None, - container_lookup: dict[str, any] | None = None, + tree: ElementTree._ElementTree | None = None, + parameter_lookup: dict[str, Any] | None = None, + container_lookup: dict[str, Any] | None = None, ) -> Parameter: """Create a Parameter object from an XML element. Parameters ---------- - element : ElementTree.Element + element : ElementTree._Element XML element - tree: Optional[ElementTree.Element] + tree: Optional[ElementTree._Element] Ignored parameter_lookup: Optional[dict] Ignored @@ -90,7 +91,7 @@ def from_xml( long_description=parameter_long_description, ) - def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: + def to_xml(self, *, elmaker: ElementMaker) -> ElementTree._Element: """Create a Parameter XML element Parameters @@ -100,7 +101,7 @@ def to_xml(self, *, elmaker: ElementMaker) -> ElementTree.Element: Returns ------- - : ElementTree.Element + : ElementTree._Element """ parameter_attrib = { "name": self.name, diff --git a/space_packet_parser/xtce/validation.py b/space_packet_parser/xtce/validation.py index 8d778f0..43a5aa0 100644 --- a/space_packet_parser/xtce/validation.py +++ b/space_packet_parser/xtce/validation.py @@ -277,12 +277,12 @@ def _is_http_url(s): ) from e -def _find_schema_url(xml_tree: ElementTree.ElementTree) -> str: +def _find_schema_url(xml_tree: ElementTree._ElementTree) -> str: """Find the XSD location from the root attributes of the document Parameters ---------- - xml_tree : ElementTree.ElementTree + xml_tree : ElementTree._ElementTree XML tree of document being validated Returns @@ -305,7 +305,7 @@ def _find_schema_url(xml_tree: ElementTree.ElementTree) -> str: def _validate_xtce_schema( - xml_tree: ElementTree.ElementTree, + xml_tree: ElementTree._ElementTree, local_xsd: str | Path | None = None, timeout: int = 30, ) -> ValidationResult: @@ -313,7 +313,7 @@ def _validate_xtce_schema( Parameters ---------- - xml_tree : ElementTree.ElementTree + xml_tree : ElementTree._ElementTree XTCE XML tree object local_xsd : Optional[Union[str, Path]] Optional local schema location. If specified, schema references in root element (or lack thereof) are ignored. @@ -382,7 +382,7 @@ def _validate_xtce_schema( return result -def _validate_xtce_structure(xml_tree: ElementTree.ElementTree) -> ValidationResult: +def _validate_xtce_structure(xml_tree: ElementTree._ElementTree) -> ValidationResult: """Validate XTCE document structure and reference integrity. This performs structural validation beyond XSD schema validation, @@ -390,7 +390,7 @@ def _validate_xtce_structure(xml_tree: ElementTree.ElementTree) -> ValidationRes Parameters ---------- - xml_tree: ElementTree.ElementTree + xml_tree: ElementTree._ElementTree Parsed XML tree of the XTCE document Returns @@ -495,7 +495,7 @@ def _validate_xtce_structure(xml_tree: ElementTree.ElementTree) -> ValidationRes def validate_xtce( - xml_source: str | Path | ElementTree.ElementTree, + xml_source: str | Path | ElementTree._ElementTree, level: str = "all", timeout: int = 30, print_results: bool = True, @@ -509,7 +509,7 @@ def validate_xtce( Parameters ---------- - xml_source : Union[str, Path, ElementTree.ElementTree] + xml_source : Union[str, Path, ElementTree._ElementTree] Path to XML file, XML string content, or ElementTree level : str Validation level: "schema", "structure", or "all". Default "all".