Skip to content

Commit

Permalink
WIP: Add python+coverage example
Browse files Browse the repository at this point in the history
Currently WIP because:

- `$(location)` and `$(rootpath)` make vars aren't working correctly
  - This is what we tried to fix with the `PYTHON_COVERAGE_TARGET`
    variable, which was ultimately not accepted. See also next point.
- Does not use the new toolchain feature that supports adding
  coveragepy directly to the python toolchain
  - Added together with the new coveragepy support in
    bazelbuild/bazel#15590, and is probably better to use than the
    `$(rootpath)` and `pip_install` solution we're showing here
  - While I'd love to rewrite the blog post to show this instead, I'd
    need a bit more time for that
- Python imports are wonky
  - For some reason, the sibling module can only be imported under a
    parent `python` module. I confirmed this by looking through
    `PYTHON_PATH`
  - Seems to be a Bazel regression? Strangely nobody is complaining
    about this yet, we should probably raise an issue
- Not tested in remote execution
  - No access to an engflow setup to test this right this instant
  - Since we're not using a toolchain (and even if we were we're using
    `pip_install`), this requires a python on the host, so there's a
    decent chance it won't work
- Requires bumping Bazel to a version with bazelbuild/bazel#15590
  merged, which currently is only available in prereleases
  • Loading branch information
Tristan Daniël Maat committed Nov 11, 2022
1 parent 163ad01 commit 8ea46d3
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.2.0
6.0.0-pre.20221020.1
32 changes: 18 additions & 14 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")

http_archive(
name = "rules_python",
sha256 = "8c8fe44ef0a9afc256d1e75ad5f448bb59b81aba149b8958f02f7b3a98f5d9b4",
strip_prefix = "rules_python-0.13.0",
url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.13.0.tar.gz",
)

load("@rules_python//python:pip.bzl", "pip_parse")

pip_parse(
name = "coveragepy",
requirements = "//python:requirements.txt",
)

load("@coveragepy//:requirements.bzl", "install_deps")

install_deps()

# Some file dependencies
http_file(
name = "emacs",
Expand Down Expand Up @@ -167,17 +185,3 @@ load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_depe
go_rules_dependencies()

go_register_toolchains(version = "1.19.3")

http_archive(
name = "io_bazel_rules_kotlin",
sha256 = "a57591404423a52bd6b18ebba7979e8cd2243534736c5c94d35c89718ea38f94",
urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/v1.6.0/rules_kotlin_release.tgz"],
)

load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories")

kotlin_repositories()

load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")

kt_register_toolchains()
40 changes: 40 additions & 0 deletions python/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Example of a python build/test with coverage.
"""

load("@coveragepy//:requirements.bzl", "entry_point")

alias(
name = "python_coverage_tools",
actual = entry_point("coverage"),
)

py_library(
name = "example",
srcs = [
"__init__.py",
"example.py",
],
)

py_test(
name = "test_example",
size = "small",
srcs = ["test_example.py"],
env = {
# In theory this should be `$(execpath :python_coverage_tool)`,
#
# however this will not resolve correctly as Bazel will
# resolve this relative to the runfiles directory. Instead, we
# just manually specify the path in the runfiles directory the
# coverage tools will be placed in.
#
# For a better solution involving setting the coverage tool in
# the toolchain, see
# https://github.com/bazelbuild/bazel/pull/15590
"PYTHON_COVERAGE": "coveragepy_coverage/rules_python_wheel_entry_point_coverage",
},
deps = [
":example",
":python_coverage_tools",
],
)
Empty file added python/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions python/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
def fizzbuzz(i: int) -> str:
if i % 3 == 0:
if i % 5 == 0:
return "FizzBuzz"
else:
return "Fizz"
elif i % 5 == 0:
return "Buzz"
else:
return str(i)
1 change: 1 addition & 0 deletions python/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
coverage==6.5.0
19 changes: 19 additions & 0 deletions python/test_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import unittest

# Bazel seems to be setting the PYTHON_PATH wrong, resulting in a
# parent "python" module. This might be a regression.
from python.example import fizzbuzz


class ExampleTest(unittest.TestCase):
def test_fizzbuzz(self):
self.assertEqual(fizzbuzz(1), "1")
self.assertEqual(fizzbuzz(2), "2")
self.assertEqual(fizzbuzz(3), "Fizz")
self.assertEqual(fizzbuzz(4), "4")
self.assertEqual(fizzbuzz(5), "Buzz")
self.assertEqual(fizzbuzz(15), "FizzBuzz")


if __name__ == "__main__":
unittest.main()

0 comments on commit 8ea46d3

Please sign in to comment.