Skip to content

Commit

Permalink
Merge branch 'main' into feat/entry-point-bzlmod-minimal
Browse files Browse the repository at this point in the history
  • Loading branch information
rickeylev authored May 17, 2023
2 parents 8e3c9b0 + 1383bd4 commit c5966cd
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 14 deletions.
6 changes: 4 additions & 2 deletions docs/pip_repository.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion examples/build_file_generation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ extension, so that targets like `py_library` and `py_binary` can be
automatically created just by running

```sh
$ bazel run //:gazelle
bazel run //:requirements.update
bazel run //:gazelle_python_manifest.update
bazel run //:gazelle
```

As a demo, try creating a `__main__.py` file in this directory, then
Expand Down
13 changes: 12 additions & 1 deletion examples/bzlmod/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("@pip//:requirements.bzl", "requirement")
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@pip//:requirements.bzl", "all_requirements", "all_whl_requirements", "requirement")
load("@python3_9//:defs.bzl", py_test_with_transition = "py_test")
load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
Expand Down Expand Up @@ -44,3 +45,13 @@ py_test_with_transition(
main = "test.py",
deps = [":lib"],
)

build_test(
name = "all_wheels",
targets = all_whl_requirements,
)

build_test(
name = "all_requirements",
targets = all_requirements,
)
3 changes: 3 additions & 0 deletions examples/bzlmod/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module(
compatibility_level = 1,
)

bazel_dep(name = "bazel_skylib", version = "1.4.1")
bazel_dep(name = "rules_python", version = "0.0.0")
local_path_override(
module_name = "rules_python",
Expand Down Expand Up @@ -34,6 +35,8 @@ pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
name = "pip",
python_interpreter_target = "@interpreter_python3_9//:python",
# Intentionally set it false because the "true" case is already covered by examples/bzlmod_build_file_generation
incompatible_generate_aliases = False,
requirements_lock = "//:requirements_lock.txt",
requirements_windows = "//:requirements_windows.txt",
)
Expand Down
45 changes: 45 additions & 0 deletions examples/bzlmod/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,57 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import pathlib
import sys
import unittest

from lib import main


class ExampleTest(unittest.TestCase):
def test_coverage_doesnt_shadow_stdlib(self):
# When we try to import the html module
import html as html_stdlib

try:
import coverage.html as html_coverage
except ImportError:
self.skipTest("not running under coverage, skipping")

self.assertNotEqual(
html_stdlib,
html_coverage,
"'html' import should not be shadowed by coverage",
)

def test_coverage_sys_path(self):
all_paths = ",\n ".join(sys.path)

for i, path in enumerate(sys.path[1:-2]):
self.assertFalse(
"/coverage" in path,
f"Expected {i + 2}th '{path}' to not contain 'coverage.py' paths, "
f"sys.path has {len(sys.path)} items:\n {all_paths}",
)

first_item, last_item = sys.path[0], sys.path[-1]
self.assertFalse(
first_item.endswith("coverage"),
f"Expected the first item in sys.path '{first_item}' to not be related to coverage",
)
if os.environ.get("COVERAGE_MANIFEST"):
# we are running under the 'bazel coverage :test'
self.assertTrue(
"pypi__coverage_cp" in last_item,
f"Expected {last_item} to be related to coverage",
)
self.assertEqual(pathlib.Path(last_item).name, "coverage")
else:
self.assertFalse(
"coverage" in last_item, f"Expected coverage tooling to not be present"
)

def test_main(self):
self.assertEquals(
"""\
Expand Down
1 change: 1 addition & 0 deletions python/extensions/pip.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def _pip_impl(module_ctx):
# this does not create the install_deps() macro.
pip_repository_bzlmod(
name = attr.name,
repo_name = attr.name,
requirements_lock = attr.requirements_lock,
incompatible_generate_aliases = attr.incompatible_generate_aliases,
)
Expand Down
10 changes: 7 additions & 3 deletions python/pip_install/pip_repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ def _pip_repository_bzlmod_impl(rctx):

bzl_packages = sorted([name for name, _ in packages])

repo_name = rctx.attr.name.split("~")[-1]
repo_name = rctx.attr.repo_name

build_contents = _BUILD_FILE_CONTENTS

Expand All @@ -379,11 +379,11 @@ def _pip_repository_bzlmod_impl(rctx):
rctx.file("BUILD.bazel", build_contents)
rctx.template("requirements.bzl", rctx.attr._template, substitutions = {
"%%ALL_REQUIREMENTS%%": _format_repr_list([
"@{}//{}".format(repo_name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:pkg".format(rctx.attr.name, p)
macro_tmpl.format(p, p) if rctx.attr.incompatible_generate_aliases else macro_tmpl.format(p, "pkg")
for p in bzl_packages
]),
"%%ALL_WHL_REQUIREMENTS%%": _format_repr_list([
"@{}//{}:whl".format(repo_name, p) if rctx.attr.incompatible_generate_aliases else "@{}_{}//:whl".format(rctx.attr.name, p)
macro_tmpl.format(p, "whl")
for p in bzl_packages
]),
"%%MACRO_TMPL%%": macro_tmpl,
Expand All @@ -396,6 +396,10 @@ pip_repository_bzlmod_attrs = {
default = False,
doc = "Allow generating aliases in '@pip//:<pkg>' -> '@pip_<pkg>//:pkg'. This replaces the aliases generated by the `bzlmod` tooling.",
),
"repo_name": attr.string(
mandatory = True,
doc = "The apparent name of the repo. This is needed because in bzlmod, the name attribute becomes the canonical name",
),
"requirements_darwin": attr.label(
allow_single_file = True,
doc = "Override the requirements_lock attribute when the host platform is Mac OS",
Expand Down
8 changes: 8 additions & 0 deletions python/pip_install/private/test/requirements_parser_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ SomeProject == 1.3 # This is a comment
FooProject==1.0.0
# Comment
BarProject==2.0.0 #Comment
""").requirements)
asserts.equals(env, [("requests", "requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49")], parse("""\
requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49
""").requirements)

