Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8334fd9

Browse files
committed
Add an "optimize" parameter to compile() to control the optimization level, and provide an interface to it in py_compile, compileall and PyZipFile.
1 parent 427d314 commit 8334fd9

17 files changed

Lines changed: 283 additions & 100 deletions

Doc/c-api/veryhigh.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,12 @@ the same library that the Python runtime is using.
230230
231231
.. c:function:: PyObject* Py_CompileStringFlags(const char *str, const char *filename, int start, PyCompilerFlags *flags)
232232
233+
This is a simplified interface to :c:func:`Py_CompileStringExFlags` below, with
234+
*optimize* set to ``-1``.
235+
236+
237+
.. c:function:: PyObject* Py_CompileStringExFlags(const char *str, const char *filename, int start, PyCompilerFlags *flags, int optimize)
238+
233239
Parse and compile the Python source code in *str*, returning the resulting code
234240
object. The start token is given by *start*; this can be used to constrain the
235241
code which can be compiled and should be :const:`Py_eval_input`,
@@ -238,6 +244,14 @@ the same library that the Python runtime is using.
238244
:exc:`SyntaxError` exception messages. This returns *NULL* if the code cannot
239245
be parsed or compiled.
240246
247+
The integer *optimize* specifies the optimization level of the compiler; a
248+
value of ``-1`` selects the optimization level of the interpreter as given by
249+
:option:`-O` options. Explicit levels are ``0`` (no optimization;
250+
``__debug__`` is true), ``1`` (asserts are removed, ``__debug__`` is false)
251+
or ``2`` (docstrings are removed too).
252+
253+
.. versionadded:: 3.2
254+
241255
242256
.. c:function:: PyObject* PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
243257

Doc/library/compileall.rst

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ compile Python sources.
5858
Public functions
5959
----------------
6060

61-
.. function:: compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None, quiet=False, legacy=False)
61+
.. function:: compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None, quiet=False, legacy=False, optimize=-1)
6262

6363
Recursively descend the directory tree named by *dir*, compiling all :file:`.py`
6464
files along the way. The *maxlevels* parameter is used to limit the depth of
@@ -76,14 +76,23 @@ Public functions
7676
If *legacy* is true, old-style ``.pyc`` file path names are written,
7777
otherwise (the default), :pep:`3147`-style path names are written.
7878

79+
*optimize* specifies the optimization level for the compiler. It is passed to
80+
the built-in :func:`compile` function.
7981

80-
.. function:: compile_path(skip_curdir=True, maxlevels=0, force=False, legacy=False)
82+
.. versionchanged:: 3.2
83+
Added the *optimize* parameter.
84+
85+
86+
.. function:: compile_path(skip_curdir=True, maxlevels=0, force=False, legacy=False, optimize=-1)
8187

8288
Byte-compile all the :file:`.py` files found along ``sys.path``. If
8389
*skip_curdir* is true (the default), the current directory is not included in
84-
the search. The *maxlevels* parameter defaults to ``0``, and the *force*
85-
and *legacy* parameters default to ``False``. All are
86-
passed to the :func:`compile_dir` function.
90+
the search. All other parameters are passed to the :func:`compile_dir`
91+
function.
92+
93+
.. versionchanged:: 3.2
94+
Added the *optimize* parameter.
95+
8796

8897
To force a recompile of all the :file:`.py` files in the :file:`Lib/`
8998
subdirectory and all its subdirectories::

Doc/library/functions.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ are always available. They are listed here in alphabetical order.
174174
type hierarchy in :ref:`types`.
175175

176176

177-
.. function:: compile(source, filename, mode, flags=0, dont_inherit=False)
177+
.. function:: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
178178

179179
Compile the *source* into a code or AST object. Code objects can be executed
180180
by :func:`exec` or :func:`eval`. *source* can either be a string or an AST
@@ -206,6 +206,12 @@ are always available. They are listed here in alphabetical order.
206206
can be found as the :attr:`compiler_flag` attribute on the :class:`_Feature`
207207
instance in the :mod:`__future__` module.
208208

209+
The argument *optimize* specifies the optimization level of the compiler; the
210+
default value of ``-1`` selects the optimization level of the interpreter as
211+
given by :option:`-O` options. Explicit levels are ``0`` (no optimization;
212+
``__debug__`` is true), ``1`` (asserts are removed, ``__debug__`` is false)
213+
or ``2`` (docstrings are removed too).
214+
209215
This function raises :exc:`SyntaxError` if the compiled source is invalid,
210216
and :exc:`TypeError` if the source contains null bytes.
211217

