#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
**manager.py**
**Platform:**
Windows, Linux, Mac Os X.
**Description:**
Defines the :class:`Manager` class and others helper objects.
**Others:**
"""
#**********************************************************************************************************************
#*** Future imports.
#**********************************************************************************************************************
from __future__ import unicode_literals
#**********************************************************************************************************************
#*** External imports.
#**********************************************************************************************************************
import inspect
import itertools
import os
import sys
import re
#**********************************************************************************************************************
#*** Internal imports.
#**********************************************************************************************************************
import foundations.common
import foundations.dataStructures
import foundations.exceptions
import foundations.strings
import foundations.verbose
import foundations.walkers
import manager.exceptions
from foundations.parsers import SectionsFileParser
from manager.component import Component
from manager.qobjectComponent import QObjectComponent
from manager.qwidgetComponent import QWidgetComponentFactory
#**********************************************************************************************************************
#*** Module attributes.
#**********************************************************************************************************************
__author__ = "Thomas Mansencal"
__copyright__ = "Copyright (C) 2008 - 2014 - Thomas Mansencal"
__license__ = "GPL V3.0 - http://www.gnu.org/licenses/"
__maintainer__ = "Thomas Mansencal"
__email__ = "[email protected]"
__status__ = "Production"
__all__ = ["LOGGER", "Components", "Profile", "Manager"]
LOGGER = foundations.verbose.installLogger()
#**********************************************************************************************************************
#*** Module classes and definitions.
#**********************************************************************************************************************
[docs]class Components(foundations.dataStructures.Structure):
"""
Defines a storage object for :class:`Manager` class Components.
"""
def __init__(self, **kwargs):
"""
Initializes the class.
:param \*\*kwargs: Arguments.
:type \*\*kwargs: dict
"""
LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__))
foundations.dataStructures.Structure.__init__(self, **kwargs)
[docs]class Profile(object):
"""
Stores :class:`Manager` class Components informations and objects.
"""
def __init__(self, name=None, file=None):
"""
Initializes the class.
:param name: Name of the Component.
:type name: unicode
:param file: File of the Component.
:type file: unicode
"""
LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__))
# --- Setting class attributes. ---
self.__name = None
self.name = name
self.__file = None
self.file = file
self.__directory = None
self.__attribute = None
self.__require = None
self.__module = None
self.__interface = None
self.__category = None
self.__title = None
self.__package = None
self.__version = None
self.__author = None
self.__email = None
self.__url = None
self.__description = None
#******************************************************************************************************************
#*** Attributes properties.
#******************************************************************************************************************
@property
def name(self):
"""
Property for **self.__name** attribute.
:return: self.__name.
:rtype: unicode
"""
return self.__name
@name.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def name(self, value):
"""
Setter for **self.__name** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"name", value)
self.__name = value
@name.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def name(self):
"""
Deleter for **self.__name** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "name"))
@property
def file(self):
"""
Property for **self.__file** attribute.
:return: self.__file.
:rtype: unicode
"""
return self.__file
@file.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def file(self, value):
"""
Setter for **self.__file** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format("file", value)
self.__file = value
@file.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def file(self):
"""
Deleter for **self.__file** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "file"))
@property
def directory(self):
"""
Property for **self.__directory** attribute.
:return: self.__directory.
:rtype: unicode
"""
return self.__directory
@directory.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def directory(self, value):
"""
Setter for **self.__directory** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"directory", value)
assert os.path.exists(value), "'{0}' attribute: '{1}' directory doesn't exists!".format("directory", value)
self.__directory = value
@directory.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def directory(self):
"""
Deleter for **self.__directory** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "directory"))
@property
def attribute(self):
"""
Property for **self.__attribute** attribute.
:return: self.__attribute.
:rtype: unicode
"""
return self.__attribute
@attribute.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def attribute(self, value):
"""
Setter for **self.__attribute** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"attribute", value)
self.__attribute = value
@attribute.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def attribute(self):
"""
Deleter for **self.__attribute** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "attribute"))
@property
def require(self):
"""
Property for **self.__require** attribute.
:return: self.__require.
:rtype: tuple or list
"""
return self.__require
@require.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def require(self, value):
"""
Setter for **self.__require** attribute.
:param value: Attribute value.
:type value: tuple or list
"""
if value is not None:
assert type(value) in (tuple, list), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format(
"require", value)
self.__require = value
@require.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def require(self):
"""
Deleter for **self.__require** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "require"))
@property
def module(self):
"""
Property for **self.__module** attribute.
:return: self.__module.
:rtype: ModuleType
"""
return self.__module
@module.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def module(self, value):
"""
Setter for **self.__module** attribute.
:param value: Attribute value.
:type value: ModuleType
"""
if value is not None:
assert type(value) is type(sys), "'{0}' attribute: '{1}' type is not 'module'!".format("module", value)
self.__module = value
@module.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def module(self):
"""
Deleter for **self.__module** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "module"))
@property
def interface(self):
"""
Property for **self.__interface** attribute.
:return: self.__interface.
:rtype: object
"""
return self.__interface
@interface.setter
def interface(self, value):
"""
Setter for **self.__interface** attribute.
:param value: Attribute value.
:type value: object
"""
self.__interface = value
@interface.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def interface(self):
"""
Deleter for **self.__interface** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "interface"))
@property
def category(self):
"""
Property for **self.__category** attribute.
:return: self.__category.
:rtype: unicode
"""
return self.__category
@category.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def category(self, value):
"""
Setter for **self.__category** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"category", value)
self.__category = value
@category.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def category(self):
"""
Deleter for **self.__category** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "category"))
@property
def title(self):
"""
Property for **self.__title** attribute.
:return: self.__title.
:rtype: unicode
"""
return self.__title
@title.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def title(self, value):
"""
Setter for **self.__title** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"title", value)
self.__title = value
@title.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def title(self):
"""
Deleter for **self.__title** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "title"))
@property
def package(self):
"""
Property for **self.__package** attribute.
:return: self.__package.
:rtype: unicode
"""
return self.__package
@package.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def package(self, value):
"""
Setter for **self.__package** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"package", value)
self.__package = value
@package.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def package(self):
"""
Deleter for **self.__package** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "package"))
@property
def version(self):
"""
Property for **self.__version** attribute.
:return: self.__version.
:rtype: unicode
"""
return self.__version
@version.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def version(self, value):
"""
Setter for **self.__version** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"version", value)
self.__version = value
@version.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def version(self):
"""
Deleter for **self.__version** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "version"))
@property
def author(self):
"""
Property for **self.__author** attribute.
:return: self.__author.
:rtype: unicode
"""
return self.__author
@author.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def author(self, value):
"""
Setter for **self.__author** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"author", value)
self.__author = value
@author.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def author(self):
"""
Deleter for **self.__author** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "author"))
@property
def email(self):
"""
Property for **self.__email** attribute.
:return: self.__email.
:rtype: unicode
"""
return self.__email
@email.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def email(self, value):
"""
Setter for **self.__email** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"email", value)
self.__email = value
@email.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def email(self):
"""
Deleter for **self.__email** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "email"))
@property
def url(self):
"""
Property for **self.__url** attribute.
:return: self.__url.
:rtype: unicode
"""
return self.__url
@url.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def url(self, value):
"""
Setter for **self.__url** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"url", value)
self.__url = value
@url.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def url(self):
"""
Deleter for **self.__url** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "url"))
@property
def description(self):
"""
Property for **self.__description** attribute.
:return: self.__description.
:rtype: unicode
"""
return self.__description
@description.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def description(self, value):
"""
Setter for **self.__description** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"description", value)
self.__description = value
@description.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def description(self):
"""
Deleter for **self.__description** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "description"))
#******************************************************************************************************************
#*** Class methods.
#******************************************************************************************************************
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.FileStructureParsingError)
[docs] def initializeProfile(self):
"""
Initializes the Component Profile.
:return: Method success.
:rtype: bool
"""
LOGGER.debug("> Building '{0}' profile.".format(self.__file))
sectionsFileParser = SectionsFileParser(self.__file)
sectionsFileParser.parse()
if sectionsFileParser.sections:
fileStructureParsingError = lambda attribute: foundations.exceptions.FileStructureParsingError(
"{0} | No '{1}' attribute found, '{2}' file structure seems invalid!".format(
self.__class__.__name__, attribute, self.__file))
self.__directory = os.path.dirname(self.__file)
self.__name = sectionsFileParser.getValue("Name", "Component", default=None)
if self.__name is None:
raise fileStructureParsingError("Name")
self.__title = sectionsFileParser.getValue("Title", "Component", default=None)
if self.__title is None:
self.__title = self.__name
self.__package = sectionsFileParser.getValue("Module", "Component", default=None)
if self.__package is None:
raise fileStructureParsingError("Module")
self.__attribute = sectionsFileParser.getValue("Object", "Component", default=None)
if self.__attribute is None:
raise fileStructureParsingError("Object")
self.__require = sectionsFileParser.getValue("Require", "Component", default=None)
self.__require = list() if self.__require is None else self.__require.split("|")
self.__version = sectionsFileParser.getValue("Version", "Component", default=None)
if self.__version is None:
raise fileStructureParsingError("Version")
self.__author = sectionsFileParser.getValue("Author", "Informations", default=None)
self.__email = sectionsFileParser.getValue("Email", "Informations", default=None)
self.__url = sectionsFileParser.getValue("Url", "Informations", default=None)
self.__description = sectionsFileParser.getValue("Description", "Informations", default=None)
return True
else:
raise foundations.exceptions.FileStructureParsingError(
"{0} | No sections found, '{1}' file structure seems invalid!".format(self.__class__.__name__, self.__file))
[docs]class Manager(object):
"""
| Defines methods to manage Components, allowing Components registration / unregistration,
instantiation and reloading.
| The Components can be registered in mass by providing paths that are recursively walk for candidates
or simply by calling the registration method on a given Component file.
| When a Component is registered, a Profile ( Stored using the :class:`Profile` class ) is built and associated to it,
this Profile object contains the Component Interface and various description attributes.
"""
def __init__(self,
paths=None,
extension="rc",
categories={"Default" : Component, "QWidget" : QWidgetComponentFactory(), "QObject" : QObjectComponent}):
"""
Initializes the class.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> manager.listComponents()
[u'core.testsComponentA', u'core.testsComponentB']
>>> manager.instantiateComponents()
True
>>> manager.getInterface("core.testsComponentA")
<testsComponentA.TestsComponentA object at 0x11dd990>
:param paths: Paths to walk.
:type paths: tuple or list
:param extension: Components file extension.
:type extension: unicode
:param categories: Components categories.
:type categories: dict
"""
LOGGER.debug("> Initializing '{0}()' class.".format(self.__class__.__name__))
# --- Setting class attributes. ---
self.__paths = None
self.paths = paths
self.__extension = None
self.extension = extension
self.__categories = None
self.categories = categories
self.__components = Components()
#******************************************************************************************************************
#*** Attributes properties.
#******************************************************************************************************************
@property
def paths(self):
"""
Property for **self.__paths** attribute.
:return: self.__paths.
:rtype: tuple or list
"""
return self.__paths
@paths.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def paths(self, value):
"""
Setter for **self.__paths** attribute.
:param value: Attribute value.
:type value: tuple or list
"""
if value is not None:
assert type(value) in (tuple, list), "'{0}' attribute: '{1}' type is not 'tuple' or 'list'!".format(
"paths", value)
for path in value:
assert type(path) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"paths", path)
assert os.path.exists(path), "'{0}' attribute: '{1}' directory doesn't exists!".format("paths", path)
self.__paths = value
@paths.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def paths(self):
"""
Deleter for **self.__paths** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "paths"))
@property
def extension(self):
"""
Property for **self.__extension** attribute.
:return: self.__extension.
:rtype: unicode
"""
return self.__extension
@extension.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def extension(self, value):
"""
Setter for **self.__extension** attribute.
:param value: Attribute value.
:type value: unicode
"""
if value is not None:
assert type(value) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"extension", value)
self.__extension = value
@extension.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def extension(self):
"""
Deleter for **self.__extension** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "extension"))
@property
def categories(self):
"""
Property for **self.__categories** attribute.
:return: self.__categories.
:rtype: dict
"""
return self.__categories
@categories.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(AssertionError)
def categories(self, value):
"""
Setter for **self.__categories** attribute.
:param value: Attribute value.
:type value: dict
"""
if value is not None:
assert type(value) is dict, "'{0}' attribute: '{1}' type is not 'dict'!".format("categories", value)
for key in value:
assert type(key) is unicode, "'{0}' attribute: '{1}' type is not 'unicode'!".format(
"categories", key)
self.__categories = value
@categories.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def categories(self):
"""
Deleter for **self.__categories** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "categories"))
@property
def components(self):
"""
Property for **self.__components** attribute.
:return: self.__components.
:rtype: dict
"""
return self.__components
@components.setter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
def components(self, value):
"""
Setter for **self.__components** attribute.
:param value: Attribute value.
:type value: dict
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is read only!".format(self.__class__.__name__, "components"))
@components.deleter
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(foundations.exceptions.ProgrammingError)
[docs] def components(self):
"""
Deleter for **self.__components** attribute.
"""
raise foundations.exceptions.ProgrammingError(
"{0} | '{1}' attribute is not deletable!".format(self.__class__.__name__, "components"))
#******************************************************************************************************************
#*** Class methods.
#******************************************************************************************************************
def __getitem__(self, component):
"""
Reimplements the :meth:`object.__getitem__` method.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> manager["core.testsComponentA"]
<manager.componentsManager.Profile object at 0x101c4bd50>
:param component: Component name.
:type component: unicode
:return: Component profile.
:rtype: Profile
"""
return self.__components.__getitem__(component).interface
def __iter__(self):
"""
Reimplements the :meth:`object.__iter__` method.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> for name, profile in manager:
... print(name)
...
core.testsComponentB
core.testsComponentA
:return: Components iterator.
:rtype: object
"""
return self.__components.iteritems()
def __contains__(self, component):
"""
Reimplements the :meth:`object.__contains__` method.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> "core.testsComponentA" in manager
True
>>> "core.nemoComponent" in manager
False
:param component: Component name.
:type component: unicode
:return: Component existence.
:rtype: bool
"""
return component in self.__components.keys()
def __len__(self):
"""
Reimplements the :meth:`object.__len__` method.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> len(manager)
2
:return: Components count.
:rtype: int
"""
return len(self.__components.keys())
# Oncilla: Statement commented by auto-documentation process:
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(manager.exceptions.ComponentModuleError,
# Oncilla: Statement commented by auto-documentation process: manager.exceptions.ComponentProfileError)
[docs] def registerComponent(self, path):
"""
Registers a Component using given path.
Usage::
>>> manager = Manager()
>>> manager.registerComponent("testsComponentA.rc")
True
>>> manager.components
{u'core.testsComponentA': <manager.componentsManager.Profile object at 0x11c9eb0>}
:param path: Component path.
:type path: unicode
:return: Method success.
:rtype: bool
"""
component = foundations.strings.getSplitextBasename(path)
LOGGER.debug("> Current Component: '{0}'.".format(component))
profile = Profile(file=path)
if profile.initializeProfile():
if os.path.isfile(os.path.join(profile.directory, profile.package) + ".py") or \
os.path.isdir(os.path.join(profile.directory, profile.package)) or \
os.path.basename(profile.directory) == profile.package:
self.__components[profile.name] = profile
return True
else:
raise manager.exceptions.ComponentModuleError(
"{0} | '{1}' has no associated module and has been rejected!".format(self.__class__.__name__, component))
else:
raise manager.exceptions.ComponentProfileError(
"{0} | '{1}' is not a valid Component and has been rejected!".format(self.__class__.__name__, component))
[docs] def unregisterComponent(self, component):
"""
Unregisters given Component.
.. warning::
The :class:`Manager` class is not responsible of any deactivation / cleanup actions
and will not trigger anything while unregistering a Component.
Usage::
>>> manager = Manager()
>>> manager.registerComponent("testsComponentA.rc")
True
>>> manager.unregisterComponent("core.testsComponentA")
True
>>> manager.components
{}
:param component: Component to remove.
:type component: unicode
:return: Method success.
:rtype: bool
"""
del(self.__components[component])
return True
# Oncilla: Statement commented by auto-documentation process:
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(manager.exceptions.ComponentRegistrationError)
[docs] def registerComponents(self):
"""
Registers the Components.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> manager.components.keys()
[u'core.testsComponentA', u'core.testsComponentB']
:return: Method success.
:rtype: bool
"""
unregisteredComponents = []
for path in self.paths:
for file in foundations.walkers.filesWalker(path, ("\.{0}$".format(self.__extension),), ("\._",)):
if not self.registerComponent(file):
unregisteredComponents.append(file)
if not unregisteredComponents:
return True
else:
raise manager.exceptions.ComponentRegistrationError(
"{0} | '{1}' Components failed to register!".format(self.__class__.__name__,
", ".join(unregisteredComponents)))
[docs] def unregisterComponents(self):
"""
Unregisters the Components.
.. warning::
The :class:`Manager` class is not responsible of any deactivation / cleanup actions
and will not trigger anything while unregistering a Component.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> manager.unregisterComponents()
True
>>> manager.components
{}
:return: Method success.
:rtype: bool
"""
self.__components.clear()
return True
# Oncilla: Statement commented by auto-documentation process:
# Oncilla: Statement commented by auto-documentation process: @foundations.exceptions.handleExceptions(manager.exceptions.ComponentInterfaceError)
[docs] def instantiateComponent(self, component, callback=None):
"""
Instantiates given Component.
Usage::
>>> manager = Manager()
>>> manager.registerComponent("testsComponentA.rc")
True
>>> manager.instantiateComponent("core.testsComponentA")
True
>>> manager.getInterface("core.testsComponentA")
<testsComponentA.TestsComponentA object at 0x17a5b90>
:param component: Component to instantiate.
:type component: unicode
:param callback: Callback object.
:type callback: object
"""
profile = self.__components[component]
callback and callback(profile)
LOGGER.debug("> Current Component: '{0}'.".format(component))
if os.path.isfile(os.path.join(profile.directory, profile.package) + ".py") or \
os.path.isdir(os.path.join(profile.directory, profile.package)):
path = profile.directory
elif os.path.basename(profile.directory) == profile.package:
path = os.path.join(profile.directory, "..")
not path in sys.path and sys.path.append(path)
profile.module = __import__(profile.package)
object = profile.attribute in profile.module.__dict__ and getattr(profile.module, profile.attribute) or None
if object and inspect.isclass(object):
instance = object(name=profile.name)
for category, type in self.__categories.iteritems():
if type.__name__ in (base.__name__ for base in object.__bases__):
profile.category = category
profile.interface = instance
LOGGER.info("{0} | '{1}' Component has been instantiated!".format(self.__class__.__name__, profile.name))
return True
else:
del(self.__components[component])
raise manager.exceptions.ComponentInterfaceError(
"{0} | '{1}' Component has no Interface and has been rejected!".format(self.__class__.__name__, profile.name))
[docs] def instantiateComponents(self, callback=None):
"""
Instantiates the Components.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> manager.instantiateComponents()
True
>>> manager.getInterface("core.testsComponentA")
<testsComponentA.TestsComponentA object at 0x17a5bb0>
:param callback: Callback object.
:type callback: object
"""
uninstantiatedComponents = [component
for component in self.listComponents()
if not self.instantiateComponent(component, callback)]
if not uninstantiatedComponents:
return True
else:
raise manager.exceptions.ComponentInstantiationError(
"{0} | '{1}' Components failed to instantiate!".format(self.__class__.__name__,
", ".join(uninstantiatedComponents)))
[docs] def reloadComponent(self, component):
"""
Reload given Component module.
Usage::
>>> manager = Manager()
>>> manager.registerComponent("testsComponentA.rc")
True
>>> manager.instantiateComponent("core.testsComponentA")
True
>>> manager.getInterface("core.testsComponentA")
<testsComponentA.TestsComponentA object at 0x17b4890>
>>> manager.reloadComponent("core.testsComponentA")
True
>>> manager.getInterface("core.testsComponentA")
<testsComponentA.TestsComponentA object at 0x17b0d70>
:param component: Component name.
:type component: unicode
:return: Reload success.
:rtype: bool
"""
dependents = list(reversed(self.listDependents(component)))
dependents.append(component)
for dependent in dependents:
profile = self.__components[dependent]
module = __import__(profile.package)
reload(module)
object = profile.attribute in dir(module) and getattr(module, profile.attribute) or None
if object and inspect.isclass(object):
for type in self.__categories.itervalues():
if type.__name__ in (base.__name__ for base in object.__bases__):
instance = object(name=profile.name)
profile.module = module
profile.interface = instance
LOGGER.info("{0} | '{1}' Component has been reloaded!".format(self.__class__.__name__, profile.name))
return True
[docs] def listComponents(self, dependencyOrder=True):
"""
Lists the Components by dependency resolving.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> manager.listComponents()
[u'core.testsComponentA', u'core.testsComponentB']
:param dependencyOrder: Components are returned by dependency order.
:type dependencyOrder: bool
"""
if dependencyOrder:
return list(itertools.chain.from_iterable([sorted(list(batch)) for batch in
foundations.common.dependencyResolver(dict((key, value.require) for (key, value) in self))]))
else:
return [key for (key, value) in self]
[docs] def listDependents(self, component, dependents=None):
"""
Lists given Component dependents Components.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> manager.listDependents("core.testsComponentA")
[u'core.testsComponentB']
:param component: Component to retrieve the dependents Components.
:type component: unicode
:param dependents: Component dependents Components.
:type dependents: set
:return: Dependent Components.
:rtype: list
"""
dependents = set() if dependents is None else dependents
for name, profile in self:
if not component in profile.require:
continue
dependents.add(name)
self.listDependents(name, dependents)
return sorted(list(dependents), key=(self.listComponents()).index)
[docs] def filterComponents(self, pattern, category=None):
"""
Filters the Components using given regex pattern.
Usage::
>>> manager = Manager(("./manager/tests/testsManager/resources/components/core",))
>>> manager.registerComponents()
True
>>> manager.filterComponents("\w+A$")
[u'core.testsComponentA']
:param pattern: Regex filtering pattern.
:type pattern: unicode
:param category: Category filter.
:type category: unicode
:return: Matching Components.
:rtype: list
"""
filteredComponents = []
for component, profile in self:
if category:
if profile.category != category:
continue
if re.search(pattern, component):
filteredComponents.append(component)
return filteredComponents
[docs] def getProfile(self, component):
"""
Gets given Component profile.
Usage::
>>> manager = Manager()
>>> manager.registerComponent("testsComponentA.rc")
True
>>> manager.getProfile("core.testsComponentA")
<manager.componentsManager.Profile object at 0x10258ef10>
:param component: Component to get the profile.
:type component: unicode
:return: Component profile.
:rtype: Profile
"""
components = self.filterComponents(r"^{0}$".format(component))
if components != []:
return self.__components[foundations.common.getFirstItem(components)]
[docs] def getInterface(self, component):
"""
Gets given Component interface.
Usage::
>>> manager = Manager()
>>> manager.registerComponent("testsComponentA.rc")
True
>>> manager.getInterface("core.testsComponentA")
<testsComponentA.TestsComponentA object at 0x17b0d70>
:param component: Component to get the interface.
:type component: unicode
:return: Component interface.
:rtype: object
"""
profile = self.getProfile(component)
if profile:
return profile.interface
# Oncilla: Statement commented by auto-documentation process:
# Oncilla: Statement commented by auto-documentation process: @staticmethod
[docs] def getComponentAttributeName(component):
"""
Gets given Component attribute name.
Usage::
>>> Manager.getComponentAttributeName("factory.componentsManagerUi")
u'factoryComponentsManagerUi'
:param component: Component to get the attribute name.
:type component: unicode
:return: Component attribute name.
:rtype: object
"""
search = re.search(r"(?P<category>\w+)\.(?P<name>\w+)", component)
if search:
name = "{0}{1}{2}".format(search.group("category"), search.group("name")[0].upper(), search.group("name")[1:])
LOGGER.debug("> Component name: '{0}' to attribute name Active_QLabel: '{1}'.".format(component, name))
else:
name = component
return name