Add inline-script cache key hash utility (PEP 723 PR 1/16)#1634
Open
StellaHuang95 wants to merge 1 commit into
Open
Add inline-script cache key hash utility (PEP 723 PR 1/16)#1634StellaHuang95 wants to merge 1 commit into
StellaHuang95 wants to merge 1 commit into
Conversation
Pure utility for computing a deterministic cache key for a PEP 723
inline-script environment, given the script's declared dependencies
and the chosen Python interpreter path. First foundation PR for
inline-script env support; no behavior impact on its own -- nothing
in the extension calls these helpers yet.
What is in:
- src/common/inlineScriptCacheKey.ts
- normalizeDependency(dep) -- folds common variants of the same
PEP 723 requirement so trivial edits don't fragment the cache:
* PEP 503 name normalization on the project name AND on each
extra: lowercase, then collapse runs of [._-] to a single -.
So `Django` ≡ `django`, `Flask-Login` ≡ `flask_login`,
`requests[Socks]` ≡ `requests[socks]`,
`pkg[socks_5]` ≡ `pkg[socks-5]`.
* Extras are deduplicated and sorted alphabetically after
canonicalization, so `requests[security,socks]` and
`requests[socks,security]` hash to the same key.
* Whitespace around comparison operators is stripped, so
`requests <3` ≡ `requests<3`.
Not a full PEP 508 parser -- only folds the superficial edits
users are likely to make. Pinned-behavior tests document what
is and isn't folded.
- normalizeInterpreterPath(path) -- wraps the existing
normalizePath helper so case/separator differences on Windows
do not fragment the cache. POSIX paths pass through unchanged.
- computeCacheKey({ dependencies, interpreterPath }) -- normalizes
and dedupes deps, sorts, builds a versioned labelled-line
payload, hashes with SHA-256, and truncates to 16 hex characters
(64 bits -- well below practical collision risk for a per-user
cache).
- src/test/common/inlineScriptCacheKey.unit.test.ts -- 37 unit tests
covering the three exports, including pinned-behavior tests for
asymmetries the docstrings call out (trailing whitespace in paths
fragments) and explicit canonicalization tests for extras (PEP 503
folding, sort, dedup, whitespace tolerance, empty-bracket collapse,
composition with version specifiers).
Caller contract
The interpreter path must be absolute and symlink-resolved before
calling computeCacheKey. The function does no I/O, so symlink
canonicalization is the caller's responsibility -- a later PR will
do that at the resolution site.
Design context
Implements the cache-key half of PR 1 in the Phase 1 roadmap of
pep723_design_questions.md. Deps-keyed + interpreter-path-keyed
matches the pipx-style choice in Q4. The PEP 503 extras handling
was added in response to reviewer feedback on the design doc.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Member
|
The normalization approach SGTM. |
This was referenced Jul 15, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Roadmap context
This is PR 1 of 16 in the PEP 723 inline-script roadmap. The full plan lives in #1602.
meta.jsonsidecarrequires-pythonto interpreter selectionInlineScriptEnvManagerskeletoncreate()happy pathcreate()uv-install fallbackget,set, and MementoPRs 1-3 are independent Phase 1 utilities that PR 5 will compose when it implements the environment creation path.
Why this PR
The cache key decides whether a PEP 723 script reuses an existing environment or builds a fresh one. Under the dependency-keyed design from Q4 of #1601, scripts using the same dependencies and interpreter should share an environment.
Trivial metadata edits such as changing package-name casing, separator style, whitespace, dependency order, or extras order should not fragment the cache.
This PR isolates that logic as pure functions with no filesystem access, global storage dependency, or extension activation behavior. The on-disk cache layout remains separate in PR 2.
What this PR does
Adds
src/common/inlineScriptCacheKey.tswith four exports:normalizeDependency(dep)Canonicalizes common variants of the same requirement:
.,_, and-to a single-.Examples:
Djangoanddjangonormalize identically.Flask-Login,flask_login, andflask.loginnormalize identically.requests[Socks,security]becomesrequests[security,socks].requests < 3becomesrequests<3.This is intentionally not a complete PEP 508 parser. Inputs it cannot meaningfully parse remain deterministic without attempting semantic normalization.
normalizeInterpreterPath(interpreterPath)Uses the existing
normalizePathhelper so Windows path casing and separator differences do not fragment the cache. POSIX path casing remains unchanged.computeCacheKey({ dependencies, interpreterPath })The resulting key is deterministic and safe to use as a directory name under the cache root introduced by PR 2.
CACHE_KEY_HEX_LENGTHExposes the key length so callers and tests do not duplicate the value
16.Caller contract
interpreterPathmust be absolute, trimmed, and already resolved through symlinks, for example withfs.realpath().The utility deliberately performs no I/O. Two different path strings that resolve to the same executable will therefore produce different keys unless the caller canonicalizes them first. The creation flow in PR 5 will own that resolution.
Cache behavior
The script path and raw
requires-pythonvalue are intentionally not included directly in the key.requires-pythonon cache hits in case the constraint changes without changing the selected interpreter.This supports the design's two outcomes: reuse an unchanged cache entry or build a fresh environment. There is no in-place dependency synchronization path.
Tests
Adds
src/test/common/inlineScriptCacheKey.unit.test.tswith 37 unit tests covering:Platform behavior is stubbed through
platformUtils, keeping the suite independent of the host operating system.User impact
Zero.
Nothing in the extension calls these helpers yet. This PR adds no settings, commands, UI, logging, filesystem writes, or activation behavior. The utility is wired into environment creation in PR 5.
Design context
This implements the cache-key portion of Q4 in #1601: a pipx-style cache keyed by normalized dependencies and the selected interpreter.
PEP 503 normalization for project names and extras was added in response to review feedback on the design PR.