mirror of https://github.com/grpc/grpc.git
By popular demand, we'll now be offering separate py_grpc_library and py_proto_library targets sharing the same interface as within google3. This change necessitated some modifications to how we pull in our own Python-level dependencies and how we make those available to those pulling in our project via Bazel. There is now a grpc_python_deps() Bazel workspace rule that pulls in the appropriate dependencies, which should be called from the client project's WORKSPACE file. A test has been added to the bazel/test/ directory to verify that this behavior works as intended. It's worth noting that the protobuf repository's usage of Starlark bind() caused a great deal of trouble in ensuring that we could also pull in six. This change also required a change in the way generated proto code is imported in the channelz and health-check modules, as well as in their associated tests. We were importing them two different ways, each relative. This resulted in two different module objects being imported into the process, which were incompatible. I am not sure exactly what caused this behavior to begin, as this should have been possible before this PR. As a workaround, I am simply trying two different absolute imports and using the one that works. This should function both inside and outside of Bazel environments.pull/19822/head
parent
74b981a6a3
commit
7b2c8c27b0
39 changed files with 571 additions and 204 deletions
@ -1,8 +1,67 @@ |
||||
load("//third_party/py:python_configure.bzl", "python_configure") |
||||
load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories") |
||||
load("@grpc_python_dependencies//:requirements.bzl", "pip_install") |
||||
"""Load dependencies needed to compile and test the grpc python library as a 3rd-party consumer.""" |
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") |
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") |
||||
load("@com_github_grpc_grpc//third_party/py:python_configure.bzl", "python_configure") |
||||
|
||||
def grpc_python_deps(): |
||||
native.bind( |
||||
name = "six", |
||||
actual = "@six_archive//:six", |
||||
) |
||||
|
||||
# protobuf binds to the name "six", so we can't use it here. |
||||
# See https://github.com/bazelbuild/bazel/issues/1952 for why bind is |
||||
# horrible. |
||||
if "six_archive" not in native.existing_rules(): |
||||
http_archive( |
||||
name = "six_archive", |
||||
strip_prefix = "six-1.12.0", |
||||
build_file = "@com_github_grpc_grpc//third_party:six.BUILD", |
||||
sha256 = "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73", |
||||
urls = ["https://files.pythonhosted.org/packages/dd/bf/4138e7bfb757de47d1f4b6994648ec67a51efe58fa907c1e11e350cddfca/six-1.12.0.tar.gz"], |
||||
) |
||||
|
||||
if "enum34" not in native.existing_rules(): |
||||
http_archive( |
||||
name = "enum34", |
||||
build_file = "@com_github_grpc_grpc//third_party:enum34.BUILD", |
||||
strip_prefix = "enum34-1.1.6", |
||||
sha256 = "8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1", |
||||
urls = ["https://files.pythonhosted.org/packages/bf/3e/31d502c25302814a7c2f1d3959d2a3b3f78e509002ba91aea64993936876/enum34-1.1.6.tar.gz"], |
||||
) |
||||
|
||||
if "futures" not in native.existing_rules(): |
||||
http_archive( |
||||
name = "futures", |
||||
build_file = "@com_github_grpc_grpc//third_party:futures.BUILD", |
||||
strip_prefix = "futures-3.3.0", |
||||
sha256 = "7e033af76a5e35f58e56da7a91e687706faf4e7bdfb2cbc3f2cca6b9bcda9794", |
||||
urls = ["https://files.pythonhosted.org/packages/47/04/5fc6c74ad114032cd2c544c575bffc17582295e9cd6a851d6026ab4b2c00/futures-3.3.0.tar.gz"], |
||||
) |
||||
|
||||
if "io_bazel_rules_python" not in native.existing_rules(): |
||||
git_repository( |
||||
name = "io_bazel_rules_python", |
||||
commit = "fdbb17a4118a1728d19e638a5291b4c4266ea5b8", |
||||
remote = "https://github.com/bazelbuild/rules_python.git", |
||||
) |
||||
|
||||
python_configure(name = "local_config_python") |
||||
pip_repositories() |
||||
pip_install() |
||||
|
||||
native.bind( |
||||
name = "python_headers", |
||||
actual = "@local_config_python//:python_headers", |
||||
) |
||||
|
||||
if "cython" not in native.existing_rules(): |
||||
http_archive( |
||||
name = "cython", |
||||
build_file = "@com_github_grpc_grpc//third_party:cython.BUILD", |
||||
sha256 = "d68138a2381afbdd0876c3cb2a22389043fa01c4badede1228ee073032b07a27", |
||||
strip_prefix = "cython-c2b80d87658a8525ce091cbe146cb7eaa29fed5c", |
||||
urls = [ |
||||
"https://github.com/cython/cython/archive/c2b80d87658a8525ce091cbe146cb7eaa29fed5c.tar.gz", |
||||
], |
||||
) |
||||
|
||||
|
@ -0,0 +1,2 @@ |
||||
bazel-* |
||||
tools/bazel-* |
@ -0,0 +1,46 @@ |
||||
load("@com_github_grpc_grpc//bazel:python_rules.bzl", "py_proto_library", "py_grpc_library") |
||||
|
||||
package(default_testonly = 1) |
||||
|
||||
proto_library( |
||||
name = "helloworld_proto", |
||||
srcs = ["helloworld.proto"], |
||||
deps = [ |
||||
"@com_google_protobuf//:duration_proto", |
||||
"@com_google_protobuf//:timestamp_proto", |
||||
], |
||||
) |
||||
|
||||
py_proto_library( |
||||
name = "helloworld_py_pb2", |
||||
srcs = [":helloworld_proto"], |
||||
) |
||||
|
||||
py_grpc_library( |
||||
name = "helloworld_py_pb2_grpc", |
||||
srcs = [":helloworld_proto"], |
||||
deps = [":helloworld_py_pb2"], |
||||
) |
||||
|
||||
py_proto_library( |
||||
name = "duration_py_pb2", |
||||
srcs = ["@com_google_protobuf//:duration_proto"], |
||||
) |
||||
|
||||
py_proto_library( |
||||
name = "timestamp_py_pb2", |
||||
srcs = ["@com_google_protobuf//:timestamp_proto"], |
||||
) |
||||
|
||||
py_test( |
||||
name = "import_test", |
||||
main = "helloworld.py", |
||||
srcs = ["helloworld.py"], |
||||
deps = [ |
||||
":helloworld_py_pb2", |
||||
":helloworld_py_pb2_grpc", |
||||
":duration_py_pb2", |
||||
":timestamp_py_pb2", |
||||
], |
||||
python_version = "PY3", |
||||
) |
@ -0,0 +1,10 @@ |
||||
local_repository( |
||||
name = "com_github_grpc_grpc", |
||||
path = "../../..", |
||||
) |
||||
|
||||
load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") |
||||
grpc_deps() |
||||
|
||||
load("@com_github_grpc_grpc//bazel:grpc_python_deps.bzl", "grpc_python_deps") |
||||
grpc_python_deps() |
@ -0,0 +1,43 @@ |
||||
// Copyright 2019 The gRPC authors. |
||||
// |
||||
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||
// you may not use this file except in compliance with the License. |
||||
// You may obtain a copy of the License at |
||||
// |
||||
// http://www.apache.org/licenses/LICENSE-2.0 |
||||
// |
||||
// Unless required by applicable law or agreed to in writing, software |
||||
// distributed under the License is distributed on an "AS IS" BASIS, |
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
// See the License for the specific language governing permissions and |
||||
// limitations under the License. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
option java_multiple_files = true; |
||||
option java_package = "io.grpc.examples.helloworld"; |
||||
option java_outer_classname = "HelloWorldProto"; |
||||
option objc_class_prefix = "HLW"; |
||||
|
||||
package helloworld; |
||||
|
||||
import "google/protobuf/timestamp.proto"; |
||||
import "google/protobuf/duration.proto"; |
||||
|
||||
// The greeting service definition. |
||||
service Greeter { |
||||
// Sends a greeting |
||||
rpc SayHello (HelloRequest) returns (HelloReply) {} |
||||
} |
||||
|
||||
// The request message containing the user's name. |
||||
message HelloRequest { |
||||
string name = 1; |
||||
google.protobuf.Timestamp request_initiation = 2; |
||||
} |
||||
|
||||
// The response message containing the greetings |
||||
message HelloReply { |
||||
string message = 1; |
||||
google.protobuf.Duration request_duration = 2; |
||||
} |
@ -0,0 +1,73 @@ |
||||
# Copyright 2019 the gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
"""The Python implementation of the GRPC helloworld.Greeter client.""" |
||||
|
||||
import contextlib |
||||
import datetime |
||||
import logging |
||||
import unittest |
||||
|
||||
import grpc |
||||
|
||||
import duration_pb2 |
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
_HOST = 'localhost' |
||||
_SERVER_ADDRESS = '{}:0'.format(_HOST) |
||||
|
||||
|
||||
class Greeter(helloworld_pb2_grpc.GreeterServicer): |
||||
|
||||
def SayHello(self, request, context): |
||||
request_in_flight = datetime.now() - request.request_initation.ToDatetime() |
||||
request_duration = duration_pb2.Duration() |
||||
request_duration.FromTimedelta(request_in_flight) |
||||
return helloworld_pb2.HelloReply( |
||||
message='Hello, %s!' % request.name, |
||||
request_duration=request_duration, |
||||
) |
||||
|
||||
|
||||
@contextlib.contextmanager |
||||
def _listening_server(): |
||||
server = grpc.server(futures.ThreadPoolExecutor()) |
||||
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) |
||||
port = server.add_insecure_port(_SERVER_ADDRESS) |
||||
server.start() |
||||
try: |
||||
yield port |
||||
finally: |
||||
server.stop(0) |
||||
|
||||
|
||||
class ImportTest(unittest.TestCase): |
||||
def run(): |
||||
with _listening_server() as port: |
||||
with grpc.insecure_channel('{}:{}'.format(_HOST, port)) as channel: |
||||
stub = helloworld_pb2_grpc.GreeterStub(channel) |
||||
request_timestamp = timestamp_pb2.Timestamp() |
||||
request_timestamp.GetCurrentTime() |
||||
response = stub.SayHello(helloworld_pb2.HelloRequest( |
||||
name='you', |
||||
request_initiation=request_timestamp, |
||||
), |
||||
wait_for_ready=True) |
||||
self.assertEqual(response.message, "Hello, you!") |
||||
self.assertGreater(response.request_duration.microseconds, 0) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
unittest.main() |
@ -0,0 +1 @@ |
||||
../../../../tools/bazel |
@ -0,0 +1,6 @@ |
||||
py_library( |
||||
name = "enum34", |
||||
srcs = ["enum/__init__.py"], |
||||
srcs_version = "PY2AND3", |
||||
visibility = ["//visibility:public"], |
||||
) |
@ -0,0 +1,6 @@ |
||||
py_library( |
||||
name = "futures", |
||||
srcs = glob(["concurrent/**/*.py"]), |
||||
srcs_version = "PY2AND3", |
||||
visibility = ["//visibility:public"], |
||||
) |
@ -0,0 +1,6 @@ |
||||
py_library( |
||||
name = "six", |
||||
srcs = ["six.py"], |
||||
srcs_version = "PY2AND3", |
||||
visibility = ["//visibility:public"], |
||||
) |
Loading…
Reference in new issue