elementpath/datatypes/uri.py
class AnyURI(AnyAtomicType):
    """
    Class for xs:anyURI data.

    :param value: a string or an untyped atomic instance.
    """
    value: str
    name = 'anyURI'

    def __init__(self, value: Union[str, bytes, UntypedAtomic, 'AnyURI']) -> None:
        if isinstance(value, str):
            self.value = collapse_white_spaces(value)
        elif isinstance(value, bytes):
            self.value = collapse_white_spaces(value.decode('utf-8'))
        elif isinstance(value, self.__class__):
            self.value = value.value
        elif isinstance(value, UntypedAtomic):
            self.value = collapse_white_spaces(value.value)
        else:
            raise TypeError('the argument has an invalid type %r' % type(value))

        self.validate(self.value)

    def __repr__(self) -> str:
        return '%s(%r)' % (self.__class__.__name__, self.value)

    def __str__(self) -> str:
        return self.value

    def __bool__(self) -> bool:
        return bool(self.value)  # For effective boolean value

    def __hash__(self) -> int:
        return hash(self.value)

    def __contains__(self, item: str) -> bool:
        return item in self.value

    def __eq__(self, other: object) -> bool:
        if isinstance(other, (AnyURI, UntypedAtomic)):
            return self.value == other.value
        elif isinstance(other, (bool, float, Decimal, Integer)):
            raise TypeError("cannot compare {} with xs:{}".format(type(other), self.name))
        return self.value == other

    def __ne__(self, other: object) -> bool:
        if isinstance(other, (AnyURI, UntypedAtomic)):
            return self.value != other.value
        elif isinstance(other, (bool, float, Decimal, Integer)):
            raise TypeError("cannot compare {} with xs:{}".format(type(other), self.name))
        return self.value != other

    def __lt__(self, other: Union[str, 'AnyURI', UntypedAtomic]) -> bool:
        if isinstance(other, (AnyURI, UntypedAtomic)):
            return self.value < other.value
        return self.value < other

    def __le__(self, other: Union[str, 'AnyURI', UntypedAtomic]) -> bool:
        if isinstance(other, (AnyURI, UntypedAtomic)):
            return self.value <= other.value
        return self.value <= other

    def __gt__(self, other: Union[str, 'AnyURI', UntypedAtomic]) -> bool:
        if isinstance(other, (AnyURI, UntypedAtomic)):
            return self.value > other.value
        return self.value > other

    def __ge__(self, other: Union[str, 'AnyURI', UntypedAtomic]) -> bool:
        if isinstance(other, (AnyURI, UntypedAtomic)):
            return self.value >= other.value
        return self.value >= other

    @classmethod
    def validate(cls, value: object) -> None:
        if isinstance(value, cls):
            return
        elif isinstance(value, bytes):
            value = value.decode()
        elif not isinstance(value, str):
            raise cls.invalid_type(value)

        try:
            url_parts = urlparse(value)
            _ = url_parts.port  # check invalid port!
        except ValueError as err:
            msg = 'invalid value {!r} for xs:{} ({})'
            raise ValueError(msg.format(value, cls.name, str(err))) from None
        else:
            if url_parts.path.startswith(':'):
                raise cls.invalid_value(value)
            elif value.count('#') > 1:
                msg = 'invalid value {!r} for xs:{} (too many # characters)'
                raise ValueError(msg.format(value, cls.name))
            elif WRONG_ESCAPE_PATTERN.search(value) is not None:
                msg = 'invalid value {!r} for xs:{} (wrong escaping)'
                raise ValueError(msg.format(value, cls.name))
elementpath/xpath_nodes.py
def node_name(obj: Any) -> Optional[str]:
    if isinstance(obj, XPathNode):
        return cast(Optional[str], obj.name)
    elif not hasattr(obj, 'tag') or not hasattr(obj, 'text'):
        return None
    elif not callable(obj.tag):
        return cast(str, obj.tag)
    elif obj.tag.__name__ != 'ProcessingInstruction':
        return None
    else:
        # Return pi target. ElementTree doesn't have a specific attribute
        # for target but put it before the text, separated by a space.
        try:
            return cast(str, obj.target)
        except AttributeError:
            return cast(str, obj.text.split(' ', maxsplit=1)[0])
