Short: PyPackages (START/DRAFT)
Most of the AR-components as described in e.g ‘Architectural overview’ are plugins: independent deplorable packages. As there are two views of packages [1], associated by how to use them: (1) import and (2) distribution packages, we need to design this well.
Seen from the ‘4+1 Architectural View Model’ [2] this is part of the “Deployment view”. And as such, a valuable reason to describe & study the options in details
Summary & Conclusions (ToDo)
For those, that are not interested in de design-study, this is the result
The top-level namespace is ‘castle’, for all public, more-or-less official packages
Only base packages (which can’t be a plugin) are located directly in ‘castle’. Also some generic “main/app” routines can be located there.
castle.aigr
, the common intermediate langagecastle.monorail
, the code to load the plugins and put them in the pipeline
Most packages are plugins and use a namespace that denotes the “location” in the pipeline; in plural form to denotes the are options.
castle.readers.<name>
castle.transformers.<name>
castle.writers.<name>
(not backends, as only the writer-part is part of Castle.)
Use “pep 420” native namespace packages for all plugins.
In short: plugins should never put an __init__.py file in a shared namespace-part (like castle.readers.)
Only the “main” package is allowed to put files there.
Optional, auxiliary (plugin) packages are usually named (placed-in)
castle.<loc>.plugins.<opt>
.
Local (non public) extensions should normally not be in ‘castle’.
Optional plugins, that can be shared by many plugins for test, debug & development purposed are allowed in one place in the castle-hierarchy,
castle.TESTDOUBLES.<hier>
,TESTDOUBLES is in capitals, to signal it’s a specical case
Those plugins should not have production code – no application should depend/need those
(But for test & verification)‘<hier>’ is typical namespace, below castle, like: aigr
castle.TESTDOUBLES.aigr.sieve
holds (parts of) ‘The Sieve (basic variant)’ in ‘Abstract Intermediate Graph Representation’, As test-input for e.g. plugins. Or as reference for a reader.
Hint
Suppose we make the “nice-fsm-plugin” that act as transformer …
Note
The resulting namespace will be:
castle.transformers.fsm.nice_fsm
The name of the top directly does not matter (for python). We advice a name that shows it’s not a python-id, and is
related to the package name. For example:
<nice-fsm-plugin>
This directory contains the only package-info-file, which name a content depends on the (package) build systems. E.g.
pyproject.toml
(setup.py is outdated)name :str e.g.
castle-RPy-writer
or “nice-fsm-castle-plugin”version :str typical a dotted number (as string)
dependencies :List[str] =[
castle-aigr
, <package-names>, …]
We need a file-hierarchy, with empty directories, that mirror the (shared) namespace
<nice-fsm-plugin>/castle/
– empty, no __init__,py<nice-fsm-plugin>/castle/transformers/
– empty, no __init__,py<nice-fsm-plugin>/castle/transformers/fsm
– empty, no __init__,py<nice-fsm-plugin>/castle/transformers/fsm/nice_fsm
Holds all code:__init__.py can be empty, but typically uses
from .<> import <>
to have the “api functionality” available<files>.py code
<sub>/ sub-package, (full-dirname to be included in packages=[…] above
Opportunity
Let study the options, our needs and how others handle packages & plugins, before designing for castle.
Importing
When importing a package we (typical) use a hierarchical namespace to make the functionality of (a part of) the
package available. For example import castle.aigr
will load that common package.
It dotted name show aigr is part of castle.
Packages that are optional, or where alternatives are available, are conveniently bundled in an extra ‘layer’:
from castle.readers import typicalReader as reader
from castle.TESTDOUBLES.readers import mockReader as reader
(selected option for mocks)from castle.readers import mockReader as reader
(alternative, not preferred)
The “dotted names” gives the user/SW-engineer an hint on which (sub)packages are available, and where it fits. Aside of that, the name is not very important. During importing we can even rename a package, with the as <name> langage feature.
Note
The functionality does not depend on the name!
After a package is imported, all it’s functionality is available; always. The name of the (sub)package isn’t
relevant, nor is the (disk) location.
It is also possible to use castle-plugins when they are not located in the castle.namespace. As shown by the
next example:
from myLocal.Hack import MyOwnReader as reader
(not advised).
Installing
When (pip) installing a distribution package, typically a zip-file is downloaded, and extracte into a
directory. The name of that directory typically correspondes with the namespace, when importing.
The developer of a distribution specifies (has to design) in which namespaces (“directory”) the functionality becomes
available.
For small, simple packages this is straightforward. Typically, the directories ‘in’ the distribution (zipfile) match the
name(s) that are used to import it.
For bigger packages –especially when using plugins, and multiple parties can contribute and (independently) distribute
sub-packages– it a bit more complicated. All parties should agree on the name(s), to make is clear for the users.
A typical user expect that all packages for CCastle become available in castle., or something that is close to it [3]
Namespaces Packages
It is possible to combine several distribution packages into one importable packages (structure). This is called namespace package(s). Since python-3.3 (pep 420), this is standardised in Native namespace packages.
In short: each independent sub-package-developer should use of a common (same name), but “empty” top-directory. That dir should be ‘in’ the distribution-package (aka the zipfile). That dir should only contain a (1) sub-dir. And all files should be in that sub-dir.
Warning
The name of that common directory should be aligned!
XXXX
Why?
Clarity
It should be easy for the user to understand which package is related to CCastle and how it is related. Some packages are mandatory (e.g castle.aigr) or are needed in de base-setup, others are (external) plugins. But packages also have a place in the AIGR pipeline – it’s convenient to effortlessly tell readers and backends (etc) aside.
Ownership
Each (distribution) package has an owner too. Typical, the have there own “code archive”, own “package-numbering” and
“release cycle”, ect. This also aplies to plugins! They should be (able to) deployed independently.
In practice, “ownership” (like: who owns the code-archive, but also “when” to release) are the borders that define the
distribution-packages.
XXXX
Footnotes
Comments
comments powered by Disqus