Metadata-Version: 2.4
Name: pybtrfs
Version: 0.6.1
Summary: Static Python bindings for btrfs ioctl operations
Home-page: https://github.com/mosquito/pybtrfs
License: GPL-2.0
Project-URL: Source, https://github.com/mosquito/pybtrfs
Project-URL: Bug Tracker, https://github.com/mosquito/pybtrfs/issues
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: C
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: System :: Filesystems
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license
Dynamic: license-file
Dynamic: project-url
Dynamic: requires-python
Dynamic: summary

# pybtrfs

Native Python bindings for btrfs — create filesystems, manage subvolumes and snapshots, mount and unmount. No shell commands, no subprocess, no runtime dependencies beyond libc.

Built as C extensions directly from vendored [btrfs-progs](https://github.com/kdave/btrfs-progs) source. Pre-built binary wheels are available on [PyPI](https://pypi.org/project/pybtrfs/) — no compiler needed.

## Why not the existing `btrfs` package?

The [`btrfs`](https://pypi.org/project/btrfs/) package on PyPI requires `libbtrfsutil` installed as a system library. That means distro packages, broken virtualenvs, and pain on minimal containers or custom builds.

`pybtrfs` statically compiles everything from vendored source — the only build-time requirement is a C compiler and Python headers. The resulting `.so` files link only to libc.

All blocking operations (ioctl calls, sync, mkfs, mount/umount) release the GIL, so they can safely run in parallel from multiple threads without blocking the interpreter.

## Requirements

- Linux with btrfs support
- Python 3.10+

## Installation

Pre-built wheels for x86_64 and aarch64 (manylinux_2_28):

```bash
pip install pybtrfs
```

Releases with wheels are also available on [GitHub](https://github.com/mosquito/pybtrfs/releases).

To build from source (requires GCC and Python headers):

```bash
pip install .
```

Or with make:

```bash
make build      # compile extensions
make install    # pip install .
```

## Usage

### Subvolumes and snapshots

```python
import pybtrfs

# Create a subvolume
pybtrfs.create_subvolume("/mnt/data/project")

# Snapshot before a risky operation
pybtrfs.create_snapshot("/mnt/data/project", "/mnt/data/project-snap",
                        read_only=True)

# Check snapshot relationship
src = pybtrfs.subvolume_info("/mnt/data/project")
snap = pybtrfs.subvolume_info("/mnt/data/project-snap")
assert snap.parent_uuid == src.uuid

# Clean up
pybtrfs.delete_subvolume("/mnt/data/project-snap")
```

### List all subvolumes

```python
with pybtrfs.SubvolumeIterator("/mnt/data", info=True) as it:
    for path, info in it:
        print(f"{path} (id={info.id}, gen={info.generation})")
```

### Create a filesystem

```python
from pybtrfs import mkfs, CsumType, RaidProfile

# Single device
result = mkfs("/dev/sdb", label="data", force=True)
print(result["uuid"])

# RAID1 mirror with xxhash checksums
result = mkfs("/dev/sdb", "/dev/sdc",
              data_profile=RaidProfile.RAID1,
              metadata_profile=RaidProfile.RAID1,
              csum_type=CsumType.XXHASH,
              force=True)
```

### Mount and unmount

```python
from pybtrfs import mount, umount, mount_data, MountFlags

mount("/dev/sdb", "/mnt/data",
      data=mount_data(compress="zstd", space_cache="v2"))

mount("/dev/sdb", "/mnt/readonly", flags=MountFlags.RDONLY)

umount("/mnt/data")
```

### Quota management

```python
import pybtrfs

# Enable quotas (required before any qgroup operations)
pybtrfs.quota_enable("/mnt/data")

# Or enable simple quotas (squota) — faster, less overhead
pybtrfs.quota_enable_simple("/mnt/data")

# Rescan to ensure accounting is up to date
pybtrfs.quota_rescan("/mnt/data")
pybtrfs.quota_rescan_wait("/mnt/data")

# Check rescan status
status = pybtrfs.quota_rescan_status("/mnt/data")
print(status)  # {"flags": 0, "progress": ...}

# List all qgroups with usage
for qg in pybtrfs.qgroup_info("/mnt/data"):
    print(f"qgroup {qg['qgroupid']}: "
          f"rfer={qg['rfer']}, excl={qg['excl']}, "
          f"max_rfer={qg['max_rfer']}, max_excl={qg['max_excl']}")

# Set a 10 GiB referenced limit on the root qgroup
pybtrfs.qgroup_limit("/mnt/data", qgroupid=5,
                      max_rfer=10 * 1024**3)

# Disable quotas
pybtrfs.quota_disable("/mnt/data")
```

### Hierarchical qgroups

```python
import pybtrfs

pybtrfs.quota_enable("/mnt/data")

# Create a level-1 parent qgroup (1/1)
parent = (1 << 48) | 1
pybtrfs.qgroup_create("/mnt/data", parent)

# Create subvolumes and assign them to the parent group
pybtrfs.create_subvolume("/mnt/data/project_a")
pybtrfs.create_subvolume("/mnt/data/project_b")
child_a = pybtrfs.subvolume_id("/mnt/data/project_a")
child_b = pybtrfs.subvolume_id("/mnt/data/project_b")

pybtrfs.qgroup_assign("/mnt/data", child_a, parent)
pybtrfs.qgroup_assign("/mnt/data", child_b, parent)

# Set a shared 50 GiB limit across both subvolumes
pybtrfs.qgroup_limit("/mnt/data", parent, max_rfer=50 * 1024**3)

# Remove assignment and destroy the group when no longer needed
pybtrfs.qgroup_remove("/mnt/data", child_a, parent)
pybtrfs.qgroup_remove("/mnt/data", child_b, parent)
pybtrfs.qgroup_destroy("/mnt/data", parent)
```

### Error handling

```python
import pybtrfs

try:
    pybtrfs.sync("/not/btrfs")
except pybtrfs.BtrfsUtilError as e:
    print(e.btrfsutil_errno)  # e.g. BtrfsUtilErrno.NOT_BTRFS
    print(e.errno)            # OS errno
```

## API reference

The package ships with `.pyi` stubs — full signatures and docstrings are available via `help(pybtrfs)`, `help(pybtrfs.mkfs)`, `help(pybtrfs.mount)`, `help(pybtrfs.quota)`, and your IDE's autocomplete.

## Testing

Tests require root and a mounted btrfs filesystem:

```bash
truncate -s 1G /tmp/btrfs.img
mkfs.btrfs /tmp/btrfs.img
mkdir -p ~/btrfs
mount /tmp/btrfs.img ~/btrfs

sudo BTRFS=~/btrfs PYTHONPATH=. pytest -v
```

## License

GPL-2.0 — see [LICENSE](LICENSE).

This project statically compiles code from [btrfs-progs](https://github.com/kdave/btrfs-progs) (GPL-2.0), including `libbtrfsutil` (LGPL-2.1) and substantial portions of the core btrfs-progs codebase (kernel-shared, mkfs, crypto, etc.) which are GPL-2.0. Since the resulting binaries are derivative works of GPL-2.0 code, this project is licensed under GPL-2.0 to comply with the upstream license terms.
