mirror of
https://github.com/wassname/sloth.git
synced 2026-06-30 04:19:51 +08:00
162 lines
4.6 KiB
Python
162 lines
4.6 KiB
Python
import exceptions
|
|
import importlib
|
|
|
|
class Factory:
|
|
"""
|
|
A generic factory for both items and inserters.
|
|
"""
|
|
|
|
def __init__(self, items=None):
|
|
"""
|
|
Constructor.
|
|
|
|
Parameters
|
|
==========
|
|
items: dict
|
|
Mapping from type to python callable. If not None, all mappings
|
|
will be registered with the factory.
|
|
"""
|
|
self.items_ = {}
|
|
|
|
if items is not None:
|
|
for _type, item in items.iteritems():
|
|
self.register(_type, item, replace=True)
|
|
|
|
def import_callable(self, module_path_name):
|
|
"""
|
|
Import the callable given by ``module_path_name``.
|
|
"""
|
|
try:
|
|
module_path, name = module_path_name.rsplit('.', 1)
|
|
except ValueError:
|
|
raise exceptions.ImproperlyConfigured('%s is not a valid module path' % module_path_name)
|
|
try:
|
|
mod = importlib.import_module(module_path)
|
|
except ImportError, e:
|
|
raise exceptions.ImproperlyConfigured('Error importing module %s: "%s"' % (module_path, e))
|
|
try:
|
|
item_callable = getattr(mod, name)
|
|
except AttributeError:
|
|
raise exceptions.ImproperlyConfigured('Module "%s" does not define a "%s" callable' % (module_path, name))
|
|
|
|
return item_callable
|
|
|
|
def register(self, _type, item, replace=False):
|
|
"""
|
|
Register a new type-item mapping.
|
|
|
|
Parameters
|
|
==========
|
|
_type: string
|
|
Type of the item.
|
|
item: python callable or string
|
|
Reference to the callable which creates the new object.
|
|
"""
|
|
_type = _type.lower()
|
|
|
|
if _type in self.items_ and not replace:
|
|
raise Exception("Type %s already has an item: %s" % \
|
|
(_type, str(self.items_[_type])))
|
|
else:
|
|
if type(item) == str:
|
|
item = self.import_callable(item)
|
|
self.items_[_type] = item
|
|
|
|
def clear(self, _type=None):
|
|
"""
|
|
Remove a type-item mapping.
|
|
|
|
Parameters
|
|
==========
|
|
_type: str
|
|
Type for which the mapping should be removed. If None, all
|
|
mappings will be removed.
|
|
"""
|
|
if _type is None:
|
|
self.items_ = {}
|
|
else:
|
|
_type = _type.lower()
|
|
if _type in self.items_:
|
|
del self.items_[_type]
|
|
|
|
def create(self, _type, *args, **kwargs):
|
|
"""
|
|
Create a new object.
|
|
|
|
Parameters
|
|
==========
|
|
_type: str
|
|
Type for which a new object should be created.
|
|
|
|
All further arguments will be passed to the constructor/creating function
|
|
of the mapping.
|
|
|
|
Returns
|
|
=======
|
|
Newly created object. If for the given type no mapping exists, this
|
|
function returns ``None``.
|
|
"""
|
|
_type = _type.lower()
|
|
|
|
if _type not in self.items_:
|
|
return None
|
|
item = self.items_[_type]
|
|
if item is None:
|
|
return None
|
|
return item(*args, **kwargs)
|
|
|
|
### testing
|
|
import pytest
|
|
class MockupRectItem: pass
|
|
class MockupPointItem: pass
|
|
class MockupPolygonItem: pass
|
|
|
|
def _create_factory():
|
|
itemfactory = Factory({'point': MockupPointItem,
|
|
'polygon': MockupPolygonItem})
|
|
itemfactory.register('rect', MockupRectItem)
|
|
|
|
return itemfactory
|
|
|
|
def test_register():
|
|
itemfactory = _create_factory()
|
|
|
|
item = itemfactory.create('rect')
|
|
assert isinstance(item, MockupRectItem)
|
|
item = itemfactory.create('point')
|
|
assert isinstance(item, MockupPointItem)
|
|
item = itemfactory.create('polygon')
|
|
assert isinstance(item, MockupPolygonItem)
|
|
item = itemfactory.create('polygon2')
|
|
assert item is None
|
|
|
|
def test_register_fail():
|
|
itemfactory = _create_factory()
|
|
with pytest.raises(Exception):
|
|
itemfactory.register('rect', MockupRectItem)
|
|
|
|
def test_register_replace():
|
|
itemfactory = _create_factory()
|
|
|
|
itemfactory.register('rect', MockupPolygonItem, replace=True)
|
|
item = itemfactory.create('rect')
|
|
assert isinstance(item, MockupPolygonItem)
|
|
|
|
def test_clear():
|
|
itemfactory = _create_factory()
|
|
|
|
item = itemfactory.create('rect')
|
|
assert isinstance(item, MockupRectItem)
|
|
itemfactory.clear('rect')
|
|
item = itemfactory.create('rect')
|
|
assert item is None
|
|
|
|
item = itemfactory.create('point')
|
|
assert isinstance(item, MockupPointItem)
|
|
item = itemfactory.create('polygon')
|
|
assert isinstance(item, MockupPolygonItem)
|
|
itemfactory.clear()
|
|
assert itemfactory.create('point') is None
|
|
assert itemfactory.create('polygon') is None
|
|
|