Beispiel #1
0
    def _validate_directive_implementation(self) -> List[str]:
        """
        Validates that defined directives provide a proper implementation.
        :return: a list of errors
        :rtype: List[str]
        """
        errors = []
        for directive in self._directive_definitions.values():
            for expected in _IMPLEMENTABLE_DIRECTIVE_FUNCTION_HOOKS:
                attr = getattr(directive.implementation, expected, None)
                if attr and not is_valid_coroutine(attr):
                    errors.append(
                        f"Directive {directive.name} Method "
                        f"{expected} is not awaitable."
                    )

            for expected in _IMPLEMENTABLE_DIRECTIVE_GENERATOR_HOOKS:
                attr = getattr(directive.implementation, expected, None)
                if attr and not is_valid_async_generator(attr):
                    errors.append(
                        f"Directive {directive.name} Method "
                        f"{expected} is not an Async Generator."
                    )

        return errors
def get_callables(implementation: Any) -> Dict[str, Callable]:
    """
    Computes a dictionary of all attribute name that starts with `on_` and are
    linked to a callable.
    :param implementation: the implementation to parse
    :type implementation: Any
    :return: a dictionary of attribute name and callable
    :rtype: Dict[str, Callable]
    """
    return {
        key: getattr(implementation, key)
        for key in dir(implementation) if key.startswith("on_")
        and is_valid_coroutine(getattr(implementation, key))
    }
    def __call__(self, implementation: Callable) -> Callable:
        """
        Registers the resolver into the schema.
        :param implementation: implementation of the resolver
        :type implementation: Callable
        :return: the implementation of the resolver
        :rtype: Callable
        """
        if not is_valid_coroutine(implementation):
            raise NonAwaitableResolver(
                f"The resolver `{repr(implementation)}` given is not awaitable."
            )

        if self._type_resolver is not None and not callable(
                self._type_resolver):
            raise NonCallable(
                "The < type_resolver > parameter of the resolver "
                f"`{repr(implementation)}` has to be a callable.")

        SchemaRegistry.register_resolver(self._schema_name, self)
        self._implementation = implementation
        return implementation
Beispiel #4
0
    async def cook(
        self,
        sdl: Union[str, List[str]] = None,
        error_coercer: Callable[[Exception, Dict[str, Any]], Dict[str,
                                                                  Any]] = None,
        custom_default_resolver: Optional[Callable] = None,
        custom_default_type_resolver: Optional[Callable] = None,
        modules: Optional[Union[str, List[str], List[Dict[str, Any]]]] = None,
        schema_name: str = None,
    ) -> None:
        """
        Cook the tartiflette, basically prepare the engine by binding it to
        given modules using the schema_name as a key. You wont be able to
        execute a request if the engine wasn't cooked.
        :param sdl: path or list of path to the files / directories containing
        the SDL
        :param error_coercer: callable in charge of transforming a couple
        Exception/error into an error dictionary
        :param custom_default_resolver: callable that will replace the builtin
        default_resolver (called as resolver for each UNDECORATED field)
        :param custom_default_type_resolver: callable that will replace the
        tartiflette `default_type_resolver` (will be called on abstract types
        to deduct the type of a result)
        :param modules: list of string containing the name of the modules you
        want the engine to import, usually this modules contains your
        Resolvers, Directives, Scalar or Subscription code
        :param schema_name: name of the SDL
        :type sdl: Union[str, List[str]]
        :type error_coercer: Callable[[Exception, Dict[str, Any]], Dict[str, Any]]
        :type custom_default_resolver: Optional[Callable]
        :type custom_default_type_resolver: Optional[Callable]
        :type modules: Optional[Union[str, List[str], List[Dict[str, Any]]]]
        :type schema_name: str
        """
        if self._cooked:
            return

        if modules is None:
            modules = self._modules or []

        if isinstance(modules, str):
            modules = [modules]

        sdl = sdl or self._sdl
        if not sdl:
            raise Exception("Please provide a SDL")

        schema_name = schema_name or self._schema_name or "default"

        custom_error_coercer = error_coercer or self._error_coercer
        if custom_error_coercer and not is_valid_coroutine(
                custom_error_coercer):
            raise NonCoroutine(
                "Given < error_coercer > is not a coroutine callable.")

        custom_default_resolver = (custom_default_resolver
                                   or self._custom_default_resolver)
        if custom_default_resolver and not is_valid_coroutine(
                custom_default_resolver):
            raise NonCoroutine(
                "Given < custom_default_resolver > is not a coroutine callable."
            )

        custom_default_type_resolver = (custom_default_type_resolver
                                        or self._custom_default_type_resolver)
        if custom_default_type_resolver and not callable(
                custom_default_type_resolver):
            raise NonCallable(
                "Given < custom_default_type_resolver > is not a coroutine callable."
            )

        self._error_coercer = error_coercer_factory(custom_error_coercer
                                                    or default_error_coercer)

        self._modules, modules_sdl = await _import_modules(
            modules, schema_name)

        SchemaRegistry.register_sdl(schema_name, sdl, modules_sdl)
        self._schema = await SchemaBakery.bake(schema_name,
                                               custom_default_resolver,
                                               custom_default_type_resolver)
        self._build_response = partial(build_response,
                                       error_coercer=self._error_coercer)

        self._cooked = True
