Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
__pycache__/
.venv/
# Locking the editable test fixtures can create these in their source directories.
*.egg-info/
# The setup-ruby GitHub Action creates this directory when caching is enabled, so we ignore
# it here so it does not show up in the output of `git ls-files` for `make lint-scripts`.
vendor/bundle/
Expand Down
9 changes: 9 additions & 0 deletions bin/compile
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,15 @@ EOT
# As such, we have to perform two rewrites:
# 1. At build time, of just the VCS editable paths (which we can safely change to /app paths early).
# 2. At runtime, to rewrite the remaining path-based editable dependency paths.
#
# TODO: Also rewrite the paths in the hook modules that some less common build backends create instead
# (imported by an `import` line in a `.pth` file), since otherwise those editable installs break at runtime:
# - `_editable_impl_<name>.py` (`editables`, used by hatchling's `dev-mode-exact` mode and pdm-backend's
# `editables` mode)
# - `_editable_skbc_<name>.py` (scikit-build-core)
# - `_<name>_editable_loader.py` (meson-python, which rebuilds from the build directory on import, so
# can't work regardless)
# The hatchling case is covered (and currently expected to fail) by the pip editable test fixture.
if [[ "${BUILD_DIR}" != "/app" ]]; then
find .heroku/python/lib/python*/site-packages/ -type f -and \( -name '*.egg-link' -or -name '*.pth' -or -name '__editable___*_finder.py' \) -exec sed -i -e "s#${BUILD_DIR}/.heroku/python#/app/.heroku/python#" {} \+
cat <<-EOT >>"${PROFILE_PATH}"
Expand Down
2 changes: 0 additions & 2 deletions spec/fixtures/pip_compiled/requirements.txt

This file was deleted.

18 changes: 0 additions & 18 deletions spec/fixtures/pip_editable/bin/test-entrypoints.sh

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

5 changes: 0 additions & 5 deletions spec/fixtures/pip_editable/requirements.txt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ BUILD_DIR="${1}"

cd "${BUILD_DIR}"

exec bin/test-entrypoints.sh
exec bin/test-editable-installs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

set -euo pipefail

exec bin/test-entrypoints.sh
exec bin/test-editable-installs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash

set -euo pipefail

# Print any path like strings in the files created by build backends for editable installs,
# so we can check that the buildpack rewrote the paths correctly for build vs runtime.
(
cd .heroku/python/lib/python*/site-packages/
shopt -s nullglob
grep --extended-regexp --only-matching --with-filename -- '/\S+' *.pth *editable*.py | LC_ALL=C sort
)
echo

echo -n "Running project entrypoint: "
project-entrypoint

echo -n "Running setuptools flat package entrypoint: "
setuptools-flat

echo -n "Running hatchling default package entrypoint: "
hatchling-default

# TODO: Remove the fallback once bin/compile also rewrites the paths in hatchling's `dev-mode-exact`
# hook module, which is currently left pointing at the build directory (so fails at runtime).
echo -n "Running hatchling exact package entrypoint: "
hatchling-exact 2>/dev/null || echo "FAILED"

echo -n "Running import of VCS package: "
python -c 'import extension; print("OK")'
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[project]
name = "hatchling-default"
version = "0.0.0"

[project.scripts]
hatchling-default = "hatchling_default:main"

# Hatchling's default editable mode results in a static `_editable_impl_*.pth` file (containing
# the path to `src/`), unlike its `dev-mode-exact` mode used by `packages/hatchling_exact`.
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def main() -> None:
print("OK")
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[project]
name = "hatchling-exact"
version = "0.0.0"

[project.scripts]
hatchling-exact = "hatchling_exact:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
# This mode uses the `editables` package, which (unlike hatchling's default mode) creates an
# `_editable_impl_*.py` hook module containing absolute paths, rather than a static `.pth` file.
# TODO: The buildpack doesn't rewrite the paths in this module yet, so it breaks at runtime.
dev-mode-exact = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def main() -> None:
print("OK")
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This tests a legacy package that has only a `setup.py` and no `pyproject.toml`, using a flat layout
# (the package directory is next to this file, rather than under `src/`). Setuptools installs flat
# layouts in editable mode using an `__editable___*_finder.py` file (containing absolute paths)
# instead of the static `.pth` file that the `src` layout of the root project results in.

