use std::{collections::BTreeSet, path::Path, path::PathBuf};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PythonModuleSuffixes {
pub source: Vec<String>,
pub bytecode: Vec<String>,
pub debug_bytecode: Vec<String>,
pub optimized_bytecode: Vec<String>,
pub extension: Vec<String>,
}
pub fn packages_from_module_name(module: &str) -> BTreeSet<String> {
let mut package_names = BTreeSet::new();
let mut search: &str = module;
while let Some(idx) = search.rfind('.') {
package_names.insert(search[0..idx].to_string());
search = &search[0..idx];
}
package_names
}
pub fn packages_from_module_names<I>(names: I) -> BTreeSet<String>
where
I: Iterator<Item = String>,
{
let mut package_names = BTreeSet::new();
for name in names {
let mut search: &str = &name;
while let Some(idx) = search.rfind('.') {
package_names.insert(search[0..idx].to_string());
search = &search[0..idx];
}
}
package_names
}
pub fn resolve_path_for_module(
root: &str,
name: &str,
is_package: bool,
bytecode_tag: Option<&str>,
) -> PathBuf {
let mut module_path = PathBuf::from(root);
let parts = name.split('.').collect::<Vec<&str>>();
for part in &parts[0..parts.len() - 1] {
module_path.push(*part);
}
if is_package {
module_path.push(parts[parts.len() - 1]);
}
if bytecode_tag.is_some() {
module_path.push("__pycache__");
}
let basename = if is_package {
"__init__"
} else {
parts[parts.len() - 1]
};
let suffix = if let Some(tag) = bytecode_tag {
format!(".{}.pyc", tag)
} else {
".py".to_string()
};
module_path.push(format!("{}{}", basename, suffix));
module_path
}
pub fn is_package_from_path(path: &Path) -> bool {
let file_name = path.file_name().unwrap().to_str().unwrap();
file_name.starts_with("__init__.")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_packages_from_module_name() {
assert_eq!(
packages_from_module_name("foo.bar"),
["foo".to_string()].iter().cloned().collect()
);
assert_eq!(
packages_from_module_name("foo.bar.baz"),
["foo".to_string(), "foo.bar".to_string()]
.iter()
.cloned()
.collect()
);
}
#[test]
fn test_resolve_path_for_module() {
assert_eq!(
resolve_path_for_module(".", "foo", false, None),
PathBuf::from("./foo.py")
);
assert_eq!(
resolve_path_for_module(".", "foo", false, Some("cpython-37")),
PathBuf::from("./__pycache__/foo.cpython-37.pyc")
);
assert_eq!(
resolve_path_for_module(".", "foo", true, None),
PathBuf::from("./foo/__init__.py")
);
assert_eq!(
resolve_path_for_module(".", "foo", true, Some("cpython-37")),
PathBuf::from("./foo/__pycache__/__init__.cpython-37.pyc")
);
assert_eq!(
resolve_path_for_module(".", "foo.bar", false, None),
PathBuf::from("./foo/bar.py")
);
assert_eq!(
resolve_path_for_module(".", "foo.bar", false, Some("cpython-37")),
PathBuf::from("./foo/__pycache__/bar.cpython-37.pyc")
);
assert_eq!(
resolve_path_for_module(".", "foo.bar", true, None),
PathBuf::from("./foo/bar/__init__.py")
);
assert_eq!(
resolve_path_for_module(".", "foo.bar", true, Some("cpython-37")),
PathBuf::from("./foo/bar/__pycache__/__init__.cpython-37.pyc")
);
assert_eq!(
resolve_path_for_module(".", "foo.bar.baz", false, None),
PathBuf::from("./foo/bar/baz.py")
);
assert_eq!(
resolve_path_for_module(".", "foo.bar.baz", false, Some("cpython-37")),
PathBuf::from("./foo/bar/__pycache__/baz.cpython-37.pyc")
);
assert_eq!(
resolve_path_for_module(".", "foo.bar.baz", true, None),
PathBuf::from("./foo/bar/baz/__init__.py")
);
assert_eq!(
resolve_path_for_module(".", "foo.bar.baz", true, Some("cpython-37")),
PathBuf::from("./foo/bar/baz/__pycache__/__init__.cpython-37.pyc")
);
}
}