Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions Doc/deprecations/pending-removal-in-3.21.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ Pending removal in Python 3.21
* The ``dims`` property of ``ast.Tuple`` will be removed in Python 3.21. Use
the ``ast.Tuple.elts`` property instead.

* :mod:`inspect`:

* :attr:`inspect.CO_NOFREE`, a name for an unused compiler flag, will
be removed in Python 3.21.

* :mod:`struct`:

* Soft-deprecated since Python 3.15, using ``'F'`` and ``'D'`` type codes are now
Expand Down
10 changes: 10 additions & 0 deletions Doc/library/inspect.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,16 @@ which is a bitmap of the following flags:

.. versionadded:: 3.14

.. data:: CO_NOFREE

Unused; always unset.

.. versionchanged:: 3.5
Previously, this flag indicated whether there are free variables
in the code object.

.. deprecated-removed:: next 3.21

.. note::
The flags are specific to CPython, and may not be defined in other
Python implementations. Furthermore, the flags are an implementation
Expand Down
14 changes: 8 additions & 6 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1576,13 +1576,15 @@ Special read-only attributes

.. index:: pair: object; generator

The following flag bits are defined for :attr:`~codeobject.co_flags`:
bit ``0x04`` is set if
The :attr:`~codeobject.co_flags` attribute uses flag bits listed in
:ref:`inspect-module-co-flags`.
For example, :attr:`~inspect.CO_VARARGS` (bit ``0x04``) is set if
the function uses the ``*arguments`` syntax to accept an arbitrary number of
positional arguments; bit ``0x08`` is set if the function uses the
``**keywords`` syntax to accept arbitrary keyword arguments; bit ``0x20`` is set
if the function is a generator. See :ref:`inspect-module-co-flags` for details
on the semantics of each flags that might be present.
positional arguments; :attr:`~inspect.CO_VARKEYWORDS` (bit ``0x08``)
is set if the function uses the ``**keywords`` syntax to accept arbitrary
keyword arguments;
:attr:`~inspect.CO_GENERATOR` (bit ``0x20``) is set if the function
is a generator.

Future feature declarations (for example, ``from __future__ import division``) also use bits
in :attr:`~codeobject.co_flags` to indicate whether a code object was compiled with a
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,11 @@ New deprecations
3.9, now issues a deprecation warning on use. This property is slated for
removal in 3.21. Use ``ast.Tuple.elts`` instead.

* :mod:`inspect`:

* :attr:`inspect.CO_NOFREE`, a name for an unused compiler flag, will
be removed in Python 3.21.

* :mod:`struct`:

* The ``'F'`` and ``'D'`` type codes, soft-deprecated since Python 3.15,
Expand Down
2 changes: 2 additions & 0 deletions Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,14 @@ typedef struct {
struct PyCodeObject _PyCode_DEF(1);

/* Masks for co_flags above */
// Keep in sync with _opcode.c, which exposes these for inspect & dis
#define CO_OPTIMIZED 0x0001
#define CO_NEWLOCALS 0x0002
#define CO_VARARGS 0x0004
#define CO_VARKEYWORDS 0x0008
#define CO_NESTED 0x0010
#define CO_GENERATOR 0x0020
// CO_NOFREE used to be 0x0040 -- don't reuse before inspect.CO_NOFREE is gone

/* The CO_COROUTINE flag is set for coroutine functions (defined with
``async def`` keywords) */
Expand Down
18 changes: 0 additions & 18 deletions Lib/dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,24 +155,6 @@ def distb(tb=None, *, file=None, show_caches=False, adaptive=False, show_offsets
disassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file, show_caches=show_caches, adaptive=adaptive,
show_offsets=show_offsets, show_positions=show_positions, show_jit=show_jit)

# The inspect module interrogates this dictionary to build its
# list of CO_* constants. It is also used by pretty_flags to
# turn the co_flags field into a human readable list.
COMPILER_FLAG_NAMES = {
1: "OPTIMIZED",
2: "NEWLOCALS",
4: "VARARGS",
8: "VARKEYWORDS",
16: "NESTED",
32: "GENERATOR",
64: "NOFREE",
128: "COROUTINE",
256: "ITERABLE_COROUTINE",
512: "ASYNC_GENERATOR",
0x4000000: "HAS_DOCSTRING",
0x8000000: "METHOD",
}

def pretty_flags(flags):
"""Return pretty representation of code flags."""
names = []
Expand Down
28 changes: 14 additions & 14 deletions Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,7 @@
"CORO_CREATED",
"CORO_RUNNING",
"CORO_SUSPENDED",
"CO_ASYNC_GENERATOR",
"CO_COROUTINE",
"CO_GENERATOR",
"CO_ITERABLE_COROUTINE",
"CO_NESTED",
"CO_NEWLOCALS",
"CO_NOFREE",
"CO_OPTIMIZED",
"CO_VARARGS",
"CO_VARKEYWORDS",
"CO_HAS_DOCSTRING",
"CO_METHOD",
# CO_* -- added below
"ClassFoundException",
"ClosureVars",
"EndOfBlock",
Expand Down Expand Up @@ -169,8 +158,10 @@
# We try to get them from dis to avoid duplication
mod_dict = globals()
for k, v in dis.COMPILER_FLAG_NAMES.items():
mod_dict["CO_" + v] = k
del k, v, mod_dict
name = "CO_" + v
mod_dict[name] = k
__all__.append(name)
del k, v, name, mod_dict

# See Include/object.h
TPFLAGS_IS_ABSTRACT = 1 << 20
Expand Down Expand Up @@ -3475,6 +3466,15 @@ def _render_details_for_cli(details):
return "\n".join(lines)


def __getattr__(name):
if name == "CO_NOFREE":
# CO_NOFREE: removed from C code in GH-26839 (Python 3.5)
import warnings
warnings._deprecated("inspect.CO_NOFREE", remove=(3, 21))
return 64
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


def _main():
""" Logic for inspecting an object given at command line """
import argparse
Expand Down
5 changes: 4 additions & 1 deletion Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

__all__ = ["cmp_op", "stack_effect", "hascompare", "opname", "opmap",
"HAVE_ARGUMENT", "EXTENDED_ARG", "hasarg", "hasconst", "hasname",
"hasjump", "hasjrel", "hasjabs", "hasfree", "haslocal", "hasexc"]
"hasjump", "hasjrel", "hasjabs", "hasfree", "haslocal", "hasexc",
"COMPILER_FLAG_NAMES"]