elementpath/datatypes/datetime.py
class Duration(AnyAtomicType):
    """
    Base class for the XSD duration types.

    :param months: an integer value that represents years and months.
    :param seconds: a decimal or an integer instance that represents \
    days, hours, minutes, seconds and fractions of seconds.
    """
    name = 'duration'
    pattern = re.compile(
        r'^(-)?P(?=[0-9]|T)(?:([0-9]+)Y)?(?:([0-9]+)M)?(?:([0-9]+)D)?'
        r'(?:T(?=[0-9])(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+(?:\.[0-9]+)?)S)?)?$'
    )

    def __init__(self, months: int = 0, seconds: Union[Decimal, int] = 0) -> None:
        if seconds < 0 < months or months < 0 < seconds:
            raise ValueError('signs differ: (months=%d, seconds=%d)' % (months, seconds))
        elif abs(months) > 2 ** 31:
            raise OverflowError("months duration overflow")
        elif abs(seconds) > 2 ** 63:  # type: ignore[operator]
            raise OverflowError("seconds duration overflow")

        self.months = months
        self.seconds = Decimal(seconds).quantize(Decimal('1.000000'))

    def __repr__(self) -> str:
        return '{}(months={!r}, seconds={})'.format(
            self.__class__.__name__, self.months, normalized_seconds(self.seconds)
        )

    def __str__(self) -> str:
        m = abs(self.months)
        years, months = m // 12, m % 12
        s = self.seconds.copy_abs()
        days = int(s // 86400)
        hours = int(s // 3600 % 24)
        minutes = int(s // 60 % 60)
        seconds = s % 60

        value = '-P' if self.sign else 'P'
        if years or months or days:
            if years:
                value += '%dY' % years
            if months:
                value += '%dM' % months
            if days:
                value += '%dD' % days

        if hours or minutes or seconds:
            value += 'T'
            if hours:
                value += '%dH' % hours
            if minutes:
                value += '%dM' % minutes
            if seconds:
                value += '%sS' % normalized_seconds(seconds)

        elif value[-1] == 'P':
            value += 'T0S'
        return value

    @classmethod
    def fromstring(cls, text: str) -> 'Duration':
        """
        Creates a Duration instance from a formatted XSD duration string.

        :param text: an ISO 8601 representation without week fragment and an optional decimal part \
        only for seconds fragment.
        """
        if not isinstance(text, str):
            msg = 'argument has an invalid type {!r}'
            raise TypeError(msg.format(type(text)))

        match = cls.pattern.match(text.strip())
        if match is None:
            raise ValueError('%r is not an xs:duration value' % text)

        sign, y, mo, d, h, mi, s = match.groups()
        seconds = Decimal(s or 0)
        minutes = int(mi or 0) + int(seconds // 60)
        seconds = seconds % 60
        hours = int(h or 0) + minutes // 60
        minutes = minutes % 60
        days = int(d or 0) + hours // 24
        hours = hours % 24
        months = int(mo or 0) + 12 * int(y or 0)

        if sign is None:
            seconds = seconds + (days * 24 + hours) * 3600 + minutes * 60
        else:
            months = -months
            seconds = -seconds - (days * 24 + hours) * 3600 - minutes * 60

        if cls is DayTimeDuration:
            if months:
                raise ValueError('months must be 0 for %r' % cls.__name__)
            return cls(seconds=seconds)
        elif cls is YearMonthDuration:
            if seconds:
                raise ValueError('seconds must be 0 for %r' % cls.__name__)
            return cls(months=months)
        return cls(months=months, seconds=seconds)

    @property
    def sign(self) -> str:
        return '-' if self.months < 0 or self.seconds < 0 else ''

    def _compare_durations(self, other: object, op: Callable[[Any, Any], Any]) -> bool:
        """
        Ordering is defined through comparison of four datetime.datetime values.

        Ref: https://www.w3.org/TR/2012/REC-xmlschema11-2-20120405/#duration
        """
        if not isinstance(other, self.__class__):
            raise TypeError("wrong type %r for operand %r" % (type(other), other))

        m1, s1 = self.months, int(self.seconds)
        m2, s2 = other.months, int(other.seconds)
        ms1, ms2 = int((self.seconds - s1) * 1000000), int((other.seconds - s2) * 1000000)
        return all([
            op(datetime.timedelta(months2days(1696, 9, m1), s1, ms1),
               datetime.timedelta(months2days(1696, 9, m2), s2, ms2)),
            op(datetime.timedelta(months2days(1697, 2, m1), s1, ms1),
               datetime.timedelta(months2days(1697, 2, m2), s2, ms2)),
            op(datetime.timedelta(months2days(1903, 3, m1), s1, ms1),
               datetime.timedelta(months2days(1903, 3, m2), s2, ms2)),
            op(datetime.timedelta(months2days(1903, 7, m1), s1, ms1),
               datetime.timedelta(months2days(1903, 7, m2), s2, ms2)),
        ])

    def __hash__(self) -> int:
        return hash((self.months, self.seconds))

    def __eq__(self, other: object) -> bool:
        if isinstance(other, self.__class__):
            return self.months == other.months and self.seconds == other.seconds
        elif isinstance(other, UntypedAtomic):
            return self.__eq__(self.fromstring(other.value))
        else:
            return other == (self.months, self.seconds)

    def __ne__(self, other: object) -> bool:
        if isinstance(other, self.__class__):
            return self.months != other.months or self.seconds != other.seconds
        elif isinstance(other, UntypedAtomic):
            return self.__ne__(self.fromstring(other.value))
        else:
            return other != (self.months, self.seconds)

    def __lt__(self, other: object) -> bool:
        return self._compare_durations(other, operator.lt)

    def __le__(self, other: object) -> bool:
        return self == other or self._compare_durations(other, operator.le)

    def __gt__(self, other: object) -> bool:
        return self._compare_durations(other, operator.gt)

    def __ge__(self, other: object) -> bool:
        return self == other or self._compare_durations(other, operator.ge)
elementpath/xpath_nodes.py
def is_document_node(obj: Any) -> bool:
    return hasattr(obj, 'getroot') and hasattr(obj, 'parse') and hasattr(obj, 'iter')
elementpath/xpath_nodes.py
class TextNode(XPathNode):
    """
    A class for processing XPath text nodes. An Element's property
    (elem.text or elem.tail) with a `None` value is not a text node.

    :param value: a string value.
    :param parent: the parent element.
    :param tail: provide `True` if the text node is the parent Element's tail.
    """
    text: None
    _tail = False

    def __init__(self, value: str, parent: Optional[ElementNode] = None,
                 tail: bool = False) -> None:
        self.value = value
        self.parent = parent
        if tail and parent is not None:
            self._tail = True

    @property
    def kind(self) -> str:
        return 'text'

    def is_tail(self) -> bool:
        """Returns `True` if the node has a parent and represents the tail text."""
        return self._tail

    def __repr__(self) -> str:
        if self.parent is not None:
            return '%s(%r, parent=%r, tail=%r)' % (
                self.__class__.__name__, self.value, self.parent, self._tail
            )
        return '%s(%r)' % (self.__class__.__name__, self.value)

    def __eq__(self, other: Any) -> bool:
        return isinstance(other, self.__class__) and \
            self.value == other.value and \
            self.parent is other.parent and \
            self._tail is other._tail

    def __hash__(self) -> int:
        return hash((self.value, self.parent, self._tail))
elementpath/xpath_nodes.py
def is_xpath_node(obj: Any) -> bool:
    return isinstance(obj, XPathNode) or \
        hasattr(obj, 'tag') and hasattr(obj, 'attrib') and hasattr(obj, 'text') or \
        hasattr(obj, 'local_name') and hasattr(obj, 'type') and hasattr(obj, 'name') or \
        hasattr(obj, 'getroot') and hasattr(obj, 'parse') and hasattr(obj, 'iter')
elementpath/xpath_token.py
class XPathFunction(XPathToken):
    """
    A token for processing XPath functions.
    """
    _name: Optional[QName] = None
    pattern = r'(?<!\$)\b[^\d\W][\w.\-\xb7\u0300-\u036F\u203F\u2040]*' \
              r'(?=\s*(?:\(\:.*\:\))?\s*\((?!\:))'

    sequence_types: Tuple[str, ...] = ()
    "Sequence types of arguments and of the return value of the function."

    nargs: NargsType = None
    "Number of arguments: a single value or a couple with None that means unbounded."

    body: Optional[XPathToken] = None
    "Body of anonymous inline function."

    variables: Optional[Dict[str, Any]] = None
    "Optional variables linked by let and for expressions."

    def __init__(self, parser: 'XPath1Parser', nargs: Optional[int] = None) -> None:
        super().__init__(parser)
        if isinstance(nargs, int) and nargs != self.nargs:
            if nargs < 0:
                raise self.error('XPST0017', 'number of arguments must be non negative')
            elif self.nargs is None:
                self.nargs = nargs
            elif isinstance(self.nargs, int):
                raise self.error('XPST0017', 'incongruent number of arguments')
            elif self.nargs[0] > nargs or self.nargs[1] is not None and self.nargs[1] < nargs:
                raise self.error('XPST0017', 'incongruent number of arguments')
            else:
                self.nargs = nargs

    def __call__(self, context: Optional[XPathContext] = None,
                 argument_list: Optional[Union[
                     XPathToken,
                     List[Union[XPathToken, AtomicValueType]],
                     Tuple[Union[XPathToken, AtomicValueType], ...]
                 ]] = None) -> Any:

        args: List[Any] = []
        if isinstance(argument_list, (list, tuple)):
            args.extend(argument_list)
        elif isinstance(argument_list, XPathToken):
            tk = argument_list
            while True:
                if tk.symbol == ',':
                    args.append(tk[1].evaluate(context))
                    tk = tk[0]
                else:
                    args.append(tk.evaluate(context))
                    break
            args.reverse()

        # Check provided argument with arity
        if self.nargs is None or self.nargs == len(args):
            pass
        elif isinstance(self.nargs, tuple):
            if len(args) < self.nargs[0]:
                raise self.error('XPTY0004', "missing required arguments")
            elif self.nargs[1] is not None and len(args) > self.nargs[1]:
                raise self.error('XPTY0004', "too many arguments")
        elif self.nargs > len(args):
            raise self.error('XPTY0004', "missing required arguments")
        else:
            raise self.error('XPTY0004', "too many arguments")

        context = copy(context)
        if self.variables is not None and context is not None:
            context.variables.update(self.variables)

        if self.symbol == 'function':
            if context is None:
                raise self.missing_context()
            elif not args and self:
                if context.item is None:
                    if is_document_node(context.root):
                        context.item = cast(DocumentProtocol, context.root).getroot()
                    else:
                        context.item = context.root

                args.append(context.item)

            partial_function = False
            if self.variables is None:
                self.variables = {}

            for variable, sequence_type, value in zip(self, self.sequence_types, args):
                varname = cast(str, variable[0].value)

                if isinstance(value, XPathToken) and value.symbol == '?':
                    partial_function = True
                    continue
                elif isinstance(value, XPathFunction) and sequence_type.startswith('function('):
                    if not value.match_function_test(sequence_type, as_argument=True):
                        msg = "argument {!r}: {} does not match sequence type {}"
                        raise self.error('XPTY0004', msg.format(varname, value, sequence_type))

                elif not self.parser.match_sequence_type(value, sequence_type):
                    value = self.cast_to_primitive_type(value, sequence_type)
                    if not self.parser.match_sequence_type(value, sequence_type):
                        msg = "argument {!r}: {} does not match sequence type {}"
                        raise self.error('XPTY0004', msg.format(varname, value, sequence_type))

                context.variables[varname] = self.variables[varname] = value

            if partial_function:
                return self

        elif self.label == 'partial function':
            for value, tk in zip(args, filter(lambda x: x.symbol == '?', self)):
                if isinstance(value, XPathToken):
                    tk.value = value.evaluate(context)
                else:
                    assert not isinstance(value, Token), "An atomic value or None expected"
                    tk.value = value
        else:
            self.clear()
            for value in args:
                if isinstance(value, XPathToken):
                    self.append(value)
                else:
                    assert not isinstance(value, Token), "An atomic value or None expected"
                    self.append(ValueToken(self.parser, value=value))

            if any(tk.symbol == '?' for tk in self._items):
                self._partial_function()
                return self

        if isinstance(self.label, MultiLabel):
            # Disambiguate multi-label tokens
            if self.namespace == XSD_NAMESPACE and \
                    'constructor function' in self.label.values:
                self.label = 'constructor function'
            else:
                for label in self.label.values:
                    if label.endswith('function'):
                        self.label = label
                        break

        if self.label == 'partial function':
            result = self._partial_evaluate(context)
        elif self.body is not None:
            assert self.label == 'inline function'
            result = self.body.evaluate(context)
        else:
            result = self.evaluate(context)

        if isinstance(result, XPathToken) and result.symbol == '?':
            pass
        elif not self.parser.match_sequence_type(result, self.sequence_types[-1]):
            result = self.cast_to_primitive_type(result, self.sequence_types[-1])
            if not self.parser.match_sequence_type(result, self.sequence_types[-1]):
                msg = "{!r} does not match sequence type {}"
                self.parser.match_sequence_type(result, self.sequence_types[-1])
                raise self.error('XPTY0004', msg.format(result, self.sequence_types[-1]))

        return result

    @property
    def source(self) -> str:
        if self.label == 'function test':
            if len(self.sequence_types) == 1 and self.sequence_types[0] == '*':
                return 'function(*)'
            else:
                return 'function(%s) as %s' % (
                    ', '.join(self.sequence_types[:-1]), self.sequence_types[-1]
                )
        elif self.label in ('sequence type', 'kind test', ''):
            return '%s(%s)%s' % (
                self.symbol, ', '.join(item.source for item in self), self.occurrence or ''
            )
        return '%s(%s)' % (self.symbol, ', '.join(item.source for item in self))

    @property
    def name(self) -> Optional[QName]:
        if self._name is not None:
            return self._name
        elif self.symbol == 'function':
            return None
        elif self.label == 'partial function':
            return None
        elif not self.namespace or self.namespace == XPATH_FUNCTIONS_NAMESPACE:
            self._name = QName(XPATH_FUNCTIONS_NAMESPACE, 'fn:%s' % self.symbol)
        elif self.namespace == XSD_NAMESPACE:
            self._name = QName(XSD_NAMESPACE, 'xs:%s' % self.symbol)
        elif self.namespace == XPATH_MATH_FUNCTIONS_NAMESPACE:
            self._name = QName(XPATH_MATH_FUNCTIONS_NAMESPACE, 'math:%s' % self.symbol)
        else:
            for pfx, uri in self.parser.namespaces.items():
                if uri == self.namespace:
                    self._name = QName(uri, f'{pfx}:{self.symbol}')
                    break
            else:
                self._name = QName(self.namespace, self.symbol)

        return self._name

    @property
    def arity(self) -> int:
        if isinstance(self.nargs, int):
            return self.nargs
        return len(self._items)

    def nud(self) -> 'XPathFunction':
        code = 'XPST0017' if self.label == 'function' else 'XPST0003'
        self.value = None
        self.parser.advance('(')
        if self.nargs is None:
            del self._items[:]
            if self.parser.next_token.symbol in (')', '(end)'):
                raise self.error(code, 'at least an argument is required')
            while True:
                self.append(self.parser.expression(5))
                if self.parser.next_token.symbol != ',':
                    break
                self.parser.advance()
        elif self.nargs == 0:
            if self.parser.next_token.symbol != ')':
                if self.parser.next_token.symbol != '(end)':
                    raise self.error(code, '%s has no arguments' % str(self))
                raise self.parser.next_token.wrong_syntax()
            self.parser.advance()
            return self
        else:
            if isinstance(self.nargs, (tuple, list)):
                min_args, max_args = self.nargs
            else:
                min_args = max_args = self.nargs

            k = 0
            while k < min_args:
                if self.parser.next_token.symbol in (')', '(end)'):
                    msg = 'Too few arguments: expected at least %s arguments' % min_args
                    raise self.wrong_nargs(msg if min_args > 1 else msg[:-1])

                self._items[k:] = self.parser.expression(5),
                k += 1
                if k < min_args:
                    if self.parser.next_token.symbol == ')':
                        msg = 'Too few arguments: expected at least %s arguments' % min_args
                        raise self.error(code, msg if min_args > 1 else msg[:-1])
                    self.parser.advance(',')

            while max_args is None or k < max_args:
                if self.parser.next_token.symbol == ',':
                    self.parser.advance(',')
                    self._items[k:] = self.parser.expression(5),
                elif k == 0 and self.parser.next_token.symbol != ')':
                    self._items[k:] = self.parser.expression(5),
                else:
                    break  # pragma: no cover
                k += 1

            if self.parser.next_token.symbol == ',':
                msg = 'Too many arguments: expected at most %s arguments' % max_args
                raise self.error(code, msg if max_args != 1 else msg[:-1])

        self.parser.advance(')')
        if any(tk.symbol == '?' for tk in self._items):
            self._partial_function()

        return self

    def match_function_test(self, function_test: str, as_argument: bool = False) -> bool:
        """
        Match if function signature is a subtype of provided *function_test*.
        For default return type is covariant and arguments are contravariant.
        If *as_argument* is `True` the match is inverted and also the return
        type is considered contravariant.

        References:
          https://www.w3.org/TR/xpath-31/#id-function-test
          https://www.w3.org/TR/xpath-31/#id-sequencetype-subtype
        """
        if not function_test.startswith('function('):
            return False
        elif function_test == 'function(*)':
            return True

        parts = function_test[9:].partition(') as ')
        if not parts[1] or not parts[2]:
            return False

        sequence_types = parts[0].split(', ')
        sequence_types.append(parts[2])

        signature = [x for x in self.sequence_types[:self.arity]]
        signature.append(self.sequence_types[-1])

        if len(sequence_types) != len(signature):
            return False

        if as_argument:
            iterator = zip(sequence_types, signature)
        else:
            iterator = zip(signature, sequence_types)

        k = 0
        for fst, st in iterator:
            k += 1
            if not as_argument and k == len(sequence_types):
                st, fst = fst, st

            if st[-1] in '*+?':
                st_occurs = st[-1]
                st = st[:-1]
            else:
                st_occurs = ''

            if fst[-1] in '*+?':
                fst_occurs = fst[-1]
                fst = fst[:-1]
            else:
                fst_occurs = ''

            if st_occurs == fst_occurs or fst_occurs == '*':
                pass
            elif not fst_occurs:
                if st_occurs not in '?*':
                    return False
            elif fst_occurs == '+':
                if st_occurs:
                    return False
            elif st_occurs:
                return False

            if st == fst:
                continue
            elif fst == 'item()':
                continue
            elif st == 'item()':
                return False
            elif fst.startswith('xs:') ^ st.startswith('xs:'):
                return False
            elif fst.startswith('xs:'):
                if not issubclass(xsd11_atomic_types[st[3:]],
                                  xsd11_atomic_types[fst[3:]]):
                    return False
            elif fst != 'node()':
                return False

        return True

    def _partial_function(self) -> None:
        """Convert a named function to an anonymous partial function."""
        def evaluate(context: Optional[XPathContext] = None) -> Any:
            return self

        def select(context: Optional[XPathContext] = None) -> Any:
            yield self

        if self.__class__.evaluate is not XPathToken.evaluate:
            setattr(self, '_partial_evaluate', self.evaluate)
        if self.__class__.select is not XPathToken.select:
            setattr(self, '_partial_select', self.select)

        setattr(self, 'evaluate', evaluate)
        setattr(self, 'select', select)

        self._name = None
        self.label = 'partial function'
        self.nargs = len([tk for tk in self._items if tk.symbol == '?'])

    def _partial_evaluate(self, context: Optional[XPathContext] = None) -> Any:
        return [x for x in self._partial_select(context)]

    def _partial_select(self, context: Optional[XPathContext] = None) -> Iterator[Any]:
        item = self._partial_evaluate(context)
        if item is not None:
            if isinstance(item, list):
                yield from item
            else:
                if context is not None:
                    context.item = item
                yield item
elementpath/namespaces.py
XML_ID = '{%s}id' % XML_NAMESPACE
elementpath/xpath_nodes.py
def is_comment_node(obj: Any) -> bool:
    return hasattr(obj, 'tag') and callable(obj.tag) and obj.tag.__name__ == 'Comment'
elementpath/xpath1/_xpath1_operators.py
OPERATORS_MAP = {
    '=': operator.eq,
    '!=': operator.ne,
    '>': operator.gt,
    '>=': operator.ge,
    '<': operator.lt,
    '<=': operator.le,
}
def nud_name_literal(self):
def evaluate_name_literal(self, context=None):
def select_name_literal(self, context=None):
def led_namespace_prefix(self, left):
def evaluate_namespace_prefix(self, context=None):
def select_namespace_prefix(self, context=None):
def nud_namespace_uri(self):
def evaluate_namespace_uri(self, context=None):
def select_namespace_uri(self, context=None):
def nud_variable_reference(self):
def evaluate_variable_reference(self, context=None):
def select_wildcard(self, context=None):
def select_self_shortcut(self, context=None):
def select_parent_shortcut(self, context=None):
def evaluate_or_operator(self, context=None):
def evaluate_and_operator(self, context=None):
def led_comparison_operators(self, left):
def evaluate_comparison_operators(self, context=None):
def evaluate_plus_operator(self, context=None):
def evaluate_minus_operator(self, context=None):
def nud_plus_minus_operators(self):
def evaluate_multiply_operator(self, context=None):
def evaluate_div_operator(self, context=None):
def evaluate_mod_operator(self, context=None):
def nud_logical_div_mod_operators(self):
def led_union_operator(self, left):
def select_union_operator(self, context=None):
def nud_descendant_path(self):
def nud_child_path(self):
def led_child_or_descendant_path(self, left):
def select_child_path(self, context=None):
def select_descendant_path(self, context=None):
def led_predicate(self, left):
def select_predicate(self, context=None):
def nud_parenthesized_expr(self):
def evaluate_parenthesized_expr(self, context=None):
def select_parenthesized_expr(self, context=None):
elementpath/datatypes/proxies.py
class StringProxy(metaclass=AtomicTypeMeta):
    name = 'string'

    def __new__(cls, *args: object, **kwargs: object) -> str:  # type: ignore[misc]
        return str(*args, **kwargs)

    @classmethod
    def __subclasshook__(cls, subclass: type) -> bool:
        return issubclass(subclass, str)

    @classmethod
    def validate(cls, value: object) -> None:
        if not isinstance(value, str):
            raise cls.invalid_type(value)
elementpath/namespaces.py
XML_LANG = '{%s}lang' % XML_NAMESPACE
elementpath/namespaces.py
def get_prefixed_name(
        qname: str, namespaces: Union[Dict[str, str], Dict[Optional[str], str]]) -> str:
    """
    Get the prefixed form of a QName, using a namespace map.

    :param qname: an extended QName or a local name or a prefixed QName.
    :param namespaces: a dictionary with a map from prefixes to namespace URIs.
    """
    try:
        if qname[0] == '{':
            ns_uri, local_name = qname[1:].split('}')
        elif qname[1] == '{' and qname[0] == 'Q':
            ns_uri, local_name = qname[2:].split('}')
        else:
            return qname
    except IndexError:
        return qname
    except (ValueError, TypeError):
        raise ValueError("{!r} is not a QName".format(qname))

    for prefix, uri in sorted(namespaces.items(), reverse=True,
                              key=lambda x: x if x[0] is not None else ('', x[1])):
        if uri == ns_uri:
            return '%s:%s' % (prefix, local_name) if prefix else local_name
    else:
        return qname
elementpath/xpath_nodes.py
def is_element_node(obj: Any) -> bool:
    return isinstance(obj, TypedElement) or \
        hasattr(obj, 'tag') and not callable(obj.tag) and \
        hasattr(obj, 'attrib') and hasattr(obj, 'text')
elementpath/datatypes/numeric.py
class Float10(float, AnyAtomicType):
    name = 'float'
    xsd_version = '1.0'
    pattern = re.compile(
        r'^(?:[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[Ee][+-]?[0-9]+)? |[+-]?INF|NaN)$'
    )

    def __new__(cls, value: Union[str, SupportsFloat]) -> 'Float10':
        if isinstance(value, str):
            value = collapse_white_spaces(value)
            if value in NUMERIC_INF_OR_NAN or cls.xsd_version != '1.0' and value == '+INF':
                pass
            elif value.lower() in INVALID_NUMERIC:
                raise ValueError('invalid value {!r} for xs:{}'.format(value, cls.name))

        _value = super().__new__(cls, value)
        if _value > 3.4028235E38:
            return super().__new__(cls, 'INF')
        elif _value < -3.4028235E38:
            return super().__new__(cls, '-INF')
        elif -1e-37 < _value < 1e-37:
            return super().__new__(cls, -0.0 if str(_value).startswith('-') else 0.0)
        return _value

    def __hash__(self) -> int:
        return super(Float10, self).__hash__()

    def __eq__(self, other: object) -> bool:
        if isinstance(other, self.__class__):
            if super(Float10, self).__eq__(other):
                return True
            return math.isclose(self, other, rel_tol=1e-7, abs_tol=0.0)
        return super(Float10, self).__eq__(other)

    def __ne__(self, other: object) -> bool:
        if isinstance(other, self.__class__):
            if super(Float10, self).__eq__(other):
                return False
            return not math.isclose(self, other, rel_tol=1e-7, abs_tol=0.0)
        return super(Float10, self).__ne__(other)

    def __add__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__add__(other))
        elif isinstance(other, float):
            return super(Float10, self).__add__(other)
        return NotImplemented

    def __radd__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__radd__(other))
        elif isinstance(other, float):
            return super(Float10, self).__radd__(other)
        return NotImplemented

    def __sub__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__sub__(other))
        elif isinstance(other, float):
            return super(Float10, self).__sub__(other)
        return NotImplemented

    def __rsub__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__rsub__(other))
        elif isinstance(other, float):
            return super(Float10, self).__rsub__(other)
        return NotImplemented

    def __mul__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__mul__(other))
        elif isinstance(other, float):
            return super(Float10, self).__mul__(other)
        return NotImplemented

    def __rmul__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__rmul__(other))
        elif isinstance(other, float):
            return super(Float10, self).__rmul__(other)
        return NotImplemented

    def __truediv__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__truediv__(other))
        elif isinstance(other, float):
            return super(Float10, self).__truediv__(other)
        return NotImplemented

    def __rtruediv__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__rtruediv__(other))
        elif isinstance(other, float):
            return super(Float10, self).__rtruediv__(other)
        return NotImplemented

    def __mod__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__mod__(other))
        elif isinstance(other, float):
            return super(Float10, self).__mod__(other)
        return NotImplemented

    def __rmod__(self, other: object) -> Union[float, 'Float10', 'Float']:
        if isinstance(other, (self.__class__, int)):
            return self.__class__(super(Float10, self).__rmod__(other))
        elif isinstance(other, float):
            return super(Float10, self).__rmod__(other)
        return NotImplemented

    def __abs__(self) -> Union['Float10', 'Float']:
        return self.__class__(super(Float10, self).__abs__())
