def test_load(): ep = entrypoints.EntryPoint('get_ep', 'entrypoints', 'get_single', None) obj = ep.load() assert obj is entrypoints.get_single # The object part is optional (e.g. pytest plugins use just a module ref) ep = entrypoints.EntryPoint('ep_mod', 'entrypoints', None) obj = ep.load() assert obj is entrypoints
def from_conf(self): return [ entrypoints.EntryPoint(name=k, module_name=v.rsplit(":", 1)[0] if ":" in v else v.rsplit(".", 1)[0], object_name=v.rsplit(":", 1)[1] if ":" in v else v.rsplit(".", 1)[1]) for k, v in self.conf.get("drivers", {}).items() if v ]
class TestFailedToLoadPlugin(_ExceptionTest): """Tests for the FailedToLoadPlugin exception.""" err = exceptions.FailedToLoadPlugin( plugin=plugins_manager.Plugin( 'plugin_name', entrypoints.EntryPoint('plugin_name', 'os.path', None), ), exception=ValueError('boom!'), )
def register(self, target_name, plugin_module): """ Register a deployment client given its target name and module :param target_name: The name of the deployment target. This name will be used by `get_deploy_client()` to retrieve a deployment client from the plugin store :param plugin_module: The module that implements the deployment plugin interface """ self.registry[target_name] = entrypoints.EntryPoint( target_name, plugin_module, None)
def test_cannot_getattr_bad(self): self.setup_entry(entrypoints.EntryPoint('bad', 'really_bad', '')) assert 'bad' in dir(bio) assert 'bad' in bio.FORMATS with pytest.raises(AttributeError, match='not loadable'): bio.bad assert 'bad' not in dir(bio) assert 'bad' not in bio.FORMATS with pytest.raises(AttributeError, match='has no attribute'): bio.bad
def test_find_new(self): self.setup_entry(entrypoints.EntryPoint('new', 'baseband.vdif', '')) assert 'new' in dir(bio) assert 'new' in bio.FORMATS assert bio.new is vdif # Check that it comes back if we remove it from the module. bio.__dict__.pop('new', None) assert 'new' not in bio.__dict__ assert 'new' in bio.FORMATS assert 'new' in dir(bio) assert bio.new is vdif
def test_fake_bad_vdif(self): assert bio.vdif is vdif del bio.vdif bio._entries['vdif'] = entrypoints.EntryPoint('vdif', 'bad.vdif', '') with pytest.raises(AttributeError, match='not loadable'): bio.vdif assert 'vdif' not in dir(bio) assert 'vdif' in bio._bad_entries # Does not auto-reload since already known as bad. with pytest.raises(AttributeError, match='has no attribute'): bio.vdif # But will reload if we reload and thus start over. reload(bio) assert bio.vdif is vdif assert 'vdif' in bio.FORMATS
def __getattr__(attr): """Get a missing attribute from a possible entry point. Looks for the attribute among the (possibly updated) entry points, and, if found, tries loading the entry. If that fails, the entry is added to _bad_entries to ensure it does not recur. """ if attr.startswith('_') or attr in _bad_entries: raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") FORMATS = globals().setdefault('FORMATS', []) if attr not in _entries: if not _entries: # On initial update, we add our own formats as explicit entries, # in part to set some order, but also so things work even in a # pure source checkout, where entry points are missing. _entries.update({ fmt: entrypoints.EntryPoint(fmt, 'baseband.'+fmt, '') for fmt in ('dada', 'guppi', 'mark4', 'mark5b', 'vdif', 'gsb') }) _entries.update(entrypoints.get_group_named('baseband.io')) FORMATS.extend([name for name, entry in _entries.items() if not (entry.object_name or name in FORMATS)]) if attr == 'FORMATS': return FORMATS entry = _entries.get(attr, None) if entry is None: raise AttributeError(f"module {__name__!r} has no attribute {attr!r}") try: value = entry.load() except Exception: _entries.pop(attr) _bad_entries.add(attr) if attr in FORMATS: FORMATS.remove(attr) raise AttributeError(f"{entry} was not loadable. Now removed") # Update so we do not have to go through __getattr__ again. globals()[attr] = value return value
def autodiscover(path=None, plugin_prefix='intake_', do_package_scan=False): r"""Discover intake drivers. In order of decreasing precedence: - Respect the 'drivers' section of the intake configuration file. - Find 'intake.drivers' entrypoints provided by any Python packages in the environment. - Search all packages in the environment for names that begin with ``intake\_``. Import them and scan them for subclasses of ``intake.source.base.DataSourceBase``. This was previously the *only* mechanism for auto-discoverying intake drivers, and it is maintained for backward compatibility. Parameters ---------- path : str or None Default is ``sys.path``. plugin_prefix : str DEPRECATED. Default is 'intake\_'. do_package_scan : boolean Whether to look for intake source classes in packages named "intake_*". This has been superceded by entrypoints declarations. Returns ------- drivers : dict Name mapped to driver class. """ # Discover drivers via package scan. if do_package_scan: package_scan_results = _package_scan(path, plugin_prefix) if package_scan_results: warnings.warn( "The option `do_package_scan` may be removed in a future release.", PendingDeprecationWarning) else: package_scan_results = {} # Discover drivers via entrypoints. group = entrypoints.get_group_named('intake.drivers', path=path) group_all = entrypoints.get_group_all('intake.drivers', path=path) if len(group_all) != len(group): # There are some name collisions. Let's go digging for them. for name, matches in itertools.groupby(group_all, lambda ep: ep.name): matches = list(matches) if len(matches) != 1: winner = group[name] logger.debug( "There are %d 'intake.driver' entrypoints for the name " "%r. They are %r. The match %r has won the race.", len(matches), name, matches, winner) for name, entrypoint in group.items(): logger.debug("Discovered entrypoint '%s = %s.%s'", name, entrypoint.module_name, entrypoint.object_name) if name in package_scan_results: cls = package_scan_results[name] del package_scan_results[name] logger.debug("Entrypoint shadowed package_scan result '%s = %s.%s'", name, cls.__module__, cls.__name__) # Discover drivers via config. drivers_conf = conf.get('drivers', {}) logger.debug("Using configuration file at %s", cfile()) for name, dotted_object_name in drivers_conf.items(): if not dotted_object_name: logger.debug('Name %s is banned in config file', name) if name in group: entrypoint = group[name] del group[name] logger.debug("Disabled entrypoint '%s = %s.%s'", entrypoint.name, entrypoint.module_name, entrypoint.object_name) if name in package_scan_results: cls = package_scan_results[name] del package_scan_results[name] logger.debug("Disabled package_scan result '%s = %s.%s'", name, cls.__module__, cls.__name__) continue module_name, object_name = dotted_object_name.rsplit('.', 1) entrypoint = entrypoints.EntryPoint(name, module_name, object_name) logger.debug("Discovered config-specified '%s = %s.%s'", entrypoint.name, entrypoint.module_name, entrypoint.object_name) if name in group: shadowed = group[name] logger.debug("Config shadowed entrypoint '%s = %s.%s'", shadowed.name, shadowed.module_name, shadowed.object_name) if name in package_scan_results: cls = package_scan_results[name] del package_scan_results[name] logger.debug("Config shadowed package scan result '%s = %s.%s'", name, cls.__module__, cls.__name__) group[name] = entrypoint # Discovery is complete. if package_scan_results: warnings.warn( f"The drivers {list(package_scan_results)} do not specify entry_" f"points and were only discovered via a package scan. This may " f"break in a future release of intake. The packages should be " f"updated.", FutureWarning) # Load entrypoints. Any that were shadowed or banned have already been # removed above. drivers = {} for entrypoint in group.values(): try: drivers[entrypoint.name] = _load_entrypoint(entrypoint) except ConfigurationError: logger.exception( "Error while loading entrypoint %s", entrypoint.name) continue logger.debug("Loaded entrypoint '%s = %s.%s'", entrypoint.name, entrypoint.module_name, entrypoint.object_name) # Now include any package scan results. Any that were shadowed or # banned have already been removed above. for name, cls in package_scan_results.items(): drivers[name] = cls logger.debug("Loaded package scan result '%s = %s.%s'", name, cls.__module__, cls.__name__) return drivers
def autodiscover_all(path=None, plugin_prefix='intake_', do_package_scan=True): """Discover intake drivers including those registered for the same name. Parameters ---------- path : str or None Default is ``sys.path``. plugin_prefix : str DEPRECATED. Default is 'intake_'. do_package_scan : boolean Default is True. In the future, the default will be changed to False, and the option may eventually be removed entirely. Returns ------- drivers : list Each entry is a tuple: ``(name, driver_class)``. """ # Discover drivers via package scan. if do_package_scan: warnings.warn( "The option `do_package_scan` may be removed in a future release.", PendingDeprecationWarning) package_scan_results = _package_scan(path, plugin_prefix) else: package_scan_results = {} # Discover drivers via entrypoints. group_all = entrypoints.get_group_all('intake.drivers', path=path) for entrypoint in group_all: logger.debug("Discovered entrypoint '%s = %s.%s'", entrypoint.name, entrypoint.module_name, entrypoint.object_name) # Discover drivers via config. drivers_conf = conf.get('drivers', {}) logger.debug("Using configuration file at %s", cfile()) for name, dotted_object_name in drivers_conf.items(): if not dotted_object_name: continue module_name, object_name = dotted_object_name.rsplit('.', 1) entrypoint = entrypoints.EntryPoint(name, module_name, object_name) logger.debug("Discovered config-specified '%s = %s.%s'", entrypoint.name, entrypoint.module_name, entrypoint.object_name) group_all.append(entrypoint) # Load entrypoints. Any that were shadowed or banned have already been # removed above. drivers = [] for entrypoint in group_all: try: drivers.append((entrypoint.name, _load_entrypoint(entrypoint))) except ConfigurationError: logger.exception( "Error while loading entrypoint %s", entrypoint.name) continue logger.debug("Loaded entrypoint '%s = %s.%s'", entrypoint.name, entrypoint.module_name, entrypoint.object_name) # Now include any package scan results. Any that were shadowed or # banned have already been removed above. for name, cls in package_scan_results.items(): drivers.append((name, cls)) logger.debug("Loaded package scan result '%s = %s.%s'", name, cls.__module__, cls.__name__) return drivers
def test_not_hasattr_bad(self): self.setup_entry(entrypoints.EntryPoint('bad', 'really_bad', '')) assert 'bad' in dir(bio) assert not hasattr(bio, 'bad') assert 'bad' not in dir(bio)