Repository: pypa/setuptools

Issue:
Editable install using setup.py breaks without legacy feature [BUG] 
### setuptools version

63.2.0

### Python version

Python 3.10

### OS

Ubuntu 22.04 LTS

### Additional environment information

_No response_

### Description

Running `pip install -e .`  in a repository with a `pyproject.toml` present, even if `pyproject.toml` is only used for tool configuration

```
[tool.black]
line-length=100
```

Results in the error
```
      Editable install will be performed using a meta path finder.

      Options like `package-data`, `include/exclude-package-data` or
      `packages.find.exclude/include` may have no effect.

      Traceback (most recent call last):
        File "/tmp/pip-build-env-fl8nfpvg/overlay/lib/python3.10/site-packages/setuptools/command/editable_wheel.py", line 138, in run
          self._create_wheel_file(bdist_wheel)
        File "/tmp/pip-build-env-fl8nfpvg/overlay/lib/python3.10/site-packages/setuptools/command/editable_wheel.py", line 287, in _create_wheel_file
          strategy(wheel_obj, files, mapping)
        File "/tmp/pip-build-env-fl8nfpvg/overlay/lib/python3.10/site-packages/setuptools/command/editable_wheel.py", line 441, in __call__
          namespaces_: Dict[str, List[str]] = dict(chain(
        File "/tmp/pip-build-env-fl8nfpvg/overlay/lib/python3.10/site-packages/setuptools/command/editable_wheel.py", line 604, in _find_namespaces
          for pkg in packages:
      TypeError: 'NoneType' object is not iterable
      error: Support for editable installs via PEP 660 was recently introduced
      in `setuptools`. If you are seeing this error, please report to:

      https://github.com/pypa/setuptools/issues

      Meanwhile you can try the legacy behavior by setting an
      environment variable and trying to install again:

      SETUPTOOLS_ENABLE_FEATURES="legacy-editable"
```

exporting SETUPTOOLS_ENABLE_FEATURES="legacy-editable" does behave as expected, as does removing the `pyproject.toml` file.

### Expected behavior

Expected install to ignore `pyproject.toml` without any build configuration.

### How to Reproduce

No specific steps to reproduce, since a similar package installs successfully with the same `setuptools` version.

The command failing is
`pip install -e .`

### Output

```console
Building editable for my-package (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Building editable for my-package (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [52 lines of output]
      running editable_wheel
      creating /tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package.egg-info
      writing /tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package.egg-info/PKG-INFO
      writing dependency_links to /tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package.egg-info/dependency_links.txt
      writing requirements to /tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package.egg-info/requires.txt
      writing top-level names to /tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package.egg-info/top_level.txt
      writing manifest file '/tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package.egg-info/SOURCES.txt'
      file my.py (for module my) not found
      reading manifest file '/tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package.egg-info/SOURCES.txt'
      writing manifest file '/tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package.egg-info/SOURCES.txt'
      creating '/tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package-0.23.1.dist-info'
      creating /tmp/pip-wheel-6iyrnxzp/tmpi0w89_xq/my_package-0.23.1.dist-info/WHEEL
      /tmp/pip-build-env-m2f24vth/overlay/lib/python3.10/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
        warnings.warn(
      running build
      running build_py
      running egg_info
      creating /tmp/tmpyhvg_rsh.build-temp/my_package.egg-info
      writing /tmp/tmpyhvg_rsh.build-temp/my_package.egg-info/PKG-INFO
      writing dependency_links to /tmp/tmpyhvg_rsh.build-temp/my_package.egg-info/dependency_links.txt
      writing requirements to /tmp/tmpyhvg_rsh.build-temp/my_package.egg-info/requires.txt
      writing top-level names to /tmp/tmpyhvg_rsh.build-temp/my_package.egg-info/top_level.txt
      writing manifest file '/tmp/tmpyhvg_rsh.build-temp/my_package.egg-info/SOURCES.txt'
      file my.py (for module my) not found
      reading manifest file '/tmp/tmpyhvg_rsh.build-temp/my_package.egg-info/SOURCES.txt'
      writing manifest file '/tmp/tmpyhvg_rsh.build-temp/my_package.egg-info/SOURCES.txt'
      file my.py (for module my) not found
      file my.py (for module my) not found
      Editable install will be performed using a meta path finder.

      Options like `package-data`, `include/exclude-package-data` or
      `packages.find.exclude/include` may have no effect.

      Traceback (most recent call last):
        File "/tmp/pip-build-env-m2f24vth/overlay/lib/python3.10/site-packages/setuptools/command/editable_wheel.py", line 138, in run
          self._create_wheel_file(bdist_wheel)
        File "/tmp/pip-build-env-m2f24vth/overlay/lib/python3.10/site-packages/setuptools/command/editable_wheel.py", line 287, in _create_wheel_file
          strategy(wheel_obj, files, mapping)
        File "/tmp/pip-build-env-m2f24vth/overlay/lib/python3.10/site-packages/setuptools/command/editable_wheel.py", line 441, in __call__
          namespaces_: Dict[str, List[str]] = dict(chain(
        File "/tmp/pip-build-env-m2f24vth/overlay/lib/python3.10/site-packages/setuptools/command/editable_wheel.py", line 604, in _find_namespaces
          for pkg in packages:
      TypeError: 'NoneType' object is not iterable
      error: Support for editable installs via PEP 660 was recently introduced
      in `setuptools`. If you are seeing this error, please report to:

      https://github.com/pypa/setuptools/issues

      Meanwhile you can try the legacy behavior by setting an
      environment variable and trying to install again:

      SETUPTOOLS_ENABLE_FEATURES="legacy-editable"
      [end of output]

```



