Skip to content

Commit 7081007

Browse files
authored
feat: add PyPI/Python support (deps-pypi crate) (#15)
* feat: add PyPI/Python support (deps-pypi crate) - Add deps-pypi crate with PEP 621 and Poetry pyproject.toml parsing - Implement PyPI registry client with HTTP caching - Add codecov badges to all crate READMEs * fix(deps-pypi): implement critical fixes from code review Implement deps_core trait integration: - Add ManifestParser trait implementation for PypiParser - Add DependencyInfo trait implementation for PypiDependency - Add ParseResultInfo trait for ParseResult - Introduce ParseResult type for parser output Fix is_prerelease() false positives: - Replace string scanning with pep440_rs::Version::is_pre() - Eliminates false positives from packages like "stable" - Uses proper PEP 440 prerelease detection Add PEP 503 package name normalization: - Implement normalize_package_name() function - Converts to lowercase, replaces underscores/dots with hyphens - Ensures consistent PyPI lookups for "Flask" vs "flask" - Apply normalization in get_versions() and get_package_metadata() Optimize version sorting: - Parse versions once before sorting instead of twice per comparison - Cache parsed Version objects during sort operation - Reduces parsing overhead by ~50% for typical package version lists Update license allowlist: - Add MPL-2.0 to deny.toml for version-ranges dependency All tests passing (23/23). Clippy clean with -D warnings. * fix(deps-pypi): correct doctest examples to use parse_content() Fixed doctests that were using the trait method parse() incorrectly. Changed to use parse_content() method directly which is the public API. All other code review items were already implemented: - ManifestParser, DependencyInfo, ParseResultInfo traits - is_prerelease() using pep440_rs - normalize_package_name() function - Version sorting optimization - MPL-2.0 license in deny.toml * style(deps-pypi): apply rustfmt
1 parent 8bd0395 commit 7081007

File tree

15 files changed

+2036
-5
lines changed

15 files changed

+2036
-5
lines changed

Cargo.lock

Lines changed: 101 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@ dashmap = "6.1"
1818
deps-core = { version = "0.2.1", path = "crates/deps-core" }
1919
deps-cargo = { version = "0.2.1", path = "crates/deps-cargo" }
2020
deps-npm = { version = "0.2.1", path = "crates/deps-npm" }
21+
deps-pypi = { version = "0.2.1", path = "crates/deps-pypi" }
2122
deps-lsp = { version = "0.2.1", path = "crates/deps-lsp" }
2223
futures = "0.3"
2324
insta = "1"
2425
mockito = "1"
2526
node-semver = "2.2"
27+
pep440_rs = "0.7"
28+
pep508_rs = "0.9"
2629
reqwest = { version = "0.12", default-features = false }
2730
semver = "1"
2831
serde = "1"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![Crates.io](https://img.shields.io/crates/v/deps-lsp)](https://crates.io/crates/deps-lsp)
44
[![docs.rs](https://img.shields.io/docsrs/deps-lsp)](https://docs.rs/deps-lsp)
5+
[![codecov](https://codecov.io/gh/bug-ops/deps-lsp/graph/badge.svg?token=S71PTINTGQ)](https://codecov.io/gh/bug-ops/deps-lsp)
56
[![CI](https://img.shields.io/github/actions/workflow/status/bug-ops/deps-lsp/ci.yml?branch=main)](https://github.com/bug-ops/deps-lsp/actions)
67
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
78
[![MSRV](https://img.shields.io/badge/MSRV-1.89-blue)](https://blog.rust-lang.org/)

crates/deps-cargo/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![Crates.io](https://img.shields.io/crates/v/deps-cargo)](https://crates.io/crates/deps-cargo)
44
[![docs.rs](https://img.shields.io/docsrs/deps-cargo)](https://docs.rs/deps-cargo)
5+
[![codecov](https://codecov.io/gh/bug-ops/deps-lsp/graph/badge.svg?token=S71PTINTGQ&flag=deps-cargo)](https://codecov.io/gh/bug-ops/deps-lsp)
56
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](../../LICENSE)
67

78
Cargo.toml support for deps-lsp.

crates/deps-core/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![Crates.io](https://img.shields.io/crates/v/deps-core)](https://crates.io/crates/deps-core)
44
[![docs.rs](https://img.shields.io/docsrs/deps-core)](https://docs.rs/deps-core)
5+
[![codecov](https://codecov.io/gh/bug-ops/deps-lsp/graph/badge.svg?token=S71PTINTGQ&flag=deps-core)](https://codecov.io/gh/bug-ops/deps-lsp)
56
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](../../LICENSE)
67

78
Core abstractions for deps-lsp: caching, errors, and traits.

crates/deps-lsp/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![Crates.io](https://img.shields.io/crates/v/deps-lsp)](https://crates.io/crates/deps-lsp)
44
[![docs.rs](https://img.shields.io/docsrs/deps-lsp)](https://docs.rs/deps-lsp)
5+
[![codecov](https://codecov.io/gh/bug-ops/deps-lsp/graph/badge.svg?token=S71PTINTGQ&flag=deps-lsp)](https://codecov.io/gh/bug-ops/deps-lsp)
56
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](../../LICENSE)
67

78
Language Server Protocol implementation for dependency management.

crates/deps-npm/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
[![Crates.io](https://img.shields.io/crates/v/deps-npm)](https://crates.io/crates/deps-npm)
44
[![docs.rs](https://img.shields.io/docsrs/deps-npm)](https://docs.rs/deps-npm)
5+
[![codecov](https://codecov.io/gh/bug-ops/deps-lsp/graph/badge.svg?token=S71PTINTGQ&flag=deps-npm)](https://codecov.io/gh/bug-ops/deps-lsp)
56
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](../../LICENSE)
67

78
npm/package.json support for deps-lsp.

crates/deps-pypi/Cargo.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "deps-pypi"
3+
version.workspace = true
4+
edition.workspace = true
5+
rust-version.workspace = true
6+
authors.workspace = true
7+
license.workspace = true
8+
repository.workspace = true
9+
description = "PyPI/Python support for deps-lsp"
10+
11+
[dependencies]
12+
deps-core = { workspace = true }
13+
async-trait = { workspace = true }
14+
pep440_rs = { workspace = true }
15+
pep508_rs = { workspace = true }
16+
serde = { workspace = true, features = ["derive"] }
17+
serde_json = { workspace = true }
18+
thiserror = { workspace = true }
19+
tower-lsp = { workspace = true }
20+
toml_edit = { workspace = true }
21+
tracing = { workspace = true }
22+
23+
[dev-dependencies]
24+
insta = { workspace = true, features = ["json"] }
25+
mockito = { workspace = true }
26+
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }

crates/deps-pypi/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# deps-pypi
2+
3+
[![Crates.io](https://img.shields.io/crates/v/deps-pypi)](https://crates.io/crates/deps-pypi)
4+
[![docs.rs](https://img.shields.io/docsrs/deps-pypi)](https://docs.rs/deps-pypi)
5+
[![codecov](https://codecov.io/gh/bug-ops/deps-lsp/graph/badge.svg?token=S71PTINTGQ&flag=deps-pypi)](https://codecov.io/gh/bug-ops/deps-lsp)
6+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](../../LICENSE)
7+
8+
PyPI/Python support for deps-lsp.
9+
10+
This crate provides parsing, validation, and registry client functionality for Python dependency management in `pyproject.toml` files, supporting both PEP 621 and Poetry formats.
11+
12+
## Features
13+
14+
- **PEP 621 Support**: Parse `[project.dependencies]` and `[project.optional-dependencies]`
15+
- **Poetry Support**: Parse `[tool.poetry.dependencies]` and `[tool.poetry.group.*.dependencies]`
16+
- **PEP 508 Parsing**: Handle complex dependency specifications with extras and markers
17+
- **PEP 440 Versions**: Validate and compare Python version specifiers
18+
- **PyPI API Client**: Fetch package metadata from PyPI JSON API with HTTP caching
19+
20+
## Usage
21+
22+
```rust
23+
use deps_pypi::{PypiParser, PypiRegistry};
24+
use deps_core::PackageRegistry;
25+
26+
// Parse pyproject.toml
27+
let content = std::fs::read_to_string("pyproject.toml")?;
28+
let parser = PypiParser::new();
29+
let dependencies = parser.parse(&content)?;
30+
31+
// Fetch versions from PyPI
32+
let registry = PypiRegistry::new();
33+
let versions = registry.get_versions("requests").await?;
34+
```
35+
36+
## Supported Formats
37+
38+
### PEP 621 (Standard)
39+
40+
```toml
41+
[project]
42+
dependencies = [
43+
"requests>=2.28.0,<3.0",
44+
"flask[async]>=3.0",
45+
"numpy>=1.24; python_version>='3.9'",
46+
]
47+
48+
[project.optional-dependencies]
49+
dev = ["pytest>=7.0", "mypy>=1.0"]
50+
```
51+
52+
### Poetry
53+
54+
```toml
55+
[tool.poetry.dependencies]
56+
python = "^3.9"
57+
requests = "^2.28.0"
58+
flask = {version = "^3.0", extras = ["async"]}
59+
60+
[tool.poetry.group.dev.dependencies]
61+
pytest = "^7.0"
62+
mypy = "^1.0"
63+
```
64+
65+
## License
66+
67+
MIT

0 commit comments

Comments
 (0)