boopak.pload
index
boopak/pload.py

pload: The PackageLoader class.
 
This module contains PackageLoader, which is responsible for loading and
tracking the Boodler packages in your collection.
 
(This does not install or modify packages in your collection. The collect
module handles those tasks.)

 
Modules
       
boopak
imp
os
sys
types
boopak.version

 
Classes
       
ExternalDir
PackageLoader
exceptions.Exception(exceptions.BaseException)
PackageLoadError
PackageNotFoundError

 
class ExternalDir
    ExternalDir: information about a package directory outside the
collection.
 
This is a simple data structure, stored as the values in the loader's
external_dirs mapping.
 
ExternalDir(dirname, metadata=None, resources=None) -- constructor
 
The dirname contains the (local) pathname of the directory to consider.
 
The metadata and resources fields, if supplied, override the Metadata
and Resources files in the directory. (The files do not even have to
exist.) If the metadata and resources fields are None, the directory's
files are checked as usual. (This override feature is used by the
package creation tool.)
 
Publicly readable fields:
 
dirname -- the directory which contains the package
metadata -- the supplied Metadata object (if any)
resources -- the supplied Resources object (if any)
 
  Methods defined here:
__init__(self, dirname, metadata=None, resources=None)

 
class PackageLoadError(exceptions.Exception)
    PackageLoadError: represents a failure to load a package.
 
This represents some kind of internal error or package formatting
problem. (If the package simply was not available, the subclass
PackageNotFoundError will be used.)
 
 
Method resolution order:
PackageLoadError
exceptions.Exception
exceptions.BaseException
__builtin__.object

Methods defined here:
__init__(self, pkgname, val='unable to load')

Data descriptors defined here:
__weakref__
list of weak references to the object (if defined)

Data and other attributes inherited from exceptions.Exception:
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T

Methods inherited from exceptions.BaseException:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__getitem__(...)
x.__getitem__(y) <==> x[y]
__getslice__(...)
x.__getslice__(i, j) <==> x[i:j]
 
Use of negative indices is not supported.
__reduce__(...)
__repr__(...)
x.__repr__() <==> repr(x)
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value
__setstate__(...)
__str__(...)
x.__str__() <==> str(x)

Data descriptors inherited from exceptions.BaseException:
__dict__
args
message
exception message

 
class PackageLoader
    PackageLoader: manages a package collection, loading packages as
requested. Also maintains an (in-memory) cache, to speed up load
requests.
 
You can also specify extra directories, outside the collection,
to load packages from.
 
This class does not deal with writing package files into the
collection directory. (For that, see PackageCollection, in
collect.py.)
 
The PackageLoader is used in two ways. A Boodler UI will want to
call the list_all_current_packages() method, which loads all the
descriptive information in the collection. A Boodler sound-playing
process will only call the load() method, which loads the particular
classes desired.
 
PackageLoader(dirname, boodler_api_vers=None, importing_ok=False)
    -- constructor
 
Create a PackageLoader, given the name of a directory which contains
a collection of packages.
 
If a version is provided (either as a VersionNumber or a string which
converts to one), then this is noted as the Boodler version which
packages must be compatible with. (As noted in the boodler.api_required
metadata field.)
 
(Note that the boodler.api_required field is not checked until the
package is actually loaded, which is after version selection occurs.
Therefore, it is best if the collection only contains packages which
are compatible with the installed Boodler version. None of this is
likely to be important, since the Boodler API version is not expected
to change much after 2.0.)
 
If the importing_ok flag is false, this loader will refuse to load
(that is, execute) Python code in packages. This is the default.
 
Note that only one importing_ok loader can exist in the process.
(This is because loaded modules need to be able to find the loader
through static variables.)
 
Publicly readable fields:
 
collecdir -- the directory containing the package collection
currently_importing -- during an import operation, the package which is
    being imported (at the moment)
 
Public methods:
 
load() -- load a package, given its name and a version spec
load_group() -- load a PackageGroup, given its package name
clear_cache() -- erase the PackageLoader's entire knowledge
generate_package_path() -- return a pathname in the collection dir
add_external_package() -- add an external directory to load a package from
remove_external_package() -- remove an external directory
clear_external_packages() -- remove all external directories
find_all_dependencies() -- determine which packages depend on which others
list_all_packages() -- return a list of all the available packages
list_all_current_packages() -- list the most recent versions of packages
load_package_dependencies() -- load all packages which a package depends on
import_package_content() -- import the package's content, if it hasn't been
load_item_by_name() -- import and return an item in a package
find_item_resources() -- find the Resource for an item in a package
attrify_filename() -- given a filename, add its File to the module
start_import_recording() -- stub, overridden in PackageCollection
stop_import_recording() -- stub, overridden in PackageCollection
 
Internal methods:
 
load_specific() -- load a package, given its name and a specific version
discover_all_groups() -- search through the collection directory
 