from setuptools import setup

setup(
name="setuptools-flat",
version="0.0.0",
packages=["setuptools_flat"],
entry_points={"console_scripts": ["setuptools-flat = setuptools_flat:main"]},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def main() -> None:
print("OK")
13 changes: 13 additions & 0 deletions spec/fixtures/pip_editable_git_compiled/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[project]
name = "pip-editable-git-compiled"
version = "0.0.0"
requires-python = ">=3.14"

[project.scripts]
project-entrypoint = "pip_editable_git_compiled:main"

# The src layout results in a static `.pth` file (containing the path to `src/`), unlike the flat
# layout of `packages/setuptools_flat` which results in an `__editable___*_finder.py` file.
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
32 changes: 32 additions & 0 deletions spec/fixtures/pip_editable_git_compiled/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This uses setuptools with a src directory layout, which results in a static `.pth` file.
--editable .

# The local packages below have to be nested under `packages/`, since `PYTHONPATH` includes the app
# root and so a same-named directory there would shadow the editable install:
# https://github.com/pypa/setuptools/issues/3535

# This uses setuptools with a flat layout, which results in an `__editable___*_finder.py` file.
# It also only has a `setup.py` and no `pyproject.toml`, like legacy packages.
--editable ./packages/setuptools_flat

# This uses hatchling (the next most popular build backend after setuptools) in its default editable
# mode, which results in a static `_editable_impl_*.pth` file.
--editable ./packages/hatchling_default

# This uses hatchling in its `dev-mode-exact` editable mode, which uses the `editables` library and
# results in an `_editable_impl_*.py` hook module containing absolute paths.
# TODO: The buildpack doesn't rewrite the paths in that module yet, so it breaks at runtime.
--editable ./packages/hatchling_exact

# We use a VCS dependency installed in editable mode in order to test that:
# - Git from the stack image can be found (ie: the system PATH has been correctly propagated to pip).
# - The editable mode repository clone is saved into the correct location.
#
# A C-based package is used instead of a pure Python package, in order to test that the
# Python headers can be found when compiling.
#
# It uses setuptools with a flat source layout, which results in an `__editable___*_finder.py` file.
#
# It's pinned to the commit SHA of the `0.45.1` tag (rather than the tag itself), so that on cached builds
# pip can tell the existing clone is already up-to-date, instead of fetching from the remote again.
--editable git+https://github.com/pypa/wheel.git@7855525de4093257e7bfb434877265e227356566#egg=extension.dist&subdirectory=tests/testdata/extension.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def main() -> None:
print("OK")
10 changes: 0 additions & 10 deletions spec/fixtures/pipenv_editable/Pipfile

This file was deleted.

45 changes: 0 additions & 45 deletions spec/fixtures/pipenv_editable/Pipfile.lock

This file was deleted.

21 changes: 0 additions & 21 deletions spec/fixtures/pipenv_editable/bin/test-entrypoints.sh

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

2 changes: 0 additions & 2 deletions spec/fixtures/pipenv_editable/pipenv_editable/__init__.py

This file was deleted.

11 changes: 0 additions & 11 deletions spec/fixtures/pipenv_editable/pyproject.toml

This file was deleted.

17 changes: 17 additions & 0 deletions spec/fixtures/pipenv_editable_git_compiled/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
# This uses setuptools with a src directory layout, which results in a static `.pth` file.
pipenv-editable-git-compiled = { file = ".", editable = true }
# We use a VCS dependency installed in editable mode in order to test that:
# - Git from the stack image can be found (ie: the system PATH has been correctly propagated to Pipenv).
# - The editable mode repository clone is saved into the correct location.
#
# A C-based package is used instead of a pure Python package, in order to test that the
# Python headers can be found when compiling.
#
# It uses setuptools with a flat source layout, which results in a `__editable___*_finder.py` file.
extension-dist = { git = "git+https://github.com/pypa/wheel.git", ref = "0.45.1", subdirectory = "tests/testdata/extension.dist", editable = true }
29 changes: 29 additions & 0 deletions spec/fixtures/pipenv_editable_git_compiled/Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading