/usr/lib/python3/dist-packages/openpyxl/worksheet/datavalidation.py is in python3-openpyxl 2.3.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | from __future__ import absolute_import
# Copyright (c) 2010-2015 openpyxl
from itertools import groupby, chain
import warnings
from openpyxl.descriptors.serialisable import Serialisable
from openpyxl.descriptors import Bool, NoneSet, String
from openpyxl.descriptors.nested import NestedText
from openpyxl.compat import OrderedDict, safe_string, deprecated, unicode
from openpyxl.utils import coordinate_from_string
from openpyxl.worksheet import rows_from_range
from openpyxl.xml.functions import Element, SubElement
def collapse_cell_addresses(cells, input_ranges=()):
""" Collapse a collection of cell co-ordinates down into an optimal
range or collection of ranges.
E.g. Cells A1, A2, A3, B1, B2 and B3 should have the data-validation
object applied, attempt to collapse down to a single range, A1:B3.
Currently only collapsing contiguous vertical ranges (i.e. above
example results in A1:A3 B1:B3). More work to come.
"""
keyfunc = lambda x: x[0]
# Get the raw coordinates for each cell given
raw_coords = [coordinate_from_string(cell) for cell in cells]
# Group up as {column: [list of rows]}
grouped_coords = OrderedDict((k, [c[1] for c in g]) for k, g in
groupby(sorted(raw_coords, key=keyfunc), keyfunc))
ranges = list(input_ranges)
# For each column, find contiguous ranges of rows
for column in grouped_coords:
rows = sorted(grouped_coords[column])
grouped_rows = [[r[1] for r in list(g)] for k, g in
groupby(enumerate(rows),
lambda x: x[0] - x[1])]
for rows in grouped_rows:
if len(rows) == 0:
pass
elif len(rows) == 1:
ranges.append("%s%d" % (column, rows[0]))
else:
ranges.append("%s%d:%s%d" % (column, rows[0], column, rows[-1]))
return " ".join(ranges)
def expand_cell_ranges(range_string):
"""
Expand cell ranges to a sequence of addresses.
Reverse of collapse_cell_addresses
Eg. converts "A1:A2 B1:B2" to (A1, A2, B1, B2)
"""
cells = []
for rs in range_string.split():
cells.extend(rows_from_range(rs))
return list(chain.from_iterable(cells))
class DataValidation(Serialisable):
tagname = "dataValidation"
showErrorMessage = Bool()
showDropDown = Bool(allow_none=True)
showInputMessage = Bool()
showErrorMessage = Bool()
allowBlank = Bool()
allow_blank = Bool()
errorTitle = String(allow_none = True)
error = String(allow_none = True)
promptTitle = String(allow_none = True)
prompt = String(allow_none = True)
sqref = String(allow_none = True)
formula1 = NestedText(allow_none=True, expected_type=unicode)
formula2 = NestedText(allow_none=True, expected_type=unicode)
type = NoneSet(values=("whole", "decimal", "list", "date", "time",
"textLength", "custom"))
errorStyle = NoneSet(values=("stop", "warning", "information"))
imeMode = NoneSet(values=("noControl", "off", "on", "disabled",
"hiragana", "fullKatakana", "halfKatakana", "fullAlpha","halfAlpha",
"fullHangul", "halfHangul"))
operator = NoneSet(values=("between", "notBetween", "equal", "notEqual",
"lessThan", "lessThanOrEqual", "greaterThan", "greaterThanOrEqual"))
def __init__(self,
type=None,
formula1=None,
formula2=None,
allow_blank=False,
showErrorMessage=True,
showInputMessage=True,
showDropDown=None,
allowBlank=None,
sqref=None,
promptTitle=None,
errorStyle=None,
error=None,
prompt=None,
errorTitle=None,
imeMode=None,
operator=None,
validation_type=None, # remove in future
):
self.showDropDown = showDropDown
self.imeMode = imeMode
self.operator = operator
self.formula1 = formula1
self.formula2 = formula2
self.allowBlank = allow_blank
if allowBlank is not None:
self.allowBlank = allowBlank
self.showErrorMessage = showErrorMessage
self.showInputMessage = showInputMessage
if validation_type is not None:
warnings.warn("Use 'DataValidation(type={0})'".format(validation_type))
if type is not None:
self.type = validation_type
self.type = type
self.cells = set()
self.ranges = []
if sqref is not None:
self.sqref = sqref
self.promptTitle = promptTitle
self.errorStyle = errorStyle
self.error = error
self.prompt = prompt
self.errorTitle = errorTitle
def to_tree(self, tagname=None):
attrs = dict(self)
el = Element(self.tagname, attrs)
for n in self.__nested__:
value = getattr(self, n)
if value:
SubElement(el, n).text = value
return el
@deprecated("Use DataValidation.add(). Will be removed in 2.4")
def add_cell(self, cell):
"""Adds a openpyxl.cell to this validator"""
self.add(cell)
def add(self, cell):
"""Adds a openpyxl.cell to this validator"""
self.cells.add(cell.coordinate)
@deprecated("Set DataValidation.ErrorTitle and DataValidation.error Will be removed in 2.4")
def set_error_message(self, error, error_title="Validation Error"):
"""Creates a custom error message, displayed when a user changes a cell
to an invalid value"""
self.errorTitle = error_title
self.error = error
@deprecated("Set DataValidation.PromptTitle and DataValidation.prompt Will be removed in 2.4")
def set_prompt_message(self, prompt, prompt_title="Validation Prompt"):
"""Creates a custom prompt message"""
self.promptTitle = prompt_title
self.prompt = prompt
@property
def sqref(self):
return collapse_cell_addresses(self.cells, self.ranges)
@sqref.setter
def sqref(self, range_string):
self.cells = expand_cell_ranges(range_string)
def __iter__(self):
for attr in ('type', 'allowBlank', 'operator', 'sqref',
'showInputMessage', 'showErrorMessage', 'errorTitle', 'error',
'errorStyle',
'promptTitle', 'prompt'):
value = getattr(self, attr)
if value is not None:
yield attr, safe_string(value)
|