From ed7fbb4c3f6a2dcefda8e3c5b769b78c3b5114a1 Mon Sep 17 00:00:00 2001 From: Hadrien Mary Date: Thu, 7 Nov 2024 14:12:59 -0500 Subject: [PATCH 1/8] parse requirements.run in python test section --- src/recipe/parser/test.rs | 42 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/recipe/parser/test.rs b/src/recipe/parser/test.rs index f3f73cbc0..fff72e016 100644 --- a/src/recipe/parser/test.rs +++ b/src/recipe/parser/test.rs @@ -78,6 +78,14 @@ fn is_true(value: &bool) -> bool { *value } +/// The extra requirements for the test +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +pub struct PythonTestRequirements { + /// Extra run requirements for the test. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub run: Vec, +} + /// A special Python test that checks if the imports are available and runs `pip check`. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct PythonTest { @@ -86,6 +94,12 @@ pub struct PythonTest { /// Whether to run `pip check` or not (default to true) #[serde(default = "pip_check_true", skip_serializing_if = "is_true")] pub pip_check: bool, + /// The (extra) requirements for the test. + /// Similar to the `requirements` section in the recipe the `run` requirements are of the + /// target_platform architecture. The current package is implicitly added to the + /// `run` requirements. + #[serde(default, skip_serializing_if = "PythonTestRequirements::is_empty")] + pub requirements: PythonTestRequirements, } impl Default for PythonTest { @@ -93,10 +107,18 @@ impl Default for PythonTest { Self { imports: Vec::new(), pip_check: true, + requirements: PythonTestRequirements::default(), } } } +impl PythonTestRequirements { + /// Check if the requirements are empty + pub fn is_empty(&self) -> bool { + self.run.is_empty() + } +} + /// A test that runs the tests of a downstream package. #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] pub struct DownstreamTest { @@ -206,7 +228,6 @@ impl TryConvertNode for RenderedMappingNode { self.iter().map(|(key, value)| { let key_str = key.as_str(); - match key_str { "python" => { let python = as_mapping(value, key_str)?.try_convert(key_str)?; @@ -244,8 +265,9 @@ impl TryConvertNode for RenderedMappingNode { impl TryConvertNode for RenderedMappingNode { fn try_convert(&self, _name: &str) -> Result> { let mut python_test = PythonTest::default(); + println!("{:?}", python_test); - validate_keys!(python_test, self.iter(), imports, pip_check); + validate_keys!(python_test, self.iter(), imports, pip_check, requirements); if python_test.imports.is_empty() { Err(vec![_partialerror!( @@ -259,6 +281,22 @@ impl TryConvertNode for RenderedMappingNode { } } +impl TryConvertNode for RenderedNode { + fn try_convert(&self, name: &str) -> Result> { + self.as_mapping() + .ok_or_else(|| vec![_partialerror!(*self.span(), ErrorKind::ExpectedMapping,)]) + .and_then(|m| m.try_convert(name)) + } +} + +impl TryConvertNode for RenderedMappingNode { + fn try_convert(&self, _name: &str) -> Result> { + let mut requirements = PythonTestRequirements::default(); + validate_keys!(requirements, self.iter(), run); + Ok(requirements) + } +} + /////////////////////////// /// Downstream Test /// /////////////////////////// From 2b61f813b498c97bf54fd579515df9747741af65 Mon Sep 17 00:00:00 2001 From: Hadrien Mary Date: Thu, 7 Nov 2024 14:32:35 -0500 Subject: [PATCH 2/8] install run deps during python test + add tests --- src/package_test/run_test.rs | 10 ++++ ...e__parser__test__test__python_parsing.snap | 12 +++++ src/recipe/parser/test.rs | 46 ++++++++++++++++++- 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap diff --git a/src/package_test/run_test.rs b/src/package_test/run_test.rs index e509b9276..9ec33282b 100644 --- a/src/package_test/run_test.rs +++ b/src/package_test/run_test.rs @@ -461,6 +461,8 @@ impl PythonTest { prefix: &Path, config: &TestConfiguration, ) -> Result<(), TestError> { + let deps = self.requirements.clone(); + let span = tracing::info_span!("Running python test"); let _guard = span.enter(); @@ -473,6 +475,14 @@ impl PythonTest { dependencies.push(MatchSpec::from_str("pip", ParseStrictness::Strict).unwrap()); } + let mut run_dependencies = deps + .run + .iter() + .map(|s| MatchSpec::from_str(s, ParseStrictness::Lenient)) + .collect::, _>>()?; + + dependencies.append(&mut run_dependencies); + create_environment( "test", &dependencies, diff --git a/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap b/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap new file mode 100644 index 000000000..8b6705676 --- /dev/null +++ b/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap @@ -0,0 +1,12 @@ +--- +source: src/recipe/parser/test.rs +assertion_line: 489 +expression: yaml_serde +snapshot_kind: text +--- +- python: + imports: + - pandas + requirements: + run: + - pandas diff --git a/src/recipe/parser/test.rs b/src/recipe/parser/test.rs index fff72e016..417f5a580 100644 --- a/src/recipe/parser/test.rs +++ b/src/recipe/parser/test.rs @@ -410,7 +410,10 @@ mod test { use super::TestType; use insta::assert_snapshot; - use crate::recipe::custom_yaml::{RenderedNode, TryConvertNode}; + use crate::recipe::{ + custom_yaml::{RenderedNode, TryConvertNode}, + parser::test::PythonTestRequirements, + }; #[test] fn test_parsing() { @@ -462,4 +465,45 @@ mod test { let yaml_serde = serde_yaml::to_string(&tests).unwrap(); assert_snapshot!(yaml_serde); } + + #[test] + fn test_python_parsing() { + let test_section = r#" + tests: + - python: + imports: + - pandas + requirements: + run: + - pandas + "#; + + // parse the YAML + let yaml_root = RenderedNode::parse_yaml(0, test_section) + .map_err(|err| vec![err]) + .unwrap(); + let tests_node = yaml_root.as_mapping().unwrap().get("tests").unwrap(); + let tests: Vec = tests_node.try_convert("tests").unwrap(); + + let yaml_serde = serde_yaml::to_string(&tests).unwrap(); + assert_snapshot!(yaml_serde); + + // from yaml + let tests: Vec = serde_yaml::from_str(&yaml_serde).unwrap(); + let t = tests.first(); + + match t { + Some(TestType::Python { python }) => { + assert_eq!(python.imports, vec!["pandas"]); + assert!(python.pip_check); + assert_eq!( + python.requirements, + PythonTestRequirements { + run: vec!["pandas".to_string()] + } + ); + } + _ => panic!("expected python test"), + } + } } From 2a3f0d5319a7cb8afe1305e81ea39184b123fcf3 Mon Sep 17 00:00:00 2001 From: Hadrien Mary Date: Thu, 7 Nov 2024 16:23:08 -0500 Subject: [PATCH 3/8] leftover --- src/recipe/parser/test.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/recipe/parser/test.rs b/src/recipe/parser/test.rs index 417f5a580..c7b8e5da2 100644 --- a/src/recipe/parser/test.rs +++ b/src/recipe/parser/test.rs @@ -265,7 +265,6 @@ impl TryConvertNode for RenderedMappingNode { impl TryConvertNode for RenderedMappingNode { fn try_convert(&self, _name: &str) -> Result> { let mut python_test = PythonTest::default(); - println!("{:?}", python_test); validate_keys!(python_test, self.iter(), imports, pip_check, requirements); From bf336cc098d4dfc1b841b4c1d6d50d3ef7d4399a Mon Sep 17 00:00:00 2001 From: Hadrien Mary Date: Wed, 13 Nov 2024 13:43:11 -0500 Subject: [PATCH 4/8] switch to python_version for PythonTest --- docs/tutorials/javascript.md | 2 +- scripts/activate.sh | 1 - src/package_test/run_test.rs | 77 ++++++++++--- src/recipe/parser.rs | 2 +- ...e__parser__test__test__python_parsing.snap | 10 +- src/recipe/parser/test.rs | 107 +++++++++++------- test-data/recipes/pin_subpackage/recipe.yaml | 2 +- 7 files changed, 139 insertions(+), 62 deletions(-) diff --git a/docs/tutorials/javascript.md b/docs/tutorials/javascript.md index efb3033b0..06681ef89 100644 --- a/docs/tutorials/javascript.md +++ b/docs/tutorials/javascript.md @@ -45,4 +45,4 @@ requirements: tests: - script: - bibtex-tidy --version -``` \ No newline at end of file +``` diff --git a/scripts/activate.sh b/scripts/activate.sh index 048567de1..10a8dd80e 100644 --- a/scripts/activate.sh +++ b/scripts/activate.sh @@ -9,4 +9,3 @@ export CARGO_TARGET_X86_64_APPLE_DARWIN_RUSTFLAGS="-C link-arg=-Wl,-rpath,$CONDA export CARGO_TARGET_AARCH64_APPLE_DARWIN_RUSTFLAGS="-C link-arg=-Wl,-rpath,$CONDA_PREFIX/lib" export RATTLER_BUILD_PATH="$PIXI_PROJECT_ROOT/target-pixi/release/rattler-build" - diff --git a/src/package_test/run_test.rs b/src/package_test/run_test.rs index 9ec33282b..b0805f674 100644 --- a/src/package_test/run_test.rs +++ b/src/package_test/run_test.rs @@ -33,7 +33,9 @@ use url::Url; use crate::{ env_vars, metadata::PlatformWithVirtualPackages, - recipe::parser::{CommandsTest, DownstreamTest, PythonTest, Script, ScriptContent, TestType}, + recipe::parser::{ + CommandsTest, DownstreamTest, PythonTest, PythonVersion, Script, ScriptContent, TestType, + }, render::solver::create_environment, source::copy_dir::CopyDir, tool_configuration, @@ -461,27 +463,77 @@ impl PythonTest { prefix: &Path, config: &TestConfiguration, ) -> Result<(), TestError> { - let deps = self.requirements.clone(); - - let span = tracing::info_span!("Running python test"); + let span = tracing::info_span!("Running python test(s)"); let _guard = span.enter(); + // The version spec of the package being built let match_spec = MatchSpec::from_str( format!("{}={}={}", pkg.name, pkg.version, pkg.build_string).as_str(), ParseStrictness::Lenient, )?; - let mut dependencies = vec![match_spec]; + + // The dependencies for the test environment + // - python_version: null -> { "": ["mypackage=xx=xx"]} + // - python_version: 3.12 -> { "3.12": ["python=3.12", "mypackage=xx=xx"]} + // - python_version: [3.12, 3.13] -> { "3.12": ["python=3.12", "mypackage=xx=xx"], "3.13": ["python=3.13", "mypackage=xx=xx"]} + let mut dependencies_map: HashMap> = match &self.python_version { + PythonVersion::Multiple(versions) => versions + .iter() + .map(|version| { + ( + version.clone(), + vec![ + MatchSpec::from_str( + &format!("python={}", version), + ParseStrictness::Lenient, + ) + .unwrap(), + match_spec.clone(), + ], + ) + }) + .collect(), + PythonVersion::Single(version) => HashMap::from([( + version.clone(), + vec![ + MatchSpec::from_str(&format!("python={}", version), ParseStrictness::Lenient) + .unwrap(), + match_spec, + ], + )]), + PythonVersion::None => HashMap::from([("".to_string(), vec![match_spec])]), + }; + + // Add `pip` if pip_check is set to true if self.pip_check { - dependencies.push(MatchSpec::from_str("pip", ParseStrictness::Strict).unwrap()); + dependencies_map.iter_mut().for_each(|(_, v)| { + v.push(MatchSpec::from_str("pip", ParseStrictness::Strict).unwrap()) + }); } - let mut run_dependencies = deps - .run - .iter() - .map(|s| MatchSpec::from_str(s, ParseStrictness::Lenient)) - .collect::, _>>()?; + // Run tests for each python version + for (python_version, dependencies) in dependencies_map { + self.run_test_inner(python_version, dependencies, path, prefix, config) + .await?; + } - dependencies.append(&mut run_dependencies); + Ok(()) + } + + async fn run_test_inner( + &self, + python_version: String, + dependencies: Vec, + path: &Path, + prefix: &Path, + config: &TestConfiguration, + ) -> Result<(), TestError> { + let span_message = match python_version.as_str() { + "" => "Testing with default python version".to_string(), + _ => format!("Testing with python {}", python_version), + }; + let span = tracing::info_span!("", message = %span_message); + let _guard = span.enter(); create_environment( "test", @@ -536,7 +588,6 @@ impl PythonTest { console::style(console::Emoji("✔", "")).green() ); } - Ok(()) } } diff --git a/src/recipe/parser.rs b/src/recipe/parser.rs index 360cdc0af..c740b1bcc 100644 --- a/src/recipe/parser.rs +++ b/src/recipe/parser.rs @@ -49,7 +49,7 @@ pub use self::{ source::{GitRev, GitSource, GitUrl, PathSource, Source, UrlSource}, test::{ CommandsTest, CommandsTestFiles, CommandsTestRequirements, DownstreamTest, - PackageContentsTest, PythonTest, TestType, + PackageContentsTest, PythonTest, PythonVersion, TestType, }, }; diff --git a/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap b/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap index 8b6705676..120ec5157 100644 --- a/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap +++ b/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap @@ -1,12 +1,14 @@ --- source: src/recipe/parser/test.rs -assertion_line: 489 +assertion_line: 507 expression: yaml_serde snapshot_kind: text --- - python: imports: - pandas - requirements: - run: - - pandas + python_version: '3.10' +- python: + imports: + - pandas + python_version: 3.10, 3.12 diff --git a/src/recipe/parser/test.rs b/src/recipe/parser/test.rs index c7b8e5da2..002f1ac15 100644 --- a/src/recipe/parser/test.rs +++ b/src/recipe/parser/test.rs @@ -78,12 +78,17 @@ fn is_true(value: &bool) -> bool { *value } -/// The extra requirements for the test -#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] -pub struct PythonTestRequirements { - /// Extra run requirements for the test. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub run: Vec, +/// The Python version(s) to test the imports against. +#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum PythonVersion { + /// A single python version + Single(String), + /// Multiple python versions + Multiple(Vec), + /// No python version specified + #[default] + None, } /// A special Python test that checks if the imports are available and runs `pip check`. @@ -94,12 +99,9 @@ pub struct PythonTest { /// Whether to run `pip check` or not (default to true) #[serde(default = "pip_check_true", skip_serializing_if = "is_true")] pub pip_check: bool, - /// The (extra) requirements for the test. - /// Similar to the `requirements` section in the recipe the `run` requirements are of the - /// target_platform architecture. The current package is implicitly added to the - /// `run` requirements. - #[serde(default, skip_serializing_if = "PythonTestRequirements::is_empty")] - pub requirements: PythonTestRequirements, + /// Python version(s) to test against. If default no python version is specified. + #[serde(default)] + pub python_version: PythonVersion, } impl Default for PythonTest { @@ -107,18 +109,11 @@ impl Default for PythonTest { Self { imports: Vec::new(), pip_check: true, - requirements: PythonTestRequirements::default(), + python_version: PythonVersion::None, } } } -impl PythonTestRequirements { - /// Check if the requirements are empty - pub fn is_empty(&self) -> bool { - self.run.is_empty() - } -} - /// A test that runs the tests of a downstream package. #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] pub struct DownstreamTest { @@ -266,7 +261,7 @@ impl TryConvertNode for RenderedMappingNode { fn try_convert(&self, _name: &str) -> Result> { let mut python_test = PythonTest::default(); - validate_keys!(python_test, self.iter(), imports, pip_check, requirements); + validate_keys!(python_test, self.iter(), imports, pip_check, python_version); if python_test.imports.is_empty() { Err(vec![_partialerror!( @@ -280,19 +275,35 @@ impl TryConvertNode for RenderedMappingNode { } } -impl TryConvertNode for RenderedNode { - fn try_convert(&self, name: &str) -> Result> { - self.as_mapping() - .ok_or_else(|| vec![_partialerror!(*self.span(), ErrorKind::ExpectedMapping,)]) - .and_then(|m| m.try_convert(name)) - } -} +impl TryConvertNode for RenderedNode { + fn try_convert(&self, _name: &str) -> Result> { + let python_version = match self { + RenderedNode::Mapping(_) => Err(vec![_partialerror!( + *self.span(), + ErrorKind::InvalidField("expected string, sequence or null".into()), + )])?, + RenderedNode::Scalar(version) => PythonVersion::Single(version.to_string()), + RenderedNode::Sequence(versions) => { + versions + .iter() + // .map(|v| v.map(|s| s.to_string())) + .map(|v| { + v.as_scalar() + .ok_or_else(|| { + vec![_partialerror!( + *self.span(), + ErrorKind::InvalidField("invalid value".into()), + )] + }) + .map(|s| s.to_string()) + }) + .collect::, _>>() + .map(PythonVersion::Multiple)? + } + RenderedNode::Null(_) => PythonVersion::None, + }; -impl TryConvertNode for RenderedMappingNode { - fn try_convert(&self, _name: &str) -> Result> { - let mut requirements = PythonTestRequirements::default(); - validate_keys!(requirements, self.iter(), run); - Ok(requirements) + Ok(python_version) } } @@ -411,7 +422,7 @@ mod test { use crate::recipe::{ custom_yaml::{RenderedNode, TryConvertNode}, - parser::test::PythonTestRequirements, + parser::test::PythonVersion, }; #[test] @@ -472,9 +483,11 @@ mod test { - python: imports: - pandas - requirements: - run: - - pandas + python_version: 3.10 + - python: + imports: + - pandas + python_version: 3.10, 3.12 "#; // parse the YAML @@ -496,10 +509,22 @@ mod test { assert_eq!(python.imports, vec!["pandas"]); assert!(python.pip_check); assert_eq!( - python.requirements, - PythonTestRequirements { - run: vec!["pandas".to_string()] - } + python.python_version, + PythonVersion::Single("3.10".to_string()) + ); + } + _ => panic!("expected python test"), + } + + let t2 = tests.get(1); + + match t2 { + Some(TestType::Python { python }) => { + assert_eq!(python.imports, vec!["pandas"]); + assert!(python.pip_check); + assert_eq!( + python.python_version, + PythonVersion::Multiple(vec!["3.10".to_string(), "3.12".to_string()]) ); } _ => panic!("expected python test"), diff --git a/test-data/recipes/pin_subpackage/recipe.yaml b/test-data/recipes/pin_subpackage/recipe.yaml index c6acfa6ba..88dd941ba 100644 --- a/test-data/recipes/pin_subpackage/recipe.yaml +++ b/test-data/recipes/pin_subpackage/recipe.yaml @@ -20,4 +20,4 @@ outputs: noarch: generic requirements: run: - - ${{ pin_subpackage(name, exact=true) }} \ No newline at end of file + - ${{ pin_subpackage(name, exact=true) }} From 8ca79a0b8047b15e1b13aa066174f0049819b631 Mon Sep 17 00:00:00 2001 From: Hadrien Mary Date: Wed, 13 Nov 2024 13:45:51 -0500 Subject: [PATCH 5/8] typo --- src/recipe/parser/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/recipe/parser/test.rs b/src/recipe/parser/test.rs index 002f1ac15..3f87115eb 100644 --- a/src/recipe/parser/test.rs +++ b/src/recipe/parser/test.rs @@ -99,7 +99,7 @@ pub struct PythonTest { /// Whether to run `pip check` or not (default to true) #[serde(default = "pip_check_true", skip_serializing_if = "is_true")] pub pip_check: bool, - /// Python version(s) to test against. If default no python version is specified. + /// Python version(s) to test against. If not specified, the default python version is used. #[serde(default)] pub python_version: PythonVersion, } From 619dd03a88ac4f8510f72066f766c80b4539627d Mon Sep 17 00:00:00 2001 From: Hadrien Mary Date: Wed, 13 Nov 2024 13:46:48 -0500 Subject: [PATCH 6/8] cleanup --- src/recipe/parser/test.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/recipe/parser/test.rs b/src/recipe/parser/test.rs index 3f87115eb..aae8b0507 100644 --- a/src/recipe/parser/test.rs +++ b/src/recipe/parser/test.rs @@ -286,7 +286,6 @@ impl TryConvertNode for RenderedNode { RenderedNode::Sequence(versions) => { versions .iter() - // .map(|v| v.map(|s| s.to_string())) .map(|v| { v.as_scalar() .ok_or_else(|| { From c8c0c3e28e1e2ac7f49021d29fcebfc7463a218f Mon Sep 17 00:00:00 2001 From: Hadrien Mary Date: Wed, 13 Nov 2024 13:57:37 -0500 Subject: [PATCH 7/8] fix tests --- ...e__parser__test__test__python_parsing.snap | 6 ++- src/recipe/parser/test.rs | 41 +++++++++++-------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap b/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap index 120ec5157..a1261746f 100644 --- a/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap +++ b/src/recipe/parser/snapshots/rattler_build__recipe__parser__test__test__python_parsing.snap @@ -1,6 +1,6 @@ --- source: src/recipe/parser/test.rs -assertion_line: 507 +assertion_line: 505 expression: yaml_serde snapshot_kind: text --- @@ -11,4 +11,6 @@ snapshot_kind: text - python: imports: - pandas - python_version: 3.10, 3.12 + python_version: + - '3.10' + - '3.12' diff --git a/src/recipe/parser/test.rs b/src/recipe/parser/test.rs index aae8b0507..f19e894d6 100644 --- a/src/recipe/parser/test.rs +++ b/src/recipe/parser/test.rs @@ -91,6 +91,13 @@ pub enum PythonVersion { None, } +impl PythonVersion { + /// Check if the python version is none + pub fn is_none(&self) -> bool { + matches!(self, PythonVersion::None) + } +} + /// A special Python test that checks if the imports are available and runs `pip check`. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct PythonTest { @@ -100,7 +107,7 @@ pub struct PythonTest { #[serde(default = "pip_check_true", skip_serializing_if = "is_true")] pub pip_check: bool, /// Python version(s) to test against. If not specified, the default python version is used. - #[serde(default)] + #[serde(default, skip_serializing_if = "PythonVersion::is_none")] pub python_version: PythonVersion, } @@ -283,22 +290,20 @@ impl TryConvertNode for RenderedNode { ErrorKind::InvalidField("expected string, sequence or null".into()), )])?, RenderedNode::Scalar(version) => PythonVersion::Single(version.to_string()), - RenderedNode::Sequence(versions) => { - versions - .iter() - .map(|v| { - v.as_scalar() - .ok_or_else(|| { - vec![_partialerror!( - *self.span(), - ErrorKind::InvalidField("invalid value".into()), - )] - }) - .map(|s| s.to_string()) - }) - .collect::, _>>() - .map(PythonVersion::Multiple)? - } + RenderedNode::Sequence(versions) => versions + .iter() + .map(|v| { + v.as_scalar() + .ok_or_else(|| { + vec![_partialerror!( + *self.span(), + ErrorKind::InvalidField("invalid value".into()), + )] + }) + .map(|s| s.to_string()) + }) + .collect::, _>>() + .map(PythonVersion::Multiple)?, RenderedNode::Null(_) => PythonVersion::None, }; @@ -486,7 +491,7 @@ mod test { - python: imports: - pandas - python_version: 3.10, 3.12 + python_version: [3.10, 3.12] "#; // parse the YAML From c42161c41bbd19822ad7751fd383df40f440e540 Mon Sep 17 00:00:00 2001 From: Hadrien Mary Date: Wed, 13 Nov 2024 14:04:40 -0500 Subject: [PATCH 8/8] versions should be string --- src/recipe/parser/test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/recipe/parser/test.rs b/src/recipe/parser/test.rs index f19e894d6..4f940ceea 100644 --- a/src/recipe/parser/test.rs +++ b/src/recipe/parser/test.rs @@ -487,11 +487,11 @@ mod test { - python: imports: - pandas - python_version: 3.10 + python_version: "3.10" - python: imports: - pandas - python_version: [3.10, 3.12] + python_version: ["3.10", "3.12"] "#; // parse the YAML