@@ -218,7 +224,7 @@ are always available. They are listed here in alphabetical order.
218224

219225
.. versionchanged:: 3.2
220226
Allowed use of Windows and Mac newlines. Also input in ``'exec'`` mode
221-
does not have to end in a newline anymore.
227+
does not have to end in a newline anymore. Added the *optimize* parameter.
222228

223229

224230
.. function:: complex([real[, imag]])

Doc/library/py_compile.rst

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ byte-code cache files in the directory containing the source code.
2222
Exception raised when an error occurs while attempting to compile the file.
2323

2424

25-
.. function:: compile(file, cfile=None, dfile=None, doraise=False)
25+
.. function:: compile(file, cfile=None, dfile=None, doraise=False, optimize=-1)
2626

2727
Compile a source file to byte-code and write out the byte-code cache file. The
2828
source code is loaded from the file name *file*. The byte-code is written to
@@ -37,6 +37,13 @@ byte-code cache files in the directory containing the source code.
3737
returns the path to byte-compiled file, i.e. whatever *cfile* value was
3838
used.
3939

40+
*optimize* controls the optimization level and is passed to the built-in
41+
:func:`compile` function. The default of ``-1`` selects the optimization
42+
level of the current interpreter.
43+
44+
.. versionchanged:: 3.2
45+
Added the *optimize* parameter.
46+
4047

4148
.. function:: main(args=None)
4249

Doc/library/zipfile.rst

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ The module defines the following items:
5151

5252

5353
.. class:: PyZipFile
54+
:noindex:
5455

5556
Class for creating ZIP archives containing Python libraries.
5657

@@ -318,37 +319,53 @@ The following data attributes are also available:
318319
string no longer than 65535 bytes. Comments longer than this will be
319320
truncated in the written archive when :meth:`ZipFile.close` is called.
320321

322+
321323
.. _pyzipfile-objects:
322324

323325
PyZipFile Objects
324326
-----------------
325327

326328
The :class:`PyZipFile` constructor takes the same parameters as the
327-
:class:`ZipFile` constructor. Instances have one method in addition to those of
328-
:class:`ZipFile` objects.
329-
330-
331-
.. method:: PyZipFile.writepy(pathname, basename='')
332-
333-
Search for files :file:`\*.py` and add the corresponding file to the archive.
334-
The corresponding file is a :file:`\*.pyo` file if available, else a
335-
:file:`\*.pyc` file, compiling if necessary. If the pathname is a file, the
336-
filename must end with :file:`.py`, and just the (corresponding
337-
:file:`\*.py[co]`) file is added at the top level (no path information). If the
338-
pathname is a file that does not end with :file:`.py`, a :exc:`RuntimeError`
339-
will be raised. If it is a directory, and the directory is not a package
340-
directory, then all the files :file:`\*.py[co]` are added at the top level. If
341-
the directory is a package directory, then all :file:`\*.py[co]` are added under
342-
the package name as a file path, and if any subdirectories are package
343-
directories, all of these are added recursively. *basename* is intended for
344-
internal use only. The :meth:`writepy` method makes archives with file names
345-
like this::
346-
347-
string.pyc # Top level name
348-
test/__init__.pyc # Package directory
349-
test/testall.pyc # Module test.testall
350-
test/bogus/__init__.pyc # Subpackage directory
351-
test/bogus/myfile.pyc # Submodule test.bogus.myfile
329+
:class:`ZipFile` constructor, and one additional parameter, *optimize*.
330+
331+
.. class:: PyZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=False, \
332+
optimize=-1)
333+
334+
.. versionadded:: 3.2
335+
The *optimize* parameter.
336+
337+
Instances have one method in addition to those of :class:`ZipFile` objects:
338+
339+
.. method:: PyZipFile.writepy(pathname, basename='')
340+
341+
Search for files :file:`\*.py` and add the corresponding file to the
342+
archive.
343+
344+
If the *optimize* parameter to :class:`PyZipFile` was not given or ``-1``,
345+
the corresponding file is a :file:`\*.pyo` file if available, else a
346+
:file:`\*.pyc` file, compiling if necessary.
347+
348+
If the *optimize* parameter to :class:`PyZipFile` was ``0``, ``1`` or
349+
``2``, only files with that optimization level (see :func:`compile`) are
350+
added to the archive, compiling if necessary.
351+
352+
If the pathname is a file, the filename must end with :file:`.py`, and
353+
just the (corresponding :file:`\*.py[co]`) file is added at the top level
354+
(no path information). If the pathname is a file that does not end with
355+
:file:`.py`, a :exc:`RuntimeError` will be raised. If it is a directory,
356+
and the directory is not a package directory, then all the files
357+
:file:`\*.py[co]` are added at the top level. If the directory is a
358+
package directory, then all :file:`\*.py[co]` are added under the package
359+
name as a file path, and if any subdirectories are package directories,
360+
all of these are added recursively. *basename* is intended for internal
361+
use only. The :meth:`writepy` method makes archives with file names like
362+
this::
363+
364+
string.pyc # Top level name
365+
test/__init__.pyc # Package directory
366+
test/testall.pyc # Module test.testall
367+
test/bogus/__init__.pyc # Subpackage directory
368+
test/bogus/myfile.pyc # Submodule test.bogus.myfile
352369

