Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add the project itself as an editable dependency #1084

Merged
merged 23 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
cb6633b
Add the project itself as an editable dependency
olivier-lacroix Mar 29, 2024
5da2522
fix: some cleanup
tdejager Mar 29, 2024
e609029
Create intermediary pyproject reference
olivier-lacroix Mar 30, 2024
a02e995
Fix flask example
olivier-lacroix Mar 30, 2024
d2c688e
lint
olivier-lacroix Mar 30, 2024
e8e3766
Add doc
olivier-lacroix Mar 30, 2024
9884c7e
Make editable installation of the project itself explicit
olivier-lacroix Mar 31, 2024
1684f88
Get name from the pyproject.toml [project] table
olivier-lacroix Mar 31, 2024
99b19f5
Align example
olivier-lacroix Mar 31, 2024
b55e98b
Revert "Make editable installation of the project itself explicit"
olivier-lacroix Apr 2, 2024
c47f26d
Merge remote-tracking branch 'upstream/main' into selfeditable
olivier-lacroix Apr 2, 2024
4d0e482
Merge branch 'main' into selfeditable
tdejager Apr 2, 2024
633cc65
Revert "Revert "Make editable installation of the project itself expl…
olivier-lacroix Apr 2, 2024
35595fe
Inform about the addition of the package itself as an editable install
olivier-lacroix Apr 2, 2024
7bc4d83
Merge branch 'main' into selfeditable
olivier-lacroix Apr 2, 2024
22ffc49
Add a test testing proper self-install
olivier-lacroix Apr 2, 2024
1876661
Add more details about the build-system section
olivier-lacroix Apr 3, 2024
6c6aeb4
Add *.egg-info to the .gitignore
olivier-lacroix Apr 3, 2024
207763d
lint
olivier-lacroix Apr 3, 2024
7e0a424
Merge branch 'main' into selfeditable
olivier-lacroix Apr 3, 2024
2758c6d
fix: used `pixi.toml` instead of `pyproject.toml`
tdejager Apr 3, 2024
d0d72b6
Add platforms for CI/CD tests
olivier-lacroix Apr 3, 2024
12a0d58
Merge branch 'main' into selfeditable
olivier-lacroix Apr 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions docs/advanced/pyproject_toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ platforms = ["linux-64", "osx-arm64", "osx-64", "win-64"]
```
This is the minimum requirement for pixi to understand and parse the project.

If you use `pixi init` in a folder that has a `pyproject.toml` file, pixi will automatically add the `[tool.pixi.project]` section to the file.
And will also add some defaults to the `.gitignore` and `.gitattributes` file.
However, it is recommended you use `pixi init` in a folder that has a `pyproject.toml` file. Pixi will automatically

- Add the above `[tool.pixi.project]` section to the file, auto-detecting your current platform;
- Add the current project as an editable pypi dependency;
- Add some defaults to the `.gitignore` and `.gitattributes` file.

## Python dependency
The `pyproject.toml` file supports the `requires_python` field.
Expand Down Expand Up @@ -144,11 +147,19 @@ test = ["test"]
```

## Build-system section
The `pyproject.toml` file normally contains a `[build-system]` section.
Currently, pixi does not use this section, but it is recommended to keep it in the file for compatibility with other tools.
The `pyproject.toml` file normally contains a `[build-system]` section. Pixi will use this section to build and install the project if it is added as a pypi path dependency.

If the `pyproject.toml` file does not contain any `[build-system]` section, pixi will fall back to [uv](https://github.com/astral-sh/uv)'s default, which is equivalent to the below:

```toml title="pyproject.toml"
[build-system]
requires = ["setuptools >= 40.8.0"]
build-backend = "setuptools.build_meta:__legacy__"
```
Including a `[build-system]` section is **highly recommended**. If you are not sure of the [build-backend](https://packaging.python.org/en/latest/tutorials/packaging-projects/#choosing-build-backend) you want to use, including the `[build-system]` section below in your `pyproject.toml` is a good starting point

```toml title="pyproject.toml"
[build-system]
requires = ["setuptools", "wheel"]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
```
1 change: 1 addition & 0 deletions examples/flask-hello-world-pyproject/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.egg-info
tdejager marked this conversation as resolved.
Show resolved Hide resolved
782 changes: 762 additions & 20 deletions examples/flask-hello-world-pyproject/pixi.lock

Large diffs are not rendered by default.

16 changes: 11 additions & 5 deletions examples/flask-hello-world-pyproject/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@
name = "flask-hello-world-pyproject"
version = "0.1.0"
description = "Example how to get started with flask in a pixi environment."
license = "MIT OR Apache-2.0"
homepage = "https://github.com/prefix/pixi"
readme = "README.md"
requires-python = ">=3.11"
dependencies = ["flask==2.*"]
dependencies = ["flask==2.*", "pytest"]

[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[tool.pixi.project]
name = "flask-hello-world-pyproject"
channels = ["conda-forge"]
platforms = ["linux-64"]
platforms = ["linux-64", "osx-arm64", "osx-64", "win-64"]

[tool.pixi.pypi-dependencies]
flask-hello-world-pyproject = { path = ".", editable = true }

[tool.pixi.tasks]
start = "python -m flask run --port=5050"
start = "python -m flask --app flask_hello_world_pyproject.app:app run --port=5050"
olivier-lacroix marked this conversation as resolved.
Show resolved Hide resolved
test = "pytest -v tests/*"
6 changes: 6 additions & 0 deletions examples/flask-hello-world-pyproject/tests/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import flask_hello_world_pyproject # noqa: F401


def test_import():
"""Simple test to validate the package itself has been installed."""
assert True
22 changes: 21 additions & 1 deletion src/cli/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use clap::Parser;
use indexmap::IndexMap;
use miette::IntoDiagnostic;
use minijinja::{context, Environment};
use pyproject_toml::PyProjectToml;
use rattler_conda_types::Platform;
use std::io::{Error, ErrorKind, Write};
use std::path::Path;
Expand Down Expand Up @@ -58,10 +59,14 @@ name = "{{ name }}"
channels = [{%- if channels %}"{{ channels|join("\", \"") }}"{%- endif %}]
platforms = ["{{ platforms|join("\", \"") }}"]

