Skip to content

add grpc bookstore python samples - #660

Merged
dpebot merged 18 commits into
GoogleCloudPlatform:masterfrom
wenchenglu:master
Nov 18, 2016
Merged

dpebot merged 18 commits into
GoogleCloudPlatform:masterfrom
wenchenglu:master

Conversation

@wenchenglu

Copy link
Copy Markdown

No description provided.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Nov 16, 2016
@wenchenglu

Copy link
Copy Markdown
Author

@jonparrott
PTAL

@wenchenglu

Copy link
Copy Markdown
Author

just noticed the travis errors, will fix those and ping for review soon.

@theacodes theacodes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Finished first pass. Please let me know when you're ready for another pass.

Comment thread endpoints/bookstore-grpc/Dockerfile Outdated
ADD . /bookstore/

RUN cd /bookstore \
&& pip install --ignore-installed six \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Comment thread endpoints/bookstore-grpc/README.md Outdated
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you don't need to do mkdir, virtualenv will do it for you.

Comment thread endpoints/bookstore-grpc/README.md Outdated

## Installing Dependencies

You'll probably want to start by creating a virtual Python environment, so that

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just import grpc, don't use the beta interface anymore.

from grpc.beta import implementations


def _add_endpoints_metadata(api_key):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No need for the _.

return store


def _serve():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No need for the _.


def _serve():
"""Configures and runs the bookstore API server."""
parser = argparse.ArgumentParser(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

prefer format over %.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use the latest version.

@wenchenglu

Copy link
Copy Markdown
Author

@jonparrott

Jon, thanks for you review, really nice comments. Ready for the second round of review now :)

Comment thread endpoints/bookstore-grpc/Dockerfile Outdated
@@ -0,0 +1,20 @@
FROM debian:jessie

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done, is this what you meant?

Comment thread endpoints/bookstore-grpc/bookstore.py Outdated
class Bookstore(object):
"""Stores and manipulates bookstore data."""

class ShelfDict(dict):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Don't do this, just catch the KeyErrors.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

there are many places used that ShelfDict, catch all over the places?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There's three options:

  1. Catch everywhere you access the dictionary.
  2. Have a top-level catch of all exceptions and map them to gRPC errors (you're already kind of doing this)
  3. Ignore exceptions and rely on gRPC's default behavior.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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.

Comment thread endpoints/bookstore-grpc/bookstore.py Outdated
raise status.StatusException(status.Code.NOT_FOUND,
'Unable to find book "%s"' % key)

class ShelfInfo(object):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Don't do nested classes, there is rarely a need for it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

do you mean move ShelfInfo to the top-level class?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes.

Comment thread endpoints/bookstore-grpc/bookstore.py Outdated
import status

class Bookstore(object):
"""Stores and manipulates bookstore data."""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe a better description here? "An in-memory backend for storing Bookstore data."

store = bookstore.Bookstore()

shelf = bookstore_pb2.Shelf()
shelf.theme = "Fiction"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use single quotes for string throughout (except docstrings)

(_, fiction) = store.create_shelf(shelf)

book = bookstore_pb2.Book()
book.title = "REAMDE"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Typo. :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

wow, nice catch :)

server.stop(args.shutdown_grace_duration)


if __name__ == '__main__':

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Move argpase stuff down here?

Comment thread endpoints/bookstore-grpc/status.py Outdated
"""A context manager that automatically handles StatusException."""
try:
yield
except StatusException as se:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

how about just exc instead of se?

Comment thread endpoints/bookstore-grpc/status.py Outdated


@contextmanager
def context(ctx):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

grpc_context instead of ctx?

@wenchenglu

Copy link
Copy Markdown
Author

ptal

Comment thread endpoints/bookstore-grpc/README.md Outdated

pip install -r requirements.txt