353370

354371
.. _zipinfo-objects:

Include/compile.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ typedef struct {
2929
#define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL"
3030

3131
struct _mod; /* Declare the existence of this type */
32-
PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,
33-
PyCompilerFlags *, PyArena *);
32+
#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar)
33+
PyAPI_FUNC(PyCodeObject *) PyAST_CompileEx(struct _mod *, const char *,
34+
PyCompilerFlags *, int, PyArena *);
3435
PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST(struct _mod *, const char *);
3536

3637

Include/pythonrun.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ PyAPI_FUNC(PyObject *) PyRun_FileExFlags(FILE *, const char *, int,
7676
#ifdef Py_LIMITED_API
7777
PyAPI_FUNC(PyObject *) Py_CompileStringFlags(const char *, const char *, int);
7878
#else
79-
#define Py_CompileString(str, p, s) Py_CompileStringFlags(str, p, s, NULL)
80-
PyAPI_FUNC(PyObject *) Py_CompileStringFlags(const char *, const char *, int,
81-
PyCompilerFlags *);
79+
#define Py_CompileString(str, p, s) Py_CompileStringExFlags(str, p, s, NULL, -1)
80+
#define Py_CompileStringFlags(str, p, s, f) Py_CompileStringExFlags(str, p, s, f, -1)
81+
PyAPI_FUNC(PyObject *) Py_CompileStringExFlags(const char *, const char *, int,
82+
PyCompilerFlags *, int);
8283
#endif
8384
PyAPI_FUNC(struct symtable *) Py_SymtableString(const char *, const char *, int);
8485

Lib/compileall.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
__all__ = ["compile_dir","compile_file","compile_path"]
2121

22-
def compile_dir(dir, maxlevels=10, ddir=None,
23-
force=False, rx=None, quiet=False, legacy=False):
22+
def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
23+
quiet=False, legacy=False, optimize=-1):
2424
"""Byte-compile all modules in the given directory tree.
2525
2626
Arguments (only dir is required):
@@ -32,6 +32,7 @@ def compile_dir(dir, maxlevels=10, ddir=None,
3232
force: if True, force compilation, even if timestamps are up-to-date
3333
quiet: if True, be quiet during compilation
3434
legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
35+
optimize: optimization level or -1 for level of the interpreter
3536
"""
3637
if not quiet:
3738
print('Listing', dir, '...')
@@ -51,7 +52,8 @@ def compile_dir(dir, maxlevels=10, ddir=None,
5152
else:
5253
dfile = None
5354
if not os.path.isdir(fullname):
54-
if not compile_file(fullname, ddir, force, rx, quiet, legacy):
55+
if not compile_file(fullname, ddir, force, rx, quiet,
56+
legacy, optimize):
5557
success = 0
5658
elif (maxlevels > 0 and name != os.curdir and name != os.pardir and
5759
os.path.isdir(fullname) and not os.path.islink(fullname)):
@@ -61,14 +63,15 @@ def compile_dir(dir, maxlevels=10, ddir=None,
6163
return success
6264

6365
def compile_file(fullname, ddir=None, force=0, rx=None, quiet=False,
64-
legacy=False):
66+
legacy=False, optimize=-1):
6567
"""Byte-compile file.
6668
fullname: the file to byte-compile
6769
ddir: if given, purported directory name (this is the
6870
directory name that will show up in error messages)
6971
force: if True, force compilation, even if timestamps are up-to-date
7072
quiet: if True, be quiet during compilation
7173
legacy: if True, produce legacy pyc paths instead of PEP 3147 paths
74+
optimize: optimization level or -1 for level of the interpreter
7275
"""
7376
success = 1
7477
name = os.path.basename(fullname)
@@ -84,7 +87,11 @@ def compile_file(fullname, ddir=None, force=0, rx=None, quiet=False,
8487
if legacy:
8588
cfile = fullname + ('c' if __debug__ else 'o')
8689
else:
87-
cfile = imp.cache_from_source(fullname)
90+
if optimize >= 0:
91+
cfile = imp.cache_from_source(fullname,
92+
debug_override=not optimize)
93+
else:
94+
cfile = imp.cache_from_source(fullname)
8895
cache_dir = os.path.dirname(cfile)
8996
head, tail = name[:-3], name[-3:]
9097
if tail == '.py':
@@ -101,7 +108,8 @@ def compile_file(fullname, ddir=None, force=0, rx=None, quiet=False,
101108
if not quiet:
102109
print('Compiling', fullname, '...')
103110
try:
104-
ok = py_compile.compile(fullname, cfile, dfile, True)
111+
ok = py_compile.compile(fullname, cfile, dfile, True,
112+
optimize=optimize)
105113
except py_compile.PyCompileError as err:
106114
if quiet:
107115
print('*** Error compiling', fullname, '...')
@@ -126,7 +134,7 @@ def compile_file(fullname, ddir=None, force=0, rx=None, quiet=False,
126134
return success
127135

128136
def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=False,
129-
legacy=False):
137+
legacy=False, optimize=-1):
130138
"""Byte-compile all module on sys.path.
131139
132140
Arguments (all optional):
@@ -136,6 +144,7 @@ def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=False,
136144
force: as for compile_dir() (default False)
137145
quiet: as for compile_dir() (default False)
138146
legacy: as for compile_dir() (default False)
147+
optimize: as for compile_dir() (default -1)
139148
"""
140149
success = 1
141150
for dir in sys.path:
@@ -144,7 +153,7 @@ def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=False,
144153
else:
145154
success = success and compile_dir(dir, maxlevels, None,
146155
force, quiet=quiet,
147-
legacy=legacy)
156+
legacy=legacy, optimize=optimize)
148157
return success
149158

150159

Lib/py_compile.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def wr_long(f, x):
7272
(x >> 16) & 0xff,
7373
(x >> 24) & 0xff]))
7474

