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

Fix rye add and rye remove to create proper tool.rye section on --dev and --exclude flags #1256

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 36 additions & 4 deletions rye/src/pyproject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,13 @@ pub struct PyProject {
doc: DocumentMut,
}

/// Returns an implicit table.
fn implicit() -> Item {
let mut table = Table::new();
table.set_implicit(true);
Item::Table(table)
}

impl PyProject {
/// Load a pyproject toml if explicitly given, else discover from current directory
///
Expand Down Expand Up @@ -912,8 +919,14 @@ impl PyProject {
) -> Result<(), Error> {
let dependencies = match kind {
DependencyKind::Normal => &mut self.doc["project"]["dependencies"],
DependencyKind::Dev => &mut self.doc["tool"]["rye"]["dev-dependencies"],
DependencyKind::Excluded => &mut self.doc["tool"]["rye"]["excluded-dependencies"],
DependencyKind::Dev => self
.obtain_tool_config_table()?
.entry("dev-dependencies")
.or_insert(Item::Value(Value::Array(Array::new()))),
DependencyKind::Excluded => self
.obtain_tool_config_table()?
.entry("excluded-dependencies")
.or_insert(Item::Value(Value::Array(Array::new()))),
DependencyKind::Optional(ref section) => {
// add this as a proper non-inline table if it's missing
let table = &mut self.doc["project"]["optional-dependencies"];
Expand Down Expand Up @@ -943,8 +956,14 @@ impl PyProject {
) -> Result<Option<Requirement>, Error> {
let dependencies = match kind {
DependencyKind::Normal => &mut self.doc["project"]["dependencies"],
DependencyKind::Dev => &mut self.doc["tool"]["rye"]["dev-dependencies"],
DependencyKind::Excluded => &mut self.doc["tool"]["rye"]["excluded-dependencies"],
DependencyKind::Dev => self
.obtain_tool_config_table()?
.entry("dev-dependencies")
.or_insert(Item::Value(Value::Array(Array::new()))),
DependencyKind::Excluded => self
.obtain_tool_config_table()?
.entry("excluded-dependencies")
.or_insert(Item::Value(Value::Array(Array::new()))),
DependencyKind::Optional(ref section) => {
&mut self.doc["project"]["optional-dependencies"][section as &str]
}
Expand Down Expand Up @@ -1047,6 +1066,19 @@ impl PyProject {
fs::write(&path, self.doc.to_string()).path_context(&path, "unable to write changes")?;
Ok(())
}

/// Gets or creates the [tool.rye] table in pyproject.toml
fn obtain_tool_config_table(&mut self) -> Result<&mut Table, Error> {
self.doc
.entry("tool")
.or_insert(implicit())
.as_table_mut()
.ok_or(anyhow!("[tool.rye] in pyproject.toml is malformed"))?
.entry("rye")
.or_insert(implicit())
.as_table_mut()
.ok_or(anyhow!("[tool.rye] in pyproject.toml is malformed"))
}
}

pub fn normalize_package_name(x: &str) -> String {
Expand Down
74 changes: 67 additions & 7 deletions rye/tests/test_add.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use insta::assert_snapshot;
use std::fs;

use toml_edit::{value, ArrayOfTables, Table};

use crate::common::{rye_cmd_snapshot, Space};
Expand Down Expand Up @@ -39,6 +39,14 @@ fn test_add_flask() {
+ my-project==0.1.0 (from file:[TEMP_PATH]/project)
+ werkzeug==3.0.1
"###);

assert_snapshot!(space.read_toml("pyproject.toml")["project"]["dependencies"], @r###"
[
"flask>=3.0.0",
"colorama>=0.4.6",
]
"###
);
}

#[test]
Expand Down Expand Up @@ -76,12 +84,13 @@ fn test_add_flask_dotenv() {
+ werkzeug==3.0.1
"###);

space.load_toml("pyproject.toml", |doc| {
let deps = doc["project"]["dependencies"].as_array().unwrap();
assert!(deps
.iter()
.any(|x| x.as_str() == Some("flask[dotenv]>=3.0.0")));
});
assert_snapshot!(space.read_toml("pyproject.toml")["project"]["dependencies"], @r###"
[
"flask[dotenv]>=3.0.0",
"colorama>=0.4.6",
]
"###
);
}

#[test]
Expand Down Expand Up @@ -120,6 +129,13 @@ fn test_add_from_find_links() {
+ my-project==0.1.0 (from file:[TEMP_PATH]/project)
+ tqdm==4.66.1
"###);

assert_snapshot!(space.read_toml("pyproject.toml")["tool"]["rye"], @r###"
managed = true
dev-dependencies = []
sources = [{ name = "extra", type = "find-links", url = "https://download.pytorch.org/whl/torch_stable.html" }]
"###
);
}

#[test]
Expand Down Expand Up @@ -208,3 +224,47 @@ fn test_add_explicit_version_or_url() {
+ pip==1.3.1 (from https://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686)
"###);
}

#[test]
fn test_add_dev() {
let space = Space::new();
space.init("my-project");
// add colorama to ensure we have this as a dependency on all platforms
rye_cmd_snapshot!(space.rye_cmd().arg("add").arg("flask").arg("colorama").arg("--dev"), @r###"
success: true
exit_code: 0
----- stdout -----
Initializing new virtualenv in [TEMP_PATH]/project/.venv
Python version: cpython@3.12.3
Added flask>=3.0.0 as dev dependency
Added colorama>=0.4.6 as dev dependency
Reusing already existing virtualenv
Generating production lockfile: [TEMP_PATH]/project/requirements.lock
Generating dev lockfile: [TEMP_PATH]/project/requirements-dev.lock
Installing dependencies
Done!

----- stderr -----
Resolved 9 packages in [EXECUTION_TIME]
Prepared 9 packages in [EXECUTION_TIME]
Installed 9 packages in [EXECUTION_TIME]
+ blinker==1.7.0
+ click==8.1.7
+ colorama==0.4.6
+ flask==3.0.0
+ itsdangerous==2.1.2
+ jinja2==3.1.2
+ markupsafe==2.1.3
+ my-project==0.1.0 (from file:[TEMP_PATH]/project)
+ werkzeug==3.0.1
"###);

assert_snapshot!(space.read_toml("pyproject.toml")["tool"]["rye"], @r###"
managed = true
dev-dependencies = [
"flask>=3.0.0",
"colorama>=0.4.6",
]
"###
);
}