1 # Project overview 2 3 ## Title 4 5 Enable Building of gRPC Python with Bazel 6 7 ## Overview 8 9 gRPC Python currently has a constellation of scripts written to build the 10 project, but it has a lot of limitations in terms of speed and maintainability. 11 [Bazel](https://bazel.build/) is the open-sourced variant of Google's internal 12 system, Blaze, which is an ideal replacement for building such projects in a 13 fast and declarative fashion. But Bazel in itself is still in active 14 development, especially in terms of Python (amongst a few other languages). 15 16 The project aimed to fill this gap and build gRPC Python with Bazel. 17 18 [Project page](https://summerofcode.withgoogle.com/projects/#6482576244473856) 19 20 [Link to proposal](https://storage.googleapis.com/summerofcode-prod.appspot.com/gsoc/core_project/doc/5316764725411840_1522049732_Naresh_Ramesh_-_GSoC_proposal.pdf) 21 22 ## Thoughts and challenges 23 24 ### State of Bazel for Python 25 26 Although previously speculated, the project didn't require any contributions 27 directly to [bazelbuild/bazel](https://github.com/bazelbuild/bazel). The Bazel 28 rules for Python are currently being separated out into their own repo at 29 [bazelbuild/rules_python](https://github.com/bazelbuild/rules_python/). 30 31 Bazel is [still very much in active development for 32 Python](https://groups.google.com/forum/#!topic/bazel-sig-python/iQjV9sfSufw) 33 though. There's still challenges when it comes to building for Python 2 vs 3. 34 Using pip packages is still in experimental. Bazel Python support is currently 35 distributed across these two repositories and is yet to begin migration to one 36 place (which will be 37 [bazelbuild/rules_python](https://github.com/bazelbuild/rules_python/)). 38 39 Bazel's roadmap for Python is publicly available [here as a Google 40 doc](https://docs.google.com/document/d/1A6J3j3y1SQ0HliS86_mZBnB5UeBe7vExWL2Ryd_EONI/edit). 41 42 ### Cross collaboration between projects 43 44 Cross contribution surprisingly came up because of building protobuf sources 45 for Python, which is still not natively supported by Bazel. An existing 46 repository, [pubref/rules_protobuf](https://github.com/pubref/rules_protobuf), 47 which was maintained by an independent maintainer (i.e. not a part of Bazel) 48 helped solve this problem, but had [one major blocking 49 issue](https://github.com/pubref/rules_protobuf/issues/233) and could not be 50 resolved at the source. But [a solution to the 51 issue](https://github.com/pubref/rules_protobuf/pull/196) was proposed by user 52 dududko, which was not merged because of failing golang tests but worked well 53 for Python. Hence, a fork of this repo was made and is to be used with gRPC 54 until the solution can be merged back at the source. 55 56 ### Building Cython code 57 58 Building Cython code is still not supported by Bazel, but the team at 59 [cython/cython](https://github.com/cython/cython) have added support for Bazel 60 on their side. The way it works is by including Cython as a third-party Bazel 61 dependency and using custom Bazel rules for building our Cython code using the 62 binary within the dependency. 63 64 ### Packaging Python code using Bazel 65 66 pip and PyPI still remain the de-facto standard for distributing Python 67 packages. Although Bazel is pretty versatile and is amazing for it's 68 reproducible and incremental build capabilities, these can only be still used 69 by the contributors and developers for building and testing the gRPC code. But 70 there's no way yet to build Python packages for distribution. 71 72 ### Building gRPC Python with Bazel on Kokoro (internal CI) 73 74 Integration with the internal CI was one of the areas that highlighted how 75 simple Bazel can be to use. gRPC was already using a dockerized Bazel setup to 76 build some of it's core code (but not as the primary build setup). Adding a new 77 job on the internal CI ended up being as simple as creating a new shell script 78 to install the required dependencies (which were python-dev and Bazel) and a 79 new configuration file which pointed to the subdirectiory (src/python) under 80 which to look for targets and run the tests accordingly. 81 82 ### Handling imports in Python code 83 84 When writing Python packages, imports in nested modules are typically made 85 relative to the package root. But because of the way Bazel works, these paths 86 wouldn't make sense from the Workspace root. So, the folks at Bazel have added 87 a nifty `imports` parameter to all the Python rules which lets us specify for 88 each target, which path to consider as the root. This parameter allows for 89 relative paths like `imports = ["../",]`. 90 91 ### Fetching Python headers for Cython code to use 92 93 Cython code makes use of `Python.h`, which pulls in the Python API for C 94 extension modules to use, but it's location depending on the Python version and 95 operating system the code is building on. To make this easier, the folks at 96 Tensorflow wrote [repository rules for Python 97 autoconfiguration](https://github.com/tensorflow/tensorflow/tree/e447ae4759317156d31a9421290716f0ffbffcd8/third_party/py). 98 This has been [adapted with some some 99 modifications](https://github.com/grpc/grpc/pull/15992) for use in gRPC Python 100 as well. 101 102 ## How to use 103 104 All the Bazel tests for gRPC Python can be run using a single command: 105 106 ```bash 107 bazel test --spawn_strategy=standalone --genrule_strategy=standalone //src/python/... 108 ``` 109 110 If any specific test is to be run, like say `LoggingPoolTest` (which is present 111 in 112 `src/python/grpcio_tests/tests/unit/framework/foundation/_logging_pool_test.py`), 113 the command to run would be: 114 115 ```bash 116 bazel test --spawn_strategy=standalone --genrule_strategy=standalone //src/python/grpcio_tests/tests/unit/framework/foundation:logging_pool_test 117 ``` 118 119 where, `logging_pool_test` is the name of the Bazel target for this test. 120 121 Similarly, to run a particular method, use: 122 123 ```bash 124 bazel test --spawn_strategy=standalone --genrule_strategy=standalone //src/python/grpcio_tests/tests/unit/_rpc_test --test_arg=RPCTest.testUnrecognizedMethod 125 ``` 126 127 ## Useful Bazel flags 128 129 - Use `bazel build` with a `-s` flag to see the logs being printed out to 130 standard output while building. 131 - Similarly, use `bazel test` with a `--test_output=streamed` to see the the 132 test logs while testing. Something to know while using this flag is that all 133 tests will be run locally, without sharding, one at a time. 134 135 ## Contributions 136 137 ### Related to the project 138 139 - [435c6f8](https://github.com/grpc/grpc/commit/435c6f8d1e53783ec049b3482445813afd8bc514) 140 Update grpc_gevent cython files to include .pxi 141 - [74426fd](https://github.com/grpc/grpc/commit/74426fd2164c51d6754732ebe372133c19ba718c) 142 Add gevent_util.h to grpc_base_c Bazel target 143 - [b6518af](https://github.com/grpc/grpc/commit/b6518afdd610f0115b42aee1ffc71520c6b0d6b1) 144 Upgrade Bazel to 0.15.0 145 - [ebcf04d](https://github.com/grpc/grpc/commit/ebcf04d075333c42979536c5dd2091d363f67e5a) 146 Kokoro setup for building gRPC Python with Bazel 147 - [3af1aaa](https://github.com/grpc/grpc/commit/3af1aaadabf49bc6274711a11f81627c0f351a9a) 148 Basic setup to build gRPC Python with Bazel 149 - [11f199e](https://github.com/grpc/grpc/commit/11f199e34dc416a2bd8b56391b242a867bedade4) 150 Workspace changes to build gRPC Python with Bazel 151 - [848fd9d](https://github.com/grpc/grpc/commit/848fd9d75f6df10f00e8328ff052c0237b3002ab) 152 Minimal Bazel BUILD files for grpcio Python 153 154 ### Other contibutions 155 156 - [89ce16b](https://github.com/grpc/grpc/commit/89ce16b6daaad4caeb1c9ba670c6c4b62ea1a93c) 157 Update Dockerfiles for python artifacts to use latest git version 158 - [32f7c48](https://github.com/grpc/grpc/commit/32f7c48dad71cac7af652bf994ab1dde3ddb0607) 159 Revert removals from python artifact dockerfiles 160 - [712eb9f](https://github.com/grpc/grpc/commit/712eb9ff91cde66af94e8381ec01ad512ed6d03c) 161 Make logging after success in jobset more apparent 162 - [c6e4372](https://github.com/grpc/grpc/commit/c6e4372f8a93bb0eb996b5f202465785422290f2) 163 Create README for gRPC Python reflection package 164 - [2e113ca](https://github.com/grpc/grpc/commit/2e113ca6b2cc31aa8a9687d40ee1bd759381654f) 165 Update logging in Python to use module-level logger 166 167 ### Pending PRs 168 169 - BUILD files for all tests in 170 [tests.json](https://github.com/ghostwriternr/grpc/blob/70c8a58b2918a5369905e5a203d7ce7897b6207e/src/python/grpcio_tests/tests/tests.json). 171 - BUILD files for gRPC testing, gRPC health checking, gRPC reflection. 172 - (Yet to complete) BUILD files for grpcio_tools. One test depends on this. 173 174 ## Known issues 175 176 - [grpc/grpc #16336](https://github.com/grpc/grpc/issues/16336) RuntimeError 177 for `_reconnect_test` Python unit test with Bazel 178 - Some tests in Bazel pass despite throwing an exception. Example: 179 `testAbortedStreamStream` in 180 `src/python/grpcio_tests/tests/unit/_metadata_code_details_test.py`. 181 - [#14557](https://github.com/grpc/grpc/pull/14557) introduced a minor bug 182 where the module level loggers don't initialize a default logging handler. 183 - Sanity test doesn't make sense in the context of Bazel, and thus fails. 184 - There are some issues with Python2 vs Python3. Specifically, 185 - On some machines, cygrpc.so: undefined symbol: _Py_FalseStruct error 186 shows up. This is because of incorrect Python version being used to build 187 Cython. 188 - Some external packages like enum34 throw errors when used with Python 3 and 189 some extra packages are currently installed as Python version in current 190 build scripts. For now, the extra packages are added to a 191 `requirements.bazel.txt` file in the repository root. 192