Quick search

Table Of Contents

Source code for kivy.factory

Factory object

The factory can be used to automatically register any class or module
and instantiate classes from it anywhere in your project. It is an
implementation of the
`Factory Pattern <>`_.

The class list and available modules are automatically generated by

Example for registering a class/module::

    >>> from kivy.factory import Factory
    >>> Factory.register('Widget', module='kivy.uix.widget')
    >>> Factory.register('Vector', module='kivy.vector')

Example of using the Factory::

    >>> from kivy.factory import Factory
    >>> widget = Factory.Widget(pos=(456,456))
    >>> vector = Factory.Vector(9, 2)

Example using a class name::

    >>> from kivy.factory import Factory
    >>> Factory.register('MyWidget', cls=MyWidget)

By default, the first classname you register via the factory is permanent.
If you wish to change the registered class, you need to unregister the
classname before you re-assign it::

    >>> from kivy.factory import Factory
    >>> Factory.register('MyWidget', cls=MyWidget)
    >>> widget = Factory.MyWidget()
    >>> Factory.unregister('MyWidget')
    >>> Factory.register('MyWidget', cls=CustomWidget)
    >>> customWidget = Factory.MyWidget()

__all__ = ('Factory', 'FactoryBase', 'FactoryException')

import copy
import importlib
from kivy.logger import Logger
from kivy.context import register_context

[docs]class FactoryException(Exception): pass
class FactoryBase(object): def __init__(self): super(FactoryBase, self).__init__() self.classes = {} @classmethod def create_from(cls, factory): """Creates a instance of the class, and initializes to the state of ``factory``. :param factory: The factory to initialize from. :return: A new instance of this class. """ obj = cls() obj.classes = copy.copy(factory.classes) return obj def is_template(self, classname): '''Return True if the classname is a template from the :class:`~kivy.lang.Builder`. .. versionadded:: 1.0.5 ''' if classname in self.classes: return self.classes[classname]['is_template'] else: return False def register(self, classname, cls=None, module=None, is_template=False, baseclasses=None, filename=None, warn=False): '''Register a new classname referring to a real class or class definition in a module. Warn, if True will emit a warning message when a class is re-declared. .. versionchanged:: 1.9.0 `warn` was added. .. versionchanged:: 1.7.0 :attr:`baseclasses` and :attr:`filename` added .. versionchanged:: 1.0.5 :attr:`is_template` has been added in 1.0.5. ''' if cls is None and module is None and baseclasses is None: raise ValueError( 'You must specify either cls= or module= or baseclasses =') if classname in self.classes: if warn: info = self.classes[classname] Logger.warning('Factory: Ignored class "{}" re-declaration. ' 'Current - module: {}, cls: {}, baseclass: {}, filename: {}. ' 'Ignored - module: {}, cls: {}, baseclass: {}, filename: {}.'. format(classname, info['module'], info['cls'], info['baseclasses'], info['filename'], module, cls, baseclasses, filename)) return self.classes[classname] = { 'module': module, 'cls': cls, 'is_template': is_template, 'baseclasses': baseclasses, 'filename': filename} def unregister(self, *classnames): '''Unregisters the classnames previously registered via the register method. This allows the same classnames to be re-used in different contexts. .. versionadded:: 1.7.1 ''' for classname in classnames: if classname in self.classes: self.classes.pop(classname) def unregister_from_filename(self, filename): '''Unregister all the factory objects related to the filename passed in the parameter. .. versionadded:: 1.7.0 ''' to_remove = [x for x in self.classes if self.classes[x]['filename'] == filename] for name in to_remove: del self.classes[name] def __getattr__(self, name): classes = self.classes if name not in classes: if name[0] == name[0].lower(): # if trying to access attributes like checking for `bind` # then raise AttributeError raise AttributeError( 'First letter of class name <%s> is in lowercase' % name) raise FactoryException('Unknown class <%s>' % name) item = classes[name] cls = item['cls'] # No class to return, import the module if cls is None: if item['module']: module = importlib.__import__( name=item['module'], fromlist='*', level=0 # force absolute ) if not hasattr(module, name): raise FactoryException( 'No class named <%s> in module <%s>' % ( name, item['module'])) cls = item['cls'] = getattr(module, name) elif item['baseclasses']: rootwidgets = [] for basecls in item['baseclasses'].split('+'): rootwidgets.append(Factory.get(basecls)) cls = item['cls'] = type(str(name), tuple(rootwidgets), {}) else: raise FactoryException('No information to create the class') return cls get = __getattr__ #: Factory instance to use for getting new classes Factory: FactoryBase = register_context('Factory', FactoryBase) # Now import the file with all registers # automatically generated by build_factory import kivy.factory_registers # NOQA'Factory: %d symbols loaded' % len(Factory.classes)) if __name__ == '__main__': Factory.register('Vector', module='kivy.vector') Factory.register('Widget', module='kivy.uix.widget')