def accept(self, source): val = source.pop_word(self) pos = val.find('/') if pos < 0: raise CommandError('Not of form package/resource: ' + val) res = val[pos + 1:] val = val[:pos] try: pinfo.parse_resource_name(res) except: raise CommandError('Invalid resource name: ' + res) try: (pkg, vers) = pinfo.parse_package_version_spec(val) except: raise CommandError('Invalid package name: ' + val) return ((pkg, vers), res)
def 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.) """ file = pkg.get_file(filename) keyls = parse_resource_name(wholekey) attr = keyls.pop() for key in keyls: submod = getattr(mod, key, None) if (submod is None): # Create an empty submodule. (fl, pathname, desc) = imp.find_module('emptymodule', boopak.__path__) try: submod = imp.load_module(mod.__name__+'.'+key, fl, pathname, desc) finally: # Clean up. if (fl): fl.close() setattr(mod, key, submod) if (type(submod) != types.ModuleType): raise ValueError('resource key based on non-module: ' + wholekey) if (mod.__name__+'.'+key != submod.__name__): raise ValueError('resource key based on imported module: ' + wholekey) mod = submod # We've drilled down so that mod is the next-to-last element # of the original wholekey. setattr(mod, attr, file) file.metadata = res # Set properties analogous to a statically-declared object. This # will help with find_item_resources() later on. file.__module__ = mod.__name__ file.__name__ = attr
def test_parse_resource_name(self): valid_list = [ ('hello', ['hello']), ('Hello.FOO.X0', ['Hello', 'FOO', 'X0']), ('X', ['X']), ('h.e.l.l.o', ['h', 'e', 'l', 'l', 'o']), ('x_00t_99', ['x_00t_99']), ('t0.t1', ['t0', 't1']), ('_._005_.a', ['_', '_005_', 'a']), ] invalid_list = [ '', ' ', '.', 'a.', '.b', '.c.', 'd..e', '..', 'x ', ' y', 'a b', 'a. b', 'a .b', '0', '0x', 'a.0', 'x.y.9z', 'a,b', 'a-b', 'a+b', 'a/b', 'a\\b', ] for (name, result) in valid_list: res = parse_resource_name(name) self.assertEqual(res, result) for name in invalid_list: self.assertRaises(ValueError, parse_resource_name, name)
def 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. """ if (not self.importing_ok): raise Exception('this loader may not import package data!') if (not (pkg.content is None)): return if (pkg.import_in_progress): raise Exception('package imported while import is in progress: ' + pkg.name) attrify_resources = False map_resources = False maincode = pkg.metadata.get_one('boodler.main') if (not maincode): attrify_resources = True (file, pathname, desc) = imp.find_module('emptymodule', boopak.__path__) else: map_resources = True (file, pathname, desc) = imp.find_module(maincode, [pkg.dir]) if (not desc[0] in ['', '.py', '.pyc']): if (file): file.close() raise PackageLoadError(pkg.name, 'module must be .py or .pyc: ' + pathname) # Imports can occur recursively, so we always hold on to the previous # value and restore it afterward. previously_importing = self.currently_importing self.currently_importing = pkg pkg.import_in_progress = True try: mod = imp.load_module(pkg.encoded_name, file, pathname, desc) finally: # Clean up. if (file): file.close() pkg.import_in_progress = False checkpkg = self.currently_importing self.currently_importing = previously_importing if (checkpkg != pkg): raise Exception('import stack unstable: ' + pkg.name) if (attrify_resources): for res in pkg.resources.resources(): filename = res.get_one('boodler.filename') if (filename): self.attrify_filename(pkg, mod, res.key, res, filename) if (map_resources): # Look for declarations in the module which are named in # the resources map. Cache the mapping from the declaration # to the resource object. for res in pkg.resources.resources(): keyls = parse_resource_name(res.key) submod = mod for key in keyls: submod = getattr(submod, key, None) if (submod is None): break if (not (submod is None)): pkg.content_info[submod] = res # The import is complete. self.module_info[mod] = pkg pkg.content = mod
def 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. """ if not self.importing_ok: raise Exception('this loader may not import package data!') if pkg.content is not None: return if pkg.import_in_progress: raise Exception('package imported while import is in progress: ' + pkg.name) attrify_resources = False map_resources = False maincode = pkg.metadata.get_one('boodler.main') # Imports can occur recursively, so we always hold on to the previous # value and restore it afterward. previously_importing = self.currently_importing self.currently_importing = pkg pkg.import_in_progress = True try: if not maincode: attrify_resources = True mod = load_module(pkg.encoded_name, 'emptymodule', boopak.__path__[0]) else: map_resources = True mod = load_module(pkg.encoded_name, maincode, pkg.dir) finally: pkg.import_in_progress = False checkpkg = self.currently_importing self.currently_importing = previously_importing if checkpkg != pkg: raise Exception('import stack unstable: ' + pkg.name) if attrify_resources: for res in pkg.resources.resources(): filename = res.get_one('boodler.filename') if filename: self.attrify_filename(pkg, mod, res.key, res, filename) if map_resources: # Look for declarations in the module which are named in # the resources map. Cache the mapping from the declaration # to the resource object. for res in pkg.resources.resources(): keyls = parse_resource_name(res.key) submod = mod for key in keyls: submod = getattr(submod, key, None) if submod is None: break if submod is not None: pkg.content_info[submod] = res # The import is complete. self.module_info[mod] = pkg return mod