# Multiline
Expand All @@ -71,6 +74,11 @@ certifi==2021.10.8 \
--hash=sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569
# via requests
""").requirements)
asserts.equals(env, [("requests", "requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49 --hash=sha256:eca58eb564b134e4ff521a02aa6f566c653835753e1fc8a50a20cb6bee4673cd")], parse("""\
requests @ https://github.com/psf/requests/releases/download/v2.29.0/requests-2.29.0.tar.gz#sha1=3897c249b51a1a405d615a8c9cb92e5fdbf0dd49 \
--hash=sha256:eca58eb564b134e4ff521a02aa6f566c653835753e1fc8a50a20cb6bee4673cd
# via requirements.txt
""").requirements)

# Options
asserts.equals(env, ["--pre"], parse("--pre\n").options)
Expand Down
4 changes: 2 additions & 2 deletions python/pip_install/requirements_parser.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def _handleParseOption(input, buffer, result):
elif input == "\n" or input == EOF:
result.options.append(buffer.rstrip("\n"))
return (_STATE.ConsumeSpace, "")
elif input == "#":
elif input == "#" and (len(buffer) == 0 or buffer[-1].isspace()):
return (_STATE.ConsumeComment, buffer)

return (_STATE.ParseOption, buffer + input)
Expand All @@ -127,7 +127,7 @@ def _handleParseRequirement(input, buffer, result):
elif input == "\n" or input == EOF:
result.requirements[-1] = (result.requirements[-1][0], buffer.rstrip(" \n"))
return (_STATE.ConsumeSpace, "")
elif input == "#":
elif input == "#" and (len(buffer) == 0 or buffer[-1].isspace()):
return (_STATE.ConsumeComment, buffer)

return (_STATE.ParseRequirement, buffer + input)
16 changes: 11 additions & 5 deletions python/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ def _python_repository_impl(rctx):
python_version = rctx.attr.python_version
python_short_version = python_version.rpartition(".")[0]
release_filename = rctx.attr.release_filename
url = rctx.attr.urls or [rctx.attr.url]
urls = rctx.attr.urls or [rctx.attr.url]

if release_filename.endswith(".zst"):
rctx.download(
url = url,
url = urls,
sha256 = rctx.attr.sha256,
output = release_filename,
)
Expand Down Expand Up @@ -153,7 +153,7 @@ def _python_repository_impl(rctx):
fail(fail_msg)
else:
rctx.download_and_extract(
url = url,
url = urls,
sha256 = rctx.attr.sha256,
stripPrefix = rctx.attr.strip_prefix,
)
Expand Down Expand Up @@ -348,7 +348,7 @@ py_runtime_pair(
rctx.file(STANDALONE_INTERPRETER_FILENAME, "# File intentionally left blank. Indicates that this is an interpreter repo created by rules_python.")
rctx.file("BUILD.bazel", build_content)

return {
attrs = {
"coverage_tool": rctx.attr.coverage_tool,
"distutils": rctx.attr.distutils,
"distutils_content": rctx.attr.distutils_content,
Expand All @@ -360,9 +360,15 @@ py_runtime_pair(
"release_filename": release_filename,
"sha256": rctx.attr.sha256,
"strip_prefix": rctx.attr.strip_prefix,
"url": url,
}

if rctx.attr.url:
attrs["url"] = rctx.attr.url
else:
attrs["urls"] = urls

return attrs

python_repository = repository_rule(
_python_repository_impl,
doc = "Fetches the external tools needed for the Python toolchain.",
Expand Down

0 comments on commit c5966cd

Please sign in to comment.