# Source code for openpyxl.descriptors.excel

    # Copyright (c) 2010-2024 openpyxl

    """
    Excel specific descriptors
    """

    from openpyxl.xml.constants import REL_NS
    from openpyxl.compat import safe_string
    from openpyxl.xml.functions import Element

    from . import (
        MatchPattern,
        MinMax,
        Integer,
        String,
        Sequence,
    )
    from .serialisable import Serialisable

    class HexBinary(MatchPattern):

        pattern = "[0-9a-fA-F]+$"

    class UniversalMeasure(MatchPattern):

        pattern = r"[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"

    class TextPoint(MinMax):
        """
        Size in hundredths of points.
        In theory other units of measurement can be used but these are unbounded
        """
        expected_type = int

        min = -400000
        max = 400000

    Coordinate = Integer

    class Percentage(MinMax):

        pattern = r"((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%" # strict
        min = -1000000
        max = 1000000

        def __set__(self, instance, value):
            if isinstance(value, str) and "%" in value:
                value = value.replace("%", "")
                value = int(float(value) * 1000)
            super().__set__(instance, value)

    class Extension(Serialisable):

        uri = String()

        def __init__(self,
                     uri=None,
                    ):
            self.uri = uri

    class ExtensionList(Serialisable):

        ext = Sequence(expected_type=Extension)

        def __init__(self,
                     ext=(),
                    ):
            self.ext = ext

    class Relation(String):

        namespace = REL_NS
        allow_none = True

    class Base64Binary(MatchPattern):
        # http://www.w3.org/TR/xmlschema11-2/#nt-Base64Binary
        pattern = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$"

    class Guid(MatchPattern):
        # https://msdn.microsoft.com/en-us/library/dd946381(v=office.12).aspx
        pattern = r"{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"

    class CellRange(MatchPattern):

        pattern = r"^[$]?([A-Za-z]{1,3})[$]?(\d+)(:[$]?([A-Za-z]{1,3})[$]?(\d+)?)?$|^[A-Za-z]{1,3}:[A-Za-z]{1,3}$"
        allow_none = True

        def __set__(self, instance, value):

            if value is not None:
                value = value.upper()
            super().__set__(instance, value)

    def _explicit_none(tagname, value, namespace=None):
        """
        Override serialisation because explicit none required
        """
        if namespace is not None:
            tagname = "{%s}%s" % (namespace, tagname)
        return Element(tagname, val=safe_string(value))