Skip to content

Commit d034e2d

Browse files
author
Marco Paolini
committed
Initial commit
0 parents  commit d034e2d

20 files changed

+720
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
__pycache__
2+
*.pyc
3+
*~
4+
*.c
5+
/build/
6+
/.wheelhouse/
7+
/.python-version
8+

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "libgraphqlparser"]
2+
path = libgraphqlparser
3+
url = git@github.com:graphql/libgraphqlparser.git

LICENSE

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
BSD License
2+
3+
For py-grahpqlparser software
4+
5+
Copyright (c) 2015-present, Elastic Coders, Srls All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without modification,
8+
are permitted provided that the following conditions are met:
9+
10+
* Redistributions of source code must retain the above copyright notice, this
11+
list of conditions and the following disclaimer.
12+
13+
* Redistributions in binary form must reproduce the above copyright notice,
14+
this list of conditions and the following disclaimer in the documentation
15+
and/or other materials provided with the distribution.
16+
17+
* Neither the name Facebook nor the names of its contributors may be used to
18+
endorse or promote products derived from this software without specific
19+
prior written permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
25+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# libgraphql cython port
2+
3+
Python2.7+ (includes python3) class-based bindings to libgraphql
4+
5+
See usage example in `examples/visitor_example.py`
6+
7+
This bindings are still experimental.
8+
9+
10+
## Building from source
11+
12+
- download submodules with `git checkout --recursive`
13+
- build libgraphql library in folder `./libgraphql` (python2.7 required for building)
14+
(usually `pushd libgraphqlparser && cmake . && make && popd` works)
15+
- generate source code with `python ast/build_ast.py`
16+
- you can now switch to python 3
17+
- install `cython`
18+
- run `LDFLAGS="-L./libgraphqlparser" CFLAGS="-Ilibgraphqlparser/c -Ilibgraphqlparser" python setup.py build_ext`
19+
20+
To package with wheel:
21+
- install wheel
22+
- create wheelhouse `mkdir .wheelhouse`
23+
- build with `pip wheel --wheel-dir=.wheelhouse .`
24+
25+
26+
## Run
27+
28+
Make sure `libgraphql` is available to the loader in your `LD_LIBRARY_PATH`
29+
30+
31+
## Known issues
32+
33+
- Only (lightly) tested on python3
34+
- Unicode string handling not yet complete (a mixture of bytes and strings all over)
35+
- Exceptions in the visitor's class callbacks are ignored
36+
- libgraphqlparser is **dynamically** linked but It would be better if it was linked statically

ast/ast_cython.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Copyright (c) 2015, Facebook, Inc.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree. An additional grant
6+
# of patent rights can be found in the PATENTS file in the same directory.
7+
8+
from casing import snake
9+
import re
10+
import ast_cython_c
11+
12+
CMODULE_NAME = 'GraphQLAst'
13+
14+
15+
class Printer(object):
16+
'''Printer for the Ast Python Object level cython interface.
17+
18+
'''
19+
def start_file(self):
20+
print ast_cython_c.license_comment() + '''
21+
22+
cimport %s
23+
24+
25+
cdef class GraphQLAst:
26+
"""Base class for all Ast pieces"""
27+
pass
28+
29+
''' % ast_cython_c.CMODULE_NAME
30+
31+
def end_file(self):
32+
pass
33+
34+
def start_type(self, name):
35+
st_name = ast_cython_c.struct_name(name)
36+
print '''
37+
cdef class %(name)s(GraphQLAst):
38+
39+
cdef %(cmodule)s.%(name)s* _wrapped
40+
41+
@staticmethod
42+
cdef create(cGraphQLAst.%(name)s *thing)
43+
44+
''' % {'name': st_name, 'cmodule': ast_cython_c.CMODULE_NAME}
45+
self._current_type = name
46+
47+
def field(self, type, name, nullable, plural):
48+
pass
49+
50+
def end_type(self, name):
51+
print
52+
print
53+
54+
def start_union(self, name):
55+
pass
56+
57+
def union_option(self, option):
58+
pass
59+
60+
def end_union(self, name):
61+
print

