Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Commit 555379a

Browse files
committed
Fix PB imports (#122)
Changes: 1. Place pb files inside proto 2. Fix the generated grpc stubs. The grpc plugin is crazy and ignores ".in." in imports, it also does not respect the directory structure. 3. Prepend "bblfsh" to all the imports in the bindings 4. Remove the sys.path hacks 5. Add `isinstance` test So now we have absolute imports starting with "bblfsh" **everywhere** and no classes are duplicated. Signed-off-by: Vadim Markovtsev <vadim@sourced.tech>
1 parent bc807c7 commit 555379a

5 files changed

Lines changed: 71 additions & 38 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,4 @@ libuast
106106

107107
bblfsh/github
108108
bblfsh/gopkg
109-
gopkg.in/bblfsh
109+
proto/gopkg.in

bblfsh/aliases.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,9 @@
33
"ProtocolServiceStub"]
44

55
import importlib
6-
import os
7-
import sys
86

97
from bblfsh.sdkversion import VERSION
108

11-
# The following two insertions fix the broken pb import paths
12-
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
13-
"gopkg/in/bblfsh/sdk/%s/protocol" % VERSION))
14-
sys.path.insert(0, os.path.dirname(__file__))
15-
169
# "in" is a reserved keyword in Python thus can't be used as package name, so
1710
# we import by string
1811

bblfsh/test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ def testSupportedLanguages(self):
299299

300300
def _validate_filter(self, resp):
301301
results = filter(resp.uast, "//Num")
302+
self.assertIsInstance(resp.uast, Node)
302303
self.assertEqual(next(results).token, "0")
303304
self.assertEqual(next(results).token, "1")
304305
self.assertEqual(next(results).token, "100")
File renamed without changes.

setup.py

Lines changed: 69 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import fileinput
1+
import glob
22
import logging
33
import os
44
import pkg_resources
5+
import re
56
import shutil
67
import subprocess
78
import sys
@@ -101,8 +102,8 @@ def call(*cmd):
101102

102103

103104
def create_dirs():
104-
mkdir(j("gopkg.in", "bblfsh", "sdk.{SDK_MAJOR}", "protocol"))
105-
mkdir(j("gopkg.in", "bblfsh", "sdk.{SDK_MAJOR}", "uast"))
105+
mkdir(j("proto", "gopkg.in", "bblfsh", "sdk.{SDK_MAJOR}", "protocol"))
106+
mkdir(j("proto", "gopkg.in", "bblfsh", "sdk.{SDK_MAJOR}", "uast"))
106107
mkdir(j("bblfsh", "gopkg", "in", "bblfsh", "sdk", SDK_MAJOR, "protocol"))
107108
mkdir(j("bblfsh", "gopkg", "in", "bblfsh", "sdk", SDK_MAJOR, "uast"))
108109
mkdir(j("bblfsh", "github", "com", "gogo", "protobuf", "gogoproto"))
@@ -143,42 +144,80 @@ def get_libuast():
143144
def proto_download():
144145
untar_url("https://github.com/bblfsh/sdk/archive/%s.tar.gz" % SDK_VERSION)
145146
sdkdir = "sdk-" + SDK_VERSION[1:]
146-
cp(j(sdkdir, "protocol", "generated.proto"),
147-
j("gopkg.in", "bblfsh", "sdk.{SDK_MAJOR}", "protocol", "generated.proto"))
148-
cp(j(sdkdir, "uast", "generated.proto"),
149-
j("gopkg.in", "bblfsh", "sdk.{SDK_MAJOR}", "uast", "generated.proto"))
147+
destdir = j("proto", "gopkg.in", "bblfsh", "sdk.{SDK_MAJOR}")
148+
cp(j(sdkdir, "protocol", "generated.proto"), j(destdir, "protocol", "generated.proto"))
149+
cp(j(sdkdir, "uast", "generated.proto"), j(destdir, "uast", "generated.proto"))
150150
rimraf(sdkdir)
151151

152152

153153
def proto_compile():
154154
sysinclude = "-I" + pkg_resources.resource_filename("grpc_tools", "_proto")
155155
from grpc.tools import protoc as protoc_module
156156

