GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( a1a024...0bdc53 )
by Raphaël
01:17
created

DependencyInjector._get_argument()   B

Complexity

Conditions 6

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 9.3798

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 26
ccs 6
cts 11
cp 0.5455
rs 7.5384
cc 6
crap 9.3798
1 1
from inspect import signature
2 1
from inspect import Parameter
3 1
from collections import OrderedDict
4 1
from pyjection.service import Service
5 1
from pyjection.reference import Reference
6
7
8 1
class DependencyInjector(object):
9
10 1
    def __init__(self):
11 1
        self._services = dict()
12 1
        self._singletons = dict()
13
14 1
    def register(self, identifier, service_subject):
15
        """
16
        Register a new service in the dependency injector
17
18
        This service can be :
19
            * A class that will be instantiated when called
20
            * An already instantiated instance that will be returned
21
22
        :param identifier: The identifier used to later retrieve a service instance
23
        :type identifier: string
24
        :param service_subject: The class or instance
25
        :type service_subject: mixed
26
27
        :return: Return the newly created service entry
28
        :rtype: Service
29
        """
30 1
        service = Service(service_subject)
31 1
        self._services[identifier] = service
32 1
        return service
33
34 1
    def register_singleton(self, identifier, service_subject):
35
        """
36
        Register a new singleton service in in the dependency injector
37
38
        This service can be :
39
            * A class that will be instantiated when called
40
            * An already instantiated instance that will be returned
41
42
        :param identifier: The identifier used to later retrieve a service singleton
43
        :type identifier: string
44
        :param service_subject: The class or instance
45
        :type service_subject: mixed
46
47
        :return: Return the newly created dependency entry
48
        :rtype: Service
49
        """
50 1
        service = Service(service_subject)
51 1
        service.is_singleton = True
52 1
        self._services[identifier] = service
53 1
        return service
54
55 1
    def get(self, identifier):
56
        """
57
        Instantiate and retrieve the service matching this identifier
58
59
        If the service has been self has a singleton the same service object
60
        will be return each time this service is asked
61
62
        :param identifier: The identifier used to later retrieve a class singleton
63
        :type identifier: string
64
        :return: The instantiated object
65
        :rtype: mixed
66
        """
67 1
        if self.has_service(identifier) is False:
68 1
            raise Exception("No service has been declared with this ID")
69
70 1
        service = self._services[identifier]
71 1
        instance = self._get_singleton(identifier, service)
72 1
        if instance is not None:
73 1
            return instance
74
75 1
        instance = self._get_instance(service)
76 1
        self._set_singleton(identifier, instance, service)
77
78 1
        return instance
79
80 1
    def has_service(self, identifier):
81
        """
82
        Check if the service matching the given identifier
83
        has already been declared
84
85
        :param identifier: Name of the service
86
        :type identifier: string
87
        :return: Whether or not the service exists
88
        :rtype: boolean
89
        """
90 1
        if identifier in self._services:
91 1
            return True
92 1
        return False
93
94 1
    def _get_singleton(self, identifier, service):
95
        """
96
        Return the singleton if it has been setted and
97
        the service represents a singleton
98
99
        :param identifier: the singleton identifier
100
        :param service: The service we need the singleton for
101
        :type identifier: string
102
        :type service: Service
103
104
        :return: The singleton instance or None
105
        :rtype: mixed
106
        """
107 1
        if service.is_singleton is True and identifier in self._singletons:
108 1
            return self._singletons[identifier]
109 1
        return None
110
111 1
    def _set_singleton(self, identifier, instance, service):
112
        """
113
        Set the instance as a singleton in the dict
114
        if the service represents a singleton
115
116
        :param identifier: the singleton identifier
117
        :param service: The service we want to set a singleton for
118
        :param instance: The singleton instance
119
        :type identifier: string
120
        :type service: Service
121
        :type instance: mixed
122
        """
123 1
        if service.is_singleton is True:
124 1
            self._singletons[identifier] = instance
125
126 1
    def _get_instance(self, service):
127
        """
128
        Return the instantiated object for the given service
129
130
        :param service: The service we need an instance for
131
        :type service: Service
132
        :return: The instantiated object
133
        """
134 1
        if service.type == 'instance':
135 1
            return service.subject
136 1
        arguments = self._generate_arguments_dict(service)
137 1
        return service.subject(**arguments)
138
139 1
    def _generate_arguments_dict(self, service):
140
        """
141
        Generate a dict containing all the parameters values
142
        required to Instantiate the service.
143
144
        An exception is raised if a mandatory argument cannot be
145
        retrieved.
146
147
        :param service: The service that needs to be instantiated
148
        :type service: Service
149
        :return: The parameters values to use to instantiate the service
150
        :rtype: dict
151
        """
152 1
        arguments = dict()
153
154
        # We can't use signature on object __init__
155 1
        if self._is_object_init(service.subject) is True:
156
            return arguments
157
158 1
        sig = signature(service.subject.__init__)
159 1
        method_parameters = OrderedDict(sig.parameters)
160
161
        # Pop the first param since it's the self class instance
162 1
        method_parameters.popitem(False)
163
164 1
        for method_parameter in method_parameters.values():
165 1
            argument = self._get_argument(service, method_parameter)
166 1
            if argument is not None:
167
                arguments[method_parameter.name] = argument
168
169 1
        return arguments
170
171 1
    def _is_object_init(self, subject):
172
        """
173
        Check if the __init__ method for the object comes from
174
        the default object or has been overridden
175
176
        :param subject: The subject we want to check the __init__ for
177
        :type subject: mixed
178
179
        :return: Whether the __init__ method is the default on or not
180
        :rtype: boolean
181
        """
182 1
        if '__objclass__' in dir(subject.__init__) and subject.__init__.__objclass__ == object:
183
            return True
184 1
        return False
185
186 1
    def _get_argument(self, service, method_parameter):
187
        """
188
        Retrieve the argument value for the given service
189
190
        :param service: The service we need an argument for
191
        :param method_parameter: The parameter we need the value for
192
        :type service: Service
193
        :type method_parameter: Parameter
194
        :return: The argument value
195
        :rtype: mixed
196
        """
197 1
        if method_parameter.name in service.arguments:
198
            value = service.arguments[method_parameter.name]
199
            # The value references an other dependency service
200
            if isinstance(value, Reference):
201
                return self.get(value.name)
202
            return value
203
204
        # If the parameter is *args or **kwargs then we don't raise any exception
205 1
        if method_parameter.kind == Parameter.VAR_POSITIONAL or \
206
                method_parameter.kind == Parameter.VAR_KEYWORD:
207 1
            return None
208
        # If the parameter has a default value then we don't raise any exception
209 1
        if method_parameter.default is not Parameter.empty:
210 1
            return None
211
        raise Exception("A required argument is not set (%s)" % method_parameter.name)
212