pypa/pip · error · InstallationError

{req_name} does not appear to be a Python project: neither '

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() when pip is asked to build/install a source tree that contains neither a setup.py nor a pyproject.toml. pip requires at least one of these metadata files to identify the directory as a valid Python project and to determine the build backend. Without them, pip has no way to know how to build the package, so it aborts before attempting any build.

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 d7d0d0a394)

Solutions

  1. Verify the directory you passed actually contains pyproject.toml or setup.py: run `ls <dir>` and confirm one of those filenames is present.
  2. If the project uses a src/ layout, point pip at the directory that holds the metadata file, e.g. `pip install ./project-root` not `pip install ./project-root/src`.
  3. If you cloned into a subdirectory, `cd` to the directory containing pyproject.toml (or pass its absolute path) before running pip install.
  4. If installing from a tarball/zip, extract it fully first and install from the extracted top-level directory, not the archive's inner nested folder.

Example fix

# before
pip install ./src
# after (assuming pyproject.toml is in the repo root)
pip install .
Defensive patterns

Strategy: validation

Validate before calling

import os

def is_installable_project(directory: str) -> bool:
    return os.path.isfile(os.path.join(directory, "pyproject.toml")) or \
           os.path.isfile(os.path.join(directory, "setup.py"))

# before calling pip / load_pyproject_toml:
if not is_installable_project(target_dir):
    raise SystemExit(f"{target_dir} has no pyproject.toml or setup.py")

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Calling pip install on a directory path (e.g. `pip install ./some_dir`) where neither ./some_dir/setup.py nor ./some_dir/pyproject.toml exists. Also triggered when pip resolves an sdist that unpacks to a tree missing both files, or when a relative/wrong directory path is passed. The check is literally `os.path.isfile(pyproject_toml)` AND `os.path.isfile(setup_py)` both returning False at pyproject.py:56.

Common situations: Pointing pip at the wrong directory (parent of the project, a src/ layout root without metadata, a build artifact dir). Cloning a repo and running install from repo root when the package lives in a subdirectory. A CI checkout that excluded metadata files. A corrupted or incomplete sdist tarball.

Related errors


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