Skip to main content

Synchronize requirements.txt to >= installed versions, safely and atomically.

Project description

🧩 reqsync

PyPI Version Python Versions CI Status License Typing: PEP 561

Upgrade a venv and rewrite requirements to >= installed_version, safely and atomically. Preserves extras, markers, comments, encoding, and line endings.


✨ Design goals

  • Safety first Refuse outside a venv by default. Abort on --hash unless you opt in to skipping those stanzas. Atomic writes with rollback.

  • Do one job well Upgrade env, then floor top-level requirements to what’s actually installed. No lockfile management.

  • Zero ceremony Works from the CLI without any config. Optional TOML/pyproject config if you want it.

  • Agent friendly Clean Python API that returns a structured Result for tool-calling, MCP, CrewAI, AG2, etc.


⭐ Features

  • Venv guard on by default; --system-ok to override.
  • Preserves extras [a,b], markers ; sys_platform != "win32", inline comments, encoding (BOM), and newline style (LF/CRLF).
  • Includes recursion: follows -r other.txt by default.
  • Constraints awareness: detects -c constraints.txt and skips modifying unless --update-constraints.
  • Policy modes: lower-bound (default), floor-only, floor-and-cap (< next major).
  • Pre/dev handling: --allow-prerelease to adopt, --keep-local to keep +local suffixes.
  • Hash-aware: refuses by default if --hash is present; --allow-hashes skips those stanzas without editing.
  • File locking with portalocker. Backup + atomic replace. Rollback on failure.
  • UX for humans and CI: --dry-run, --show-diff, --check, --json-report, --only/--exclude.
  • Minimal runtime deps.

🚀 Installation

pip install reqsync

Requires Python 3.8+.


🧪 Quick start

# Activate your venv (required by default)
source .venv/bin/activate

# Preview
reqsync run --path requirements.txt --dry-run --show-diff

# Apply with backup
reqsync run --path requirements.txt --show-diff

Common variations:

# Read-only sync to current env (don’t run pip)
reqsync run --no-upgrade --show-diff

# CI gate: fail if changes would be made
reqsync run --check --no-upgrade --path requirements.txt

🛠️ CLI

reqsync run [OPTIONS]

Key options:

  • --path PATH target requirements (default requirements.txt)
  • --follow-includes / --no-follow-includes follow -r recursively (default true)
  • --update-constraints allow modifying constraint files (default false)
  • --policy [lower-bound|floor-only|floor-and-cap] default lower-bound
  • --allow-prerelease adopt pre/dev; --keep-local keep +local
  • --no-upgrade skip pip install -U -r
  • --pip-args "..." allowlisted pip flags (indexes, proxies, -r, -c)
  • --only PATTERNS and --exclude PATTERNS scope by canonical names
  • --check no writes; exit 11 if changes would be made
  • --dry-run no writes; pair with --show-diff for unified diff
  • --json-report FILE machine-readable changes
  • --backup-suffix S .bak by default; --timestamped-backups/--no-timestamped-backups
  • --system-ok allow outside a venv (not recommended)
  • --allow-hashes skip hashed stanzas instead of refusing

Full option details: see docs/USAGE.md.


⚙️ Configuration

Config is optional. CLI flags always win.

Resolution order:

  1. CLI flags
  2. reqsync.toml at project root
  3. [tool.reqsync] in pyproject.toml
  4. reqsync.json
  5. Built-in defaults

Examples: see docs/CONFIG.md and examples/.


🧬 Policy modes

  • lower-bound Always set >= installed_version.

  • floor-only Only raise existing lower bounds. If none exists, leave it unchanged.

  • floor-and-cap Set >= installed_version,<next_major. Useful guardrail in larger teams.


📁 Includes and constraints

  • -r includes are followed (on by default) and processed with the same rules.
  • -c constraints are detected but not modified unless you pass --update-constraints.

