elementpath/datatypes/datetime.py
class GregorianYear(GregorianYear10):
    """XSD 1.1 xs:gYear builtin type"""
    name = 'gYear'
    xsd_version = '1.1'
elementpath/datatypes/datetime.py
class GregorianYearMonth(GregorianYearMonth10):
    """XSD 1.1 xs:gYearMonth builtin type"""
    name = 'gYearMonth'
    xsd_version = '1.1'
elementpath/datatypes/datetime.py
class GregorianYear10(OrderedDateTime):
    """XSD 1.0 xs:gYear builtin type"""
    name = 'gYear'
    pattern = re.compile(r'^(?P<year>-?[0-9]*[0-9]{4})'
                         r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))?$')

    def __init__(self, year: int, tzinfo: Optional[Timezone] = None) -> None:
        super(GregorianYear10, self).__init__(year, tzinfo=tzinfo)

    def __str__(self) -> str:
        return '{}{}'.format(self.iso_year, str(self.tzinfo or ''))
elementpath/namespaces.py
XSD_NAMESPACE = "http://www.w3.org/2001/XMLSchema"
elementpath/xpath2/_xpath2_functions.py
def is_local_url_scheme(scheme):
def is_local_dir_url(url):
def evaluate_item_sequence_type(self, context=None):
def nud_item_sequence_type(self):
def evaluate_prefix_from_qname_function(self, context=None):
def evaluate_local_name_from_qname_function(self, context=None):
def evaluate_uri_from_qname_function(self, context=None):
def evaluate_namespace_uri_for_prefix_function(self, context=None):
def select_in_scope_prefixes_function(self, context=None):
def evaluate_resolve_qname_function(self, context=None):
def evaluate_node_name_function(self, context=None):
def evaluate_nilled_function(self, context=None):
def select_data_function(self, context=None):
def evaluate_base_uri_function(self, context=None):
def evaluate_document_uri_function(self, context=None):
def evaluate_round_half_to_even_function(self, context=None):
def evaluate_abs_function(self, context=None):
def evaluate_avg_function(self, context=None):
def evaluate_max_min_functions(self, context=None):
    def max_or_min():
def evaluate_empty_and_exists_functions(self, context=None):
def select_empty_function(self, context=None):
def select_exists_function(self, context=None):
def select_distinct_values_function(self, context=None):
    def distinct_values():
def select_insert_before_function(self, context=None):
def select_index_of_function(self, context=None):
def select_remove_function(self, context=None):
def select_reverse_function(self, context=None):
def select_subsequence_function(self, context=None):
def select_unordered_function(self, context=None):
def select_zero_or_one_function(self, context=None):
def select_one_or_more_function(self, context=None):
def select_exactly_one_function(self, context=None):
def evaluate_deep_equal_function(self, context=None):
    def deep_equal():
