-
Notifications
You must be signed in to change notification settings - Fork 92
feat: add pyproject.toml support to generate-recipe command #1849
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
base: main
Are you sure you want to change the base?
Conversation
- Add new 'pyproject' subcommand to generate-recipe CLI - Integrate core functionality from pyrattler-recipe-autogen - Support dependency extraction from project.dependencies with version constraints - Add tool.conda.recipe.* configuration overrides for all recipe sections - Include schema version support with default schema header - Set default output to recipe/recipe.yaml directory structure - Convert Python version operators to conda format - Support entry points conversion from project.scripts This enables generating conda recipes directly from pyproject.toml files following the same patterns as pyrattler-recipe-autogen.
Add patterns to ignore test files generated during pyproject recipe development to prevent accidental commits of temporary test artifacts.
- Add 11 unit tests covering all core functionality - Test dependency conversion with version constraints and environment markers - Test schema version handling (default and custom) - Test YAML formatting with schema header - Test context, package, requirements, and about section generation - Test dynamic version resolution for different build backends - Test Python constraint formatting and package name mapping All tests pass and provide good coverage of the pyproject module functionality.
- test_generate_recipe_pyproject_basic: Tests basic pyproject.toml parsing and recipe generation - test_generate_recipe_pyproject_with_conda_overrides: Tests conda-specific overrides - Both tests verify schema header generation, dependency conversion, and build system integration - Fixed directory creation issue in test framework by explicitly creating temp directories
- Replace disallowed std::fs methods with fs_err - Fix wildcard pattern in match expression - Initialize structs directly instead of field reassignment - Remove unnecessary let binding before return - Move functions before test module to fix items-after-test-module - Change PathBuf parameter to Path reference - Remove duplicate if branches in JSON serialization All clippy warnings have been resolved and the code now passes lint checks.
…ated logic for stdout support
@wolfv would you or anyone else on the team mind reviewing and providing feedback? I believe this feature may be useful for those behind corporate networks that need to generate a recipe for their python project that may not be published anywhere. This option will allow them to create the recipe with their local pyproject.toml. Even if it doesn't get merged in it was a good learning experience. Thanks! |
I like the idea, will have to check out the code :) |
|
||
/// Convert Python dependency format to conda dependency format | ||
/// Following the same pattern as pyrattler-recipe-autogen | ||
fn convert_python_to_conda_dependency(dep: &str) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to re-use / share more code with the pypi
implementation?
} | ||
|
||
/// Apply common Python package name to conda package name mappings | ||
fn apply_package_name_mapping(dep: &str) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here - we would need the same code in pypi
, right?
Hey @millsks this is definitely functionality that we are interested in! I am wondering - currently it looks like not a lot of code is shared with the PyPI generator. Do you think you could change that? Ideally we'd only have one version of these functions / mappings. @zelosleone maybe you can also take a look? |
} | ||
|
||
/// Generate a recipe from a pyproject.toml file | ||
pub async fn generate_pyproject_recipe(opts: &PyprojectOpts) -> miette::Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need to be pub? it doesnt really being used anywhere besides the internal module via mod.rs anyways
fn assemble_recipe( | ||
toml_data: HashMap<String, Value>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need a function like this like wolf suggested you can use pypi code here, since you are already mapping the toml to json before, it shouldn't be a problem to actually use the pypi code to generate the recipe with correct datas. And the custom logic here with 400 lines could be like simplified to maybe just one call.
fn build_context_section( | ||
project: &serde_json::Map<String, Value>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also suffers the same fate as assemble_recipe
as pypi code should already handle the normalization with correct mapping
fn build_package_section( | ||
_project: &serde_json::Map<String, Value>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as functions before this, please use pypi code for these after the correct mapping via toml to json
fn build_source_section( | ||
project: &serde_json::Map<String, Value>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as functions before this, please use pypi code for these after the correct mapping via toml to json
// Default to PyPI source | ||
let package_name = name.to_lowercase().replace("-", "_"); | ||
let pypi_url = format!( | ||
"https://pypi.org/packages/source/{}/{}/{}-${{{{ version }}}}.tar.gz", | ||
&package_name[..1], | ||
package_name, | ||
package_name | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this defaulting could be also removed if we can just share code with pypi module.
} | ||
|
||
/// Build the build section | ||
fn build_build_section(toml_data: &HashMap<String, Value>) -> miette::Result<serialize::Build> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is also redudant and pypi code for this is better that you can use
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be more specific pypi uses the correct extraction methods with additional wheel analysis, you can get it from there
fn build_requirements_section( | ||
project: &serde_json::Map<String, Value>, | ||
toml_data: &HashMap<String, Value>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dont get why we are always extracting full toml data for specific sections of the build. you might want to map them correctly to pypi code via toml to json and just use the specific ones. but yeah this is also redudant and can be replaced with correct code sharing/calls to pypi module
Some problems that needs fixing:
|
Hi @wolfv and @zelosleone. Thanks for the feedback and suggestions. I'll start working on it this week. |
🎯 Summary
This PR adds native support for generating conda recipes from
pyproject.toml
files to therattler-build generate-recipe
command. This integrates the core functionality from pyrattler-recipe-autogen directly into rattler-build, eliminating the need for a separate tool.🚀 Features Added
New Command
Core Functionality
tool.conda.recipe.*
configuration sectionsproject.scripts
to conda recipe entry points📝 Example Usage
Input
pyproject.toml
:Generated
recipe.yaml
:🔧 Implementation Details
Files Added/Modified
src/recipe_generator/pyproject.rs
- Complete pyproject.toml parsing and recipe generation logicsrc/recipe_generator/serialize.rs
- Addedschema_version
field support to Recipe structsrc/recipe_generator/luarocks/mod.rs
- Integrated pyproject command into CLIrust-tests/src/lib.rs
- Added comprehensive integration testsKey Components
tool.conda.recipe.*
sections to customize any part of the recipe🧪 Testing
Unit Tests (11 tests - all passing)
test_convert_python_to_conda_dependency
- Package name conversion logictest_format_python_constraint
- Version constraint formattingtest_build_package_section
- Package metadata generationtest_build_requirements_section
- Dependencies and build requirementstest_build_about_section
- About section with conda overridestest_build_context_section
- Context variables handlingtest_build_context_section_dynamic_version
- Dynamic version resolutiontest_build_schema_version
- Schema version configurationtest_resolve_dynamic_version
- Dynamic version extraction from filestest_apply_package_name_mapping
- Python to conda package mappingtest_format_yaml_with_schema
- YAML output with schema headersIntegration Tests (2 tests - all passing)
test_generate_recipe_pyproject_basic
- End-to-end basic functionality testtest_generate_recipe_pyproject_with_conda_overrides
- Advanced conda overrides test🎁 Benefits
pyrattler-recipe-autogen
tool🔗 Related Issues
Closes #1848 - Generate a recipe.yaml from pyproject.toml using generate-recipe subcommand
📋 Checklist
🚦 Testing Instructions
pyproject.toml
file:📚 Additional Notes
luarocks
recipe generator🚀 Quick Demo
Want to test this feature quickly? Here's a complete example:
This will generate a complete conda recipe with:
click>=8.0.0
→click >=8.0.0
)tool.conda.recipe.*
sections