Class global field:
 
global_loader -- If a PackageLoader can import packages, it needs to
    be accessible from a global context. (See the package module.)
    PackageLoader.global_loader is where to find it.
 
  Methods defined here:
__init__(self, collecdir, boodler_api_vers=None, importing_ok=False)
add_external_package(self, dirname, metadata=None, resources=None)
add_external_package(dirname, metadata=None, resources=None) ->
    (str, VersionNumber)
 
Add an external directory to load a package from. The argument
must be a complete (unpacked) Boodler directory, with a
Metadata file. That package will then be loadable (possibly
hiding a package in the collection directory).
 
The metadata and resources fields, if supplied, override the 
Metadata and Resources files in the directory. (The files do not
even have to exist.) If the metadata and resources fields are
None, the directory's files are checked as usual. (This override
feature is used by the package creation tool. It should not be
used for any other purpose.)
 
Returns the name and version of the package that was found.
 
Since this changes the set of what packages are available,
it implicitly invokes clear_cache().
 
The external package facility is not intended to be how most
packages are loaded. Most packages should be in the collection
directory. You might add an external package in your development
workspace (while developing a soundscape), or in a temporary
download directory (while deciding whether to install a newly-
downloaded package).
attrify_filename(self, pkg, mod, wholekey, res, filename)
attrify_filename(pkg, mod, wholekey, res, filename) -> None
 
Given a filename, create a File representing it, and store the
File in the module at a location defined by wholekey. Submodules
are created as necessary. The res argument is the Resource
object associated with wholekey.
 
The filename must be in universal format: relative to the package
root, and written with forward slashes, not backslashes.
 
(If the filename is invalid or unsafe, ValueError is raised.
However, this does not check whether the file exists.)
clear_cache(self)
clear_cache() -> None
 
Erase the PackageLoader's entire knowledge of what groups and
packages are available.
 
This should be called whenever packages are added to, modified
in, or deleted from the collection directory.
clear_external_packages(self)
clear_external_packages() -> None
 
Remove all external directories.
 
Since this changes the set of what packages are available,
it implicitly invokes clear_cache().
discover_all_groups(self)
discover_all_groups() -> None
 
Search through the collection directory, and load all the PackageGroups
that are available.
 
This only searches the on-disk directory the first time you call
it. To force it to re-scan the directory, call clear_cache() first.
find_all_dependencies(self)
find_all_dependencies() -> (dict, dict, dict)
 
Go through the entire collection, and determine exactly which
packages depend on which other packages.
 
This returns a triple (forward, backward, bad). In the forward
dict, each package key (pkgname,vers) maps to an array of package
keys which the package depends on. In the backward dict, each
package key maps to an array of packages which depend *on* it.
In the bad dict, each package key maps to an array of
(pkgname,spec) of dependencies which could not be loaded.
 
(In the bad dict tuples, the second element may be None, a
VersionSpec, or a VersionNumber.)
 
This only searches the on-disk directory the first time you call
it. To force it to re-scan the directory, call clear_cache() first.
find_item_resources(self, obj)
find_item_resources(obj) -> (PackageInfo, Resource)
 
Given an object in a package module, try to find the package,
and the Resource that represents the object. If it has no metadata
defined, this returns a blank Resource object.
 
This tries to use object attributes such as __module__ and __name__
to identify it. This will work on classes (but not instances)
defined in a module; this covers the normal case of Agent classes.
It will also work on File objects defined in a module. Beyond
that, results are questionable.
generate_package_path(self, pkgname, vers=None)
generate_package_path(pkgname, vers=None) -> str
 
Return the pathname in the collection directory which contains the
given package group (if vers is None), or the given package
(otherwise).
 
This does not create the directory or check for its existence.
 
This is guaranteed to create a distinct pathname for every
pkgname or (pkgname, vers) pair. This is true even on case-
insensitive filesystems, which is a wrinkle, since version
strings are case-sensitive. We work around this by putting
a "^" character before each capital letter.
import_package_content(self, pkg)
import_package_content(pkg) -> None
 
Import the package's content, if it hasn't already been imported.
 
Warning: this method imports Python source code from the package
directory, which means it *executes* Python source code from the
package directory. Do not call this on untrusted packages.
 
A sound-player will have to call this, but a package manager
should not.
list_all_current_packages(self)
list_all_current_packages() -> list of (str, VersionNumber)
 
Search through the collection directory, and return a list of all the
available packages. If multiple versions of a package are available,
only the most recent will be listed.
 
Returns a list of (packagename, version) tuples (in no particular
order).
 
This only searches the on-disk directory the first time you call
it. To force it to re-scan the directory, call clear_cache() first.
list_all_packages(self)
list_all_packages() -> list of (str, list of VersionNumber)
 
Search through the collection directory, and return a list of all the
available packages. 
 