elementpath/datatypes/datetime.py
class YearMonthDuration(Duration):

    name = 'yearMonthDuration'

    def __init__(self, months: int = 0) -> None:
        super(YearMonthDuration, self).__init__(months, 0)

    def __repr__(self) -> str:
        return '%s(months=%r)' % (self.__class__.__name__, self.months)

    def __str__(self) -> str:
        m = abs(self.months)
        years, months = m // 12, m % 12

        if not years:
            return '-P%dM' % months if self.months < 0 else 'P%dM' % months
        elif not months:
            return '-P%dY' % years if self.months < 0 else 'P%dY' % years
        elif self.months < 0:
            return '-P%dY%dM' % (years, months)
        else:
            return 'P%dY%dM' % (years, months)

    def __add__(self, other: object) \
            -> Union['YearMonthDuration', 'DayTimeDuration', 'OrderedDateTime']:
        if isinstance(other, self.__class__):
            return YearMonthDuration(months=self.months + other.months)
        elif isinstance(other, (DateTime10, Date10)):
            return other + self
        raise TypeError("cannot add %r to %r" % (type(other), type(self)))

    def __sub__(self, other: object) -> 'YearMonthDuration':
        if not isinstance(other, self.__class__):
            raise TypeError("cannot subtract %r from %r" % (type(other), type(self)))
        return YearMonthDuration(months=self.months - other.months)

    def __mul__(self, other: object) -> 'YearMonthDuration':
        if not isinstance(other, (float, int, Decimal)):
            raise TypeError("cannot multiply a %r by %r" % (type(self), type(other)))
        return YearMonthDuration(months=int(round_number(self.months * other)))

    def __truediv__(self, other: object) -> Union[float, 'YearMonthDuration']:
        if isinstance(other, self.__class__):
            return self.months / other.months
        elif isinstance(other, (float, int, Decimal)):
            return YearMonthDuration(months=int(round_number(self.months / other)))
        else:
            raise TypeError("cannot divide a %r by %r" % (type(self), type(other)))
