0
# Entry Points System
1
2
Comprehensive entry point discovery and management, including entry point objects, collections, and selection mechanisms for package-defined executable scripts and plugins. Entry points allow packages to advertise functionality that can be discovered and loaded at runtime.
3
4
## Capabilities
5
6
### EntryPoint Class
7
8
Individual entry point objects representing package-defined entry points:
9
10
```python { .api }
11
class EntryPoint:
12
"""
13
An entry point as defined by Python packaging conventions.
14
15
Entry points allow packages to advertise components for discovery by other packages.
16
Common uses include console scripts, plugin systems, and extensible applications.
17
"""
18
19
name: str # Entry point name
20
value: str # Entry point value specification (module:attribute)
21
group: str # Entry point group (e.g., 'console_scripts')
22
dist: Distribution | None # Associated distribution (optional)
23
24
def __init__(self, name: str, value: str, group: str) -> None:
25
"""
26
Create an entry point.
27
28
Parameters:
29
- name: Entry point name
30
- value: Entry point value (e.g., 'package.module:function')
31
- group: Entry point group (e.g., 'console_scripts')
32
"""
33
34
def load(self) -> Any:
35
"""
36
Load the entry point from its definition.
37
38
If only a module is indicated by the value, return that module.
39
Otherwise, return the named object.
40
41
Returns:
42
Any: The loaded object or module
43
"""
44
45
def matches(self, **params) -> bool:
46
"""
47
Check if EntryPoint matches the given parameters.
48
49
Parameters:
50
- **params: Parameters to match against (name, group, module, attr, extras)
51
52
Returns:
53
bool: True if all parameters match
54
55
Raises:
56
ValueError: If 'dist' parameter is provided (not suitable for matching)
57
"""
58
59
@property
60
def module(self) -> str:
61
"""Return the module name from the entry point value."""
62
63
@property
64
def attr(self) -> str:
65
"""Return the attribute name from the entry point value."""
66
67
@property
68
def extras(self) -> list[str]:
69
"""Return the list of extras from the entry point value."""
70
71
# Class attributes
72
pattern: re.Pattern[str] # Regular expression for parsing entry point values
73
74
# Internal methods
75
def _for(self, dist: Distribution) -> EntryPoint:
76
"""
77
Associate this entry point with a distribution.
78
79
Parameters:
80
- dist: Distribution to associate with
81
82
Returns:
83
EntryPoint: This entry point with distribution associated
84
"""
85
86
def _key(self) -> tuple[str, str, str]:
87
"""
88
Return comparison key for sorting and equality.
89
90
Returns:
91
tuple[str, str, str]: Tuple of (name, value, group)
92
"""
93
94
# Comparison and representation methods
95
def __lt__(self, other: EntryPoint) -> bool:
96
"""Less than comparison for sorting."""
97
98
def __eq__(self, other: object) -> bool:
99
"""Equality comparison."""
100
101
def __hash__(self) -> int:
102
"""Hash for use in sets and dictionaries."""
103
104
def __repr__(self) -> str:
105
"""String representation of entry point."""
106
107
def __setattr__(self, name: str, value: Any) -> None:
108
"""
109
Prevent attribute modification (EntryPoint objects are immutable).
110
111
Raises:
112
AttributeError: Always, as EntryPoint objects are immutable
113
"""
114
```
115
116
#### Usage Examples
117
118
```python
119
import importlib_metadata
120
121
# Get entry points and work with individual ones
122
eps = importlib_metadata.entry_points(group='console_scripts')
123
if eps:
124
ep = next(iter(eps))
125
print(f"Entry point: {ep.name}")
126
print(f"Module: {ep.module}")
127
print(f"Attribute: {ep.attr}")
128
print(f"Group: {ep.group}")
129
print(f"Extras: {ep.extras}")
130
131
# Load the actual object
132
try:
133
obj = ep.load()
134
print(f"Loaded: {obj}")
135
except ImportError as e:
136
print(f"Failed to load: {e}")
137
138
# Check if entry point matches criteria
139
pip_eps = importlib_metadata.entry_points(name='pip')
140
for ep in pip_eps:
141
if ep.matches(group='console_scripts'):
142
print(f"Found pip console script: {ep.value}")
143
```
144
145
### EntryPoints Collection
146
147
Immutable collection class for working with multiple entry points:
148
149
```python { .api }
150
class EntryPoints(tuple):
151
"""
152
An immutable collection of selectable EntryPoint objects.
153
154
Provides methods for filtering and accessing entry points by various criteria.
155
"""
156
157
def __getitem__(self, name: str) -> EntryPoint:
158
"""
159
Get the EntryPoint in self matching name.
160
161
Parameters:
162
- name: Entry point name to find
163
164
Returns:
165
EntryPoint: The matching entry point
166
167
Raises:
168
KeyError: If no entry point with the given name is found
169
"""
170
171
def select(self, **params) -> EntryPoints:
172
"""
173
Select entry points from self that match the given parameters.
174
175
Parameters:
176
- **params: Selection criteria (typically group and/or name)
177
178
Returns:
179
EntryPoints: New EntryPoints collection with matching entry points
180
"""
181
182
@property
183
def names(self) -> set[str]:
184
"""
185
Return the set of all names of all entry points.
186
187
Returns:
188
set[str]: Set of entry point names
189
"""
190
191
@property
192
def groups(self) -> set[str]:
193
"""
194
Return the set of all groups of all entry points.
195
196
Returns:
197
set[str]: Set of entry point groups
198
"""
199
200
# Class attributes
201
__slots__ = () # Memory optimization for tuple subclass
202
203
# Class methods for construction
204
@classmethod
205
def _from_text_for(cls, text: str | None, dist: Distribution) -> EntryPoints:
206
"""
207
Create EntryPoints from text with associated distribution.
208
209
Parameters:
210
- text: Entry points text content (e.g., from entry_points.txt)
211
- dist: Distribution to associate with entry points
212
213
Returns:
214
EntryPoints: Collection of entry points with distribution associated
215
"""
216
217
@staticmethod
218
def _from_text(text: str | None) -> Iterator[EntryPoint]:
219
"""
220
Parse entry points from text content.
221
222
Parameters:
223
- text: Entry points text content in INI format
224
225
Returns:
226
Iterator[EntryPoint]: Iterator of parsed entry points
227
"""
228
229
# Representation method
230
def __repr__(self) -> str:
231
"""
232
Custom representation showing class name and tuple content.
233
234
Returns:
235
str: String representation like 'EntryPoints([...])'
236
"""
237
```
238
239
#### Usage Examples
240
241
```python
242
import importlib_metadata
243
244
# Get all entry points
245
all_eps = importlib_metadata.entry_points()
246
print(f"Total entry points: {len(all_eps)}")
247
print(f"Available groups: {all_eps.groups}")
248
print(f"Available names: {len(all_eps.names)} unique names")
249
250
# Select by group
251
console_scripts = all_eps.select(group='console_scripts')
252
print(f"Console scripts: {len(console_scripts)}")
253
254
# Select by name
255
pip_eps = all_eps.select(name='pip')
256
print(f"Entry points named 'pip': {len(pip_eps)}")
257
258
# Combine selection criteria
259
specific_eps = all_eps.select(group='console_scripts', name='pip')
260
print(f"pip console scripts: {len(specific_eps)}")
261
262
# Access by name (dictionary-like)
263
if 'pip' in console_scripts.names:
264
pip_ep = console_scripts['pip']
265
print(f"pip script: {pip_ep.value}")
266
```
267
268
### Entry Point Parsing and Validation
269
270
Entry points use a specific syntax for the value specification. The EntryPoint class uses a compiled regular expression pattern to parse these values:
271
272
```python { .api }
273
# EntryPoint.pattern - Regular expression for parsing entry point values
274
# Pattern: r'(?P<module>[\w.]+)\s*(:\s*(?P<attr>[\w.]+)\s*)?((?P<extras>\[.*\])\s*)?$'
275
276
# Entry point value patterns (examples):
277
# - "module" # Module only
278
# - "package.module" # Package and module
279
# - "package.module:attribute" # Module with attribute
280
# - "package.module:object.attribute" # Nested attribute
281
# - "package.module:attr [extra1, extra2]" # With extras
282
283
# The pattern captures three groups:
284
# - module: Required module/package name ([\w.]+)
285
# - attr: Optional attribute name after colon ([\w.]+)
286
# - extras: Optional extras specification in brackets (\[.*\])
287
```
288
289
The pattern is lenient about whitespace around the colon, following the attribute, and following any extras. Invalid entry point references raise ValueError with a descriptive message pointing to the packaging specification.
290
291
#### Usage Examples
292
293
```python
294
import importlib_metadata
295
296
# Create entry point manually (for testing/examples)
297
ep = importlib_metadata.EntryPoint(
298
name='my-script',
299
value='mypackage.cli:main',
300
group='console_scripts'
301
)
302
303
print(f"Entry point module: {ep.module}") # 'mypackage.cli'
304
print(f"Entry point attr: {ep.attr}") # 'main'
305
print(f"Entry point extras: {ep.extras}") # []
306
307
# Entry point with extras
308
ep_with_extras = importlib_metadata.EntryPoint(
309
name='advanced-script',
310
value='mypackage.advanced:run [dev, test]',
311
group='console_scripts'
312
)
313
print(f"Extras: {ep_with_extras.extras}") # ['dev', 'test']
314
```
315
316
### Distribution-Specific Entry Points
317
318
Entry points are associated with specific distributions and can be accessed through Distribution objects:
319
320
```python
321
import importlib_metadata
322
323
# Get entry points for a specific distribution
324
dist = importlib_metadata.distribution('pip')
325
dist_eps = dist.entry_points
326
327
# Filter distribution entry points
328
console_scripts = dist_eps.select(group='console_scripts')
329
for ep in console_scripts:
330
print(f"pip provides script: {ep.name} -> {ep.value}")
331
print(f"Associated distribution: {ep.dist.name if ep.dist else 'None'}")
332
```
333
334
## Error Handling
335
336
Entry point operations can raise various exceptions:
337
338
```python
339
import importlib_metadata
340
341
eps = importlib_metadata.entry_points(group='console_scripts')
342
343
# KeyError when accessing non-existent entry point
344
try:
345
ep = eps['nonexistent-script']
346
except KeyError:
347
print("Entry point not found")
348
349
# ImportError when loading entry point
350
try:
351
ep = next(iter(eps))
352
obj = ep.load()
353
except ImportError as e:
354
print(f"Failed to load entry point: {e}")
355
356
# ValueError when matching with 'dist' parameter
357
try:
358
ep = next(iter(eps))
359
ep.matches(dist=dist) # Not allowed
360
except ValueError:
361
print("Cannot match on 'dist' parameter")
362
363
# ValueError when creating entry point with invalid value
364
try:
365
invalid_ep = importlib_metadata.EntryPoint(
366
name='bad-script',
367
value='invalid-name', # Invalid module name
368
group='console_scripts'
369
)
370
except ValueError as e:
371
print(f"Invalid entry point reference: {e}")
372
373
# AttributeError when trying to modify entry point (immutable)
374
try:
375
ep = next(iter(eps))
376
ep.name = 'new-name' # Not allowed
377
except AttributeError:
378
print("EntryPoint objects are immutable")
379
```