Beispiel #5
0
    async def cook(
        self,
        sdl: Union[str, List[str]] = None,
        error_coercer: Callable[[Exception, Dict[str, Any]], Dict[str,
                                                                  Any]] = None,
        custom_default_resolver: Optional[Callable] = None,
        custom_default_type_resolver: Optional[Callable] = None,
        modules: Optional[Union[str, List[str], List[Dict[str, Any]]]] = None,
        query_cache_decorator: Optional[Callable] = UNDEFINED_VALUE,
        json_loader: Optional[Callable[[str], Dict[str, Any]]] = None,
        custom_default_arguments_coercer: Optional[Callable] = None,
        coerce_list_concurrently: Optional[bool] = None,
        schema_name: Optional[str] = None,
    ) -> None:
        """
        Cook the tartiflette, basically prepare the engine by binding it to
        given modules using the schema_name as a key. You wont be able to
        execute a request if the engine wasn't cooked.
        :param sdl: path or list of path to the files / directories containing
        the SDL
        :param error_coercer: callable in charge of transforming a couple
        Exception/error into an error dictionary
        :param custom_default_resolver: callable that will replace the builtin
        default_resolver (called as resolver for each UNDECORATED field)
        :param custom_default_type_resolver: callable that will replace the
        tartiflette `default_type_resolver` (will be called on abstract types
        to deduct the type of a result)
        :param modules: list of string containing the name of the modules you
        want the engine to import, usually this modules contains your
        Resolvers, Directives, Scalar or Subscription code
        :param query_cache_decorator: callable that will replace the
        tartiflette default lru_cache decorator to cache query parsing
        :param json_loader: A callable that will replace default python
        json module.loads for ast_json loading
        :param custom_default_arguments_coercer: callable that will replace the
        tartiflette `default_arguments_coercer`
        :param coerce_list_concurrently: whether or not list will be coerced
        concurrently
        :param schema_name: name of the SDL
        :type sdl: Union[str, List[str]]
        :type error_coercer: Callable[[Exception, Dict[str, Any]], Dict[str, Any]]
        :type custom_default_resolver: Optional[Callable]
        :type custom_default_type_resolver: Optional[Callable]
        :type modules: Optional[Union[str, List[str], List[Dict[str, Any]]]]
        :type query_cache_decorator: Optional[Callable]
        :type json_loader: Optional[Callable[[str], Dict[str, Any]]]
        :type custom_default_arguments_coercer: Optional[Callable]
        :type coerce_list_concurrently: Optional[bool]
        :type schema_name: Optional[str]
        """
        # pylint: disable=too-many-arguments,too-many-locals
        if self._cooked:
            return

        if modules is None:
            modules = self._modules or []

        if isinstance(modules, str):
            modules = [modules]

        sdl = sdl or self._sdl
        if not sdl:
            raise Exception("Please provide a SDL")

        schema_name = schema_name or self._schema_name or "default"

        custom_error_coercer = error_coercer or self._error_coercer
        if custom_error_coercer and not is_valid_coroutine(
                custom_error_coercer):
            raise NonCoroutine(
                "Given < error_coercer > is not a coroutine callable.")

        custom_default_resolver = (custom_default_resolver
                                   or self._custom_default_resolver)
        if custom_default_resolver and not is_valid_coroutine(
                custom_default_resolver):
            raise NonCoroutine(
                "Given < custom_default_resolver > is not a coroutine callable."
            )

        custom_default_type_resolver = (custom_default_type_resolver
                                        or self._custom_default_type_resolver)
        if custom_default_type_resolver and not callable(
                custom_default_type_resolver):
            raise NonCallable(
                "Given < custom_default_type_resolver > is not a coroutine callable."
            )

        custom_default_arguments_coercer = (
            custom_default_arguments_coercer
            or self._custom_default_arguments_coercer)
        if custom_default_arguments_coercer and not is_valid_coroutine(
                custom_default_arguments_coercer):
            raise NonCoroutine(
                "Given < custom_default_arguments_coercer > is not a "
                "coroutine callable.")

        self._error_coercer = error_coercer_factory(custom_error_coercer
                                                    or default_error_coercer)

        self._modules, modules_sdl = await _import_modules(
            modules, schema_name)

        SchemaRegistry.register_sdl(schema_name, sdl, modules_sdl)
        self._schema = await SchemaBakery.bake(
            schema_name,
            custom_default_resolver,
            custom_default_type_resolver,
            custom_default_arguments_coercer,
            (coerce_list_concurrently if coerce_list_concurrently is not None
             else self._coerce_list_concurrently),
        )
        self._build_response = partial(build_response,
                                       error_coercer=self._error_coercer)

        (
            self._query_executor,
            self._subscription_executor,
        ) = self._schema.bake_execute(self._perform_query,
                                      self._perform_subscription)

        if query_cache_decorator is UNDEFINED_VALUE:
            query_cache_decorator = self._query_cache_decorator

        self._cached_parse_and_validate_query = (
            query_cache_decorator(parse_and_validate_query)
            if callable(query_cache_decorator) else parse_and_validate_query)

        self._schema.json_loader = json_loader or self._json_loader
        self._cooked = True