Install the [GRPC libraries and tools](https://github.com/grpc/grpc/blob/v1.0.x/INSTALL.md)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Follow prequisites in GRPC Quickstart is better than the INSTALL.md

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

ghost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Getting close.

@@ -0,0 +1,19 @@
FROM gcr.io/google_appengine/python

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Definitely link to the Python runtime page on github: https://github.com/GoogleCloudPlatform/python-runtime

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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?

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Dockerfile

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

@theacodes

ghost commented Nov 17, 2016

Copy link
Copy Markdown
Contributor

I still want to drop the usage of the beta interface.

@wenchenglu

ghost commented Nov 17, 2016

Copy link
Copy Markdown
Author

removed grpc beta interface, PTAL

Comment thread endpoints/bookstore-grpc/bookstore.py Outdated
class Bookstore(object):
"""An in-memory backend for storing Bookstore data."""

class ShelfDict(dict):

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I thought we were going to remove ShelfDict and BookDict?

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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?

Comment thread endpoints/bookstore-grpc/bookstore.py Outdated

def delete_book(self, shelf_id, book_id):
with self._lock:
_ = self._shelves[shelf_id]._books[book_id]

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You can probably just remove this line.

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I think so, done

# See the License for the specific language governing permissions and
# limitations under the License.

"""The Python GRPC Bookstore Client Example."""

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

s/GRPC/gRPC.

import bookstore_pb2


class ApiKeyMetadata(object):

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You can remove this class now.

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

"""The Python GRPC Bookstore Client Example."""

import argparse
import grpc

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

grpc goes into the second section (third-party imports)

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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,

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In general, put a newline after the opening ( to avoid hanging indents. (please do this throughout).

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done


shelf = bookstore_pb2.Shelf()
shelf.theme = 'Fiction'
(_, fiction) = store.create_shelf(shelf)

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No need for these parens (there's a few more instances of this, please do it throughout)

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yep, go ahead.

@@ -0,0 +1,3 @@
# The sample bookstore has been built and tested with GRPC version

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This comment really doesn't add a lot of value, remove it?

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

Comment thread endpoints/bookstore-grpc/status.py Outdated

from contextlib import contextmanager

from grpc.beta import interfaces

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Still using beta here?

ghost Nov 17, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

removed

@wenchenglu

ghost commented Nov 17, 2016

Copy link
Copy Markdown
Author

PTAL

Comment thread endpoints/bookstore-grpc/status.py Outdated
import grpc


Code = grpc.StatusCode

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this used anywhere?

Comment thread endpoints/bookstore-grpc/status.py Outdated
# See the License for the specific language governing permissions and
# limitations under the License.

import status

ghost Nov 17, 2016

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

imports should be:

from contextlib import contextmanager

import grpc

import status

@theacodes

ghost commented Nov 17, 2016

Copy link
Copy Markdown
Contributor

A few final tiny things and this is good to go.

@wenchenglu

ghost commented Nov 17, 2016

Copy link
Copy Markdown
Author

done, ptal

@theacodes

ghost commented Nov 17, 2016

Copy link
Copy Markdown
Contributor

@dpebot can you merge when travis passes?

@dpebot

ghost commented Nov 17, 2016

Copy link
Copy Markdown
Collaborator

Okay! I'll merge when all statuses are green.

@dpebot dpebot added the automerge Merge the pull request once unit tests and other checks pass. label Nov 17, 2016
@wenchenglu

ghost commented Nov 18, 2016

Copy link
Copy Markdown
Author

@jonparrott

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

@jeffmendoza

ghost commented Nov 18, 2016

Copy link
Copy Markdown
Contributor

@ryanmats Jon is sick today, do you know about any flake8 tools to fix errors?

@ryanmats

ghost commented Nov 18, 2016

Copy link
Copy Markdown
Contributor

@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.

@wenchenglu

ghost commented Nov 18, 2016

Copy link
Copy Markdown
Author

@waprin

fixed lint errors as you suggested, PTAL

@dpebot
dpebot merged commit 9036dcb into GoogleCloudPlatform:master Nov 18, 2016
@theacodes

ghost commented Nov 19, 2016

Copy link
Copy Markdown
Contributor

@waprin's suggestion was great. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge Merge the pull request once unit tests and other checks pass. cla: yes This human has signed the Contributor License Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants