[TransWarp] FYI: 'api' packages namespace standardization
Phillip J. Eby
pje at telecommunity.com
Tue Jun 18 20:27:03 EDT 2002
The Problem: Exports in __init__ Considered Harmful for Frameworks
==================================================================
People often want to use part of a package without importing all of
it. This is especially relevant to large frameworks such as Zope and
PEAK. However, people also don't want to have to import pieces from a
zillion individual modules in order to get something done.
Often, packages are written whose __init__ imports items from contained
modules or packages in order to 'export' them as a unit to external
code. But this can create problems for people who need access to only a
part of the code, often including the framework developers themselves! If
two packages in a framework have dependencies on each other, and any of the
interdependent modules are imported from an __init__ module, it becomes
almost impossible to make the imports robust and non-circular.
Currently, PEAK has or will develop some of these problems. The current
arrangement is an inconsistent mix of export policies: some packages have
an 'api' module or other submodule which does the "exporting" in place of
__init__, while other packages do their exports directly from the __init__
module.
Implementing a consistent policy for how API functions are "exported" from
packages should help to simplify the task of documenting, explaining, and
understanding/using PEAK. (Not to mention some of the tasks of writing it!)
The Solution
------------
Individual PEAK packages, such as peak.naming, peak.binding, peak.model,
etc., will each include an 'api' module, which will contain or import the
"commonly used" functions and classes for users of that package. The
__init__ module for each package will not import/export anything, and will
generally contain only a docstring. It is acceptable for the __init__
module to contain actual code or data, in the rare case that it is justifiable.
The root package, 'peak', will also have an 'api' module, which will
contain a few very commonly used general PEAK API functions (such as
'setupModule()') and a set of lazyImport objects for each of the top-level
packages' API modules. In other words, the following two imports produce
essentially the same results:
from peak.api import subpackage
import peak.subpackage.api as subpackage
The only difference being that the 'subpackage' object imported from
'peak.api' will be a lazyImport proxy for the actual 'peak.subpackage.api'
module. This is only relevant if you need the actual module object for
some reason.
The standard way to access any PEAK functionality will be through the
appropriate 'api' module or its lazyImport proxy from 'peak.api'. Some
code within PEAK itself, however, will necessarily break this rule. For
example: imports within the same package, and any cross-package imports
which would otherwise create a circular import dependency.
Note, by the way, that "housekeeping" packages like peak.util and
peak.tests will not have 'api' modules, since they do not have any kind of
coherent API which they export to their clients.
The Implementation
------------------
Here's a general idea of the moves that will take place:
peak.binding.__init__ -> peak.binding.api
peak.util.Import -> peak.binding.imports
peak.model.basic -> peak.model.api
peak.naming.__init__ -> peak.naming.api (merge)
For right now, the peak.metamodels package won't get an API, since its
status is rather fuzzy at the moment. (Primarily, it's there to drive unit
tests.)
Over time, I'd like to begin moving modules out of peak.util and into other
suitable subpackages. At this point, the Import module is the only one
with an obvious place to go. There are also a few peak.util modules which
will disappear as soon as PEAK requires Python 2.2.1 (which will be as soon
as I upgrade my Windows PC's at home and work to 2.2.1!).
The changes will take place as soon as I get to them, possibly right after
I mail this announcement. Some will be by direct repository moves, which
may break current checkouts (Ty, take note!), although in practice it seems
that moving or renaming files in the repository doesn't actually break a
checkout. Anyway, the moves will also require changes to source code, and
those changes will therefore be checked in normally.
More information about the PEAK
mailing list