Repository: pypa/setuptools

Issue:
[BUG] Entry points are missing when supplied as a string.
### setuptools version

setuptools==60.9.0

### Python version

3.8.12

### OS

Debian

### Additional environment information

_No response_

### Description

When installing a Python package which uses `setuptools` and has at least one `entry_point` directly from Git the `entry_point` script is not created with `setuptools==60.9.0`.

I have verified that this does work with `setuptools=60.8.2` but not `60.9.0`.

### Expected behavior

The expected `entry_point` script `tap-postgres` is present in `venv/bin/`.

### How to Reproduce

```
python -m venv venv
source venv/bin/activate
pip install git+https://github.com/thread/pipelinewise-tap-postgres.git@ee9bedb4711bb27c9660892f56c8fb27f3770d2a
```

### Output

```console

```

[BUG] Entry points are missing when supplied as a string.
### setuptools version

setuptools==60.9.0

### Python version

3.8.12

### OS

Debian

### Additional environment information

_No response_

### Description

When installing a Python package which uses `setuptools` and has at least one `entry_point` directly from Git the `entry_point` script is not created with `setuptools==60.9.0`.

I have verified that this does work with `setuptools=60.8.2` but not `60.9.0`.

### Expected behavior

The expected `entry_point` script `tap-postgres` is present in `venv/bin/`.

### How to Reproduce

```
python -m venv venv
source venv/bin/activate
pip install git+https://github.com/thread/pipelinewise-tap-postgres.git@ee9bedb4711bb27c9660892f56c8fb27f3770d2a
```

### Output

```console

```



Discussion:
I encountered something similar. My project used `setup.py`, but had a `pyproject.toml` for black config. Either removing `pyproject.toml` or running `pip install --no-use-pep517 -e .` worked for me. I suspect it's something packaging related.
It seems likely that the changes to how entry points are processed in Setuptools 60.9 have broken some assumption that wasn't captured by the tests. More investigation is needed.
I have a clue as to what's going on. The thread/pipelinewise-tap-postgres project defines entry points as a string, and when I was debugging, I found that `importlib_metadata.EntryPoints._from_text()` doesn't return an `EntryPoints` instance as I'd expected, but instead returns an iterable... and when passed through [`validate()`](https://github.com/pypa/setuptools/blob/abbaacc62aa26c611d68b935363765af702c0861/setuptools/_entry_points.py#L35-L40), the iterable will have been consumed, resulting in no entry points.

```
>>> entry_points='''
...           [console_scripts]
...           tap-postgres=tap_postgres:main
...       '''
>>> from importlib import metadata
>>> metadata.EntryPoints._from_text(entry_points)
<itertools.starmap object at 0x10e54c040>
>>> list(metadata.EntryPoints._from_text(entry_points))
[EntryPoint(name='tap-postgres', value='tap_postgres:main', group='console_scripts')]
>>> import setuptools._entry_points
>>> setuptools._entry_points.load(entry_points)
<itertools.starmap object at 0x10ed60e20>
>>> list(_)
[]
```
I encountered something similar. My project used `setup.py`, but had a `pyproject.toml` for black config. Either removing `pyproject.toml` or running `pip install --no-use-pep517 -e .` worked for me. I suspect it's something packaging related.
It seems likely that the changes to how entry points are processed in Setuptools 60.9 have broken some assumption that wasn't captured by the tests. More investigation is needed.
I have a clue as to what's going on. The thread/pipelinewise-tap-postgres project defines entry points as a string, and when I was debugging, I found that `importlib_metadata.EntryPoints._from_text()` doesn't return an `EntryPoints` instance as I'd expected, but instead returns an iterable... and when passed through [`validate()`](https://github.com/pypa/setuptools/blob/abbaacc62aa26c611d68b935363765af702c0861/setuptools/_entry_points.py#L35-L40), the iterable will have been consumed, resulting in no entry points.

```
>>> entry_points='''
...           [console_scripts]
...           tap-postgres=tap_postgres:main
...       '''
>>> from importlib import metadata
>>> metadata.EntryPoints._from_text(entry_points)
<itertools.starmap object at 0x10e54c040>
>>> list(metadata.EntryPoints._from_text(entry_points))
[EntryPoint(name='tap-postgres', value='tap_postgres:main', group='console_scripts')]
>>> import setuptools._entry_points
>>> setuptools._entry_points.load(entry_points)
<itertools.starmap object at 0x10ed60e20>
>>> list(_)
[]
```

Resolving patch:
diff --git a/setuptools/_entry_points.py b/setuptools/_entry_points.py
--- a/setuptools/_entry_points.py
+++ b/setuptools/_entry_points.py
@@ -53,7 +53,16 @@ def load(eps):
 
 @load.register(str)
 def _(eps):
-    return validate(metadata.EntryPoints._from_text(eps))
+    r"""
+    >>> ep, = load('[console_scripts]\nfoo=bar')
+    >>> ep.group
+    'console_scripts'
+    >>> ep.name
+    'foo'
+    >>> ep.value
+    'bar'
+    """
+    return validate(metadata.EntryPoints(metadata.EntryPoints._from_text(eps)))
 
 
 load.register(type(None), lambda x: x)


Test patch: