{"record":{"id":"8ea6b09fd2b67472","repo":"pypa/pip","slug":"directory-name-r-is-not-installable-neither-se","errorCode":null,"errorMessage":"Directory {name!r} is not installable. Neither 'setup.py' nor 'pyproject.toml' found.","messagePattern":"Directory (.+?) is not installable\\. Neither 'setup\\.py' nor 'pyproject\\.toml' found\\.","errorType":"validation","errorClass":"InstallationError","httpStatus":null,"severity":"error","filePath":"src/pip/_internal/req/constructors.py","lineNumber":315,"sourceCode":"        return True\n    return False\n\n\ndef _get_url_from_path(path: str, name: str) -> str | None:\n    \"\"\"\n    First, it checks whether a provided path is an installable directory. If it\n    is, returns the path.\n\n    If false, check if the path is an archive file (such as a .whl).\n    The function checks if the path is a file. If false, if the path has\n    an @, it will treat it as a PEP 440 URL requirement and return the path.\n    \"\"\"\n    if _looks_like_path(name) and os.path.isdir(path):\n        if is_installable_dir(path):\n            return path_to_url(path)\n        # TODO: The is_installable_dir test here might not be necessary\n        #       now that it is done in load_pyproject_toml too.\n        raise InstallationError(\n            f\"Directory {name!r} is not installable. Neither 'setup.py' \"\n            \"nor 'pyproject.toml' found.\"\n        )\n    if not is_archive_file(path):\n        return None\n    if os.path.isfile(path):\n        return path_to_url(path)\n    urlreq_parts = name.split(\"@\", 1)\n    if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]):\n        # If the path contains '@' and the part before it does not look\n        # like a path, try to treat it as a PEP 440 URL req instead.\n        return None\n    logger.warning(\n        \"Requirement %r looks like a filename, but the file does not exist\",\n        name,\n    )\n    return path_to_url(path)\n","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_internal/req/constructors.py#L297-L333","documentation":"pip was given a local directory path to install, but the directory does not contain either 'setup.py' or 'pyproject.toml'. The function _get_url_from_path() checks is_installable_dir() and, when it fails, reports that the directory is not a valid installable Python project.","triggerScenarios":"Running 'pip install ./some-dir/' where some-dir exists as a directory but has no setup.py or pyproject.toml. Also triggered when a requirements file points at a directory path that is a subfolder of the actual project root.","commonSituations":"Pointing at the wrong subdirectory in a monorepo (e.g. ./src instead of ./src/mypackage). Checking out only part of a repo. A directory that contains source code but was never set up as a package. CI running from the wrong working directory.","solutions":["Verify the target directory contains setup.py or pyproject.toml: 'ls ./some-dir/setup.py ./some-dir/pyproject.toml'","Navigate to or point at the correct project root directory that has the build files","Add a minimal pyproject.toml to the directory if it is meant to be installable","Check for typos in the path and ensure relative paths are resolved from the correct working directory"],"exampleFix":"# before\npip install ./src\n\n# after\npip install ./src/mypackage   # the dir that actually has pyproject.toml","handlingStrategy":"validation","validationCode":"import os\n\ndef is_installable(path: str) -> bool:\n    if not os.path.isdir(path):\n        return False\n    return os.path.exists(os.path.join(path, \"setup.py\")) or os.path.exists(\n        os.path.join(path, \"pyproject.toml\")\n    )\n\nif not is_installable(\"./some-dir\"):\n    print(\"Directory is not installable; add setup.py or pyproject.toml\")","typeGuard":"def is_installable_dir(path: str) -> bool:\n    \"\"\"Narrowing guard: True if path is a dir with setup.py or pyproject.toml.\"\"\"\n    import os\n    return (\n        os.path.isdir(path)\n        and (\n            os.path.isfile(os.path.join(path, \"setup.py\"))\n            or os.path.isfile(os.path.join(path, \"pyproject.toml\"))\n        )\n    )","tryCatchPattern":"from pip._internal.exceptions import InstallationError\nfrom pip._internal.utils.misc import is_installable_dir\n\nif not is_installable_dir(path):\n    raise SystemExit(f\"{path} is not an installable directory\")","preventionTips":["Always verify the target directory contains setup.py or pyproject.toml before running pip install","Use os.path checks in CI scripts before invoking pip install on a directory","In monorepos, use explicit subdirectory paths pointing at the package root"],"tags":["pip","directory","pyproject","setup-py","installation"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}