def evaluate_matches_function(self, context=None):
def evaluate_replace_function(self, context=None):
def select_tokenize_function(self, context=None):
def evaluate_resolve_uri_function(self, context=None):
def evaluate_codepoints_to_string_function(self, context=None):
def evaluate_string_to_codepoints_function(self, context=None):
def evaluate_compare_function(self, context=None):
def evaluate_contains_function(self, context=None):
def evaluate_codepoint_equal_function(self, context=None):
def evaluate_string_join_function(self, context=None):
def evaluate_normalize_unicode_function(self, context=None):
def evaluate_upper_case_function(self, context=None):
def evaluate_lower_case_function(self, context=None):
def evaluate_encode_for_uri_function(self, context=None):
def evaluate_iri_to_uri_function(self, context=None):
def evaluate_escape_html_uri_function(self, context=None):
def evaluate_starts_with_function(self, context=None):
def evaluate_ends_with_function(self, context=None):
def evaluate_substring_functions(self, context=None):
def evaluate_years_from_duration_function(self, context=None):
def evaluate_months_from_duration_function(self, context=None):
def evaluate_days_from_duration_function(self, context=None):
def evaluate_hours_from_duration_function(self, context=None):
def evaluate_minutes_from_duration_function(self, context=None):
def evaluate_seconds_from_duration_function(self, context=None):
def evaluate_from_datetime_functions(self, context=None):
def evaluate_timezone_from_datetime_function(self, context=None):
def evaluate_from_date_functions(self, context=None):
def evaluate_hours_from_time_function(self, context=None):
def evaluate_minutes_from_time_function(self, context=None):
def evaluate_seconds_from_time_function(self, context=None):
def evaluate_timezone_from_time_function(self, context=None):
def evaluate_adjust_datetime_to_timezone_function(self, context=None):
def evaluate_adjust_date_to_timezone_function(self, context=None):
def evaluate_adjust_time_to_timezone_function(self, context=None):
def evaluate_default_collation_function(self, context=None):
def evaluate_static_base_uri_function(self, context=None):
def evaluate_current_datetime_function(self, context=None):
def evaluate_current_date_function(self, context=None):
def evaluate_current_time_function(self, context=None):
def evaluate_implicit_timezone_function(self, context=None):
def evaluate_root_function(self, context=None):
def evaluate_lang_function(self, context=None):
def select_id_function(self, context=None):
def select_idref_function(self, context=None):
def evaluate_doc_functions(self, context=None):
def evaluate_collection_function(self, context=None):
def evaluate_error_function(self, context=None):
def select_trace_function(self, context=None):
REPLACEMENT_PATTERN = re.compile(r'^([^\\$]|[\\]{2}|\\\$|\$\d+)*$')
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/datatypes/binary.py
class Base64Binary(AbstractBinary):
    name = 'base64Binary'
    pattern = re.compile(
        r'((?:(?:[A-Za-z0-9+/] ?){4})*(?:(?:[A-Za-z0-9+/] ?){3}[A-Za-z0-9+/]|'
        r'(?:[A-Za-z0-9+/] ?){2}'
        r'[AEIMQUYcgkosw048] ?=|[A-Za-z0-9+/] ?[AQgw] ?= ?=))?'
    )

    @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)

        value = value.replace(' ', '')
        if value:
            match = cls.pattern.match(value)
            if match is None or match.group(0) != value:
                raise cls.invalid_value(value)

    def __str__(self) -> str:
        return self.value.decode('utf-8')

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

    def __len__(self) -> int:
        if self.value[-2] == ord('='):
            return len(self.value) // 4 * 3 - 2
        elif self.value[-1] == ord('='):
            return len(self.value) // 4 * 3 - 1
        return len(self.value) // 4 * 3

    def __eq__(self, other: object) -> bool:
        if isinstance(other, self.__class__):
            return self.value == other.value
        elif isinstance(other, UntypedAtomic):
            return self.value == self.__class__(other).value
        elif isinstance(other, str):
            return self.value == other.encode()
        return isinstance(other, bytes) and self.value == other

    @staticmethod
    def encoder(value: bytes) -> bytes:
        return codecs.encode(value, 'base64').rstrip(b'\n')

    def decode(self) -> bytes:
        return codecs.decode(self.value, 'base64')
elementpath/datatypes/proxies.py
class BooleanProxy(metaclass=AtomicTypeMeta):
    name = 'boolean'
    pattern = re.compile(r'^(?:true|false|1|0)$')

    def __new__(cls, value: object) -> bool:  # type: ignore[misc]
        if isinstance(value, bool):
            return value
        elif isinstance(value, (int, float, Decimal)):
            if math.isnan(value):
                return False
            return bool(value)
        elif isinstance(value, UntypedAtomic):
            value = value.value
        elif not isinstance(value, str):
            raise TypeError('invalid type {!r} for xs:{}'.format(type(value), cls.name))

        if value.strip() not in BOOLEAN_VALUES:
            raise ValueError('invalid value {!r} for xs:{}'.format(value, cls.name))
        return 't' in value or '1' in value

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

    @classmethod
    def validate(cls, value: object) -> None:
        if isinstance(value, bool):
            return
        elif isinstance(value, str):
            if cls.pattern.match(value) is None:
                raise cls.invalid_value(value)
        else:
            raise cls.invalid_type(value)
elementpath/datatypes/datetime.py
class DateTime10(OrderedDateTime):
    """XSD 1.0 xs:dateTime builtin type"""
    name = 'dateTime'
    pattern = re.compile(
        r'^(?P<year>-?[0-9]*[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})'
        r'(T(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2}):'
        r'(?P<second>[0-9]{2})(?:\.(?P<microsecond>[0-9]+))?)'
        r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))?$')

    def __init__(self, year: int, month: int, day: int, hour: int = 0,
                 minute: int = 0, second: int = 0, microsecond: int = 0,
                 tzinfo: Optional[datetime.tzinfo] = None) -> None:
        super(DateTime10, self).__init__(
            year, month, day, hour, minute, second, microsecond, tzinfo
        )

    def __str__(self) -> str:
        if self.microsecond:
            return '{}-{:02}-{:02}T{:02}:{:02}:{:02}.{}{}'.format(
                self.iso_year, self.month, self.day, self.hour, self.minute, self.second,
                '{:06}'.format(self.microsecond).rstrip('0'), str(self.tzinfo or '')
            )
        return '{}-{:02}-{:02}T{:02}:{:02}:{:02}{}'.format(
            self.iso_year, self.month, self.day, self.hour,
            self.minute, self.second, str(self.tzinfo or '')
        )
