Skip to content

Commit a2f8d2d

Browse files
committed
Temporarily fix openpyxl read_worksheets issue
1 parent ba951fa commit a2f8d2d

6 files changed

Lines changed: 130 additions & 1 deletion

File tree

Orange/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# This module is a mixture of imports and code, so we allow import anywhere
22
# pylint: disable=wrong-import-position,wrong-import-order
3-
43
from Orange import data
54

65
from .misc.lazy_module import _LazyModule

Orange/data/io.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@
2828
from Orange.data import Compression, open_compressed, detect_encoding, \
2929
isnastr, guess_data_type, sanitize_variable
3030
from Orange.data.io_base import FileFormatBase, Flags, DataTableMixin, PICKLE_PROTOCOL
31+
from Orange.misc.openpyxl_patch import read_worksheets
3132

3233
from Orange.util import flatten
3334

3435

36+
# temporary fix for file not closed issue until openpyxl prepare release
37+
openpyxl.reader.excel.ExcelReader.read_worksheets = read_worksheets
38+
39+
3540
# Support values longer than 128K (i.e. text contents features)
3641
csv.field_size_limit(100*1024*1024)
3742

Orange/misc/_distmatrix_xlsx.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import numpy as np
22
import openpyxl
33

4+
from Orange.misc.openpyxl_patch import read_worksheets
5+
6+
7+
# temporary fix for file not closed issue until openpyxl prepare release
8+
openpyxl.reader.excel.ExcelReader.read_worksheets = read_worksheets
9+
410

511
def read_matrix(filename, sheet_name=None):
612
sheet = _get_sheet(filename, sheet_name)

Orange/misc/openpyxl_patch.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import warnings
2+
3+
from openpyxl.cell import MergedCell
4+
from openpyxl.comments.comment_sheet import CommentSheet
5+
from openpyxl.drawing.spreadsheet_drawing import SpreadsheetDrawing
6+
from openpyxl.packaging.relationship import (
7+
get_rels_path,
8+
RelationshipList,
9+
get_dependents,
10+
)
11+
from openpyxl.pivot.table import TableDefinition
12+
from openpyxl.reader.drawings import find_images
13+
from openpyxl.worksheet._read_only import ReadOnlyWorksheet
14+
from openpyxl.worksheet._reader import WorksheetReader
15+
from openpyxl.xml.constants import COMMENTS_NS
16+
from openpyxl.xml.functions import fromstring
17+
from openpyxl.worksheet.table import Table
18+
19+
20+
# temporary fix for file not closed issue until openpyxl prepare release
21+
# https://foss.heptapod.net/openpyxl/openpyxl/-/merge_requests/
22+
# 436#7922bd5f66e11e4ca4539f093b2680a25c1f80db
23+
def read_worksheets(self):
24+
# pylint: disable=too-many-branches
25+
comment_warning = (
26+
"Cell '{0}':{1} is part of a merged range but has a comment which will "
27+
"be removed because merged cells cannot contain any data."
28+
)
29+
for sheet, rel in self.parser.find_sheets():
30+
if rel.target not in self.valid_files:
31+
continue
32+
33+
if "chartsheet" in rel.Type:
34+
self.read_chartsheet(sheet, rel)
35+
continue
36+
37+
rels_path = get_rels_path(rel.target)
38+
rels = RelationshipList()
39+
if rels_path in self.valid_files:
40+
rels = get_dependents(self.archive, rels_path)
41+
42+
if self.read_only:
43+
ws = ReadOnlyWorksheet(self.wb, sheet.name, rel.target, self.shared_strings)
44+
ws.sheet_state = sheet.state
45+
self.wb._sheets.append(ws) # pylint: disable=protected-access
46+
continue
47+
fh = self.archive.open(rel.target)
48+
ws = self.wb.create_sheet(sheet.name)
49+
ws._rels = rels # pylint: disable=protected-access
50+
ws_parser = WorksheetReader(
51+
ws, fh, self.shared_strings, self.data_only, self.rich_text
52+
)
53+
ws_parser.bind_all()
54+
fh.close()
55+
56+
# assign any comments to cells
57+
for r in rels.find(COMMENTS_NS):
58+
src = self.archive.read(r.target)
59+
comment_sheet = CommentSheet.from_tree(fromstring(src))
60+
for ref, comment in comment_sheet.comments:
61+
try:
62+
ws[ref].comment = comment
63+
except AttributeError:
64+
c = ws[ref]
65+
if isinstance(c, MergedCell):
66+
warnings.warn(comment_warning.format(ws.title, c.coordinate))
67+
continue
68+
69+
# preserve link to VML file if VBA
70+
if self.wb.vba_archive and ws.legacy_drawing:
71+
ws.legacy_drawing = rels.get(ws.legacy_drawing).target
72+
else:
73+
ws.legacy_drawing = None
74+
75+
for t in ws_parser.tables:
76+
src = self.archive.read(t)
77+
xml = fromstring(src)
78+
table = Table.from_tree(xml)
79+
ws.add_table(table)
80+
81+
#pylint: disable=protected-access
82+
drawings = rels.find(SpreadsheetDrawing._rel_type)
83+
for rel in drawings:
84+
charts, images = find_images(self.archive, rel.target)
85+
for c in charts:
86+
ws.add_chart(c, c.anchor)
87+
for im in images:
88+
ws.add_image(im, im.anchor)
89+
90+
pivot_rel = rels.find(TableDefinition.rel_type)
91+
pivot_caches = self.parser.pivot_caches
92+
for r in pivot_rel:
93+
pivot_path = r.Target
94+
src = self.archive.read(pivot_path)
95+
tree = fromstring(src)
96+
pivot = TableDefinition.from_tree(tree)
97+
pivot.cache = pivot_caches[pivot.cacheId]
98+
ws.add_pivot(pivot)
99+
100+
ws.sheet_state = sheet.state
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import unittest
2+
3+
import openpyxl
4+
5+
6+
class TestRemoveTemporarySolution(unittest.TestCase):
7+
def test_remove_openpyxl_temp_solution(self):
8+
"""
9+
When this test starts to fail revert https://github.com/biolab/orange3/pull/6737
10+
"""
11+
self.assertLessEqual(
12+
[int(x) for x in openpyxl.__version__.split(".")], [3, 1, 2]
13+
)
14+
15+
16+
if __name__ == "__main__":
17+
unittest.main()

Orange/tests/test_base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import unittest
55
from distutils.version import LooseVersion
66

7+
import openpyxl
8+
79
import Orange
810

911
from Orange.base import SklLearner, Learner, Model

0 commit comments

Comments
 (0)