1from __future__ import absolute_import 2# Copyright (c) 2010-2019 openpyxl 3 4""" 5Excel specific descriptors 6""" 7 8from openpyxl.xml.constants import REL_NS 9from openpyxl.compat import safe_string, unicode 10from openpyxl.xml.functions import Element 11 12from . import ( 13 MatchPattern, 14 MinMax, 15 Integer, 16 String, 17 Typed, 18 Sequence, 19) 20from .serialisable import Serialisable 21from openpyxl.utils.cell import RANGE_EXPR 22 23class HexBinary(MatchPattern): 24 25 pattern = "[0-9a-fA-F]+$" 26 27 28class UniversalMeasure(MatchPattern): 29 30 pattern = r"[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)" 31 32 33class TextPoint(MinMax): 34 """ 35 Size in hundredths of points. 36 In theory other units of measurement can be used but these are unbounded 37 """ 38 expected_type = int 39 40 min = -400000 41 max = 400000 42 43 44Coordinate = Integer 45 46 47class Percentage(MinMax): 48 49 pattern = r"((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%" # strict 50 min = -1000000 51 max = 1000000 52 53 def __set__(self, instance, value): 54 if isinstance(value, unicode) and "%" in value: 55 value = value.replace("%", "") 56 value = int(float(value) * 1000) 57 super(Percentage, self).__set__(instance, value) 58 59 60class Extension(Serialisable): 61 62 uri = String() 63 64 def __init__(self, 65 uri=None, 66 ): 67 self.uri = uri 68 69 70class ExtensionList(Serialisable): 71 72 ext = Sequence(expected_type=Extension) 73 74 def __init__(self, 75 ext=(), 76 ): 77 self.ext = ext 78 79 80class Relation(String): 81 82 namespace = REL_NS 83 allow_none = True 84 85 86class Base64Binary(MatchPattern): 87 # http://www.w3.org/TR/xmlschema11-2/#nt-Base64Binary 88 pattern = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$" 89 90 91class Guid(MatchPattern): 92 # https://msdn.microsoft.com/en-us/library/dd946381(v=office.12).aspx 93 pattern = r"{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}" 94 95 96class CellRange(MatchPattern): 97 98 pattern = r"^[$]?([A-Za-z]{1,3})[$]?(\d+)(:[$]?([A-Za-z]{1,3})[$]?(\d+)?)?$|^[A-Za-z]{1,3}:[A-Za-z]{1,3}$" 99 allow_none = True 100 101 def __set__(self, instance, value): 102 103 if value is not None: 104 value = value.upper() 105 super(CellRange, self).__set__(instance, value) 106 107 108def _explicit_none(tagname, value, namespace=None): 109 """ 110 Override serialisation because explicit none required 111 """ 112 if namespace is not None: 113 tagname = "{%s}%s" % (namespace, tagname) 114 return Element(tagname, val=safe_string(value)) 115