def set_columns_width(self, begin, end, start_cell): """ Копирование ширины колонок :param begin: начало секции, пример ('A', 1) :type begin: 2-tuple :param end: конец секции, пример ('E', 6) :type end: 2-tuple :param start_cell: ячейка с которой выводилась секция :type start_cell: 2-tuple """ # определим интервал столбцов из которых надо взять ширину end = self.get_cell_end(end) cols = list(ColumnHelper.get_range(begin[0], end[0])) # определим интервал столбцов, начинаемый со столбца начальной ячейки, куда надо прописать ширину end_col = ColumnHelper.add(start_cell[0], ColumnHelper.difference(end[0], begin[0])) new_cols = list(ColumnHelper.get_range(start_cell[0], end_col)) # запишем ширину столбцов в интервал for index, src_col in enumerate(cols): dst_col = new_cols[index] src_col_el = self._create_or_get_output_col(src_col) # если нет исходной колонки, то не надо копировать if not src_col_el is None: # копируем данные attrib_col = dict(src_col_el.items()) dst_col_el = self._create_or_get_output_col(dst_col, attrib_col) # записываем в новую колонку self._set_new_column_width(dst_col, src_col_el, dst_col_el)
def set_columns_width(self, begin, end, start_cell): """ Копирование ширины колонок :param begin: начало секции, пример ('A', 1) :type begin: 2-tuple :param end: конец секции, пример ('E', 6) :type end: 2-tuple :param start_cell: ячейка с которой выводилась секция :type start_cell: 2-tuple """ # определим интервал столбцов из которых надо взять ширину end = self.get_cell_end(end) cols = list(ColumnHelper.get_range(begin[0], end[0])) # определим интервал столбцов, начинаемый со столбца начальной ячейки, куда надо прописать ширину end_col = ColumnHelper.add(start_cell[0], ColumnHelper.difference(end[0], begin[0])) new_cols = list(ColumnHelper.get_range(start_cell[0], end_col)) # запишем ширину столбцов в интервал for index, src_col in enumerate(cols): dst_col = new_cols[index] src_col_el = self._create_or_get_output_col(src_col) # если нет исходной колонки, то не надо копировать if not src_col_el is None: # копируем данные attrib_col = dict(src_col_el.items()) dst_col_el = self._create_or_get_output_col( dst_col, attrib_col) # записываем в новую колонку self._set_new_column_width(dst_col, src_col_el, dst_col_el)
def cell_dimensions(section, merge_cell, start_cell): """ Получение координаты ячейки после смещения из-за объединения ячеек :param section: начало секции :type section: 2-tuple :param merge_cell: начало объединенной ячейки :type merge_cell: 2-tuple :param start_cell: стартовая ячейка :type start_cell: 2-tuple """ section_begin_col, section_begin_row = section start_col, start_row = start_cell begin_col, begin_row = merge_cell new_begin_row = start_row + begin_row - section_begin_row new_begin_col = ColumnHelper.add( start_col, ColumnHelper.difference(begin_col, section_begin_col)) return new_begin_col + str(new_begin_row)
def test_range_cols(self): section_range = list(ColumnHelper.get_range(('ALC'), ('AVB'))) self.assertIn('ALC', section_range) self.assertIn('AVB', section_range) self.assertIn('AVA', section_range) self.assertNotIn('ALA', section_range) self.assertNotIn('AVC', section_range) section_range = list(ColumnHelper.get_range(('X'), ('AB'))) self.assertIn('X', section_range) self.assertIn('Y', section_range) self.assertIn('AA', section_range) self.assertNotIn('Q', section_range) self.assertNotIn('AC', section_range) self.assertEqual(len(section_range), 5) section_range = list(ColumnHelper.get_range(('B'), ('CBD'))) self.assertIn('B', section_range) self.assertIn('C', section_range) self.assertIn('AAA', section_range) self.assertIn('ZZ', section_range) self.assertIn('ABA', section_range) self.assertIn('CBD', section_range) self.assertIn('CAA', section_range) self.assertIn('BZZ', section_range) self.assertNotIn('CBE', section_range) section_range = list(ColumnHelper.get_range(('BCCC'), ('BCCD'))) self.assertIn('BCCC', section_range) self.assertIn('BCCD', section_range) self.assertNotIn('A', section_range) self.assertNotIn('BCCE', section_range) self.assertEqual(len(section_range), 2)
def _calculate_merge_column(self, column): column_number = ColumnHelper.column_to_number(column) first_section_column = ColumnHelper.number_to_column(column_number - self.section.get_width()) last_section_column = ColumnHelper.number_to_column(column_number - 1) return first_section_column, last_section_column
def _calculate_merge_column(self, column): column_number = ColumnHelper.column_to_number(column) first_section_column = ColumnHelper.number_to_column( column_number - self.section.get_width()) last_section_column = ColumnHelper.number_to_column(column_number - 1) return first_section_column, last_section_column
def calculate_indent(self, column, w): """ Получение колонки на `w` раньше чем `column` :param column: строковое представление колонки :type column: str :param w: смещение :type w: int """ return ColumnHelper.number_to_column( ColumnHelper.column_to_number(column) - w)
def get_next_column(self, current_col, end_col, begin_col): """ Получение следующей колонки :param current_col: текущая колонка :type current_col: str :param end_col: конечная колонка :type end_col: str :param begin_col: начальная колонка :type begin_col: str """ return ColumnHelper.add(current_col, ColumnHelper.difference(end_col, begin_col) + 1)
def get_next_column(self, current_col, end_col, begin_col): """ Получение следующей колонки :param current_col: текущая колонка :type current_col: str :param end_col: конечная колонка :type end_col: str :param begin_col: начальная колонка :type begin_col: str """ return ColumnHelper.add( current_col, ColumnHelper.difference(end_col, begin_col) + 1)
def _create_or_get_output_col(self, col_index, attrib_col=None): """ Найдем существующую колонку в результирующих данных Если не передали начальные данные, то колонка не создается, если не найдена, :param col_index: индекс колонки :type col_index: int :param attrib_col: атрибуты элемента колонки :type attrib_col: dict """ # найдем интервал, в который попадаем искомый индекс col_index = ColumnHelper.column_to_number(col_index) + 1 col_el = None for col in self.write_cols.getchildren(): begin_col = int(col.attrib['min']) end_col = int(col.attrib['max']) if begin_col <= col_index <= end_col: col_el = col break if col_el is None: # если не нашли - создадим if attrib_col is None: return None attrib_col["min"] = str(col_index) attrib_col["max"] = str(col_index) col_el = SubElement(self.write_cols, 'col', attrib=attrib_col) return col_el
def get_width(self): u""" Получение ширины секции """ begin_col, begin_row = self.begin end_col, end_row = self.sheet_data.get_cell_end(self.end) return ColumnHelper.difference(end_col, begin_col) + 1
def test_horizontal(self, report=None): if report is None: return for i in range(3): section3 = report.get_section('Section3') section3.flush({'section3': i}, oriented=Section.HORIZONTAL) self.assertEqual(section3.sheet_data.cursor.row, ('C', 9)) self.assertEqual(section3.sheet_data.cursor.column, (ColumnHelper.add('G', 2 * i), 7))
def set_dimension(self): u""" Установка диапазона """ _, row_index = self.cursor.row col_index, _ = self.cursor.column dimension = 'A1:%s' % \ (ColumnHelper.add(col_index, -1) + str(row_index - 1)) self.write_dimension.set('ref', dimension)
def flush( self, params, oriented=ISpreadsheetSection.LEFT_DOWN, used_formulas=None ): """ Вывод. Имеется два механизма вывода. Для использования старого не передавать direction :param params: параметры замены :type params: dict :param oriented: направление ориентации :type oriented: ISpreadsheetSection :param used_formulas: использованные формулы :type used_formulas: dict """ assert isinstance(params, dict) assert oriented in (Section.VERTICAL, Section.HORIZONTAL, Section.LEFT_DOWN, Section.RIGHT_UP, Section.RIGHT, Section.HIERARCHICAL) # Тут смещение курсора, копирование данных из листа и общих строк # Генерация новых данных и новых общих строк cursor = self.sheet_data.cursor begin_col, begin_row = self.begin end_col, end_row = self.sheet_data.get_cell_end(self.end) current_col, current_row = CalculateNextCursorXLSX().get_next_cursor(cursor, (begin_col, begin_row), (end_col, end_row), oriented, self) self.sheet_data.last_section.row = (current_col, current_row) self.sheet_data.last_section.column = (ColumnHelper.add(current_col, ColumnHelper.difference(end_col, begin_col)), current_row + end_row - begin_row) self.sheet_data.flush(self.begin, self.end, (current_col, current_row), params, used_formulas)
def set_pagebreaks(self, begin, end, start_cell): """ Копирование разделителей страниц :param begin: начало секции, пример ('A', 1) :type begin: 2-tuple :param end: конец секции, пример ('E', 6) :type end: 2-tuple :param start_cell: ячейка с которой выводилась секция :type start_cell: 2-tuple """ # определим интервал столбцов и колонок из которых надо взять разделители end = self.get_cell_end(end) begin_col = ColumnHelper.column_to_number(begin[0]) end_col = ColumnHelper.column_to_number(end[0]) begin_row = int(begin[1]) end_row = int(end[1]) # определим интервал столбцов и колонок, начинаемый с начальной ячейки, куда надо добавить разделители new_begin_col = ColumnHelper.column_to_number(start_cell[0]) new_begin_row = int(start_cell[1]) # вытащим смещение индексов столбцов у которых есть разделители и которые попали в этот интервал colbreaks = [] if self.read_colbreaks is not None: for elem in self.read_colbreaks.getchildren(): col_index = int(elem.attrib['id']) if begin_col <= col_index - 1 <= end_col: colbreaks.append(col_index - begin_col + new_begin_col) self._set_colpagebreaks(colbreaks) # вытащим смещение индексов строк у которых есть разделители и которые попали в этот интервал rowbreaks = [] if self.read_rowbreaks is not None: for elem in self.read_rowbreaks.getchildren(): row_index = int(elem.attrib['id']) if begin_row <= row_index <= end_row: rowbreaks.append(row_index - begin_row + new_begin_row) self._set_rowpagebreaks(rowbreaks)
def flush(self, params, oriented=ISpreadsheetSection.LEFT_DOWN, used_formulas=None): """ Вывод. Имеется два механизма вывода. Для использования старого не передавать direction :param params: параметры замены :type params: dict :param oriented: направление ориентации :type oriented: ISpreadsheetSection :param used_formulas: использованные формулы :type used_formulas: dict """ assert isinstance(params, dict) assert oriented in (Section.VERTICAL, Section.HORIZONTAL, Section.LEFT_DOWN, Section.RIGHT_UP, Section.RIGHT, Section.HIERARCHICAL) # Тут смещение курсора, копирование данных из листа и общих строк # Генерация новых данных и новых общих строк cursor = self.sheet_data.cursor begin_col, begin_row = self.begin end_col, end_row = self.sheet_data.get_cell_end(self.end) current_col, current_row = CalculateNextCursorXLSX().get_next_cursor( cursor, (begin_col, begin_row), (end_col, end_row), oriented, self) self.sheet_data.last_section.row = (current_col, current_row) self.sheet_data.last_section.column = (ColumnHelper.add( current_col, ColumnHelper.difference( end_col, begin_col)), current_row + end_row - begin_row) self.sheet_data.flush(self.begin, self.end, (current_col, current_row), params, used_formulas)
def cell_dimensions(section, merge_cell, start_cell): """ Получение координаты ячейки после смещения из-за объединения ячеек :param section: начало секции :type section: 2-tuple :param merge_cell: начало объединенной ячейки :type merge_cell: 2-tuple :param start_cell: стартовая ячейка :type start_cell: 2-tuple """ section_begin_col, section_begin_row = section start_col, start_row = start_cell begin_col, begin_row = merge_cell new_begin_row = start_row + begin_row - section_begin_row new_begin_col = ColumnHelper.add(start_col, ColumnHelper.difference(begin_col, section_begin_col)) return new_begin_col + str(new_begin_row)
def _addr_in_range(self, addr, begin, end): u""" Проверяет, попадает ли адрес в диапазон :param addr: адрес ячейки :type addr: 2-tuple :param begin: начальная ячейка диапазона :type begin: 2-tuple :param end: конечная ячейка диапазона :type end: 2-tuple """ col, row = addr rows = xrange(begin[1], end[1] + 1) cols = list(ColumnHelper.get_range(begin[0], end[0])) return all([col in cols, row in rows])
def _get_next_index(self, cell_coord, may_change, diff, is_column): """ Изменяем индекс у столбца(строки) ячейки(в зависимости от флага is_column) may_change - можно ли индекс изменять diff - на сколько нужно изменить индекс """ reg_exp = self.col_re if is_column else self.row_re index = reg_exp.search(cell_coord).group() if may_change: if is_column: index = ColumnHelper.add(index, diff) else: index = str(int(index) + diff) else: index = ''.join(['$', index]) return index
def _set_new_column_width(self, col_index, src_col, dst_col): """ Установка новой ширины колонки Особенность в том, что нужно разбивать интервалы, если потребуется :param col_index: индекс колонки :type col_index: int :param src_col: элемент исходной колонки :type src_col: lxml.etree.Element :param dst_col: элемент выходной колонки :type dst_col: lxml.etree.Element """ col_index = ColumnHelper.column_to_number(col_index) + 1 # если ширина колонок отличается и колонка-приемник является интервалом, # то нужно разбить интервал на части с разной шириной колонок if dst_col.attrib["width"] != src_col.attrib["width"]: begin_col = int(dst_col.attrib['min']) end_col = int(dst_col.attrib['max']) # если задано интервалом, то будем разбивать if end_col - begin_col > 0: if col_index > begin_col: # предыдущий интервал: max = col-1 prev_attrib_col = dict(dst_col.items()) prev_attrib_col['max'] = str(col_index - 1) prev_col_el = SubElement(self.write_cols, 'col', attrib=prev_attrib_col) if col_index < end_col: # следующий интервал: min = col+1 next_attrib_col = dict(dst_col.items()) next_attrib_col["min"] = str(col_index + 1) next_col_el = SubElement(self.write_cols, 'col', attrib=next_attrib_col) # интервал для текущей колонки: min = max = col dst_col.attrib["min"] = str(col_index) dst_col.attrib["max"] = str(col_index) dst_col.attrib["width"] = src_col.attrib["width"]
def _range(self, begin, end): u""" Диапазон строк, колонок :param begin: начальная ячейка :type begin: 2-tuple :param end: конечная ячейка :type end: 2-tuple """ # Если есть объединенная ячейка, и она попадает на конец секции, то адресс конца секции записывается как конец # объединенной ячейки end = self.get_cell_end(end) rows = begin[1], end[1] + 1 cols = begin[0], end[0] range_rows = xrange(*rows) range_cols = list(ColumnHelper.get_range(*cols)) return range_rows, range_cols
def get_next_formula(self, row, column): """ Изменяем формулу и отдаём """ diff_row = row - self._last_row self._last_row = row diff_column = ColumnHelper.difference(column, self._last_column) self._last_column = column if not self.first: formula = self.formula for start, end in self._get_cell_coord(): # Подстрока с адресом ячейки cell_coord = self.formula[start:end] change_column, change_row = self._change_analyze(cell_coord) column_index = self._get_next_index(cell_coord, change_column, diff_column, is_column=True) row_index = self._get_next_index(cell_coord, change_row, diff_row, is_column=False) # Сцепляем индекс колонки и индекс ячейки new_cell_coord = ''.join([column_index, row_index]) # Заменяем подстроку в формуле formula = formula.replace(cell_coord, new_cell_coord) self.formula = formula else: self.first = False return self.formula
def set_section(self, begin, end, start_cell, params, used_formulas=None): u""" Вывод секции :param begin: начальная ячейка секции :type begin: 2-tuple :param end: конечная ячейка секции :type end: 2-tuple :param start_cell: стартовая ячейка (с которой начинается запись) :type start_cell: 2-tuple :param params: параметры отчета :type params: dict :param used_formulas: используемые формулы :type used_formulas: dict """ # TODO: разбить на методы range_rows, range_cols = self._range(begin, end) start_column, start_row = start_cell if used_formulas is None: used_formulas = {} for i, num_row, row in self._find_rows(range_rows): attrib_row = dict(row.items()) row_index = start_row + i attrib_row['r'] = str(row_index) # следующая строка создает линейное время для флаша от числа флашей row_el = self._create_or_get_output_row(row_index, attrib_row) for j, col, cell in self._find_cells(range_cols, num_row, row): attrib_cell = dict(cell.items()) col_index = ColumnHelper.add(start_column, j) attrib_cell['r'] = col_index + str(row_index) cell_el = self._create_or_get_output_cell(row_el, col_index + str(row_index), attrib_cell) # Перенос формул formula = self._get_tag_formula(cell) if formula is not None: formula_el = SubElement(cell_el, 'f') row_cursor_column, row_cursor_row = self.cursor.row column_cursor_column, column_cursor_row = self.cursor.column formula_el.text = Formula.get_instance(formula.text).get_next_formula(row_cursor_row, column_cursor_column) # Если есть формула, то значение является вычисляемым параметром и не сильно интересует continue value = self._get_tag_value(cell) if not value is None: value_el = SubElement(cell_el, 'v') if attrib_cell.get('t') in ('n', None): # number value_el.text = value.text elif attrib_cell.get('t') == 's': # 't' = 's' - значит есть значения shared strings index_value = int(value.text) value_string = self.shared_table.get_value(index_value) who_found_params = self._get_values_by_re(value_string) is_int = False if who_found_params: for found_param in who_found_params: param_name = found_param[1:-1] param_value = params.get(param_name) if used_formulas: formula_id_list = used_formulas.get(param_name) assert ( formula_id_list is None or isinstance( formula_id_list, (list, tuple)) ), ("used_formulas values must be " "lists or tuples") if formula_id_list is not None: for formula_id in formula_id_list: cell_string = ''.join([col_index, str(row_index)]) self.formula_id_dict.setdefault( formula_id, []).append(cell_string) # Находим теги шаблонов, если есть таковые if param_name[0] == self.PREFIX_TAG and param_name[-1] == self.PREFIX_TAG: param_value = self.tags.get(param_name[1:-1]) if isinstance(param_value, datetime) and found_param == value_string: # В OpenXML хранится дата относительно 1900 года days = date_to_float(param_value) if days > 0: # Дата конвертируется в int, начиная с 31.12.1899 is_int = True cell_el.attrib['t'] = 'n' # type - number value_el.text = unicode(days) else: date_less_1900 = '%s.%s.%s' % ( param_value.date().day, param_value.date().month, param_value.date().year ) # strftime(param_value, locale.nl_langinfo(locale.D_FMT)) - неработает для 1900 и ниже value_string = value_string.replace(found_param, unicode(date_less_1900)) # Добавил long, возможно нужно использовать # общего предка numbers.Number elif isinstance( param_value, (int, float, long, Decimal) ) and found_param == value_string: # В первую очередь добавляем числовые значения is_int = True cell_el.attrib['t'] = 'n' # type - number value_el.text = unicode(param_value) elif isinstance(param_value, basestring): # Строковые параметры value_string = value_string.replace(found_param, unicode(param_value)) elif isinstance(param_value, FormulaWriteExcel): # Записываем формулу, которой не было в # шаблоне func_ = param_value.excel_function f_id = param_value.formula_id if f_id and func_: attrib_cell['t'] = 'e' # тип вычислимого по формуле поля cell_el.remove(value_el) # значения в ячейке с формулой нет formula_el = SubElement(cell_el, 'f') row_cursor_column, row_cursor_row = self.cursor.row column_cursor_column, column_cursor_row = self.cursor.column f_cells = self.formula_id_dict.get( f_id, []) if param_value.ranged and f_cells: formula_el.text = '%s(%s)' % ( func_, ':'.join([f_cells[0], f_cells[-1]]) ) elif f_cells: # Группируем по 30 элементов cells_number = int( len(f_cells) / XLSX_GROUPING_COUNT ) + 1 val_list = [] for x in range(cells_number): sub_args = ( ','.join( f_cells[x * XLSX_GROUPING_COUNT:(x + 1) * XLSX_GROUPING_COUNT] ) ) if sub_args: sub_val = '(%s)' % ( sub_args ) val_list.append(sub_val) formula_el.text = '%s(%s)' % ( func_, ','.join(val_list) ) self.formula_id_dict[f_id] = [] else: continue elif param_value: # любой объект, например список или # словарь. Вынесено для производительности value_string = value_string.replace(found_param, unicode(param_value)) else: # Не передано значение параметра value_string = value_string.replace(found_param, '') if not is_int: # Добавим данные в shared strings new_index = self.shared_table.get_new_index(value_string) value_el.text = new_index else: # Параметры в поле не найдены index = self.shared_table.get_new_index(value_string) value_el.text = index elif attrib_cell.get('t'): raise SheetDataException("Unknown value '%s' for tag t" % attrib_cell.get('t'))
def set_section(self, begin, end, start_cell, params, used_formulas=None): u""" Вывод секции :param begin: начальная ячейка секции :type begin: 2-tuple :param end: конечная ячейка секции :type end: 2-tuple :param start_cell: стартовая ячейка (с которой начинается запись) :type start_cell: 2-tuple :param params: параметры отчета :type params: dict :param used_formulas: используемые формулы :type used_formulas: dict """ # TODO: разбить на методы range_rows, range_cols = self._range(begin, end) start_column, start_row = start_cell if used_formulas is None: used_formulas = {} for i, num_row, row in self._find_rows(range_rows): attrib_row = dict(row.items()) row_index = start_row + i attrib_row['r'] = str(row_index) # следующая строка создает линейное время для флаша от числа флашей row_el = self._create_or_get_output_row(row_index, attrib_row) for j, col, cell in self._find_cells(range_cols, num_row, row): attrib_cell = dict(cell.items()) col_index = ColumnHelper.add(start_column, j) attrib_cell['r'] = col_index + str(row_index) cell_el = self._create_or_get_output_cell( row_el, col_index + str(row_index), attrib_cell) # Перенос формул formula = self._get_tag_formula(cell) if formula is not None: formula_el = SubElement(cell_el, 'f') row_cursor_column, row_cursor_row = self.cursor.row column_cursor_column, column_cursor_row = self.cursor.column formula_el.text = Formula.get_instance( formula.text).get_next_formula(row_cursor_row, column_cursor_column) # Если есть формула, то значение является вычисляемым параметром и не сильно интересует continue value = self._get_tag_value(cell) if not value is None: value_el = SubElement(cell_el, 'v') if attrib_cell.get('t') in ('n', None): # number value_el.text = value.text elif attrib_cell.get( 't' ) == 's': # 't' = 's' - значит есть значения shared strings index_value = int(value.text) value_string = self.shared_table.get_value(index_value) who_found_params = self._get_values_by_re(value_string) is_int = False if who_found_params: for found_param in who_found_params: param_name = found_param[1:-1] param_value = params.get(param_name) if used_formulas: formula_id_list = used_formulas.get( param_name) assert (formula_id_list is None or isinstance( formula_id_list, (list, tuple)) ), ("used_formulas values must be " "lists or tuples") if formula_id_list is not None: for formula_id in formula_id_list: cell_string = ''.join( [col_index, str(row_index)]) self.formula_id_dict.setdefault( formula_id, []).append(cell_string) # Находим теги шаблонов, если есть таковые if param_name[ 0] == self.PREFIX_TAG and param_name[ -1] == self.PREFIX_TAG: param_value = self.tags.get( param_name[1:-1]) if isinstance( param_value, datetime ) and found_param == value_string: # В OpenXML хранится дата относительно 1900 года days = date_to_float(param_value) if days > 0: # Дата конвертируется в int, начиная с 31.12.1899 is_int = True cell_el.attrib[ 't'] = 'n' # type - number value_el.text = unicode(days) else: date_less_1900 = '%s.%s.%s' % ( param_value.date().day, param_value.date().month, param_value.date().year) # strftime(param_value, locale.nl_langinfo(locale.D_FMT)) - неработает для 1900 и ниже value_string = value_string.replace( found_param, unicode(date_less_1900)) # Добавил long, возможно нужно использовать # общего предка numbers.Number elif isinstance( param_value, (int, float, long, Decimal)) and found_param == value_string: # В первую очередь добавляем числовые значения is_int = True cell_el.attrib['t'] = 'n' # type - number value_el.text = unicode(param_value) elif isinstance(param_value, basestring): # Строковые параметры value_string = value_string.replace( found_param, unicode(param_value)) elif isinstance(param_value, FormulaWriteExcel): # Записываем формулу, которой не было в # шаблоне func_ = param_value.excel_function f_id = param_value.formula_id if f_id and func_: attrib_cell['t'] = 'e' # тип вычислимого по формуле поля cell_el.remove(value_el) # значения в ячейке с формулой нет formula_el = SubElement(cell_el, 'f') row_cursor_column, row_cursor_row = self.cursor.row column_cursor_column, column_cursor_row = self.cursor.column f_cells = self.formula_id_dict.get( f_id, []) if param_value.ranged and f_cells: formula_el.text = '%s(%s)' % ( func_, ':'.join( [f_cells[0], f_cells[-1]])) elif f_cells: # Группируем по 30 элементов cells_number = int( len(f_cells) / XLSX_GROUPING_COUNT) + 1 val_list = [] for x in range(cells_number): sub_args = (','.join(f_cells[ x * XLSX_GROUPING_COUNT:(x + 1) * XLSX_GROUPING_COUNT])) if sub_args: sub_val = '(%s)' % ( sub_args) val_list.append(sub_val) formula_el.text = '%s(%s)' % ( func_, ','.join(val_list)) self.formula_id_dict[f_id] = [] else: continue elif param_value: # любой объект, например список или # словарь. Вынесено для производительности value_string = value_string.replace( found_param, unicode(param_value)) else: # Не передано значение параметра value_string = value_string.replace( found_param, '') if not is_int: # Добавим данные в shared strings new_index = self.shared_table.get_new_index( value_string) value_el.text = new_index else: # Параметры в поле не найдены index = self.shared_table.get_new_index( value_string) value_el.text = index elif attrib_cell.get('t'): raise SheetDataException( "Unknown value '%s' for tag t" % attrib_cell.get('t'))