def subtest_dependency_cases(self): pkg = self.loader.load('depend.on.cases') tup = pkg.load_dependencies() badls = [ ('missing.nospec', None), ('missing.spec', version.VersionSpec('2.0')), ('missing.num', version.VersionNumber('3.0')), ] badls.sort() baddict = dict([ (key,[val]) for (key,val) in badls ]) self.assertEqual(tup, (self.packages_to_set([ ('depend.on.cases', '1.0'), ('depend.one', '2.0'), ]), baddict, 0)) bad = self.loader.find_all_dependencies()[2] ls = bad[('depend.on.cases', version.VersionNumber('1.0'))] ls.sort() self.assertEqual(ls, badls)
def test_encode_package_name(self): (pkgname, vers) = ('xy.zzy', version.VersionNumber('1.2.3a.four')) val = encode_package_name(pkgname, vers) self.assertEqual(val, '_BooPkg_xy_zzyV1_2_3a_four') ls = [ ('x.y_z', '1.1._'), ('x.y.z', '1.1._'), ('x.y.z1', '1.1._'), ('x.y.z', '11.1._'), ('x.y.z', '1.11._'), ('x.y.z', '1.1.1_'), ('x.y.z', '1.1.a'), ('x.y.z', '1.1.A'), ('x.y.z', '1.1.U'), ('x.y.z', '1.1.C'), ('x.y.z', '1.1.CU'), ] st = set() for (pkgname, vers) in ls: vers = version.VersionNumber(vers) val = encode_package_name(pkgname, vers) self.assert_(pinfo.ident_name_regexp.match(val)) st.add(val) self.assertEqual(len(st), len(ls))
def parse_package_version_spec(val): """parse_package_version_spec(val) -> (pkgname, VersionNumber) or (pkgname, VersionSpec) or (pkgname, None) Parse a package identifier together with its version spec (e.g., "org.boodler.sample:1.0") or exact version spec (e.g., "org.boodler.sample::1.0"). If neither is present, the second value of the return tuple will be None. Raises a ValueError if the name was in any way invalid. (Thus, this function can be used to ensure that a package name is valid.) """ vers = None pos = val.find(':') if (pos >= 0): spec = val[pos + 1:] val = val[:pos] if (spec.startswith(':')): vers = version.VersionNumber(spec[1:]) else: vers = version.VersionSpec(spec) parse_package_name(val) return (val, vers)
def __init__(self, collecdir, boodler_api_vers=None, importing_ok=False): if (type(boodler_api_vers) in [str, unicode]): boodler_api_vers = version.VersionNumber(boodler_api_vers) self.boodler_api_vers = boodler_api_vers if (collecdir is None): raise ValueError('PackageLoader requires a collection directory') # We allow the loader to run even without a collection directory, # so that TestSoundAgent will work. #if (not os.path.isdir(collecdir)): # raise ValueError('PackageLoader collection directory is not readable: ' # + collecdir) self.collecdir = collecdir self.importing_ok = False self.module_info = None # Set up the (empty) caches self.package_groups = {} self.package_names = {} self.packages = {} self.external_dirs = {} self.collection_scanned = False self.all_deps = None self.currently_importing = None if (importing_ok): if (PackageLoader.global_loader): raise ValueError('A PackageLoader already exists with importing_ok set') self.importing_ok = True PackageLoader.global_loader = self self.module_info = {}
def discover_versions(self, fl, external_versions=None): """discover_versions(file, external_versions=None) -> None Determine what versions are available. We look both at the contents of an open Versions file, and at a list of versions found in external packages. Either of these may be None. This is an internal method; it is called only by load_group, when the PackageGroup is created. """ res = {} if (fl): while (True): ln = fl.readline() if (not ln): break ln = deunicode(ln) ln = ln.strip() if (not ln): continue if (ln.startswith('#')): continue vers = version.VersionNumber(ln) res[vers] = False if (external_versions): for vers in external_versions: res[vers] = True self.versions = list(res.keys()) self.versions.sort() self.versions.reverse()
def subtest_generate_package_path(self): coldir = self.coldir path = self.loader.generate_package_path('foo.bar') self.assertEqual(path, os.path.join(coldir, 'foo.bar')) path = self.loader.generate_package_path('foo.bar', version.VersionNumber('2.1')) self.assertEqual(path, os.path.join(coldir, 'foo.bar', '2.1')) path = self.loader.generate_package_path('foo.bar', version.VersionNumber('2.1.0a')) self.assertEqual(path, os.path.join(coldir, 'foo.bar', '2.1.0a')) path = self.loader.generate_package_path('foo.bar', version.VersionNumber('2.1.0A')) self.assertEqual(path, os.path.join(coldir, 'foo.bar', '2.1.0^A'))
def test_build_package_filename(self): ls = [ ('foo.bar', '1.0', 'foo.bar.1.0.boop'), ('foo.bar', '2.30.xyzzy.1', 'foo.bar.2.30.xyzzy.1.boop'), ('foo.bar.baz', '9.8.A.b.Cd.EF', 'foo.bar.baz.9.8.^A.b.^Cd.^E^F.boop'), ] for (pkgname, pkgvers, result) in ls: pkgvers = version.VersionNumber(pkgvers) val = build_package_filename(pkgname, pkgvers) self.assertEqual(val, result)
def test_parse_package_version_spec(self): valid_list = [ 'foo:1.0', 'foo:2-', 'foo:-3.1', 'foo:2-4', 'foo::1.2.3', 'foo.bar::1.5.6a', ] invalid_list = [ '0x', ':foo', 'foo:0.1', 'foo:1.2.3', 'foo::0.1', 'foo:::1.0', 'foo:1:2', 'foo: 1.0', 'foo :1.0', 'foo: :1.0', 'foo:: 1.0', ] (pkg, vers) = parse_package_version_spec('x.y.z') self.assertEqual(pkg, 'x.y.z') self.assertEqual(vers, None) (pkg, vers) = parse_package_version_spec('x.y.z:2.4') self.assertEqual(pkg, 'x.y.z') self.assert_(isinstance(vers, version.VersionSpec)) self.assertEqual(vers, version.VersionSpec('2.4')) (pkg, vers) = parse_package_version_spec('x.y.z::2.4.6') self.assertEqual(pkg, 'x.y.z') self.assert_(isinstance(vers, version.VersionNumber)) self.assertEqual(vers, version.VersionNumber('2.4.6')) for val in valid_list: parse_package_version_spec(val) for val in invalid_list: self.assertRaises(ValueError, parse_package_version_spec, val)
def subtest_version_specs(self): pkg = self.loader.load('version.specs') self.assertEqual(pkg.key, ('version.specs', '2.5')) pkg = self.loader.load('version.specs', '1') self.assertEqual(pkg.key, ('version.specs', '1.5.3')) pkg = self.loader.load('version.specs', '1.3') self.assertEqual(pkg.key, ('version.specs', '1.5.3')) self.assertRaises(pload.PackageNotFoundError, self.loader.load, 'version.specs', '1.6') pkg = self.loader.load('version.specs', '2') self.assertEqual(pkg.key, ('version.specs', '2.5')) pkg = self.loader.load('version.specs', '2.4') self.assertEqual(pkg.key, ('version.specs', '2.5')) self.assertRaises(pload.PackageNotFoundError, self.loader.load, 'version.specs', '2.6') self.assertRaises(pload.PackageNotFoundError, self.loader.load, 'version.specs', '3') pkg = self.loader.load('version.specs', '1.2') self.assertEqual(pkg.key, ('version.specs', '1.5.3')) pkg = self.loader.load('version.specs', version.VersionNumber('1.2')) self.assertEqual(pkg.key, ('version.specs', '1.2'))
def 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. """ pos = name.find('/') if (pos < 0): if (package is None): raise ValueError('argument must be of the form package/Resource') mod = package.get_content() elif (pos == 0): # consult Python's module map name = name[ 1 : ] headtail = name.split('.', 1) if (len(headtail) != 2): raise ValueError('argument must be of the form package/Resource') (modname, name) = headtail mod = sys.modules.get(modname) if (mod is None): raise ValueError('not found in Python modules: ' + modname) else: pkgname = name[ : pos ] name = name[ pos+1 : ] pkgspec = None pos = pkgname.find(':') if (pos >= 0): val = pkgname[ pos+1 : ] pkgname = pkgname[ : pos ] if (val.startswith(':')): val = val[ 1 : ] pkgspec = version.VersionNumber(val) else: pkgspec = version.VersionSpec(val) package = self.load(pkgname, pkgspec) mod = package.get_content() if (not name): # "module/" returns the module itself return mod namels = name.split('.') try: res = mod for el in namels: res = getattr(res, el) return res except AttributeError, ex: raise ValueError('unable to load ' + name + ' (' + str(ex) + ')')
def 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). """ label = '<external '+dirname+'>' exrec = ExternalDir(dirname, metadata, resources) if (not os.path.isdir(dirname)): raise PackageLoadError(label, 'not a directory') # Load the metadata file, and see what package/version we are # dealing with. (But only if a metadata object wasn't handed to # us!) if (not metadata): metadatafile = os.path.join(dirname, Filename_Metadata) if (not os.path.isfile(metadatafile)): raise PackageLoadError(label, 'package has no metadata file') fl = open(metadatafile, 'rbU') try: metadata = boopak.pinfo.Metadata(label, fl) finally: fl.close() val = metadata.get_one('boodler.package') if (not val): raise PackageLoadError(label, 'no boodler.package metadata entry') parse_package_name(val) pkgname = str(val) val = metadata.get_one('boodler.version') if (not val): vers = version.VersionNumber() else: vers = version.VersionNumber(val) # Add this to the external directory table. (We have not actually # loaded the package.) self.external_dirs[(pkgname, vers)] = exrec self.clear_cache() return (pkgname, vers)
def 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.) """ if (type(vers) in [str, unicode]): vers = version.VersionNumber(vers) pkg = self.packages.get( (pkgname, vers) ) if (pkg): return pkg # Make sure the name is valid. parse_package_name(pkgname) pkgname = str(pkgname) exrec = self.external_dirs.get( (pkgname, vers) ) if (exrec is None): is_external = False dirname = self.generate_package_path(pkgname, vers) else: is_external = True dirname = exrec.dirname # dirname is now the directory where the package should reside. # This may be in the collection or external. if (not os.path.isdir(dirname)): raise PackageNotFoundError(pkgname, 'package version directory does not exist') # Read the metadata. (But if the external directory record has # an overriding Metadata object, use that instead.) if (is_external and exrec.metadata): metadata = exrec.metadata else: metadatafile = os.path.join(dirname, Filename_Metadata) if (not os.path.isfile(metadatafile)): raise PackageLoadError(pkgname, 'package has no metadata file') fl = open(metadatafile, 'rbU') try: metadata = boopak.pinfo.Metadata(pkgname, fl) finally: fl.close() # Read the resources (if there are any). Again, there may be an # overriding Resources object. if (is_external and exrec.resources): resources = exrec.resources else: resourcesfile = os.path.join(dirname, Filename_Resources) if (os.path.isfile(resourcesfile)): fl = open(resourcesfile, 'rbU') try: resources = boopak.pinfo.Resources(pkgname, fl) finally: fl.close() else: # Create an empty resources object resources = boopak.pinfo.Resources(pkgname) # Create the PackageInfo object and look through its metadata. pkg = PackageInfo(self, pkgname, vers, dirname, metadata, resources, is_external) pkg.validate_metadata() # Valid; we can now add it to the cache. self.packages[(pkgname, vers)] = pkg self.package_names[pkg.encoded_name] = pkg return pkg
class PackageInfo: """PackageInfo: represents a single package. A PackageInfo is not the imported module object which a Boodler module sees from the inside. It's a wrapper around that. PackageInfo(loader, name, vers, dir, metadata, resources, external) -- constructor Publicly readable fields: name -- the package name version -- the package version number key -- a tuple containing (name, version) encoded_name -- the name of the package's module metadata -- the Metadata for the package resources -- the Resources for the package loader -- the PackageLoader which loaded the package Public methods: load_dependencies() -- attempt to load everything this package depends on get_content() -- return the module which is the content of this package get_file() -- get a File object contained within this package open_file() -- open a File object contained within this package Internal methods: validate_metadata() -- check the metadata, and load information from it """ def __init__(self, loader, name, vers, dir, metadata, resources, external): self.loader = loader self.name = name self.version = vers self.key = (name, vers) self.encoded_name = encode_package_name(name, vers) self.dir = dir self.content = None self.content_info = {} self.import_in_progress = False self.metadata = metadata self.resources = resources self.resource_tree = None self.external = external self.dependencies = set() self.imported_pkg_specs = {} def __repr__(self): return '<PackageInfo \'' + self.name + ' ' + str(self.version) + '\'>' def validate_metadata(self): """validate_metadata() -> None Make sure that the metadata object attached to this package correctly describes the package. Also loads up various fields with information from the metadata object. Also checks that the resource tree has a valid shape. If anything is discovered to be wrong, this raises PackageLoadError. This is called by the package loader (and nothing else should call it). """ pkgname = self.name metadata = self.metadata val = metadata.get_one('boodler.package') if (not val): raise PackageLoadError(pkgname, 'no boodler.package metadata entry') if (val != pkgname): raise PackageLoadError( pkgname, 'boodler.package does not match package location: ' + val) val = metadata.get_one('boodler.version') if (not val): val = '(missing, 1.0 assumed)' vers = version.VersionNumber() else: vers = version.VersionNumber(val) if (vers != self.version): raise PackageLoadError( pkgname, 'boodler.version does not match package version: ' + val) val = metadata.get_one('boodler.main') if (not val): pass elif (val == '.'): pass elif (ident_name_regexp.match(val)): pass else: raise PackageLoadError(pkgname, 'boodler.main is not a module or . :' + val) val = metadata.get_one('boodler.api_required') if (val): spec = version.VersionSpec(val) if (self.loader.boodler_api_vers): if (not spec.match(self.loader.boodler_api_vers)): raise PackageLoadError( pkgname, 'boodler.api_required does not match Boodler version: ' + val) for val in metadata.get_all('boodler.requires'): try: pos = val.find(' ') if (pos < 0): deppkg = val depspec = None else: deppkg = val[:pos].strip() depspec = val[pos + 1:].strip() depspec = version.VersionSpec(depspec) parse_package_name(deppkg) deppkg = str(deppkg) self.dependencies.add((deppkg, depspec)) except ValueError, ex: raise PackageLoadError(pkgname, 'boodler.requires line invalid: ' + val) for val in metadata.get_all('boodler.requires_exact'): try: pos = val.find(' ') if (pos < 0): raise ValueError('version number required') else: deppkg = val[:pos].strip() depspec = val[pos + 1:].strip() depspec = version.VersionNumber(depspec) parse_package_name(deppkg) deppkg = str(deppkg) self.dependencies.add((deppkg, depspec)) except ValueError, ex: raise PackageLoadError( pkgname, 'boodler.requires_exact line invalid: ' + val)
def validate_metadata(self): """validate_metadata() -> None Make sure that the metadata object attached to this package correctly describes the package. Also loads up various fields with information from the metadata object. Also checks that the resource tree has a valid shape. If anything is discovered to be wrong, this raises PackageLoadError. This is called by the package loader (and nothing else should call it). """ pkgname = self.name metadata = self.metadata val = metadata.get_one('boodler.package') if (not val): raise PackageLoadError(pkgname, 'no boodler.package metadata entry') if (val != pkgname): raise PackageLoadError( pkgname, 'boodler.package does not match package location: ' + val) val = metadata.get_one('boodler.version') if (not val): val = '(missing, 1.0 assumed)' vers = version.VersionNumber() else: vers = version.VersionNumber(val) if (vers != self.version): raise PackageLoadError( pkgname, 'boodler.version does not match package version: ' + val) val = metadata.get_one('boodler.main') if (not val): pass elif (val == '.'): pass elif (ident_name_regexp.match(val)): pass else: raise PackageLoadError(pkgname, 'boodler.main is not a module or . :' + val) val = metadata.get_one('boodler.api_required') if (val): spec = version.VersionSpec(val) if (self.loader.boodler_api_vers): if (not spec.match(self.loader.boodler_api_vers)): raise PackageLoadError( pkgname, 'boodler.api_required does not match Boodler version: ' + val) for val in metadata.get_all('boodler.requires'): try: pos = val.find(' ') if (pos < 0): deppkg = val depspec = None else: deppkg = val[:pos].strip() depspec = val[pos + 1:].strip() depspec = version.VersionSpec(depspec) parse_package_name(deppkg) deppkg = str(deppkg) self.dependencies.add((deppkg, depspec)) except ValueError, ex: raise PackageLoadError(pkgname, 'boodler.requires line invalid: ' + val)
def packages_to_set(self, ls): ls = [ (name, version.VersionNumber(vers)) for (name, vers) in ls ] return set(ls)
def build_package(loader, name, vers='1.0', mod_content = None, mod_main = None, external_path = None, resources = None, depends = None, metadata = None): if (type(vers) in [str, unicode]): vers = version.VersionNumber(vers) if (not external_path): path = loader.generate_package_path(name) if (not os.path.isdir(path)): os.makedirs(path) fl = open(os.path.join(path, pload.Filename_Versions), 'a') fl.write(str(vers)+'\n') fl.close() path = loader.generate_package_path(name, vers) else: path = external_path os.mkdir(path) if (mod_main or mod_content): if (not mod_main): mod_main = 'main' if (not mod_content): mod_content = [] fl = open(os.path.join(path, pload.Filename_Metadata), 'wb') fl.write('boodler.package: ' + name + '\n') fl.write('boodler.version: ' + str(vers) + '\n') if (mod_main): if (mod_main == '__init__'): fl.write('boodler.main: .\n') else: fl.write('boodler.main: ' + mod_main + '\n') if (depends): if (type(depends) != list): depends = [ depends ] for (val1, val2) in depends: if (val2 is None): fl.write('boodler.requires: ' + val1 + '\n') elif (isinstance(val2, version.VersionSpec)): fl.write('boodler.requires: ' + val1 + ' ' + str(val2) + '\n') elif (isinstance(val2, version.VersionNumber)): fl.write('boodler.requires_exact: ' + val1 + ' ' + str(val2) + '\n') else: fl.write('boodler.requires: ' + val1 + ' ' + val2 + '\n') if (metadata): for key in metadata: fl.write(key + ': ' + metadata[key] + '\n') fl.close() if (mod_main): fl = open(os.path.join(path, mod_main+'.py'), 'w') if (depends): fl.write('from boopak import package\n') count = 1 for (val1, val2) in depends: fl.write('imp'+str(count)+'=') fl.write('package.bimport') if (not val2): fl.write('("' + val1 + '")\n') else: fl.write('("' + val1 + '", "' + val2 + '")\n') count += 1 if (type(mod_content) == dict): for key in mod_content: val = mod_content[key] fl.write(key + ' = ' + repr(val) + '\n') else: for val in mod_content: fl.write(val + '\n') fl.close() if (resources): fl = open(os.path.join(path, pload.Filename_Resources), 'wb') for reskey in resources: resfile = resources[reskey] fl.write(':'+reskey+'\n') if (type(resfile) is dict): for key in resfile: fl.write(key + ': ' + resfile[key] + '\n') continue content = 'content='+reskey if (type(resfile) is tuple): (resfile, content) = resfile fl.write('boodler.filename: '+resfile+'\n') val = os.path.join(path, *resfile.split('/')) if (not os.path.isdir(os.path.dirname(val))): os.makedirs(os.path.dirname(val)) subfl = open(val, 'wb') subfl.write(content) subfl.close() fl.close() if (not external_path): dic = collection.get(name) if (not dic): dic = {} collection[name] = dic dic[vers] = path
def setUp(self): basedir = tempfile.mkdtemp(prefix='test_pload') self.basedir = basedir coldir = os.path.join(basedir, 'Collection') os.makedirs(coldir) self.coldir = coldir self.loader = pload.PackageLoader(coldir, importing_ok=True) build_package(self.loader, 'simple.test', '1.0') build_package(self.loader, 'import.module', mod_content={'key':'val'}, mod_main='main') build_package(self.loader, 'import.module', '2.0', mod_content={'key':'val2'}, mod_main='__init__') build_package(self.loader, 'version.specs', '1.2') build_package(self.loader, 'version.specs', '1.5') build_package(self.loader, 'version.specs', '1.5.3') build_package(self.loader, 'version.specs', '2.5') self.empty_dir_path = os.path.join(basedir, 'empty-dir') os.mkdir(self.empty_dir_path) self.external_one_path = os.path.join(basedir, 'external-one') build_package(self.loader, 'external.one', '1.0', external_path=self.external_one_path, metadata={'key':'ext1'}) build_package(self.loader, 'external.two', '2.5', mod_content={'key':'orig'}) self.external_two_path = os.path.join(basedir, 'external-two') build_package(self.loader, 'external.two', '2.5', external_path=self.external_two_path, mod_content={'key':'replacement'}) build_package(self.loader, 'external.three', '2.0', mod_content={'key':'orig'}) self.external_three_path = os.path.join(basedir, 'external-three') build_package(self.loader, 'external.three', '2.5', external_path=self.external_three_path, mod_content={'key':'replacement'}) build_package(self.loader, 'only.files', resources={ 'one':'one.txt', 'dir.two':'dir/two.txt', 'dir.three':'dir/three.txt', }) build_package(self.loader, 'mod.and.files', mod_content=[ 'from boopak import package', 'package.bexport("one")', 'package.bexport("dir")', 'package.bexport("alt.four")', ], resources={ 'zero':'zero.txt', 'one':'one.txt', 'dir.two':'dir/two.txt', 'dir.three':'dir/three.txt', 'alt.four':'alt/four.txt', 'alt.five':'alt/five.txt', }) build_package(self.loader, 'depend.one', '1', mod_content={'key':11}) build_package(self.loader, 'depend.one', '2', mod_content={'key':12}) build_package(self.loader, 'depend.two', depends=('depend.one', '1'), mod_content={'key':21}) build_package(self.loader, 'depend.two', '2', depends=('depend.one', '2'), mod_content={'key':22}) build_package(self.loader, 'depend.three', depends=('depend.two', None), mod_content={'key':3}) build_package(self.loader, 'self.depend', '1', depends=('self.depend', '1'), mod_content={'key':1}) build_package(self.loader, 'self.depend', '2', depends=('self.depend', '1'), mod_content={'key':2}) build_package(self.loader, 'mutual.depend.one', depends=('mutual.depend.two', None), mod_content={'key':1}) build_package(self.loader, 'mutual.depend.two', depends=('mutual.depend.one', None), mod_content={'key':2}) build_package(self.loader, 'depend.on.fail', depends=('external.one', None), mod_content={'key':1}) build_package(self.loader, 'depend.on.cases', depends=[ ('depend.one', None), ('missing.nospec', None), ('missing.spec', version.VersionSpec('2')), ('missing.num', version.VersionNumber('3')), ]) build_package(self.loader, 'unicode.metadata', metadata={ 'test.plain':'result', 'test.unicode':'alpha is \xce\xb1', }) build_package(self.loader, 'mixin.static', resources={ 'zero':'zero.txt', 'one':'one.txt', 'two':'two.txt', 'mixer': { 'dc.title':'Mix-In' }, }, mod_content=[ 'from boopak.package import bexport', 'bexport()', 'from boodle.sample import MixIn', 'class mixer(MixIn):', ' ranges = [', ' MixIn.range(2.0, 2.1, two, volume=1.4),', ' MixIn.range(1.5, one, pitch=1.3),', ' MixIn.range(1.0, zero),', ' ]', ' default = MixIn.default(zero)', ]) build_package(self.loader, 'mixin.file', resources={ 'zero':'zero.txt', 'one':'one.txt', 'two':'two.txt', 'mixer':('mixer.mixin', """ # Comment. range 2 2.1 two - 1.4 range - 1.5 one 1.3 range - 1.0 zero else two """), })