#301528·homebrew-core

[email protected]: sitecustomize.py imports `re` at startup, costing ~12% of interpreter start time

Author: namaserajeshCreated Aug 31, 2026Updated Aug 31, 2026

brew config AND brew doctor output OR brew gist-logs <formula> link

brew config
HOMEBREW_VERSION: 6.0.20
ORIGIN: https://github.com/Homebrew/brew
HEAD: 3e3da86e4eaccd23f4ce43df9b0a31b16c707347
Last commit: 4 days ago
Branch: stable
Core tap: N/A
Core cask tap: N/A
HOMEBREW_PREFIX: /opt/homebrew
Homebrew Ruby: 4.0.6 => /opt/homebrew/Library/Homebrew/vendor/portable-ruby/4.0.6/bin/ruby
CPU: octa-core 64-bit arm_ibiza
Clang: 21.0.0 build 2100
Git: 2.50.1 => /Library/Developer/CommandLineTools/usr/bin/git
Curl: 8.7.1 => /usr/bin/curl
macOS: 26.6.2-arm64
CLT: 26.6.0.0.1781586589
Xcode: N/A
Rosetta 2: false
brew doctor
Warning: The following taps are not trusted:
  anomalyco/tap
  updatest/tap

This is the only warning. It concerns trust for two third-party taps and is unrelated to [email protected] interpreter startup timing — the measurements below use python3 -c pass, which touches no tap.

Verification

  • My brew doctor output says Your system is ready to brew. and am still able to reproduce my issue. Not ticked, honestly: the only warning is tap-trust for two third-party taps (above), which cannot affect python3 -c pass startup.
  • I ran brew update and am still able to reproduce my issue.
  • I have resolved all warnings from brew doctor and that did not fix my problem. Not ticked: the remaining warnings are the tap-trust ones above; resolving them would not change interpreter startup.
  • I searched for recent similar issues at https://github.com/Homebrew/homebrew-core/issues?q=is%3Aissue and found no duplicates.
  • My issue is not about a failure to build a formula from source.
  • I did not use AI/LLM to create this issue, or I disclosed the tool and model used; I will answer maintainer questions myself without AI/LLM. Disclosure: this report was drafted with Claude Code (Anthropic, Claude Opus 5). All measurements below were run on my machine and are reproducible with the commands given. I will answer maintainer questions myself.

What were you trying to do (and why)?

Reduce Python interpreter startup time. A local test suite spawns roughly 1,320 processes per run, so per-process startup cost is multiplied heavily. Profiling python3 startup pointed at Homebrew's generated sitecustomize.py.

What happened (include all command output)?

sitecustomize.py — generated by the formula and executed on every interpreter start — does a module-level import re (line 4), solely to compile two path-rewriting regexes. re is a relatively expensive import.

bash
$ python3 -X importtime -c pass 2>&1 | grep -E ' re$| sitecustomize$| site$'
import time:       236 |       2672 |     re
import time:       485 |       3156 |   sitecustomize
import time:       388 |       5142 | site

re accounts for 2,672 µs of sitecustomize's 3,156 µs — about 85% of what sitecustomize costs.

Wall-clock, 200 iterations each:

bash
python3 -c pass      : 21.30 ms
python3 -S -c pass   : 13.47 ms   (site processing skipped)
site machinery       :  7.83 ms   (37% of startup)

The re import alone is roughly 12.5% of a bare interpreter start.

Both regex call sites sit inside branches that are always true for a brewed Python, so simply deferring the import to point of use would not help the common case:

  • lines 28-29 — long_prefix, inside if os.path.realpath(sys.executable).startswith('/opt/homebrew/Cellar/[email protected]')
  • line 35 — cellar_prefix, inside if 'PYTHONHOME' not in os.environ

What did you expect to happen?

That a bare python3 -c pass would not spend ~12% of its startup importing re on behalf of sitecustomize, given the regexes rewrite only a handful of sys.path entries.

I prototyped a string-only equivalent and property-tested it over 153 generated inputs (version shapes 3.14.7, 3.14.10_1, 3.14.0rc1, 3.14.0a1, 3.14.0b2; both Frameworks/... and plain lib/... layouts; plus non-matching and malformed paths) — 0 mismatches.

I am deliberately not proposing it as a patch, because it is not strictly equivalent: re.sub substitutes anywhere in the string and repeatedly, a prefix-based string version does not. Counterexample:

input:  /some/prefix/opt/homebrew/Cellar/[email protected]/3.14.7/lib/python3.14/site-packages
regex:  /some/prefix/opt/homebrew/lib/python3.14/site-packages
string: (unchanged)

Whether such a sys.path entry can legitimately occur is a question about the formula's intent, which maintainers are better placed to answer than I am.

Possible directions, in case any is useful:

  1. Replace the regexes with string operations, if prefix-only matching is acceptable.
  2. Bake the concrete version string into the generated file at install time — the formula already knows it — reducing this to str.replace.
  3. Guard the work so re is imported only when a sys.path entry actually needs rewriting.

Happy to test any of these here and report numbers.

Step-by-step reproduction instructions (by running brew commands)

bash
$ brew install [email protected]
$ python3 -X importtime -c pass 2>&1 | grep -E ' re$| sitecustomize$| site$'
$ # compare against site processing being skipped:
$ python3 -c pass        # ~21.3 ms here
$ python3 -S -c pass     # ~13.5 ms here

Inspect the file directly:

bash
$ sed -n '1,10p;28,29p;35p' "$(brew --prefix [email protected])/Frameworks/Python.framework/Versions/3.14/lib/python3.14/sitecustomize.py"