Ejemplo n.º 1
0
 def test_kwargs(self):
     specification = extract_factory_specification(_mock_func_with_kwargs)
     self.assertItemsEqual(['x', 'y', 'z'], specification.argument_names)
     self.assertEqual({
         'y': 1,
         'z': 'foo'
     }, specification.argument_default_values)
Ejemplo n.º 2
0
    def test_specification_for_init_if_type(self):
        @attrs
        class _MockAttrClass(object):
            no_default = attrib()
            string_default = attrib(default='default_string')
            factory_default = attrib(default=Factory(dict))

        specification = extract_factory_specification(_MockAttrClass)
        self.assertItemsEqual(
            ('no_default', 'string_default', 'factory_default'),
            specification.argument_names)
        self.assertIn('factory_default', specification.argument_default_values)
        self.assertEqual(
            'default_string',
            specification.argument_default_values['string_default'])
Ejemplo n.º 3
0
    def decorate(type_or_callable):
        factory_specification = extract_factory_specification(
            type_or_callable)  # type: FactorySpecification

        injectable_arguments = {
            argument: corresponding
            for (argument, corresponding) in (
                (argument, correspondence(argument))
                for argument in factory_specification.argument_names)
            if corresponding is not None
        }

        # This is a mapping to e.g. 'mydata_' to 'mydata'

        def validate_treatment(argument_name):
            # type: (basestring)->bool
            _NULL = []
            result = factory_specification.argument_default_values.get(
                argument_name, _NULL)
            if result is _NULL:
                if argument_name in injectable_arguments:
                    raise NoDefaultValueForArgument(
                        'Argument {} in callable {} implied to be injectable, but no default value was specified'
                        .format(argument_name, type_or_callable))
            else:
                if result is INJECTED and argument_name not in injectable_arguments:
                    raise NoSourceForArgument(
                        'Cannot inject argument {} into callable {}, injectable arguments {}'
                        .format(argument_name, type_or_callable,
                                injectable_arguments.keys()))

        for element in factory_specification.argument_names:
            validate_treatment(element)

        # We do this only after calculating injection_treatment, so we can catch variables marked as INJECT who do not
        # have a source
        if len(injectable_arguments) == 0:
            return type_or_callable  # Nothing to do here

        arg_to_position = {
            arg_name: index
            for (index,
                 arg_name) in enumerate(factory_specification.argument_names)
            if arg_name in injectable_arguments
        }

        # optimize for retrieval
        injectable_arguments_tuple = tuple(
            (argument, corresponding, arg_to_position[argument])
            for (argument, corresponding) in injectable_arguments.iteritems())

        def _raise_missing(argument, corresponding):
            if argument not in factory_specification.argument_default_values or \
                    factory_specification.argument_default_values[argument] is INJECTED:
                raise NoValuesProvided(
                    'Cannot provide for value {}'.format(corresponding))

        if not _USE_WRAPPING_INJECTOR:
            if inspect.isfunction(type_or_callable) or \
                    inspect.ismethod(type_or_callable) or inspect.ismethoddescriptor(type_or_callable):
                return rewrite_ast(type_or_callable, class_name,
                                   injectable_arguments_tuple,
                                   arg_to_ioc_container)

        @wraps(type_or_callable)
        def substitute_parameters(*args, **kwargs):
            for (argument, corresponding,
                 position_for_argument) in injectable_arguments_tuple:
                if position_for_argument < len(args) or argument in kwargs:
                    continue  # do not override this variable
                provided = arg_to_ioc_container[corresponding].provided
                try:
                    kwargs[argument] = getattr(provided, corresponding)
                except AttributeError:  # provided is None
                    # If it has a default, and no provider is available for the data, let the default be used implicitly
                    _raise_missing(argument, corresponding)

            return type_or_callable(*args, **kwargs)

        return substitute_parameters
Ejemplo n.º 4
0
 def test_degenerate_specification_for_non_callable(self):
     # noinspection PyTypeChecker
     specification = extract_factory_specification('Not a callable object')
     self.assertFalse(specification.argument_default_values)
     self.assertFalse(specification.argument_names)
Ejemplo n.º 5
0
    def test_specification_for_attrs_object(self):
        class _MockClass(object):
            pass

        specification = extract_factory_specification(_MockClass)
        self.assertIs(_MockClass.__init__, specification.constructing_function)
Ejemplo n.º 6
0
 def test_argument_names(self):
     specification = extract_factory_specification(_mock_func)
     self.assertItemsEqual(['x'], specification.argument_names)
Ejemplo n.º 7
0
 def test_degenerate(self):
     specification = extract_factory_specification(_mock_func)
     self.assertIsInstance(specification, FactorySpecification)
     self.assertIs(_mock_func, specification.constructing_function)