elementpath/datatypes/datetime.py
class Time(AbstractDateTime):
    """XSD xs:time builtin type"""
    name = 'time'
    pattern = re.compile(
        r'^(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2}):'
        r'(?P<second>[0-9]{2})(?:\.(?P<microsecond>[0-9]+))?'
        r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))?$')

    def __init__(self, hour: int = 0, minute: int = 0,
                 second: int = 0, microsecond: int = 0,
                 tzinfo: Union[None, Timezone, datetime.tzinfo] = None) -> None:
        if hour == 24 and minute == second == microsecond == 0:
            hour = 0
        super(Time, self).__init__(
            hour=hour, minute=minute, second=second, microsecond=microsecond, tzinfo=tzinfo
        )

    def __str__(self) -> str:
        if self.microsecond:
            return '{:02}:{:02}:{:02}.{}{}'.format(
                self.hour, self.minute, self.second,
                '{:06}'.format(self.microsecond).rstrip('0'),
                str(self.tzinfo or '')
            )
        return '{:02}:{:02}:{:02}{}'.format(
            self.hour, self.minute, self.second, str(self.tzinfo or '')
        )

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

    def __le__(self, other: object) -> bool:
        return cast(bool, operator.le(*self._get_operands(other)))

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

    def __ge__(self, other: object) -> bool:
        return cast(bool, operator.ge(*self._get_operands(other)))

    def __add__(self, other: object) -> 'Time':
        if isinstance(other, DayTimeDuration):
            dt = self._dt + other.get_timedelta()
        elif isinstance(other, datetime.timedelta):
            dt = self._dt + other
        else:
            raise TypeError("wrong type %r for operand %r" % (type(other), other))
        return Time(dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)

    def __sub__(self, other: object) -> Union['DayTimeDuration', 'Time']:
        if isinstance(other, self.__class__):
            delta = operator.sub(*self._get_operands(other))
            return DayTimeDuration.fromtimedelta(delta)
        elif isinstance(other, DayTimeDuration):
            dt = self._dt - other.get_timedelta()
            return Time(dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
        elif isinstance(other, datetime.timedelta):
            dt = self._dt - other
            return Time(dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo)
        else:
            raise TypeError("wrong type %r for operand %r" % (type(other), other))
elementpath/datatypes/untyped.py
class UntypedAtomic(metaclass=AtomicTypeMeta):
    """
    Class for xs:untypedAtomic data. Provides special methods for comparing
    and converting to basic data types.

    :param value: the untyped value, usually a string.
    """
    name = 'untypedAtomic'
    value: str

    @classmethod
    def validate(cls, value: object) -> None:
        if not isinstance(value, cls):
            raise cls.invalid_type(value)

    def __init__(self, value: Union[str, bytes, bool, float, Decimal,
                                    'UntypedAtomic', AnyAtomicType]) -> None:
        if isinstance(value, str):
            self.value = value
        elif isinstance(value, bytes):
            self.value = value.decode('utf-8')
        elif isinstance(value, bool):
            self.value = 'true' if value else 'false'
        elif isinstance(value, float):
            self.value = str(value).rstrip('0').rstrip('.')
        elif isinstance(value, Decimal):
            self.value = str(value.normalize())
        elif isinstance(value, UntypedAtomic):
            self.value = value.value
        elif isinstance(value, AnyAtomicType):
            self.value = str(value)
        else:
            raise TypeError("{!r} is not an atomic value".format(value))

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

    def _get_operands(self, other: Any, force_float: bool = True) -> Tuple[Any, Any]:
        """
        Returns a couple of operands, applying a cast to the instance value based on
        the type of the *other* argument.

        :param other: The other operand, that determines the cast for the untyped instance.
        :param force_float: Force a conversion to float if *other* is an UntypedAtomic instance.
        :return: A couple of values.
        """
        if isinstance(other, UntypedAtomic):
            if force_float:
                return float(self.value), float(other.value)
            return self.value, other.value
        elif isinstance(other, bool):
            # Cast to xs:boolean
            value = self.value.strip()
            if value not in BOOLEAN_VALUES:
                raise ValueError("{!r} cannot be cast to xs:boolean".format(self.value))
            return value in ('1', 'true'), other
        elif isinstance(other, int):
            return float(self.value), other
        elif other is None or isinstance(other, (str, list)):
            return self.value, other

        try:
            return type(other).fromstring(self.value), other
        except AttributeError:
            return type(other)(self.value), other

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

    def __eq__(self, other: Any) -> Any:
        return operator.eq(*self._get_operands(other, force_float=False))

    def __ne__(self, other: Any) -> Any:
        return not operator.eq(*self._get_operands(other, force_float=False))

    def __lt__(self, other: Any) -> Any:
        return operator.lt(*self._get_operands(other))

    def __le__(self, other: Any) -> Any:
        return operator.le(*self._get_operands(other))

    def __gt__(self, other: Any) -> Any:
        return operator.gt(*self._get_operands(other))

    def __ge__(self, other: Any) -> Any:
        return operator.ge(*self._get_operands(other))

    def __add__(self, other: Any) -> Any:
        return operator.add(*self._get_operands(other))
    __radd__ = __add__

    def __sub__(self, other: Any) -> Any:
        return operator.sub(*self._get_operands(other))

    def __rsub__(self, other: Any) -> Any:
        return operator.sub(*reversed(self._get_operands(other)))

    def __mul__(self, other: Any) -> Any:
        return operator.mul(*self._get_operands(other))
    __rmul__ = __mul__

    def __truediv__(self, other: Any) -> Any:
        return operator.truediv(*self._get_operands(other))

    def __rtruediv__(self, other: Any) -> Any:
        return operator.truediv(*reversed(self._get_operands(other)))

    def __int__(self) -> int:
        return int(self.value)

    def __float__(self) -> float:
        return float(self.value)

    def __bool__(self) -> bool:
        return bool(self.value)  # For effective boolean value, not for cast to xs:boolean.

    def __abs__(self) -> Decimal:
        return abs(Decimal(self.value))

    def __mod__(self, other: Any) -> Any:
        return operator.mod(*self._get_operands(other))

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

    def __bytes__(self) -> bytes:
        return bytes(self.value, encoding='utf-8')
elementpath/datatypes/qname.py
class QName(AbstractQName):
    name = 'QName'
elementpath/datatypes/binary.py
class HexBinary(AbstractBinary):
    name = 'hexBinary'
    pattern = re.compile(r'^([0-9a-fA-F]{2})*$')

    @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)

        value = value.strip()
        if cls.pattern.match(value) is None:
            raise cls.invalid_value(value)

    @staticmethod
    def encoder(value: bytes) -> bytes:
        return codecs.encode(value, 'hex')

    def decode(self) -> bytes:
        return codecs.decode(self.value, 'hex')

    def __str__(self) -> str:
        return self.value.decode('utf-8').upper()

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

    def __len__(self) -> int:
        return len(self.value) // 2

    def __eq__(self, other: object) -> bool:
        if isinstance(other, self.__class__):
            return self.value.upper() == other.value.upper()
        elif isinstance(other, UntypedAtomic):
            return self.value.upper() == self.__class__(other).value.upper()
        elif isinstance(other, str):
            return self.value.upper() == other.encode().upper()
        return isinstance(other, bytes) and self.value.upper() == other.upper()
