deps_pypi/
lib.rs

1//! PyPI/Python support for deps-lsp.
2//!
3//! This crate provides parsing, validation, and registry client functionality
4//! for Python dependency management in `pyproject.toml` files, supporting both
5//! PEP 621 and Poetry formats.
6//!
7//! # Features
8//!
9//! - **PEP 621 Support**: Parse `[project.dependencies]` and `[project.optional-dependencies]`
10//! - **Poetry Support**: Parse `[tool.poetry.dependencies]` and `[tool.poetry.group.*.dependencies]`
11//! - **PEP 508 Parsing**: Handle complex dependency specifications with extras and markers
12//! - **PEP 440 Versions**: Validate and compare Python version specifiers
13//! - **PyPI API Client**: Fetch package metadata from PyPI JSON API with HTTP caching
14//!
15//! # Architecture
16//!
17//! deps-pypi follows the same architecture as deps-cargo and deps-npm:
18//! - **Types**: `PypiDependency`, `PypiVersion`, `PypiPackage` with LSP range tracking
19//! - **Parser**: Parse both PEP 621 and Poetry formats using `toml_edit`
20//! - **Registry**: PyPI JSON API client with HTTP caching
21//! - **Error Handling**: Typed errors with `thiserror`
22//!
23//! # Examples
24//!
25//! ## Parsing pyproject.toml
26//!
27//! ```no_run
28//! use deps_pypi::PypiParser;
29//! use tower_lsp_server::ls_types::Uri;
30//!
31//! let content = r#"
32//! [project]
33//! dependencies = [
34//!     "requests>=2.28.0,<3.0",
35//!     "flask[async]>=3.0",
36//! ]
37//! "#;
38//!
39//! let parser = PypiParser::new();
40//! let uri = Uri::from_file_path("/project/pyproject.toml").unwrap();
41//! let result = parser.parse_content(content, &uri).unwrap();
42//!
43//! assert_eq!(result.dependencies.len(), 2);
44//! assert_eq!(result.dependencies[0].name, "requests");
45//! assert_eq!(result.dependencies[1].extras, vec!["async"]);
46//! ```
47//!
48//! ## Fetching versions from PyPI
49//!
50//! ```no_run
51//! use deps_pypi::PypiRegistry;
52//! use deps_core::HttpCache;
53//! use std::sync::Arc;
54//!
55//! # #[tokio::main]
56//! # async fn main() {
57//! let cache = Arc::new(HttpCache::new());
58//! let registry = PypiRegistry::new(cache);
59//!
60//! let versions = registry.get_versions("requests").await.unwrap();
61//! assert!(!versions.is_empty());
62//!
63//! let latest = registry
64//!     .get_latest_matching("requests", ">=2.28.0,<3.0")
65//!     .await
66//!     .unwrap();
67//! assert!(latest.is_some());
68//! # }
69//! ```
70//!
71//! ## Supported Formats
72//!
73//! ### PEP 621 (Standard)
74//!
75//! ```toml
76//! [project]
77//! dependencies = [
78//!     "requests>=2.28.0,<3.0",
79//!     "flask[async]>=3.0",
80//!     "numpy>=1.24; python_version>='3.9'",
81//! ]
82//!
83//! [project.optional-dependencies]
84//! dev = ["pytest>=7.0", "mypy>=1.0"]
85//! ```
86//!
87//! ### Poetry
88//!
89//! ```toml
90//! [tool.poetry.dependencies]
91//! python = "^3.9"
92//! requests = "^2.28.0"
93//! flask = {version = "^3.0", extras = ["async"]}
94//!
95//! [tool.poetry.group.dev.dependencies]
96//! pytest = "^7.0"
97//! mypy = "^1.0"
98//! ```
99
100pub mod ecosystem;
101pub mod error;
102pub mod formatter;
103pub mod lockfile;
104pub mod parser;
105pub mod registry;
106pub mod types;
107
108// Re-export commonly used types
109pub use ecosystem::PypiEcosystem;
110pub use error::{PypiError, Result};
111pub use formatter::PypiFormatter;
112pub use lockfile::PypiLockParser;
113pub use parser::PypiParser;
114pub use registry::PypiRegistry;
115pub use types::{
116    PypiDependency, PypiDependencySection, PypiDependencySource, PypiPackage, PypiVersion,
117};