0
# Package Conversion
1
2
Convert legacy Python package formats (.egg files and Windows installers) to modern wheel format. Supports both zipped .egg files and unpacked .egg directories, as well as Windows executable installers created with bdist_wininst.
3
4
## Capabilities
5
6
### Main Conversion Function
7
8
Convert multiple package files to wheel format with metadata transformation and platform detection.
9
10
```python { .api }
11
def convert(files: list[str], dest_dir: str, verbose: bool) -> None:
12
"""
13
Convert .egg files and Windows installers to wheels.
14
15
Parameters:
16
- files: List of file patterns (supports glob patterns)
17
- dest_dir: Output directory for converted wheels
18
- verbose: Print conversion progress messages
19
20
Supported formats:
21
- .egg files (zipped archives)
22
- .egg directories (unpacked)
23
- .exe files (Windows bdist_wininst installers)
24
"""
25
```
26
27
### Conversion Source Classes
28
29
Abstract base class and implementations for different package formats.
30
31
```python { .api }
32
class ConvertSource(metaclass=ABCMeta):
33
"""
34
Abstract base class for conversion sources.
35
"""
36
37
name: str
38
"""Package name (normalized)."""
39
40
version: str
41
"""Package version."""
42
43
pyver: str
44
"""Python version tags (default: "py2.py3")."""
45
46
abi: str
47
"""ABI tags (default: "none")."""
48
49
platform: str
50
"""Platform tags (default: "any")."""
51
52
metadata: Message
53
"""Email message object containing package metadata."""
54
55
@property
56
def dist_info_dir(self) -> str:
57
"""Get .dist-info directory name."""
58
return f"{self.name}-{self.version}.dist-info"
59
60
@abstractmethod
61
def generate_contents(self) -> Iterator[tuple[str, bytes]]:
62
"""Generate (filename, content) pairs for wheel contents."""
63
pass
64
```
65
66
### Egg File Conversion
67
68
Convert zipped .egg files to wheel format with metadata transformation.
69
70
```python { .api }
71
class EggFileSource(ConvertSource):
72
"""
73
Convert .egg files to wheels.
74
75
Handles:
76
- Binary wheels detection (assumes CPython)
77
- PKG-INFO metadata conversion
78
- requires.txt dependency conversion
79
- entry_points.txt preservation
80
"""
81
82
def __init__(self, path: Path):
83
"""
84
Initialize from .egg file path.
85
86
Parameters:
87
- path: Path to .egg file
88
89
Raises:
90
- ValueError: If filename doesn't match .egg pattern
91
"""
92
93
def generate_contents(self) -> Iterator[tuple[str, bytes]]:
94
"""
95
Generate wheel contents from .egg file.
96
97
Yields:
98
Tuples of (archive_path, file_content)
99
100
Processing:
101
- Converts EGG-INFO/ to .dist-info/
102
- Transforms PKG-INFO to METADATA
103
- Converts requires.txt to Requires-Dist headers
104
- Preserves entry_points.txt
105
"""
106
```
107
108
### Egg Directory Conversion
109
110
Convert unpacked .egg directories to wheel format.
111
112
```python { .api }
113
class EggDirectorySource(EggFileSource):
114
"""
115
Convert .egg directories to wheels.
116
117
Similar to EggFileSource but reads from filesystem directory
118
instead of zip archive.
119
"""
120
121
def generate_contents(self) -> Iterator[tuple[str, bytes]]:
122
"""
123
Generate wheel contents from .egg directory.
124
125
Yields:
126
Tuples of (archive_path, file_content)
127
128
Updates name and version from PKG-INFO if available.
129
"""
130
```
131
132
### Windows Installer Conversion
133
134
Convert Windows executable installers to wheel format with platform detection.
135
136
```python { .api }
137
class WininstFileSource(ConvertSource):
138
"""
139
Convert Windows bdist_wininst installers to wheels.
140
141
Handles:
142
- Platform detection from installer filename
143
- .pyd file ABI detection
144
- .egg-info metadata extraction
145
- SCRIPTS directory mapping to .data/scripts/
146
"""
147
148
def __init__(self, path: Path):
149
"""
150
Initialize from Windows installer path.
151
152
Parameters:
153
- path: Path to .exe installer file
154
155
Processing:
156
- Extracts platform from filename pattern
157
- Scans for .egg-info and .pyd files for metadata
158
- Determines Python version and ABI from content
159
"""
160
161
def generate_contents(self) -> Iterator[tuple[str, bytes]]:
162
"""
163
Generate wheel contents from Windows installer.
164
165
Yields:
166
Tuples of (archive_path, file_content)
167
168
Mapping:
169
- SCRIPTS/ -> {name}-{version}.data/scripts/
170
- .egg-info/ -> .dist-info/ (with metadata conversion)
171
"""
172
```
173
174
### Metadata Conversion Functions
175
176
Utility functions for converting between metadata formats.
177
178
```python { .api }
179
def convert_requires(requires: str, metadata: Message) -> None:
180
"""
181
Convert requires.txt format to Requires-Dist headers.
182
183
Parameters:
184
- requires: Content of requires.txt file
185
- metadata: Message object to add headers to
186
187
Format handling:
188
- [extra] sections become conditional requirements
189
- Requirement lines converted to Requires-Dist format
190
- Generates Provides-Extra headers for extras
191
"""
192
193
def convert_pkg_info(pkginfo: str, metadata: Message) -> None:
194
"""
195
Convert PKG-INFO format to Metadata 2.4 format.
196
197
Parameters:
198
- pkginfo: PKG-INFO file content
199
- metadata: Message object to populate
200
201
Transformations:
202
- Updates Metadata-Version to 2.4
203
- Converts Description to message body
204
- Maps Home-page to Project-URL: Homepage
205
- Maps Download-URL to Project-URL: Download
206
- Filters out "UNKNOWN" values
207
"""
208
209
def normalize(name: str) -> str:
210
"""
211
Normalize package name for wheel filename.
212
213
Parameters:
214
- name: Package name to normalize
215
216
Returns:
217
Normalized name ([-_.] replaced with underscores, lowercased)
218
"""
219
```
220
221
### Usage Examples
222
223
#### Converting Egg Files
224
225
```python
226
from wheel._commands.convert import convert
227
import os
228
229
# Convert all .egg files in current directory
230
egg_files = ['package-1.0-py2.7.egg', 'another-2.0.egg']
231
convert(egg_files, dest_dir='wheels/', verbose=True)
232
233
# Using glob patterns
234
convert(['*.egg'], dest_dir='dist/', verbose=False)
235
```
236
237
#### Programmatic Conversion with Custom Source
238
239
```python
240
from wheel._commands.convert import EggFileSource
241
from wheel.wheelfile import WheelFile
242
from pathlib import Path
243
244
# Create custom conversion
245
egg_path = Path('package-1.0.egg')
246
source = EggFileSource(egg_path)
247
248
# Generate wheel
249
wheel_path = f"{source.name}-{source.version}-{source.pyver}-{source.abi}-{source.platform}.whl"
250
with WheelFile(wheel_path, 'w') as wf:
251
for name, content in source.generate_contents():
252
wf.writestr(name, content)
253
254
# Add generated metadata
255
wf.writestr(
256
f"{source.dist_info_dir}/METADATA",
257
source.metadata.as_string(policy=serialization_policy).encode('utf-8')
258
)
259
```
260
261
#### Windows Installer Conversion
262
263
```python
264
from wheel._commands.convert import convert
265
266
# Convert Windows installers
267
convert(['package-1.0.win32-py3.8.exe'], dest_dir='wheels/', verbose=True)
268
269
# Results in: package-1.0-py38-cp38-win32.whl
270
```
271
272
## Constants and Types
273
274
```python { .api }
275
import re
276
from email.message import Message
277
from email.policy import EmailPolicy
278
from abc import ABCMeta, abstractmethod
279
from collections.abc import Iterator
280
from pathlib import Path
281
282
# Filename parsing patterns
283
egg_filename_re: re.Pattern[str]
284
"""Pattern for parsing .egg filenames: name-version(-pyver)(-arch).egg"""
285
286
egg_info_re: re.Pattern[str]
287
"""Pattern for parsing .egg-info directory names"""
288
289
wininst_re: re.Pattern[str]
290
"""Pattern for parsing Windows installer filenames"""
291
292
pyd_re: re.Pattern[str]
293
"""Pattern for parsing .pyd file extensions for ABI detection"""
294
295
# Email serialization policy
296
serialization_policy: EmailPolicy
297
"""Email policy for metadata serialization (UTF-8, no line wrapping)"""
298
299
GENERATOR: str
300
"""Generator string for WHEEL files (f"wheel {__version__}")"""
301
```