def __getattr__(self, attr): if attr in self.__dict__: return self.__dict__[attr] data = self.__dict__['_data'] from rez.plugin_managers import plugin_manager if attr in plugin_manager.get_plugin_types(): # get plugin config data, and apply overrides plugin_type = attr config_data = plugin_manager.get_plugin_config_data(plugin_type) d = copy.deepcopy(config_data) deep_update(d, data.get(plugin_type, {})) # validate schema = plugin_manager.get_plugin_config_schema(plugin_type) try: d = schema.validate(d) except SchemaError as e: raise ConfigurationError( "Error in Rez configuration under plugins.%s: %s" % (plugin_type, str(e))) elif attr in data: d = data[attr] else: raise AttributeError( "No such configuration setting: 'plugins.%s'" % attr) d_ = convert_dicts(d, RO_AttrDictWrapper) self.__dict__[attr] = d_ return d_
def __getattr__(self, attr): if attr in self.__dict__: return self.__dict__[attr] data = self.__dict__['_data'] from rez.plugin_managers import plugin_manager if attr in plugin_manager.get_plugin_types(): # get plugin config data, and apply overrides plugin_type = attr config_data = plugin_manager.get_plugin_config_data(plugin_type) d = copy.deepcopy(config_data) deep_update(d, data.get(plugin_type, {})) # validate schema = plugin_manager.get_plugin_config_schema(plugin_type) try: d = schema.validate(d) except SchemaError as e: raise ConfigurationError( "Error in Rez configuration under plugins.%s: %s" % (plugin_type, str(e))) elif attr in data: d = data[attr] else: raise AttributeError("No such configuration setting: 'plugins.%s'" % attr) d_ = convert_dicts(d, RO_AttrDictWrapper) self.__dict__[attr] = d_ return d_
def update_settings(self, new_settings, override=False): """Can be called within test methods to modify settings on a per-test basis (as opposed cls.settings, which modifies it for all tests on the class) Note that multiple calls will not "accumulate" updates, but will instead patch the class's settings with the new_settings each time. new_settings : dict the updated settings to override the config with override : bool normally, the resulting config will be the result of merging the base cls.settings with the new_settings - ie, like doing cls.settings.update(new_settings). If this is True, however, then the cls.settings will be ignored entirely, and the new_settings will be the only configuration settings applied """ # restore the "normal" config... from rez.utils.data_utils import deep_update self.teardown_config() # ...then copy the class settings dict to instance, so we can # modify... if override: self.settings = dict(new_settings) else: self.settings = dict(type(self).settings) deep_update(self.settings, new_settings) # now swap the config back in... self.setup_config()
def _data(self): data = copy.deepcopy(self._data_without_overrides) # need to do this regardless of overrides, in order to flatten # ModifyList instances deep_update(data, self.overrides) return data
def config_schema(self): """Returns the merged configuration data schema for this plugin type.""" from rez.config import _plugin_config_dict d = _plugin_config_dict.get(self.type_name, {}) for name, plugin_class in self.plugin_classes.items(): if hasattr(plugin_class, "schema_dict") \ and plugin_class.schema_dict: d_ = {name: plugin_class.schema_dict} deep_update(d, d_) return dict_to_schema(d, required=True, modifier=expand_system_vars)
def _load_config_from_filepaths(filepaths): data = {} sourced_filepaths = [] loaders = ((".py", _load_config_py), ("", _load_config_yaml)) for filepath in filepaths: for extension, loader in loaders: if extension: no_ext = os.path.splitext(filepath)[0] filepath_with_ext = no_ext + extension else: filepath_with_ext = filepath if not os.path.isfile(filepath_with_ext): continue data_ = loader(filepath_with_ext) deep_update(data, data_) sourced_filepaths.append(filepath_with_ext) break return data, sourced_filepaths
def override(self, key, value): def _nosuch(): raise AttributeError("no such setting: %r" % '.'.join(key)) if len(key) < 2: _nosuch() from rez.plugin_managers import plugin_manager if key[0] not in plugin_manager.get_plugin_types(): _nosuch() plugin_type = key[0] key = key[1:] data = {} new_overrides = {plugin_type: data} while len(key) > 1: data_ = {} data[key[0]] = data_ data = data_ key = key[1:] data[key[0]] = value deep_update(self.__dict__['_data'], new_overrides) if plugin_type in self.__dict__: del self.__dict__[plugin_type] # uncache
def load_plugins(self): import pkgutil from rez.backport.importlib import import_module type_module_name = 'rezplugins.' + self.type_name package = import_module(type_module_name) # on import, the `__path__` variable of the imported package is extended # to include existing directories on the plugin search path (via # extend_path, above). this means that `walk_packages` will walk over all # modules on the search path at the same level (.e.g in a # 'rezplugins/type_name' sub-directory). paths = [package.__path__] if isinstance(package.__path__, basestring) \ else package.__path__ # reverse plugin path order, so that custom plugins have a chance to # override the builtin plugins (from /rezplugins). paths = reversed(paths) for path in paths: for loader, modname, ispkg in pkgutil.iter_modules( [path], package.__name__ + '.'): if loader is None: continue plugin_name = modname.split('.')[-1] if plugin_name.startswith('_'): continue if config.debug("plugins"): print_debug("loading %s plugin at %s: %s..." % (self.type_name, path, modname)) try: # load_module will force reload the module if it's # already loaded, so check for that module = sys.modules.get(modname) if module is None: module = loader.find_module(modname).load_module( modname) if hasattr(module, 'register_plugin') and \ hasattr(module.register_plugin, '__call__'): plugin_class = module.register_plugin() if plugin_class != None: self.register_plugin(plugin_name, plugin_class, module) else: if config.debug("plugins"): print_warning( "'register_plugin' function at %s: %s did not return a class." % (path, modname)) else: if config.debug("plugins"): print_warning( "no 'register_plugin' function at %s: %s" % (path, modname)) # delete from sys.modules? except Exception as e: nameish = modname.split('.')[-1] self.failed_plugins[nameish] = str(e) if config.debug("plugins"): import traceback from StringIO import StringIO out = StringIO() traceback.print_exc(file=out) print_debug(out.getvalue()) # load config data, _ = _load_config_from_filepaths( [os.path.join(path, "rezconfig")]) deep_update(self.config_data, data)
def load_plugins(self): import pkgutil from rez.backport.importlib import import_module type_module_name = 'rezplugins.' + self.type_name package = import_module(type_module_name) # on import, the `__path__` variable of the imported package is extended # to include existing directories on the plugin search path (via # extend_path, above). this means that `walk_packages` will walk over all # modules on the search path at the same level (.e.g in a # 'rezplugins/type_name' sub-directory). paths = [package.__path__] if isinstance(package.__path__, basestring) \ else package.__path__ # reverse plugin path order, so that custom plugins have a chance to # be found before the builtin plugins (from /rezplugins). paths = reversed(paths) for path in paths: if config.debug("plugins"): print_debug("searching plugin path %s...", path) for importer, modname, ispkg in pkgutil.iter_modules( [path], package.__name__ + '.'): if importer is None: continue plugin_name = modname.split('.')[-1] if plugin_name.startswith('_') or plugin_name == 'rezconfig': continue if plugin_name in self.plugin_modules: # same named plugins will have identical module name, # which will just reuse previous imported module from # `sys.modules` below. skipping the rest of the process # for good. if config.debug("plugins"): print_warning( "skipped same named %s plugin at %s: %s" % (self.type_name, path, modname)) continue if config.debug("plugins"): print_debug("loading %s plugin at %s: %s..." % (self.type_name, path, modname)) try: # nerdvegas/rez#218 # load_module will force reload the module if it's # already loaded, so check for that plugin_module = sys.modules.get(modname) if plugin_module is None: loader = importer.find_module(modname) plugin_module = loader.load_module(modname) elif os.path.dirname(plugin_module.__file__) != path: if config.debug("plugins"): # this should not happen but if it does, tell why. print_warning( "plugin module %s is not loaded from current " "load path but reused from previous imported " "path: %s" % (modname, plugin_module.__file__)) if (hasattr(plugin_module, "register_plugin") and callable(plugin_module.register_plugin)): plugin_class = plugin_module.register_plugin() if plugin_class is not None: self.register_plugin(plugin_name, plugin_class, plugin_module) else: if config.debug("plugins"): print_warning( "'register_plugin' function at %s: %s did " "not return a class." % (path, modname)) else: if config.debug("plugins"): print_warning( "no 'register_plugin' function at %s: %s" % (path, modname)) # delete from sys.modules? except Exception as e: nameish = modname.split('.')[-1] self.failed_plugins[nameish] = str(e) if config.debug("plugins"): import traceback from rez.vendor.six.six import StringIO out = StringIO() traceback.print_exc(file=out) print_debug(out.getvalue()) # load config data, _ = _load_config_from_filepaths( [os.path.join(path, "rezconfig")]) deep_update(self.config_data, data)