Discussion:
Reported in #3498. Same issue in #3500.
@vogre Does your package make use of `pbr`?
@synchronizing -- no, not using `pbr`, also version lower than `64.0.0` (so no pakcage_dir in trace)
Thank you very much for the report @vogre, I will investigate this issue and get back to you as soon as possible.

I also believe that the issue described here may be similar to #3500. Do you think they are separated problems?
Hi @vogre, it seems that somehow, your build is indeed using v64 (the editable install was not present in v63.2.0).

`pip` has been reported to have a virtual environment leak on Ubuntu and Debian in the past (I believe it was fixed in recent versions). Maybe your machine also has the same leak.

Could you share some form of reproducer (for example, containing a 
 simplified `setup.py`/`setup.cfg`)?



Resolving patch:
diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py
--- a/setuptools/command/editable_wheel.py
+++ b/setuptools/command/editable_wheel.py
@@ -439,7 +439,7 @@ def __call__(self, wheel: "WheelFile", files: List[str], mapping: Dict[str, str]
         roots = _find_package_roots(top_level, package_dir, src_root)
 
         namespaces_: Dict[str, List[str]] = dict(chain(
-            _find_namespaces(self.dist.packages, roots),
+            _find_namespaces(self.dist.packages or [], roots),
             ((ns, []) for ns in _find_virtual_namespaces(roots)),
         ))
 


Test patch:
diff --git a/setuptools/tests/test_editable_install.py b/setuptools/tests/test_editable_install.py
--- a/setuptools/tests/test_editable_install.py
+++ b/setuptools/tests/test_editable_install.py
@@ -163,6 +163,35 @@ def test_editable_with_flat_layout(tmp_path, venv, editable_opts):
     assert subprocess.check_output(cmd).strip() == b"4 2"
 
 
+def test_editable_with_single_module(tmp_path, venv, editable_opts):
+    files = {
+        "mypkg": {
+            "pyproject.toml": dedent("""\
+                [build-system]
+                requires = ["setuptools", "wheel"]
+                build-backend = "setuptools.build_meta"
+
+                [project]
+                name = "mod"
+                version = "3.14159"
+
+                [tool.setuptools]
+                py-modules = ["mod"]
+                """),
+            "mod.py": "b = 2",
+        },
+    }
+    jaraco.path.build(files, prefix=tmp_path)
+    project = tmp_path / "mypkg"
+
+    cmd = [venv.exe(), "-m", "pip", "install",
+           "--no-build-isolation",  # required to force current version of setuptools
+           "-e", str(project), *editable_opts]
+    print(str(subprocess.check_output(cmd), "utf-8"))
+    cmd = [venv.exe(), "-c", "import mod; print(mod.b)"]
+    assert subprocess.check_output(cmd).strip() == b"2"
+
+
 class TestLegacyNamespaces:
     """Ported from test_develop"""