-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Package by default: Add in preview #17841
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -283,6 +283,7 @@ async fn init_script( | |
| async fn init_project( | ||
| path: &Path, | ||
| name: &PackageName, | ||
| // TODO(konsti): Remove when stabilizing. | ||
| package: bool, | ||
| project_kind: InitProjectKind, | ||
| bare: bool, | ||
|
|
@@ -725,33 +726,35 @@ pub(crate) enum InitKind { | |
| Script, | ||
| } | ||
|
|
||
| impl Default for InitKind { | ||
| fn default() -> Self { | ||
| Self::Project(InitProjectKind::default()) | ||
| } | ||
| } | ||
|
|
||
| /// The kind of Python project to initialize (either an application or a library). | ||
| #[derive(Debug, Copy, Clone, Default)] | ||
| pub(crate) enum InitProjectKind { | ||
| /// Initialize a Python application. | ||
| /// A python package with a `main` function in a `__init__.py` and a script entrypoint pointing | ||
| /// to that. | ||
| #[default] | ||
| ApplicationWithLibrary, | ||
| /// A flat application with a `main.py`. | ||
| Application, | ||
| /// Initialize a Python library. | ||
| /// A python package, no entrypoint. | ||
| Library, | ||
| } | ||
|
|
||
| impl InitKind { | ||
| /// Returns `true` if the project should be packaged by default. | ||
| pub(crate) fn packaged_by_default(self) -> bool { | ||
| matches!(self, Self::Project(InitProjectKind::Library)) | ||
| } | ||
| /// Initialize only a `pyproject.toml` | ||
| Bare, | ||
| /// Initialize only a `pyproject.toml` with `[build-system]` table (but without associated | ||
| /// source files). | ||
| BareWithBuildSystem, | ||
| // TODO(konsti): Remove when stabilizing. | ||
| /// Initialize a Python application. | ||
| ApplicationOld, | ||
| // TODO(konsti): Remove when stabilizing. | ||
| /// Initialize a Python library. | ||
| LibraryOld, | ||
| } | ||
|
|
||
| impl InitProjectKind { | ||
| /// Initialize this project kind at the target path. | ||
| // TODO(konsti): Remove when stabilizing packaged-init. | ||
| #[expect(clippy::fn_params_excessive_bools)] | ||
| fn init( | ||
| fn init_old( | ||
| self, | ||
| name: &PackageName, | ||
| path: &Path, | ||
|
|
@@ -766,7 +769,7 @@ impl InitProjectKind { | |
| package: bool, | ||
| ) -> Result<()> { | ||
| match self { | ||
| Self::Application => Self::init_application( | ||
| Self::ApplicationOld => Self::init_application_old( | ||
| name, | ||
| path, | ||
| requires_python, | ||
|
|
@@ -779,7 +782,7 @@ impl InitProjectKind { | |
| no_readme, | ||
| package, | ||
| ), | ||
| Self::Library => Self::init_library( | ||
| Self::LibraryOld => Self::init_library_old( | ||
| name, | ||
| path, | ||
| requires_python, | ||
|
|
@@ -792,12 +795,14 @@ impl InitProjectKind { | |
| no_readme, | ||
| package, | ||
| ), | ||
| _ => unreachable!(), | ||
| } | ||
| } | ||
|
|
||
| /// Initialize a Python application at the target path. | ||
| // TODO(konsti): Remove when stabilizing packaged-init. | ||
| #[expect(clippy::fn_params_excessive_bools)] | ||
| fn init_application( | ||
| fn init_application_old( | ||
| name: &PackageName, | ||
| path: &Path, | ||
| requires_python: &RequiresPython, | ||
|
|
@@ -816,7 +821,7 @@ impl InitProjectKind { | |
| // read conditional includes that depend on the repository path. | ||
| init_vcs(path, vcs)?; | ||
|
|
||
| // Do no fill in `authors` for non-packaged applications unless explicitly requested. | ||
| // Do not fill in `authors` for non-packaged applications unless explicitly requested. | ||
| let author_from = author_from.unwrap_or_else(|| { | ||
| if package { | ||
| AuthorFrom::default() | ||
|
|
@@ -879,8 +884,9 @@ impl InitProjectKind { | |
| } | ||
|
|
||
| /// Initialize a library project at the target path. | ||
| // TODO(konsti): Remove when stabilizing packaged-init. | ||
| #[expect(clippy::fn_params_excessive_bools)] | ||
| fn init_library( | ||
| fn init_library_old( | ||
| name: &PackageName, | ||
| path: &Path, | ||
| requires_python: &RequiresPython, | ||
|
|
@@ -930,6 +936,122 @@ impl InitProjectKind { | |
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Initialize this project kind at the target path. | ||
| #[expect(clippy::fn_params_excessive_bools)] | ||
| fn init( | ||
| self, | ||
| name: &PackageName, | ||
| path: &Path, | ||
| requires_python: &RequiresPython, | ||
| description: Option<&str>, | ||
| no_description: bool, | ||
| bare: bool, | ||
| vcs: Option<VersionControlSystem>, | ||
| build_backend: Option<ProjectBuildBackend>, | ||
| author_from: Option<AuthorFrom>, | ||
| no_readme: bool, | ||
| package: bool, | ||
| ) -> Result<()> { | ||
| // TODO(konsti): Remove when stabilizing. | ||
| if matches!(self, Self::ApplicationOld | Self::LibraryOld) { | ||
| return self.init_old( | ||
| name, | ||
| path, | ||
| requires_python, | ||
| description, | ||
| no_description, | ||
| bare, | ||
| vcs, | ||
| build_backend, | ||
| author_from, | ||
| no_readme, | ||
| package, | ||
| ); | ||
| } | ||
|
|
||
| fs_err::create_dir_all(path)?; | ||
|
|
||
| // Initialize the version control system first so that Git configuration can properly | ||
| // read conditional includes that depend on the repository path. | ||
| init_vcs(path, vcs)?; | ||
|
|
||
| // Do not fill in `authors` for non-packaged applications unless explicitly requested. | ||
| let author_from = author_from.unwrap_or_else(|| match self { | ||
| Self::ApplicationWithLibrary | Self::Library | Self::BareWithBuildSystem => { | ||
| AuthorFrom::default() | ||
| } | ||
| Self::Application | Self::Bare => AuthorFrom::None, | ||
| Self::ApplicationOld | Self::LibraryOld => unreachable!(), | ||
| }); | ||
| let author = get_author_info(path, author_from); | ||
|
|
||
| // Create the `pyproject.toml` | ||
| let mut pyproject = pyproject_project( | ||
| name, | ||
| requires_python, | ||
| author.as_ref(), | ||
| description, | ||
| no_description, | ||
| no_readme || bare, | ||
| ); | ||
|
|
||
| match self { | ||
| // Create only the most barebones `pyproject.toml`, no build system | ||
| Self::Bare => {} | ||
| // Create only a barebones `pyproject.toml`, but with a build system table | ||
| Self::BareWithBuildSystem => { | ||
| // Add a build system | ||
| let build_backend = build_backend.unwrap_or(ProjectBuildBackend::Uv); | ||
| pyproject.push('\n'); | ||
| pyproject.push_str(&pyproject_build_system(name, build_backend)); | ||
|
konstin marked this conversation as resolved.
|
||
| } | ||
| Self::ApplicationWithLibrary => { | ||
| // Since it'll be packaged, we can add a `[project.scripts]` entry | ||
| pyproject.push('\n'); | ||
| pyproject.push_str(&pyproject_project_scripts(name, name.as_str(), "main")); | ||
|
|
||
| // Add a build system | ||
| let build_backend = build_backend.unwrap_or(ProjectBuildBackend::Uv); | ||
| pyproject.push('\n'); | ||
| pyproject.push_str(&pyproject_build_system(name, build_backend)); | ||
| pyproject_build_backend_prerequisites(name, path, build_backend)?; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we don't call this in Edit: I now realize this is another thing you call out, so my opinion is that we shouldn't generate broken configuration if we can help it
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this mean we should error for
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think it's possible to generate something that's not broken? If not, then erroring out would be fine
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's two aspects here: Stable already allows It seems fine to not create a build system with |
||
|
|
||
| // Generate `src` files with app-style `main()` in `__init__.py` | ||
| generate_package_scripts(name, path, build_backend, false)?; | ||
| } | ||
| Self::Application => { | ||
| let main_contents = indoc::formatdoc! {r#" | ||
| def main(): | ||
| print("Hello from {name}!") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
| "#}; | ||
|
|
||
| // Create `main.py` if it doesn't exist | ||
| // (This isn't intended to be a particularly special or magical filename, just nice) | ||
| // TODO(zanieb): Only create `main.py` if there are no other Python files? | ||
| let main_py = path.join("main.py"); | ||
| if !main_py.try_exists()? && !bare { | ||
| fs_err::write(path.join("main.py"), main_contents)?; | ||
| } | ||
| } | ||
| Self::Library => { | ||
| let build_backend = build_backend.unwrap_or(ProjectBuildBackend::Uv); | ||
| pyproject.push('\n'); | ||
| pyproject.push_str(&pyproject_build_system(name, build_backend)); | ||
| pyproject_build_backend_prerequisites(name, path, build_backend)?; | ||
|
|
||
| // Generate `src` files | ||
| generate_package_scripts(name, path, build_backend, true)?; | ||
| } | ||
| _ => unreachable!(), | ||
| } | ||
| fs_err::write(path.join("pyproject.toml"), pyproject)?; | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| #[derive(Debug)] | ||
|
|
@@ -1151,7 +1273,6 @@ fn generate_package_scripts( | |
| let pkg_dir = src_dir.join(&*module_name); | ||
| fs_err::create_dir_all(&pkg_dir)?; | ||
|
|
||
| // Python script for pure-python packaged apps or libs | ||
| let pure_python_script = if is_lib { | ||
| indoc::formatdoc! {r#" | ||
| def hello() -> str: | ||
|
|
||
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.
nit: don't use Old/New, they quickly become confusing :) I'd go with
ApplicationWithPackageInitOffandLibraryWithPackageInitOffThere 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 should only be temporary, https://github.com/astral-sh/uv/pull/19197/changes removes the nomenclature entirely, the idea is more like
<style>ToBeRemovedand<style>ToBecomeTheDefault