elementpath/datatypes/datetime.py
class DayTimeDuration(Duration):

    name = 'dayTimeDuration'

    def __init__(self, seconds: Union[Decimal, int] = 0) -> None:
        super(DayTimeDuration, self).__init__(0, seconds)

    @classmethod
    def fromtimedelta(cls, td: datetime.timedelta) -> 'DayTimeDuration':
        return cls(seconds=Decimal(
            '{}.{:06}'.format(td.days * 86400 + td.seconds, td.microseconds)
        ))

    def get_timedelta(self) -> datetime.timedelta:
        return datetime.timedelta(
            seconds=int(self.seconds), microseconds=int(self.seconds % 1 * 1000000)
        )

    def __repr__(self) -> str:
        return '%s(seconds=%s)' % (self.__class__.__name__, normalized_seconds(self.seconds))

    def __add__(self, other: object) -> Union['DayTimeDuration', Time, OrderedDateTime]:
        if isinstance(other, (Time, Date10)):
            return other + self
        elif isinstance(other, self.__class__):
            return DayTimeDuration(self.seconds + other.seconds)
        raise TypeError("cannot add %r to %r" % (type(other), type(self)))

    def __sub__(self, other: object) -> 'DayTimeDuration':
        if not isinstance(other, self.__class__):
            raise TypeError("cannot subtract %r from %r" % (type(other), type(self)))
        return DayTimeDuration(seconds=self.seconds - other.seconds)

    def __mul__(self, other: object) -> 'DayTimeDuration':
        if isinstance(other, (float, int, Decimal)):
            if math.isnan(other):
                raise ValueError("cannot multiply a %r by NaN" % type(self))

            if isinstance(other, (int, Decimal)):
                seconds = self.seconds * other
            else:
                seconds = self.seconds * Decimal.from_float(other)

            return DayTimeDuration(seconds)
        else:
            raise TypeError("cannot multiply a %r by %r" % (type(self), type(other)))

    def __truediv__(self, other: object) -> Union[Decimal, 'DayTimeDuration']:
        if isinstance(other, self.__class__):
            return self.seconds / other.seconds
        elif isinstance(other, (float, int, Decimal)):
            if math.isnan(other):
                raise ValueError("cannot divide a %r by NaN" % type(self))

            if isinstance(other, (int, Decimal)):
                seconds = self.seconds / other
            else:
                seconds = self.seconds / Decimal.from_float(other)

            return DayTimeDuration(seconds)
        else:
            raise TypeError("cannot divide a %r by %r" % (type(self), type(other)))
