{"id":23787591,"url":"https://github.com/peter554/pyimports","last_synced_at":"2026-02-12T10:06:29.809Z","repository":{"id":270160588,"uuid":"720506609","full_name":"Peter554/pyimports","owner":"Peter554","description":"A rust crate for parsing and analyzing the imports within a python package","archived":false,"fork":false,"pushed_at":"2025-02-08T16:59:58.000Z","size":5336,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-23T04:20:32.042Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://crates.io/crates/pyimports","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Peter554.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-18T17:38:53.000Z","updated_at":"2025-02-25T07:34:23.000Z","dependencies_parsed_at":"2025-01-13T22:29:20.731Z","dependency_job_id":"7448f4c7-19ce-4013-84e2-bb42626fc907","html_url":"https://github.com/Peter554/pyimports","commit_stats":null,"previous_names":["peter554/pyimports"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/Peter554/pyimports","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Peter554%2Fpyimports","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Peter554%2Fpyimports/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Peter554%2Fpyimports/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Peter554%2Fpyimports/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Peter554","download_url":"https://codeload.github.com/Peter554/pyimports/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Peter554%2Fpyimports/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29363010,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T08:51:36.827Z","status":"ssl_error","status_checked_at":"2026-02-12T08:51:26.849Z","response_time":55,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-01T15:14:33.686Z","updated_at":"2026-02-12T10:06:29.790Z","avatar_url":"https://github.com/Peter554.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pyimports\n\n\u003e [!NOTE]  \n\u003e I've contributed most of this code to [grimp](https://github.com/seddonym/grimp/).\n\u003e I'd suggest that you look there since grimp is more mature and better maintained.\n\n[![CI](https://github.com/Peter554/pyimports/actions/workflows/ci.yml/badge.svg)](https://github.com/Peter554/pyimports/actions/workflows/ci.yml)\n[![Crates.io](https://img.shields.io/crates/v/pyimports.svg)](https://crates.io/crates/pyimports)\n[![Docs](https://img.shields.io/badge/Docs-grey)](https://docs.rs/pyimports/)\n\nA rust crate for parsing and analyzing the imports within a python package.\n\n## Example\n\nA short example (for more information refer to [the docs](https://docs.rs/pyimports/)):\n\n```rust\nuse anyhow::Result;\nuse maplit::{hashmap,hashset};\n\nuse pyimports::prelude::*;\nuse pyimports::package_info::{PackageInfo,PackageItemToken};\nuse pyimports::imports_info::{ImportsInfo,InternalImportsPathQueryBuilder};\n\n// You shouldn't use `testpackage!`, it just creates a fake python package\n// in a temporary directory. It's (unfortunately) included in the public API\n// so that it can be used in the doctests.\nuse pyimports::{testpackage,testutils::TestPackage};\n\nfn main() -\u003e Result\u003c()\u003e {\n    let testpackage = testpackage! {\n        \"__init__.py\" =\u003e \"from testpackage import a, b\",\n        \"a.py\" =\u003e \"from testpackage import b\",\n        \"b.py\" =\u003e \"from testpackage import c, d\",\n        \"c.py\" =\u003e \"from testpackage import d\",\n        \"d.py\" =\u003e \"\"\n    };\n    let package_info = PackageInfo::build(testpackage.path())?;\n    let imports_info = ImportsInfo::build(package_info)?;\n\n    let item = |pypath: \u0026str| -\u003e Result\u003cPackageItemToken\u003e {\n        Ok(imports_info.package_info().get_item_by_pypath(\u0026pypath.parse()?).unwrap().token())\n    };\n\n    let root_pkg = item(\"testpackage\")?;\n    let root_init = item(\"testpackage.__init__\")?;\n    let a = item(\"testpackage.a\")?;\n    let b = item(\"testpackage.b\")?;\n    let c = item(\"testpackage.c\")?;\n    let d = item(\"testpackage.d\")?;\n\n    assert_eq!(\n        imports_info.internal_imports().get_direct_imports(),\n        hashmap! {\n            root_pkg =\u003e hashset!{root_init},\n            root_init =\u003e hashset!{a, b},\n            a =\u003e hashset!{b},\n            b =\u003e hashset!{c, d},\n            c =\u003e hashset!{d},\n            d =\u003e hashset!{},\n        }\n    );\n\n    assert_eq!(\n        imports_info.internal_imports().get_items_directly_imported_by(root_init)?,\n        hashset! {a, b}\n    );\n\n    assert_eq!(\n        imports_info.internal_imports().get_items_that_directly_import(d)?,\n        hashset! {b, c}\n    );\n\n    assert_eq!(\n        imports_info.internal_imports().get_downstream_items(root_init)?,\n        hashset! {a, b, c, d}\n    );\n\n    assert_eq!(\n        imports_info.internal_imports().find_path(\n            \u0026InternalImportsPathQueryBuilder::default()\n                .from(root_init)\n                .to(d)\n                .build()?\n        )?,\n        Some(vec![root_init, b, d])\n    );\n\n    Ok(())\n}\n```\n\n## Scope\n\nThis crate might be useful for something eventually, but right now it's mainly just\na hobby project for me to learn about rust.\n\nIf you are looking for something more mature, try [grimp](https://github.com/seddonym/grimp/)/[import-linter](https://github.com/seddonym/import-linter).\n\n## Limitations\n\nThe 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).\n\n## Next steps\n\nSome possible next steps that I may explore if/when I get time:\n\n- Fix issue with python parser, to support python 3.12+.\n- Performance benchmarking/improvements.\n- Python bindings (via [maturin](https://github.com/PyO3/maturin)).\n- Higher level features e.g. import contracts, similar to [import-linter](https://github.com/seddonym/import-linter).\n- Faster path calculations (via e.g. [fast_paths](https://github.com/easbar/fast_paths)).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeter554%2Fpyimports","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeter554%2Fpyimports","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeter554%2Fpyimports/lists"}