-
Notifications
You must be signed in to change notification settings - Fork 1.5k
uv init: Project layouts, defaults and terminology #8178
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
Comments
I think |
Thanks for your thoughts! I'll own responding to this and seeing what we can integrate. |
I've only ended up in this thread because I was confused about the default behaviour here - to me it feels like Feel free to ignore me though, I realise I'm a data point of one and maybe those do somehow make sense to other devs. |
I think both the options available and their documentation are somewhat confusing at present. There are multiple different decisions in determining how a project should be structured, but those decisions seem to be split between Often, I might want to create a standalone application, such as a Flask webapp. This doesn't need to expose a Python API or be imported into other projects, so I would assume I don't need a build system to turn my code into a package. I'll probably just write a Dockerfile that will produce a container image with my dependencies installed, ready to run my code directly. In terms of layout, I probably want a 'flat layout', where my code is in
None of these do what I want! No matter what I choose, I'll have to move things around and change This is addressed in #6460, which seems to be resolved by #6585, adding 'Virtual Projects', which don't get built or installed as packages. But the only place this is documented is under the setting that enables it, where I can read a brief summary of what a virtual project is, but not why I might want to use one. #6585 states that a project will be treated as 'virtual' merely by the lack of a A brief aside regarding 'virtual projects' and I love |
I agree. As someone migrating from Poetry to uv, uv's project layout options were a lot harder for me to understand. |
I can follow the logic for not wanting a "hello.py", but I can fully understand that an example (in the terms mentioned by the request) is a good thing for most of the people. I cannot support not creating the ".git" and ".gitignore" files. All amateurs (which I count myself) should have it, but many do not know about it. Nothing serious should be done without them. What we need is a revamp on the "layout" structure. Which is confusing. I had to test all the options to understant what is meant. With the "--layout" option is clear and does what people do. . |
Counterpoint: I can't imagine ever needing to start a python project without a I think that |
@clbarnes Not everyone is starting a new project, nor running uv where their .gitignore, .git repo or README lives - think mono-repos, projects where uv is inside docker, projects where you're in a git submodule etc. - in some of these cases, creating a .git repo is a positively hostile thing to do as you can suddenly end up with nested repositories being pushed and then someone (me) has to untangle it. |
Lots of insightful thoughts. I would also argue for project layout to be separated from rather the project is intended to be an application or a python package. In fact, it is not uncommon for python applications to also use a src layout. This is especially useful with containers as mounting all source code files is just a singular mount, or for standardized use in CI/CD. |
I second the idea of a more customized option for Additionally, it would be neat to be able to customize the starting Typically, I would systematically exclude |
Also, while I don't disagree with @clbarnes 's justification of |
People are looking for a less opinionated version of `uv init`. The goal here is to create a `pyproject.toml` and nothing else. With the `--lib` or `--package` flags, we'll still configure a build backend but we won't create the source tree. This disables things like the default `description`, author behavior, and VCS. See - #8178 - #7181 - #6750
Also coming here because I love the The Also, I was kind of expecting this choice of layout to be also reflected in the section for For me, this is the only thing making me hesitate to recommend |
What things did you not want? |
I'm a little confused by this, you want to run with your working directory as |
How about allowing users to provide their own configuration template in some uv config directory? Or even several templates one could choose with something like |
@hunter-gatherer8 please see #9754 |
Can someone take a little time to elaborate the reasoning behind "src" layout for non-Pythonistas 🙏 With "flat" layout:
we already have a folder-level isolation. It does look "nested" to a TypeScript-first version of me 😄 I get that the project can have multiple packages and those packages will, supposedly, have common files under Quoting the article, that everyone refers to:
I don't get this point. With Poetry I had to install my library package, and it definitely has the "flat" layout.
This point is more clear. But it's a "protection by convention", not the strongest argument. We can still accidentally put a non-public data or code in |
|
https://hynek.me/articles/testing-packaging/ and https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-structure have some discussion of the topic. |
Python was originally designed as a scripting language, more akin to bash or perl than Java. As such, it's pretty liberal about sweeping local directories for python code to import and execute. However, there are a few different ways of executing python code and that module discovery happens differently in different execution contexts. Some tools designed with that style in mind (e.g. testing utilities) also do things under the hood to make things "easier", which actually makes module discovery even more complicated. As python has been used for bigger, more complicated projects, this module discovery complexity has been found to add little utility and a lot of headaches. Isolating your code in a Python as a language has changed to support bigger, more complicated projects (e.g. Also it helps separate the actual module from general project-related cruft like CI configuration, scripts, infrastructure setup, docs etc.. |
Coming from using I personally would prefer the pretty simple/bareback approach of poetry's
and
This might be a simple case of personal preference and I totally (and welcome) uv's intent to being as user-friendly as possible but I personally think pruning back on the options and just giving options for the src/flat layout would suffice and more straightforward. I would also love to have the |
I am grateful that this conversation is happening here. As someone who recently needed to setup a Python project, I ran into the flat vs src decision myself. In the end, I decided that I would use the src layout as my default, as well as making the choice to use Having said that, I think simply discussing this matter in the uv documentation will go a long way to helping the community, especially people new to Python project layouts like me. Today, the uv documentation (https://docs.astral.sh/uv/concepts/projects/init/) discusses the difference between "Application", "Packaged Application", and "Library". This page could be a good place to discuss why the uv team chose Application as the default and what the implications are (e.g., perhaps referencing https://hynek.me/articles/testing-packaging/). This is akin to the practice of keeping architectural decision records (https://adr.github.io/). The goal is not to justify that the current decision to make Application the default is the right one--people will always debate such a decision. The goal is to give users context about how the decision was made at the time, which empowers users to better evaluate the alternatives given their own situations and future evolutions in the Python community. Thanks again for considering this topic. And many thanks to @MikeHart85 for his thoughtful and intelligent proposal. |
I think this is summarized in #3957 (comment) — we don't want this to be the default longterm. We intend to revisit this entire interface once our build backend is ready. |
Thank you for pointing this proposal! Proposalfollowing with @zanieb ideas and the philosophy of uv, for becoming the cargo of python (or npm/bunof python): What it goes in my mind, is that you can set a basic "PEP compliant version of project initialization" for
Also, you could use the proposal as a way to migrate from current out the box options out there in the python community, to a more uv compliant version of it. Benefits:
An example of this was the Possible Drawbacks
Basic StructureThe Easter Eggthe team could even create a dedicated package for using the |
uv is a great tool for managing virtual environments, even outside of packages, so I'm wondering: should there be a template for e.g.
Currently, |
Thank you for working on this wonderful tool.
I'd like to suggest several changes to
uv init
arguments and defaults, with the following goals:Much of this revolves around separating the concept of project directory structure ("layout" in Python) from project purpose and contents ("library", "application", etc), as well as disambiguating the overloaded term "package". Currently these terms are conflated and inconsistent in
uv
.Apologies in advance for the massive wall of text.
Current behavior
"Application" (default):
$ uv init [--app] project-name $ tree project-name/ project-name/ ├── hello.py ├── pyproject.toml # only [project] (builds don't work due to misnamed hello.py) └── README.md
"Library":
"Application Package":
Suggested behavior
Src layout (default):
Flat layout:
Single module layout:
Bare / no layout:
--no-entrypoint
to suppress[project.scripts]
--entrypoint=name
to customize key name under[project.scripts]
, defaulting toproject-name
--build-system=<hatchling|...|none>
, withhatchling
being default, andnone
to suppress[build-system]
--no-build-system
, synonymous with--build-system=none
, for symmetry--no-package
--typed
to create apy.typed
--package
--app
, or:--entrypoint=project-name
__main__.py
[1] instead ofexample.py
, but that may unnecessarily confuse newcomers--lib
, or:--no-entrypoint
--typed
(IMO explicituv init --lib --typed
would be better)I would just remove
--lib
and--app
to keep things simple.Reasoning for suggestions
uv run python
>>> import project_name
uv init
--app
, default) layout is the most limitedhello.py
project_name.py
allows builds to work--layout=none
for custom layouts, notebook projects, etcpy.typed
--package
conflates it with build-system/distribution, src layout, and absence ofpy.typed
__init__.py
[5]--layout=single
with build-system)six
, which is a single module library: PyPI GitHub__init__.py
should not contain general purpose code__init__.py
is a special purpose file, and putting arbitrary code there can easily have unintended side effects__all__
, etc [6]uv run project-name
anduv build
as shownuv init
needs to change, to support generating themContext
--app
and--lib
options touv init
#6689Discussion in the latter floated using "distribution" (ala PDM) instead of "package" (ala Poetry) in some contexts, but it seems "package" won out. I would argue "distribution" would have been the correct choice. As mentioned, "package" has a very specific meaning in Python, not strictly related to whether the project is built for distribution.
Thanks for considering.
The text was updated successfully, but these errors were encountered: