pypa/pip · error · InstallationError

does not appear to be a Python project: neither 'setup.py'…

Error message

{req_name} does not appear to be a Python project: neither 'setup.py' nor 'pyproject.toml' found.

What it means

Raised by load_pyproject_toml (pyproject.py:56) as InstallationError when neither a pyproject.toml nor a setup.py exists in the project directory pip was asked to build/install from. pip needs at least one of these to know how to build the project, so their absence means the target is not recognizable as a Python project.

Solutions

  1. Verify the directory actually contains the project's setup.py or pyproject.toml (ls the path).
  2. Point pip at the correct subdirectory: 'pip install ./path/to/real/package'.
  3. For monorepos use the subdirectory feature of your VCS URL or path.
  4. If the project legitimately lacks build config, add a minimal pyproject.toml with a build-backend.

Example fix

# before
pip install ./   # cwd has no setup.py/pyproject.toml
# after: point at the real package dir
pip install ./src/myproject
# or add minimal build config
# pyproject.toml:
# [build-system]
# requires = ["setuptools>=61"]
# build-backend = "setuptools.build_meta"
Defensive patterns

Strategy: validation

Validate before calling

import os, sys

def is_python_project_dir(path: str) -> bool:
    return os.path.isfile(os.path.join(path, 'setup.py')) or os.path.isfile(os.path.join(path, 'pyproject.toml'))

if __name__ == '__main__':
    target = sys.argv[1]
    if not is_python_project_dir(target):
        print(f'{target} has neither setup.py nor pyproject.toml'); sys.exit(1)

Type guard

import os

def is_python_project(path: str) -> bool:
    return (os.path.isdir(path)
            and (os.path.isfile(os.path.join(path, 'setup.py'))
                 or os.path.isfile(os.path.join(path, 'pyproject.toml'))))

Try / catch

from subprocess import run, CalledProcessError
try:
    run(["pip", "install", target], check=True)
except CalledProcessError:
    # Point at the correct subdirectory containing the build files.
    run(["pip", "install", correct_subdir], check=True)

Prevention

When it happens

Trigger: Installing/building from a path (local dir, sdist, or VCS checkout) that contains no pyproject.toml and no setup.py — e.g. pointing pip at a docs folder, an empty checkout, or the wrong subdirectory of a monorepo.

Common situations: Wrong path given to pip install; a Git submodule that wasn't initialized; a monorepo where the package lives in a subdirectory; a tarball missing its build files; a directory that is just data/notebooks.

Related errors


AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08). Data as JSON: /api/errors/6c6461d44a8ad040. Report an issue: GitHub.

Appendix: source

Thrown at src/pip/_internal/pyproject.py:57

        req_name - The name of the requirement we're processing (for
                   error reporting)

    Returns:
        None if we should use the legacy code path, otherwise a tuple
        (
            requirements from pyproject.toml,
            name of PEP 517 backend,
            requirements we should check are installed after setting
                up the build environment
            directory paths to import the backend from (backend-path),
                relative to the project root.
        )
    """
    has_pyproject = os.path.isfile(pyproject_toml)
    has_setup = os.path.isfile(setup_py)

    if not has_pyproject and not has_setup:
        raise InstallationError(
            f"{req_name} does not appear to be a Python project: "
            f"neither 'setup.py' nor 'pyproject.toml' found."
        )

    if has_pyproject:
        with open(pyproject_toml, encoding="utf-8") as f:
            pp_toml = tomllib.loads(f.read())
        build_system = pp_toml.get("build-system")
    else:
        build_system = None

    if build_system is None:
        # In the absence of any explicit backend specification, we
        # assume the setuptools backend that most closely emulates the
        # traditional direct setup.py execution, and require wheel and
        # a version of setuptools that supports that backend.

        build_system = {

View on GitHub (pinned to f399c37189)