Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 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
8 changes: 8 additions & 0 deletions Doc/c-api/init_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,14 @@ PyConfig
by the function calculating the :ref:`Path Configuration
<init-path-config>`.

.. c:member:: int optimize

Should the compiler optimize bytecode? If equal to 0, disable the
compiler optimizations and set :c:member:`~PyConfig.optimization_level`
to 0. Set to 0 by :option:`-X noopt <-X>` command line option.

.. versionadded:: 3.10

.. c:member:: int optimization_level

Compilation optimization level:
Expand Down
9 changes: 8 additions & 1 deletion Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ are always available. They are listed here in alphabetical order.
object has ``CO_COROUTINE`` set in ``co_code``, and can be interactively
executed via ``await eval(code_object)``.

If the *ast.PyCF_DISABLE_ALL_OPTIMIZATIONS* bit is set in *flags*, all compiler
optimizations will be disabled and the value of *optimize* will be ignored. If
this bit is not set, the value of ``sys.flags.noopt`` will be used.

The argument *optimize* specifies the optimization level of the compiler; the
default value of ``-1`` selects the optimization level of the interpreter as
given by :option:`-O` options. Explicit levels are ``0`` (no optimization;
Expand Down Expand Up @@ -319,10 +323,13 @@ are always available. They are listed here in alphabetical order.
Previously, :exc:`TypeError` was raised when null bytes were encountered
in *source*.

.. versionadded:: 3.8
.. versionchanged:: 3.8
``ast.PyCF_ALLOW_TOP_LEVEL_AWAIT`` can now be passed in flags to enable
support for top-level ``await``, ``async for``, and ``async with``.

.. versionchanged:: 3.10
New *noopt* optional keyword-only parameter.


.. class:: complex([real[, imag]])

Expand Down
10 changes: 9 additions & 1 deletion Doc/library/importlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1410,7 +1410,7 @@ an :term:`importer`.

.. versionadded:: 3.4

.. function:: cache_from_source(path, debug_override=None, *, optimization=None)
.. function:: cache_from_source(path, debug_override=None, *, optimization=None, noopt=None)

Return the :pep:`3147`/:pep:`488` path to the byte-compiled file associated
with the source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return
Expand All @@ -1429,6 +1429,11 @@ an :term:`importer`.
``/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc``. The string representation
of *optimization* can only be alphanumeric, else :exc:`ValueError` is raised.

The *noopt* parameter is used to specify if compiler optimization are
disabled. If it is true, disable compiler optimizations, *optimization* is
ignored and ``.noopt`` suffix is used (ex: ``baz.cpython-32.noopt.pyc``). If
it is ``None``, use ``sys.flags.noopt`` value.

The *debug_override* parameter is deprecated and can be used to override
the system's value for ``__debug__``. A ``True`` value is the equivalent of
setting *optimization* to the empty string. A ``False`` value is the same as
Expand All @@ -1444,6 +1449,9 @@ an :term:`importer`.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.

.. versionchanged:: 3.10
Added *noopt* parameter.


.. function:: source_from_cache(path)

Expand Down
8 changes: 7 additions & 1 deletion Doc/library/py_compile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ byte-code cache files in the directory containing the source code.
Exception raised when an error occurs while attempting to compile the file.


.. function:: compile(file, cfile=None, dfile=None, doraise=False, optimize=-1, invalidation_mode=PycInvalidationMode.TIMESTAMP, quiet=0)
.. function:: compile(file, cfile=None, dfile=None, doraise=False, optimize=-1, invalidation_mode=PycInvalidationMode.TIMESTAMP, quiet=0, noopt=None)

Compile a source file to byte-code and write out the byte-code cache file.
The source code is loaded from the file named *file*. The byte-code is
Expand Down Expand Up @@ -60,6 +60,9 @@ byte-code cache files in the directory containing the source code.
:func:`compile` function. The default of ``-1`` selects the optimization
level of the current interpreter.

If *noopt* is true, disable compiler optimizations and ignore *optimize*
Comment thread
pablogsal marked this conversation as resolved.
Outdated
argument. If it is ``None``, use ``sys.flags.noopt`` value.

*invalidation_mode* should be a member of the :class:`PycInvalidationMode`
enum and controls how the generated bytecode cache is invalidated at
runtime. The default is :attr:`PycInvalidationMode.CHECKED_HASH` if
Expand Down Expand Up @@ -92,6 +95,9 @@ byte-code cache files in the directory containing the source code.
.. versionchanged:: 3.8
The *quiet* parameter was added.

.. versionchanged:: 3.10
The *noopt* parameter was added.


.. class:: PycInvalidationMode

Expand Down
4 changes: 4 additions & 0 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ always available.
:const:`inspect` :option:`-i`
:const:`interactive` :option:`-i`
:const:`isolated` :option:`-I`
:const:`noopt` :option:`-X noopt <-X>`
:const:`optimize` :option:`-O` or :option:`-OO`
:const:`dont_write_bytecode` :option:`-B`
:const:`no_user_site` :option:`-s`
Expand Down Expand Up @@ -469,6 +470,9 @@ always available.
Mode <devmode>` and the ``utf8_mode`` attribute for the new :option:`-X`
``utf8`` flag.

.. versionchanged:: 3.10
Added ``noopt`` attribute for the new :option:`-X noopt <-X>` option.


.. data:: float_info

Expand Down
7 changes: 4 additions & 3 deletions Doc/using/cmdline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ Miscellaneous options
* ``-X pycache_prefix=PATH`` enables writing ``.pyc`` files to a parallel
tree rooted at the given directory instead of to the code tree. See also
:envvar:`PYTHONPYCACHEPREFIX`.
* ``-X noopt`` disables the compiler optimizations.

It also allows passing arbitrary values and retrieving them through the
:data:`sys._xoptions` dictionary.
Expand All @@ -477,9 +478,9 @@ Miscellaneous options
The ``-X pycache_prefix`` option. The ``-X dev`` option now logs
``close()`` exceptions in :class:`io.IOBase` destructor.

.. versionchanged:: 3.9
Using ``-X dev`` option, check *encoding* and *errors* arguments on
string encoding and decoding operations.
.. versionadded:: 3.10
The ``-X noopt`` option. Using ``-X dev`` option, check *encoding* and
*errors* arguments on string encoding and decoding operations.

The ``-X showalloccount`` option has been removed.

Expand Down
30 changes: 30 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ Other Language Changes
:meth:`~object.__index__` method).
(Contributed by Serhiy Storchaka in :issue:`37999`.)

* Added :option:`-X noopt <-X>` command line to disable compiler optimizations.
:mod:`importlib` uses ``.noopt.pyc`` suffix for ``.pyc`` filenames if
:data:`sys.flags.noopt` is true.
(Contributed by Yury Selivanov, Victor Stinner and Pablo Galindo in :issue:`2506`)


New Modules
===========
Expand All @@ -109,6 +114,12 @@ base64
Add :func:`base64.b32hexencode` and :func:`base64.b32hexdecode` to support the
Base32 Encoding with Extended Hex Alphabet.

builtins
--------

The :func:`compile` function gets a new optional bit in the *flags* argument
(:data:`ast.PyCF_DISABLE_ALL_OPTIMIZATIONS`) to disable all compiler optimizations.

curses
------

Expand All @@ -126,6 +137,20 @@ Added the *root_dir* and *dir_fd* parameters in :func:`~glob.glob` and
:func:`~glob.iglob` which allow to specify the root directory for searching.
(Contributed by Serhiy Storchaka in :issue:`38144`.)

importlib
---------

Add a new *noopt* optional keyword-only parameter to
:func:`importlib.util.cache_from_source` to disable compiler optimizations.
(Contributed by Yury Selivanov, Victor Stinner and Pablo Galindo in :issue:`2506`)

py_compile
----------

Add a new *noopt* optional keyword-only parameter to :func:`py_compile.compile`
to disable compiler optimizations.
(Contributed by Yury Selivanov, Victor Stinner and Pablo Galindo in :issue:`2506`)

os
--

Expand All @@ -145,6 +170,11 @@ Add :data:`sys.orig_argv` attribute: the list of the original command line
arguments passed to the Python executable.
(Contributed by Victor Stinner in :issue:`23427`.)


Add new :data:`sys.flags.noopt` flag for the new :option:`-X noopt <-X>` option
(disable compiler optimizations).
(Contributed by Yury Selivanov, Victor Stinner and Pablo Galindo in :issue:`2506`)

xml
---

Expand Down
7 changes: 6 additions & 1 deletion Include/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ extern "C" {
#define PyCF_IGNORE_COOKIE 0x0800
#define PyCF_TYPE_COMMENTS 0x1000
#define PyCF_ALLOW_TOP_LEVEL_AWAIT 0x2000
#define PyCF_DISABLE_ALL_OPTIMIZATIONS 0x3000
Comment thread
pablogsal marked this conversation as resolved.
Outdated
#define PyCF_COMPILE_MASK (PyCF_ONLY_AST | PyCF_ALLOW_TOP_LEVEL_AWAIT | \
PyCF_TYPE_COMMENTS | PyCF_DONT_IMPLY_DEDENT)
PyCF_TYPE_COMMENTS | PyCF_DONT_IMPLY_DEDENT | \
PyCF_DISABLE_ALL_OPTIMIZATIONS)

#ifndef Py_LIMITED_API
typedef struct {
Expand Down Expand Up @@ -106,4 +108,7 @@ PyAPI_FUNC(int) _PyAST_Optimize(struct _mod *, PyArena *arena, _PyASTOptimizeSta
/* This doesn't need to match anything */
#define Py_fstring_input 800

/* Value of 'optimize' to disable all optimizations */
#define _PyCompiler_disable_all_optimizations -2

#endif /* !Py_COMPILE_H */
11 changes: 11 additions & 0 deletions Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,17 @@ typedef struct {

_PyConfig_Write() initializes Py_GetArgcArgv() to this list. */
PyWideStringList orig_argv;

/* Should the compiler optimize bytecode?

If equal to 0, disable compiler optimizations and set optimization_level
to 0.

If equal to 1, enable compiler optimizations.

Set to 0 by -X noopt. It's default value is 1 */
int optimize;

} PyConfig;

PyAPI_FUNC(void) PyConfig_InitPythonConfig(PyConfig *config);
Expand Down
5 changes: 5 additions & 0 deletions Include/pythonrun.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ PyAPI_FUNC(PyObject *) Py_CompileStringObject(
PyObject *filename, int start,
PyCompilerFlags *flags,
int optimize);
PyAPI_FUNC(PyObject *) _Py_CompileString(
const char *str,
PyObject *filename, int start,
PyCompilerFlags *flags,
int optimize);
#endif
PyAPI_FUNC(struct symtable *) Py_SymtableString(
const char *str,
Expand Down
4 changes: 2 additions & 2 deletions Lib/distutils/command/build_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,10 @@ def get_outputs(self, include_bytecode=1):
if include_bytecode:
if self.compile:
outputs.append(importlib.util.cache_from_source(
filename, optimization=''))
filename, optimization='', noopt=False))
if self.optimize > 0:
outputs.append(importlib.util.cache_from_source(
filename, optimization=self.optimize))
filename, optimization=self.optimize, noopt=False))

outputs += [
os.path.join(build_dir, filename)
Expand Down
4 changes: 2 additions & 2 deletions Lib/distutils/command/install_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ def _bytecode_filenames(self, py_filenames):
continue
if self.compile:
bytecode_files.append(importlib.util.cache_from_source(
py_file, optimization=''))
py_file, optimization='', noopt=False))
if self.optimize > 0:
bytecode_files.append(importlib.util.cache_from_source(
py_file, optimization=self.optimize))
py_file, optimization=self.optimize, noopt=False))

return bytecode_files

Expand Down
6 changes: 4 additions & 2 deletions Lib/distutils/tests/test_install_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ def test_byte_compile(self):
f = os.path.join(project_dir, 'foo.py')
self.write_file(f, '# python file')
cmd.byte_compile([f])
pyc_file = importlib.util.cache_from_source('foo.py', optimization='')
pyc_file = importlib.util.cache_from_source('foo.py', optimization='',
noopt=False)
pyc_opt_file = importlib.util.cache_from_source('foo.py',
optimization=cmd.optimize)
optimization=cmd.optimize,
noopt=False)
self.assertTrue(os.path.exists(pyc_file))
self.assertTrue(os.path.exists(pyc_opt_file))

Expand Down
9 changes: 5 additions & 4 deletions Lib/distutils/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,10 +444,11 @@ def byte_compile (py_files,
# dfile - purported source filename (same as 'file' by default)
if optimize >= 0:
opt = '' if optimize == 0 else optimize
cfile = importlib.util.cache_from_source(
file, optimization=opt)
cfile = importlib.util.cache_from_source(file,
optimization=opt,
noopt=False)
else:
cfile = importlib.util.cache_from_source(file)
cfile = importlib.util.cache_from_source(file, noopt=False)
dfile = file
if prefix:
if file[:len(prefix)] != prefix:
Expand All @@ -462,7 +463,7 @@ def byte_compile (py_files,
if force or newer(file, cfile):
log.info("byte-compiling %s to %s", file, cfile_base)
if not dry_run:
compile(file, cfile, dfile)
compile(file, cfile, dfile, noopt=False)
else:
log.debug("skipping byte-compilation of %s to %s",
file, cfile_base)
Expand Down
Loading