ast/ast_cython_c.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Copyright (c) 2015, Facebook, Inc.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree. An additional grant
6+
# of patent rights can be found in the PATENTS file in the same directory.
7+
8+
from casing import snake
9+
import re
10+
import ast_cython
11+
from license import C_LICENSE_COMMENT
12+
13+
CMODULE_NAME = 'cGraphQLAst'
14+
15+
16+
def struct_name(type):
17+
return 'GraphQLAst' + type
18+
19+
20+
def return_type(type):
21+
if type == 'OperationKind' or type == 'string':
22+
return 'const char *'
23+
24+
if type == 'boolean':
25+
return 'int'
26+
27+
return 'const %s *' % struct_name(type)
28+
29+
30+
def field_prototype(owning_type, type, name, nullable, plural):
31+
st_name = struct_name(owning_type)
32+
if plural:
33+
return 'int %s_get_%s_size(const %s *node)' % (
34+
st_name, snake(name), st_name)
35+
else:
36+
ret_type = return_type(type)
37+
return '%s %s_get_%s(const %s *node)' % (
38+
ret_type, st_name, snake(name), st_name)
39+
40+
41+
def license_comment():
42+
return re.sub(re.compile(r'^[ ]*', re.MULTILINE), '#', C_LICENSE_COMMENT) + '# @generated'
43+
44+
45+
class Printer(object):
46+
'''Printer for the Ast low-level C cython interface.
47+
48+
'''
49+
def start_file(self):
50+
print license_comment() + '''
51+
52+
cdef extern from "GraphQLAst.h":
53+
54+
'''
55+
56+
def end_file(self):
57+
pass
58+
59+
def start_type(self, name):
60+
# Forward declarations for AST nodes.
61+
st_name = struct_name(name)
62+
print ' struct ' + st_name + ':'
63+
print ' pass'
64+
self._current_type = name
65+
self._current_type_fields = []
66+
67+
def field(self, type, name, nullable, plural):
68+
self._current_type_fields.append((type, name, nullable, plural))
69+
print ' ' + field_prototype(self._current_type, type, name, nullable, plural)
70+
71+
def end_type(self, name):
72+
print
73+
print
74+
75+
def start_union(self, name):
76+
print ' struct ' + struct_name(name) + ':'
77+
print ' pass'
78+
79+
def union_option(self, option):
80+
pass
81+
82+
def end_union(self, name):
83+
print

ast/ast_cython_impl.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Copyright (c) 2015, Facebook, Inc.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree. An additional grant
6+
# of patent rights can be found in the PATENTS file in the same directory.
7+
8+
from casing import snake
9+
import ast_cython_c
10+
import ast_cython
11+
12+
SIMPLE_RETURN_CASTS = {
13+
'boolean': 'bool',
14+
'int': '',
15+
'string': '', # XXX decode?
16+
'OperationKind': ''
17+
}
18+
19+
SOURCE_TYPE_CASTS = {
20+
'IntValue': 'int',
21+
'FloatValue': 'float',
22+
'StringValue': '', # XXX decode?
23+
'BooleanValue': 'bool',
24+
'EnumValue': '' # XXX decode?
25+
}
26+
27+
def field_prototype(owning_type, type, name, nullable, plural):
28+
_map = {'cmodule': ast_cython_c.CMODULE_NAME,
29+
'owning_st': ast_cython_c.struct_name(owning_type),
30+
'snake': snake(name),
31+
'return_st': ast_cython_c.struct_name(type)}
32+
if plural:
33+
return '''
34+
def get_%(snake)s_size(self):
35+
return int(%(cmodule)s.%(owning_st)s_get_%(snake)s_size(self._wrapped))
36+
''' % _map
37+
if type in SIMPLE_RETURN_CASTS:
38+
# TODO: convert string to unicode
39+
if owning_type in SOURCE_TYPE_CASTS:
40+
_map['cast'] = SOURCE_TYPE_CASTS[owning_type]
41+
else:
42+
_map['cast'] = SIMPLE_RETURN_CASTS[type]
43+
return '''
44+
def get_%(snake)s(self):
45+
val = %(cmodule)s.%(owning_st)s_get_%(snake)s(self._wrapped)
46+
if val is None:
47+
return None
48+
return %(cast)s(val)
49+
''' % _map
50+
elif type in ['Type', 'Value']:
51+
# XXX this types have no functions...
52+
return '''
53+
'''
54+
else:
55+
# python object return type
56+
return '''
57+
def get_%(snake)s(self):
58+
cdef %(cmodule)s.%(return_st)s *next
59+
next = %(cmodule)s.%(owning_st)s_get_%(snake)s(self._wrapped)
60+
if next is NULL:
61+
return None
62+
return %(return_st)s.create(next)
63+
''' % _map
64+
65+
class Printer(object):
66+
'''Printer for a visitor in cython
67+
'''
68+
69+
def __init__(self):
70+
self._types = []
71+
72+
def start_file(self):
73+
print ast_cython_c.license_comment() + '''
74+
75+
cimport %s
76+
77+
cdef class GraphQLAst:
78+
"""Base class for all Ast pieces"""
79+
pass
80+
81+
''' % ast_cython_c.CMODULE_NAME
82+
83+
def start_type(self, name):
84+
self._current_type = name
85+
_map = {'snake': snake(name), 'name': name}
86+
print '''
87+
88+
cdef class %(name)s(GraphQLAst):
89+
90+
@staticmethod
91+
cdef create(%(cmodule)s.%(name)s *thing):
92+
node = %(name)s()
93+
node._wrapped = thing
94+
return node
95+
96+
''' % {'name': ast_cython_c.struct_name(name),
97+
'cmodule': ast_cython_c.CMODULE_NAME}
98+
99+
def field(self, type, name, nullable, plural):
100+
print field_prototype(self._current_type, type, name, nullable, plural)
101+
102+
def end_type(self, name):
103+
print
104+
print
105+
106+
def end_file(self):
107+
pass
108+
109+
def start_union(self, name):
110+
pass
111+
112+
def union_option(self, option):
113+
pass
114+
115+
def end_union(self, name):
116+
pass

0 commit comments

Comments
 (0)