elementpath/datatypes/datetime.py
class GregorianMonth(OrderedDateTime):
    """XSD xs:gMonth builtin type"""
    name = 'gMonth'
    pattern = re.compile(r'^--(?P<month>[0-9]{2})'
                         r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))?$')

    def __init__(self, month: int, tzinfo: Optional[Timezone] = None) -> None:
        super(GregorianMonth, self).__init__(month=month, tzinfo=tzinfo)

    def __str__(self) -> str:
        return '--{:02}{}'.format(self.month, str(self.tzinfo or ''))
elementpath/exceptions.py
class ElementPathSyntaxError(ElementPathError, SyntaxError):
    pass
elementpath/datatypes/datetime.py
class GregorianDay(OrderedDateTime):
    """XSD xs:gDay builtin type"""
    name = 'gDay'
    pattern = re.compile(r'^---(?P<day>[0-9]{2})'
                         r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))?$')

    def __init__(self, day: int, tzinfo: Optional[Timezone] = None) -> None:
        super(GregorianDay, self).__init__(day=day, tzinfo=tzinfo)

    def __str__(self) -> str:
        return '---{:02}{}'.format(self.day, str(self.tzinfo or ''))
elementpath/datatypes/datetime.py
class GregorianMonthDay(OrderedDateTime):
    """XSD xs:gMonthDay builtin type"""
    name = 'gMonthDay'
    pattern = re.compile(r'^--(?P<month>[0-9]{2})-(?P<day>[0-9]{2})'
                         r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))?$')

    def __init__(self, month: int, day: int, tzinfo: Optional[Timezone] = None) -> None:
        super(GregorianMonthDay, self).__init__(month=month, day=day, tzinfo=tzinfo)

    def __str__(self) -> str:
        return '--{:02}-{:02}{}'.format(self.month, self.day, str(self.tzinfo or ''))
