FactoryType   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 32
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 10
c 0
b 0
f 0
wmc 11

2 Methods

Rating   Name   Duplication   Size   Complexity  
B __init__() 0 13 5
B __call__() 0 16 6
1
"""A python implementation of the factory design pattern.  It's designed for use as a base class
2
for various types of data gateways.
3
"""
4
from __future__ import absolute_import, division, print_function
5
6
from .compat import with_metaclass
7
from .exceptions import InitializationError
8
9
__all__ = ['Factory']
10
11
12
class FactoryBase(object):
13
14
    @classmethod
15
    def initialize(cls, context, default_provider):
16
        cls.context = context
17
        cls._default_provider = (default_provider.__name__ if isinstance(default_provider, type)
18
                                 else str(default_provider))
19
        if not cls.is_registered_provider(cls._default_provider):
20
            raise RuntimeError("{0} is not a registered provider for "
21
                               "{1}".format(cls._default_provider, cls.__name__))
22
23
    @classmethod
24
    def get_instance(cls, provider=None):
25
        if not hasattr(cls, 'context'):
26
            raise InitializationError("RecordRepoFactory has not been initialized.")
27
        provider = provider.__name__ if isinstance(provider, type) else provider or cls._default_provider  # noqa
28
        return cls.providers[provider](cls.context)
29
30
    @classmethod
31
    def get_registered_provider_names(cls):
32
        return cls.providers.keys()
33
34
    @classmethod
35
    def get_registered_providers(cls):
36
        return cls.providers.values()
37
38
    @classmethod
39
    def is_registered_provider(cls, provider):
40
        if isinstance(provider, type):
41
            provider = provider.__name__
42
        return provider in cls.get_registered_provider_names()
43
44
45
class FactoryType(type):
46
47
    def __init__(cls, name, bases, attr):
48
        super(FactoryType, cls).__init__(name, bases, attr)
49
        if 'skip_registration' in cls.__dict__ and cls.skip_registration:
50
            pass  # we don't even care  # pragma: no cover
51
        elif cls.factory is None:
52
            # this must be the base implementation; add a factory object
53
            cls.factory = type(cls.__name__ + 'Factory', (FactoryBase, ),
54
                               {'providers': dict(), 'cache': dict()})
55
            if hasattr(cls, 'gateways'):
56
                cls.gateways.add(cls)
57
        else:
58
            # must be a derived object, register it as a provider in cls.factory
59
            cls.factory.providers[cls.__name__] = cls
60
61
    def __call__(cls, *args):
62
        if 'factory' in cls.__dict__:
63
            if args and args[0]:
64
                return cls.factory.get_instance(args[0])
65
            else:
66
                return cls.factory.get_instance()
67
        else:
68
            if not getattr(cls, 'do_cache', False):
69
                return super(FactoryType, cls).__call__(*args)
70
            cache_id = "{0}".format(cls.__name__)
71
            try:
72
                return cls.factory.cache[cache_id]
73
            except KeyError:
74
                instance = super(FactoryType, cls).__call__(*args)
75
                cls.factory.cache[cache_id] = instance
76
                return instance
77
78
79
@with_metaclass(FactoryType)
80
class Factory(object):
81
    skip_registration = True
82
    factory = None
83
84
85
# ## Document these ##
86
# __metaclass__
87
# factory
88
# skip_registration
89
# gateways
90
# do_cache
91
92
# TODO: add name parameter  --give example from transcomm client factory
93