gh-94673: [c-analyzer] Add a Script to Identify Static Types (#94989)

issue: https://github.com/python/cpython/issues/94673
This commit is contained in:
Eric Snow 2022-07-18 19:03:57 -06:00 committed by GitHub
parent 0daba82221
commit 7a1a85d640
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 613 additions and 151 deletions

View file

@ -600,17 +600,9 @@ StopIteration_traverse(PyStopIterationObject *self, visitproc visit, void *arg)
return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg);
}
ComplexExtendsException(
PyExc_Exception, /* base */
StopIteration, /* name */
StopIteration, /* prefix for *_init, etc */
0, /* new */
0, /* methods */
StopIteration_members, /* members */
0, /* getset */
0, /* str */
"Signal the end from iterator.__next__()."
);
ComplexExtendsException(PyExc_Exception, StopIteration, StopIteration,
0, 0, StopIteration_members, 0, 0,
"Signal the end from iterator.__next__().");
/*

View file

@ -1,3 +1,4 @@
from collections import namedtuple
import csv
import re
import textwrap
@ -225,7 +226,11 @@ WIDTH = 20
def resolve_columns(specs):
if isinstance(specs, str):
specs = specs.replace(',', ' ').strip().split()
return _resolve_colspecs(specs)
resolved = []
for raw in specs:
column = ColumnSpec.from_raw(raw)
resolved.append(column)
return resolved
def build_table(specs, *, sep=' ', defaultwidth=None):
@ -233,37 +238,145 @@ def build_table(specs, *, sep=' ', defaultwidth=None):
return _build_table(columns, sep=sep, defaultwidth=defaultwidth)
_COLSPEC_RE = re.compile(textwrap.dedent(r'''
^
(?:
\[
(
(?: [^\s\]] [^\]]* )?
[^\s\]]
) # <label>
]
)?
( \w+ ) # <field>
(?:
class ColumnSpec(namedtuple('ColumnSpec', 'field label fmt')):
REGEX = re.compile(textwrap.dedent(r'''
^
(?:
:
( [<^>] ) # <align>
( \d+ ) # <width1>
)
|
\[
(
(?: [^\s\]] [^\]]* )?
[^\s\]]
) # <label>
]
)?
( [-\w]+ ) # <field>
(?:
(?:
:
( \d+ ) # <width2>
)?
( [<^>] ) # <align>
( \d+ )? # <width1>
)
|
(?:
:
( .*? ) # <fmt>
)?
)
)?
$
'''), re.VERBOSE)
(?:
:
( \d+ ) # <width2>
)?
(?:
:
( .*? ) # <fmt>
)?
)
)?
$
'''), re.VERBOSE)
@classmethod
def from_raw(cls, raw):
if not raw:
raise ValueError('missing column spec')
elif isinstance(raw, cls):
return raw
if isinstance(raw, str):
*values, _ = cls._parse(raw)
else:
*values, _ = cls._normalize(raw)
if values is None:
raise ValueError(f'unsupported column spec {raw!r}')
return cls(*values)
@classmethod
def parse(cls, specstr):
parsed = cls._parse(specstr)
if not parsed:
return None
*values, _ = parsed
return cls(*values)
@classmethod
def _parse(cls, specstr):
m = cls.REGEX.match(specstr)
if not m:
return None
(label, field,
align, width1,
width2, fmt,
) = m.groups()
if not label:
label = field
if fmt:
assert not align and not width1, (specstr,)
_parsed = _parse_fmt(fmt)
if not _parsed:
raise NotImplementedError
elif width2:
width, _ = _parsed
if width != int(width2):
raise NotImplementedError(specstr)
elif width2:
fmt = width2
width = int(width2)
else:
assert not fmt, (fmt, specstr)
if align:
width = int(width1) if width1 else len(label)
fmt = f'{align}{width}'
else:
width = None
return field, label, fmt, width
@classmethod
def _normalize(cls, spec):
if len(spec) == 1:
raw, = spec
raise NotImplementedError
return _resolve_column(raw)
if len(spec) == 4:
label, field, width, fmt = spec
if width:
if not fmt:
fmt = str(width)
elif _parse_fmt(fmt)[0] != width:
raise ValueError(f'width mismatch in {spec}')
elif len(raw) == 3:
label, field, fmt = spec
if not field:
label, field = None, label
elif not isinstance(field, str) or not field.isidentifier():
# XXX This doesn't seem right...
fmt = f'{field}:{fmt}' if fmt else field
label, field = None, label
elif len(raw) == 2:
label = None
field, fmt = raw
if not field:
field, fmt = fmt, None
elif not field.isidentifier() or fmt.isidentifier():
label, field = field, fmt
else:
raise NotImplementedError
fmt = f':{fmt}' if fmt else ''
if label:
return cls._parse(f'[{label}]{field}{fmt}')
else:
return cls._parse(f'{field}{fmt}')
@property
def width(self):
if not self.fmt:
return None
parsed = _parse_fmt(self.fmt)
if not parsed:
return None
width, _ = parsed
return width
def resolve_width(self, default=None):
return _resolve_width(self.width, self.fmt, self.label, default)
def _parse_fmt(fmt):
@ -272,100 +385,31 @@ def _parse_fmt(fmt):
width = fmt[1:]
if width.isdigit():
return int(width), align
return None, None
elif fmt.isdigit():
return int(fmt), '<'
return None
def _parse_colspec(raw):
m = _COLSPEC_RE.match(raw)
if not m:
return None
label, field, align, width1, width2, fmt = m.groups()
if not label:
label = field
if width1:
width = None
fmt = f'{align}{width1}'
elif width2:
width = int(width2)
if fmt:
_width, _ = _parse_fmt(fmt)
if _width == width:
width = None
else:
width = None
return field, label, width, fmt
def _normalize_colspec(spec):
if len(spec) == 1:
raw, = spec
return _resolve_column(raw)
if len(spec) == 4:
label, field, width, fmt = spec
if width:
fmt = f'{width}:{fmt}' if fmt else width
elif len(raw) == 3:
label, field, fmt = spec
if not field:
label, field = None, label
elif not isinstance(field, str) or not field.isidentifier():
fmt = f'{field}:{fmt}' if fmt else field
label, field = None, label
elif len(raw) == 2:
label = None
field, fmt = raw
if not field:
field, fmt = fmt, None
elif not field.isidentifier() or fmt.isidentifier():
label, field = field, fmt
else:
raise NotImplementedError
fmt = f':{fmt}' if fmt else ''
if label:
return _parse_colspec(f'[{label}]{field}{fmt}')
else:
return _parse_colspec(f'{field}{fmt}')
def _resolve_colspec(raw):
if isinstance(raw, str):
spec = _parse_colspec(raw)
else:
spec = _normalize_colspec(raw)
if spec is None:
raise ValueError(f'unsupported column spec {raw!r}')
return spec
def _resolve_colspecs(columns):
parsed = []
for raw in columns:
column = _resolve_colspec(raw)
parsed.append(column)
return parsed
def _resolve_width(spec, defaultwidth):
_, label, width, fmt = spec
def _resolve_width(width, fmt, label, default):
if width:
if not isinstance(width, int):
raise NotImplementedError
return width
elif width and fmt:
width, _ = _parse_fmt(fmt)
if width:
return width
elif fmt:
parsed = _parse_fmt(fmt)
if parsed:
width, _ = parsed
if width:
return width
if not defaultwidth:
if not default:
return WIDTH
elif not hasattr(defaultwidth, 'get'):
return defaultwidth or WIDTH
defaultwidths = defaultwidth
defaultwidth = defaultwidths.get(None) or WIDTH
return defaultwidths.get(label) or defaultwidth
elif hasattr(default, 'get'):
defaults = default
default = defaults.get(None) or WIDTH
return defaults.get(label) or default
else:
return default or WIDTH
def _build_table(columns, *, sep=' ', defaultwidth=None):
@ -373,16 +417,13 @@ def _build_table(columns, *, sep=' ', defaultwidth=None):
div = []
rowfmt = []
for spec in columns:
label, field, _, colfmt = spec
width = _resolve_width(spec, defaultwidth)
if colfmt:
colfmt = f':{colfmt}'
else:
colfmt = f':{width}'
width = spec.resolve_width(defaultwidth)
colfmt = spec.fmt
colfmt = f':{spec.fmt}' if spec.fmt else f':{width}'
header.append(f' {{:^{width}}} '.format(label))
header.append(f' {{:^{width}}} '.format(spec.label))
div.append('-' * (width + 2))
rowfmt.append(f' {{{field}{colfmt}}} ')
rowfmt.append(f' {{{spec.field}{colfmt}}} ')
return (
sep.join(header),
sep.join(div),

View file

@ -20,7 +20,7 @@ import c_parser.__main__ as c_parser
import c_analyzer.__main__ as c_analyzer
import c_analyzer as _c_analyzer
from c_analyzer.info import UNKNOWN
from . import _analyzer, _capi, _files, _parser, REPO_ROOT
from . import _analyzer, _builtin_types, _capi, _files, _parser, REPO_ROOT
logger = logging.getLogger(__name__)
@ -325,6 +325,47 @@ def cmd_capi(filenames=None, *,
print(line)
def _cli_builtin_types(parser):
parser.add_argument('--format', dest='fmt', default='table')
# parser.add_argument('--summary', dest='format',
# action='store_const', const='summary')
def process_format(args, *, argv=None):
orig = args.fmt
args.fmt = _builtin_types.resolve_format(args.fmt)
if isinstance(args.fmt, str):
if args.fmt not in _builtin_types._FORMATS:
parser.error(f'unsupported format {orig!r}')
parser.add_argument('--include-modules', dest='showmodules',
action='store_true')
def process_modules(args, *, argv=None):
pass
return [
process_format,
process_modules,
]
def cmd_builtin_types(fmt, *,
showmodules=False,
verbosity=VERBOSITY,
):
render = _builtin_types.get_renderer(fmt)
types = _builtin_types.iter_builtin_types()
match = _builtin_types.resolve_matcher(showmodules)
if match:
types = (t for t in types if match(t, log=lambda msg: logger.log(1, msg)))
lines = render(
types,
# verbose=verbosity > VERBOSITY,
)
print()
for line in lines:
print(line)
# We do not define any other cmd_*() handlers here,
# favoring those defined elsewhere.
@ -354,6 +395,11 @@ COMMANDS = {
[_cli_capi],
cmd_capi,
),
'builtin-types': (
'show the builtin types',
[_cli_builtin_types],
cmd_builtin_types,
),
}

View file

@ -0,0 +1,365 @@
from collections import namedtuple
import os.path
import re
import textwrap
from c_common import tables
from . import REPO_ROOT
from ._files import iter_header_files, iter_filenames
CAPI_PREFIX = os.path.join('Include', '')
INTERNAL_PREFIX = os.path.join('Include', 'internal', '')
REGEX = re.compile(textwrap.dedent(rf'''
(?:
^
(?:
(?:
(?:
(?:
(?:
( static ) # <static>
\s+
|
( extern ) # <extern>
\s+
)?
PyTypeObject \s+
)
|
(?:
( PyAPI_DATA ) # <capi>
\s* [(] \s* PyTypeObject \s* [)] \s*
)
)
(\w+) # <name>
\s*
(?:
(?:
( = \s* {{ ) # <def>
$
)
|
( ; ) # <decl>
)
)
|
(?:
# These are specific to Objects/exceptions.c:
(?:
SimpleExtendsException
|
MiddlingExtendsException
|
ComplexExtendsException
)
\( \w+ \s* , \s*
( \w+ ) # <excname>
\s* ,
)
)
)
'''), re.VERBOSE)
def _parse_line(line):
m = re.match(REGEX, line)
if not m:
return None
(static, extern, capi,
name,
def_, decl,
excname,
) = m.groups()
if def_:
isdecl = False
if extern or capi:
raise NotImplementedError(line)
kind = 'static' if static else None
elif excname:
name = f'_PyExc_{excname}'
isdecl = False
kind = 'static'
else:
isdecl = True
if static:
kind = 'static'
elif extern:
kind = 'extern'
elif capi:
kind = 'capi'
else:
kind = None
return name, isdecl, kind
class BuiltinTypeDecl(namedtuple('BuiltinTypeDecl', 'file lno name kind')):
KINDS = {
'static',
'extern',
'capi',
'forward',
}
@classmethod
def from_line(cls, line, filename, lno):
# This is similar to ._capi.CAPIItem.from_line().
parsed = _parse_line(line)
if not parsed:
return None
name, isdecl, kind = parsed
if not isdecl:
return None
return cls.from_parsed(name, kind, filename, lno)
@classmethod
def from_parsed(cls, name, kind, filename, lno):
if not kind:
kind = 'forward'
return cls.from_values(filename, lno, name, kind)
@classmethod
def from_values(cls, filename, lno, name, kind):
if kind not in cls.KINDS:
raise ValueError(f'unsupported kind {kind!r}')
self = cls(filename, lno, name, kind)
if self.kind not in ('extern', 'capi') and self.api:
raise NotImplementedError(self)
elif self.kind == 'capi' and not self.api:
raise NotImplementedError(self)
return self
@property
def relfile(self):
return self.file[len(REPO_ROOT) + 1:]
@property
def api(self):
return self.relfile.startswith(CAPI_PREFIX)
@property
def internal(self):
return self.relfile.startswith(INTERNAL_PREFIX)
@property
def private(self):
if not self.name.startswith('_'):
return False
return self.api and not self.internal
@property
def public(self):
if self.kind != 'capi':
return False
return not self.internal and not self.private
class BuiltinTypeInfo(namedtuple('BuiltinTypeInfo', 'file lno name static decl')):
@classmethod
def from_line(cls, line, filename, lno, *, decls=None):
parsed = _parse_line(line)
if not parsed:
return None
name, isdecl, kind = parsed
if isdecl:
return None
return cls.from_parsed(name, kind, filename, lno, decls=decls)
@classmethod
def from_parsed(cls, name, kind, filename, lno, *, decls=None):
if not kind:
static = False
elif kind == 'static':
static = True
else:
raise NotImplementedError((filename, line, kind))
decl = decls.get(name) if decls else None
return cls(filename, lno, name, static, decl)
@property
def relfile(self):
return self.file[len(REPO_ROOT) + 1:]
@property
def exported(self):
return not self.static
@property
def api(self):
if not self.decl:
return False
return self.decl.api
@property
def internal(self):
if not self.decl:
return False
return self.decl.internal
@property
def private(self):
if not self.decl:
return False
return self.decl.private
@property
def public(self):
if not self.decl:
return False
return self.decl.public
@property
def inmodule(self):
return self.relfile.startswith('Modules' + os.path.sep)
def render_rowvalues(self, kinds):
row = {
'name': self.name,
**{k: '' for k in kinds},
'filename': f'{self.relfile}:{self.lno}',
}
if self.static:
kind = 'static'
else:
if self.internal:
kind = 'internal'
elif self.private:
kind = 'private'
elif self.public:
kind = 'public'
else:
kind = 'global'
row['kind'] = kind
row[kind] = kind
return row
def _ensure_decl(decl, decls):
prev = decls.get(decl.name)
if prev:
if decl.kind == 'forward':
return None
if prev.kind != 'forward':
if decl.kind == prev.kind and decl.file == prev.file:
assert decl.lno != prev.lno, (decl, prev)
return None
raise NotImplementedError(f'duplicate {decl} (was {prev}')
decls[decl.name] = decl
def iter_builtin_types(filenames=None):
decls = {}
seen = set()
for filename in iter_header_files():
seen.add(filename)
with open(filename) as infile:
for lno, line in enumerate(infile, 1):
decl = BuiltinTypeDecl.from_line(line, filename, lno)
if not decl:
continue
_ensure_decl(decl, decls)
srcfiles = []
for filename in iter_filenames():
if filename.endswith('.c'):
srcfiles.append(filename)
continue
if filename in seen:
continue
with open(filename) as infile:
for lno, line in enumerate(infile, 1):
decl = BuiltinTypeDecl.from_line(line, filename, lno)
if not decl:
continue
_ensure_decl(decl, decls)
for filename in srcfiles:
with open(filename) as infile:
localdecls = {}
for lno, line in enumerate(infile, 1):
parsed = _parse_line(line)
if not parsed:
continue
name, isdecl, kind = parsed
if isdecl:
decl = BuiltinTypeDecl.from_parsed(name, kind, filename, lno)
if not decl:
raise NotImplementedError((filename, line))
_ensure_decl(decl, localdecls)
else:
builtin = BuiltinTypeInfo.from_parsed(
name, kind, filename, lno,
decls=decls if name in decls else localdecls)
if not builtin:
raise NotImplementedError((filename, line))
yield builtin
def resolve_matcher(showmodules=False):
def match(info, *, log=None):
if not info.inmodule:
return True
if log is not None:
log(f'ignored {info.name!r}')
return False
return match
##################################
# CLI rendering
def resolve_format(fmt):
if not fmt:
return 'table'
elif isinstance(fmt, str) and fmt in _FORMATS:
return fmt
else:
raise NotImplementedError(fmt)
def get_renderer(fmt):
fmt = resolve_format(fmt)
if isinstance(fmt, str):
try:
return _FORMATS[fmt]
except KeyError:
raise ValueError(f'unsupported format {fmt!r}')
else:
raise NotImplementedError(fmt)
def render_table(types):
types = sorted(types, key=(lambda t: t.name))
colspecs = tables.resolve_columns(
'name:<33 static:^ global:^ internal:^ private:^ public:^ filename:<30')
header, div, rowfmt = tables.build_table(colspecs)
leader = ' ' * sum(c.width+2 for c in colspecs[:3]) + ' '
yield leader + f'{"API":^29}'
yield leader + '-' * 29
yield header
yield div
kinds = [c[0] for c in colspecs[1:-1]]
counts = {k: 0 for k in kinds}
base = {k: '' for k in kinds}
for t in types:
row = t.render_rowvalues(kinds)
kind = row['kind']
yield rowfmt.format(**row)
counts[kind] += 1
yield ''
yield f'total: {sum(counts.values()):>3}'
for kind in kinds:
yield f' {kind:>10}: {counts[kind]:>3}'
def render_repr(types):
for t in types:
yield repr(t)
_FORMATS = {
'table': render_table,
'repr': render_repr,
}

View file

@ -7,7 +7,7 @@ filename funcname name reason
# global objects to fix in core code
#-----------------------
# static types
# exported builtin types (C-API)
Objects/boolobject.c - PyBool_Type -
Objects/bytearrayobject.c - PyByteArrayIter_Type -
@ -18,8 +18,6 @@ Objects/capsule.c - PyCapsule_Type -
Objects/cellobject.c - PyCell_Type -
Objects/classobject.c - PyInstanceMethod_Type -
Objects/classobject.c - PyMethod_Type -
Objects/codeobject.c - _PyLineIterator -
Objects/codeobject.c - _PyPositionsIterator -
Objects/codeobject.c - PyCode_Type -
Objects/complexobject.c - PyComplex_Type -
Objects/descrobject.c - PyClassMethodDescr_Type -
@ -42,16 +40,12 @@ Objects/dictobject.c - PyDictValues_Type -
Objects/dictobject.c - PyDict_Type -
Objects/enumobject.c - PyEnum_Type -
Objects/enumobject.c - PyReversed_Type -
Objects/exceptions.c - _PyExc_BaseExceptionGroup -
Objects/exceptions.c - _PyExc_EncodingWarning -
Objects/fileobject.c - PyStdPrinter_Type -
Objects/floatobject.c - FloatInfoType -
Objects/floatobject.c - PyFloat_Type -
Objects/frameobject.c - PyFrame_Type -
Objects/funcobject.c - PyClassMethod_Type -
Objects/funcobject.c - PyFunction_Type -
Objects/funcobject.c - PyStaticMethod_Type -
Objects/genericaliasobject.c - _Py_GenericAliasIterType -
Objects/genericaliasobject.c - Py_GenericAliasType -
Objects/genobject.c - PyAsyncGen_Type -
Objects/genobject.c - PyCoro_Type -
@ -63,13 +57,10 @@ Objects/genobject.c - _PyCoroWrapper_Type -
Objects/interpreteridobject.c - _PyInterpreterID_Type -
Objects/iterobject.c - PyCallIter_Type -
Objects/iterobject.c - PySeqIter_Type -
Objects/iterobject.c - _PyAnextAwaitable_Type -
Objects/listobject.c - PyListIter_Type -
Objects/listobject.c - PyListRevIter_Type -
Objects/listobject.c - PyList_Type -
Objects/longobject.c - Int_InfoType -
Objects/longobject.c - PyLong_Type -
Objects/memoryobject.c - _PyMemoryIter_Type -
Objects/memoryobject.c - PyMemoryView_Type -
Objects/memoryobject.c - _PyManagedBuffer_Type -
Objects/methodobject.c - PyCFunction_Type -
@ -91,7 +82,6 @@ Objects/rangeobject.c - PyRange_Type -
Objects/setobject.c - PyFrozenSet_Type -
Objects/setobject.c - PySetIter_Type -
Objects/setobject.c - PySet_Type -
Objects/setobject.c - _PySetDummy_Type -
Objects/sliceobject.c - PyEllipsis_Type -
Objects/sliceobject.c - PySlice_Type -
Objects/tupleobject.c - PyTupleIter_Type -
@ -99,11 +89,8 @@ Objects/tupleobject.c - PyTuple_Type -
Objects/typeobject.c - PyBaseObject_Type -
Objects/typeobject.c - PySuper_Type -
Objects/typeobject.c - PyType_Type -
Objects/unicodeobject.c - EncodingMapType -
Objects/unicodeobject.c - PyUnicodeIter_Type -
Objects/unicodeobject.c - PyUnicode_Type -
Objects/unionobject.c - _PyUnion_Type -
Objects/unionobject.c - _Py_UnionType -
Objects/weakrefobject.c - _PyWeakref_CallableProxyType -
Objects/weakrefobject.c - _PyWeakref_ProxyType -
Objects/weakrefobject.c - _PyWeakref_RefType -
@ -113,8 +100,23 @@ Python/bltinmodule.c - PyZip_Type -
Python/context.c - PyContextToken_Type -
Python/context.c - PyContextVar_Type -
Python/context.c - PyContext_Type -
Python/traceback.c - PyTraceBack_Type -
#-----------------------
# other exported builtin types
# Not in a .h file:
Objects/codeobject.c - _PyLineIterator -
# Not in a .h file:
Objects/codeobject.c - _PyPositionsIterator -
Objects/genericaliasobject.c - _Py_GenericAliasIterType -
# Not in a .h file:
Objects/iterobject.c - _PyAnextAwaitable_Type -
# Not in a .h file:
Objects/memoryobject.c - _PyMemoryIter_Type -
#Objects/unicodeobject.c - _PyUnicodeASCIIIter_Type -
Objects/unionobject.c - _PyUnion_Type -
Python/context.c - _PyContextTokenMissing_Type -
Python/errors.c - UnraisableHookArgsType -
Python/hamt.c - _PyHamtItems_Type -
Python/hamt.c - _PyHamtKeys_Type -
Python/hamt.c - _PyHamtValues_Type -
@ -123,17 +125,32 @@ Python/hamt.c - _PyHamt_BitmapNode_Type -
Python/hamt.c - _PyHamt_CollisionNode_Type -
Python/hamt.c - _PyHamt_Type -
Python/symtable.c - PySTEntry_Type -
#-----------------------
# private static builtin types
Objects/setobject.c - _PySetDummy_Type -
Objects/unicodeobject.c - EncodingMapType -
#Objects/unicodeobject.c - PyFieldNameIter_Type -
#Objects/unicodeobject.c - PyFormatterIter_Type -
#-----------------------
# static builtin structseq
Objects/floatobject.c - FloatInfoType -
Objects/longobject.c - Int_InfoType -
Python/errors.c - UnraisableHookArgsType -
Python/sysmodule.c - AsyncGenHooksType -
Python/sysmodule.c - FlagsType -
Python/sysmodule.c - Hash_InfoType -
Python/sysmodule.c - VersionInfoType -
Python/thread.c - ThreadInfoType -
Python/traceback.c - PyTraceBack_Type -
#-----------------------
# builtin exception types
Objects/exceptions.c - _PyExc_BaseException -
Objects/exceptions.c - _PyExc_BaseExceptionGroup -
Objects/exceptions.c - _PyExc_UnicodeEncodeError -
Objects/exceptions.c - _PyExc_UnicodeDecodeError -
Objects/exceptions.c - _PyExc_UnicodeTranslateError -
@ -197,9 +214,11 @@ Objects/exceptions.c - _PyExc_ImportWarning -
Objects/exceptions.c - _PyExc_UnicodeWarning -
Objects/exceptions.c - _PyExc_BytesWarning -
Objects/exceptions.c - _PyExc_ResourceWarning -
Objects/exceptions.c - _PyExc_EncodingWarning -
Objects/exceptions.c - PyExc_EnvironmentError -
Objects/exceptions.c - PyExc_IOError -
Objects/exceptions.c - PyExc_BaseException -
Objects/exceptions.c - PyExc_BaseExceptionGroup -
Objects/exceptions.c - PyExc_Exception -
Objects/exceptions.c - PyExc_TypeError -
Objects/exceptions.c - PyExc_StopAsyncIteration -
@ -263,6 +282,7 @@ Objects/exceptions.c - PyExc_ImportWarning -
Objects/exceptions.c - PyExc_UnicodeWarning -
Objects/exceptions.c - PyExc_BytesWarning -
Objects/exceptions.c - PyExc_ResourceWarning -
Objects/exceptions.c - PyExc_EncodingWarning -
#-----------------------
# singletons
@ -354,8 +374,6 @@ Objects/unicodeobject.c - static_strings -
# other
# initialized once
Objects/exceptions.c - PyExc_BaseExceptionGroup -
Objects/exceptions.c - PyExc_EncodingWarning -
# XXX This should have been found by the analyzer but wasn't:
Python/context.c - _token_missing -
# XXX This should have been found by the analyzer but wasn't:

Can't render this file because it has a wrong number of fields in line 4.