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"" # 归一化尝试:把常见的 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, '') 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'' print('comment:', comment) try: hyperlink = cell.hyperlink.target if cell.hyperlink else None except Exception as e: hyperlink = f'' 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')