[tool.pixi.pypi-dependencies]
{{ name }} = { path = ".", editable = true }

"#;

const GITIGNORE_TEMPLATE: &str = r#"# pixi environments
.pixi
*.egg-info

"#;

Expand Down Expand Up @@ -147,12 +152,20 @@ pub async fn execute(args: Args) -> miette::Result<()> {
if pyproject_manifest_path.is_file() {
let file = fs::read_to_string(pyproject_manifest_path.clone()).unwrap();
if !file.contains("[tool.pixi.project]") {
// Get name from the pyproject [project] table
let name = match PyProjectToml::new(file.as_str()) {
Ok(pyproject) => pyproject
.project
.map(|p| p.name)
.expect("'name' should be defined in the [project] table"),
Err(e) => miette::bail!("Failed to parse 'pyproject.toml'. Error is {}", e),
};
let rv = env
.render_named_str(
consts::PYPROJECT_MANIFEST,
PYROJECT_TEMPLATE,
context! {
default_name,
name,
channels,
platforms
},
Expand All @@ -169,6 +182,13 @@ pub async fn execute(args: Args) -> miette::Result<()> {
pyproject_manifest_path.to_string_lossy(),
e
);
} else {
// Inform about the addition of the package itself as an editable dependency of the project
eprintln!(
"{}Added package '{}' as an editable dependency.",
console::style(console::Emoji("✔ ", "")).green(),
name
);
}
}

Expand Down
28 changes: 15 additions & 13 deletions src/project/manifest/pyproject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,31 @@ impl PyProjectManifest {

impl From<PyProjectManifest> for ProjectManifest {
fn from(item: PyProjectManifest) -> Self {
// Start by loading the data nested under "tool.pixi"
// Start by loading the data nested under "tool.pixi" as manifest,
// and create a reference to the 'pyproject.toml' project table
let mut manifest = item.tool.pixi.clone();
let pyproject = item
.project
.as_ref()
.expect("the [project] table should exist");

// TODO: tool.pixi.project.name should be made optional or read from project.name
// TODO: could copy across / convert some other optional fields if relevant

// Add python as dependency based on the project.requires_python property (if any)
let pythonspec = item
.project
.as_ref()
.and_then(|p| p.requires_python.as_ref())
.map(|v| VersionOrUrl::VersionSpecifier(v.clone()));
let pythonspec = pyproject
.requires_python
.clone()
.map(VersionOrUrl::VersionSpecifier);
let target = manifest.default_feature_mut().targets.default_mut();
target.add_dependency(
PackageName::from_str("python").unwrap(),
version_or_url_to_nameless_matchspec(&pythonspec).unwrap(),
SpecType::Run,
);

// add pyproject dependencies as pypi dependencies
if let Some(deps) = item
.project
.as_ref()
.and_then(|p| p.dependencies.as_ref())
.cloned()
{
// Add pyproject dependencies as pypi dependencies
if let Some(deps) = pyproject.dependencies.clone() {
for d in deps.into_iter() {
target.add_pypi_dependency(
PyPiPackageName::from_normalized(d.name.clone()),
Expand Down Expand Up @@ -115,6 +114,9 @@ mod tests {
};

const PYPROJECT_FULL: &str = r#"
[project]
name = "project"

[tool.pixi.project]
name = "project"
version = "0.1.0"
Expand Down
3 changes: 3 additions & 0 deletions tests/test_examples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ pixi run -v --manifest-path examples/pypi-source-deps/pixi.toml test
echo "Running the solve-groups example:"
pixi run -v --manifest-path examples/solve-groups/pixi.toml -e min-py38 test
pixi run -v --manifest-path examples/solve-groups/pixi.toml -e max-py310 test

echo "Running the flask-hello-world-pyproject example:"
pixi run -v --manifest-path examples/flask-hello-world-pyproject/pyproject.toml test
Loading