elementpath/xpath_nodes.py
def is_processing_instruction_node(obj: Any) -> bool:
    return hasattr(obj, 'tag') and callable(obj.tag) and obj.tag.__name__ == 'ProcessingInstruction'


Question: import sys
import math
import decimal
from ..datatypes import Duration, DayTimeDuration, YearMonthDuration, \
    StringProxy, AnyURI, Float10
from ..namespaces import XML_ID, XML_LANG, get_prefixed_name
from ..xpath_nodes import TextNode, is_xpath_node, is_document_node, \
    is_element_node, is_comment_node, is_processing_instruction_node, node_name
from ..xpath_token import XPathFunction
from ._xpath1_operators import XPath1Parser
#
# Copyright (c), 2018-2021, SISSA (International School for Advanced Studies).
# All rights reserved.
# This file is distributed under the terms of the MIT License.
# See the file 'LICENSE' in the root directory of the present
# distribution, or http://opensource.org/licenses/MIT.
#
# @author Davide Brunato <brunato@sissa.it>
#
# type: ignore
"""
XPath 1.0 implementation - part 3 (functions)
"""


method = XPath1Parser.method
function = XPath1Parser.function


###
# Kind tests (for matching of node types in XPath 1.0 or sequence types in XPath 2.0)
@method(function('node', nargs=0, label='kind test'))
def select_node_kind_test(self, context=None):
    if context is None:
        raise self.missing_context()

    for item in context.iter_children_or_self():
        if item is None:
            yield context.root
        elif is_xpath_node(item):
            yield item


@method('node')
def nud_item_sequence_type(self):
    XPathFunction.nud(self)
    if self.parser.next_token.symbol in ('*', '+', '?'):
        self.occurrence = self.parser.next_token.symbol
        self.parser.advance()
    return self


@method(function('processing-instruction', nargs=(0, 1), bp=79, label='kind test'))
def select_pi_kind_test(self, context=None):
    if context is None:
        raise self.missing_context()

    for item in context.iter_children_or_self():

Answer:         if is_processing_instruction_node(item):