import builtins
import _opcode
Expand All @@ -17,6 +18,8 @@
HAVE_ARGUMENT, MIN_INSTRUMENTED_OPCODE) # noqa: F401
EXTENDED_ARG = opmap['EXTENDED_ARG']

COMPILER_FLAG_NAMES = {n: name for name, n in _opcode.COMPILER_FLAGS.items()}

opname = ['<%r>' % (op,) for op in range(max(opmap.values()) + 1)]
for m in (opmap, _specialized_opmap):
for op, i in m.items():
Expand Down
13 changes: 13 additions & 0 deletions Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE, temp_cwd
from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python
from test.support import has_subprocess_support
from test.support import warnings_helper
from test import support

from test.test_inspect import inspect_fodder as mod
Expand Down Expand Up @@ -6973,5 +6974,17 @@ def f():
self.assertIn(expected, output)


class TestCompilerConstants(unittest.TestCase):
def test_previously_documented_values(self):
# The numeric values are in the docs; we better not change them
self.assertEqual(inspect.CO_VARARGS, 0x04)
self.assertEqual(inspect.CO_VARKEYWORDS, 0x08)
self.assertEqual(inspect.CO_GENERATOR, 0x20)

@warnings_helper.ignore_warnings(category=DeprecationWarning)
def test_nofree(self):
self.assertEqual(inspect.CO_NOFREE, 0x40)


if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deprecate :py:attr:`inspect.CO_NOFREE`, a name for an unused compiler flag.
34 changes: 34 additions & 0 deletions Modules/_opcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,40 @@ _opcode_exec(PyObject *m) {
if (PyModule_AddIntMacro(m, ENABLE_SPECIALIZATION) < 0) {
return -1;
}
PyObject *compiler_flag_names = PyDict_New();
if (compiler_flag_names == NULL) {
return -1;
}
PyObject *val;
# define ADD_CO(NAME) \
do { \
val = PyLong_FromLong(CO_ ## NAME); \
if (val == NULL) { \
return -1; \
} \
if (PyDict_SetItemString(compiler_flag_names, #NAME, val) < 0) { \
return -1; \
} \
Py_DECREF(val); \
} while(0) \
/////////////////////////////////////////////////////////////////////////
ADD_CO(OPTIMIZED);
ADD_CO(NEWLOCALS);
ADD_CO(VARARGS);
ADD_CO(VARKEYWORDS);
ADD_CO(NESTED);
ADD_CO(GENERATOR);
ADD_CO(COROUTINE);
ADD_CO(ITERABLE_COROUTINE);
ADD_CO(ASYNC_GENERATOR);
ADD_CO(HAS_DOCSTRING);
ADD_CO(METHOD);
# undef ADD_CO
if (PyModule_Add(m, "COMPILER_FLAGS",
PyFrozenDict_New(compiler_flag_names)) < 0) {
return -1;
}
Py_DECREF(compiler_flag_names);
return 0;
}

Expand Down
Loading