use crate::util::ResultDynError;
use crate::util::{conda_fn_to_name_version, str_to_py_marker, toml_to_py_marker};
use serde_json::Value as JsonValue;
use serde_yaml::Value;
use toml::Value as TomlValue;
#[derive(Debug, PartialEq)]
pub enum LockFileType {
Requirements, UvLock, Poetry, PipfileLock, PEP751, PixiLock, }
#[derive(Debug)]
pub struct LockFile {
pub file_type: LockFileType,
pub content: String,
}
impl LockFile {
pub fn new(content: String) -> Self {
let file_type = Self::detect_type(&content);
Self { file_type, content }
}
fn detect_type(content: &str) -> LockFileType {
if let Ok(json) = serde_json::from_str::<JsonValue>(content) {
if json.get("_meta").is_some() && json.get("default").is_some() {
return LockFileType::PipfileLock;
}
}
let mut count = 0;
for line in content.lines() {
let t = line.trim();
if t.is_empty() || t.starts_with('#') {
continue;
}
count += 1;
if count > 20 {
break;
}
if t.starts_with("[metadata]") || t.starts_with("[[package]]") {
return LockFileType::Poetry;
}
if t.starts_with("[[distribution]]") {
return LockFileType::UvLock;
}
if t.starts_with("[[packages]]") {
return LockFileType::PEP751;
}
if t.starts_with("version:") || t.starts_with("environments:") {
return LockFileType::PixiLock;
}
}
LockFileType::Requirements
}
fn get_uv_requirements_dep(&self) -> ResultDynError<Vec<String>> {
let dependencies = self
.content
.lines()
.filter_map(|line| {
let t = line.trim();
if t.is_empty() || t.starts_with('#') {
return None;
}
Some(t.to_string())
})
.collect();
Ok(dependencies)
}
fn get_uv_native_dep(&self) -> ResultDynError<Vec<String>> {
let parsed: TomlValue = self.content.parse()?; let mut dependencies = Vec::new();
if let Some(dists) = parsed.get("distribution").and_then(|p| p.as_array()) {
for d in dists {
if let (Some(name), Some(version)) = (
d.get("name").and_then(|n| n.as_str()),
d.get("version").and_then(|v| v.as_str()),
) {
dependencies.push(format!("{name}=={version}"));
}
}
}
Ok(dependencies)
}
fn get_poetry_dep(&self) -> ResultDynError<Vec<String>> {
let parsed: TomlValue = self.content.parse()?; let mut dependencies = Vec::new();
if let Some(packages) = parsed.get("package").and_then(|p| p.as_array()) {
for package in packages {
if let (Some(name), Some(version)) = (
package.get("name").and_then(|n| n.as_str()),
package.get("version").and_then(|v| v.as_str()),
) {
let mut em = toml_to_py_marker(package, "python-versions");
if let Some(markers) = package
.get("markers")
.or_else(|| package.get("marker"))
.and_then(|m| m.as_str())
{
em.push(markers.to_string()); }
let dep_string = if em.is_empty() {
format!("{name}=={version}")
} else {
let ems = em.join(" and ");
format!("{name}=={version}; {ems}")
};
dependencies.push(dep_string);
}
}
}
Ok(dependencies)
}
fn get_pep751_dep(&self) -> ResultDynError<Vec<String>> {
let parsed: TomlValue = self.content.parse()?; let mut dependencies = Vec::new();
if let Some(packages) = parsed.get("packages").and_then(|p| p.as_array()) {
for package in packages {
if let (Some(name), Some(version)) = (
package.get("name").and_then(|n| n.as_str()),
package.get("version").and_then(|v| v.as_str()),
) {
let mut em = toml_to_py_marker(package, "requires-python");
if let Some(marker) = package.get("marker").and_then(|m| m.as_str()) {
em.push(marker.to_string());
}
let dep_string = if em.is_empty() {
format!("{name}=={version}")
} else {
let ems = em.join(" and ");
format!("{name}=={version}; {ems}")
};
dependencies.push(dep_string);
}
}
}
Ok(dependencies)
}
fn get_pipfilelock_dep(
&self,
options: Option<&Vec<String>>,
) -> ResultDynError<Vec<String>> {
let mut groups = vec!["default".to_string()];
if let Some(opts) = options {
groups.extend(opts.iter().cloned());
}
let parsed: JsonValue = serde_json::from_str(&self.content)?;
let mut dependencies = Vec::new();
for group in groups {
if let Some(packages) = parsed.get(group).and_then(|g| g.as_object()) {
for (name, details) in packages.iter() {
let em = details
.get("markers")
.map_or_else(|| "".to_string(), |v| format!("; {v}"));
if let Some(version) = details.get("version").and_then(|v| v.as_str())
{
dependencies.push(format!("{name}{version}{em}"));
}
}
}
}
Ok(dependencies)
}
fn get_pixi_dep(&self) -> ResultDynError<Vec<String>> {
let parsed_yaml: Value = serde_yaml::from_str(&self.content)?;
let default_packages: Vec<Value> = Vec::with_capacity(0);
let packages = parsed_yaml
.get("packages")
.and_then(Value::as_sequence)
.unwrap_or(&default_packages);
let deps = packages
.iter()
.filter_map(|package| {
let url = package.get("conda")?.as_str()?;
let filename = url.split('/').next_back()?;
let (package_name, package_version) = conda_fn_to_name_version(filename)?;
let marker = package
.get("depends")
.and_then(Value::as_sequence)
.and_then(|deps| {
deps.iter().filter_map(Value::as_str).find_map(|dep_str| {
dep_str.strip_prefix("python ").map(str_to_py_marker)
})
})?;
Some(format!("{package_name}=={package_version}; {marker}"))
})
.collect();
Ok(deps)
}
pub fn get_dependencies(
&self,
options: Option<&Vec<String>>,
) -> ResultDynError<Vec<String>> {
if options.is_some() && self.file_type != LockFileType::PipfileLock {
return Err("Options can only be used with Pipfile.lock".into());
}
match self.file_type {
LockFileType::Requirements => self.get_uv_requirements_dep(),
LockFileType::UvLock => self.get_uv_native_dep(),
LockFileType::Poetry => self.get_poetry_dep(),
LockFileType::PipfileLock => self.get_pipfilelock_dep(options),
LockFileType::PEP751 => self.get_pep751_dep(),
LockFileType::PixiLock => self.get_pixi_dep(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_dependencies_uv_a() {
let content = r#"
opentelemetry-api==1.24.0
# via
# apache-airflow
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
opentelemetry-exporter-otlp==1.24.0
# via apache-airflow
apache-airflow
"#;
let lockfile = LockFile::new(content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec![
"opentelemetry-api==1.24.0".to_string(),
"opentelemetry-exporter-otlp==1.24.0".to_string(),
"apache-airflow".to_string(),
]
);
}
#[test]
fn test_get_dependencies_uv_b() {
let content = r#"
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml -o requiremnts.lock
arraykit==0.10.0
# via static-frame
arraymap==0.4.0
# via static-frame
certifi==2025.1.31
# via requests
charset-normalizer==3.4.1
# via requests
idna==3.10
# via requests
jinja2==3.1.3
# via test-poetry (pyproject.toml)
markupsafe==3.0.2
# via jinja2
numpy==2.2.2
# via
# arraykit
# arraymap
# static-frame
requests==2.32.3
# via test-poetry (pyproject.toml)
static-frame==2.16.1
# via test-poetry (pyproject.toml)
typing-extensions==4.12.2
# via static-frame
urllib3==2.3.0
# via requests
zipp==3.18.1
# via test-poetry (pyproject.toml)
"#;
let lockfile = LockFile::new(content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec![
"arraykit==0.10.0",
"arraymap==0.4.0",
"certifi==2025.1.31",
"charset-normalizer==3.4.1",
"idna==3.10",
"jinja2==3.1.3",
"markupsafe==3.0.2",
"numpy==2.2.2",
"requests==2.32.3",
"static-frame==2.16.1",
"typing-extensions==4.12.2",
"urllib3==2.3.0",
"zipp==3.18.1"
]
);
}
#[test]
fn test_get_dependencies_uv_c() {
let content = r#"
version = 1
requires-python = ">=3.12"
[[distribution]]
name = "arraykit"
version = "0.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d0/35/d1d6cc29d930eff913e49fe0081149f5cb630a630cf35b329d811dc390e2/arraykit-0.10.0.tar.gz", hash = "sha256:ee890b71c6e60505a9a77ad653ecb9c879e0f1a887980359d7fbaf29d33d5446", size = 83187 }
[[distribution]]
name = "arraymap"
version = "0.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6c/89/1d8b77225282b1a37029755ff53f63b1566bab8da1ac0e88f2fb8187c490/arraymap-0.4.0.tar.gz", hash = "sha256:af1aa15f9f0c799888326561275052b4ea709b0a3a2ff58d01c55a447f8b1213", size = 24770 }
[[distribution]]
name = "certifi"
version = "2025.1.31"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
]
[[distribution]]
name = "charset-normalizer"
version = "3.4.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 }
[[distribution]]
name = "idna"
version = "3.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
]
[[distribution]]
name = "jinja2"
version = "3.1.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markupsafe" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b2/5e/3a21abf3cd467d7876045335e681d276ac32492febe6d98ad89562d1a7e1/Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90", size = 268261 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/30/6d/6de6be2d02603ab56e72997708809e8a5b0fbfee080735109b40a3564843/Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", size = 133236 },
]
[[distribution]]
name = "markupsafe"
version = "3.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 }
[[distribution]]
name = "numpy"
version = "2.2.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ec/d0/c12ddfd3a02274be06ffc71f3efc6d0e457b0409c4481596881e748cb264/numpy-2.2.2.tar.gz", hash = "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f", size = 20233295 }
[[distribution]]
name = "requests"
version = "2.32.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
{ name = "charset-normalizer" },
{ name = "idna" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
]
[[distribution]]
name = "static-frame"
version = "2.16.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "arraykit" },
{ name = "arraymap" },
{ name = "numpy" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/51/12/747c89bd6fcdd5d03c5565ca76448b5d6f641e436ea9f948ccaa7af20a15/static-frame-2.16.1.tar.gz", hash = "sha256:0f0e5e1c09c06891d71dca9b24e04526e99407dfae9d25d79e2011cb69c9ed9a", size = 733653 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f5/bf/d71b2bf7504437ce5365ad6ad975d7773adc55da6bde9b3ebd5c28a85d0b/static_frame-2.16.1-py3-none-any.whl", hash = "sha256:9f330f0672a6491bb9be0f64c64ee8abf06ffb9ee1b253f1f7695719538cc4df", size = 791035 },
]
[[distribution]]
name = "typing-extensions"
version = "4.12.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
]
[[distribution]]
name = "urllib3"
version = "2.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 },
]
[[distribution]]
name = "zipp"
version = "3.18.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/3e/ef/65da662da6f9991e87f058bc90b91a935ae655a16ae5514660d6460d1298/zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715", size = 21220 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c2/0a/ba9d0ee9536d3ef73a3448e931776e658b36f128d344e175bc32b092a8bf/zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", size = 8247 },
]
"#;
let lockfile = LockFile::new(content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec![
"arraykit==0.10.0",
"arraymap==0.4.0",
"certifi==2025.1.31",
"charset-normalizer==3.4.1",
"idna==3.10",
"jinja2==3.1.3",
"markupsafe==3.0.2",
"numpy==2.2.2",
"requests==2.32.3",
"static-frame==2.16.1",
"typing-extensions==4.12.2",
"urllib3==2.3.0",
"zipp==3.18.1"
]
);
}
#[test]
fn test_get_dependencies_poetry_a() {
let poetry_content = r#"
[[package]]
name = "packaging"
version = "24.2"
[[package]]
name = "requests"
version = "2.31.0"
"#;
let lockfile = LockFile::new(poetry_content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(dependencies, vec!["packaging==24.2", "requests==2.31.0"]);
}
#[test]
fn test_get_dependencies_poetry_b() {
let poetry_content = r#"
# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand.
[[package]]
name = "arraykit"
version = "0.10.0"
description = "Array utilities for StaticFrame"
optional = false
python-versions = ">=3.9"
groups = ["main"]
[package.dependencies]
numpy = ">=1.19.5"
[[package]]
name = "arraymap"
version = "0.4.0"
description = "Dictionary-like lookup from NumPy array values to their integer positions"
optional = false
python-versions = ">=3.9"
groups = ["main"]
[package.dependencies]
numpy = ">=1.19.5"
[[package]]
name = "certifi"
version = "2025.1.31"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"},
{file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"},
]
[[package]]
name = "charset-normalizer"
version = "3.4.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7"
groups = ["main"]
[[package]]
name = "idna"
version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
]
[package.extras]
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
[[package]]
name = "jinja2"
version = "3.1.3"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"},
{file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"},
]
[package.dependencies]
MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
[[package]]
name = "markupsafe"
version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
groups = ["main"]
[[package]]
name = "numpy"
version = "2.2.2"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = ">=3.10"
groups = ["main"]
[[package]]
name = "requests"
version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
]
[package.dependencies]
certifi = ">=2017.4.17"
charset-normalizer = ">=2,<4"
idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<3"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "static-frame"
version = "2.16.1"
description = "Immutable and statically-typeable DataFrames with runtime type and data validation."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "static-frame-2.16.1.tar.gz", hash = "sha256:0f0e5e1c09c06891d71dca9b24e04526e99407dfae9d25d79e2011cb69c9ed9a"},
{file = "static_frame-2.16.1-py3-none-any.whl", hash = "sha256:9f330f0672a6491bb9be0f64c64ee8abf06ffb9ee1b253f1f7695719538cc4df"},
]
[package.dependencies]
arraykit = "0.10.0"
arraymap = "0.4.0"
numpy = ">=1.23.5"
typing-extensions = ">=4.12.0"
[package.extras]
extras = ["duckdb (>=1.0.0)", "msgpack (>=1.0.4)", "msgpack-numpy (>=0.4.8)", "openpyxl (>=3.0.9)", "pandas (>=1.1.5)", "pyarrow (>=3.0.0)", "tables (>=3.9.1)", "visidata (>=2.4)", "xarray (>=0.13.0)", "xlsxwriter (>=1.1.2)"]
[[package]]
name = "typing-extensions"
version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
]
[[package]]
name = "urllib3"
version = "2.3.0"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"},
{file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"},
]
[package.extras]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
[[package]]
name = "zipp"
version = "3.18.1"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"},
{file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.12"
content-hash = "88d4af2d19b75cf5d80ba6b72bbee80790fa9757747e24304c4b1c51e86f3837"
"#;
let lockfile = LockFile::new(poetry_content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec![
"arraykit==0.10.0; python_version >= '3.9'",
"arraymap==0.4.0; python_version >= '3.9'",
"certifi==2025.1.31; python_version >= '3.6'",
"charset-normalizer==3.4.1; python_version >= '3.7'",
"idna==3.10; python_version >= '3.6'",
"jinja2==3.1.3; python_version >= '3.7'",
"markupsafe==3.0.2; python_version >= '3.9'",
"numpy==2.2.2; python_version >= '3.10'",
"requests==2.32.3; python_version >= '3.8'",
"static-frame==2.16.1; python_version >= '3.9'",
"typing-extensions==4.12.2; python_version >= '3.8'",
"urllib3==2.3.0; python_version >= '3.9'",
"zipp==3.18.1; python_version >= '3.8'"
]
);
}
#[test]
fn test_get_dependencies_poetry_c() {
let poetry_content = r#"
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
[[package]]
name = "pathlib2"
version = "2.3.7.post1"
description = "Object-oriented filesystem paths"
optional = false
python-versions = "*"
groups = ["main"]
markers = "sys_platform == \"win32\""
files = [
{file = "pathlib2-2.3.7.post1-py2.py3-none-any.whl", hash = "sha256:5266a0fd000452f1b3467d782f079a4343c63aaa119221fbdc4e39577489ca5b"},
{file = "pathlib2-2.3.7.post1.tar.gz", hash = "sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641"},
]
[package.dependencies]
six = "*"
[[package]]
name = "six"
version = "1.17.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
markers = "sys_platform == \"win32\""
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
]
[metadata]
lock-version = "2.1"
python-versions = ">=3.13"
content-hash = "f05bd817b200790c9d7fdfecc11143473da90202f39a4a185ba66e28b04e079a"
"#;
let lockfile = LockFile::new(poetry_content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec!["pathlib2==2.3.7.post1; sys_platform == \"win32\"",
"six==1.17.0; python_version != '3.0.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version >= '2.7' and sys_platform == \"win32\""]
);
}
#[test]
fn test_get_dependencies_pipfilelock_a() {
let pipfile_lock_content = r#"
{
"_meta": { "hash": { "sha256": "abc123" } },
"default": {
"asgiref": { "version": "==3.6.0" },
"django": { "version": "==4.1.7" }
},
"develop": {
"attrs": { "version": "==22.2.0" }
}
}
"#;
let lockfile = LockFile::new(pipfile_lock_content.to_string());
let dependencies_default = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies_default,
vec!["asgiref==3.6.0", "django==4.1.7"]
);
let dependencies_with_develop = lockfile
.get_dependencies(Some(&vec!["develop".to_string()]))
.unwrap();
assert_eq!(
dependencies_with_develop,
vec!["asgiref==3.6.0", "django==4.1.7", "attrs==22.2.0"]
);
}
#[test]
fn test_get_dependencies_pipfilelock_b() {
let pipfile_lock_content = r#"
{
"_meta": { "hash": { "sha256": "abc123" } },
"default": {
"asgiref": { "markers": "python_version < '3.4'", "version": "==3.6.0" },
"django": { "markers": "python_version >= '3.4'", "version": "==4.1.7" }
},
"develop": {
"attrs": { "markers": "python_version >= '3.4'", "version": "==22.2.0" }
}
}
"#;
let lockfile = LockFile::new(pipfile_lock_content.to_string());
let dependencies_default = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies_default,
vec![
"asgiref==3.6.0; \"python_version < '3.4'\"",
"django==4.1.7; \"python_version >= '3.4'\""
]
);
let dependencies_with_develop = lockfile
.get_dependencies(Some(&vec!["develop".to_string()]))
.unwrap();
assert_eq!(
dependencies_with_develop,
vec![
"asgiref==3.6.0; \"python_version < '3.4'\"",
"django==4.1.7; \"python_version >= '3.4'\"",
"attrs==22.2.0; \"python_version >= '3.4'\""
]
);
}
#[test]
fn test_get_dependencies_pip_tools_a() {
let content = r#"
#
# This file is autogenerated by pip-compile with Python 3.13
# by the following command:
#
# pip-compile --output-file=requirements.lock requirements.txt
#
certifi==2025.1.31
# via requests
charset-normalizer==3.4.1
# via requests
idna==3.10
# via requests
jinja2==3.1.3
# via -r requirements.txt
markupsafe==3.0.2
# via jinja2
requests==2.32.3
# via -r requirements.txt
urllib3==2.3.0
# via requests
zipp==3.18.1
# via -r requirements.txt
"#;
let lockfile = LockFile::new(content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec![
"certifi==2025.1.31",
"charset-normalizer==3.4.1",
"idna==3.10",
"jinja2==3.1.3",
"markupsafe==3.0.2",
"requests==2.32.3",
"urllib3==2.3.0",
"zipp==3.18.1"
]
);
}
#[test]
fn test_get_dependencies_pep751_a() {
let content = r#"
metadata-version = "1.0"
requires-python = ">=3.9"
created-by = "PEP 751"
[[packages]]
name = "attrs"
version = "23.2.0"
requires-python = ">=3.7"
index = "https://pypi.org/simple/"
wheels = [
{name = "attrs-23.2.0-py3-none-any.whl", upload-time = 2023-12-31T06:30:30.772444Z, url = "https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl", size = 60752, hashes = {sha256 = "99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"} }
]
[[packages]]
name = "cattrs"
version = "23.2.3"
requires-python = ">=3.8"
index = "https://pypi.org/simple/"
wheels = [
{name = "cattrs-23.2.3-py3-none-any.whl", upload-time = 2023-11-30T22:19:19.163763Z, url = "https://files.pythonhosted.org/packages/b3/0d/cd4a4071c7f38385dc5ba91286723b4d1090b87815db48216212c6c6c30e/cattrs-23.2.3-py3-none-any.whl", size = 57474, hashes = {sha256 = "0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"} }
]
[[packages]]
name = "numpy"
version = "2.0.1"
requires-python = ">=3.9"
index = "https://pypi.org/simple/"
wheels = [
{name = "numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", upload-time = 2024-07-21T13:37:15.810939Z, url = "https://files.pythonhosted.org/packages/64/1c/401489a7e92c30db413362756c313b9353fb47565015986c55582593e2ae/numpy-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", size = 20965374, hashes = {sha256 = "6bf4e6f4a2a2e26655717a1983ef6324f2664d7011f6ef7482e8c0b3d51e82ac"} },
{name = "numpy-2.0.1-cp312-cp312-win_amd64.whl", upload-time = 2024-07-21T13:40:17.532627Z, url = "https://files.pythonhosted.org/packages/b5/59/f6ad378ad85ed9c2785f271b39c3e5b6412c66e810d2c60934c9f/numpy-2.0.1-cp312-cp312-win_amd64.whl", size = 16255757, hashes = {sha256 = "bb2124fdc6e62baae159ebcfa368708867eb56806804d005860b6007388df171"} },
]
"#;
let lockfile = LockFile::new(content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec![
"attrs==23.2.0; python_version >= '3.7'",
"cattrs==23.2.3; python_version >= '3.8'",
"numpy==2.0.1; python_version >= '3.9'"
]
);
}
#[test]
fn test_get_dependencies_pep751_b() {
let content = r#"
metadata-version = "1.0"
requires-python = ">=3.9"
created-by = "PEP 751"
[[packages]]
name = "attrs"
version = "23.2.0"
requires-python = ">=3.7"
marker = "python_version > '3.0'"
index = "https://pypi.org/simple/"
wheels = [
{name = "attrs-23.2.0-py3-none-any.whl", upload-time = 2023-12-31T06:30:30.772444Z, url = "https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl", size = 60752, hashes = {sha256 = "99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"} }
]
[[packages]]
name = "cattrs"
version = "23.2.3"
requires-python = ">=3.8"
marker = "python_version > '3.1'"
index = "https://pypi.org/simple/"
wheels = [
{name = "cattrs-23.2.3-py3-none-any.whl", upload-time = 2023-11-30T22:19:19.163763Z, url = "https://files.pythonhosted.org/packages/b3/0d/cd4a4071c7f38385dc5ba91286723b4d1090b87815db48216212c6c6c30e/cattrs-23.2.3-py3-none-any.whl", size = 57474, hashes = {sha256 = "0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"} }
]
"#;
let lockfile = LockFile::new(content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec![
"attrs==23.2.0; python_version >= '3.7' and python_version > '3.0'",
"cattrs==23.2.3; python_version >= '3.8' and python_version > '3.1'"
]
);
}
#[test]
fn test_get_dependencies_pixi_lock() {
let content = r#"
version: 6
environments:
default:
channels:
- url: https://conda.anaconda.org/conda-forge/
packages:
linux-64:
- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2025.1.31-hbcca054_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-31_h59b9bed_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-31_he106b2a_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hf1ad2bd_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h767d61c_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-31_h7ac8fdf_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.4-hb9d3cd8_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.29-pthreads_h94d23a6_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.49.1-hee588c1_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-h8f9b012_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.0.2-py39h9cb892a_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py39h3b40f6f_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.9.21-h9c0c6dc_1_cpython.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.9-5_cp39.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda
packages:
- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2
sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726
md5: d7c89558ba9fa0495403155b64376d81
license: None
size: 2562
timestamp: 1578324546067
- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2
build_number: 16
sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22
md5: 73aaf86a425cc6e73fcf236a5a46396d
depends:
- _libgcc_mutex 0.1 conda_forge
- libgomp >=7.5.0
constrains:
- openmp_impl 9999
license: BSD-3-Clause
license_family: BSD
size: 23621
timestamp: 1650670423406
- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda
sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d
md5: 62ee74e96c5ebb0af99386de58cf9553
depends:
- __glibc >=2.17,<3.0.a0
- libgcc-ng >=12
license: bzip2-1.0.6
license_family: BSD
size: 252783
timestamp: 1720974456583
- conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2025.1.31-hbcca054_0.conda
sha256: bf832198976d559ab44d6cdb315642655547e26d826e34da67cbee6624cda189
md5: 19f3a56f68d2fd06c516076bff482c52
license: ISC
size: 158144
timestamp: 1738298224464
- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.43-h712a8e2_4.conda
sha256: db73f38155d901a610b2320525b9dd3b31e4949215c870685fd92ea61b5ce472
md5: 01f8d123c96816249efd255a31ad7712
depends:
- __glibc >=2.17,<3.0.a0
constrains:
- binutils_impl_linux-64 2.43
license: GPL-3.0-only
license_family: GPL
size: 671240
timestamp: 1740155456116
- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-31_h59b9bed_openblas.conda
build_number: 31
sha256: 9839fc4ac0cbb0aa3b9eea520adfb57311838959222654804e58f6f2d1771db5
md5: 728dbebd0f7a20337218beacffd37916
depends:
- libopenblas >=0.3.29,<0.3.30.0a0
- libopenblas >=0.3.29,<1.0a0
constrains:
- liblapacke =3.9.0=31*_openblas
- liblapack =3.9.0=31*_openblas
- blas =2.131=openblas
- mkl <2025
- libcblas =3.9.0=31*_openblas
license: BSD-3-Clause
license_family: BSD
size: 16859
timestamp: 1740087969120
- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-31_he106b2a_openblas.conda
build_number: 31
sha256: ede8545011f5b208b151fe3e883eb4e31d495ab925ab7b9ce394edca846e0c0d
md5: abb32c727da370c481a1c206f5159ce9
depends:
- libblas 3.9.0 31_h59b9bed_openblas
constrains:
- liblapacke =3.9.0=31*_openblas
- liblapack =3.9.0=31*_openblas
- blas =2.131=openblas
license: BSD-3-Clause
license_family: BSD
size: 16796
timestamp: 1740087984429
- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_0.conda
sha256: 67a6c95e33ebc763c1adc3455b9a9ecde901850eb2fceb8e646cc05ef3a663da
md5: e3eb7806380bc8bcecba6d749ad5f026
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=13
license: MIT
license_family: MIT
size: 53415
timestamp: 1739260413716
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-14.2.0-h767d61c_2.conda
sha256: 3a572d031cb86deb541d15c1875aaa097baefc0c580b54dc61f5edab99215792
md5: ef504d1acbd74b7cc6849ef8af47dd03
depends:
- __glibc >=2.17,<3.0.a0
- _openmp_mutex >=4.5
constrains:
- libgomp 14.2.0 h767d61c_2
- libgcc-ng ==14.2.0=*_2
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
size: 847885
timestamp: 1740240653082
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-14.2.0-h69a702a_2.conda
sha256: fb7558c328b38b2f9d2e412c48da7890e7721ba018d733ebdfea57280df01904
md5: a2222a6ada71fb478682efe483ce0f92
depends:
- libgcc 14.2.0 h767d61c_2
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
size: 53758
timestamp: 1740240660904
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-14.2.0-h69a702a_2.conda
sha256: e05263e8960da03c341650f2a3ffa4ccae4e111cb198e8933a2908125459e5a6
md5: fb54c4ea68b460c278d26eea89cfbcc3
depends:
- libgfortran5 14.2.0 hf1ad2bd_2
constrains:
- libgfortran-ng ==14.2.0=*_2
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
size: 53733
timestamp: 1740240690977
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-14.2.0-hf1ad2bd_2.conda
sha256: c17b7cf3073a1f4e1f34d50872934fa326346e104d3c445abc1e62481ad6085c
md5: 556a4fdfac7287d349b8f09aba899693
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=14.2.0
constrains:
- libgfortran 14.2.0
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
size: 1461978
timestamp: 1740240671964
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-14.2.0-h767d61c_2.conda
sha256: 1a3130e0b9267e781b89399580f3163632d59fe5b0142900d63052ab1a53490e
md5: 06d02030237f4d5b3d9a7e7d348fe3c6
depends:
- __glibc >=2.17,<3.0.a0
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
size: 459862
timestamp: 1740240588123
- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-31_h7ac8fdf_openblas.conda
build_number: 31
sha256: f583661921456e798aba10972a8abbd9d33571c655c1f66eff450edc9cbefcf3
md5: 452b98eafe050ecff932f0ec832dd03f
depends:
- libblas 3.9.0 31_h59b9bed_openblas
constrains:
- libcblas =3.9.0=31*_openblas
- liblapacke =3.9.0=31*_openblas
- blas =2.131=openblas
license: BSD-3-Clause
license_family: BSD
size: 16790
timestamp: 1740087997375
- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.6.4-hb9d3cd8_0.conda
sha256: cad52e10319ca4585bc37f0bc7cce99ec7c15dc9168e42ccb96b741b0a27db3f
md5: 42d5b6a0f30d3c10cd88cb8584fda1cb
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=13
license: 0BSD
size: 111357
timestamp: 1738525339684
- conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda
sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6
md5: 30fd6e37fe21f86f4bd26d6ee73eeec7
depends:
- libgcc-ng >=12
license: LGPL-2.1-only
license_family: GPL
size: 33408
timestamp: 1697359010159
- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.29-pthreads_h94d23a6_0.conda
sha256: cc5389ea254f111ef17a53df75e8e5209ef2ea6117e3f8aced88b5a8e51f11c4
md5: 0a4d0252248ef9a0f88f2ba8b8a08e12
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=14
- libgfortran
- libgfortran5 >=14.2.0
constrains:
- openblas >=0.3.29,<0.3.30.0a0
license: BSD-3-Clause
license_family: BSD
size: 5919288
timestamp: 1739825731827
- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.49.1-hee588c1_2.conda
sha256: a086289bf75c33adc1daed3f1422024504ffb5c3c8b3285c49f025c29708ed16
md5: 962d6ac93c30b1dfc54c9cccafd1003e
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=13
- libzlib >=1.3.1,<2.0a0
license: Unlicense
size: 918664
timestamp: 1742083674731
- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-14.2.0-h8f9b012_2.conda
sha256: 8f5bd92e4a24e1d35ba015c5252e8f818898478cb3bc50bd8b12ab54707dc4da
md5: a78c856b6dc6bf4ea8daeb9beaaa3fb0
depends:
- __glibc >=2.17,<3.0.a0
- libgcc 14.2.0 h767d61c_2
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
size: 3884556
timestamp: 1740240685253
- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda
sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18
md5: 40b61aab5c7ba9ff276c41cfffe6b80b
depends:
- libgcc-ng >=12
license: BSD-3-Clause
license_family: BSD
size: 33601
timestamp: 1680112270483
- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c
md5: 5aa797f8787fe7a17d1b0821485b5adc
depends:
- libgcc-ng >=12
license: LGPL-2.1-or-later
size: 100393
timestamp: 1702724383534
- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda
sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4
md5: edb0dca6bc32e4f4789199455a1dbeb8
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=13
constrains:
- zlib 1.3.1 *_2
license: Zlib
license_family: Other
size: 60963
timestamp: 1727963148474
- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda
sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586
md5: 47e340acb35de30501a76c7c799c41d7
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=13
license: X11 AND BSD-3-Clause
size: 891641
timestamp: 1738195959188
- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.0.2-py39h9cb892a_1.conda
sha256: cac3d9a87db5a3b54f8a97c77ee1cf35af6a7f9c725b6911bc5f1d6c6d101637
md5: be95cf76ebd05d08be67e50e88d3cd49
depends:
- __glibc >=2.17,<3.0.a0
- libblas >=3.9.0,<4.0a0
- libcblas >=3.9.0,<4.0a0
- libgcc >=13
- liblapack >=3.9.0,<4.0a0
- libstdcxx >=13
- python >=3.9,<3.10.0a0
- python_abi 3.9.* *_cp39
constrains:
- numpy-base <0a0
license: BSD-3-Clause
license_family: BSD
size: 7925462
timestamp: 1732314760363
- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.4.1-h7b32b05_0.conda
sha256: cbf62df3c79a5c2d113247ddea5658e9ff3697b6e741c210656e239ecaf1768f
md5: 41adf927e746dc75ecf0ef841c454e48
depends:
- __glibc >=2.17,<3.0.a0
- ca-certificates
- libgcc >=13
license: Apache-2.0
license_family: Apache
size: 2939306
timestamp: 1739301879343
- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.2.3-py39h3b40f6f_2.conda
sha256: 5cf1fd8e385f9a2a2cd5bff29a22fbcca6b2107d17efb7f8dd5bea8b158bc3a1
md5: 8fbcaa8f522b0d2af313db9e3b4b05b9
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=13
- libstdcxx >=13
- numpy >=1.19,<3
- numpy >=1.22.4
- python >=3.9,<3.10.0a0
- python-dateutil >=2.8.1
- python-tzdata >=2022a
- python_abi 3.9.* *_cp39
- pytz >=2020.1,<2024.2
constrains:
- openpyxl >=3.1.0
- zstandard >=0.19.0
- numexpr >=2.8.4
- pyxlsb >=1.0.10
- lxml >=4.9.2
- tzdata >=2022.7
- qtpy >=2.3.0
- bottleneck >=1.3.6
- pyqt5 >=5.15.8
- matplotlib >=3.6.3
- numba >=0.56.4
- beautifulsoup4 >=4.11.2
- pytables >=3.8.0
- xarray >=2022.12.0
- s3fs >=2022.11.0
- tabulate >=0.9.0
- xlsxwriter >=3.0.5
- psycopg2 >=2.9.6
- sqlalchemy >=2.0.0
- gcsfs >=2022.11.0
- pyreadstat >=1.2.0
- fastparquet >=2022.12.0
- blosc >=1.21.3
- scipy >=1.10.0
- fsspec >=2022.11.0
license: BSD-3-Clause
license_family: BSD
size: 12897186
timestamp: 1736811288486
- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.9.21-h9c0c6dc_1_cpython.conda
build_number: 1
sha256: 06042ce946a64719b5ce1676d02febc49a48abcab16ef104e27d3ec11e9b1855
md5: b4807744af026fdbe8c05131758fb4be
depends:
- __glibc >=2.17,<3.0.a0
- bzip2 >=1.0.8,<2.0a0
- ld_impl_linux-64 >=2.36.1
- libffi >=3.4,<4.0a0
- libgcc >=13
- liblzma >=5.6.3,<6.0a0
- libnsl >=2.0.1,<2.1.0a0
- libsqlite >=3.47.0,<4.0a0
- libuuid >=2.38.1,<3.0a0
- libxcrypt >=4.4.36
- libzlib >=1.3.1,<2.0a0
- ncurses >=6.5,<7.0a0
- openssl >=3.4.0,<4.0a0
- readline >=8.2,<9.0a0
- tk >=8.6.13,<8.7.0a0
- tzdata
constrains:
- python_abi 3.9.* *_cp39
license: Python-2.0
size: 23622848
timestamp: 1733407924273
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhff2d567_1.conda
sha256: a50052536f1ef8516ed11a844f9413661829aa083304dc624c5925298d078d79
md5: 5ba79d7c71f03c678c8ead841f347d6e
depends:
- python >=3.9
- six >=1.5
license: Apache-2.0
license_family: APACHE
size: 222505
timestamp: 1733215763718
- conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2025.1-pyhd8ed1ab_0.conda
sha256: 1597d6055d34e709ab8915091973552a0b8764c8032ede07c4e99670da029629
md5: 392c91c42edd569a7ec99ed8648f597a
depends:
- python >=3.9
license: Apache-2.0
license_family: APACHE
size: 143794
timestamp: 1737541204030
- conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.9-5_cp39.conda
build_number: 5
sha256: 019e2f8bca1d1f1365fbb9965cd95bb395c92c89ddd03165db82f5ae89a20812
md5: 40363a30db350596b5f225d0d5a33328
constrains:
- python 3.9.* *_cpython
license: BSD-3-Clause
license_family: BSD
size: 6193
timestamp: 1723823354399
- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2024.1-pyhd8ed1ab_0.conda
sha256: 1a7d6b233f7e6e3bbcbad054c8fd51e690a67b129a899a056a5e45dd9f00cb41
md5: 3eeeeb9e4827ace8c0c1419c85d590ad
depends:
- python >=3.7
license: MIT
license_family: MIT
size: 188538
timestamp: 1706886944988
- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda
sha256: 2d6d0c026902561ed77cd646b5021aef2d4db22e57a5b0178dfc669231e06d2c
md5: 283b96675859b20a825f8fa30f311446
depends:
- libgcc >=13
- ncurses >=6.5,<7.0a0
license: GPL-3.0-only
license_family: GPL
size: 282480
timestamp: 1740379431762
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda
sha256: 41db0180680cc67c3fa76544ffd48d6a5679d96f4b71d7498a759e94edc9a2db
md5: a451d576819089b0d672f18768be0f65
depends:
- python >=3.9
license: MIT
license_family: MIT
size: 16385
timestamp: 1733381032766
- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda
sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e
md5: d453b98d9c83e71da0741bb0ff4d76bc
depends:
- libgcc-ng >=12
- libzlib >=1.2.13,<2.0.0a0
license: TCL
license_family: BSD
size: 3318875
timestamp: 1699202167581
- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025a-h78e105d_0.conda
sha256: c4b1ae8a2931fe9b274c44af29c5475a85b37693999f8c792dad0f8c6734b1de
md5: dbcace4706afdfb7eb891f7b37d07c04
license: LicenseRef-Public-Domain
size: 122921
timestamp: 1737119101255
"#;
let lockfile = LockFile::new(content.to_string());
let dependencies = lockfile.get_dependencies(None).unwrap();
assert_eq!(
dependencies,
vec![
"numpy==2.0.2; python_version >= '3.9' and python_version < '3.10.0a0'",
"pandas==2.2.3; python_version >= '3.9' and python_version < '3.10.0a0'",
"python-dateutil==2.9.0.post0; python_version >= '3.9'",
"python-tzdata==2025.1; python_version >= '3.9'",
"pytz==2024.1; python_version >= '3.7'",
"six==1.17.0; python_version >= '3.9'",
]
);
}
}