hatch-zipped-directory 0.2.1
A custom builder to build zipped directories
Requires Python: >=3.9
Keywords: hatch, packaging

# hatch-zipped-directory

[![PyPI - Version](https://img.shields.io/pypi/v/hatch-zipped-directory.svg)](https://pypi.org/project/hatch-zipped-directory)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/hatch-zipped-directory.svg)](https://pypi.org/project/hatch-zipped-directory)
[![Tests](https://github.com/dairiki/hatch-zipped-directory/actions/workflows/tests.yml/badge.svg)](https://github.com/dairiki/hatch-zipped-directory/actions/workflows/tests.yml)
[![Trackgit Views](https://us-central1-trackgit-analytics.cloudfunctions.net/token/ping/lhautvz4zffrt8jawcpl)](https://trackgit.com)

-----

This is a [Hatch](https://hatch.pypa.io/latest/) plugin that provides
a custom builder to support building zip archives for quasi-manual
installation into various foreign package installation systems.
(Specifically, I use this for packaging
[Inkscape](https://inkscape.org/) extensions and symbols libraries,
but it may be useful in other contexts, such as deploying to cloud
compute platforms.)

The builder creates a zip archive.  All the contents of the zip
archive will be included under a single specific top-level directory.
The default name of the top-level directory is a file-name-safe
version of the project name, however the name of the directory may be
configured by setting the `install-name` key in the target-specific
configuration section.
This behavior may be disabled by setting `install-name = ''`.

In addition to whatever files are selected for inclusion in the
archive via Hatch’s regular [build configuration
settings](https://hatch.pypa.io/latest/config/build/), any configured
project README and license files will be included in the top level of
the install directory within the zip archive.

As well, a `METADATA.json` file containing the project metadata in
JSON format (as described in
[PEP 566](https://peps.python.org/pep-0566/#json-compatible-metadata))
will be included in the top level of the install directory within the
zip archive.


## Example

Assume a project source directory looking something like:
```
.
├── pyproject.toml
├── LICENSE.txt
├── README.md
├── src
│   ├── subdir
│   │   ├── data.txt
│   │   └── more-code.py
│   └── my-code.py
└── tests
    └── test_foo.py
```

Where `pyproject.toml` looks like:
```toml
[build-system]
requires = [
    "hatchling",
    "hatch-zipped-directory",
]
build-backend = "hatchling.build"

[project]
name = "test-project"
version = "0.42"

[tool.hatch.build.targets.zipped-directory]
install-name = "org.example.test"
sources = [
    "/src",
]
```

Then, running
```sh
hatch build --target zipped-directory
```

will build a zip archive named `dist/test_project-0.42.zip` with the following
structure:
```
.
└── org.example.test
    ├── LICENSE.txt
    ├── METADATA.json
    ├── README.md
    ├── my-code.py
    └── subdir
        ├── data.txt
        └── more-code.py
```

## Reproducible Builds

By default, this plugin attempts to build [reproducible][reproducible
builds] archives by setting the timestamps of the zip entries to a
fixed value. When building in reproducible mode, the UNIX file modes
of the archive entries is also normalized (to either 0644 or 0755
depending on whether the file is executable.)

The timestamp used for reproducible builds may be configured by
setting the `SOURCE_DATE_EPOCH` environment variable.

Reproducible builds may be disabled by setting `reproducible = false`
in an appropriate section of `pyproject.toml` or `hatch.toml`.  See
Hatch’s documentation on [Build Configuration] for details.


## Author

Jeff Dairiki <dairiki@dairiki.org>

## License

`hatch-zipped-directory` is distributed under the terms of the
[MIT](https://spdx.org/licenses/MIT.html) license.

[reproducible builds]: https://hatch.pypa.io/latest/config/build/#reproducible-builds
[Build Configuration]: https://hatch.pypa.io/latest/config/build/


## Changes

### 0.2.1 (2025-06-06)

#### Bugs Fixed

- Timestamps of parent directory entries are now set to the correct
  magic value with reproducible builds are enabled. ([#5], [#6])

#### Tests Fixed

- The functional test (`test_functional.py`) was testing the latest
  version of our plugin from PyPI rather than from local source.

- The CI tests appear to have been running whatever version of python
  was compiled into the installed `hatch` binary, rather than the system
  default python.

[#5]: https://github.com/dairiki/hatch-zipped-directory/issues/5
[#6]: https://github.com/dairiki/hatch-zipped-directory/pull/6

### 0.2.0 (2025-03-11)

#### Features

- Write parent directory entries to zip archive. Python requires this
  when importing modules directly from a zip archive. ([#4] — thank
  you @PolyPik)

#### Breaking Changes

- Drop support for Python 3.7 & 3.8.

#### Bugs Fixed

- (typing) `atomic_open` returns `io.BufferedRandom` (not `io.BufferedWriter`).

#### Tests

- Test under python 3.14.
- Test under windows.

[#4]: https://github.com/dairiki/hatch-zipped-directory/pull/4

### 0.1.0 (2023-12-12)

#### Bitrot

- Fix for hatchling 1.19 (hatch 1.8). `BuilderInterface.build`
  arguments are now all kw-only. ([hatch/6c252f8])

[hatch/6c252f8]: https://github.com/pypa/hatch/commit/6c252f8b8a65711846a6060c3d54f02936da2aa0)

### 0.1.0b4 (2023-09-10)

#### Features

- Add support for [reproducible builds] which are now enabled by
  default. When enabled, timestamps in the zip archive are set to a
  fixed value (configurable via the `SOURCE_DATE_EPOCH` environment
  variable) and the UNIX access modes of archive members are
  [normalized to either 0644 or 0755][mode-normalization] depending on
  whether the file is executable or not.

[reproducible builds]: https://hatch.pypa.io/latest/config/build/#reproducible-builds
[mode-normalization]: https://github.com/pypa/flit/pull/66

### 0.1.0b3 (2023-05-10)

#### Features

- Refactor JSON metadata code. Now we use `hatchling` to generate
  conventionall RFC 822-formatted distribution metadata, then convert
  that to JSON, explicitly following the steps outline in [PEP
  566](https://peps.python.org/pep-0566/#json-compatible-metadata).
  Among other things, this allows configuration of the
  *Metadata-Version* by setting
  `tool.hatch.build.targets.zipped-directory.core-metadata-version`.

#### Tests

- We now have 100% test coverage.

### 0.1.0b2 (2023-01-10)

#### Features

- The prefixing of file names under a top-level directory in the zip
  archive can now be disabled by setting `install-name = ""`.
  Thank you @gwerbin([#1][])

#### Bugs

- Use explicit encoding in hatch metadata hook (for Windows).

[#1]: https://github.com/dairiki/hatch-zipped-directory/issues/1

### 0.1.0b1 (2022-10-07)

Initial release.