Skip to content
Snippets Groups Projects
Commit e3da23a4 authored by André Anjos's avatar André Anjos :speech_balloon:
Browse files

[scripts.pixi] More default functionality

parent 11fcc50a
Branches
Tags
1 merge request!14Provide support for auto-generating pixi configuration files
Pipeline #85256 passed
......@@ -18,7 +18,8 @@ logger = setup(__name__.split(".", 1)[0])
epilog="""
Examples:
1. Creates a pixi configuration file for a project you just checked out:
1. Creates a **draft** pixi configuration file for a project you just checked
out:
.. code:: sh
......@@ -27,7 +28,7 @@ Examples:
...
>>>
2. Creates a pixi configuration file for a project you checked out at
2. Creates a draft pixi configuration file for a project you checked out at
directory my-project:
.. code:: sh
......@@ -40,10 +41,10 @@ Examples:
.. tip::
You may hand-edit the output file ``pixi.toml`` to adjust for details, add
conda or Python packages you'd like to complement your work environment.
An example would be adding debuggers such as ``pdbpp`` to the installation
plan.
You may hand-edit the output file ``pixi.toml`` to adjust for details,
add conda or Python packages you'd like to complement your work
environment. An example would be adding debuggers such as ``pdbpp`` to
the installation plan.
""",
)
......@@ -70,29 +71,11 @@ Examples:
show_default=True,
help="Version of python to build the environment for",
)
@click.option(
"-i/-I",
"--ignore-template/--no-ignore-template",
default=False,
show_default=True,
help="If set, then ignores any project-based templates found "
"on ``conda/pixi.toml.in``",
)
@click.option(
"-o",
"--output",
default="pixi.toml",
show_default=True,
help="The name of the environment plan file",
type=click.Path(path_type=pathlib.Path),
)
@verbosity_option(logger=logger)
def pixi(
project_dir,
profile,
python,
ignore_template,
output,
**_,
) -> None:
"""Create a pixi recipe for a project."""
......@@ -105,27 +88,34 @@ def pixi(
the_profile = Profile(profile)
def _make_requirement_dict(
requirements: list[str], version: dict[str, str]
) -> dict[str, str]:
python_to_conda = {
v: k
for k, v in the_profile.data["conda"]["to_python"].items()
if not k.startswith("__")
}
version = the_profile.conda_constraints(python)
assert version is not None
def _make_requirement_dict(requirements: list[str]) -> dict[str, str]:
retval: dict[str, str] = {}
for k in requirements:
pr = packaging.requirements.Requirement(k)
name = (
pr.name
if pr.name not in python_to_conda
else python_to_conda[pr.name]
)
if pr.name in version:
retval[pr.name] = version[pr.name]
retval[name] = version[name]
if pr.specifier:
if pr.name in retval:
retval[pr.name] = ",".join(
(retval[pr.name], str(pr.specifier))
)
if name in retval:
retval[name] = ",".join((retval[name], str(pr.specifier)))
else:
retval[pr.name] = str(pr.specifier)
retval.setdefault(pr.name, "*")
retval[name] = str(pr.specifier)
retval.setdefault(name, "*")
return retval
version = the_profile.conda_constraints(python)
assert version is not None
# loads the pyproject.toml file (easy)
pyproject = project_dir / "pyproject.toml"
if pyproject.exists():
......@@ -143,7 +133,7 @@ def pixi(
+ pyproject["project"].get("maintainers", [])
],
description=pyproject["project"]["description"],
license=pyproject["project"]["license"]["text"],
# license=pyproject["project"]["license"]["text"],
readme="README.md",
homepage=pyproject["project"]["urls"]["homepage"],
repository=pyproject["project"]["urls"]["repository"],
......@@ -159,7 +149,7 @@ def pixi(
config["dependencies"] = {"python": python + ".*"}
config["dependencies"].update(
_make_requirement_dict(
pyproject.get("project", {}).get("dependencies", []), version
pyproject.get("project", {}).get("dependencies", [])
)
)
......@@ -168,12 +158,12 @@ def pixi(
# setup standardized build procedure
config.setdefault("feature", {}).setdefault("build", {})["dependencies"] = (
_make_requirement_dict(
pyproject.get("build-system", {}).get("requires", []), version
pyproject.get("build-system", {}).get("requires", [])
)
)
# add pip so that the build works
config["feature"]["build"]["dependencies"].update(
_make_requirement_dict(["pip"], version)
_make_requirement_dict(["pip"])
)
config["feature"]["build"]["tasks"] = dict(
build="pip install --no-build-isolation --no-dependencies --editable ."
......@@ -189,15 +179,31 @@ def pixi(
):
config.setdefault("feature", {}).setdefault(feature, {})[
"dependencies"
] = _make_requirement_dict(deps, version)
] = _make_requirement_dict(deps)
if "pre-commit" in config["feature"][feature]["dependencies"]:
config["feature"][feature]["tasks"] = {
"qa": "pre-commit run --all-files"
"qa": "pre-commit run --all-files",
"qa-install": "pre-commit install",
}
# this feature can be separated from the rest
config.setdefault("environments", {})["qa"] = [feature]
cmds.append("To do quality-assurance, run: `pixi run qa`")
cmds.append(
"To install pre-commit hook, run: `pixi run qa-install`"
)
cmds.append("To run quality-assurance, run: `pixi run qa`")
# if ruff is part of pre-commit configuration, then also add that
# dependence to the qa stack
precommit_config = project_dir / ".pre-commit-config.yaml"
if (
precommit_config.exists()
and "ruff" in precommit_config.open().read()
and "ruff" not in config["feature"][feature]["dependencies"]
):
config["feature"][feature]["dependencies"]["ruff"] = "*"
config["feature"][feature]["tasks"]["ruff"] = "ruff check"
cmds.append("To run a simple ruff check, run: `pixi run ruff`")
if "sphinx" in config["feature"][feature]["dependencies"]:
config["feature"][feature]["tasks"] = {
......@@ -226,6 +232,7 @@ def pixi(
cmds.append("To do run test, run: `pixi run test`")
# backup previous installation plan, if one exists
output = project_dir / "pixi.toml"
if output.exists():
backup = output.parent / (output.name + "~")
shutil.copy(output, backup)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment