Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
gh-141510: Use frozendict in the stdlib
Co-authored-by: Donghee Na <donghee.na@python.org>
  • Loading branch information
vstinner and corona10 committed Feb 17, 2026
commit 300cf8f0bbf45b8919e9a450719d1d89a8b231dc
4 changes: 2 additions & 2 deletions Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def _lt_from_ge(self, other):
return op_result
return not op_result

_convert = {
_convert = frozendict({
'__lt__': [('__gt__', _gt_from_lt),
('__le__', _le_from_lt),
('__ge__', _ge_from_lt)],
Expand All @@ -183,7 +183,7 @@ def _lt_from_ge(self, other):
'__ge__': [('__le__', _le_from_ge),
('__gt__', _gt_from_ge),
('__lt__', _lt_from_ge)]
}
})

def total_ordering(cls):
"""Class decorator that fills in missing ordering methods"""
Expand Down
5 changes: 3 additions & 2 deletions Lib/gettext.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ def _error(value):
('+', '-'),
('*', '/', '%'),
)
_binary_ops = {op: i for i, ops in enumerate(_binary_ops, 1) for op in ops}
_c2py_ops = {'||': 'or', '&&': 'and', '/': '//'}
_binary_ops = frozendict({op: i for i, ops in enumerate(_binary_ops, 1)
for op in ops})
_c2py_ops = frozendict({'||': 'or', '&&': 'and', '/': '//'})


def _parse(tokens, priority=-1):
Expand Down
4 changes: 2 additions & 2 deletions Lib/json/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ def __reduce__(self):
return self.__class__, (self.msg, self.doc, self.pos)


_CONSTANTS = {
_CONSTANTS = frozendict({
'-Infinity': NegInf,
'Infinity': PosInf,
'NaN': NaN,
}
})


