Every plugin Postulo ships is its own package, core included #129
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
Depends on
#125 The dashboard is a grid a person arranges by dragging
Postulo/postulo
#133 A document is a kind, and a kind is a plugin
Postulo/postulo
#149 Mail has two halves: the instance's and the person's
Postulo/postulo
Reference
Postulo/postulo#129
Loading…
Add table
Add a link
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?
Observation
What exists
Three parts to the imperative, and they are in three different states.
Manifests: done. #97 and #98 settled it. Every built-in declares one through
@declares(shipped(...)), andtests/test_plugin_manifests.pywalks all seven and fails onone that says nothing about itself.
manifest_of()looks in the manifest, then the looseattributes plugins used before there was one, then the wheel the plugin was installed from.
Locale: false for every plugin Postulo ships.
docs/PLUGINS.mdsays a plugin's stringsare never added to Postulo's catalogues. There is one locale directory in the repository
and every built-in's strings are in it, translated into 39 languages as part of Postulo's
own release.
Independence: not attempted, and unevenly possible. Where the built-ins actually live:
postuloschema.org,page-metadataplugins/builtin.pyeuropassresume/importers.pytemplates/resume/email,smtpnotifications/localdocuments/stores.pyphone-numberscore/features.pyThe two sources are already what the imperative describes. The feature is the furthest from
it, and it is the newest, which says something about which direction the code drifts when
nothing pulls the other way.
What this asks for
Every plugin Postulo ships becomes its own package: its own manifest (has one), its own
locale/, its own templates, its own registration through an entry point, and imports onlyfrom a declared surface rather than from wherever in core the thing happens to be.
Worth being careful about
"As self-contained as possible" is the operative phrase, and where the line falls is the
work. A plugin holding one person's data must scope it with
for_user()or it breaks theproject's first promise. One that renders must extend the base template or it renders
unstyled. Those are reasons to depend on Postulo, not failures of discipline — which is why
the first prerequisite is a named surface rather than a rule against importing.
A rule nobody checks drifts back.
phone-numberswas written a week ago, entirelyinside core, by somebody who had just read the plugin documentation. That is the argument
for a test that walks each built-in package and fails on an import past the surface — the
same shape as the manifest test that already exists.
Staging is available and worth taking. The two sources satisfy the imperative today; the
importer and the transport hold no data and could follow with only the surface and the
locale questions answered. Only the store, the notifier and the feature need the data
question settled first, so this need not be one large change.
Moving a template moves a translation. Extracted strings are keyed by their source
location; moving a built-in's templates and modules into a package rewrites references
throughout all 39 catalogues even where no string changes. That is churn the catalogues
already tolerate, but it wants to happen in one commit per plugin, not spread over several.
shipped()says these are Postulo's, taking the version, author, licence and source URLfrom the application. That is truthful for a built-in and worth keeping when it moves: a
package that ships inside the image is not a third party and should not claim to be one.
#125 changes because of this. That issue offers a cheap answer for "internal widgets
plugin" — name the existing registry as one and give it an entry point when third parties
arrive. Under this imperative that answer is no longer available: seventeen widgets, each
with its own template and context, would be seventeen packages or one, and either way the
locale and surface questions arrive with them.
This is not a user-visible change, which makes it the kind of work that is easy to
justify and easy to leave half-finished. The measure of it is not that the directories
moved: it is that the next
phone-numberscannot be written inside core without a testsaying so.
Seven plugins, six packages, and a test that takes its list from the registry.
The issue named the measure and this meets it: "it is that the next
phone-numberscannot be written inside core without a test saying so."
tests/test_plugin_surface.pynowasks
registry.builtins()what Postulo ships rather than holding a list — so a built-inadded tomorrow is checked tomorrow, including the one nobody remembers to add to a list. It
fails on a plugin outside
postulo.plugins, on one with no catalogues of its own, on onethat imports a model, and on one that imports anything else from Postulo without a written
reason. 33 tests.
Nothing Postulo ships touches the database now
That is the result worth having, and it came from drawing two lines the code had already
argued for.
The career record.
Record's own docstring says "a career record, in Postulo's termsrather than Europass's". So Postulo defines it: it moved to
postulo.resume.importingalong with
apply(), whichresume/importers.pyhad already said belonged there —"
apply()stays in core and deliberately: an importer turns bytes into a record and doesnot touch the database." The plugin fills in a record it does not own, and the next
importer somebody writes fills in the same one. Two model imports gone.
The store contract.
DocumentMetadata,ExternalRefandStorePluginare what a storeauthor writes against, and
docs/PLUGINS.mdwas pointing them atpostulo.documents.stores— a module the surface promise does not cover. They are part of
postulo.plugins.apinow,and the local store imports them from where everybody else does.
Ownership scoping done wrong in a plugin is how one person sees another's data. The way not
to get it wrong in seven places is not to need it in seven places.
The five warnings
"As self-contained as possible" is the operative phrase. Four dependencies went away;
five remain and are recorded with what each is for —
sitefor the notifier's from-address,mailanddestinationsfor the transport (#148),download_pathfor the store, theidentifier schemes and the record for the importer. Each is a reason to depend on Postulo,
not a failure of discipline, which is why the surface (#126) came first.
A rule nobody checks drifts back. Checked, and from the registry rather than a list.
Staging was available. Taken, over three commits: #126 the surface, #127 the catalogues,
this one the packages.
Moving a template moves a translation. Twenty-seven strings into six catalogues, each
keeping the translation it already had in all thirty-nine European languages — nothing
retranslated, nothing left English. The completeness test walks every set (#127), so a gap
would have failed rather than gone quiet.
shipped()says these are Postulo's. Unchanged. A package that ships inside the imageis not a third party and does not claim to be one.
One thing declined
Entry points. The issue asked for "its own registration through an entry point"; built-ins
still use
register_builtin(). An entry point would be a slower import of a module in thesame distribution, and it would cost the ordering
docs/PLUGINS.mdpromises — third-partyplugins tried first, Postulo's last, so a plugin somebody writes can take precedence over
ours. Entry points resolve into one list with no way to say after everything else. Nothing
else in the imperative depends on it: the manifest, the catalogues, the templates and the
surface are all in place, and the registration path is the one the locale machinery runs
through either way.
#125 is affected as the issue said: the cheap answer for widgets is gone, and whatever it
becomes now arrives with the locale and surface questions already answered.
3453 tests pass. Shipped in
b3b7adfon0.3.0, withmainkept level.