Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/chardet/output_names.py: 62%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

24 statements  

1"""Public-API encoding-name remapping. 

2 

3Two output transforms applied to detection results before they cross the 

4public API: 

5 

6* :func:`apply_preferred_superset` -- when the ``prefer_superset`` API option 

7 is enabled, replaces detected ISO/subset encoding names with their 

8 Windows/CP supersets that modern software actually uses 

9 (e.g., ISO-8859-1 -> Windows-1252). 

10 

11* :func:`apply_compat_names` -- when the default ``compat_names=True`` mode 

12 is enabled, maps internal Python codec names to the names chardet 5.x/6.x 

13 returned, preserving backward compatibility for callers that compare 

14 encoding strings directly. 

15 

16Both transforms operate in-place on a :class:`~chardet.pipeline.DetectionDict` 

17and return the same dict for fluent chaining. 

18""" 

19 

20from __future__ import annotations 

21 

22from chardet._utils import decodes_without_error 

23from chardet.pipeline import DetectionDict 

24 

25# Preferred superset name for each encoding, used by the ``prefer_superset`` 

26# API option. When enabled, detected encoding names are replaced with the 

27# Windows/CP superset that modern software actually uses (browsers, editors, 

28# etc. treat these ISO subsets as their Windows counterparts). 

29# Values are lowercase codec names, like the keys: this table only swaps one 

30# codec for another. Display casing ("Windows-1252") is a separate step that 

31# :data:`_COMPAT_NAMES` applies afterwards, and a display-cased value here 

32# would reach it under a name it cannot map and no codec accepts. 

33PREFERRED_SUPERSET: dict[str, str] = { 

34 "ascii": "cp1252", 

35 "euc_kr": "cp949", 

36 "iso8859-1": "cp1252", 

37 "iso8859-2": "cp1250", 

38 "iso8859-5": "cp1251", 

39 "iso8859-6": "cp1256", 

40 "iso8859-7": "cp1253", 

41 "iso8859-8": "cp1255", 

42 "iso8859-9": "cp1254", 

43 "iso8859-11": "cp874", 

44 "iso8859-13": "cp1257", 

45 "tis-620": "cp874", 

46} 

47 

48 

49# Mapping from Python codec names to chardet 5.x/6.x compatible display names. 

50# Only entries where codec name differs from the compat output are listed. 

51# Encodings where codec name == compat name (e.g., "ascii", "utf-8") and 

52# encodings new to v7 have no entry — the codec name passes through unchanged. 

53_COMPAT_NAMES: dict[str, str] = { 

54 # 5.x compat — these encodings existed in chardet 5.x with different names 

55 "big5hkscs": "Big5", 

56 "cp855": "IBM855", 

57 "cp866": "IBM866", 

58 "cp874": "CP874", 

59 "cp932": "CP932", 

60 "cp949": "CP949", 

61 "euc_jis_2004": "EUC-JP", 

62 "euc_kr": "EUC-KR", 

63 "gb18030": "GB18030", 

64 "hz": "HZ-GB-2312", 

65 "iso2022_jp_2": "ISO-2022-JP", 

66 "iso2022_kr": "ISO-2022-KR", 

67 "iso8859-1": "ISO-8859-1", 

68 "iso8859-2": "ISO-8859-2", 

69 "iso8859-5": "ISO-8859-5", 

70 "iso8859-6": "ISO-8859-6", 

71 "iso8859-7": "ISO-8859-7", 

72 "iso8859-8": "ISO-8859-8", 

73 "iso8859-9": "ISO-8859-9", 

74 "iso8859-13": "ISO-8859-13", 

75 "johab": "Johab", 

76 "koi8-r": "KOI8-R", 

77 "mac-cyrillic": "MacCyrillic", 

78 "mac-roman": "MacRoman", 

79 "shift_jis_2004": "SHIFT_JIS", 

80 "tis-620": "TIS-620", 

81 "utf-16": "UTF-16", 

82 "utf-32": "UTF-32", 

83 "utf-8-sig": "UTF-8-SIG", 

84 "cp1250": "Windows-1250", 

85 "cp1251": "Windows-1251", 

86 "cp1252": "Windows-1252", 

87 "cp1253": "Windows-1253", 

88 "cp1254": "Windows-1254", 

89 "cp1255": "Windows-1255", 

90 "cp1256": "Windows-1256", 

91 "cp1257": "Windows-1257", 

92 # 6.x compat — new in chardet 6.x with different names 

93 "kz1048": "KZ1048", 

94 "mac-greek": "MacGreek", 

95 "mac-iceland": "MacIceland", 

96 "mac-latin2": "MacLatin2", 

97 "mac-turkish": "MacTurkish", 

98} 

99 

100 

101def _remap_encoding(result: DetectionDict, mapping: dict[str, str]) -> DetectionDict: 

102 """Replace the encoding name using *mapping*, modifying *result* in-place.""" 

103 enc = result.get("encoding") 

104 if isinstance(enc, str): 

105 result["encoding"] = mapping.get(enc, enc) 

106 return result 

107 

108 

109def apply_preferred_superset( 

110 result: DetectionDict, 

111 data: bytes | None = None, 

112) -> DetectionDict: 

113 """Replace the encoding name with its preferred Windows/CP superset. 

114 

115 Modifies the ``"encoding"`` value in *result* in-place and returns *result* 

116 for fluent chaining. 

117 

118 The Windows code pages leave a few C1 positions undefined that their ISO 

119 subsets map (0x81, 0x8D, 0x8F, 0x90, 0x9D under cp1252), so the remap is 

120 decode-safe only for data that avoids them. When *data* is given, the 

121 remap applies only if the superset decodes it; otherwise the detected 

122 name stands, being the one that does. 

123 

124 :param result: A detection result dict containing an ``"encoding"`` key. 

125 :param data: The bytes *result* was detected from, when known. 

126 :returns: The same *result* dict, modified in-place. 

127 """ 

128 enc = result.get("encoding") 

129 if not isinstance(enc, str): 

130 return result 

131 superset = PREFERRED_SUPERSET.get(enc) 

132 if superset is None: 

133 return result 

134 if data is None or decodes_without_error(data, superset): 

135 result["encoding"] = superset 

136 return result 

137 

138 

139# Deprecated alias — kept for external consumers. 

140apply_legacy_rename = apply_preferred_superset 

141 

142 

143def apply_compat_names( 

144 result: DetectionDict, 

145) -> DetectionDict: 

146 """Convert internal codec names to chardet 5.x/6.x compatible names. 

147 

148 Modifies the ``"encoding"`` value in *result* in-place and returns *result* 

149 for fluent chaining. 

150 

151 :param result: A detection result dict containing an ``"encoding"`` key. 

152 :returns: The same *result* dict, modified in-place. 

153 """ 

154 return _remap_encoding(result, _COMPAT_NAMES)