https://github.com/peter554/pyimports
A rust crate for parsing and analyzing the imports within a python package
https://github.com/peter554/pyimports
Last synced: 5 months ago
JSON representation
A rust crate for parsing and analyzing the imports within a python package
- Host: GitHub
- URL: https://github.com/peter554/pyimports
- Owner: Peter554
- License: mit
- Created: 2023-11-18T17:38:53.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2025-02-08T16:59:58.000Z (over 1 year ago)
- Last Synced: 2025-11-23T04:20:32.042Z (8 months ago)
- Language: Rust
- Homepage: https://crates.io/crates/pyimports
- Size: 5.09 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# pyimports
> [!NOTE]
> I've contributed most of this code to [grimp](https://github.com/seddonym/grimp/).
> I'd suggest that you look there since grimp is more mature and better maintained.
[](https://github.com/Peter554/pyimports/actions/workflows/ci.yml)
[](https://crates.io/crates/pyimports)
[](https://docs.rs/pyimports/)
A rust crate for parsing and analyzing the imports within a python package.
## Example
A short example (for more information refer to [the docs](https://docs.rs/pyimports/)):
```rust
use anyhow::Result;
use maplit::{hashmap,hashset};
use pyimports::prelude::*;
use pyimports::package_info::{PackageInfo,PackageItemToken};
use pyimports::imports_info::{ImportsInfo,InternalImportsPathQueryBuilder};
// You shouldn't use `testpackage!`, it just creates a fake python package
// in a temporary directory. It's (unfortunately) included in the public API
// so that it can be used in the doctests.
use pyimports::{testpackage,testutils::TestPackage};
fn main() -> Result<()> {
let testpackage = testpackage! {
"__init__.py" => "from testpackage import a, b",
"a.py" => "from testpackage import b",
"b.py" => "from testpackage import c, d",
"c.py" => "from testpackage import d",
"d.py" => ""
};
let package_info = PackageInfo::build(testpackage.path())?;
let imports_info = ImportsInfo::build(package_info)?;
let item = |pypath: &str| -> Result {
Ok(imports_info.package_info().get_item_by_pypath(&pypath.parse()?).unwrap().token())
};
let root_pkg = item("testpackage")?;
let root_init = item("testpackage.__init__")?;
let a = item("testpackage.a")?;
let b = item("testpackage.b")?;
let c = item("testpackage.c")?;
let d = item("testpackage.d")?;
assert_eq!(
imports_info.internal_imports().get_direct_imports(),
hashmap! {
root_pkg => hashset!{root_init},
root_init => hashset!{a, b},
a => hashset!{b},
b => hashset!{c, d},
c => hashset!{d},
d => hashset!{},
}
);
assert_eq!(
imports_info.internal_imports().get_items_directly_imported_by(root_init)?,
hashset! {a, b}
);
assert_eq!(
imports_info.internal_imports().get_items_that_directly_import(d)?,
hashset! {b, c}
);
assert_eq!(
imports_info.internal_imports().get_downstream_items(root_init)?,
hashset! {a, b, c, d}
);
assert_eq!(
imports_info.internal_imports().find_path(
&InternalImportsPathQueryBuilder::default()
.from(root_init)
.to(d)
.build()?
)?,
Some(vec![root_init, b, d])
);
Ok(())
}
```
## Scope
This crate might be useful for something eventually, but right now it's mainly just
a hobby project for me to learn about rust.
If you are looking for something more mature, try [grimp](https://github.com/seddonym/grimp/)/[import-linter](https://github.com/seddonym/import-linter).
## Limitations
The python parser used within this crate does not currently support python 3.12+ - see the related GitHub issue [here](https://github.com/RustPython/Parser/issues/125).
## Next steps
Some possible next steps that I may explore if/when I get time:
- Fix issue with python parser, to support python 3.12+.
- Performance benchmarking/improvements.
- Python bindings (via [maturin](https://github.com/PyO3/maturin)).
- Higher level features e.g. import contracts, similar to [import-linter](https://github.com/seddonym/import-linter).
- Faster path calculations (via e.g. [fast_paths](https://github.com/easbar/fast_paths)).