-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
bpo-23892: Introduce sys.implementation.opt_levels #9826
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3.9 now :) |
||
|
||
: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, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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')) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, we should probably also make sure that no other required attrs exist. (We could parameterize this part at the same time.) required = [attr for attr in dir(sys.implementation) if not attr.startswith('_')]
expected = ['name', 'version', 'hexversion', 'cache_tag', 'opt_levels']
self.assertCountEqual(required, expected)
# Make sure (best effort) that sys.implementation.__dir__() is correct.
for attr in expected:
self.assertTrue(hasattr(sys.implementation, attr)) We should also make sure that self.assertIs(type(sys.implementation.opt_levels), tuple, sys.implementation.opt_levels)
for opt in sys.implementation.opt_levels:
if type(opt) is int:
self.assertTrue(opt.isalnum(), opt)
else:
self.assertIs(type(opt), int, opt)
self.assertGreaterEqual(opt, 0) |
||
version = sys.implementation.version | ||
self.assertEqual(version[:2], (version.major, version.minor)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2034,63 +2034,44 @@ def _compile(file, optimize=-1): | |
return False | ||
return True | ||
|
||
def _check_cache(pycache, file): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! I think even if this ends up not being in sys.implementation, these changes in zipfile still might be worth adding to simplify the code. |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This "break" implies that the order of If we end up sticking with opt levels as currently used then the importance of order should be made clear in the docs. |
||
else: | ||
fname = arcname = file_py | ||
# Compile py into PEP 3147 pyc file. | ||
if _compile(file_py): | ||
fname = pycache_opt[sys.flags.optimize] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this catch the IndexError and fall back FWIW, this code implies that Also, PEP 488 opens that door for dealing with sets of optimizations (either as a container of strings/ints or as a hash of them). This code would fall apart then. We can discuss this more on the BPO issue. |
||
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] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Introduce sys.implementation.opt_levels. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that mentioning the possible values, and the relation to the "optimization" parameter of
importlib.util.cache_from_source()
, is perhaps warranted here (in addition to linking to PEP-488).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
The relationship between
sys.flags.optimize
and that "optimization" parameter (as well as the "optimize" parameter ofcompile()
) reflects a gap in the solution presented by PEP 488. That needs to be resolved.