def from_path(cls, path): """Load a developer package. A developer package may for example be a package.yaml or package.py in a user's source directory. Args: path: Directory containing the package definition file. Returns: `Package` object. """ name = None data = None for name_ in config.plugins.package_repository.filesystem.package_filenames: for format_ in (FileFormat.py, FileFormat.yaml): filepath = os.path.join(path, "%s.%s" % (name_, format_.extension)) if os.path.isfile(filepath): data = load_from_file(filepath, format_) break if data: name = data.get("name") if name is not None or isinstance(name, basestring): break if data is None: raise PackageMetadataError("No package definition file found at %s" % path) if name is None or not isinstance(name, basestring): raise PackageMetadataError( "Error in %r - missing or non-string field 'name'" % filepath) package = create_package(name, data, package_cls=cls) # preprocessing result = package._get_preprocessed(data) if result: package, data = result package.filepath = filepath # find all includes, this is needed at install time to copy the right # py sourcefiles into the package installation package.includes = set() def visit(d): for k, v in d.iteritems(): if isinstance(v, SourceCode): package.includes |= (v.includes or set()) elif isinstance(v, dict): visit(v) visit(data) package._validate_includes() return package
def test_1_memory_variant_parent(self): """Test that a package's variant's parent is the original package """ desc = 'the foo package' package = create_package('foo', {'description': desc}) self.assertEqual(package.description, desc) variant = package.iter_variants().next() parent_package = variant.parent self.assertEqual(package.description, desc)
def test_4(self): """test package creation.""" package_data = { "name": "foo", "version": "1.0.0", "description": "something foo-like", "requires": ["python-2.6+"]} package = create_package("foo", package_data) self.assertEqual(package.version, Version("1.0.0")) self.assertEqual(package.description, "something foo-like") self.assertEqual(package.requires, [PackageRequest("python-2.6+")]) family = package.parent self.assertEqual(family.name, package.name) packages = list(family.iter_packages()) self.assertEqual(len(packages), 1) self.assertEqual(package, packages[0])
def from_path(cls, path): """Load a developer package. A developer package may for example be a package.yaml or package.py in a user's source directory. Args: path: Directory containing the package definition file. Returns: `Package` object. """ name = None data = None for name_ in config.plugins.package_repository.filesystem.package_filenames: for format_ in (FileFormat.py, FileFormat.yaml): filepath = os.path.join(path, "%s.%s" % (name_, format_.extension)) if os.path.isfile(filepath): data = load_from_file(filepath, format_) break if data: name = data.get("name") if name is not None or isinstance(name, basestring): break if data is None: raise PackageMetadataError( "No package definition file found at %s" % path) if name is None or not isinstance(name, basestring): raise PackageMetadataError( "Error in %r - missing or non-string field 'name'" % filepath) package = create_package(name, data, package_cls=cls) # preprocessing result = package._get_preprocessed(data) if result: package, data = result package.filepath = filepath # find all includes, this is needed at install time to copy the right # py sourcefiles into the package installation package.includes = set() def visit(d): for k, v in d.iteritems(): if isinstance(v, SourceCode): package.includes |= (v.includes or set()) elif isinstance(v, dict): visit(v) visit(data) package._validate_includes() return package
def _get_preprocessed(self, data): """ Returns: (DeveloperPackage, new_data) 2-tuple IFF the preprocess function changed the package; otherwise None. """ from rez.serialise import process_python_objects from rez.utils.data_utils import get_dict_diff from copy import deepcopy with add_sys_paths(config.package_definition_build_python_paths): preprocess = getattr(self, "preprocess", None) if preprocess: preprocess_func = preprocess.func print_info("Applying preprocess from package.py") else: # load globally configured preprocess function dotted = self.config.package_preprocess_function if not dotted: return None if '.' not in dotted: print_error( "Setting 'package_preprocess_function' must be of " "form 'module[.module.module...].funcname'. Package " "preprocessing has not been applied.") return None name, funcname = dotted.rsplit('.', 1) try: module = __import__(name=name, fromlist=[funcname]) except Exception as e: print_error( "Failed to load preprocessing function '%s': %s" % (dotted, str(e))) return None setattr(module, "InvalidPackageError", InvalidPackageError) preprocess_func = getattr(module, funcname) if not preprocess_func or not isfunction(isfunction): print_error("Function '%s' not found" % dotted) return None print_info("Applying preprocess function %s" % dotted) preprocessed_data = deepcopy(data) # apply preprocessing try: preprocess_func(this=self, data=preprocessed_data) except InvalidPackageError: raise except Exception as e: print_error("Failed to apply preprocess: %s: %s" % (e.__class__.__name__, str(e))) return None # if preprocess added functions, these need to be converted to # SourceCode instances preprocessed_data = process_python_objects(preprocessed_data) if preprocessed_data == data: return None # recreate package from modified package data package = create_package(self.name, preprocessed_data, package_cls=self.__class__) # print summary of changed package attributes added, removed, changed = get_dict_diff(data, preprocessed_data) lines = ["Package attributes were changed in preprocessing:"] if added: lines.append("Added attributes: %s" % ['.'.join(x) for x in added]) if removed: lines.append("Removed attributes: %s" % ['.'.join(x) for x in removed]) if changed: lines.append("Changed attributes: %s" % ['.'.join(x) for x in changed]) txt = '\n'.join(lines) print_info(txt) return package, preprocessed_data
def from_path(cls, path, format=None): """Load a developer package. A developer package may for example be a package.yaml or package.py in a user's source directory. Args: path: Directory containing the package definition file, or file path for the package file itself format: which FileFormat to use, or None to check both .py and .yaml Returns: `Package` object. """ name = None data = None if format is None: formats = (FileFormat.py, FileFormat.yaml) else: formats = (format,) try: mode = os.stat(path).st_mode except (IOError, OSError): raise PackageMetadataError( "Path %r did not exist, or was not accessible" % path) is_dir = stat.S_ISDIR(mode) for name_ in config.plugins.package_repository.filesystem.package_filenames: for format_ in formats: if is_dir: filepath = os.path.join(path, "%s.%s" % (name_, format_.extension)) exists = os.path.isfile(filepath) else: # if format was not specified, verify that it has the # right extension before trying to load if format is None: if os.path.splitext(path)[1] != format_.extension: continue filepath = path exists = True if exists: data = load_from_file(filepath, format_, disable_memcache=True) break if data: name = data.get("name") if name is not None or isinstance(name, basestring): break if data is None: raise PackageMetadataError("No package definition file found at %s" % path) if name is None or not isinstance(name, basestring): raise PackageMetadataError( "Error in %r - missing or non-string field 'name'" % filepath) package = create_package(name, data, package_cls=cls) # preprocessing result = package._get_preprocessed(data) if result: package, data = result package.filepath = filepath # find all includes, this is needed at install time to copy the right # py sourcefiles into the package installation package.includes = set() def visit(d): for k, v in d.iteritems(): if isinstance(v, SourceCode): package.includes |= (v.includes or set()) elif isinstance(v, dict): visit(v) visit(data) package._validate_includes() return package
def _get_preprocessed(self, data): """ Returns: (DeveloperPackage, new_data) 2-tuple IFF the preprocess function changed the package; otherwise None. """ from rez.serialise import process_python_objects from rez.utils.data_utils import get_dict_diff_str from copy import deepcopy with add_sys_paths(config.package_definition_build_python_paths): preprocess_func = getattr(self, "preprocess", None) if preprocess_func: print_info("Applying preprocess from package.py") else: # load globally configured preprocess function dotted = self.config.package_preprocess_function if not dotted: return None if '.' not in dotted: print_error( "Setting 'package_preprocess_function' must be of " "form 'module[.module.module...].funcname'. Package " "preprocessing has not been applied.") return None name, funcname = dotted.rsplit('.', 1) try: module = __import__(name=name, fromlist=[funcname]) except Exception as e: print_error("Failed to load preprocessing function '%s': %s" % (dotted, str(e))) return None setattr(module, "InvalidPackageError", InvalidPackageError) preprocess_func = getattr(module, funcname) if not preprocess_func or not isfunction(isfunction): print_error("Function '%s' not found" % dotted) return None print_info("Applying preprocess function %s" % dotted) preprocessed_data = deepcopy(data) # apply preprocessing try: preprocess_func(this=self, data=preprocessed_data) except InvalidPackageError: raise except Exception as e: print_error("Failed to apply preprocess: %s: %s" % (e.__class__.__name__, str(e))) return None # if preprocess added functions, these may need to be converted to # SourceCode instances preprocessed_data = process_python_objects(preprocessed_data) if preprocessed_data == data: return None # recreate package from modified package data package = create_package(self.name, preprocessed_data, package_cls=self.__class__) # print summary of changed package attributes txt = get_dict_diff_str( data, preprocessed_data, title="Package attributes were changed in preprocessing:" ) print_info(txt) return package, preprocessed_data
def _get_preprocessed(self, data): """ Returns: (DeveloperPackage, new_data) 2-tuple IF the preprocess function changed the package; otherwise None. """ from rez.serialise import process_python_objects from rez.utils.data_utils import get_dict_diff_str from copy import deepcopy package_preprocess_mode = self.config.package_preprocess_mode def _get_package_level(): return getattr(self, "preprocess", None) def _get_global_level(): # load globally configured preprocess function package_preprocess_function = self.config.package_preprocess_function if not package_preprocess_function: return None elif isfunction(package_preprocess_function): preprocess_func = package_preprocess_function else: if '.' not in package_preprocess_function: print_error( "Setting 'package_preprocess_function' must be of " "form 'module[.module.module...].funcname'. Package " "preprocessing has not been applied.") return None elif isinstance(package_preprocess_function, basestring): if '.' not in package_preprocess_function: print_error( "Setting 'package_preprocess_function' must be of " "form 'module[.module.module...].funcname'. " "Package preprocessing has not been applied." ) return None name, funcname = package_preprocess_function.rsplit('.', 1) try: module = __import__(name=name, fromlist=[funcname]) except Exception as e: print_error( "Failed to load preprocessing function '%s': %s" % (package_preprocess_function, str(e)) ) return None setattr(module, "InvalidPackageError", InvalidPackageError) preprocess_func = getattr(module, funcname) else: print_error( "Invalid package_preprocess_function: %s" % package_preprocess_function ) return None if not preprocess_func or not isfunction(preprocess_func): print_error("Function '%s' not found" % package_preprocess_function) return None return preprocess_func with add_sys_paths(config.package_definition_build_python_paths): preprocess_mode = PreprocessMode[self.config.package_preprocess_mode] package_preprocess = _get_package_level() global_preprocess = _get_global_level() if preprocess_mode == PreprocessMode.after: preprocessors = [global_preprocess, package_preprocess] elif preprocess_mode == PreprocessMode.before: preprocessors = [package_preprocess, global_preprocess] else: preprocessors = [package_preprocess or global_preprocess] preprocessed_data = deepcopy(data) for preprocessor in preprocessors: if not preprocessor: continue level = "global" if preprocessor == global_preprocess else "local" print_info("Applying {0} preprocess function".format(level)) # apply preprocessing try: preprocessor(this=self, data=preprocessed_data) except InvalidPackageError: raise except Exception as e: print_error("Failed to apply preprocess: %s: %s" % (e.__class__.__name__, str(e))) return None # if preprocess added functions, these may need to be converted to # SourceCode instances preprocessed_data = process_python_objects(preprocessed_data) if preprocessed_data == data: return None # recreate package from modified package data package = create_package(self.name, preprocessed_data, package_cls=self.__class__) # print summary of changed package attributes txt = get_dict_diff_str( data, preprocessed_data, title="Package attributes were changed in preprocessing:" ) print_info(txt) return package, preprocessed_data