From 6f88e453cbb532dc772b489d3f41dabbc51fc8a4 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Fri, 12 Oct 2018 13:04:27 -0400 Subject: [PATCH 1/2] bpo-23892: Introduce sys.implementation.opt_levels --- Doc/library/sys.rst | 5 ++ Lib/test/support/__init__.py | 2 +- Lib/test/test_sys.py | 1 + Lib/zipfile.py | 75 +++++++------------ .../2018-10-12-13-03-04.bpo-23892.ttyikM.rst | 1 + Python/sysmodule.c | 5 ++ 6 files changed, 41 insertions(+), 48 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-10-12-13-03-04.bpo-23892.ttyikM.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 46d8db0230b8a4..2aac95484bf6d2 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -814,6 +814,11 @@ always available. ``cache_tag`` is set to ``None``, it indicates that module caching should be disabled. + *opt_levels* is a tuple containing the available compiler-supported + optimization levels. See :pep:`488` for more information. + + .. versionadded:: 3.8 + :data:`sys.implementation` may contain additional attributes specific to the Python implementation. These non-standard attributes must start with an underscore, and are not described here. Regardless of its contents, diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index ed0d46de6426d6..abd1c3184d8631 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -472,7 +472,7 @@ def forget(modname): # It doesn't matter if they exist or not, unlink all possible # combinations of PEP 3147/488 and legacy pyc files. unlink(source + 'c') - for opt in ('', 1, 2): + for opt in sys.implementation.opt_levels: unlink(importlib.util.cache_from_source(source, optimization=opt)) # Check whether a gui is actually available diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index b90366d814452b..26de670be11986 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -736,6 +736,7 @@ def test_implementation(self): self.assertTrue(hasattr(sys.implementation, 'version')) self.assertTrue(hasattr(sys.implementation, 'hexversion')) self.assertTrue(hasattr(sys.implementation, 'cache_tag')) + self.assertTrue(hasattr(sys.implementation, 'opt_levels')) version = sys.implementation.version self.assertEqual(version[:2], (version.major, version.minor)) diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 4a6b40ee441c6f..9ebc5ea702bc24 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -2034,63 +2034,44 @@ def _compile(file, optimize=-1): return False return True + def _check_cache(pycache, file): + return (os.path.isfile(pycache) and + os.stat(pycache).st_mtime >= os.stat(file).st_mtime) + file_py = pathname + ".py" file_pyc = pathname + ".pyc" - pycache_opt0 = importlib.util.cache_from_source(file_py, optimization='') - pycache_opt1 = importlib.util.cache_from_source(file_py, optimization=1) - pycache_opt2 = importlib.util.cache_from_source(file_py, optimization=2) + + pycache_opt = [importlib.util.cache_from_source(file_py, optimization=opt) + for opt in sys.implementation.opt_levels] if self._optimize == -1: # legacy mode: use whatever file is present - if (os.path.isfile(file_pyc) and - os.stat(file_pyc).st_mtime >= os.stat(file_py).st_mtime): + if _check_cache(file_pyc, file_py): # Use .pyc file. arcname = fname = file_pyc - elif (os.path.isfile(pycache_opt0) and - os.stat(pycache_opt0).st_mtime >= os.stat(file_py).st_mtime): - # Use the __pycache__/*.pyc file, but write it to the legacy pyc - # file name in the archive. - fname = pycache_opt0 - arcname = file_pyc - elif (os.path.isfile(pycache_opt1) and - os.stat(pycache_opt1).st_mtime >= os.stat(file_py).st_mtime): - # Use the __pycache__/*.pyc file, but write it to the legacy pyc - # file name in the archive. - fname = pycache_opt1 - arcname = file_pyc - elif (os.path.isfile(pycache_opt2) and - os.stat(pycache_opt2).st_mtime >= os.stat(file_py).st_mtime): - # Use the __pycache__/*.pyc file, but write it to the legacy pyc - # file name in the archive. - fname = pycache_opt2 - arcname = file_pyc else: - # Compile py into PEP 3147 pyc file. - if _compile(file_py): - if sys.flags.optimize == 0: - fname = pycache_opt0 - elif sys.flags.optimize == 1: - fname = pycache_opt1 - else: - fname = pycache_opt2 - arcname = file_pyc + for pycache in pycache_opt: + if _check_cache(pycache, file_py): + # Use the __pycache__/*.pyc file, but write it to the legacy pyc + # file name in the archive. + fname = pycache + arcname = file_pyc + break else: - fname = arcname = file_py + # Compile py into PEP 3147 pyc file. + if _compile(file_py): + fname = pycache_opt[sys.flags.optimize] + arcname = file_pyc + else: + fname = arcname = file_py else: # new mode: use given optimization level - if self._optimize == 0: - fname = pycache_opt0 - arcname = file_pyc - else: - arcname = file_pyc - if self._optimize == 1: - fname = pycache_opt1 - elif self._optimize == 2: - fname = pycache_opt2 - else: - msg = "invalid value for 'optimize': {!r}".format(self._optimize) - raise ValueError(msg) - if not (os.path.isfile(fname) and - os.stat(fname).st_mtime >= os.stat(file_py).st_mtime): + arcname = file_pyc + try: + fname = pycache_opt[self._optimize] + except IndexError: + msg = "invalid value for 'optimize': {!r}".format(self._optimize) + raise ValueError(msg) + if not _check_cache(fname, file_py): if not _compile(file_py, optimize=self._optimize): fname = arcname = file_py archivename = os.path.split(arcname)[1] diff --git a/Misc/NEWS.d/next/Library/2018-10-12-13-03-04.bpo-23892.ttyikM.rst b/Misc/NEWS.d/next/Library/2018-10-12-13-03-04.bpo-23892.ttyikM.rst new file mode 100644 index 00000000000000..6dd8f83078b91c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-10-12-13-03-04.bpo-23892.ttyikM.rst @@ -0,0 +1 @@ +Introduce sys.implementation.opt_levels. diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 58ea60595cd3c0..37b9cb7ef6414f 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2232,6 +2232,11 @@ make_impl_info(PyObject *version_info) if (res < 0) goto error; + res = PyDict_SetItemString(impl_info, "opt_levels", + Py_BuildValue("(sii)", "", 1, 2)); + if (res < 0) + goto error; + #ifdef MULTIARCH value = PyUnicode_FromString(MULTIARCH); if (value == NULL) From 8247004f315541ccee9a9baec16e72615ff96ce1 Mon Sep 17 00:00:00 2001 From: Cheryl Sabella Date: Wed, 27 Mar 2019 10:51:30 -0400 Subject: [PATCH 2/2] Correction for refleak. --- Python/sysmodule.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 37b9cb7ef6414f..306417833dc271 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2232,8 +2232,11 @@ make_impl_info(PyObject *version_info) if (res < 0) goto error; - res = PyDict_SetItemString(impl_info, "opt_levels", - Py_BuildValue("(sii)", "", 1, 2)); + value = Py_BuildValue("(sii)", "", 1, 2); + if (value == NULL) + goto error; + res = PyDict_SetItemString(impl_info, "opt_levels", value); + Py_DECREF(value); if (res < 0) goto error;