75-
def compile(file, cfile=None, dfile=None, doraise=False):
75+
def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1):
7676
"""Byte-compile one Python source file to Python bytecode.
7777
7878
:param file: The source file name.
@@ -86,6 +86,10 @@ def compile(file, cfile=None, dfile=None, doraise=False):
8686
will be printed, and the function will return to the caller. If an
8787
exception occurs and this flag is set to True, a PyCompileError
8888
exception will be raised.
89+
:param optimize: The optimization level for the compiler. Valid values
90+
are -1, 0, 1 and 2. A value of -1 means to use the optimization
91+
level of the current interpreter, as given by -O command line options.
92+
8993
:return: Path to the resulting byte compiled file.
9094
9195
Note that it isn't necessary to byte-compile Python modules for
@@ -111,7 +115,8 @@ def compile(file, cfile=None, dfile=None, doraise=False):
111115
timestamp = int(os.stat(file).st_mtime)
112116
codestring = f.read()
113117
try:
114-
codeobject = builtins.compile(codestring, dfile or file,'exec')
118+
codeobject = builtins.compile(codestring, dfile or file, 'exec',
119+
optimize=optimize)
115120
except Exception as err:
116121
py_exc = PyCompileError(err.__class__, err, dfile or file)
117122
if doraise:
@@ -120,7 +125,10 @@ def compile(file, cfile=None, dfile=None, doraise=False):
120125
sys.stderr.write(py_exc.msg + '\n')
121126
return
122127
if cfile is None:
123-
cfile = imp.cache_from_source(file)
128+
if optimize >= 0:
129+
cfile = imp.cache_from_source(file, debug_override=not optimize)
130+
else:
131+
cfile = imp.cache_from_source(file)
124132
try:
125133
os.makedirs(os.path.dirname(cfile))
126134
except OSError as error:

0 commit comments

Comments
 (0)