* fast locals proxy never assumes the value cache is already up to date
* operations become O(n) as required to avoid that assumption
* remove `*View()` APIs from proposal due to algorithmic complexity issue
* add Python pseudo-code to the PEP 667 comparison section
* reword PEP 667 comparison section to focus on the remaining differences
in the C API proposal
* address remaining review comments from the July threads
* Rationale section renamed to Motivation
* Design Discussion section renamed to Rationale and Design Discussion
* kind enum is guaranteed to be at least 32 bits
* fast refs mapping is stored on the underlying frame
* delay initial cache refresh for each proxy instance to the
first operation that needs it
* be specific about which operations always update the cache, and which
update it if it hasn't been updated by this proxy instance
* eliminate more mentions of the old "dynamic snapshot" terminology
* add new rational/discussion section covering PEP 667 (including
how the PEP 558 implementation could be turned into a PEP 667
implementation if desired)
* make it clearer that proxy instances are ephemeral (lots of
stale phrasing with "the" dating from when they stored on the frame)
Co-authored-by: Hugo van Kemenade <hugovk@users.noreply.github.com>
- Fix miscellaneous typos
- Remove an outdated mention of possibly dropping suport for storing
extra f_locals keys in optimised scopes
- Make it more explicit that accessing frame.f_locals in Python
refreshes the f_locals cache on that frame
- Replace GetReturnsCopy with GetKind & other updates
- Reference Jan/Feb 2021 python-dev threads
- Note that read-only views on optimised frames have
the same cache consistency limitations as the read/write
proxy does.
Further implementation work on the fast locals proxy resulted
in treating the "f_locals" frame storage more as an implicitly
or explicitly updated cache, rather than treating it solely as a
dynamic snapshot.
* `pdb` stores `__return__` and `__exception__`` entries on
arbitrary frames, so that feature needs to be preserved
* Some fast locals proxy operations will implicitly update the
underlying shared mapping on the frame
* Anyone explicitly calling `LocalsToFast` is going to want the
read/write proxy, not any of the read-only options (plus it's
hard to fit an essay in an error message)
* Remove lingering reference to the removed `PyLocals_RefreshViews()`
Changes detected by Topy (https://github.com/intgr/topy), all changes
verified by hand, false positives have been omitted.
These range from straight-out misspellings to debatable hyphen placement.
The hyphen changes are supported by grammar manuals of style.
The initial version of the PEP entrenched the tracing mode distinction,
and was worded accordingly.
Now that tracing mode is only relevant as a historical artifact that is
being eliminated, the wording should make that clear.
Also removes a stale mention of Python 3.9.
Also removes the exec() and eval() caveats on the reference implementation
(those have been migrated now, albeit not using a code structure that we
would genuinely want to merge).
When updating the PEP to specify independent snapshots for locals()
at function scope, I missed this reference to the old semantics
that returned a direct reference to the dynamic internal snapshot.
* Switch to independent snapshots at function scope
* New public C API, PyEval_Get_PyLocals(), that matches the updated locals() builtin
* At function scope, PyEval_GetLocals() returns the internal shared mapping from inside the proxy (returning a borrowed reference means this API can't offer the new independent snapshot semantics)
- new design discussion section to cover the requirement that the
semantics of locals() itself at function scope be left alone
- propose a C level API that exactly matches Python level
frame.f_locals semantics
- other minor text formatting and wording updates
Changing the frame API semantics based on whether or not a
tracing function is active is tricky to implement and hard
to document clearly, so this simplifies the proposal by
instead having the frame API always expose a write-through
proxy at function scope, and restricting the dynamic
snapshot behaviour to the locals() builtin.
It turns out that *any* write-back based design has
inherent flaws that make it difficult to build a source
debugger that reliably allows mutation of function local
variables.
So this switches to Nathaniel's suggested write-through
proxy idea, but constrains it to only applying when a
trace hook is installed. This means the official language
level semantics can just use the simpler model where
rebinding function local variables via locals() simply
isn't possible - only folks already working with frames
and trace functions will need to be aware of the semantics
of the write-through proxy.
We should be able to resolve the reported problems just
by changing how trace hooks work, rather than making
any fundamental changes to locals() or frame.f_locals.
- new open questions around how storage and updates
will work
- note that we definitely *don't* want to return the
write-through proxy from locals() at function scope