0
# Package Management
1
2
Dependency resolution, lock file management, and repository handling. Provides complete control over project dependencies, package sources, and lock file operations for reproducible builds.
3
4
## Capabilities
5
6
### Lock File Management
7
8
Poetry's lock file system ensures reproducible builds by recording exact versions and hashes of all dependencies.
9
10
```python { .api }
11
class Locker:
12
"""
13
Lock file management for reproducible dependency resolution.
14
15
Handles poetry.lock file operations including reading locked packages,
16
updating lock data, and validating lock file freshness.
17
"""
18
19
def is_locked(self) -> bool:
20
"""
21
Check if project has a lock file.
22
23
Returns:
24
True if poetry.lock exists and is valid
25
"""
26
27
def is_fresh(self) -> bool:
28
"""
29
Check if lock file is up-to-date with pyproject.toml.
30
31
Returns:
32
True if lock file matches current dependencies
33
"""
34
35
def locked_repository(self) -> Repository:
36
"""
37
Get repository containing all locked packages.
38
39
Returns:
40
Repository with locked package versions
41
"""
42
43
def locked_packages(self) -> list:
44
"""
45
Get list of locked packages with metadata.
46
47
Returns:
48
List of locked packages with versions and hashes
49
"""
50
51
def set_lock_data(self, root, packages) -> None:
52
"""
53
Update lock file with new dependency data.
54
55
Args:
56
root: Root package information
57
packages: List of resolved packages
58
"""
59
60
def set_pyproject_data(self, data: dict) -> None:
61
"""
62
Set pyproject.toml data for lock file validation.
63
64
Args:
65
data: Pyproject configuration data
66
"""
67
```
68
69
#### Usage Example
70
71
```python
72
from poetry.factory import Factory
73
74
# Create Poetry instance
75
poetry = Factory().create_poetry()
76
locker = poetry.locker
77
78
# Check lock file status
79
if locker.is_locked():
80
print("Project has lock file")
81
82
if locker.is_fresh():
83
print("Lock file is up to date")
84
else:
85
print("Lock file needs updating")
86
87
# Get locked packages
88
locked_packages = locker.locked_packages()
89
for package in locked_packages:
90
print(f"{package.name}: {package.version}")
91
92
# Get locked repository
93
locked_repo = locker.locked_repository()
94
print(f"Locked repository has {len(locked_repo.packages)} packages")
95
else:
96
print("No lock file found")
97
```
98
99
### Repository Management
100
101
Manages multiple package repositories with priority handling and source resolution.
102
103
```python { .api }
104
class Repository:
105
"""
106
Base repository class for package sources.
107
108
Provides interface for package discovery, metadata retrieval,
109
and dependency resolution from various sources.
110
"""
111
112
def find_packages(self, dependency) -> list:
113
"""
114
Find packages matching dependency specification.
115
116
Args:
117
dependency: Dependency specification
118
119
Returns:
120
List of matching packages
121
"""
122
123
def package(self, name: str, version: str):
124
"""
125
Get specific package by name and version.
126
127
Args:
128
name: Package name
129
version: Package version
130
131
Returns:
132
Package instance or None
133
"""
134
135
class RepositoryPool:
136
"""
137
Manages multiple package repositories with priority handling.
138
139
Coordinates package discovery across multiple sources with
140
configurable priority levels and fallback behavior.
141
"""
142
143
PRIMARY = "primary" # Primary repository priority
144
SUPPLEMENTAL = "supplemental" # Supplemental repository priority
145
EXPLICIT = "explicit" # Explicit repository priority
146
147
def add_repository(self, repository, priority: str = "supplemental") -> None:
148
"""
149
Add repository to pool with specified priority.
150
151
Args:
152
repository: Repository instance
153
priority: Repository priority level
154
"""
155
156
def has_primary_repositories(self) -> bool:
157
"""
158
Check if pool has primary repositories configured.
159
160
Returns:
161
True if primary repositories exist
162
"""
163
164
def find_packages(self, dependency) -> list:
165
"""
166
Find packages across all repositories in priority order.
167
168
Args:
169
dependency: Dependency specification
170
171
Returns:
172
List of packages from all sources
173
"""
174
175
class HTTPRepository(Repository):
176
"""
177
HTTP-based package repository (PyPI, private indexes).
178
179
Handles package discovery and metadata retrieval from
180
HTTP-based package indexes with authentication support.
181
"""
182
183
def __init__(self, name: str, url: str, config = None,
184
disable_cache: bool = False):
185
"""
186
Initialize HTTP repository.
187
188
Args:
189
name: Repository name
190
url: Repository URL
191
config: Configuration instance
192
disable_cache: Whether to disable caching
193
"""
194
195
class InstalledRepository(Repository):
196
"""
197
Repository representing currently installed packages.
198
199
Provides access to packages installed in the current
200
environment for dependency resolution and conflict detection.
201
"""
202
203
@classmethod
204
def load(cls, env, with_dependencies: bool = True):
205
"""
206
Load installed packages from environment.
207
208
Args:
209
env: Environment instance
210
with_dependencies: Whether to include dependencies
211
212
Returns:
213
Repository with installed packages
214
"""
215
```
216
217
#### Usage Example
218
219
```python
220
from poetry.factory import Factory
221
from poetry.repositories.http_repository import HTTPRepository
222
from poetry.repositories.installed_repository import InstalledRepository
223
224
# Create Poetry instance
225
poetry = Factory().create_poetry()
226
pool = poetry.pool
227
228
# Add custom repository
229
custom_repo = HTTPRepository(
230
name="custom",
231
url="https://my-repo.com/simple/",
232
config=poetry.config
233
)
234
pool.add_repository(custom_repo, priority="supplemental")
235
236
# Check repository configuration
237
if pool.has_primary_repositories():
238
print("Primary repositories configured")
239
240
# Get installed packages
241
env_manager = EnvManager(poetry.file.parent)
242
env = env_manager.get_system_env()
243
installed_repo = InstalledRepository.load(env)
244
245
print(f"Installed packages: {len(installed_repo.packages)}")
246
```
247
248
### Package Collections
249
250
Utilities for managing collections of packages with dependency analysis.
251
252
```python { .api }
253
class PackageCollection:
254
"""
255
Collection of packages with dependency analysis utilities.
256
257
Provides methods for package organization, dependency traversal,
258
and conflict detection across package sets.
259
"""
260
261
def __init__(self, packages: list = None):
262
"""
263
Initialize package collection.
264
265
Args:
266
packages: Initial list of packages
267
"""
268
269
def add(self, package) -> None:
270
"""
271
Add package to collection.
272
273
Args:
274
package: Package to add
275
"""
276
277
def remove(self, package) -> None:
278
"""
279
Remove package from collection.
280
281
Args:
282
package: Package to remove
283
"""
284
285
def find_dependencies(self, package) -> list:
286
"""
287
Find dependencies of package within collection.
288
289
Args:
290
package: Package to analyze
291
292
Returns:
293
List of dependency packages
294
"""
295
296
def find_dependents(self, package) -> list:
297
"""
298
Find packages that depend on given package.
299
300
Args:
301
package: Package to analyze
302
303
Returns:
304
List of dependent packages
305
"""
306
307
class DependencyPackage:
308
"""
309
Package representation for dependency management.
310
311
Enhanced package class with dependency-specific metadata
312
and resolution information.
313
"""
314
315
def __init__(self, package, dependency):
316
"""
317
Initialize dependency package.
318
319
Args:
320
package: Base package instance
321
dependency: Dependency specification
322
"""
323
324
@property
325
def constraint(self) -> str:
326
"""Version constraint for this dependency."""
327
328
@property
329
def extras(self) -> list:
330
"""Optional extras for this dependency."""
331
332
@property
333
def marker(self) -> str:
334
"""Environment marker for conditional dependencies."""
335
```
336
337
#### Usage Example
338
339
```python
340
from poetry.packages.package_collection import PackageCollection
341
from poetry.factory import Factory
342
343
# Create Poetry instance and get dependencies
344
poetry = Factory().create_poetry()
345
dependencies = poetry.package.all_requires
346
347
# Create package collection
348
collection = PackageCollection()
349
350
# Add packages to collection
351
for dep in dependencies:
352
# Resolve dependency to actual package
353
packages = poetry.pool.find_packages(dep)
354
if packages:
355
collection.add(packages[0])
356
357
# Analyze dependencies
358
for package in collection:
359
deps = collection.find_dependencies(package)
360
dependents = collection.find_dependents(package)
361
362
print(f"{package.name}:")
363
print(f" Dependencies: {[d.name for d in deps]}")
364
print(f" Dependents: {[d.name for d in dependents]}")
365
```
366
367
### Dependency Specification
368
369
Utilities for parsing and formatting dependency specifications.
370
371
```python { .api }
372
def parse_dependency_specification(spec: str) -> dict:
373
"""
374
Parse dependency specification string.
375
376
Args:
377
spec: Dependency specification (e.g., "requests>=2.25.0,<3.0")
378
379
Returns:
380
Dictionary with parsed dependency information
381
"""
382
383
def format_dependency_specification(name: str, constraint: str,
384
extras: list = None,
385
markers: str = None) -> str:
386
"""
387
Format dependency specification string.
388
389
Args:
390
name: Package name
391
constraint: Version constraint
392
extras: Optional extras
393
markers: Environment markers
394
395
Returns:
396
Formatted dependency specification
397
"""
398
399
class DependencySpec:
400
"""
401
Structured dependency specification.
402
403
Provides parsing and formatting utilities for dependency
404
specifications with support for version constraints, extras,
405
and environment markers.
406
"""
407
408
def __init__(self, name: str, constraint: str = "*"):
409
"""
410
Initialize dependency specification.
411
412
Args:
413
name: Package name
414
constraint: Version constraint
415
"""
416
417
@property
418
def name(self) -> str:
419
"""Package name."""
420
421
@property
422
def constraint(self) -> str:
423
"""Version constraint."""
424
425
@classmethod
426
def from_string(cls, spec: str) -> "DependencySpec":
427
"""
428
Parse dependency specification from string.
429
430
Args:
431
spec: Dependency specification string
432
433
Returns:
434
DependencySpec instance
435
"""
436
437
def to_string(self) -> str:
438
"""
439
Convert to dependency specification string.
440
441
Returns:
442
Formatted dependency specification
443
"""
444
```
445
446
#### Usage Example
447
448
```python
449
from poetry.utils.dependency_specification import DependencySpec
450
451
# Parse dependency specifications
452
spec1 = DependencySpec.from_string("requests>=2.25.0,<3.0")
453
spec2 = DependencySpec.from_string("pytest[dev]>=6.0")
454
455
print(f"Package: {spec1.name}")
456
print(f"Constraint: {spec1.constraint}")
457
458
# Format dependency specification
459
formatted = DependencySpec("django", ">=3.2,<4.0").to_string()
460
print(f"Formatted: {formatted}")
461
```
462
463
### Advanced Package Operations
464
465
#### Dependency Resolution
466
467
```python
468
from poetry.factory import Factory
469
from poetry.puzzle.solver import Solver
470
471
def resolve_dependencies(poetry_instance):
472
"""Resolve project dependencies."""
473
solver = Solver(
474
poetry_instance.package,
475
poetry_instance.pool,
476
poetry_instance.config
477
)
478
479
# Resolve dependencies
480
operations = solver.solve()
481
482
return operations
483
```
484
485
#### Lock File Operations
486
487
```python
488
from poetry.factory import Factory
489
490
def update_lock_file(project_path, groups=None):
491
"""Update project lock file."""
492
poetry = Factory().create_poetry(cwd=project_path)
493
494
# Get current dependencies
495
dependencies = poetry.package.all_requires
496
497
# Resolve dependencies
498
solver = Solver(poetry.package, poetry.pool, poetry.config)
499
packages = solver.solve()
500
501
# Update lock file
502
poetry.locker.set_lock_data(poetry.package, packages)
503
504
print(f"Updated lock file with {len(packages)} packages")
505
```
506
507
## Error Handling
508
509
Package management exceptions and error conditions:
510
511
```python { .api }
512
class PackageNotFoundError(PoetryError):
513
"""Package not found in any repository."""
514
515
class VersionConflictError(PoetryError):
516
"""Version constraint conflicts in dependency resolution."""
517
518
class LockFileError(PoetryError):
519
"""Lock file operation errors."""
520
521
class RepositoryError(PoetryError):
522
"""Repository access or configuration errors."""
523
```
524
525
Common package management errors:
526
- Package not found in configured repositories
527
- Version conflicts during dependency resolution
528
- Network errors accessing remote repositories
529
- Authentication failures for private repositories
530
- Lock file corruption or format errors
531
- Circular dependency detection