Plugin installer: upgrading a plugin drops the constraint on Postulo's own packages it was installed with #598
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#598
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, readingpin_ownersandconstraints, runninguv pip install --targetoffline into a scratch folder, and running the constraint functions against a temporary plugins directory.Checked again on 2026-10-01 against
mainat0a5cad587: still present. The code is now atplugins/installing.py:281-304(pin_owners; the pop the fix speaks of, formerly lines 474-476, is at :300-302),plugins/installing.py:307-328(constraints),plugins/installing.py:351-390(conflicts_with_core) andplugins/installing.py:783-790(where the copies are recorded); thesite.addsitedircall moved toplugins/record.py:89(activate, #248).uv pip install --targetinstalls a plugin's whole dependency tree into the plugins directory, including copies of packages Postulo already has (an offline run forhttpxlaid downhttpx,httpcore,anyio,h11,idna,certifiandtyping_extensions, pinned to Postulo's versions by the constraint file).install_wheelrecords those copies as the plugin's dependencies.pin_owners()cannot tell Postulo's pins from those copies, so on that plugin's next upgrade it drops the constraint on Postulo's own packages, and the promise in the module docstring that "a plugin can never change the version of something Postulo itself depends on. The refusal names the package" does not hold. Related to #246 (closed), which built the ownership table.plugins/installing.py:455-478(pin_owners: every entry ofmetadata.distributions(), the plugins directory included, becomes owner"", and lines 474-476 pop any package the plugin being installed brought whose owner is""),plugins/installing.py:481-502(constraints),plugins/installing.py:525-564(conflicts_with_core), andplugins/installing.py:957-964(where the copies are recorded).httpx>=0.28. Installing either recordshttpx==0.28.1(and the rest of the tree) as its dependencies. Checked in the snapshot: before the installconstraints(exclude="plug-a")heldhttpx==0.28.1; after it, it held nohttpxpin,conflicts_with_corefor a plug-a 1.1 needinghttpx==0.30.0returned nothing, and for a different plugin needing it returned "httpx: needs 0.30.0, and plug-a has 0.28.1." So the upgrade is not refused; the installer puts the newerhttpxin the plugins directory, whichsite.addsitedirappends after site-packages, so both the import check and every worker go on loading Postulo's older copy. The plugin fails later, at the first call that needs the newer version, while the record and the page say the newer one is installed. For every other plugin the refusal names the first plugin instead of Postulo.plugins_dir()(comparedistribution.locate_file("")with the directory), never drop those for the plugin being installed, and limit the pop at lines 474-476 to packages that exist only in the plugins directory. Optionally leave out of the record, or avoid installing, packages the core environment already satisfies.Done when
tests/test_plugin_rollback.pyhas a test that, after installing a plugin whose recorded dependencies include a package Postulo itself provides,constraints(exclude=<that plugin>)still pins Postulo's version andconflicts_with_corerefuses an upgrade needing another version with the "Postulo has" wording.