Skip to main content

A Python wrapper for Linux quotactl(2) APIs

Project description

PyQuota

PyQuota is a Python wrapper for the Linux quotactl(2) APIs.

Requirements

  • Linux with quota support (kernel built with CONFIG_QUOTA)
  • Privilege: root or CAP_SYS_ADMIN for quota operations
  • Kernel: >= 2.4.22; project quota requires >= 4.1; Q_GETNEXTQUOTA requires >= 4.6

XFS-specific quotactl commands (e.g. Q_XQUOTAON) are not supported.

Future work: Linux 5.13+ adds quotactl_fd(), which uses a file descriptor instead of a device path (useful for filesystems without a block device, e.g. UBIFS). This wrapper does not yet support it.

Breaking changes (current release)

  • get_user_quota, get_next_user_quota, get_user_quota_info (and group/project) now take an optional return_type and default to named tuples. Use return_type="tuple" to get the raw tuple (e.g. pq.get_user_quota(device, uid, return_type="tuple")).
  • get_user_quota_named and other *_named functions are removed; use the corresponding get_* with default return_type="named".
  • get_user_quota_with_valid and other *_with_valid functions are replaced by get_*_quota_partial (and get_*_quota_info_partial), which return named tuples only (QuotaPartial, NextQuotaPartial, QuotaInfoPartial) with optional fields as None when not set.

Installation

pip install pyquota

From source (build deps: Python development headers, C compiler):

git clone https://github.com/tjumyk/pyquota.git && cd pyquota
pip install -e .

Units

  • Block limits (block_hard_limit, block_soft_limit): in 1024-byte disk quota blocks (quotactl(2))
  • Current block usage (block_current): in bytes
  • Inode limits/current: inodes (count)
  • Grace periods (block_grace, inode_grace in QuotaInfo): in seconds before soft limit becomes hard
  • Time limits (block_time, inode_time in Quota): Unix timestamps (seconds since epoch) when grace expires, or 0 if not over soft limit

API overview

quotactl command User quota Group quota Project quota
Q_QUOTAON user_quota_on group_quota_on project_quota_on
Q_QUOTAOFF user_quota_off group_quota_off project_quota_off
Q_GETQUOTA get_user_quota get_group_quota get_project_quota
Q_GETNEXTQUOTA get_next_user_quota get_next_group_quota get_next_project_quota
Q_SETQUOTA set_user_quota set_group_quota set_project_quota
Q_GETINFO get_user_quota_info get_group_quota_info get_project_quota_info
Q_SETINFO set_user_quota_info set_group_quota_info set_project_quota_info
Q_GETFMT get_user_quota_format get_group_quota_format get_project_quota_format
Q_SYNC sync_user_quotas sync_group_quotas sync_project_quotas

Return type: get_*_quota, get_next_*_quota, and get_*_quota_info accept an optional return_type ("named" | "tuple"). Default is "named", returning Quota, NextQuota, or QuotaInfo. Use return_type="tuple" for the raw tuple.

Partial validity: When the kernel may return incomplete data, use get_*_quota_partial or get_*_quota_info_partial. They return named tuples (QuotaPartial, etc.) where fields the kernel did not set are None (interpreted from the kernel’s valid mask per man 2 quotactl). Use e.g. if q.block_hard_limit is not None:. According to the man page, the kernel currently always fills all fields and sets the valid mask to QIF_ALL/IIF_ALL on get; the valid mask is used on set to indicate which fields the caller provides. The partial API exists for forward compatibility if a kernel ever returns incomplete data.

Usage

import pyquota as pq

# Turn on user quota for a filesystem
pq.user_quota_on("/dev/sda1", pq.QFMT_VFS_V0, "/aquota.user")

# Turn off user quota
pq.user_quota_off("/dev/sda1")

# Get quota (default: named tuple Quota)
quota = pq.get_user_quota("/dev/sda1", 1000)
print(quota.block_hard_limit, quota.block_current)

# Raw tuple: use return_type="tuple"
raw = pq.get_user_quota("/dev/sda1", 1000, return_type="tuple")

# Get next user with quota (kernel >= 4.6)
next_quota = pq.get_next_user_quota("/dev/sda1", 1000)  # next_quota.id is the uid

# Set user quota (hard 100MB, soft 90MB, no inode limits)
pq.set_user_quota("/dev/sda1", 1000, 102400, 92160, 0, 0)

# Or pass the result of get_user_quota (only the four limit fields are applied)
q = pq.get_user_quota("/dev/sda1", 1000)
pq.set_user_quota("/dev/sda1", 1000, quota=q)

# Quotafile info (grace periods in seconds, flags)
info = pq.get_user_quota_info("/dev/sda1")
print(info.block_grace, info.inode_grace)
print(bool(info.flags & pq.DQF_ROOT_SQUASH), bool(info.flags & pq.DQF_SYS_FILE))

pq.set_user_quota_info("/dev/sda1", 604800, 604800, 0)  # 1 week grace, no flags

# Format: QFMT_VFS_OLD, QFMT_VFS_V0, or QFMT_VFS_V1
fmt = pq.get_user_quota_format("/dev/sda1")

# Sync quota usage to disk
pq.sync_user_quotas("/dev/sda1")
pq.sync_user_quotas(None)  # all filesystems with active user quotas

