ver Feb20th
fixed server/main.py fixed several sheetcopilot tasks fixed several calc metrics, including float difference of sheet_data and conditional formatting recognition
This commit is contained in:
@@ -117,7 +117,7 @@ def compare_table(result: str, expected: str = None, **options) -> float:
|
||||
pdworkbooke = None
|
||||
worksheete_names: List[str] = None
|
||||
|
||||
parse_idx: Callable[[Union[str, int], BOOK, BOOK], BOOK] = \
|
||||
parse_idx: Callable[[Union[str, int], BOOK, BOOK], Tuple[BOOK, str]] = \
|
||||
functools.partial(
|
||||
_parse_sheet_idx,
|
||||
result_sheet_names=worksheetr_names,
|
||||
@@ -136,10 +136,15 @@ def compare_table(result: str, expected: str = None, **options) -> float:
|
||||
# Compare Sheet Data by Internal Value {{{ #
|
||||
# sheet_idx0: 0 == "RI0" == "RNSheet1" | "EI0" == "ENSheet1"
|
||||
# sheet_idx1: as sheet_idx0
|
||||
# precision: int as number of decimal digits, default to 4
|
||||
|
||||
sheet1: pd.DataFrame = _load_sheet(*parse_idx(r["sheet_idx0"], pdworkbookr, pdworkbooke))
|
||||
sheet2: pd.DataFrame = _load_sheet(*parse_idx(r["sheet_idx1"], pdworkbookr, pdworkbooke))
|
||||
error_limit: int = r.get("precision", 4)
|
||||
sheet1: pd.DataFrame = _load_sheet(*parse_idx(r["sheet_idx0"], pdworkbookr, pdworkbooke)).round(error_limit)
|
||||
sheet2: pd.DataFrame = _load_sheet(*parse_idx(r["sheet_idx1"], pdworkbookr, pdworkbooke)).round(error_limit)
|
||||
metric: bool = sheet1.equals(sheet2)
|
||||
logger.debug("Sheet1: \n%s", str(sheet1))
|
||||
logger.debug("Sheet2: \n%s", str(sheet2))
|
||||
logger.debug("Sheet1 =v= Sheet2: \n%s", str(sheet1==sheet2))
|
||||
logger.debug("Assertion: %s =v= %s - %s", r["sheet_idx0"], r["sheet_idx1"], metric)
|
||||
# }}} Compare Sheet Data by Internal Value #
|
||||
|
||||
@@ -187,8 +192,13 @@ def compare_table(result: str, expected: str = None, **options) -> float:
|
||||
# sheet_idx1: as sheet_idx0
|
||||
# props: list of str indicating concerned styles, see utils._read_cell_style
|
||||
|
||||
styles1: Dict[str, List[Any]] = load_xlsx_styles(*parse_idx(r["sheet_idx0"], xlworkbookr, xlworkbooke), **r)
|
||||
styles2: Dict[str, List[Any]] = load_xlsx_styles(*parse_idx(r["sheet_idx1"], xlworkbookr, xlworkbooke), **r)
|
||||
sheet_idx1: Tuple[Book, str] = parse_idx(r["sheet_idx0"], xlworkbookr, xlworkbooke)
|
||||
book_name1: str = parse_idx(r["sheet_idx0"], result, expected)[0]
|
||||
styles1: Dict[str, List[Any]] = load_xlsx_styles(*sheet_idx1, book_name1, **r)
|
||||
|
||||
sheet_idx2: Tuple[Book, str] = parse_idx(r["sheet_idx1"], xlworkbookr, xlworkbooke)
|
||||
book_name2: str = parse_idx(r["sheet_idx1"], result, expected)[0]
|
||||
styles2: Dict[str, List[Any]] = load_xlsx_styles(*sheet_idx2, book_name2, **r)
|
||||
# number_formats1: List[str] = [c.number_format.lower() for col in sheet1.iter_cols() for c in col if c.value is not None and c.data_type=="n"]
|
||||
# number_formats2: List[str] = [c.number_format.lower() for col in sheet2.iter_cols() for c in col if c.value is not None and c.data_type=="n"]
|
||||
metric: bool = styles1 == styles2
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import logging
|
||||
import zipfile
|
||||
from typing import Any, TypeVar, Union, Iterable, Optional, Callable
|
||||
from typing import Dict, List, Set, Match, Tuple
|
||||
from typing import Dict, List, Set, Match, Tuple, Pattern
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
import re
|
||||
import functools
|
||||
@@ -18,10 +18,10 @@ from openpyxl import Workbook
|
||||
from openpyxl.chart._chart import ChartBase
|
||||
from openpyxl.worksheet.worksheet import Worksheet
|
||||
from openpyxl.worksheet.filters import AutoFilter, SortState
|
||||
from openpyxl.worksheet.cell_range import MultiCellRange
|
||||
from openpyxl.worksheet.cell_range import MultiCellRange, CellRange
|
||||
from openpyxl.worksheet.dimensions import DimensionHolder
|
||||
from openpyxl.formatting.formatting import ConditionalFormattingList
|
||||
from openpyxl.utils import coordinate_to_tuple
|
||||
from openpyxl.utils import coordinate_to_tuple, get_column_letter
|
||||
from openpyxl.cell.cell import Cell
|
||||
from openpyxl.styles.differential import DifferentialStyle
|
||||
from openpyxl.pivot.table import TableDefinition as PivotTableDefinition
|
||||
@@ -255,7 +255,7 @@ def load_pivot_tables(xlsx_file: Workbook, sheet_name: str, **options) -> Dict[s
|
||||
if "filter" in pivot_props:
|
||||
info["filter_fields"] = set(f.fld for f in pvt.pageFields)
|
||||
if "col_fields" in pivot_props:
|
||||
info["col_fields"] = [f.x for f in pvt.colFields]
|
||||
info["col_fields"] = [f.x-left_bias for f in pvt.colFields]
|
||||
if "row_fields" in pivot_props:
|
||||
info["row_fields"] = [f.x-left_bias for f in pvt.rowFields]
|
||||
if "data_fields" in pivot_props:
|
||||
@@ -347,22 +347,39 @@ def _read_cell_style(style_name: str, cell: Cell, diff_style: Optional[Different
|
||||
elif style_name=="font_size":
|
||||
return (diff_style or cell).font.size if cell.value is not None else None
|
||||
elif style_name=="fill_type":
|
||||
return (diff_style or cell).fill.tagname
|
||||
try:
|
||||
return (diff_style or cell).fill.tagname
|
||||
except:
|
||||
return None
|
||||
elif style_name=="bgcolor":
|
||||
return (diff_style or cell).fill.bgColor.rgb
|
||||
try:
|
||||
return (diff_style or cell).fill.bgColor.rgb
|
||||
except:
|
||||
return None
|
||||
elif style_name=="fgcolor":
|
||||
return (diff_style or cell).fill.fgColor.rgb
|
||||
try:
|
||||
return (diff_style or cell).fill.fgColor.rgb
|
||||
except:
|
||||
return None
|
||||
elif style_name=="hyperlink":
|
||||
return cell.hyperlink or "" if cell.value is not None else None
|
||||
else:
|
||||
raise NotImplementedError("Unsupported Style: {:}".format(style_name))
|
||||
|
||||
def load_xlsx_styles(xlsx_file: Workbook, sheet_name: str, **options) -> Dict[str, List[Any]]:
|
||||
_absolute_range_pattern: Pattern[str] = re.compile( r"""\$(?P<col1>[A-Z]{1,3})\$(?P<row1>\d+) # coord1
|
||||
(?::
|
||||
\$(?P<col2>[A-Z]{1,3})\$(?P<row2>\d+) # coord2
|
||||
)?
|
||||
"""
|
||||
, re.X
|
||||
)
|
||||
def load_xlsx_styles(xlsx_file: Workbook, sheet_name: str, book_name: str, **options) -> Dict[str, List[Any]]:
|
||||
# function load_xlsx_styles {{{ #
|
||||
"""
|
||||
Args:
|
||||
xlsx_file (Workbook): concerned excel book
|
||||
sheet_name (str): sheet name
|
||||
book_name (str): book name
|
||||
options (Dict[str, List[str]): dick like {"props": list of str} giving
|
||||
the concerned styles
|
||||
|
||||
@@ -398,10 +415,35 @@ def load_xlsx_styles(xlsx_file: Workbook, sheet_name: str, **options) -> Dict[st
|
||||
active_cells: List[Cell] = []
|
||||
if r.type == "expression":
|
||||
condition: Callable[[str], bool] = formula_parser.ast("=" + r.formula[0])[1].compile()
|
||||
logger.debug("Expression condition: %s", r.formula[0])
|
||||
|
||||
arguments: List[Any] = []
|
||||
absolute_range_match: List[Tuple[str, str, str, str]] = _absolute_range_pattern.findall(r.formula[0])
|
||||
for m in absolute_range_match:
|
||||
logger.debug("Absolute ranges: %s", repr(m))
|
||||
if m[2] is None and m[3] is None:
|
||||
arguments.append(read_cell_value(book_name, sheet_name, coordinate="{:}{:}".format(m[0], m[1])))
|
||||
else:
|
||||
arguments.append( [ read_cell_value( book_name, sheet_name
|
||||
, coordinate="{:}{:}".format( get_column_letter(c[1])
|
||||
, c[0]
|
||||
)
|
||||
)\
|
||||
for c in CellRange("{:}{:}:{:}{:}".format(m[0], m[1], m[2], m[3])).cells\
|
||||
]
|
||||
)
|
||||
logger.debug("Absolute range arguments: %s", repr(arguments))
|
||||
|
||||
for rge in fmt.cells:
|
||||
for c in rge.cells:
|
||||
cell: Cell = worksheet.cell(row=c[0], column=c[1])
|
||||
if condition(str(cell.value)):
|
||||
cell_value = read_cell_value( book_name, sheet_name
|
||||
, coordinate="{:}{:d}".format( get_column_letter(c[1])
|
||||
, c[0]
|
||||
)
|
||||
)
|
||||
if condition(cell_value, *arguments):
|
||||
logger.debug("Active Cell %s(%s) for %s", repr(cell), str(cell_value), r.formula[0])
|
||||
active_cells.append(cell)
|
||||
else:
|
||||
raise NotImplementedError("Not Implemented Condition Type: {:}".format(r.type))
|
||||
@@ -409,6 +451,7 @@ def load_xlsx_styles(xlsx_file: Workbook, sheet_name: str, **options) -> Dict[st
|
||||
for c in active_cells:
|
||||
style_dict[c.coordinate] = [_read_cell_style(st, c, r.dxf) for st in concerned_styles]
|
||||
|
||||
logger.debug(".[%s].styles: %s", sheet_name, repr(style_dict))
|
||||
return style_dict
|
||||
# }}} function load_xlsx_styles #
|
||||
|
||||
|
||||
@@ -387,12 +387,15 @@ def _create_atspi_node(node: Accessible, depth: int = 0, flag: Optional[str] = N
|
||||
index_base += MAXIMUN_COLUMN
|
||||
return xml_node
|
||||
else:
|
||||
for i, ch in enumerate(node):
|
||||
# HYPERPARAMETER
|
||||
if i>=1025:
|
||||
logger.warning("Max width reached")
|
||||
break
|
||||
xml_node.append(_create_atspi_node(ch, depth+1, flag))
|
||||
try:
|
||||
for i, ch in enumerate(node):
|
||||
# HYPERPARAMETER
|
||||
if i>=1025:
|
||||
logger.warning("Max width reached")
|
||||
break
|
||||
xml_node.append(_create_atspi_node(ch, depth+1, flag))
|
||||
except:
|
||||
logger.warning("Error occurred during children traversing. Has Ignored. Node: %s", lxml.etree.tostring(xml_node, encoding="unicode"))
|
||||
return xml_node
|
||||
# }}} function _create_atspi_node #
|
||||
|
||||
|
||||
Reference in New Issue
Block a user