pypa / hatch

Modern, extensible Python project management
https://hatch.pypa.io/latest/
MIT License
5.92k stars 294 forks source link

Unable to install from `sdist` using force-include with `hatchling>=1.19` #1305

Open hguturu opened 6 months ago

hguturu commented 6 months ago

Following up on #1130 since I don't know if its being tracked due to being closed.

I think this issue of being unable to install from sdist with force-includes for hatchling>=1.19. Either the toml needs to be configures to install from sdist or install from repo, but is currently unable to do both.

I created a test repo https://github.com/hguturu/hatching_test/ to reproduce.

The workaround highlighted in #1130 fixes the dist problem, but then we are not able to directly install from the repo using pip install ..

My understanding of why this happening due to the change in hatchling>=1.19 to not silently fail if force include is missing. https://github.com/pypa/hatch/issues/1130#issuecomment-1854394920

pip install . -> directly builds the wheel from the source repo, and thus the force include is valid and requires [tool.hatch.build.targets.wheel.force-include].

But, if wheel is build from the sdist release that already has the force include completed, then [tool.hatch.build.targets.wheel.force-include] triggers an error since it can't find the files to "force include". You made a comment earlier that you let it silently fail, I wonder if it is indeed due to this. A wheel can be build either from source repo or from sdist. The force-includes may no longer be valid if they are defined w.r.t. the source repo if building a wheel from an sdist.
RitikShah commented 6 months ago

Just ran into this as well.

ofek commented 6 months ago

What would you recommend as a fix?

hguturu commented 6 months ago

I think the best way to solve this is to validate that the force-include files exist at their mapped location in the sdist rather than in the source location.

E.g. you have the following force-include

[tool.hatch.build.targets.sdist.force-include]
"lib/fonts/FooSans" = "src/footest/FooSans"
"lib/stylelib" = "src/footest/stylelib"

for the below repo:

.
├── README.md
├── lib
│   ├── fonts
│   │   └── FooSans
│   │       └── foo.otf
│   └── stylelib
│       └── foo.mplstyle
├── pyproject.toml
├── src
│   └── footest
│       ├── __init__.py
│       └── __pycache__
│           └── __init__.cpython-310.pyc
└── tox.ini

When building a wheel or sdist it makes sense to validate that lib/fonts/FooSans and lib/stylelib exist. But it doesn't make sense to validate that they exist when building from an sdist since the sdist is "post force inclusion" and would look like:

.
├── PKG-INFO
├── README.md
├── pyproject.toml
├── src
│   └── footest
│       ├── FooSans
│       │   └── foo.otf
│       ├── __init__.py
│       └── stylelib
│           └── foo.mplstyle
└── tox.ini

Where the moves have already happened. Thus any validation should look for src/footest/FooSans and src/footest/stylelib.

Now, if there is no way to determine if you are building from an sdist or from the source repo, then I think another validation would be to check if all the files exist at the source (heuristic for source repo) or if all the files exist at their mapped location (heuristic for sdist).

Alternatively, don't apply the force-inclusion when building the sdist and mirror the full path.