/usr/lib/python3/dist-packages/openpyxl/utils/cell.py is in python3-openpyxl 2.4.9-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 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | from __future__ import absolute_import
# Copyright (c) 2010-2017 openpyxl
"""
Collection of utilities used within the package and also available for client code
"""
import re
from openpyxl.compat import basestring
from .exceptions import CellCoordinatesException
# constants
COORD_RE = re.compile(r'^[$]?([A-Z]+)[$]?(\d+)$')
COL_RANGE = """[A-Z]{1,3}:[A-Z]{1,3}:"""
ROW_RANGE = r"""\d+:\d+:"""
RANGE_EXPR = r"""
[$]?(?P<min_col>[A-Za-z]{1,3})?
[$]?(?P<min_row>\d+)?
(:[$]?(?P<max_col>[A-Za-z]{1,3})?
[$]?(?P<max_row>\d+)?)?
"""
ABSOLUTE_RE = re.compile('^' + RANGE_EXPR +'$', re.VERBOSE)
SHEET_TITLE = r"""
(('(?P<quoted>([^']|'')*)')|(?P<notquoted>[^'^ ^!]*))!"""
SHEETRANGE_RE = re.compile("""{0}(?P<cells>{1})(?=,?)""".format(
SHEET_TITLE, RANGE_EXPR), re.VERBOSE)
def get_column_interval(start, end):
"""
Given the start and end colums, return all the columns in the series.
The start and end columns can be either column letters or 1-based
indexes.
"""
if isinstance(start, basestring):
start = column_index_from_string(start)
if isinstance(end, basestring):
end = column_index_from_string(end)
return [get_column_letter(x) for x in range(start, end + 1)]
def coordinate_from_string(coord_string):
"""Convert a coordinate string like 'B12' to a tuple ('B', 12)"""
match = COORD_RE.match(coord_string.upper())
if not match:
msg = 'Invalid cell coordinates (%s)' % coord_string
raise CellCoordinatesException(msg)
column, row = match.groups()
row = int(row)
if not row:
msg = "There is no row 0 (%s)" % coord_string
raise CellCoordinatesException(msg)
return (column, row)
def absolute_coordinate(coord_string):
"""Convert a coordinate to an absolute coordinate string (B12 -> $B$12)"""
m = ABSOLUTE_RE.match(coord_string.upper())
if not m:
raise ValueError("Value is not a valid coordinate range")
d = m.groupdict('')
for k, v in d.items():
if v:
d[k] = "${0}".format(v)
if d['max_col'] or d['max_row']:
fmt = "{min_col}{min_row}:{max_col}{max_row}"
else:
fmt = "{min_col}{min_row}"
return fmt.format(**d)
def _get_column_letter(col_idx):
"""Convert a column number into a column letter (3 -> 'C')
Right shift the column col_idx by 26 to find column letters in reverse
order. These numbers are 1-based, and can be converted to ASCII
ordinals by adding 64.
"""
# these indicies corrospond to A -> ZZZ and include all allowed
# columns
if not 1 <= col_idx <= 18278:
raise ValueError("Invalid column index {0}".format(col_idx))
letters = []
while col_idx > 0:
col_idx, remainder = divmod(col_idx, 26)
# check for exact division and borrow if needed
if remainder == 0:
remainder = 26
col_idx -= 1
letters.append(chr(remainder+64))
return ''.join(reversed(letters))
_COL_STRING_CACHE = {}
_STRING_COL_CACHE = {}
for i in range(1, 18279):
col = _get_column_letter(i)
_STRING_COL_CACHE[i] = col
_COL_STRING_CACHE[col] = i
def get_column_letter(idx,):
"""Convert a column index into a column letter
(3 -> 'C')
"""
try:
return _STRING_COL_CACHE[idx]
except KeyError:
raise ValueError("Invalid column index {0}".format(idx))
def column_index_from_string(str_col):
"""Convert a column name into a numerical index
('A' -> 1)
"""
# we use a function argument to get indexed name lookup
try:
return _COL_STRING_CACHE[str_col.upper()]
except KeyError:
raise ValueError("{0} is not a valid column name".format(str_col))
def range_boundaries(range_string):
"""
Convert a range string into a tuple of boundaries:
(min_col, min_row, max_col, max_row)
Cell coordinates will be converted into a range with the cell at both end
"""
m = ABSOLUTE_RE.match(range_string)
if not m:
raise ValueError("{0} is not a valid coordinate or range")
min_col, min_row, sep, max_col, max_row = m.groups()
if min_col is not None:
min_col = column_index_from_string(min_col)
if min_row is not None:
min_row = int(min_row)
if max_col is not None:
max_col = column_index_from_string(max_col)
else:
max_col = min_col
if max_row is not None:
max_row = int(max_row)
else:
max_row = min_row
return min_col, min_row, max_col, max_row
def rows_from_range(range_string):
"""
Get individual addresses for every cell in a range.
Yields one row at a time.
"""
min_col, min_row, max_col, max_row = range_boundaries(range_string)
rows = range(min_row, max_row+1)
cols = [get_column_letter(col) for col in range(min_col, max_col+1)]
for row in rows:
yield tuple('{0}{1}'.format(col, row) for col in cols)
def cols_from_range(range_string):
"""
Get individual addresses for every cell in a range.
Yields one row at a time.
"""
min_col, min_row, max_col, max_row = range_boundaries(range_string)
rows = range(min_row, max_row+1)
cols = (get_column_letter(col) for col in range(min_col, max_col+1))
for col in cols:
yield tuple('{0}{1}'.format(col, row) for row in rows)
def coordinate_to_tuple(coordinate):
"""
Convert an Excel style coordinate to (row, colum) tuple
"""
col, row = coordinate_from_string(coordinate)
return row, _COL_STRING_CACHE[col]
def range_to_tuple(range_string):
"""
Convert a worksheet range to the sheetname and maximum and minimum
coordinate indices
"""
m = SHEETRANGE_RE.match(range_string)
if m is None:
raise ValueError("Value must be of the form sheetname!A1:E4")
sheetname = m.group("quoted") or m.group("notquoted")
cells = m.group("cells")
boundaries = range_boundaries(cells)
return sheetname, boundaries
def quote_sheetname(sheetname):
"""
Add quotes around sheetnames if they contain spaces.
"""
if "'" in sheetname:
sheetname = sheetname.replace("'", "''")
if (" " in sheetname
or "-" in sheetname
or "'" in sheetname):
sheetname = u"'{0}'".format(sheetname)
return sheetname
|