前言
openpyxl 在 3.1.0 之后版本引入了一个新的 bug,具体问题可以参考 issue-1959。一旦你使用的 Excel 文件中的通配符(wildcard) 不存在数字的话,就会如下的错误:
File "/usr/local/lib/python3.8/site-packages/openpyxl/worksheet/filters.py", line 165, in __set__
raise ValueError("Value must be either numerical or a string containing a wildcard")
ValueError: Value must be either numerical or a string containing a wildcard
造成影响的关键代码如下:
# https://foss.heptapod.net/openpyxl/openpyxl/-/blob/branch/3.1/openpyxl/worksheet/filters.py
class CustomFilterValueDescriptor(Convertible):
"""
Excel uses wildcards for string matching
"""
pattern = re.compile(r"\d+|^\*.+|^.+\*$")
expected_type = float
def __set__(self, instance, value):
if isinstance(value, str):
m = self.pattern.match(value)
if not m:
raise ValueError("Value must be either numerical or a string containing a wildcard")
if "*" in value:
self.expected_type = str
super().__set__(instance, value)
其中的 pattern
表达式存在问题。
解决办法
方法一 将 openpyxl 的版本回到到 3.0.10 即可解决
在这个版本之前没有引入 CustomFilterValueDescriptor
,对通配符没有做任何校验。
方法二 Monkey patch
使用猴子补丁,重载 CustomFilterValueDescriptor
这个类方法,然后等待官方升级解决问题。
from openpyxl.worksheet.filters import CustomFilterValueDescriptor
def monkey_set(self,instance,value):
pass
CustomFilterValueDescriptor.__set__ = monkey_set