-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
Description
Bug report
Bug description:
timeit
crashes when using wildcard imports in either the "setup" or "statement" fields.
$ python -m timeit -s "from collections import Counter" -- "Counter([1, 2])" # allowed
1000000 loops, best of 5: 277 nsec per loop
$ python -m timeit -s "from collections import *" -- "Counter([1, 2])" # cashes
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "Lib/timeit.py", line 378, in <module>
sys.exit(main())
~~~~^^
File "Lib/timeit.py", line 316, in main
t = Timer(stmt, setup, timer)
File "Lib/timeit.py", line 132, in __init__
code = compile(src, dummy_src_name, "exec")
File "<timeit-src>", line 3
SyntaxError: import * only allowed at module level
This is surprising as this syntax is allowed in other contexts where code strings are executed (namely exec
and python -c
). The cause is code strings are placed inside a wrapper function that performs the timing here.
The git history of the timeit
tests show 2bef585 explicitly added a test for this behavior, but based on the commit message / corresponding issue (GH #62718) I'm not sure if this is indeed the intended behavior. The comments seem to focus on statements that would effect a timing result (e.g., break
ending a loop early or return
changing the timed value), which I don't think applies to wild card imports.
Extra history: #46779 discussed this briefly in the context of from __main__ import *
and the performance implications of wildcard imports when namespace arguments were first introduced.
Allowing wildcard imports in both stages would be great to bring unity with the other exec-likes and make CLI usage nicer, but the argument for statement
is weaker than setup
.
Potential options
- move
setup
to outsideinner
and updateglobals
andlocals
to be the same whenexec
is called on the code-object.- doesn't allow wildcards in
statement
- any variable created in setup requires a global namespace lookup which adds overhead
setup
would be ran exactly once, so breaks methods that repeat with randomization
- doesn't allow wildcards in
- remove
inner
and instead callexec
whereinner
was called, and either move the timing code bits to outsideexec
or extract the timed value from theexec
namespace.- supports wildcard imports in both code strings
- variable access seems to be through
LOAD_NAME
instead ofLOAD_FAST
which may have a overhead? - significantly more invasive to the existing code
- do nothing and leave the mismatch. PEP8 / the docs discourage wildcard imports anyway.
CPython versions tested on:
CPython main branch
Operating systems tested on:
macOS