🧵 Preservation rules

  • Lines that are comments, directives (-r, -c, --index-url, etc.), -e/--editable, VCS/URL/local paths are preserved and not edited.
  • Inline comments are preserved. URLs containing # are handled safely.
  • Encoding and newline style are preserved exactly.

🔒 Safety gates

  • Refuses to run outside a venv unless --system-ok.
  • Refuses to edit hashed files (--hash=) by default. Use --allow-hashes to skip those stanzas instead.
  • File lock prevents concurrent edits. Atomic replace with backup and rollback.

🤖 Python API (for agents/tools)

from pathlib import Path
from reqsync._types import Options
from reqsync.core import sync

opts = Options(
    path=Path("requirements.txt"),
    follow_includes=True,
    policy="lower-bound",
    dry_run=True,
    show_diff=True,
    no_upgrade=True,
)
result = sync(opts)
print("Changed:", result.changed)
print(result.diff or "")

More integration patterns: docs/INTEGRATION.md.


📊 Exit codes

Code Meaning
0 Success
1 Generic error
2 Requirements file not found
3 Hashes present without --allow-hashes
4 Pip upgrade failed
5 Parse error
6 Constraint conflict detected
7 Refused to run outside venv without --system-ok
8 Repo dirty and guard blocked (if enabled)
9 Lock acquisition timeout
10 Write failed; backup restored
11 --check and changes would be made

🔄 How this compares

Tool Primary goal Edits your file Hash-aware Lockfile
reqsync Floor to installed (>=) Yes, preserves formatting Refuses or skips No
pip-tools Deterministic pins Generates pinned file Yes Yes
pip-upgrader/pur Bump versions Rewrites pins (==) No No
uv/poetry/pdm Env + lock mgmt Manage lockfiles Yes Yes

Use reqsync when you want your requirements.txt to reflect the versions you’re actually running, while keeping future installs flexible.


📦 Versioning & release

  • Version is derived from Git tags via hatch-vcs. Tag format: vX.Y.Z.
  • Repo: https://github.com/ImYourBoyRoy/reqsync
  • CI: tests, lint, type-check, build, twine metadata check, wheel smoke test.
  • Publishing: PyPI Trusted Publishing via OIDC on tags.

🧰 Development

python -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -e .[dev]
pre-commit install

pre-commit run -a
pytest -q
ruff check .
ruff format --check .
mypy src/reqsync

Contributing guidelines: CONTRIBUTING.md Changelog: CHANGELOG.md


📚 Docs


📜 License

MIT. See LICENSE.


⭐ Support

If this tool helps you, star the repo and share it. Issues and PRs welcome.

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

reqsync-0.1.0.tar.gz (22.6 kB view details)

Uploaded Source

Built Distribution

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

reqsync-0.1.0-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

Details for the file reqsync-0.1.0.tar.gz.

File metadata

  • Download URL: reqsync-0.1.0.tar.gz
  • Upload date:
  • Size: 22.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for reqsync-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d0fb2343232f93e99260b00e705776091edf193d490e92c802ec46714fa7e8ba
MD5 4d912b47f2a9be150bca994b152dac61
BLAKE2b-256 d2ba3d546a98d12c72d0d30dc277fe9e03390b45aee9404915060c240178bf63

See more details on using hashes here.

Provenance

The following attestation bundles were made for reqsync-0.1.0.tar.gz:

Publisher: publish.yml on ImYourBoyRoy/reqsync

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file reqsync-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: reqsync-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for reqsync-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8896309bee09a4fe1c57a1063205b17f87b49ad354574d7332a29e34beafaa7a
MD5 7bc9b7bd1a93571415c240e92e0470d9
BLAKE2b-256 2d97582e7e86c2b3bb21d46cfa55ff6f28fb208e75186975993d268fd7922a88

See more details on using hashes here.

Provenance

The following attestation bundles were made for reqsync-0.1.0-py3-none-any.whl:

Publisher: publish.yml on ImYourBoyRoy/reqsync

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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