python / python/cpython

Allow top-level statements in a global pre-setup phase for `timeit`

Open
#137,578 7 comments 0 reactions 1 assignee View on GitHub

@picnixz is already working on this.

Since Aug 9, 2025.

stdlib type-feature
Dominant language
Python
Stars
77.2k
Forks
36k
PR merge metrics
PR metrics pending

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 2bef58577f1caa293a4843f4bdf245407825a61a 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

  1. move setup to outside inner and update globals and locals to be the same when exec 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
  2. remove inner and instead call exec where inner was called, and either move the timing code bits to outside exec or extract the timed value from the exec namespace.
    • supports wildcard imports in both code strings
    • variable access seems to be through LOAD_NAME instead of LOAD_FAST which may have a overhead?
    • significantly more invasive to the existing code
  3. 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

Linked PRs
  • gh-137587

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.