Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.idea

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
19 changes: 19 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
language: python
sudo: false
services:
- docker
cache:
directories:
- $HOME/.cache/pip
python:
- "3.4"
- "3.5"
- "3.6"
install:
- pip install --upgrade pip
- pip install grpcio
- CC=gcc-5 CXX=g++-5 pip install -e .
script:
- python3 -m unittest discover .
notifications:
email: false
35 changes: 35 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
PYTHON ?= python3

makefile_dir := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))

all: bblfsh/github/com/gogo/protobuf/gogoproto/gogo_pb2.py \
bblfsh/github/com/bblfsh/sdk/uast/generated_pb2.py \
bblfsh/github/com/bblfsh/sdk/protocol/generated_pb2_*.py \
bblfsh/github/__init__.py \
bblfsh/github/com/__init__.py \
bblfsh/github/com/gogo/__init__.py \
bblfsh/github/com/gogo/protobuf/__init__.py \
bblfsh/github/com/gogo/protobuf/gogoproto/__init__.py \
bblfsh/github/com/bblfsh/__init__.py \
bblfsh/github/com/bblfsh/sdk/__init__.py \
bblfsh/github/com/bblfsh/sdk/uast/__init__.py \
bblfsh/github/com/bblfsh/sdk/protocol/__init__.py

bblfsh/github/com/gogo/protobuf/gogoproto/gogo_pb2.py: github.com/gogo/protobuf/gogoproto/gogo.proto
protoc --python_out bblfsh github.com/gogo/protobuf/gogoproto/gogo.proto

bblfsh/github/com/bblfsh/sdk/uast/generated_pb2.py: github.com/bblfsh/sdk/uast/generated.proto
protoc --python_out bblfsh github.com/bblfsh/sdk/uast/generated.proto

bblfsh/github/com/bblfsh/sdk/protocol:
@mkdir -p $@

bblfsh/github/com/bblfsh/sdk/protocol/generated_pb2_*.py: \
bblfsh/github/com/bblfsh/sdk/protocol github.com/bblfsh/sdk/protocol/generated.proto
$(PYTHON) -m grpc.tools.protoc --python_out=bblfsh/github/com/bblfsh/sdk/protocol \
--grpc_python_out=bblfsh/github/com/bblfsh/sdk/protocol \
-I github.com/bblfsh/sdk/protocol -I $(makefile_dir) \
github.com/bblfsh/sdk/protocol/generated.proto

%/__init__.py:
Copy link
Contributor

@juanjux juanjux Jun 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(non blocking) another option would be to add a first level __init__ with an import hook that knows how to do the rest, but this does the job perfectly too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very hacky too.

Copy link
Contributor

@juanjux juanjux Jun 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is but done well it could be more generic/automatic for other use cases of this gRPC module.

@touch $@
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Babelfish Python client

This a pure Python implementation of querying [Babelfish](https://doc.bblf.sh/) server.

### Usage

API
```
from bblfsh import BblfshClient

client = BblfshClient("0.0.0.0:9432")
print(client.parse_uast("/path/to/file.py"))
```

Command line
```
python3 -m bblfsh -f file.py
```

### Installation

```
pip3 install bblfsh
```

It is possible to regenerate the gRPC/protobuf bindings by executing `make`.

### License

Apache 2.0.
1 change: 1 addition & 0 deletions bblfsh/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from bblfsh.client import BblfshClient
34 changes: 34 additions & 0 deletions bblfsh/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import argparse
import sys

from bblfsh.client import BblfshClient
from bblfsh.launcher import ensure_bblfsh_is_running


def setup():
parser = argparse.ArgumentParser(
description="Query for a UAST to Babelfish and dump it to stdout."
)
parser.add_argument("-e", "--endpoint", default="0.0.0.0:9432",
help="bblfsh gRPC endpoint.")
parser.add_argument("-f", "--file", required=True,
help="File to parse.")
parser.add_argument("-l", "--language", default=None,
help="File's language. The default is to autodetect.")
parser.add_argument("--disable-bblfsh-autorun", action="store_true",
help="Do not automatically launch Babelfish server "
"if it is not running.")
args = parser.parse_args()
return args


def main():
args = setup()
if not args.disable_bblfsh_autorun:
ensure_bblfsh_is_running()
client = BblfshClient(args.endpoint)
print(client.parse_uast(args.file, args.language))


if __name__ == "__main__":
sys.exit(main())
64 changes: 64 additions & 0 deletions bblfsh/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import os
import sys

import grpc

# The following two insertions fix the broken pb import paths
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
"github/com/bblfsh/sdk/protocol"))
sys.path.insert(0, os.path.dirname(__file__))
from bblfsh.github.com.bblfsh.sdk.protocol.generated_pb2 import ParseUASTRequest
from bblfsh.github.com.bblfsh.sdk.protocol.generated_pb2_grpc import ProtocolServiceStub


class BblfshClient(object):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should have a method to close the client and the underlying connection.
Maybe close()? I'm not sure that's Python's convention. Also, __enter__ and __exit__ so it works with with?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no close(). Python does it automatically without ResourceWarning-s. Even the Python grpc primer does not close anything: http://www.grpc.io/docs/tutorials/basic/python.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

"""
Babelfish gRPC client. Currently it is only capable of fetching UASTs.
"""

def __init__(self, endpoint):
"""
Initializes a new instance of BblfshClient.

:param endpoint: The address of the Babelfish server, \
for example "0.0.0.0:9432"
:type endpoint: str
"""
self._channel = grpc.insecure_channel(endpoint)
self._stub = ProtocolServiceStub(self._channel)

def parse_uast(self, filename, language=None, contents=None):
"""
Queries the Babelfish server and receives the UAST for the specified
file.

:param filename: The path to the file. Can be arbitrary if contents \
is not None.
:param language: The programming language of the file. Refer to \
https://doc.bblf.sh/languages.html for the list of \
currently supported languages. None means autodetect.
:param contents: The contents of the file. IF None, it is read from \
filename.
:type filename: str
:type language: str
:type contents: str
:return: UAST object.
"""
if contents is None:
with open(filename) as fin:
contents = fin.read()
request = ParseUASTRequest(filename=os.path.basename(filename),
content=contents,
language=self._scramble_language(language))
response = self._stub.ParseUAST(request)
return response

@staticmethod
def _scramble_language(lang):
if lang is None:
return None
lang = lang.lower()
lang = lang.replace(" ", "-")
lang = lang.replace("+", "p")
lang = lang.replace("#", "sharp")
return lang
Empty file added bblfsh/github/__init__.py
Empty file.
Empty file added bblfsh/github/com/__init__.py
Empty file.
Empty file.
Empty file.
Empty file.
Loading