depkeeper 0.1.0.dev3__tar.gz → 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- depkeeper-1.0.0/PKG-INFO +428 -0
- depkeeper-1.0.0/README.md +378 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/__init__.py +2 -3
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/__main__.py +6 -4
- depkeeper-1.0.0/depkeeper/__version__.py +11 -0
- depkeeper-1.0.0/depkeeper/cli.py +210 -0
- depkeeper-1.0.0/depkeeper/commands/__init__.py +7 -0
- depkeeper-1.0.0/depkeeper/commands/_report.py +741 -0
- depkeeper-1.0.0/depkeeper/commands/check.py +845 -0
- depkeeper-1.0.0/depkeeper/commands/update.py +1398 -0
- depkeeper-1.0.0/depkeeper/config.py +538 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/constants.py +46 -25
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/context.py +11 -7
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/core/__init__.py +5 -6
- depkeeper-1.0.0/depkeeper/core/checker.py +892 -0
- depkeeper-1.0.0/depkeeper/core/data_store.py +891 -0
- depkeeper-1.0.0/depkeeper/core/dependency_analyzer.py +1321 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/core/parser.py +332 -313
- depkeeper-1.0.0/depkeeper/core/sources/__init__.py +24 -0
- depkeeper-1.0.0/depkeeper/core/sources/base.py +98 -0
- depkeeper-1.0.0/depkeeper/core/sources/conda_yaml.py +395 -0
- depkeeper-1.0.0/depkeeper/core/sources/pyproject_toml.py +588 -0
- depkeeper-1.0.0/depkeeper/core/sources/registry.py +101 -0
- depkeeper-1.0.0/depkeeper/core/sources/requirements_txt.py +161 -0
- depkeeper-1.0.0/depkeeper/core/verify.py +520 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/exceptions.py +56 -16
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/models/__init__.py +5 -6
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/models/conflict.py +29 -16
- depkeeper-1.0.0/depkeeper/models/package.py +407 -0
- depkeeper-1.0.0/depkeeper/models/requirement.py +313 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper/utils/__init__.py +22 -32
- depkeeper-1.0.0/depkeeper/utils/console.py +349 -0
- depkeeper-1.0.0/depkeeper/utils/filesystem.py +517 -0
- depkeeper-1.0.0/depkeeper/utils/http.py +664 -0
- depkeeper-1.0.0/depkeeper/utils/logger.py +193 -0
- depkeeper-1.0.0/depkeeper/utils/naming.py +55 -0
- depkeeper-1.0.0/depkeeper/utils/redact.py +44 -0
- depkeeper-1.0.0/depkeeper/utils/version_utils.py +546 -0
- depkeeper-1.0.0/depkeeper.egg-info/PKG-INFO +428 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper.egg-info/SOURCES.txt +17 -1
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper.egg-info/requires.txt +6 -11
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/pyproject.toml +20 -15
- depkeeper-1.0.0/tests/test_config.py +444 -0
- depkeeper-1.0.0/tests/test_config_allow_major.py +30 -0
- depkeeper-1.0.0/tests/test_config_hardening.py +63 -0
- depkeeper-1.0.0/tests/test_context.py +124 -0
- depkeeper-1.0.0/tests/test_main.py +132 -0
- depkeeper-0.1.0.dev3/PKG-INFO +0 -220
- depkeeper-0.1.0.dev3/README.md +0 -167
- depkeeper-0.1.0.dev3/depkeeper/__version__.py +0 -12
- depkeeper-0.1.0.dev3/depkeeper/cli.py +0 -157
- depkeeper-0.1.0.dev3/depkeeper/commands/__init__.py +0 -0
- depkeeper-0.1.0.dev3/depkeeper/commands/check.py +0 -608
- depkeeper-0.1.0.dev3/depkeeper/commands/update.py +0 -684
- depkeeper-0.1.0.dev3/depkeeper/core/checker.py +0 -458
- depkeeper-0.1.0.dev3/depkeeper/core/data_store.py +0 -645
- depkeeper-0.1.0.dev3/depkeeper/core/dependency_analyzer.py +0 -1011
- depkeeper-0.1.0.dev3/depkeeper/models/package.py +0 -371
- depkeeper-0.1.0.dev3/depkeeper/models/requirement.py +0 -148
- depkeeper-0.1.0.dev3/depkeeper/utils/console.py +0 -238
- depkeeper-0.1.0.dev3/depkeeper/utils/filesystem.py +0 -324
- depkeeper-0.1.0.dev3/depkeeper/utils/http.py +0 -267
- depkeeper-0.1.0.dev3/depkeeper/utils/logger.py +0 -146
- depkeeper-0.1.0.dev3/depkeeper/utils/version_utils.py +0 -92
- depkeeper-0.1.0.dev3/depkeeper.egg-info/PKG-INFO +0 -220
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/LICENSE +0 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper.egg-info/dependency_links.txt +0 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper.egg-info/entry_points.txt +0 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/depkeeper.egg-info/top_level.txt +0 -0
- {depkeeper-0.1.0.dev3 → depkeeper-1.0.0}/setup.cfg +0 -0
depkeeper-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: depkeeper
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Modern Python dependency management for requirements.txt files
|
|
5
|
+
Author: Rahul Kaushal
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/rahulkaushal04/depkeeper
|
|
8
|
+
Project-URL: Documentation, https://github.com/rahulkaushal04/depkeeper/blob/main/docs/index.md
|
|
9
|
+
Project-URL: Repository, https://github.com/rahulkaushal04/depkeeper
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/rahulkaushal04/depkeeper/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/rahulkaushal04/depkeeper/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: dependencies,requirements,pip,package-management,security,updates
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Topic :: System :: Software Distribution
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: click>=8.1.8
|
|
29
|
+
Requires-Dist: packaging>=26.2
|
|
30
|
+
Requires-Dist: httpx[http2]>=0.24.1
|
|
31
|
+
Requires-Dist: rich>=14.3.4
|
|
32
|
+
Requires-Dist: tomli>=2.5.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=7.4.4; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.23.8; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-mock>=3.14.1; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-httpx>=0.22.0; extra == "dev"
|
|
39
|
+
Requires-Dist: mypy>=1.14.1; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff>=0.17.4; extra == "dev"
|
|
41
|
+
Requires-Dist: types-setuptools; extra == "dev"
|
|
42
|
+
Requires-Dist: pre-commit>=3.5.0; extra == "dev"
|
|
43
|
+
Provides-Extra: test
|
|
44
|
+
Requires-Dist: pytest>=7.4.4; extra == "test"
|
|
45
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "test"
|
|
46
|
+
Requires-Dist: pytest-asyncio>=0.23.8; extra == "test"
|
|
47
|
+
Requires-Dist: pytest-mock>=3.14.1; extra == "test"
|
|
48
|
+
Requires-Dist: pytest-httpx>=0.22.0; extra == "test"
|
|
49
|
+
Dynamic: license-file
|
|
50
|
+
|
|
51
|
+
<p align="center"><img src="assets/logo.svg" width="120" alt="depkeeper logo"></p>
|
|
52
|
+
|
|
53
|
+
<h1 align="center">depkeeper</h1>
|
|
54
|
+
|
|
55
|
+
<p align="center"><strong>Safe dependency updates for requirements.txt, pyproject.toml and conda environment.yml.</strong></p>
|
|
56
|
+
|
|
57
|
+
<p align="center">
|
|
58
|
+
<a href="https://github.com/rahulkaushal04/depkeeper/actions/workflows/tests.yml"><img src="https://github.com/rahulkaushal04/depkeeper/actions/workflows/tests.yml/badge.svg" alt="Tests"></a>
|
|
59
|
+
<a href="https://codecov.io/gh/rahulkaushal04/depkeeper"><img src="https://codecov.io/gh/rahulkaushal04/depkeeper/branch/main/graph/badge.svg" alt="Coverage"></a>
|
|
60
|
+
<a href="https://pypi.org/project/depkeeper/"><img src="https://img.shields.io/pypi/v/depkeeper.svg" alt="PyPI"></a>
|
|
61
|
+
<a href="https://pypi.org/project/depkeeper/"><img src="https://img.shields.io/pypi/pyversions/depkeeper.svg" alt="Python versions"></a>
|
|
62
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache-2.0"></a>
|
|
63
|
+
<a href="https://github.com/rahulkaushal04/depkeeper/blob/main/docs/index.md"><img src="https://img.shields.io/badge/docs-in_repo-blue" alt="Docs"></a>
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
<p align="center">
|
|
67
|
+
<a href="#install">Install</a> ·
|
|
68
|
+
<a href="#quick-start">Quick start</a> ·
|
|
69
|
+
<a href="#commands">Commands</a> ·
|
|
70
|
+
<a href="#configuration">Configuration</a> ·
|
|
71
|
+
<a href="#use-it-in-ci">CI</a> ·
|
|
72
|
+
<a href="#limitations">Limitations</a> ·
|
|
73
|
+
<a href="https://github.com/rahulkaushal04/depkeeper/blob/main/docs/index.md">Docs</a>
|
|
74
|
+
</p>
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
depkeeper is a command-line tool. It reads your dependency file, asks PyPI what is newer, and picks the
|
|
79
|
+
newest version that is **safe** for each package. Then it edits the file in place.
|
|
80
|
+
|
|
81
|
+
It keeps the ranges you wrote. It never jumps a major version. It does not install anything.
|
|
82
|
+
|
|
83
|
+
## Why
|
|
84
|
+
|
|
85
|
+
`pip list --outdated` shows the latest release. That is often a new major version that breaks your build.
|
|
86
|
+
|
|
87
|
+
depkeeper answers one question:
|
|
88
|
+
|
|
89
|
+
> What is the newest version of each dependency I can take without crossing a major version, without
|
|
90
|
+
> breaking Python compatibility, without violating the constraints I wrote, and without conflicting with
|
|
91
|
+
> the other packages in my file?
|
|
92
|
+
|
|
93
|
+
| | `pip list --outdated` | pip-tools | depkeeper |
|
|
94
|
+
|---|---|---|---|
|
|
95
|
+
| Shows newer versions | ✓ (latest only) | – | ✓ (latest and a safe target) |
|
|
96
|
+
| Respects major-version boundaries | – | – | ✓ |
|
|
97
|
+
| Edits your existing file, keeps your ranges | – | regenerates from `.in` | ✓ |
|
|
98
|
+
| Needs a new file format or lock file | no | `.in` files | no |
|
|
99
|
+
| Resolves the full transitive graph | at install time | ✓ | – (see [Limitations](#limitations)) |
|
|
100
|
+
|
|
101
|
+
depkeeper does not replace a resolver. Run `pip install` and your tests after every update.
|
|
102
|
+
|
|
103
|
+
## Features
|
|
104
|
+
|
|
105
|
+
**Safe recommendations**
|
|
106
|
+
- Stays inside the current major version (`1.x` is never moved to `2.x`).
|
|
107
|
+
- Skips releases whose `requires_python` excludes your target Python.
|
|
108
|
+
- Keeps upper bounds, exclusions and `~=` ranges. Only the lower bound moves.
|
|
109
|
+
- Never recommends yanked releases. Pre-releases are excluded unless a package sets `allow_prerelease = true` in config.
|
|
110
|
+
- Calendar-versioned packages (such as `certifi`) are detected and labelled `year`, `month` or `patch`.
|
|
111
|
+
- Cross-checks the recommended versions against each other and backs off on conflicts.
|
|
112
|
+
|
|
113
|
+
**File formats**
|
|
114
|
+
- `requirements*.txt` (including `-r` and `-c` files)
|
|
115
|
+
- `pyproject.toml` (PEP 621, PEP 735 dependency groups, `build-system.requires`, Poetry), edited without touching comments or formatting
|
|
116
|
+
- conda `environment.yml` (`dependencies:` and `pip:` lists)
|
|
117
|
+
|
|
118
|
+
**Policy and cooldown**
|
|
119
|
+
- `--min-age 7d` skips versions released too recently.
|
|
120
|
+
- `hold`, `ignore`, `max_update`, `allow_major`, `allow_prerelease` and `versioning` per package, in config.
|
|
121
|
+
- `--ignore PKG` and `--max-update {patch,minor,major}` on the command line.
|
|
122
|
+
- `--allow-major PKG` opts a package into a major upgrade (default: never crosses a major; newer majors are reported).
|
|
123
|
+
|
|
124
|
+
**CI gating**
|
|
125
|
+
- `check --fail-on {none,updates,minor,major}` exits `3` when updates at that level exist.
|
|
126
|
+
- Exit `4` when a package could not be looked up. A failed lookup is never reported as "up to date".
|
|
127
|
+
|
|
128
|
+
**Safe writes**
|
|
129
|
+
- Atomic file replacement, with rollback for multi-file updates.
|
|
130
|
+
- `--backup` saves a timestamped copy of every file it changes.
|
|
131
|
+
- Refuses to drop `--hash` lines unless you say so. `--refresh-hashes` regenerates them from PyPI digests.
|
|
132
|
+
- Aborts if a file changed on disk since it was read.
|
|
133
|
+
|
|
134
|
+
**Verify before writing**
|
|
135
|
+
- `update --verify` asks pip's resolver whether the new set resolves for your target Python (wheels only, nothing is built). On a conflict, nothing is written, and success states what was checked.
|
|
136
|
+
|
|
137
|
+
**Output formats** (`check --format`)
|
|
138
|
+
|
|
139
|
+
| Format | Use it for |
|
|
140
|
+
|---|---|
|
|
141
|
+
| `table` | Reading in a terminal (default) |
|
|
142
|
+
| `simple` | Plain lines, easy to grep |
|
|
143
|
+
| `json` | Bare array of packages |
|
|
144
|
+
| `json-v2` | Versioned envelope with file, line, age and links |
|
|
145
|
+
| `markdown` | A report for a PR body or CI summary |
|
|
146
|
+
|
|
147
|
+
For `simple`, `json`, `json-v2` and `markdown`, only the payload goes to stdout. Logs and warnings go to
|
|
148
|
+
stderr, so `depkeeper -v check -f json | jq` works.
|
|
149
|
+
|
|
150
|
+
## Install
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python -m pip install depkeeper # into your project's environment
|
|
154
|
+
pipx install depkeeper # or as an isolated tool
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Requires Python 3.8 or newer.
|
|
158
|
+
|
|
159
|
+
> [!IMPORTANT]
|
|
160
|
+
> depkeeper only proposes versions that support your **target Python**. It picks that version in this
|
|
161
|
+
> order: `--python-version X.Y`, the `python_version` config key, the file's own `requires-python` (or
|
|
162
|
+
> conda `python` pin), then the Python that runs depkeeper. If your project targets 3.12 and none of the
|
|
163
|
+
> first three is set, run depkeeper on 3.12 or pass `--python-version 3.12`.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
depkeeper --version
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Quick start
|
|
170
|
+
|
|
171
|
+
Start with a small `requirements.txt`:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
requests==2.28.0
|
|
175
|
+
flask>=2.0,<2.3
|
|
176
|
+
click~=8.0
|
|
177
|
+
urllib3==1.26.0
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**1. Look (read-only).** The output below is real, captured on the date of writing. Versions and ages will
|
|
181
|
+
differ when you run it.
|
|
182
|
+
|
|
183
|
+
```console
|
|
184
|
+
$ depkeeper check --format simple
|
|
185
|
+
[OUTDATED] requests 2.28.0 → 2.34.2
|
|
186
|
+
released 175 days ago
|
|
187
|
+
Python: installed: >=3.7, <4, latest: >=3.10, recommended: >=3.10
|
|
188
|
+
[OUTDATED] flask 2.0 → 3.1.3 (recommended: 2.2.5)
|
|
189
|
+
released 1283 days ago
|
|
190
|
+
Python: latest: >=3.9, recommended: >=3.7
|
|
191
|
+
[OUTDATED] click 8.0 → 8.5.0
|
|
192
|
+
released 72 days ago
|
|
193
|
+
Python: latest: >=3.10, recommended: >=3.10
|
|
194
|
+
[OUTDATED] urllib3 1.26.0 → 2.8.0 (recommended: 1.26.20)
|
|
195
|
+
released 798 days ago
|
|
196
|
+
Python: installed: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4, latest: >=3.10, recommended: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Read `recommended` as "what depkeeper will write". `flask` stays on 2.2.5 because of your `<2.3` cap.
|
|
200
|
+
`urllib3` stays on 1.x because 2.x is a major jump.
|
|
201
|
+
|
|
202
|
+
**2. Preview the write.**
|
|
203
|
+
|
|
204
|
+
```console
|
|
205
|
+
$ depkeeper update --dry-run
|
|
206
|
+
[WARNING] major available: urllib3 2.8.0 (use --allow-major urllib3)
|
|
207
|
+
Update Plan (Dry Run)
|
|
208
|
+
┏━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
209
|
+
┃ Package ┃ Current ┃ New Version ┃ Change ┃ Python Requires ┃
|
|
210
|
+
┡━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
|
211
|
+
│ requests │ 2.28.0 │ 2.34.2 │ minor │ >=3.10 │
|
|
212
|
+
│ flask │ 2.0 │ 2.2.5 │ minor │ >=3.7 │
|
|
213
|
+
│ click │ 8.0 │ 8.5.0 │ minor │ >=3.10 │
|
|
214
|
+
│ urllib3 │ 1.26.0 │ 1.26.20 │ patch │ !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2. │
|
|
215
|
+
└──────────┴─────────┴─────────────┴────────┴──────────────────────────────────────────────────────┘
|
|
216
|
+
Dry run mode - no changes applied
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
(The real table also prints a `175d old`-style age under each new version. It is trimmed here.)
|
|
220
|
+
|
|
221
|
+
**3. Apply.**
|
|
222
|
+
|
|
223
|
+
```console
|
|
224
|
+
$ depkeeper update --backup --yes
|
|
225
|
+
[OK] Backup saved: requirements.txt.20261106_182111_458701_7f45f023.backup
|
|
226
|
+
[OK] Successfully updated 4 package(s)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```text
|
|
230
|
+
requests==2.34.2
|
|
231
|
+
flask>=2.2.5,<2.3
|
|
232
|
+
click~=8.5
|
|
233
|
+
urllib3==1.26.20
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Only the lower bounds moved. `<2.3` stayed. `~=` stayed. Add `--pin` if you want exact `==` pins instead.
|
|
237
|
+
|
|
238
|
+
**4. Test.**
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
python -m pip install -r requirements.txt && pytest
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Supported files
|
|
245
|
+
|
|
246
|
+
| File | Read | Written | Notes |
|
|
247
|
+
|---|---|---|---|
|
|
248
|
+
| `requirements*.txt` | ✓ | ✓ | `-r` includes are followed and rewritten. `-c` constraint files are read, never rewritten. |
|
|
249
|
+
| `pyproject.toml` | ✓ | ✓ | PEP 621, PEP 735 groups, `build-system.requires`, Poetry. Comments and layout are kept. |
|
|
250
|
+
| conda `environment.yml` | ✓ | ✓ | Conda packages are looked up on PyPI by name. This is approximate. |
|
|
251
|
+
| `Pipfile`, `poetry.lock`, `setup.py`, `setup.cfg` | – | – | Not supported. |
|
|
252
|
+
|
|
253
|
+
Editable installs, VCS URLs, direct URLs and local paths are reported but never changed.
|
|
254
|
+
|
|
255
|
+
## Commands
|
|
256
|
+
|
|
257
|
+
```text
|
|
258
|
+
depkeeper [-c FILE] [-v|-vv] [--color|--no-color] COMMAND [FILE]
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Global options go before the command: `depkeeper -v check`. `FILE` defaults to `requirements.txt`.
|
|
262
|
+
|
|
263
|
+
| Command | What it does |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `depkeeper check` | Report available updates. Never writes. |
|
|
266
|
+
| `depkeeper check --outdated-only` | Hide packages that are up to date. |
|
|
267
|
+
| `depkeeper check -f json` | Machine-readable output (`simple`, `json`, `json-v2`, `markdown`, `table`). |
|
|
268
|
+
| `depkeeper check --fail-on minor` | Exit `3` if a minor or major update exists. |
|
|
269
|
+
| `depkeeper check --min-age 7d` | Ignore versions released in the last 7 days. |
|
|
270
|
+
| `depkeeper check --python-version 3.12` | Pick versions that support Python 3.12. |
|
|
271
|
+
| `depkeeper check --ignore PKG` | Skip a package (repeatable). |
|
|
272
|
+
| `depkeeper update --allow-major django` | Let `django` cross its major, within your declared bounds. |
|
|
273
|
+
| `depkeeper update --dry-run` | Show the plan. Write nothing. |
|
|
274
|
+
| `depkeeper update -y` | Apply without the confirmation prompt. |
|
|
275
|
+
| `depkeeper update --backup` | Save a timestamped backup of every file first. |
|
|
276
|
+
| `depkeeper update --verify` | Check with pip's resolver before writing. |
|
|
277
|
+
| `depkeeper update --pin` | Write exact `==` pins. |
|
|
278
|
+
| `depkeeper update -p NAME` | Update only these packages (repeatable). |
|
|
279
|
+
| `depkeeper update --ignore NAME` | Never update these packages (repeatable). |
|
|
280
|
+
| `depkeeper update --max-update minor` | Skip updates larger than `minor`. |
|
|
281
|
+
| `depkeeper update --refresh-hashes` | Regenerate `--hash` lines for the new version. |
|
|
282
|
+
| `depkeeper update --allow-hash-removal` | Update hashed requirements and drop their hashes. |
|
|
283
|
+
| `depkeeper update -f markdown` | Print a PR description of the changes (needs `--yes` or `--dry-run`). |
|
|
284
|
+
|
|
285
|
+
Both commands also accept `--strict-version-matching` and `--check-conflicts / --no-check-conflicts`.
|
|
286
|
+
`--refresh-hashes` and `--allow-hash-removal` cannot be used together.
|
|
287
|
+
|
|
288
|
+
Full flag reference: [CLI commands](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/reference/cli-commands.md).
|
|
289
|
+
|
|
290
|
+
### Exit codes
|
|
291
|
+
|
|
292
|
+
| Code | Meaning |
|
|
293
|
+
|---|---|
|
|
294
|
+
| `0` | Success. Updates being available is **not** an error. |
|
|
295
|
+
| `1` | Error (bad file, bad config, write failed, `--verify` found a conflict, hash removal refused). `update` also exits `1` if you decline the prompt or `--packages` matches nothing. |
|
|
296
|
+
| `2` | Usage error. |
|
|
297
|
+
| `3` | `check --fail-on`: updates at or above the chosen level exist. |
|
|
298
|
+
| `4` | A package could not be looked up on PyPI. |
|
|
299
|
+
| `130` | Interrupted. |
|
|
300
|
+
|
|
301
|
+
## Configuration
|
|
302
|
+
|
|
303
|
+
Put settings in `depkeeper.toml` (table `[depkeeper]`) or in `pyproject.toml` (table `[tool.depkeeper]`).
|
|
304
|
+
depkeeper looks in the current directory, then its parents up to the repository root. A command-line flag
|
|
305
|
+
always beats the config file.
|
|
306
|
+
|
|
307
|
+
```toml
|
|
308
|
+
# depkeeper.toml
|
|
309
|
+
[depkeeper]
|
|
310
|
+
min_age = "7d" # cooldown: skip releases newer than 7 days
|
|
311
|
+
fail_on = "minor" # `check` exits 3 on minor or major updates
|
|
312
|
+
python_version = "3.12" # target Python for compatibility filtering
|
|
313
|
+
ignore = ["boto3"] # never touch these
|
|
314
|
+
check_conflicts = true
|
|
315
|
+
|
|
316
|
+
[depkeeper.packages.django]
|
|
317
|
+
max_update = "patch" # django: patch updates only
|
|
318
|
+
|
|
319
|
+
[depkeeper.packages.flask]
|
|
320
|
+
hold = true # flask: report, but do not update
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Keys: `check_conflicts`, `strict_version_matching`, `fail_on`, `ignore`, `python_version`, `min_age`,
|
|
324
|
+
`versioning`, `packages`. Unknown keys are an error. Details:
|
|
325
|
+
[Configuration options](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/reference/configuration-options.md).
|
|
326
|
+
|
|
327
|
+
## Use it in CI
|
|
328
|
+
|
|
329
|
+
`check` exits `0` even when updates exist. Use `--fail-on` to make a pipeline fail on drift. A scheduled
|
|
330
|
+
job that fails when a minor or major update is waiting:
|
|
331
|
+
|
|
332
|
+
```yaml
|
|
333
|
+
# .github/workflows/dependency-drift.yml
|
|
334
|
+
name: Dependency drift
|
|
335
|
+
on:
|
|
336
|
+
schedule:
|
|
337
|
+
- cron: "0 6 * * 1" # Mondays, 06:00 UTC
|
|
338
|
+
workflow_dispatch:
|
|
339
|
+
|
|
340
|
+
permissions:
|
|
341
|
+
contents: read
|
|
342
|
+
|
|
343
|
+
jobs:
|
|
344
|
+
check:
|
|
345
|
+
runs-on: ubuntu-latest
|
|
346
|
+
steps:
|
|
347
|
+
- uses: actions/checkout@v4
|
|
348
|
+
- uses: actions/setup-python@v5
|
|
349
|
+
with:
|
|
350
|
+
python-version: "3.12"
|
|
351
|
+
- run: python -m pip install "depkeeper==X.Y.Z" # pin to a release you have tested: recommendations are behaviour
|
|
352
|
+
- run: depkeeper check --fail-on minor --min-age 7d
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
The job fails on exit `3` (updates found) and on exit `4` (a lookup failed). To publish a report instead of
|
|
356
|
+
failing, drop `--fail-on` and add `--format markdown >> "$GITHUB_STEP_SUMMARY"`.
|
|
357
|
+
|
|
358
|
+
<details>
|
|
359
|
+
<summary>Open an update PR instead</summary>
|
|
360
|
+
|
|
361
|
+
`update --format markdown` prints a PR body. Pair it with any pull-request action.
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
depkeeper update --yes --verify --format markdown > pr-body.md
|
|
365
|
+
python -m pip install -r requirements.txt && pytest
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
`--verify` aborts with exit `1` and writes nothing if pip's resolver rejects the new set.
|
|
369
|
+
More patterns: [CI/CD integration](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/guides/ci-cd-integration.md).
|
|
370
|
+
|
|
371
|
+
</details>
|
|
372
|
+
|
|
373
|
+
## How it works
|
|
374
|
+
|
|
375
|
+
<p align="center"><img src="assets/diagrams/how-it-works.svg" alt="depkeeper parses your dependency file, fetches PyPI metadata, filters each package down to one safe version (staying within its major unless --allow-major), cross-checks the picks, then reports or writes." width="900"></p>
|
|
376
|
+
|
|
377
|
+
<p align="center"><em>Candidate versions pass through six named rules to one pick; only the write branch touches your files.</em></p>
|
|
378
|
+
|
|
379
|
+
depkeeper is a synchronous CLI around an async core. It keeps no cache and no state between runs.
|
|
380
|
+
Design notes: [ARCHITECTURE.md](ARCHITECTURE.md).
|
|
381
|
+
|
|
382
|
+
## Limitations
|
|
383
|
+
|
|
384
|
+
- **Not a full resolver.** depkeeper cross-checks the packages you declared using each version's direct
|
|
385
|
+
dependencies. It does not expand the transitive graph. `update --verify` and `pip install` are the
|
|
386
|
+
real test.
|
|
387
|
+
- **PyPI only.** `--index-url`, `--extra-index-url` and `--find-links` are parsed and ignored.
|
|
388
|
+
Packages that exist only on a private index show up as errors.
|
|
389
|
+
- **Major upgrades are opt-in.** A floor of `django>=3.2,<5.0` stays on the newest `3.x` and reports the
|
|
390
|
+
newer major. Use `--allow-major django` to move to the newest `4.x` (your `<5.0` is still respected).
|
|
391
|
+
- **conda is approximate.** Conda-channel packages are matched to PyPI by name. A missing match is a
|
|
392
|
+
warning, not a failure.
|
|
393
|
+
- **Pre-releases are off by default.** There is no `--pre` flag; opt in per package with `allow_prerelease = true`.
|
|
394
|
+
- **No security scanning.** Use `pip-audit` or similar next to depkeeper.
|
|
395
|
+
- **No cache.** Every run fetches metadata again.
|
|
396
|
+
- **Hash removal leaves a partly hashed file.** `pip install --require-hashes` rejects that. Prefer
|
|
397
|
+
`--refresh-hashes`.
|
|
398
|
+
- **Direct references are never updated.** VCS, URL, local path and editable requirements are reported only.
|
|
399
|
+
|
|
400
|
+
Full list: [Known limitations](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/reference/limitations.md).
|
|
401
|
+
|
|
402
|
+
## Documentation
|
|
403
|
+
|
|
404
|
+
Full docs: **[docs/](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/index.md)**
|
|
405
|
+
|
|
406
|
+
- [Getting started](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/getting-started/index.md)
|
|
407
|
+
- [Concepts](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/concepts/index.md): how versions are recommended, how conflicts are resolved, write safety
|
|
408
|
+
- [Guides](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/guides/index.md): checking, updating, configuration, CI/CD, troubleshooting
|
|
409
|
+
- [Reference](https://github.com/rahulkaushal04/depkeeper/blob/main/docs/reference/index.md): CLI, config, exit codes, file formats, JSON output
|
|
410
|
+
- [CHANGELOG.md](CHANGELOG.md)
|
|
411
|
+
|
|
412
|
+
## Contributing
|
|
413
|
+
|
|
414
|
+
Issues and pull requests are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
git clone https://github.com/rahulkaushal04/depkeeper.git
|
|
418
|
+
cd depkeeper
|
|
419
|
+
pip install -e ".[dev]"
|
|
420
|
+
python -m pytest tests -q --no-cov
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Report security problems privately. See [SECURITY.md](SECURITY.md). Please follow the
|
|
424
|
+
[Code of Conduct](CODE_OF_CONDUCT.md).
|
|
425
|
+
|
|
426
|
+
## License
|
|
427
|
+
|
|
428
|
+
[Apache License 2.0](LICENSE). Copyright 2025-2026 Rahul Kaushal.
|