Source code for exopy.utils.declarator

# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright 2015-2018 by Exopy Authors, see AUTHORS for more details.
#
# Distributed under the terms of the BSD license.
#
# The full license is in the file LICENCE, distributed with this software.
# -----------------------------------------------------------------------------
"""Base class for extension declaration relying on a visitor pattern.

"""
import re
from importlib import import_module

from atom.api import Str, Bool
from enaml.core.api import Declarative, d_

from .traceback import format_exc


[docs]class Declarator(Declarative): """Base class for extension object which uses a visitor pattern. """ #: Flag indicating whether the declarator has been successfully registered is_registered = Bool()
[docs] def get_path(self): """Query from parent the path to use for this declarator. Returns ------- path : unicode or None Path declared by the parent. This can be None if no path is declared. """ if isinstance(self.parent, Declarator): return self.parent.get_path()
[docs] def get_group(self): """Get the group defined by the closest parent. """ if not isinstance(self.parent, Declarator): return group = getattr(self.parent, 'group', None) if group: return group return self.parent.get_group()
[docs] def register(self, collector, traceback): """Add the contribution of this extension to the plugin. Parameters ---------- collector : DeclaratorCollector Collector in charge handling the registering of declarators. Contributions should be added to the contributions member (Dict). If a declarator cannot be registered because another one need to be registered first it should add itself to the _delayed member (List) traceback : dict Dictionary in which any issue occuring during registration should be recorded. """ raise NotImplementedError()
[docs] def unregister(self, plugin): """Remove the contribution of this extension to the plugin. Parameters ---------- collector : DeclaratorCollector Collector in charge handling the registering of declarators. """ raise NotImplementedError()
def __str__(self): """Provide a nice string representation of the object. """ raise NotImplementedError()
PATH_VALIDATOR = re.compile('^(\.?\w+)*$')
[docs]class GroupDeclarator(Declarator): """Declarator used to group an ensemble of declarator. """ #: Prefix path to use for all children Declarator. Path should be dot #: separated. path = d_(Str()) #: Id of the group common to all children Declarator. It is the #: responsability of the children to mention they are part of a group. group = d_(Str())
[docs] def get_path(self): """Overriden method to walk all parents. """ paths = [] if isinstance(self.parent, GroupDeclarator): parent_path = self.parent.get_path() if parent_path: paths.append(parent_path) if self.path: paths.append(self.path) if paths: return '.'.join(paths)
[docs] def register(self, plugin, traceback): """Register all children Declarator. """ if not PATH_VALIDATOR.match(self.path): msg = 'Invalid path {} in {} (path {}, group {})' traceback['Error %s' % len(traceback)] = msg.format(self.path, type(self), self.path, self.group) return for ch in self.children: if not isinstance(ch, Declarator): msg = 'All children of GroupDeclarator must be Declarator, got' traceback['Error %s' % len(traceback)] = msg + '%s' % type(ch) continue ch.register(plugin, traceback) self.is_registered = True
[docs] def unregister(self, plugin): """Unregister all children Declarator. """ if self.is_registered: for ch in self.children: if isinstance(ch, Declarator): ch.unregister(plugin) self.is_registered = False
def __str__(self): """Identify the declarator by its path and group. """ st = '{} whose path is "{}" and group is "{}" declaring :\n{}' return st.format(type(self).__name__, self.path, self.group, '\n'.join(' - {}'.format(c) for c in self.children))
[docs]def import_and_get(path, name, traceback, id): """Function importing a module and retrieving an object from it. This function provides a common pattern for declarator. """ import enaml try: with enaml.imports(): mod = import_module(path) except Exception: msg = 'Failed to import {} :\n{}' traceback[id] = msg.format(path, format_exc()) return try: return getattr(mod, name) except AttributeError: msg = '{} has no attribute {}:\n{}' traceback[id] = msg.format(path, name, format_exc()) return