Skip to content

Commit 6a9311c

Browse files
author
Ryan Beasley
authored
Add py_import rule (#174)
This change adds adds a `py_import` rule to import Python eggs like `java_import` imports Java jars. py_import.egg generated using `zipper`[1]: ```console $ third_party/ijar/zipper Cc examples/py_import/py_import.egg examples/py_import/helloworld.py=examples/helloworld/helloworld.py examples/__init__.py= examples/py_import/__init__.py= ``` Partially addresses bazelbuild/bazel#7312. Addresses #222. [1]: https://github.com/bazelbuild/bazel/tree/master/third_party/ijar Testing Done: ```console $ bazelisk test --override_repository=rules_python=$PWD/../.. ... //:py_import_test PASSED in 0.6s ```
1 parent a4c375b commit 6a9311c

File tree

10 files changed

+156
-4
lines changed

10 files changed

+156
-4
lines changed

.bazelrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# This lets us glob() up all the files inside the examples to make them inputs to tests
44
# (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it)
55
# To update these lines, run tools/bazel_integration_test/update_deleted_packages.sh
6-
build --deleted_packages=examples/legacy_pip_import/boto,examples/legacy_pip_import/extras,examples/legacy_pip_import/helloworld,examples/pip_install,examples/pip_parse
7-
query --deleted_packages=examples/legacy_pip_import/boto,examples/legacy_pip_import/extras,examples/legacy_pip_import/helloworld,examples/pip_install,examples/pip_parse
6+
build --deleted_packages=examples/legacy_pip_import/boto,examples/legacy_pip_import/extras,examples/legacy_pip_import/helloworld,examples/pip_install,examples/pip_parse,examples/py_import
7+
query --deleted_packages=examples/legacy_pip_import/boto,examples/legacy_pip_import/extras,examples/legacy_pip_import/helloworld,examples/pip_install,examples/pip_parse,examples/py_import
88

99
test --test_output=errors

examples/BUILD

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ bazel_integration_test(
3131
name = "pip_parse_example",
3232
timeout = "long",
3333
)
34+
35+
bazel_integration_test(
36+
name = "py_import_example",
37+
timeout = "long",
38+
)

examples/py_import/BUILD

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2020 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
load("@pip//:requirements.bzl", "requirement")
16+
load("@rules_python//python:defs.bzl", "py_import", "py_test")
17+
18+
package(default_visibility = ["//visibility:public"])
19+
20+
licenses(["notice"]) # Apache 2.0
21+
22+
# Adapt helloworld.egg so it can be depended on as if it were a
23+
# py_library target
24+
py_import(
25+
name = "py_import",
26+
# Note: this .egg file can be regenerated using zipper:
27+
# $ third_party/ijar/zipper Cc \
28+
# examples/py_import/helloworld.egg \
29+
# examples/py_import/helloworld.py=examples/legacy_pip_import/helloworld/helloworld.py \
30+
# examples/__init__.py= \
31+
# examples/py_import/__init__.py=
32+
srcs = ["helloworld.egg"],
33+
deps = [requirement("futures")],
34+
)
35+
36+
py_test(
37+
name = "py_import_test",
38+
srcs = ["py_import_test.py"],
39+
deps = [":py_import"],
40+
)

examples/py_import/WORKSPACE

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
workspace(name = "py_import")
2+
3+
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
4+
5+
# Note, this relies on a pre-release of 0.3.0, and doesn't actually work with 0.2.0
6+
# Use --override_repository=rules_python=$HOME/Projects/rules_python to test for now
7+
http_archive(
8+
name = "rules_python",
9+
sha256 = "778197e26c5fbeb07ac2a2c5ae405b30f6cb7ad1f5510ea6fdac03bded96cc6f",
10+
url = "https://github.com/bazelbuild/rules_python/releases/download/0.2.0/rules_python-0.2.0.tar.gz",
11+
)
12+
13+
load("@rules_python//python:pip.bzl", "pip_install")
14+
15+
pip_install(requirements = "//:requirements.txt")

examples/py_import/helloworld.egg

949 Bytes
Binary file not shown.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright 2017-2019 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import unittest
16+
17+
from examples.py_import import helloworld
18+
19+
20+
class HelloWorldTest(unittest.TestCase):
21+
22+
def test_helloworld(self):
23+
hw = helloworld.HelloWorld()
24+
hw.SayHello()
25+
26+
def test_helloworld_async(self):
27+
hw = helloworld.HelloWorld()
28+
hw.SayHelloAsync()
29+
hw.Stop()
30+
31+
def test_helloworld_multiple(self):
32+
hw = helloworld.HelloWorld()
33+
hw.SayHelloAsync()
34+
hw.SayHelloAsync()
35+
hw.SayHelloAsync()
36+
hw.SayHelloAsync()
37+
hw.Stop()
38+
39+
40+
if __name__ == '__main__':
41+
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
futures>=3.1
949 Bytes
Binary file not shown.

python/defs.bzl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,56 @@ def py_test(**attrs):
7171
# buildifier: disable=native-python
7272
native.py_test(**_add_tags(attrs))
7373

74+
def _py_import_impl(ctx):
75+
# See https://github.com/bazelbuild/bazel/blob/0.24.0/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPythonSemantics.java#L104 .
76+
import_paths = [
77+
"/".join([ctx.workspace_name, x.short_path])
78+
for x in ctx.files.srcs
79+
]
80+
81+
return [
82+
DefaultInfo(
83+
default_runfiles = ctx.runfiles(ctx.files.srcs, collect_default = True),
84+
),
85+
PyInfo(
86+
transitive_sources = depset(transitive = [
87+
dep[PyInfo].transitive_sources
88+
for dep in ctx.attr.deps
89+
]),
90+
imports = depset(direct = import_paths, transitive = [
91+
dep[PyInfo].imports
92+
for dep in ctx.attr.deps
93+
]),
94+
),
95+
]
96+
97+
py_import = rule(
98+
doc = """This rule allows the use of Python packages as dependencies.
99+
100+
It imports the given `.egg` file(s), which might be checked in source files,
101+
fetched externally as with `http_file`, or produced as outputs of other rules.
102+
103+
It may be used like a `py_library`, in the `deps` of other Python rules.
104+
105+
This is similar to [java_import](https://docs.bazel.build/versions/master/be/java.html#java_import).
106+
""",
107+
implementation = _py_import_impl,
108+
attrs = {
109+
"deps": attr.label_list(
110+
doc = "The list of other libraries to be linked in to the " +
111+
"binary target.",
112+
providers = [PyInfo],
113+
),
114+
"srcs": attr.label_list(
115+
doc = "The list of Python package files provided to Python targets " +
116+
"that depend on this target. Note that currently only the .egg " +
117+
"format is accepted. For .whl files, try the whl_library rule. " +
118+
"We accept contributions to extend py_import to handle .whl.",
119+
allow_files = [".egg"],
120+
),
121+
},
122+
)
123+
74124
def py_runtime(**attrs):
75125
"""See the Bazel core [py_runtime](https://docs.bazel.build/versions/master/be/python.html#py_runtime) documentation.
76126

tools/bazel_integration_test/bazel_integration_test.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ _ATTRS = {
1313
It is assumed by the test runner that the bazel binary is found at label_workspace/bazel (wksp/bazel.exe on Windows)""",
1414
),
1515
"bazel_commands": attr.string_list(
16-
default = ["info", "test ..."],
17-
doc = """The list of bazel commands to run. Defaults to `["info", "test ..."]`.
16+
default = ["info", "test --test_output=errors ..."],
17+
doc = """The list of bazel commands to run.
1818
1919
Note that if a command contains a bare `--` argument, the --test_arg passed to Bazel will appear before it.
2020
""",

0 commit comments

Comments
 (0)