157-
def protoc(python_out, proto_file, *extra, grpc=True):
158-
main_args = [protoc_module.__file__, "--python_out=" + python_out]
157+
from_import_re = re.compile(r"from ((github|gopkg)\.[^ ]*) import (.*)")
158+
importlib_import_re = re.compile(r"([^ ]+) = importlib\.import_module\('(.*)")
159+
grpc_import_re = re.compile(
160+
r"from (([^ .]+\.)*in(\.[^ .]+)*) import ([^ ]+) as ([^\n]+)")
161+
162+
def patch(file, *patchers):
163+
with open(file) as fin:
164+
code = fin.readlines()
165+
for i, line in enumerate(code):
166+
for regexp, replacer in patchers:
167+
match = regexp.match(line)
168+
if match:
169+
code[i] = replacer(match)
170+
log.info("patched import in %s: %s", file, match.groups()[0])
171+
break
172+
if line.startswith("class") or line.startswith("DESCRIPTOR"):
173+
break
174+
with open(file, "w") as fout:
175+
fout.write("".join(code))
176+
177+
def protoc(proto_file, grpc=False):
178+
main_args = [protoc_module.__file__, "--python_out=bblfsh"]
179+
target_dir = j("bblfsh", *os.path.dirname(proto_file).split("."))
159180
if grpc:
160-
main_args += ["--grpc_python_out=" + python_out]
161-
main_args += extra
162-
main_args += ["-I.", sysinclude, proto_file]
163-
log.info("%s -m grpc.tools.protoc " + " ".join(main_args), sys.executable)
181+
# using "." creates "gopkg.in" instead of "gopkg/in" directories
182+
main_args += ["--grpc_python_out=" + target_dir]
183+
main_args += ["-Iproto", sysinclude, j("proto", proto_file)]
184+
log.info("%s -m grpc.tools.protoc " + " ".join(main_args[1:]), sys.executable)
164185
protoc_module.main(main_args)
165-
166-
sdk_root = j("bblfsh", "gopkg", "in", "bblfsh", "sdk", SDK_MAJOR)
167-
# SDK
168-
protoc(j(sdk_root, "protocol"),
169-
j("gopkg.in", "bblfsh", "sdk." + SDK_MAJOR, "protocol", "generated.proto"),
170-
"-I" + j("gopkg.in", "bblfsh", "sdk." + SDK_MAJOR, "protocol"))
171-
# UAST
172-
protoc("bblfsh", j("github.com", "gogo", "protobuf", "gogoproto", "gogo.proto"),
173-
grpc=False)
174-
protoc("bblfsh", j("gopkg.in", "bblfsh", "sdk." + SDK_MAJOR, "uast", "generated.proto"),
175-
grpc=False)
176-
for line in fileinput.input([j(sdk_root, "protocol", "generated_pb2.py"),
177-
j(sdk_root, "uast", "generated_pb2.py")],
178-
inplace=True):
179-
print(line.replace("from github.com.gogo.protobuf.gogoproto import",
180-
"from bblfsh.github.com.gogo.protobuf.gogoproto import"),
181-
end="")
186+
if grpc:
187+
# we need to move the file back to grpc_out
188+
grpc_garbage_dir = None
189+
target = j(target_dir, "generated_pb2_grpc.py")
190+
for root, dirnames, filenames in os.walk(target_dir):
191+
for filename in filenames:
192+
if filename == "generated_pb2_grpc.py" and grpc_garbage_dir is not None:
193+
mv(j(root, filename), target)
194+
if os.path.samefile(root, target_dir):
195+
grpc_garbage_dir = j(root, dirnames[0])
196+
rimraf(grpc_garbage_dir)
197+
198+
# grpc ignores "in" and we need to patch the import path
199+
def grpc_replacer(match):
200+
groups = match.groups()
201+
return 'import importlib\n%s = importlib.import_module("bblfsh.%s.%s")\n' % (
202+
groups[-1], groups[0], groups[-2])
203+
204+
patch(target, (grpc_import_re, grpc_replacer))
205+
206+
target = glob.glob(j(target_dir, "*_pb2.py"))[0]
207+
208+
def from_import_replacer(match):
209+
return "from bblfsh.%s import %s\n" % (match.group(1), match.group(3))
210+
211+
def importlib_import_replacer(match):
212+
return "%s = importlib.import_module('bblfsh.%s\n" % (match.group(1), match.group(2))
213+
214+
patch(target,
215+
(from_import_re, from_import_replacer),
216+
(importlib_import_re, importlib_import_replacer))
217+
218+
protoc(j("gopkg.in", "bblfsh", "sdk." + SDK_MAJOR, "protocol", "generated.proto"), True)
219+
protoc(j("github.com", "gogo", "protobuf", "gogoproto", "gogo.proto"))
220+
protoc(j("gopkg.in", "bblfsh", "sdk." + SDK_MAJOR, "uast", "generated.proto"))
182221

183222

184223
def do_get_deps():

0 commit comments

Comments
 (0)