Exemple #1
0
 def test_new_handle(self):
     ffi = FFI(backend=self.Backend())
     o = [2, 3, 4]
     p = ffi.new_handle(o)
     assert ffi.typeof(p) == ffi.typeof("void *")
     assert ffi.from_handle(p) is o
     assert ffi.from_handle(ffi.cast("char *", p)) is o
     py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
Exemple #2
0
 def test_new_handle(self):
     ffi = FFI(backend=self.Backend())
     o = [2, 3, 4]
     p = ffi.new_handle(o)
     assert ffi.typeof(p) == ffi.typeof("void *")
     assert ffi.from_handle(p) is o
     assert ffi.from_handle(ffi.cast("char *", p)) is o
     py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
Exemple #3
0
class LibGraphqlParser:
    def __init__(self):
        self._ffi = FFI()
        self._ffi.cdef(CDEFS_LIBGRAPHQL)
        # TODO do a conf of this ?
        try:
            self._lib = self._ffi.dlopen("/usr/local/lib/libgraphqlparser.so")
        except OSError:
            self._lib = self._ffi.dlopen("/usr/local/lib/libgraphqlparser.dylib")
        self._lib_callbacks = self._ffi.new(
            "struct GraphQLAstVisitorCallbacks *"
        )
        self._errors = self._ffi.new("char **")
        self._callbacks = []
        self._interested_by = {}
        self._default_visitor_cls = Visitor
        self._creates_callbacks()

    def _create_visitor_element(self, libgraphql_type, element):
        try:
            return _LIBGRAPHQL_TYPE_TO_CLASS[libgraphql_type](
                self._lib, self._ffi, element)
        except KeyError:
            pass

        return _VisitorElement(self._lib, self._ffi, libgraphql_type, element)

    def _callback_enter(self, libgraphql_type, element, udata):
        context = self._ffi.from_handle(udata)
        context.update(
            Visitor.IN, self._create_visitor_element(libgraphql_type, element)
        )
        return context.continue_child

    def _callback_exit(self, libgraphql_type, element, udata):
        context = self._ffi.from_handle(udata)
        if context.continue_child:
            context.update(
                Visitor.OUT, self._create_visitor_element(libgraphql_type, element)
            )
        return None

    def _set_callback(self, proto, func, attr):
        c_func = self._ffi.callback(proto)(func)
        # Keep the callbacks alive in this list
        # to keep the underlying cdata alive.
        # because we do it with reflexion and
        # not with decoration
        self._callbacks.append(c_func)
        setattr(self._lib_callbacks, attr, c_func)

    def _set_exit_callback(self, typee):
        self._set_callback(
            "void(struct GraphQLAst%s *, void *)" % typee[0],
            partial(self._callback_exit, typee[0]), "end_visit_%s" % typee[1]
        )

    def _set_enter_callback(self, typee):
        self._set_callback(
            "int(struct GraphQLAst%s *, void *)" % typee[0],
            partial(self._callback_enter, typee[0]), "visit_%s" % typee[1]
        )

    def _creates_callbacks(self):
        for typee in TYPES_LIBGRAPHQL:
            if typee[0] not in ["Name"]:
                self._set_enter_callback(typee)
                self._set_exit_callback(typee)

    def _parse(self, query):
        if isinstance(query, str):
            # TODO don't replace here.
            query = query.replace("\n", " ").encode("UTF-8")

        c_query = self._ffi.new("char[]", query)
        parsed_data = _ParsedData(
            self._lib.graphql_parse_string(c_query, self._errors),
            self._lib.graphql_node_free
        )

        if self._errors[0] != self._ffi.NULL:
            # TODO specialize Exception here
            e = Exception(
                self._ffi.string(self._errors[0]).decode('UTF-8', 'replace')
            )
            self._lib.graphql_error_free(self._errors[0])
            raise e

        return parsed_data

    def parse_and_visit(self, query, ctx=None):
        if not ctx:
            ctx = self._default_visitor_cls()

        with self._parse(query) as parsed:
            self._lib.graphql_node_visit(
                parsed, self._lib_callbacks, self._ffi.new_handle(ctx)
            )

    def parse_and_jsonify(self, query):
        with self._parse(query) as parsed:
            return self._ffi.string(self._lib.graphql_ast_to_json(parsed))