HEXDIGITS = re.compile(r'[0-9A-Fa-f]{4}', FLAGS)
Expand Down
4 changes: 2 additions & 2 deletions Lib/json/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
(?P<null>null)
''', re.VERBOSE)

_group_to_theme_color = {
_group_to_theme_color = frozendict({
"key": "definition",
"string": "string",
"number": "number",
"boolean": "keyword",
"null": "keyword",
}
})


def _colorize_json(json_str, theme):
Expand Down
48 changes: 24 additions & 24 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,81 +46,81 @@

hascompare = [opmap["COMPARE_OP"]]

_cache_format = {
"LOAD_GLOBAL": {
_cache_format = frozendict(
LOAD_GLOBAL={

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values of LOAD_GLOBAL can also be a frozendict (that is, we can have nested frozendicts).

"counter": 1,
"index": 1,
"module_keys_version": 1,
"builtin_keys_version": 1,
},
"BINARY_OP": {
BINARY_OP={
"counter": 1,
"descr": 4,
},
"UNPACK_SEQUENCE": {
UNPACK_SEQUENCE={
"counter": 1,
},
"COMPARE_OP": {
COMPARE_OP={
"counter": 1,
},
"CONTAINS_OP": {
CONTAINS_OP={
"counter": 1,
},
"FOR_ITER": {
FOR_ITER={
"counter": 1,
},
"LOAD_SUPER_ATTR": {
LOAD_SUPER_ATTR={
"counter": 1,
},
"LOAD_ATTR": {
LOAD_ATTR={
"counter": 1,
"version": 2,
"keys_version": 2,
"descr": 4,
},
"STORE_ATTR": {
STORE_ATTR={
"counter": 1,
"version": 2,
"index": 1,
},
"CALL": {
CALL={
"counter": 1,
"func_version": 2,
},
"CALL_KW": {
CALL_KW={
"counter": 1,
"func_version": 2,
},
"CALL_FUNCTION_EX": {
CALL_FUNCTION_EX={
"counter": 1,
},
"STORE_SUBSCR": {
STORE_SUBSCR={
"counter": 1,
},
"SEND": {
SEND={
"counter": 1,
},
"JUMP_BACKWARD": {
JUMP_BACKWARD={
"counter": 1,
},
"TO_BOOL": {
TO_BOOL={
"counter": 1,
"version": 2,
},
"POP_JUMP_IF_TRUE": {
POP_JUMP_IF_TRUE={
"counter": 1,
},
"POP_JUMP_IF_FALSE": {
POP_JUMP_IF_FALSE={
"counter": 1,
},
"POP_JUMP_IF_NONE": {
POP_JUMP_IF_NONE={
"counter": 1,
},
"POP_JUMP_IF_NOT_NONE": {
POP_JUMP_IF_NOT_NONE={
"counter": 1,
},
}
)

_inline_cache_entries = {
_inline_cache_entries = frozendict({
name : sum(value.values()) for (name, value) in _cache_format.items()
}
})
10 changes: 6 additions & 4 deletions Lib/optparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,10 +407,12 @@ def _parse_num(val, type):
def _parse_int(val):
return _parse_num(val, int)

_builtin_cvt = { "int" : (_parse_int, _("integer")),
"long" : (_parse_int, _("integer")),
"float" : (float, _("floating-point")),
"complex" : (complex, _("complex")) }
_builtin_cvt = frozendict({
"int": (_parse_int, _("integer")),
"long": (_parse_int, _("integer")),
"float": (float, _("floating-point")),
"complex": (complex, _("complex")),
})

def check_builtin(option, opt, value):
(cvt, what) = _builtin_cvt[option.type]
Expand Down
8 changes: 4 additions & 4 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
# Based on the description of the PHP's version_compare():
# http://php.net/manual/en/function.version-compare.php

_ver_stages = {
_ver_stages = frozendict({
# any string not found in this dict, will get 0 assigned
'dev': 10,
'alpha': 20, 'a': 20,
Expand All @@ -136,7 +136,7 @@
'RC': 50, 'rc': 50,
# number, will get 100 assigned
'pl': 200, 'p': 200,
}
})


def _comparable_version(version):
Expand Down Expand Up @@ -705,11 +705,11 @@ def _syscmd_file(target, default=''):

# Default values for architecture; non-empty strings override the
# defaults given as parameters
_default_architecture = {
_default_architecture = frozendict({
'win32': ('', 'WindowsPE'),
'win16': ('', 'Windows'),
'dos': ('', 'MSDOS'),
}
})

def architecture(executable=sys.executable, bits='', linkage=''):

Expand Down
2 changes: 1 addition & 1 deletion Lib/plistlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ class InvalidFileException (ValueError):
def __init__(self, message="Invalid file"):
ValueError.__init__(self, message)

_BINARY_FORMAT = {1: 'B', 2: 'H', 4: 'L', 8: 'Q'}
_BINARY_FORMAT = frozendict({1: 'B', 2: 'H', 4: 'L', 8: 'Q'})

_undefined = object()

Expand Down
3 changes: 2 additions & 1 deletion Lib/ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@
source=_ssl)

PROTOCOL_SSLv23 = _SSLMethod.PROTOCOL_SSLv23 = _SSLMethod.PROTOCOL_TLS
_PROTOCOL_NAMES = {value: name for name, value in _SSLMethod.__members__.items()}
_PROTOCOL_NAMES = frozendict({
value: name for name, value in _SSLMethod.__members__.items()})

_SSLv2_IF_EXISTS = getattr(_SSLMethod, 'PROTOCOL_SSLv2', None)

Expand Down
4 changes: 2 additions & 2 deletions Lib/stringprep.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def in_table_b1(code):
return ord(code) in b1_set


b3_exceptions = {
b3_exceptions = frozendict({
0xb5:'\u03bc', 0xdf:'ss', 0x130:'i\u0307', 0x149:'\u02bcn',
0x17f:'s', 0x1f0:'j\u030c', 0x345:'\u03b9', 0x37a:' \u03b9',
0x390:'\u03b9\u0308\u0301', 0x3b0:'\u03c5\u0308\u0301', 0x3c2:'\u03c3', 0x3d0:'\u03b2',
Expand Down Expand Up @@ -184,7 +184,7 @@ def in_table_b1(code):
0x1d79c:'\u03bd', 0x1d79d:'\u03be', 0x1d79e:'\u03bf', 0x1d79f:'\u03c0',
0x1d7a0:'\u03c1', 0x1d7a1:'\u03b8', 0x1d7a2:'\u03c3', 0x1d7a3:'\u03c4',
0x1d7a4:'\u03c5', 0x1d7a5:'\u03c6', 0x1d7a6:'\u03c7', 0x1d7a7:'\u03c8',
0x1d7a8:'\u03c9', 0x1d7bb:'\u03c3', }
0x1d7a8:'\u03c9', 0x1d7bb:'\u03c3', })

def map_table_b3(code):
r = b3_exceptions.get(ord(code))
Expand Down
2 changes: 1 addition & 1 deletion Lib/symtable.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ def get_namespace(self):
_flags = [('USE', USE)]
_flags.extend(kv for kv in globals().items() if kv[0].startswith('DEF_'))
_scopes_names = ('FREE', 'LOCAL', 'GLOBAL_IMPLICIT', 'GLOBAL_EXPLICIT', 'CELL')
_scopes_value_to_name = {globals()[n]: n for n in _scopes_names}
_scopes_value_to_name = frozendict({globals()[n]: n for n in _scopes_names})


def main(args):
Expand Down
4 changes: 2 additions & 2 deletions Lib/tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -860,11 +860,11 @@ def data_filter(member, dest_path):
return member.replace(**new_attrs, deep=False)
return member

_NAMED_FILTERS = {
_NAMED_FILTERS = frozendict({
"fully_trusted": fully_trusted_filter,
"tar": tar_filter,
"data": data_filter,
}
})

#------------------
# Exported Classes
Expand Down
4 changes: 2 additions & 2 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1916,7 +1916,7 @@ def _allow_reckless_class_checks(depth=2):
return _caller(depth) in {'abc', '_py_abc', 'functools', None}


_PROTO_ALLOWLIST = {
_PROTO_ALLOWLIST = frozendict({
Comment thread
vstinner marked this conversation as resolved.
Outdated
'collections.abc': [
'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable',
'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection',
Expand All @@ -1925,7 +1925,7 @@ def _allow_reckless_class_checks(depth=2):
'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'],
'io': ['Reader', 'Writer'],
'os': ['PathLike'],
}
})


@functools.cache
Expand Down
Loading