add grpc bookstore python samples - #660
Conversation
|
@jonparrott |
|
just noticed the travis errors, will fix those and ping for review soon. |
theacodes
left a comment
There was a problem hiding this comment.
Finished first pass. Please let me know when you're ready for another pass.
| ADD . /bookstore/ | ||
|
|
||
| RUN cd /bookstore \ | ||
| && pip install --ignore-installed six \ |
There was a problem hiding this comment.
Don't do this, use a virtualenv:
RUN virtualenv /env
ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH
ADD . /bookstore/
WORKDIR /bookstore
RUN pip install -r requirements.txt
| You'll probably want to start by creating a virtual Python environment, so that | ||
| you can install dependencies without installing them globally. To do this, run: | ||
|
|
||
| mkdir bookstore-env |
There was a problem hiding this comment.
you don't need to do mkdir, virtualenv will do it for you.
|
|
||
| ## Installing Dependencies | ||
|
|
||
| You'll probably want to start by creating a virtual Python environment, so that |
There was a problem hiding this comment.
Be definitive: Install the dependencies using virtualenv:
(Note: I will eventually replace this README with an autogenerated one, but I'll keep the protoc instructions and such)
| import bookstore_pb2 | ||
|
|
||
| from google.protobuf import empty_pb2 | ||
| from grpc.beta import implementations |
There was a problem hiding this comment.
Just import grpc, don't use the beta interface anymore.
| from grpc.beta import implementations | ||
|
|
||
|
|
||
| def _add_endpoints_metadata(api_key): |
There was a problem hiding this comment.
Instead of doing nested functions and closures, prefer a callable class:
class ApiKeyMetadata(object):
def __init__(self, api_key):
self.api_key = api_key
def __call__(self, metadata):
...
| return struct_pb2.Value() | ||
|
|
||
|
|
||
| def _create_sample_bookstore(): |
| return store | ||
|
|
||
|
|
||
| def _serve(): |
|
|
||
| def _serve(): | ||
| """Configures and runs the bookstore API server.""" | ||
| parser = argparse.ArgumentParser( |
There was a problem hiding this comment.
Apply all of my comments about the argparse section in the client to this argparse section as well.
|
|
||
| store = _create_sample_bookstore() | ||
| server = bookstore_pb2.beta_create_Bookstore_server(BookstoreServicer(store)) | ||
| server.add_insecure_port('[::]:%d' % args.port) |
| @@ -0,0 +1,3 @@ | |||
| # The sample bookstore has been built and tested with GRPC version | |||
| # 1.0.0 It may work with other versions. | |||
| grpcio == 1.0.0 | |||
|
Jon, thanks for you review, really nice comments. Ready for the second round of review now :) |
| @@ -0,0 +1,20 @@ | |||
| FROM debian:jessie | |||
There was a problem hiding this comment.
Our other endpoints sample uses the python runtime, any strong reason for not using it here?
| && apt-get install -y python-dev python-pip virtualenv \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| RUN virtualenv /env |
There was a problem hiding this comment.
I should've mentioned this during the last review, but use python 3, please. virtualenv -p python3.4. If you use the Python runtime, use -p python3.5.
There was a problem hiding this comment.
done, is this what you meant?
| class Bookstore(object): | ||
| """Stores and manipulates bookstore data.""" | ||
|
|
||
| class ShelfDict(dict): |
There was a problem hiding this comment.
Don't do this, just catch the KeyErrors.
There was a problem hiding this comment.
there are many places used that ShelfDict, catch all over the places?
There was a problem hiding this comment.
There's three options:
- Catch everywhere you access the dictionary.
- Have a top-level catch of all exceptions and map them to gRPC errors (you're already kind of doing this)
- Ignore exceptions and rely on gRPC's default behavior.
There was a problem hiding this comment.
I played with this a bit, and think option 2 is the best which gives better errors with having to catch everywhere.
Let me know how you think.
There was a problem hiding this comment.
I played with this a bit, and think option 2 is the best which gives better errors with having to catch everywhere.
Let me know how you think.
| raise status.StatusException(status.Code.NOT_FOUND, | ||
| 'Unable to find book "%s"' % key) | ||
|
|
||
| class ShelfInfo(object): |
There was a problem hiding this comment.
Don't do nested classes, there is rarely a need for it.
There was a problem hiding this comment.
do you mean move ShelfInfo to the top-level class?
| import status | ||
|
|
||
| class Bookstore(object): | ||
| """Stores and manipulates bookstore data.""" |
There was a problem hiding this comment.
Maybe a better description here? "An in-memory backend for storing Bookstore data."
| store = bookstore.Bookstore() | ||
|
|
||
| shelf = bookstore_pb2.Shelf() | ||
| shelf.theme = "Fiction" |
There was a problem hiding this comment.
Use single quotes for string throughout (except docstrings)
| (_, fiction) = store.create_shelf(shelf) | ||
|
|
||
| book = bookstore_pb2.Book() | ||
| book.title = "REAMDE" |
| server.stop(args.shutdown_grace_duration) | ||
|
|
||
|
|
||
| if __name__ == '__main__': |
There was a problem hiding this comment.
Move argpase stuff down here?
| """A context manager that automatically handles StatusException.""" | ||
| try: | ||
| yield | ||
| except StatusException as se: |
There was a problem hiding this comment.
how about just exc instead of se?
|
|
||
|
|
||
| @contextmanager | ||
| def context(ctx): |
There was a problem hiding this comment.
grpc_context instead of ctx?
|
ptal |
|
|
||
| pip install -r requirements.txt | ||
|
|
||
| Install the [GRPC libraries and tools](https://github.com/grpc/grpc/blob/v1.0.x/INSTALL.md) |
There was a problem hiding this comment.
Follow prequisites in GRPC Quickstart is better than the INSTALL.md
| @@ -0,0 +1,19 @@ | |||
| FROM gcr.io/google_appengine/python | |||
There was a problem hiding this comment.
Definitely link to the Python runtime page on github: https://github.com/GoogleCloudPlatform/python-runtime
There was a problem hiding this comment.
do you mean adding a comment in this Dockerfile? something like this:
https://github.com/GoogleCloudPlatform/python-runtime
Or adding this link in the README.md?
commented
Nov 17, 2016
|
I still want to drop the usage of the beta interface. |
commented
Nov 17, 2016
|
removed grpc beta interface, PTAL |
| class Bookstore(object): | ||
| """An in-memory backend for storing Bookstore data.""" | ||
|
|
||
| class ShelfDict(dict): |
There was a problem hiding this comment.
I thought we were going to remove ShelfDict and BookDict?
There was a problem hiding this comment.
yes, you mentioned that. then you provided 3 options, and I think the option 2 is the best to avoid duplicate catch statement and still returning the useful errors. Do you have a better suggestion to do that without using wrapper dict?
|
|
||
| def delete_book(self, shelf_id, book_id): | ||
| with self._lock: | ||
| _ = self._shelves[shelf_id]._books[book_id] |
There was a problem hiding this comment.
You can probably just remove this line.
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """The Python GRPC Bookstore Client Example.""" |
| import bookstore_pb2 | ||
|
|
||
|
|
||
| class ApiKeyMetadata(object): |
| """The Python GRPC Bookstore Client Example.""" | ||
|
|
||
| import argparse | ||
| import grpc |
There was a problem hiding this comment.
grpc goes into the second section (third-party imports)
There was a problem hiding this comment.
here? or next to "from google.protobuf import empty_pb2"?
| channel = grpc.insecure_channel('{}:{}'.format(host,port)) | ||
|
|
||
| stub = bookstore_pb2.BookstoreStub(channel) | ||
| shelves = stub.ListShelves(empty_pb2.Empty(), timeout, |
There was a problem hiding this comment.
In general, put a newline after the opening ( to avoid hanging indents. (please do this throughout).
|
|
||
| shelf = bookstore_pb2.Shelf() | ||
| shelf.theme = 'Fiction' | ||
| (_, fiction) = store.create_shelf(shelf) |
There was a problem hiding this comment.
No need for these parens (there's a few more instances of this, please do it throughout)
There was a problem hiding this comment.
done, and another place
after grep, only find two for statement using that now:
for (_, s) in self.shelves.iteritems()]
for (, book) in self._shelves[shelf_id]._books.iteritems()]
not sure if it is recommended to remove parens there
| @@ -0,0 +1,3 @@ | |||
| # The sample bookstore has been built and tested with GRPC version | |||
There was a problem hiding this comment.
This comment really doesn't add a lot of value, remove it?
|
|
||
| from contextlib import contextmanager | ||
|
|
||
| from grpc.beta import interfaces |
commented
Nov 17, 2016
|
PTAL |
| import grpc | ||
|
|
||
|
|
||
| Code = grpc.StatusCode |
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import status |
There was a problem hiding this comment.
imports should be:
from contextlib import contextmanager
import grpc
import status
commented
Nov 17, 2016
|
A few final tiny things and this is good to go. |
commented
Nov 17, 2016
|
done, ptal |
commented
Nov 17, 2016
|
@dpebot can you merge when travis passes? |
commented
Nov 17, 2016
|
Okay! I'll merge when all statuses are green. |
commented
Nov 18, 2016
|
I saw there are many flake8 lint errors. Do I have to manually fix them one by one? or is there some tool I can use? thanks |
commented
Nov 18, 2016
|
@ryanmats Jon is sick today, do you know about any flake8 tools to fix errors? |
commented
Nov 18, 2016
|
@jeffmendoza @wlu2016 i'm not aware of any flake8 tools to automatically fix errors, but there might be. Jon said he would be on chat from time to time today so maybe he'd know. |
commented
Nov 18, 2016
|
fixed lint errors as you suggested, PTAL |
commented
Nov 19, 2016
|
@waprin's suggestion was great. Thanks! |
No description provided.