Wheel Files¶
Read and write wheel files. The reader checks each file against the
RECORD file as it is read. The writer computes RECORD as files are
added and generates the WHEEL file from the wheel’s name.
Added in version 26.4.
Usage¶
Write a wheel by name. The name, version, build tag and tags come from the
filename, and WHEEL and RECORD are generated when the context exits:
from packaging.wheelfile import WheelWriter
with WheelWriter("example-1.0-py3-none-any.whl", generator="mytool 1.0") as writer:
writer.write_file("example/__init__.py", b"print('hello')\n")
writer.write_data_file("scripts/example", b"#!python\n", mode=0o755)
writer.write_dist_info_file("METADATA", metadata_bytes)
A file object can be used instead of a path. The wheel name must then be given
as WheelMetadata, since there is no filename to parse. The same applies
to reading:
>>> from io import BytesIO
>>> from packaging.wheelfile import WheelMetadata, WheelReader, WheelWriter
>>> buffer = BytesIO()
>>> metadata = WheelMetadata.from_filename("example-1.0-py3-none-any.whl")
>>> with WheelWriter(buffer, generator="mytool 1.0", metadata=metadata) as writer:
... writer.write_file("example/__init__.py", b"print('hello')\n")
... writer.write_dist_info_file("METADATA", b"Metadata-Version: 2.4\nName: example\nVersion: 1.0\n")
>>> with WheelReader(buffer) as reader:
... (reader.name, str(reader.version))
... reader.dist_info_dir
... reader.validate_record()
... reader.read_file("example/__init__.py")
... print(reader.read_dist_info_file("WHEEL").decode())
('example', '1.0')
'example-1.0.dist-info'
b"print('hello')\n"
Wheel-Version: 1.0
Generator: mytool 1.0
Root-Is-Purelib: true
Tag: py3-none-any
Reading a file that does not match RECORD raises WheelError:
>>> from zipfile import ZipFile
>>> with ZipFile(buffer, "a") as zf:
... zf.writestr("extra.txt", "not in RECORD")
>>> with WheelReader(buffer) as reader:
... reader.read_file("extra.txt")
Traceback (most recent call last):
...
packaging.wheelfile.WheelError: No hash found for file 'extra.txt'
Reproducible wheels¶
Every archive member has a timestamp and permission bits. By default, members
written from bytes or file objects get mode 0o664 and the timestamp
1980-01-01, the earliest the ZIP format can store. Members written from a path
keep the permissions of the file on disk. The timestamp and mode
arguments of WheelWriter change the defaults for every member,
including the generated WHEEL and RECORD files, and the same arguments
on each write method override them for one member.
If the SOURCE_DATE_EPOCH environment variable is set when a
WheelWriter is created and no timestamp is given, its value is
used as the default timestamp. Timestamps outside the range the ZIP format can
store are clamped to that range.
Reference¶
- class packaging.wheelfile.WheelWriter¶
- __init__(path_or_fd, /, *, generator, metadata=None, root_is_purelib=True, compress=True, hash_algorithm='sha256', timestamp=None, mode=0o664)¶
Write a wheel file, generating
WHEELandRECORD.This is a context manager; the archive is created on entry. On a clean exit,
WHEELis written unless it was written explicitly, andRECORDis written last. If the body raises, a wheel given by path is removed.- Parameters:
path_or_fd (str | PathLike[str] | IO[bytes]) – path of the wheel to create, or a binary file object
generator (str) – the name and version of the tool creating the wheel
metadata (WheelMetadata | None) – the wheel name, version, build tag and tags; if omitted, they are parsed from the filename
root_is_purelib (bool) – whether the root of the archive is
purelibcompress (bool) – whether to deflate the archive members
timestamp (datetime | None) – the default timestamp for every archive member, including the generated
WHEELandRECORDfiles; if omitted, the value of theSOURCE_DATE_EPOCHenvironment variable, or else 1980-01-01mode (int) – the default permission bits for members written from bytes or file objects, including
WHEELandRECORD
- Raises:
WheelError – if a file object is given without
metadata, orSOURCE_DATE_EPOCHis not an integerValueError – if the hash algorithm is unavailable or weak
- Return type:
None
- write_file(name, contents, *, timestamp=None, mode=None)¶
Write a file to the archive and record its hash.
- Parameters:
name (str | PurePath) – the path of the file inside the archive
contents (bytes | PathLike[str] | IO[bytes]) – the file contents, a path to a file to copy, or a binary file object; a
stris rejected, as it is too easy to mistake for a pathtimestamp (datetime | None) – the timestamp of the member; the writer default if omitted
mode (int | None) – the permission bits of the member; if omitted, a path or file object keeps its own permissions and anything else gets the writer default
- Return type:
None
- write_files_from_directory(directory)¶
Write every file under a directory, in sorted order, keeping relative paths.
An existing
RECORDfile is skipped, so an unpacked wheel can be packed again. An existingWHEELfile is kept as is.- Raises:
WheelError – if the directory does not exist
- Parameters:
- Return type:
None
- write_data_file(filename, contents, *, timestamp=None, mode=None)¶
Write a file relative to the
.datadirectory.- Parameters:
- Raises:
WheelError – if the first path component is not one of those
- Return type:
None
- packaging.wheelfile.write_wheelfile(fp, /, *, generator, tags, build_tag=(), root_is_purelib)¶
Write the contents of a
WHEELfile to a binary stream.
- class packaging.wheelfile.WheelReader¶
Read a wheel file, verifying its contents against
RECORD.This is a context manager; the archive is opened on entry and closed on exit.
- Parameters:
path_or_fd – path to the wheel, or a binary file object; with a path, the name and version are taken from the filename
- Raises:
WheelError – if the filename is not a valid wheel filename
- iterate_contents()¶
Iterate over the files listed in RECORD.
The stream of each element is checked against RECORD as it is read, and closed when the iteration advances to the next element.
- Return type:
Iterator[WheelContentElement]
- validate_record()¶
Read every file in the archive and check it against
RECORD.- Raises:
WheelError – if a file is missing from
RECORD, or its size or hash does not match- Return type:
None
- extractall(base_path)¶
Extract all files into an existing directory, verifying them against
RECORD.- Raises:
WheelError – if the directory does not exist, a file fails validation, or a member path escapes the directory
- Parameters:
- Return type:
None
- open(archive_name)¶
Open a file in the archive for reading.
- Parameters:
archive_name (str) – the full path of the file inside the archive
- Raises:
WheelError – if the file is not listed in
RECORD- Return type:
- read_file(archive_name)¶
Read a file in the archive, verifying it against
RECORD.
- read_data_file(filename)¶
Read a file relative to the
.datadirectory.
- class packaging.wheelfile.WheelArchiveFile¶
A read-only binary stream for one member of a wheel.
The contents are checked against the
RECORDfile as they are read. A size or hash mismatch raisesWheelErroronce the stream has been read in full.- __init__(fp, arcname, record_entry)¶
- Parameters:
arcname (str)
record_entry (WheelRecordEntry | None)
- Return type:
None
- class packaging.wheelfile.WheelMetadata¶
The parts of a wheel filename that identify the wheel.
- name: NormalizedName¶
Alias for field number 0
- classmethod from_filename(fname)¶
Parse a wheel filename.
- Raises:
packaging.utils.InvalidWheelFilename – if the filename is invalid
- Parameters:
fname (str)
- Return type:
- class packaging.wheelfile.WheelRecordEntry¶
One row of the
RECORDfile.
- class packaging.wheelfile.WheelContentElement¶
A file yielded by
WheelReader.iterate_contents().- stream: WheelArchiveFile¶
Alias for field number 3
- static __new__(_cls, path, hash_value, size, stream)¶
Create new instance of WheelContentElement(path, hash_value, size, stream)
- Parameters:
path (pathlib.PurePath)
hash_value (bytes)
size (int)
stream (WheelArchiveFile)