elementpath/datatypes/datetime.py
class Date10(OrderedDateTime):
    """XSD 1.0 xs:date builtin type"""
    name = 'date'
    pattern = re.compile(r'^(?P<year>-?[0-9]*[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})'
                         r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))?$')

    def __init__(self, year: int, month: int, day: int,
                 tzinfo: Optional[datetime.tzinfo] = None) -> None:
        super(Date10, self).__init__(year, month, day, tzinfo=tzinfo)

    def __str__(self) -> str:
        return '{}-{:02}-{:02}{}'.format(
            self.iso_year, self.month, self.day, str(self.tzinfo or '')
        )
elementpath/datatypes/datetime.py
class DateTimeStamp(DateTime):
    """XSD 1.1 xs:dateTimeStamp builtin type"""
    name = 'dateTimeStamp'
    pattern = re.compile(
        r'^(?P<year>-?[0-9]*[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})'
        r'(T(?P<hour>[0-9]{2}):(?P<minute>[0-9]{2}):'
        r'(?P<second>[0-9]{2})(?:\.(?P<microsecond>[0-9]+))?)'
        r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))$')
elementpath/datatypes/datetime.py
class Date(Date10):
    """XSD 1.1 xs:date builtin type"""
    name = 'date'
    xsd_version = '1.1'
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 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/datatypes/datetime.py
class DateTime(DateTime10):
    """XSD 1.1 xs:dateTime builtin type"""
    name = 'dateTime'
    xsd_version = '1.1'
elementpath/exceptions.py
class ElementPathError(Exception):
    """
    Base exception class for elementpath package.

    :param message: the message related to the error.
    :param code: an optional error code.
    :param token: an optional token instance related with the error.
    """
    def __init__(self, message: str,
                 code: Optional[str] = None,
                 token: Optional[Token[Any]] = None) -> None:
        super(ElementPathError, self).__init__(message)
        self.message = message
        self.code = code
        self.token = token

    def __str__(self) -> str:
        if self.token is None or not isinstance(self.token.value, (str, bytes)):
            if not self.code:
                return self.message
            return '[{}] {}'.format(self.code, self.message)
        elif not self.code:
            return '{1} at line {2}, column {3}: {0}'.format(
                self.message, self.token, *self.token.position
            )
        return '{2} at line {3}, column {4}: [{1}] {0}'.format(
            self.message, self.code, self.token, *self.token.position
        )
elementpath/datatypes/atomic_types.py
XSD_NAMESPACE = "http://www.w3.org/2001/XMLSchema"
class AtomicTypeMeta(ABCMeta):
class AnyAtomicType(metaclass=AtomicTypeMeta):
    def __new__(mcs, class_name: str, bases: Tuple[Type[Any], ...], dict_: Dict[str, Any]) \
    def validate(cls, value: object) -> None:
    def is_valid(cls, value: object) -> bool:
    def invalid_type(cls, value: object) -> TypeError:
    def invalid_value(cls, value: object) -> ValueError:
elementpath/datatypes/datetime.py
class GregorianYearMonth10(OrderedDateTime):
    """XSD 1.0 xs:gYearMonth builtin type"""
    name = 'gYearMonth'
    pattern = re.compile(r'^(?P<year>-?[0-9]*[0-9]{4})-(?P<month>[0-9]{2})'
                         r'(?P<tzinfo>Z|[+-](?:(?:0[0-9]|1[0-3]):[0-5][0-9]|14:00))?$')

    def __init__(self, year: int, month: int, tzinfo: Optional[Timezone] = None) -> None:
        super(GregorianYearMonth10, self).__init__(year, month, tzinfo=tzinfo)

    def __str__(self) -> str:
        return '{}-{:02}{}'.format(self.iso_year, self.month, str(self.tzinfo or ''))


