depkeeper 0.1.0.dev2__tar.gz → 0.1.1__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-0.1.1/PKG-INFO +474 -0
- depkeeper-0.1.1/README.md +417 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper/__init__.py +2 -3
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper/__main__.py +3 -4
- depkeeper-0.1.1/depkeeper/__version__.py +11 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper/cli.py +31 -14
- depkeeper-0.1.1/depkeeper/commands/__init__.py +7 -0
- depkeeper-0.1.1/depkeeper/commands/check.py +625 -0
- depkeeper-0.1.1/depkeeper/commands/update.py +959 -0
- depkeeper-0.1.1/depkeeper/config.py +307 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper/constants.py +57 -4
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper/context.py +11 -7
- depkeeper-0.1.1/depkeeper/core/__init__.py +26 -0
- depkeeper-0.1.1/depkeeper/core/checker.py +505 -0
- depkeeper-0.1.1/depkeeper/core/data_store.py +766 -0
- depkeeper-0.1.1/depkeeper/core/dependency_analyzer.py +1273 -0
- depkeeper-0.1.1/depkeeper/core/parser.py +1095 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper/exceptions.py +33 -6
- depkeeper-0.1.1/depkeeper/models/__init__.py +22 -0
- depkeeper-0.1.1/depkeeper/models/conflict.py +164 -0
- depkeeper-0.1.1/depkeeper/models/package.py +365 -0
- depkeeper-0.1.1/depkeeper/models/requirement.py +207 -0
- depkeeper-0.1.1/depkeeper/utils/__init__.py +122 -0
- depkeeper-0.1.1/depkeeper/utils/console.py +301 -0
- depkeeper-0.1.1/depkeeper/utils/filesystem.py +506 -0
- depkeeper-0.1.1/depkeeper/utils/http.py +384 -0
- depkeeper-0.1.1/depkeeper/utils/logger.py +167 -0
- depkeeper-0.1.1/depkeeper/utils/naming.py +55 -0
- depkeeper-0.1.1/depkeeper/utils/version_utils.py +393 -0
- depkeeper-0.1.1/depkeeper.egg-info/PKG-INFO +474 -0
- depkeeper-0.1.1/depkeeper.egg-info/SOURCES.txt +39 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper.egg-info/requires.txt +8 -3
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/pyproject.toml +20 -9
- depkeeper-0.1.1/tests/test_config.py +400 -0
- depkeeper-0.1.1/tests/test_context.py +122 -0
- depkeeper-0.1.1/tests/test_main.py +129 -0
- depkeeper-0.1.0.dev2/PKG-INFO +0 -218
- depkeeper-0.1.0.dev2/README.md +0 -167
- depkeeper-0.1.0.dev2/depkeeper/__version__.py +0 -12
- depkeeper-0.1.0.dev2/depkeeper.egg-info/PKG-INFO +0 -218
- depkeeper-0.1.0.dev2/depkeeper.egg-info/SOURCES.txt +0 -16
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/LICENSE +0 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper.egg-info/dependency_links.txt +0 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper.egg-info/entry_points.txt +0 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/depkeeper.egg-info/top_level.txt +0 -0
- {depkeeper-0.1.0.dev2 → depkeeper-0.1.1}/setup.cfg +0 -0
depkeeper-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: depkeeper
|
|
3
|
+
Version: 0.1.1
|
|
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://rahulkaushal04.github.io/depkeeper/
|
|
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 :: 4 - Beta
|
|
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>=23.2
|
|
30
|
+
Requires-Dist: httpx[http2]>=0.24.1
|
|
31
|
+
Requires-Dist: rich>=13.9.4
|
|
32
|
+
Requires-Dist: tomli>=2.4.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=7.4.4; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov>=4.1.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: types-setuptools; extra == "dev"
|
|
41
|
+
Requires-Dist: pre-commit>=3.5.0; extra == "dev"
|
|
42
|
+
Provides-Extra: test
|
|
43
|
+
Requires-Dist: pytest>=7.4.4; extra == "test"
|
|
44
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "test"
|
|
45
|
+
Requires-Dist: pytest-asyncio>=0.23.8; extra == "test"
|
|
46
|
+
Requires-Dist: pytest-mock>=3.14.1; extra == "test"
|
|
47
|
+
Requires-Dist: pytest-httpx>=0.22.0; extra == "test"
|
|
48
|
+
Provides-Extra: docs
|
|
49
|
+
Requires-Dist: mkdocs<2.0,>=1.6.1; extra == "docs"
|
|
50
|
+
Requires-Dist: mkdocs-material<10.0,>=9.7.1; extra == "docs"
|
|
51
|
+
Requires-Dist: mkdocstrings[python]<2.0,>=0.26.1; extra == "docs"
|
|
52
|
+
Requires-Dist: pymdown-extensions<11.0,>=10.15; extra == "docs"
|
|
53
|
+
Requires-Dist: mkdocs-minify-plugin<1.0,>=0.8.0; extra == "docs"
|
|
54
|
+
Requires-Dist: mike<3.0,>=2.2.0; extra == "docs"
|
|
55
|
+
Requires-Dist: black>=24.10.0; extra == "docs"
|
|
56
|
+
Dynamic: license-file
|
|
57
|
+
|
|
58
|
+
# depkeeper
|
|
59
|
+
|
|
60
|
+
[](https://github.com/rahulkaushal04/depkeeper/actions/workflows/tests.yml)
|
|
61
|
+
[](https://codecov.io/gh/rahulkaushal04/depkeeper)
|
|
62
|
+
[](https://pypi.org/project/depkeeper/)
|
|
63
|
+
[](https://pypi.org/project/depkeeper/)
|
|
64
|
+
[](LICENSE)
|
|
65
|
+
[](https://rahulkaushal04.github.io/depkeeper/)
|
|
66
|
+
|
|
67
|
+
**Safe, conflict-aware dependency updates for pip requirements files.**
|
|
68
|
+
|
|
69
|
+
depkeeper analyses `requirements.txt`-style files, computes a safe upgrade target for every
|
|
70
|
+
requirement, cross-validates those targets against each other, and rewrites the file in place —
|
|
71
|
+
without discarding the constraints you authored.
|
|
72
|
+
|
|
73
|
+
It is a single-purpose CLI. It does not manage virtual environments, install packages, replace
|
|
74
|
+
`pip`, or introduce a lock file format.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Contents
|
|
79
|
+
|
|
80
|
+
- [Why depkeeper](#why-depkeeper) · [What it guarantees](#what-it-guarantees)
|
|
81
|
+
- [Install](#install) · [Quick start](#quick-start) · [Commands](#commands)
|
|
82
|
+
- [Configuration](#configuration) · [Common workflows](#common-workflows)
|
|
83
|
+
- [Architecture](#architecture) · [Limitations](#limitations)
|
|
84
|
+
- [Troubleshooting](#troubleshooting) · [Documentation](#documentation) · [Contributing](#contributing)
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Why depkeeper
|
|
89
|
+
|
|
90
|
+
`pip list --outdated` reports the **latest** version, which is frequently a major release that
|
|
91
|
+
will break your build. Lock-file tools solve this properly but require adopting a new workflow and
|
|
92
|
+
file format.
|
|
93
|
+
|
|
94
|
+
depkeeper fills the gap. It answers one question, precisely:
|
|
95
|
+
|
|
96
|
+
> What is the largest upgrade I can take for each requirement **without** crossing a major
|
|
97
|
+
> version, **without** breaking Python compatibility, **without** violating the constraints I
|
|
98
|
+
> declared, and **without** conflicting with the other packages in my file?
|
|
99
|
+
|
|
100
|
+
Then it applies the answer to the file you already have.
|
|
101
|
+
|
|
102
|
+
| | pip | pip-tools | Poetry | depkeeper |
|
|
103
|
+
|---|---|---|---|---|
|
|
104
|
+
| Reports available updates | latest only | no | yes | yes, with a *safe* target |
|
|
105
|
+
| Enforces major-version boundaries | no | no | no | **yes** |
|
|
106
|
+
| Preserves your declared ranges on write | n/a | regenerates | rewrites | **yes** |
|
|
107
|
+
| Full transitive resolution | at install time | yes | yes | no — see [Limitations](#limitations) |
|
|
108
|
+
| Requires a new file format | no | `.in` files | `pyproject.toml` + lock | **no** |
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## What it guarantees
|
|
113
|
+
|
|
114
|
+
These are enforced in code, not advisory:
|
|
115
|
+
|
|
116
|
+
| Guarantee | Meaning |
|
|
117
|
+
|---|---|
|
|
118
|
+
| **Major-version boundary** | A package on `1.x` is never moved to `2.x`. |
|
|
119
|
+
| **Python compatibility** | Releases whose `requires_python` excludes your interpreter are never proposed. |
|
|
120
|
+
| **Constraint preservation** | Upper bounds, exclusions and `~=` bands are preserved verbatim and never violated. |
|
|
121
|
+
| **No pre-releases** | Alpha/beta/rc versions are excluded from every candidate list. |
|
|
122
|
+
| **Atomic, reversible writes** | Multi-file updates are all-or-nothing, with rollback and optional backups. |
|
|
123
|
+
| **Hash integrity** | Updates that would strip `--hash` entries are refused unless explicitly allowed. |
|
|
124
|
+
| **Clean stdout** | `--format json` puts the payload on stdout and every diagnostic on stderr. |
|
|
125
|
+
| **Idempotency** | Re-running produces no change. Safe to run on a schedule. |
|
|
126
|
+
|
|
127
|
+
The trade-off is explicit: depkeeper is deliberately conservative. It will never propose the major
|
|
128
|
+
upgrade you eventually need.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Install
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
python -m pip install depkeeper # into the project's environment (recommended)
|
|
136
|
+
pipx install depkeeper # isolated global tool
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Requires **Python 3.8+**.
|
|
140
|
+
|
|
141
|
+
> [!IMPORTANT]
|
|
142
|
+
> depkeeper filters candidate versions against **the interpreter it runs on**, not your project's.
|
|
143
|
+
> Installing it on 3.8 while your service targets 3.12 makes recommendations silently
|
|
144
|
+
> conservative. Install it into the project environment, or use
|
|
145
|
+
> `pipx install --python python3.12 depkeeper`.
|
|
146
|
+
|
|
147
|
+
Verify:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
depkeeper --version # depkeeper 0.1.1
|
|
151
|
+
python -m depkeeper --help # equivalent module entry point
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Quick start
|
|
157
|
+
|
|
158
|
+
Given this file:
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
requests==2.28.0
|
|
162
|
+
flask>=2.0,<2.3
|
|
163
|
+
celery[redis]>=5.0,<6.0
|
|
164
|
+
click~=8.0
|
|
165
|
+
certifi
|
|
166
|
+
urllib3==1.26.0
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**1. Inspect (read-only, never writes):**
|
|
170
|
+
|
|
171
|
+
```console
|
|
172
|
+
$ depkeeper check
|
|
173
|
+
┏━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━┓
|
|
174
|
+
┃ Status ┃ Package ┃ Current ┃ Latest ┃ Recommended ┃ Update Type ┃ Conflicts ┃
|
|
175
|
+
┡━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━┩
|
|
176
|
+
│ [OUTDATED] │ requests │ 2.28.0 │ 2.34.2 │ 2.34.2 │ minor │ - │
|
|
177
|
+
│ [OUTDATED] │ flask │ 2.0 │ 3.1.3 │ 2.2.5 │ minor │ - │
|
|
178
|
+
│ [OUTDATED] │ celery │ 5.0 │ 5.6.3 │ 5.6.3 │ minor │ - │
|
|
179
|
+
│ [OUTDATED] │ click │ 8.0 │ 8.4.2 │ 8.4.2 │ minor │ - │
|
|
180
|
+
│ [OK] │ certifi │ - │ 2026.7.22 │ - │ - │ - │
|
|
181
|
+
│ [OUTDATED] │ urllib3 │ 1.26.0 │ 2.7.0 │ 1.26.20 │ patch │ - │
|
|
182
|
+
└────────────┴──────────┴─────────┴───────────┴─────────────┴─────────────┴───────────┘
|
|
183
|
+
[WARNING] 5 package(s) have updates available
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**2. Preview the exact write:**
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
depkeeper update --dry-run
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**3. Apply:**
|
|
193
|
+
|
|
194
|
+
```console
|
|
195
|
+
$ depkeeper update --backup
|
|
196
|
+
Update 6 packages? (y, n) [y]: y
|
|
197
|
+
[OK] ✓ Successfully updated 6 package(s)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```text
|
|
201
|
+
requests==2.34.2
|
|
202
|
+
flask>=2.2.5,<2.3 # your <2.3 cap held — latest is 3.1.3
|
|
203
|
+
celery[redis]>=5.6.3,<6.0 # extra and upper bound preserved
|
|
204
|
+
click~=8.4 # compatible-release form preserved
|
|
205
|
+
certifi==2026.7.22 # unversioned requirement gained a pin
|
|
206
|
+
urllib3==1.26.20 # major boundary held — latest is 2.7.0
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**4. Verify — this step is not optional:**
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
python -m pip install -r requirements.txt && pytest
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
depkeeper validates the packages you declared against each other. It does not expand the
|
|
216
|
+
transitive graph, so `pip` remains the authority on whether the set installs.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Commands
|
|
221
|
+
|
|
222
|
+
### `depkeeper check [FILE]`
|
|
223
|
+
|
|
224
|
+
Read-only analysis. Never modifies the filesystem. Exits `0` on success regardless of findings.
|
|
225
|
+
|
|
226
|
+
| Option | Description |
|
|
227
|
+
|---|---|
|
|
228
|
+
| `--outdated-only` | Show only packages with an update or a conflict |
|
|
229
|
+
| `-f`, `--format table\|simple\|json` | Output format (default `table`) |
|
|
230
|
+
| `--strict-version-matching` | Only a sole `==` pin counts as a current version |
|
|
231
|
+
| `--check-conflicts` / `--no-check-conflicts` | Cross-package conflict resolution (default on) |
|
|
232
|
+
|
|
233
|
+
### `depkeeper update [FILE]`
|
|
234
|
+
|
|
235
|
+
Applies recommended versions in place.
|
|
236
|
+
|
|
237
|
+
| Option | Description |
|
|
238
|
+
|---|---|
|
|
239
|
+
| `--dry-run` | Run the full pipeline, print the plan, write nothing |
|
|
240
|
+
| `-y`, `--yes` | Skip the confirmation prompt |
|
|
241
|
+
| `--backup` | Timestamped backup of **every** affected file before writing |
|
|
242
|
+
| `--pin` | Replace every specifier with an exact `==` pin |
|
|
243
|
+
| `--allow-hash-removal` | Permit updating `--hash`-pinned requirements (removes the digests) |
|
|
244
|
+
| `-p`, `--packages NAME` | Restrict to specific packages (repeatable) |
|
|
245
|
+
| `--strict-version-matching` | As above |
|
|
246
|
+
| `--check-conflicts` / `--no-check-conflicts` | As above |
|
|
247
|
+
|
|
248
|
+
### Global options
|
|
249
|
+
|
|
250
|
+
`-c/--config PATH` · `-v` / `-vv` (INFO / DEBUG, always on stderr) · `--color/--no-color` ·
|
|
251
|
+
`--version` · `-h/--help`
|
|
252
|
+
|
|
253
|
+
Global options must precede the subcommand: `depkeeper -v check`, not `depkeeper check -v`.
|
|
254
|
+
|
|
255
|
+
Full specification: **[CLI reference](https://rahulkaushal04.github.io/depkeeper/reference/cli-commands/)**.
|
|
256
|
+
|
|
257
|
+
### Exit codes
|
|
258
|
+
|
|
259
|
+
| Code | Meaning |
|
|
260
|
+
|---|---|
|
|
261
|
+
| `0` | Success — **including** "updates are available" |
|
|
262
|
+
| `1` | Application error (parse, config, write, refused hash removal) |
|
|
263
|
+
| `2` | Usage error (unknown option, missing file) |
|
|
264
|
+
| `130` | Interrupted (`Ctrl+C`) |
|
|
265
|
+
|
|
266
|
+
Gate automation on the JSON payload, never on `check`'s exit code.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Configuration
|
|
271
|
+
|
|
272
|
+
Two settings are persistable, in `depkeeper.toml` or `pyproject.toml`. Everything else is a
|
|
273
|
+
per-invocation flag, deliberately — options that change what gets *written* stay visible in the
|
|
274
|
+
command line.
|
|
275
|
+
|
|
276
|
+
```toml
|
|
277
|
+
# depkeeper.toml
|
|
278
|
+
[depkeeper]
|
|
279
|
+
check_conflicts = true # cross-package conflict resolution
|
|
280
|
+
strict_version_matching = false # treat only `==` as a current version
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
```toml
|
|
284
|
+
# pyproject.toml
|
|
285
|
+
[tool.depkeeper]
|
|
286
|
+
check_conflicts = true
|
|
287
|
+
strict_version_matching = false
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Precedence: **defaults < config file < CLI flag**. Unknown keys and wrong types are hard errors.
|
|
291
|
+
Discovery is limited to the current working directory (not recursive).
|
|
292
|
+
|
|
293
|
+
Environment: `DEPKEEPER_CONFIG`, `DEPKEEPER_COLOR`, `NO_COLOR`, `CI`, plus `httpx`'s
|
|
294
|
+
`HTTPS_PROXY` / `SSL_CERT_FILE`.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Common workflows
|
|
299
|
+
|
|
300
|
+
**Daily**
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
depkeeper check --outdated-only
|
|
304
|
+
depkeeper update --dry-run
|
|
305
|
+
depkeeper update --backup && pip install -r requirements.txt && pytest
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**One package at a time** (keeps regressions bisectable)
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
depkeeper update -p django -y && pytest
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Application release — freeze to exact versions**
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
depkeeper update --pin --backup
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**CI drift report** — stdout stays parseable even with `-v`
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
depkeeper -v check --format json --no-check-conflicts > report.json 2> depkeeper.log
|
|
324
|
+
jq '[.[] | select(.status == "outdated")] | length' report.json
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Multi-file projects** — `-r` includes are followed and rewritten
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
depkeeper update requirements/dev.txt --dry-run # also writes base.txt
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Hash-pinned files** — depkeeper refuses these by default
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
depkeeper update --allow-hash-removal -y
|
|
337
|
+
pip-compile --generate-hashes requirements.in # regenerate; not optional
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
More: **[User guide](https://rahulkaushal04.github.io/depkeeper/guides/)** ·
|
|
341
|
+
**[CI/CD integration](https://rahulkaushal04.github.io/depkeeper/guides/ci-cd-integration/)**
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Architecture
|
|
346
|
+
|
|
347
|
+
Synchronous CLI around an asynchronous core. No daemon, no persistent state, no cache directory.
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
requirements.txt
|
|
351
|
+
│
|
|
352
|
+
▼
|
|
353
|
+
RequirementsParser ──► PyPIDataStore ──► VersionChecker ──► DependencyAnalyzer ──┐
|
|
354
|
+
(text → model) (one HTTP call (per-package (cross-package │
|
|
355
|
+
per package) target version) consistency) │
|
|
356
|
+
▼
|
|
357
|
+
renderer (table/simple/json)
|
|
358
|
+
writer (atomic, rollback-safe)
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
| Component | Responsibility |
|
|
362
|
+
|---|---|
|
|
363
|
+
| `core/parser.py` | Requirements text → `Requirement` objects, `-r`/`-c` resolution, provenance |
|
|
364
|
+
| `core/data_store.py` | PyPI metadata cache with per-key request coalescing |
|
|
365
|
+
| `core/checker.py` | Per-package recommendation under boundary, Python and constraint filters |
|
|
366
|
+
| `core/dependency_analyzer.py` | Iterative conflict resolution within major boundaries |
|
|
367
|
+
| `commands/` | User interaction, rendering, the write pipeline, exit codes |
|
|
368
|
+
| `utils/` | HTTP, console, logging, atomic filesystem, naming, version algebra |
|
|
369
|
+
|
|
370
|
+
See **[ARCHITECTURE.md](ARCHITECTURE.md)** for the contributor-facing map, or the
|
|
371
|
+
**[architecture deep dive](https://rahulkaushal04.github.io/depkeeper/concepts/architecture/)**
|
|
372
|
+
for design decisions, concurrency model and error propagation.
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Limitations
|
|
377
|
+
|
|
378
|
+
Honest, verified, and documented in full at
|
|
379
|
+
**[Known limitations](https://rahulkaushal04.github.io/depkeeper/reference/limitations/)**.
|
|
380
|
+
The ones most likely to affect you:
|
|
381
|
+
|
|
382
|
+
- **Not a resolver.** The transitive graph is not expanded. Always `pip install` and test.
|
|
383
|
+
- **Only `pypi.org` is queried.** `--index-url` lines are parsed and ignored; private packages
|
|
384
|
+
report as errors.
|
|
385
|
+
- **Calendar versions hit the major boundary.** `certifi 2023.x` never auto-bumps to `2024.x`.
|
|
386
|
+
- **Major upgrades are yours to make.** Raise the floor by hand, then let depkeeper continue.
|
|
387
|
+
- **Backslash line continuations are not parsed**, so default
|
|
388
|
+
`pip-compile --generate-hashes` output is unreadable to depkeeper.
|
|
389
|
+
- **No runtime tuning.** Timeouts, retries and concurrency are constants; override them via the
|
|
390
|
+
Python API if you must.
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Troubleshooting
|
|
395
|
+
|
|
396
|
+
Start here:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
depkeeper -vv check --format json > report.json 2> debug.log
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
`debug.log` names the file parsed, the effective configuration, every HTTP retry and every
|
|
403
|
+
resolution decision.
|
|
404
|
+
|
|
405
|
+
| Symptom | Cause |
|
|
406
|
+
|---|---|
|
|
407
|
+
| Recommendation far below `Latest` | Your declared cap, the major boundary, a conflict, or `requires_python` |
|
|
408
|
+
| Recommendations differ between laptop and CI | Different Python versions running depkeeper |
|
|
409
|
+
| `✗ ERROR` rows | Package not on public PyPI, network/proxy failure, or TLS interception |
|
|
410
|
+
| `update` changed a package `check` showed as `✓ OK` | Unversioned requirement — it received a pin |
|
|
411
|
+
| A proposed **downgrade** | Declared version is unusable; review before accepting |
|
|
412
|
+
|
|
413
|
+
Full guide: **[Troubleshooting](https://rahulkaushal04.github.io/depkeeper/guides/troubleshooting/)**
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## Documentation
|
|
418
|
+
|
|
419
|
+
Published at **[rahulkaushal04.github.io/depkeeper](https://rahulkaushal04.github.io/depkeeper/)**.
|
|
420
|
+
|
|
421
|
+
| Section | Contents |
|
|
422
|
+
|---|---|
|
|
423
|
+
| [Getting started](https://rahulkaushal04.github.io/depkeeper/getting-started/) | Install, quick start, reading the output |
|
|
424
|
+
| [Concepts](https://rahulkaushal04.github.io/depkeeper/concepts/) | Architecture, version recommendation, conflict resolution, parsing, write safety |
|
|
425
|
+
| [User guide](https://rahulkaushal04.github.io/depkeeper/guides/) | Checking, updating, configuration, CI/CD, operations, best practices, troubleshooting |
|
|
426
|
+
| [Reference](https://rahulkaushal04.github.io/depkeeper/reference/) | CLI, config, exit codes, file formats, JSON schema, errors, limitations, Python API |
|
|
427
|
+
| [Contributing](https://rahulkaushal04.github.io/depkeeper/contributing/) | Setup, code style, testing, extending, releases |
|
|
428
|
+
|
|
429
|
+
Repository documents: [ARCHITECTURE.md](ARCHITECTURE.md) ·
|
|
430
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) · [CHANGELOG.md](CHANGELOG.md) ·
|
|
431
|
+
[SECURITY.md](SECURITY.md) · [SUPPORT.md](SUPPORT.md) ·
|
|
432
|
+
[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Project status
|
|
437
|
+
|
|
438
|
+
Version **0.1.1**, classified `Development Status :: 4 - Beta`.
|
|
439
|
+
|
|
440
|
+
The write path is defensive — atomic replacement, two-phase commit, rollback, optional backups —
|
|
441
|
+
and behaviour is documented and covered by tests across Linux, macOS and Windows on Python
|
|
442
|
+
3.8–3.12. Pin the version in automation: recommendation logic is a behavioural contract, and a
|
|
443
|
+
version bump can legitimately change an update plan.
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Contributing
|
|
448
|
+
|
|
449
|
+
Contributions are welcome. Start with [CONTRIBUTING.md](CONTRIBUTING.md), and read the
|
|
450
|
+
[system invariants](https://rahulkaushal04.github.io/depkeeper/concepts/#non-negotiable-invariants)
|
|
451
|
+
before changing anything in `core/`.
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
git clone https://github.com/rahulkaushal04/depkeeper.git
|
|
455
|
+
cd depkeeper
|
|
456
|
+
pip install -e ".[dev,docs]"
|
|
457
|
+
pre-commit install
|
|
458
|
+
|
|
459
|
+
python -m pytest tests -q --no-cov
|
|
460
|
+
python -m mypy depkeeper --python-version 3.13
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Report vulnerabilities privately — see [SECURITY.md](SECURITY.md), never a public issue.
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## License
|
|
468
|
+
|
|
469
|
+
[Apache License 2.0](LICENSE). Copyright 2025-2026 Rahul Kaushal.
|
|
470
|
+
|
|
471
|
+
Built with [Click](https://click.palletsprojects.com/),
|
|
472
|
+
[Rich](https://rich.readthedocs.io/), [httpx](https://www.python-httpx.org/) and
|
|
473
|
+
[packaging](https://packaging.pypa.io/) — the last of which is why depkeeper agrees with `pip`
|
|
474
|
+
about what a version means.
|