Replace user with group or project for group/project quotas. Project quota requires kernel >= 4.1.

Error handling

Errors from the C API are raised as pyquota.APIError (or a subclass) with messages matching the quotactl(2) ERRORS section. Each instance has an errno attribute. Subclasses: PermissionError (EPERM), NotFoundError (ENOENT, ESRCH), InvalidError (EINVAL, etc.); catch pq.APIError or use e.errno.

import pyquota as pq

try:
    pq.get_user_quota("/dev/sda1", 1000)
except pq.PermissionError:
    print("Need root or CAP_SYS_ADMIN")
except pq.NotFoundError as e:
    print("Not found:", e)
except pq.APIError as e:
    print(e, "errno:", e.errno)

Invalid arguments (e.g. empty device path, negative ID) raise ValueError before calling the kernel.

Reference

See the man page for detailed semantics of each command. Type stubs (.pyi) are provided for IDE completion and type checkers. API documentation is built with Sphinx and published at https://tjumyk.github.io/pyquota/ when available.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyquota-0.1.2.tar.gz (16.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyquota-0.1.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (37.9 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

pyquota-0.1.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (34.7 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

pyquota-0.1.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (37.9 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

pyquota-0.1.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (34.8 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

pyquota-0.1.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (39.6 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

pyquota-0.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (36.8 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

pyquota-0.1.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (39.6 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

pyquota-0.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (36.9 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

pyquota-0.1.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (39.2 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

pyquota-0.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl (36.5 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ i686manylinux: glibc 2.5+ i686

File details

Details for the file pyquota-0.1.2.tar.gz.

File metadata

  • Download URL: pyquota-0.1.2.tar.gz
  • Upload date:
  • Size: 16.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for pyquota-0.1.2.tar.gz
Algorithm Hash digest
SHA256 494fb58db048cf5463f2c0205538ac8917a268eabb25d7018d5874521d5f95b8
MD5 a592e0f6293628a6d2a8ba3726fc4a2a
BLAKE2b-256 bd1cfdb288efff3c64ddcc22efcd2db3bf76fbf19c780de5b5b66b23860a78b5

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 58f5353aba31d5d6dbcd9b297b991e9b31fbcb8df6f547fa6f129026fbc26331
MD5 df951a17b52938c3d0eabbd0b336e199
BLAKE2b-256 b86ef7a0fcf8f6debc1d9a62644d9e6b35a019283167c3d41df40ee94612f2c7

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 1873367f9529c744c047e008bbfbb2e47d5505d05d74fd9d59ff371f19957634
MD5 122eaaac509179e96709dea0dd29c007
BLAKE2b-256 d8b7946f0de6c183d52ae2476f53cecad898d48b05b064892d7947fa2c67c26b

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0b8680fd69e12ce23cae2a85d135ee933cf1979026a4736f70b9d8e0e4f7f801
MD5 422aedc536854a298838679b1573d618
BLAKE2b-256 46574b97d7b442943ec4a9781cc4949c142f3a30410b74cded3fa4dc163f6d05

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 fafb2e6d29d9bd0d0ec37629e222f9cb1587bf41384268a33f503fe97c8d708e
MD5 e21def2448f26b9abaf636b83e4edc3f
BLAKE2b-256 46630a5ec5930c8534c3ed2259387143d834b8e71fb235d017ac252ac1fff02f

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 17f8fc57c3732625e78a55ec1e12bf2b37845380b3a0dd8f25635b8820c181bf
MD5 ef14c434ce8549b03cc4dd64b373ae3e
BLAKE2b-256 6a44420198fed260cca141fb438bd79d846eb82d907bf47a09a2bb0f54e9e9dc

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 50808a18b4de72528299054612b89d11093b5776ca33c45cb6b853bab5f45c27
MD5 f814c9b6efab91a9bd8b98c123804cd6
BLAKE2b-256 c6a75aca289d83ad7627e2332ae97f0a5079feacfd54b247971307da52da21f5

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 711a194202b336eca90db492a251498813c98240f5cb66f6bd4c057b3605d5ff
MD5 15a68c6ec21c4cadbb5a22224542fc6b
BLAKE2b-256 5c8d3200d83db7421e21a3becaba5b50e9f67f1bf9a09ba3de7ba111721f12b9

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 fedc30530cfc959e82d5a778db77b70ed001e29657719900ec6406af267280a2
MD5 3068632a54ef65db2a2a3f1524d3acb9
BLAKE2b-256 67a89d42b0c385d0956b7242f7395e6a99d41fb304c5050ec977393d2ee2f9b5

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0ada053a6636739cb7ba758676d44b8d7ee3813d5c7aeaacbb4808b5cc1bfbf9
MD5 4bf41f27aca399be064ff1cdbc7d5f0f
BLAKE2b-256 1cfac43087825aaba905d405740e2751854768ea3bd548c6bf1b83c8d739e449

See more details on using hashes here.

File details

Details for the file pyquota-0.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl.

File metadata

File hashes

Hashes for pyquota-0.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm Hash digest
SHA256 2858abf50f7d731142c7b882bad6fdec841c22c7d5ac760d5b15f64e5d6dbdce
MD5 579cb56f39f1a9796bcac236565afcd5
BLAKE2b-256 184ff54153db06a8ed39d2308cf554b85c04552e66c9b8742057036c24c92d8c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page