first commint

This commit is contained in:
suqin
2025-12-06 17:48:48 +08:00
commit 37f211ffc6
14 changed files with 5122 additions and 0 deletions

305
inspect_cells.py Normal file
View File

@@ -0,0 +1,305 @@
import openpyxl
import sys
try:
from openpyxl.styles.colors import COLOR_INDEX
except Exception:
COLOR_INDEX = []
FILE = 'global.xlsx'
SHEET = 'Sheet1'
CELLS = ['P547', 'X458']
try:
wb = openpyxl.load_workbook(FILE, data_only=False)
except Exception as e:
print(f"Failed to open {FILE}: {e}")
sys.exit(1)
if SHEET in wb.sheetnames:
ws = wb[SHEET]
else:
print(f"Sheet '{SHEET}' not found. Available sheets: {wb.sheetnames}. Using active sheet '{wb.active.title}'.")
ws = wb.active
def color_info(c):
if c is None:
return None
info = {}
for attr in ('type','rgb','indexed','index','theme','tint','auto'):
try:
info[attr] = getattr(c, attr, None)
except Exception as e:
info[attr] = f"<error: {e}>"
# 归一化尝试:把常见的 tuple/list/int/bytes 等 rgb 表示转换为可读字符串
info['normalized'], info['original_repr'] = normalize_color_value(c)
try:
kind, value = safe_resolve_color(c)
info['resolved'] = {'kind': kind, 'value': value}
except Exception as e:
info['resolved'] = {'error': str(e)}
return info
def normalize_color_value(val):
"""
尝试把颜色对象或多种表示归一化为一个字符串(优先 ARGB hex并返回 (normalized_str_or_None, original_repr).
支持:
- openpyxl Color 对象 (会尝试读取 .rgb/.indexed/.index/.theme/.tint)
- str (如 'FF00B050', '#FF00B050', 'rgb(0,176,80)')
- tuple/list of ints (r,g,b) 或 (r,g,b,a)
- int (如 16711680)
- bytes
任何不能解析的值将返回 (None, repr(val)).
"""
import logging
logger = logging.getLogger(__name__)
def as_argb_from_rgb_tuple(tpl):
try:
comps = list(tpl)
if len(comps) == 3:
r, g, b = comps
a = 255
elif len(comps) >= 4:
r, g, b, a = comps[:4]
else:
return None
return "{0:02X}{1:02X}{2:02X}{3:02X}".format(a, r, g, b)
except Exception as e:
logger.debug(f"as_argb_from_rgb_tuple failed: {e} for {tpl}")
return None
# If it's an openpyxl Color-like object, try attributes first
try:
# guard: if object has .rgb/.indexed etc, prefer those
if hasattr(val, 'rgb') or hasattr(val, 'indexed') or hasattr(val, 'index') or hasattr(val, 'theme'):
# try .rgb
try:
rgb = getattr(val, 'rgb', None)
if rgb:
s = str(rgb)
# strip leading '#' if present
if s.startswith('#'):
s = s[1:]
if len(s) == 6:
s = 'FF' + s
return (s.upper(), repr(rgb))
except Exception as e:
logger.debug(f"error reading .rgb: {e}")
# try indexed/index mapping (best-effort)
try:
idx = getattr(val, 'indexed', None) or getattr(val, 'index', None)
if idx is not None:
try:
idx_int = int(idx)
# map using openpyxl COLOR_INDEX if available
if COLOR_INDEX and 0 <= idx_int < len(COLOR_INDEX):
hexv = COLOR_INDEX[idx_int]
if hexv:
hexs = hexv.upper()
if len(hexs) == 6:
hexs = 'FF' + hexs
return (hexs, repr(idx_int))
return (f'INDEXED_{idx_int}', repr(idx_int))
except Exception:
return (f'INDEXED_{idx}', repr(idx))
except Exception as e:
logger.debug(f"error reading .indexed/index: {e}")
# theme
try:
theme = getattr(val, 'theme', None)
if theme is not None:
return (f'THEME_{theme}', repr(theme))
except Exception as e:
logger.debug(f"error reading .theme: {e}")
except Exception:
# not an object we can introspect
pass
# Primitive types
# str
try:
if isinstance(val, str):
s = val.strip()
if s.startswith('#'):
s = s[1:]
# If it contains 'rgb(' leave as-is
if s.lower().startswith('rgb('):
return (s, repr(val))
# if hex-like
hexchars = ''.join(ch for ch in s if ch.isalnum())
if all(c in '0123456789ABCDEFabcdef' for c in hexchars) and len(hexchars) in (6,8):
if len(hexchars) == 6:
hexchars = 'FF' + hexchars
return (hexchars.upper(), repr(val))
except Exception as e:
logger.debug(f"error normalizing str val: {e}")
# tuple/list
try:
if isinstance(val, (tuple, list)):
# might be like (r,g,b) or (r,g,b,a)
normalized = as_argb_from_rgb_tuple(val)
if normalized:
return (normalized, repr(val))
except Exception as e:
logger.debug(f"error normalizing sequence val: {e}")
# int (maybe packed RGB)
try:
if isinstance(val, int):
v = val & 0xFFFFFFFF
# If it's 24-bit or 32-bit
if v <= 0xFFFFFF:
# assume RGB
r = (v >> 16) & 0xFF
g = (v >> 8) & 0xFF
b = v & 0xFF
a = 255
else:
a = (v >> 24) & 0xFF
r = (v >> 16) & 0xFF
g = (v >> 8) & 0xFF
b = v & 0xFF
return ("{0:02X}{1:02X}{2:02X}{3:02X}".format(a, r, g, b), repr(val))
except Exception as e:
logger.debug(f"error normalizing int val: {e}")
# bytes
try:
if isinstance(val, (bytes, bytearray)):
hexs = val.hex().upper()
if len(hexs) == 6:
hexs = 'FF' + hexs
return (hexs, repr(val))
except Exception as e:
logger.debug(f"error normalizing bytes val: {e}")
# fallback: try to stringify, but filter out known library error messages
try:
r = repr(val)
if 'MUST BE OF TYPE' in r.upper() or 'VALUES MUST' in r.upper():
return (None, r)
return (r, r)
except Exception:
return (None, '<unrepresentable>')
from openpyxl.styles import colors as _colors
def safe_resolve_color(fg):
# 返回 (kind, value)
# - ('argb', 'FF00B050') 或 ('indexed', 35) 或 ('theme', 2) 或 (None, None)
try:
if fg is None:
return (None, None)
except Exception:
return (None, None)
# 1) rgb 字符串
try:
rgb = getattr(fg, 'rgb', None)
if rgb:
s = str(rgb)
if s.startswith('#'):
s = s[1:]
if len(s) == 6:
s = 'FF' + s
return ('argb', s.upper())
except Exception:
# 读取 rgb 可能抛异常,记录并继续回退
pass
# 2) indexed / index -> 尝试映射到 hex
try:
idx = getattr(fg, 'indexed', None) or getattr(fg, 'index', None)
if idx is not None:
try:
idx_int = int(idx)
# COLOR_INDEX 是 openpyxl 内置的索引颜色表
hexv = None
try:
hexv = _colors.COLOR_INDEX[idx_int] # e.g. '00FF00'
except Exception:
hexv = None
if hexv:
hexs = hexv.upper()
if len(hexs) == 6:
hexs = 'FF' + hexs
return ('argb', hexs)
else:
return ('indexed', idx_int)
except Exception:
return ('indexed', idx)
except Exception:
pass
# 3) theme
try:
theme = getattr(fg, 'theme', None)
if theme is not None:
return ('theme', theme)
except Exception:
pass
return (None, None)
for coord in CELLS:
print(f"--- {coord} ---")
cell = ws[coord]
print('coordinate:', cell.coordinate)
print('row, column:', cell.row, cell.column)
print('value repr:', repr(cell.value))
print('data_type:', getattr(cell, 'data_type', None))
print('is_date:', getattr(cell, 'is_date', None))
print('number_format:', getattr(cell, 'number_format', None))
print('font:', cell.font)
try:
font_attrs = { 'name': cell.font.name, 'size': cell.font.sz, 'bold': cell.font.bold, 'italic': cell.font.italic, 'color': getattr(cell.font, 'color', None) }
except Exception as e:
font_attrs = {'error': str(e)}
print('font attributes:', font_attrs)
fill = getattr(cell, 'fill', None)
print('fill obj:', type(fill))
if fill is not None:
try:
print(' patternType:', getattr(fill, 'patternType', None))
except Exception as e:
print(' patternType error:', e)
fg = getattr(fill, 'fgColor', None)
bg = getattr(fill, 'bgColor', None)
print(' fgColor:', color_info(fg))
print(' bgColor:', color_info(bg))
fg_kind, fg_value = safe_resolve_color(fg)
bg_kind, bg_value = safe_resolve_color(bg)
print(' fgColor resolved:', {'kind': fg_kind, 'value': fg_value})
print(' bgColor resolved:', {'kind': bg_kind, 'value': bg_value})
else:
print(' fill is None')
print('alignment:', cell.alignment)
print('border:', cell.border)
print('protection:', cell.protection)
try:
comment = cell.comment.text if cell.comment else None
except Exception as e:
comment = f'<error reading comment: {e}>'
print('comment:', comment)
try:
hyperlink = cell.hyperlink.target if cell.hyperlink else None
except Exception as e:
hyperlink = f'<error reading hyperlink: {e}>'
print('hyperlink:', hyperlink)
# raw repr of the cell object's __dict__ if available
try:
d = {k: repr(v) for k,v in cell.__dict__.items()}
print('cell.__dict__ keys:', list(cell.__dict__.keys()))
except Exception:
d = None
# don't print full dict to avoid huge output, but show if present
print()
print('Done')