Skip to content

Commit

Permalink
feature/issue-95-poetry-dependency-groups (#136)
Browse files Browse the repository at this point in the history
* Add support for Poetry dependency groups

* Implement dep group attrs

* Fix arg string

* Update docs

* Fix repo Poetry model

* Update docs

* Buildifier
  • Loading branch information
njlr authored Jan 7, 2025
1 parent 2bff754 commit 5598e21
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 16 deletions.
8 changes: 6 additions & 2 deletions docs/ext_lock_import.md

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

6 changes: 5 additions & 1 deletion docs/rules.md

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

5 changes: 4 additions & 1 deletion docs/workspace_rules.md

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

1 change: 1 addition & 0 deletions examples/poetry/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pycross_target_environment(
pycross_poetry_lock_model(
name = "example_lock_model",
lock_file = "poetry.lock",
optional_groups = ["dev"],
project_file = "pyproject.toml",
)

Expand Down
21 changes: 21 additions & 0 deletions examples/poetry/example_lock.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ PINS = {
"charset-normalizer": "[email protected]",
"click": "[email protected]",
"cognitojwt": "[email protected]",
"cowsay": "[email protected]",
"cryptography": "[email protected]",
"cython": "[email protected]",
"decorator": "[email protected]",
Expand Down Expand Up @@ -367,6 +368,16 @@ def targets():
wheel = ":[email protected]",
)

native.alias(
name = "[email protected]",
actual = "@example_lock_wheel_cowsay_6.1_py3_none_any//file",
)

pycross_wheel_library(
name = "[email protected]",
wheel = ":[email protected]",
)

_cryptography_41_0_5_deps = [
":[email protected]",
]
Expand Down Expand Up @@ -1874,6 +1885,16 @@ def repositories():
index = "https://pypi.org",
)

maybe(
pypi_file,
name = "example_lock_wheel_cowsay_6.1_py3_none_any",
package_name = "cowsay",
package_version = "6.1",
filename = "cowsay-6.1-py3-none-any.whl",
sha256 = "274b1e6fc1b966d53976333eb90ac94cb07a450a700b455af9fbdf882244b30a",
index = "https://pypi.org",
)

maybe(
pypi_file,
name = "example_lock_wheel_cryptography_41.0.5_cp37_abi3_macosx_10_12_universal2",
Expand Down
10 changes: 10 additions & 0 deletions examples/poetry/poetry.lock

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

3 changes: 3 additions & 0 deletions examples/poetry/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ tree-sitter = "=0.20.2"
future = "=0.18.2"
opencv-python = "=4.6.0.66"
keyring = "=23.9.1"

[tool.poetry.group.dev.dependencies]
cowsay = "^6.1"
7 changes: 7 additions & 0 deletions examples/poetry/tools/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ py_binary(
main = "ipython.py",
deps = [requirement("ipython")],
)

py_binary(
name = "app",
srcs = ["app.py"],
main = "app.py",
deps = [requirement("cowsay")],
)
3 changes: 3 additions & 0 deletions examples/poetry/tools/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import cowsay

cowsay.cow("Hello rules_pycross")
10 changes: 10 additions & 0 deletions pycross/private/lock_attrs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ POETRY_IMPORT_ATTRS = dict(
allow_single_file = True,
mandatory = True,
),
default = attr.bool(
doc = "Whether to install dependencies from the default group.",
default = True,
),
optional_groups = attr.string_list(
doc = "List of optional dependency groups to install.",
),
all_optional_groups = attr.bool(
doc = "Install all optional dependencies.",
),
)

def handle_resolve_attrs(attrs, environment_files_and_labels, local_wheel_names_and_labels):
Expand Down
38 changes: 29 additions & 9 deletions pycross/private/poetry_lock_model.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,32 @@ load(":lock_attrs.bzl", "POETRY_IMPORT_ATTRS")

TRANSLATOR_TOOL = Label("//pycross/private/tools:poetry_translator.py")

def _handle_args(attrs, project_file, lock_file, output):
args = []
args.extend(["--project-file", project_file])
args.extend(["--lock-file", lock_file])
args.extend(["--output", output])

if attrs.default:
args.append("--default")

for group in attrs.optional_groups:
args.extend(["--optional-group", group])

return args

def _pycross_poetry_lock_model_impl(ctx):
out = ctx.actions.declare_file(ctx.attr.name + ".json")

args = ctx.actions.args().use_param_file("--flagfile=%s")
args.add("--project-file", ctx.file.project_file)
args.add("--lock-file", ctx.file.lock_file)
args.add("--output", out)
args.add_all(
_handle_args(
ctx.attr,
ctx.file.project_file.path,
ctx.file.lock_file.path,
out.path,
),
)

ctx.actions.run(
inputs = (
Expand Down Expand Up @@ -40,11 +59,14 @@ pycross_poetry_lock_model = rule(
} | POETRY_IMPORT_ATTRS,
)

def lock_repo_model_poetry(*, project_file, lock_file):
def lock_repo_model_poetry(*, project_file, lock_file, default = True, optional_groups = [], all_optional_groups = False):
return json.encode(dict(
model_type = "poetry",
project_file = str(project_file),
lock_file = str(lock_file),
default = default,
optional_groups = optional_groups,
all_optional_groups = all_optional_groups,
))

def repo_create_poetry_model(rctx, params, output):
Expand All @@ -59,14 +81,12 @@ def repo_create_poetry_model(rctx, params, output):
attrs = struct(**params)
else:
attrs = params
args = [
"--project-file",
args = _handle_args(
attrs,
str(rctx.path(Label(attrs.project_file))),
"--lock-file",
str(rctx.path(Label(attrs.lock_file))),
"--output",
output,
]
)

exec_internal_tool(
rctx,
Expand Down
49 changes: 46 additions & 3 deletions pycross/private/tools/poetry_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,13 @@ def get_files_for_package(
return result


def translate(project_file: Path, lock_file: Path) -> RawLockSet:
def translate(
project_file: Path,
lock_file: Path,
default_group: bool,
optional_groups: List[str],
all_optional_groups: bool,
) -> RawLockSet:
try:
with open(project_file, "rb") as f:
project_dict = tomli.load(f)
Expand All @@ -113,7 +119,19 @@ def translate(project_file: Path, lock_file: Path) -> RawLockSet:
raise Exception(f"Could not load lock file: {lock_file}: {e}")

pinned_package_specs = {}
for pin, pin_info in (project_dict.get("tool", {}).get("poetry", {}).get("dependencies", {})).items():

dependency_items = []

if default_group:
dependency_items.extend((project_dict.get("tool", {}).get("poetry", {}).get("dependencies", {})).items())

groups = project_dict.get("tool", {}).get("poetry", {}).get("group", {})

for group_name, group in groups.items():
if all_optional_groups or group_name in optional_groups:
dependency_items.extend(group.get("dependencies", {}).items())

for pin, pin_info in dependency_items:
pin = package_canonical_name(pin)
if pin == "python":
# Skip the special line indicating python version.
Expand Down Expand Up @@ -242,7 +260,13 @@ def parse_file_info(file_info) -> PackageFile:
def main(args: Any) -> None:
output = args.output

lock_set = translate(args.project_file, args.lock_file)
lock_set = translate(
project_file=args.project_file,
lock_file=args.lock_file,
default_group=args.default,
optional_groups=args.optional_group,
all_optional_groups=args.all_optional_groups,
)

with open(output, "w") as f:
f.write(lock_set.to_json(indent=2))
Expand All @@ -265,6 +289,25 @@ def parse_flags() -> Any:
help="The path to pdm.lock.",
)

parser.add_argument(
"--default",
action="store_true",
help="Whether to install dependencies from the default group.",
)

parser.add_argument(
"--optional-group",
action="append",
default=[],
help="Optional dependency groups to install.",
)

parser.add_argument(
"--all-optional-groups",
action="store_true",
help="Install all optional dependency groups.",
)

parser.add_argument(
"--output",
type=Path,
Expand Down

0 comments on commit 5598e21

Please sign in to comment.