예제 #1
0
    def _add_adapter(self, func, config: dict, options: dict, parser):
        message = config['target']
        params = None
        if isinstance(message, str):
            service = self._context_map.locate_service(message)
            if service is not None:
                params = ffd.get_arguments(service.__call__)
        else:
            params = ffd.get_arguments(message)

        if params is None:
            raise ffd.FrameworkError(f'Could not locate service {message}')

        options['params'].update(params)
        options['alias'].update(config['alias'] if config['alias'] is not None else {})
        options['help_'].update(config['help_'] if config['help_'] is not None else {})
        options['middleware'].extend(config['middleware'] if config['middleware'] is not None else [])
        for name, config in options['params'].items():
            args = [f'--{inflection.dasherize(name)}']
            if name in options['alias']:
                args.append(f'-{options["alias"][name]}')

            kwargs = {
                'default': config['default'],
                'required': config['default'] is inspect.Parameter.empty,
                'help': options['help_'][name] if name in options['help_'] else None,
            }

            if config['type'] == bool:
                kwargs['action'] = 'store_true' if not config['default'] else 'store_false'
            else:
                kwargs['type'] = config['type']

            parser.add_argument(*args, **kwargs)
예제 #2
0
    def __call__(self, entity) -> Repository:
        if not issubclass(entity, ffd.AggregateRoot):
            raise ffd.LogicError('Repositories can only be generated for aggregate roots')

        for k, v in self._cache.items():
            if entity.same_type(k):
                return v

        if entity not in self._cache:
            for k, v in self._factories.items():
                if issubclass(entity, k):
                    self._cache[entity] = v(entity)
                    break
                elif issubclass(k, entity):
                    self._cache[entity] = v(k)
                    break

        if entity not in self._cache:
            context = entity.get_class_context()
            if context in self._default_factory and self._default_factory[context] is not None:
                self._cache[entity] = self._default_factory[context](entity)

            if entity not in self._cache:
                raise ffd.FrameworkError(
                    f'No registry found for entity {entity}. Have you configured a persistence mechanism or extension?'
                )

        return self._cache[entity]
예제 #3
0
 def batch_wrapper(cls: ffd.MetaAware):
     try:
         cls.add_annotation(self)
         setattr(cls, '_batch_size', batch_size)
         setattr(cls, '_batch_window', batch_window)
     except AttributeError:
         raise ffd.FrameworkError(
             '@authenticator used on invalid target')
     return cls
예제 #4
0
    def __call__(self, **kwargs):
        self._load_factories()
        connections = {}
        factories = {}

        for context in self._context_map.contexts:
            storage = context.config.get('storage', {})
            if 'services' in storage:
                for name, config in storage.get('services').items():
                    config = config or {}
                    if name not in self._connection_factories and config.get('type') not in self._connection_factories:
                        raise ffd.ConfigurationError(f"No ConnectionFactory configured for '{name}'")
                    key = name if name in self._connection_factories else config.get('type')
                    connections[name] = context.container.build(self._connection_factories[key])(
                        **(config.get('connection') or {})
                    )

        for context in self._context_map.contexts:
            storage = context.config.get('storage', {})
            if 'services' in storage:
                for name, config in storage.get('services').items():
                    config = config or {}
                    if name not in self._repository_factories and config.get('type') not in self._repository_factories:
                        raise ffd.ConfigurationError(f"No RepositoryFactory configured for '{name}'")
                    key = name if name in self._repository_factories else config.get('type')
                    factory = context.container.autowire(self._repository_factories[key])
                    try:
                        factories[name] = factory(connections[name], **(config.get('repository') or {}))
                    except TypeError as e:
                        if '__init__() takes exactly one argument' in str(e):
                            raise ffd.FrameworkError(f"{factory.__name__}.__init__() must take a connection as "
                                                     f"the first argument")
                        raise e

        for context in self._context_map.contexts:
            if context.name == 'firefly':
                continue
            storage = context.config.get('storage', {})
            registered_aggregates = []
            if 'aggregates' in storage:
                for entity, service in storage.get('aggregates').items():
                    if not entity.startswith(context.name):
                        entity = f'{context.name}.{entity}'
                    entity = ffd.load_class(entity)
                    registered_aggregates.append(entity)
                    self._registry.register_factory(entity, factories[service])
            if 'default' in storage:
                for entity in context.entities:
                    if issubclass(entity, ffd.AggregateRoot) and entity is not ffd.AggregateRoot \
                            and entity not in registered_aggregates:
                        self._registry.register_factory(entity, factories[storage.get('default')])

        # TODO Get persistence working in these core services.
        # self._registry(ffd.ContextMap).add(self._context_map)

        self.dispatch(ffd.StorageConfigured())
예제 #5
0
    def __call__(self, message: ffd.Message, next_: Callable) -> ffd.Message:
        if not self._initialized:
            self._initialize()

        self.debug('Message context: %s', message.get_context())
        self.debug('This context: %s', self._context)
        self.debug('Environment: %s', self._ff_environment)
        if message.get_context() != 'firefly' and \
                message.get_context() == self._context and \
                not message.headers.get('external', False) and \
                self._ff_environment != 'test':
            self.debug(
                'EventResolvingMiddleware - event originated from this context. Dispatching.'
            )
            self._publish_message(message)
            return next_(message)

        args = message.to_dict(recursive=False)
        args['_message'] = message

        if str(message) in self._event_listeners:
            services = self._event_listeners[str(message)]
            for service in services:
                try:
                    if self._service_is_batch_capable(
                            service) and self._batch_service.is_registered(
                                service.__class__):
                        self.debug('Deferring to batch service')
                        return self._batch_service.handle(service, args)
                    else:
                        parsed_args = ffd.build_argument_list(args, service)
                        self.debug('Calling service %s with arguments: %s',
                                   service.__class__.__name__, parsed_args)
                        service(**parsed_args)
                except TypeError as e:
                    self.exception(e)
                    raise ffd.FrameworkError(
                        f'Error calling {service.__class__.__name__}:\n\n{str(e)}'
                    )
        else:
            self.info('No event listener found for message %s', message)

        return next_(message)
예제 #6
0
    def convert_type(message: Message, new_name: str,
                     new_base: Union[Message, Tuple[Message]]):
        if not is_dataclass(message):
            raise ffd.FrameworkError('message must be a dataclass')

        types = get_type_hints(message.__class__)
        message_fields = []
        for field_ in fields(message):
            message_fields.append((field_.name, types[field_.name], field_))

        if not isinstance(new_base, tuple):
            new_base = (new_base, )

        cls = make_dataclass(new_name,
                             fields=message_fields,
                             bases=new_base,
                             eq=False,
                             repr=False)

        return cls(**asdict(message))
예제 #7
0
    def __call__(self, message: ffd.Message, next_: Callable) -> ffd.Message:
        if not self._initialized:
            self._initialize()

        if message.get_context() != 'firefly' and \
                message.get_context() == self._context and \
                not message.headers.get('external', False):
            self._publish_message(message)
            return next_(message)

        args = message.to_dict(recursive=False)
        args['_message'] = message

        if str(message) in self._event_listeners:
            services = self._event_listeners[str(message)]
            for service in services:
                try:
                    service(**ffd.build_argument_list(args, service))
                except TypeError as e:
                    raise ffd.FrameworkError(
                        f'Error calling {service.__class__.__name__}:\n\n{str(e)}'
                    )

        return next_(message)
예제 #8
0
 def authenticator_wrapper(cls: ffd.MetaAware):
     try:
         cls.add_annotation(self)
     except AttributeError:
         raise ffd.FrameworkError('@authorizer used on invalid target')
     return cls