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)
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))