Question: from ..exceptions import ElementPathError, ElementPathSyntaxError
from ..namespaces import XSD_NAMESPACE
from ..datatypes import xsd10_atomic_types, xsd11_atomic_types, GregorianDay, \
    GregorianMonth, GregorianMonthDay, GregorianYear10, GregorianYear, \
    GregorianYearMonth10, GregorianYearMonth, Duration, DayTimeDuration, \
    YearMonthDuration, Date10, Date, DateTime10, DateTime, DateTimeStamp, \
    Time, UntypedAtomic, QName, HexBinary, Base64Binary, BooleanProxy
from ._xpath2_functions import XPath2Parser


register = XPath2Parser.register
unregister = XPath2Parser.unregister
method = XPath2Parser.method
constructor = XPath2Parser.constructor


###
# Constructors for string-based XSD types
@constructor('normalizedString')
@constructor('token')
@constructor('language')
@constructor('NMTOKEN')
@constructor('Name')
@constructor('NCName')
@constructor('ID')
@constructor('IDREF')
@constructor('ENTITY')
@constructor('anyURI')
def cast_string_based_types(self, value):
    try:
        return xsd10_atomic_types[self.symbol](value)
    except ValueError as err:
        raise self.error('FORG0001', err)


###
# Constructors for numeric XSD types
@constructor('decimal')
@constructor('double')
@constructor('float')
def cast_numeric_types(self, value):
    try:
        if self.parser.xsd_version == '1.0':
            return xsd10_atomic_types[self.symbol](value)
        return xsd11_atomic_types[self.symbol](value)
    except ValueError as err:
        if isinstance(value, (str, UntypedAtomic)):
            raise self.error('FORG0001', err)
        raise self.error('FOCA0002', err)


@constructor('integer')
@constructor('nonNegativeInteger')
@constructor('positiveInteger')
@constructor('nonPositiveInteger')
@constructor('negativeInteger')
@constructor('long')
@constructor('int')
@constructor('short')
@constructor('byte')
@constructor('unsignedLong')
@constructor('unsignedInt')
@constructor('unsignedShort')
@constructor('unsignedByte')
def cast_integer_types(self, value):
    try:
        return xsd10_atomic_types[self.symbol](value)
    except ValueError:
        msg = 'could not convert {!r} to xs:{}'.format(value, self.symbol)
        if isinstance(value, (str, bytes, int, UntypedAtomic)):
            raise self.error('FORG0001', msg) from None
        raise self.error('FOCA0002', msg) from None
    except OverflowError as err:
        raise self.error('FOCA0002', err) from None


###
# Constructors for datetime XSD types
@constructor('date')
def cast_date_type(self, value):
    cls = Date if self.parser.xsd_version == '1.1' else Date10
    if isinstance(value, cls):
        return value

    try:
        if isinstance(value, UntypedAtomic):
            return cls.fromstring(value.value)
        elif isinstance(value, DateTime10):
            return cls(value.year, value.month, value.day, value.tzinfo)
        return cls.fromstring(value)
    except OverflowError as err:
        raise self.error('FODT0001', err) from None
    except ValueError as err:
        raise self.error('FORG0001', err)


@constructor('gDay')
def cast_gregorian_day_type(self, value):
    if isinstance(value, GregorianDay):
        return value

    try:
        if isinstance(value, UntypedAtomic):
            return GregorianDay.fromstring(value.value)
        elif isinstance(value, (Date10, DateTime10)):
            return GregorianDay(value.day, value.tzinfo)
        return GregorianDay.fromstring(value)
    except ValueError as err:
        raise self.error('FORG0001', err)


@constructor('gMonth')
def cast_gregorian_month_type(self, value):
    if isinstance(value, GregorianMonth):
        return value

    try:
        if isinstance(value, UntypedAtomic):
            return GregorianMonth.fromstring(value.value)
        elif isinstance(value, (Date10, DateTime10)):
            return GregorianMonth(value.month, value.tzinfo)
        return GregorianMonth.fromstring(value)
    except ValueError as err:
        raise self.error('FORG0001', err)


@constructor('gMonthDay')
def cast_gregorian_month_day_type(self, value):

Answer:     if isinstance(value, GregorianMonthDay):