Returns a list of (packagename, list of version) tuples. The top
list is in no particular order, but the version list will be sorted
newest-to-oldest.
 
This only searches the on-disk directory the first time you call
it. To force it to re-scan the directory, call clear_cache() first.
load(self, pkgname, versionspec=None)
load(pkgname, versionspec=None) -> PackageInfo
 
Load a package, given its name and a version spec.
 
If no second argument is given, the most recent available version
of the package is loaded. If the argument is a VersionNumber,
that version will be loaded. If it is a VersionSpec, the most
recent version that matches the spec will be loaded. A string
value will be converted to a VersionSpec (not a VersionNumber).
 
This generates a PackageNotFoundError if no matching package
is available. It generates PackageLoadError if the package
was malformed in some way which prevented loading.
load_group(self, pkgname)
load_group(self, pkgname) -> PackageGroup
 
Load a PackageGroup, given its package name.
 
This is not tremendously useful for outside users, although you
can call it if you want. A PackageGroup represents all the
available versions of a particular package.
load_item_by_name(self, name, package=None)
load_item_by_name(name, package=None) -> value
 
Given a string that names a resource -- for example,
'com.eblong.example/reptile.Hiss' -- import the module and
return the resource object.
 
If the string begins with a slash ('/boodle.builtin.NullAgent')
then the regular Python modules are searched. No importing
is done in this case; it is really intended only for the
contents of boodle.agent.
 
If the string ends with a slash ('com.eblong.example/'), then
the module itself is returned.
 
If the package argument is supplied (a PackageInfo object), it
becomes the package to look in for unqualified resource names
('reptile.Hiss'). If no package argument is supplied, then
an unqualified resource name raises ValueError.
load_package_dependencies(self, pkg)
load_package_dependencies(pkg) -> (set, dict, int)
 
Attempt to load all the packages which the given package depends on.
The argument should be a PackageInfo object.
 
This returns a triple (good, bad, count):
 
- good is a set containing (packagename, version) pairs for every
package that was loaded successfully. (This will include the original
package.)
- bad is a dict. The keys are packagenames which did not load
successfully. Each maps to a (nonempty) list of version requests
for that package, which could not be fulfilled. (The list contains
None, VersionSpecs, and VersionNumbers. Values may occur more than
once.)
- count is an int, representing how many actual errors occurred.
This describes package format problems and read errors. It does not
include packages that were simply not available. (The bad dict
includes both errors and not-availables; so len(bad) >= count.)
 
If bad is empty, then all dependencies are available.
 
Note that the good list may include more than one version of a
package.
load_specific(self, pkgname, vers)
load_specific(pkgname, vers) -> PackageInfo
 
Load a package, given its name and a specific version number.
(The version number may be a VersionNumber or a string that
can be converted to one.)
 
This is an internal call; external callers should use load().
 
(load_specific() is intended to be called by a package
function which has already consulted package_groups and a
PackageGroup object. If you bypass those, you might load
a package which is not part of any PackageGroup. That would
leave the cache in a confusing state.)
remove_external_package(self, dirname)
remove_external_package(dirname) -> None
 
Remove an external directory. The argument should be one that was
previously passed to add_external_package(). (If it is not a
current external directory, this silently does nothing.)
 
Since this changes the set of what packages are available,
it implicitly invokes clear_cache().
start_import_recording(self)
start_import_recording() -> None
 
Stub, overridden in PackageCollection. In a PackageLoader, this
does nothing.
stop_import_recording(self)
stop_import_recording() -> dic
 
Stub, overridden in PackageCollection. In a PackageLoader, this
does nothing and returns an empty dict.

Data and other attributes defined here:
global_loader = None
import_recorder = None

 
class PackageNotFoundError(PackageLoadError)
    PackageNotFoundError: represents a failure to load a package
because it was not in the collection.
 
 
Method resolution order:
PackageNotFoundError
PackageLoadError
exceptions.Exception
exceptions.BaseException
__builtin__.object

Methods inherited from PackageLoadError:
__init__(self, pkgname, val='unable to load')

Data descriptors inherited from PackageLoadError:
__weakref__
list of weak references to the object (if defined)

Data and other attributes inherited from exceptions.Exception:
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T

Methods inherited from exceptions.BaseException:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__getitem__(...)
x.__getitem__(y) <==> x[y]
__getslice__(...)
x.__getslice__(i, j) <==> x[i:j]
 
Use of negative indices is not supported.
__reduce__(...)
__repr__(...)
x.__repr__() <==> repr(x)
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value
__setstate__(...)
__str__(...)
x.__str__() <==> str(x)

Data descriptors inherited from exceptions.BaseException:
__dict__
args
message
exception message

 
Data
        Filename_Metadata = 'Metadata'
Filename_Resources = 'Resources'
Filename_Versions = 'Versions'