-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 962c937
Showing
35 changed files
with
1,272 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
bazel-* | ||
|
||
.venv | ||
*.egg-info | ||
|
||
# Poetry extracts vendored tarballs into this directory. | ||
tests/multi/app/vendor/unpacked |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
# rules_python_poetry | ||
|
||
Bazel rules to install Python dependencies from a [Poetry](https://python-poetry.org/) project. | ||
Works with native Python rules for Bazel. | ||
|
||
## Getting started | ||
|
||
Add the following to your `WORKSPACE` file: | ||
|
||
```py | ||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") | ||
|
||
http_archive( | ||
name = "rules_python", | ||
url = "https://github.com/bazelbuild/rules_python/releases/download/0.1.0/rules_python-0.1.0.tar.gz", | ||
sha256 = "b6d46438523a3ec0f3cead544190ee13223a52f6a6765a29eae7b7cc24cc83a0", | ||
) | ||
|
||
http_archive( | ||
name = "rules_python_poetry", | ||
url = "TODO", | ||
sha256 = "TODO", | ||
) | ||
|
||
load("@rules_python_poetry//:defs.bzl", "poetry_install_toolchain", "poetry_install") | ||
|
||
# Optional, if you want to use a specific version of Poetry (1.0.10 is the default). | ||
poetry_install_toolchain(poetry_version = "1.1.4") | ||
|
||
poetry_install( | ||
name = "my_deps", | ||
pyproject_toml = "//path/to:pyproject.toml", | ||
poetry_lock = "//path/to:poetry.lock", | ||
dev = True, # Optional | ||
) | ||
``` | ||
|
||
Under the hood, `poetry_install` uses Poetry to export a `requirements.txt` file which is then passed to [`rule_python`'s `pip_install` repository rule](https://github.com/bazelbuild/rules_python#importing-pip-dependencies). | ||
You can consume dependencies the same way as you would with `pip_install`, e.g.: | ||
|
||
```py | ||
load("@my_deps//:requirements.bzl", "requirement") | ||
|
||
py_library( | ||
name = "my_lib", | ||
srcs = ["my_lib.py"], | ||
deps = [ | ||
":my_other_lib", | ||
requirement("some_pip_dep"), | ||
requirement("another_pip_dep[some_extra]"), | ||
], | ||
) | ||
``` | ||
|
||
## Poetry dependencies | ||
|
||
Poetry allows you to specify dependencies from different types of sources that are not automatically fetched and installed by the `poetry_install` rule. You will have to manually declare these dependencies. | ||
|
||
See [`tests/multi/app`](tests/multi/app) for examples. | ||
|
||
### Local directory dependency | ||
|
||
A dependency on a local directory, for example if you have multiple projects within a monorepo that depend on each other. | ||
|
||
```toml | ||
[tool.poetry.dependencies] | ||
foo = {path = "../libs/foo"} | ||
``` | ||
|
||
If the local dependency has a `py_library` target, you can include it in the `deps` attribute. | ||
|
||
```py | ||
py_library( | ||
name = "my_lib", | ||
srcs = ["my_lib.py"], | ||
deps = [ | ||
"//path/to/libs:foo", | ||
], | ||
) | ||
``` | ||
|
||
### Local file dependency | ||
|
||
A dependency on a local tarball, for example if you have vendored packages. | ||
|
||
```toml | ||
[tool.poetry.dependencies] | ||
foo = {path = "../vendor/foo-1.2.3.tar.gz"} | ||
``` | ||
|
||
There are some options available. | ||
The first is to extract the archive and vendor the extracted files. Then add a `py_library` that can be included as a `deps`, like the local directory dependency. | ||
|
||
The second is to use the `py_archive` repository rule to declare the archive as an external repository in your `WORKSPACE` file, e.g.: | ||
|
||
```py | ||
load("@rules_python_poetry//:defs.bzl", "py_archive") | ||
|
||
py_archive( | ||
name = "foo", | ||
archive = "//path/to/vendor:foo-1.2.3.tar.gz", | ||
strip_prefix = "foo-1.2.3", | ||
) | ||
``` | ||
|
||
The `py_archive` rule defines a target named `:py_library` that can be referenced like so: | ||
|
||
```py | ||
py_library( | ||
name = "my_lib", | ||
srcs = ["my_lib.py"], | ||
deps = [ | ||
"@foo//:py_library", | ||
], | ||
) | ||
``` | ||
|
||
### URL dependency | ||
|
||
A dependency on a remote archive. | ||
|
||
```toml | ||
[tool.poetry.dependencies] | ||
foo = {url = "https://example.com/packages/foo-1.2.3.tar.gz"} | ||
``` | ||
|
||
You can use the `py_archive` repository rule to declare the remote archive as an external repository in your `WORKSPACE` file, e.g.: | ||
|
||
```py | ||
load("@rules_python_poetry//:defs.bzl", "py_archive") | ||
|
||
py_archive( | ||
name = "foo", | ||
url = "https://example.com/packages/foo-1.2.3.tar.gz", | ||
sha256 = "...", | ||
strip_prefix = "foo-1.2.3", | ||
) | ||
``` | ||
|
||
The `py_archive` rule defines a target named `:py_library` that can be referenced like so: | ||
|
||
```py | ||
py_library( | ||
name = "my_lib", | ||
srcs = ["my_lib.py"], | ||
deps = [ | ||
"@foo//:py_library", | ||
], | ||
) | ||
``` | ||
|
||
### Git dependency | ||
|
||
Git dependencies are not currently supported. You can work around this by using a URL dependency instead of a git key. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
workspace(name = "rules_python_poetry") | ||
|
||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") | ||
|
||
http_archive( | ||
name = "rules_python", | ||
url = "https://github.com/bazelbuild/rules_python/releases/download/0.1.0/rules_python-0.1.0.tar.gz", | ||
sha256 = "b6d46438523a3ec0f3cead544190ee13223a52f6a6765a29eae7b7cc24cc83a0", | ||
) | ||
|
||
load("//:defs.bzl", "poetry_install_toolchain", "poetry_install", "py_archive") | ||
|
||
poetry_install_toolchain(poetry_version = "1.0.10") | ||
|
||
# Simple test | ||
|
||
poetry_install( | ||
name = "simple_deps", | ||
pyproject_toml = "//tests/simple:pyproject.toml", | ||
poetry_lock = "//tests/simple:poetry.lock", | ||
dev = True, | ||
) | ||
|
||
# Multi test | ||
|
||
py_archive( | ||
name = "multi_app_requests", | ||
archive = "//tests/multi/app/vendor:requests-2.25.0.tar.gz", | ||
strip_prefix = "requests-2.25.0", | ||
) | ||
|
||
py_archive( | ||
name = "multi_app_responses", | ||
url = "https://files.pythonhosted.org/packages/88/98/bf9e777a482ac076a6d75fad7d62b064f535244bf1771c3b2a7d41fd5920/responses-0.12.1.tar.gz", | ||
sha256 = "2e5764325c6b624e42b428688f2111fea166af46623cb0127c05f6afb14d3457", | ||
strip_prefix = "responses-0.12.1", | ||
) | ||
|
||
poetry_install( | ||
name = "multi_app_deps", | ||
pyproject_toml = "//tests/multi/app:pyproject.toml", | ||
poetry_lock = "//tests/multi/app:poetry.lock", | ||
) | ||
|
||
poetry_install( | ||
name = "multi_liba_deps", | ||
pyproject_toml = "//tests/multi/liba:pyproject.toml", | ||
poetry_lock = "//tests/multi/liba:poetry.lock", | ||
) | ||
|
||
poetry_install( | ||
name = "multi_libb_deps", | ||
pyproject_toml = "//tests/multi/libb:pyproject.toml", | ||
poetry_lock = "//tests/multi/libb:poetry.lock", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
load("//internal/toolchain:toolchain.bzl", _poetry_install_toolchain = "poetry_install_toolchain") | ||
load("//internal:export.bzl", _poetry_export = "poetry_export") | ||
load("//internal:install.bzl", _poetry_install = "poetry_install") | ||
load("//internal:py_archive.bzl", _py_archive = "py_archive") | ||
|
||
poetry_install_toolchain = _poetry_install_toolchain | ||
poetry_export = _poetry_export | ||
poetry_install = _poetry_install | ||
py_archive = _py_archive |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
def _poetry_export_impl(repository_ctx): | ||
poetry_runner_py = repository_ctx.path(Label("@poetry_toolchain//:poetry_runner.py")) | ||
strip_dependencies_py = repository_ctx.path(Label("@poetry_toolchain//:strip_dependencies.py")) | ||
|
||
repository_ctx.symlink(repository_ctx.attr.pyproject_toml, repository_ctx.path("pyproject.toml.in")) | ||
repository_ctx.symlink(repository_ctx.attr.poetry_lock, repository_ctx.path("poetry.lock.in")) | ||
|
||
for format in ["pyproject.toml", "poetry.lock"]: | ||
result = repository_ctx.execute([ | ||
"python", | ||
strip_dependencies_py, | ||
"--file", | ||
repository_ctx.path(format + ".in"), | ||
"--output", | ||
repository_ctx.path(format), | ||
"--format", | ||
format, | ||
]) | ||
if result.return_code: | ||
fail("Poetry strip dependencies failed:\n%s\n%s" % (result.stdout, result.stderr)) | ||
|
||
args = [ | ||
"python", | ||
poetry_runner_py, | ||
"export", | ||
"--without-hashes", | ||
"--format", | ||
repository_ctx.attr.format, | ||
"--output", | ||
repository_ctx.path(repository_ctx.attr.format), | ||
] | ||
if repository_ctx.attr.dev: | ||
args.append("--dev") | ||
|
||
result = repository_ctx.execute(args) | ||
if result.return_code: | ||
fail("Poetry export to requirements.txt failed:\n%s\n%s" % (result.stdout, result.stderr)) | ||
|
||
repository_ctx.file("BUILD.bazel") | ||
|
||
poetry_export = repository_rule( | ||
implementation = _poetry_export_impl, | ||
attrs = { | ||
"pyproject_toml": attr.label( | ||
mandatory = True, | ||
allow_single_file = True, | ||
doc = "Label of the project's pyproject.toml file", | ||
), | ||
"poetry_lock": attr.label( | ||
mandatory = True, | ||
allow_single_file = True, | ||
doc = "Label of the project's poetry.lock file", | ||
), | ||
"dev": attr.bool( | ||
default = False, | ||
doc = "Include development dependencies", | ||
), | ||
"format": attr.string( | ||
default = "requirements.txt", | ||
doc = "Format to export to. Currently, only requirements.txt is supported.", | ||
), | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
load("@rules_python//python:pip.bzl", "pip_install") | ||
load("//internal/toolchain:toolchain.bzl", "poetry_install_toolchain") | ||
load("//internal:export.bzl", "poetry_export") | ||
|
||
def poetry_install(name, pyproject_toml, poetry_lock, dev = False, **kwargs): | ||
if "poetry_toolchain" not in native.existing_rules().keys(): | ||
poetry_install_toolchain() | ||
|
||
export_name = name + "_export" | ||
poetry_export( | ||
name = export_name, | ||
pyproject_toml = pyproject_toml, | ||
poetry_lock = poetry_lock, | ||
dev = dev, | ||
) | ||
|
||
pip_install( | ||
name = name, | ||
requirements = "@{}//:requirements.txt".format(export_name), | ||
**kwargs, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
BUILD_TMPL = """\ | ||
package(default_visibility = ["//visibility:public"]) | ||
load("@rules_python//python:defs.bzl", "py_library") | ||
py_library( | ||
name = "py_library", | ||
srcs = glob(["**/*.py"]), | ||
data = glob(["**/*"], exclude=["**/*.py", "**/* *"]), | ||
) | ||
""" | ||
|
||
def _py_archive_impl(repository_ctx): | ||
if repository_ctx.attr.url: | ||
repository_ctx.download_and_extract( | ||
url = repository_ctx.attr.url, | ||
sha256 = repository_ctx.attr.sha256, | ||
stripPrefix = repository_ctx.attr.strip_prefix, | ||
) | ||
elif repository_ctx.attr.archive: | ||
repository_ctx.extract( | ||
archive = repository_ctx.attr.archive, | ||
stripPrefix = repository_ctx.attr.strip_prefix, | ||
) | ||
else: | ||
fail("Either 'url' or 'archive' must be provided.") | ||
|
||
repository_ctx.file("BUILD.bazel", BUILD_TMPL) | ||
|
||
py_archive = repository_rule( | ||
implementation = _py_archive_impl, | ||
attrs = { | ||
"url": attr.string( | ||
doc = "URL of the Python archive.", | ||
), | ||
"sha256": attr.string( | ||
doc = "SHA256 hash of the downloaded archive file.", | ||
), | ||
"archive": attr.label( | ||
allow_single_file = True, | ||
doc = "Label of the Python archive. Either 'url' or 'archive' must be provided.", | ||
), | ||
"strip_prefix": attr.string( | ||
doc = "A directory prefix to strip from the extracted files.", | ||
), | ||
}, | ||
) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# -*- coding: utf-8 -*- | ||
# Adapted from https://github.com/python-poetry/poetry/blob/master/get-poetry.py | ||
|
||
import sys | ||
import os | ||
|
||
lib = os.path.normpath(os.path.join(os.path.realpath(__file__), "..", "src")) | ||
vendors = os.path.join(lib, "poetry", "_vendor") | ||
current_vendors = os.path.join( | ||
vendors, "py{}".format(".".join(str(v) for v in sys.version_info[:2])) | ||
) | ||
|
||
sys.path.insert(0, lib) | ||
sys.path.insert(0, current_vendors) | ||
|
||
if __name__ == "__main__": | ||
from poetry.console import main | ||
main() |
Oops, something went wrong.