Skip to content

Latest commit

 

History

History
638 lines (463 loc) · 14.1 KB

File metadata and controls

638 lines (463 loc) · 14.1 KB

PyImport2Pkg v0.2.0 使用说明

Python 导入语句到 pip 包名的反向映射工具

目录


简介

PyImport2Pkg 解决了一个常见问题:给定 Python 代码中的 import 语句,如何知道需要安装哪个 pip 包?

例如:

  • import cv2 → 需要安装 opencv-python
  • from PIL import Image → 需要安装 Pillow
  • import sklearn → 需要安装 scikit-learn

核心功能

  1. 项目分析: 扫描整个项目,生成 requirements.txt
  2. 智能映射: 处理模块名与包名不一致的情况
  3. 命名空间支持: 正确处理 google.cloud.*azure.* 等命名空间包
  4. 可选依赖识别: 区分必需依赖和可选依赖(try-except、平台判断等)
  5. Python 版本感知: 自动检测目标 Python 版本,处理 backports

安装

# 开发模式安装
pip install -e ".[dev]"

# 或直接安装
pip install pyimport2pkg

验证安装:

pyimport2pkg --help

快速开始

分析当前项目

# 分析当前目录,输出到终端
pyimport2pkg analyze .

# 分析并保存到文件
pyimport2pkg analyze . -o requirements.txt

查询单个模块

# 查询 cv2 对应的包
pyimport2pkg query cv2

# 输出:
# Module: cv2
# Package candidates:
#   1. opencv-python (hardcoded)
#   2. opencv-contrib-python (hardcoded)
#   3. opencv-python-headless (hardcoded)

命令详解

analyze - 分析项目

分析 Python 项目中的所有导入语句,生成依赖列表。

基本语法

pyimport2pkg analyze <path> [options]

参数说明

参数 简写 说明 默认值
path - 要分析的文件或目录路径 必需
--output -o 输出文件路径 输出到终端
--format -f 输出格式: requirements/json/simple requirements
--exclude - 排除的目录(逗号分隔)
--exclude-optional - 排除可选依赖 包含可选依赖
--python-version - 目标 Python 版本(如 3.8) 自动检测
--no-comments - 不输出注释 输出注释
--use-database - 使用本地映射数据库 不使用

使用示例

# 基本分析
pyimport2pkg analyze ./myproject

# 排除测试目录
pyimport2pkg analyze . --exclude tests,docs

# 输出 JSON 格式
pyimport2pkg analyze . -f json -o deps.json

# 指定 Python 版本(影响 backports 检测)
pyimport2pkg analyze . --python-version 3.8

# 只输出必需依赖(排除 try-except 等可选导入)
pyimport2pkg analyze . --exclude-optional

# 使用数据库增强映射精度
pyimport2pkg analyze . --use-database

# 简洁输出(无注释,适合管道处理)
pyimport2pkg analyze . --no-comments -f simple

query - 查询映射

查询单个模块名对应的包名。

基本语法

pyimport2pkg query <module_name>

使用示例

# 查询经典不匹配
pyimport2pkg query PIL
# → Pillow (hardcoded)

# 查询命名空间包
pyimport2pkg query google.cloud.storage
# → google-cloud-storage (namespace)

# 查询 PyWin32 模块
pyimport2pkg query win32api
# → pywin32 (pth_injected)

# 查询普通包(猜测)
pyimport2pkg query numpy
# → numpy (guessed)

build-db - 构建数据库

从 PyPI 下载热门包信息,构建本地映射数据库。

基本语法

pyimport2pkg build-db [options]

参数说明

参数 说明 默认值
--max-packages 处理的最大包数量 5000
--concurrency 并发下载数 20

使用示例

# 构建默认大小的数据库
pyimport2pkg build-db

# 构建更大的数据库
pyimport2pkg build-db --max-packages 10000

# 加快构建速度
pyimport2pkg build-db --concurrency 50

输出说明

Building mapping database from top 5000 PyPI packages...
Processing packages: 100%|████████████████| 5000/5000

Database built successfully!
  Total packages: 5000
  Successful: 4850
  Failed: 150

Error breakdown:
  - timeout: 80
  - not_found: 45
  - http_error: 25

Database saved to: ~/.pyimport2pkg/data/mappings.db
Detailed error log: ~/.pyimport2pkg/data/build_errors.json

db-info - 数据库信息

显示本地映射数据库的统计信息。

使用示例

pyimport2pkg db-info

输出示例

Database Information:
  Location: ~/.pyimport2pkg/data/mappings.db
  Size: 12.5 MB

Statistics:
  Total packages: 4850
  Total module mappings: 15230
  Last updated: 2025-12-05 10:30:00

Top packages by download count:
  1. urllib3 (150.2M downloads)
  2. requests (120.5M downloads)
  3. boto3 (98.3M downloads)
  ...

输出格式

requirements 格式(默认)

# Auto-generated by pyimport2pkg
# Generated at: 2025-12-05T10:30:00

# === Required packages ===
numpy
pandas
requests
scikit-learn

# === Conditional imports (if块内,平台/环境相关) ===
pywin32  # conditional in utils.py:15

# === Try-except imports (可选依赖,有替代方案) ===
ujson  # try_except in main.py:8
orjson  # try_except in main.py:12

# === Packages with multiple candidates ===
# cv2 -> opencv-python (10.5M downloads)
#   alternatives: opencv-contrib-python (2.1M), opencv-python-headless (1.8M)

# === Errors (需要手动检查) ===
# [Syntax Error] broken.py:10 - invalid syntax
# [Dynamic Import] utils.py:25 - Dynamic import with non-literal argument

# === Warnings ===
# - Package name 'custom_lib' was guessed. Please verify it's correct.

各 Section 说明

Section 说明
Required packages 顶层无条件导入的包
Conditional imports if 块内的导入(通常是平台/环境相关)
Try-except imports try-except 块内的导入(有替代方案的可选依赖)
Multiple candidates 一个模块对应多个可能的包(需要用户选择)
Errors 解析错误(语法错误、动态导入等)
Warnings 包名是猜测的,建议验证

json 格式

pyimport2pkg analyze . -f json
{
  "meta": {
    "tool": "pyimport2pkg",
    "version": "0.2.0",
    "generated_at": "2025-12-05T10:30:00"
  },
  "required": [
    {
      "package": "numpy",
      "module": "numpy",
      "source": "guessed",
      "files": ["main.py:1", "utils.py:3"]
    },
    {
      "package": "Pillow",
      "module": "PIL",
      "source": "hardcoded",
      "alternatives": [],
      "files": ["image_utils.py:5"]
    }
  ],
  "optional": [
    {
      "package": "ujson",
      "module": "ujson",
      "context": "try_except",
      "source": "guessed",
      "files": ["main.py:8"]
    }
  ],
  "unresolved": [],
  "warnings": [
    "Package name 'custom_lib' was guessed. Please verify it's correct."
  ]
}

simple 格式

pyimport2pkg analyze . -f simple
numpy
pandas
requests
scikit-learn
Pillow

特点:

  • 每行一个包名
  • 无注释
  • 只包含 required 包
  • 适合管道处理:pyimport2pkg analyze . -f simple | xargs pip install

高级用法

1. Python 版本自动检测

工具会按以下优先级自动检测目标 Python 版本:

  1. .python-version 文件(pyenv)
  2. pyproject.tomlrequires-python
  3. setup.cfgpython_requires
  4. .venv/pyvenv.cfg 虚拟环境配置
# 查看检测到的版本(在 stderr 中显示)
pyimport2pkg analyze .
# → Detected Python version: 3.8

# 手动覆盖版本
pyimport2pkg analyze . --python-version 3.6

2. Backports 处理

根据目标 Python 版本自动处理 backports:

模块 标准库版本 低版本需要安装
dataclasses 3.7+ dataclasses
importlib.metadata 3.8+ importlib-metadata
zoneinfo 3.9+ backports.zoneinfo
tomllib 3.11+ tomli
# Python 3.6 项目
pyimport2pkg analyze . --python-version 3.6
# → dataclasses 会出现在依赖列表中

# Python 3.8 项目
pyimport2pkg analyze . --python-version 3.8
# → dataclasses 不会出现(已是标准库)

3. 排除目录

# 排除多个目录
pyimport2pkg analyze . --exclude tests,docs,examples,scripts

# 默认已排除的目录:
# - .venv, venv, env, .env
# - __pycache__
# - .git, .hg, .svn
# - node_modules
# - *.egg-info

4. 与 CI/CD 集成

# GitHub Actions 示例
- name: Generate requirements
  run: |
    pip install pyimport2pkg
    pyimport2pkg analyze . -o requirements.txt --exclude-optional

- name: Install dependencies
  run: pip install -r requirements.txt

5. 管道处理

# 直接安装分析出的包
pyimport2pkg analyze . -f simple --no-comments | xargs pip install

# 比较现有 requirements.txt
diff <(pyimport2pkg analyze . -f simple | sort) <(cat requirements.txt | grep -v '^#' | sort)

# 检查缺失的依赖
pyimport2pkg analyze . -f simple | while read pkg; do
  pip show "$pkg" > /dev/null 2>&1 || echo "Missing: $pkg"
done

Python API

基本用法

from pathlib import Path
from pyimport2pkg.scanner import scan_project
from pyimport2pkg.parser import Parser
from pyimport2pkg.filter import Filter
from pyimport2pkg.mapper import Mapper
from pyimport2pkg.resolver import Resolver
from pyimport2pkg.exporter import Exporter

# 1. 扫描项目
project_path = Path("./myproject")
files = scan_project(project_path)

# 2. 解析导入
parser = Parser()
all_imports = []
for f in files:
    all_imports.extend(parser.parse_file(f))

# 3. 过滤(移除标准库、本地模块)
filter_ = Filter(project_root=project_path)
third_party, filtered = filter_.filter_imports(all_imports)

# 4. 映射到包名
mapper = Mapper()
results = mapper.map_imports(third_party)

# 5. 解决冲突
resolver = Resolver()
results = resolver.resolve_all(results)

# 6. 导出
exporter = Exporter(include_optional=True)
required = [r for r in results if not r.import_info.is_optional]
optional = [r for r in results if r.import_info.is_optional]

content = exporter.export_requirements_txt(required, optional)
print(content)

便捷函数

from pyimport2pkg.exporter import export_requirements, export_json

# 快速导出
content = export_requirements(results, include_optional=True)

# JSON 导出
json_content = export_json(results)

单独使用各模块

# 只用映射功能
from pyimport2pkg.mappings import get_hardcoded_mapping, resolve_namespace_package

pkg = get_hardcoded_mapping("cv2")  # ['opencv-python', ...]
pkg = resolve_namespace_package("google", ["cloud", "storage"])  # ['google-cloud-storage']

# 只用过滤功能
from pyimport2pkg.filter import Filter, detect_python_version

version = detect_python_version(Path("."))  # (3, 8) or None
filter_ = Filter(python_version=(3, 8))
is_stdlib = filter_.is_stdlib("dataclasses")  # False for 3.6, True for 3.7+

# 只用解析功能
from pyimport2pkg.parser import Parser

parser = Parser()
imports = parser.parse_source("import numpy\nfrom PIL import Image")
for imp in imports:
    print(f"{imp.module_name}: {imp.context}, optional={imp.is_optional}")

常见问题

Q: 为什么某些包被标记为 "guessed"?

A: 当模块名与包名相同且不在硬编码映射中时,工具会猜测包名等于模块名。这通常是正确的(如 numpypandas),但建议验证。

Q: 如何处理多候选包(如 cv2)?

A: 工具会列出所有候选并推荐下载量最高的:

# cv2 -> opencv-python (10.5M downloads)
#   alternatives: opencv-contrib-python, opencv-python-headless

根据需求选择:

  • opencv-python: 标准版本
  • opencv-contrib-python: 包含额外模块
  • opencv-python-headless: 无 GUI,适合服务器

Q: 动态导入怎么处理?

A: 动态导入(importlib.import_module(var))无法静态分析,会在 Errors section 中报告:

# [Dynamic Import] utils.py:25 - Dynamic import with non-literal argument

需要手动检查代码并添加依赖。

Q: 如何添加自定义映射?

A: 目前需要修改源码中的 mappings/hardcoded.py。未来版本计划支持配置文件。

Q: 数据库文件存储在哪里?

A: 默认位置:

  • Windows: %USERPROFILE%\.pyimport2pkg\data\mappings.db
  • macOS/Linux: ~/.pyimport2pkg/data/mappings.db

Q: 为什么 --exclude-optional 后某些包消失了?

A: 该选项会排除:

  • try-except 块中的导入(通常有替代方案)
  • if 条件块中的导入(通常是平台相关)

这些是可选依赖,不影响核心功能运行。


映射优先级

工具按以下优先级确定包名:

  1. 命名空间包(有子模块时)

    • google.cloud.storagegoogle-cloud-storage
  2. 硬编码映射

    • cv2opencv-python
    • PILPillow
  3. 命名空间包(仅顶层)

    • google → 多个候选
  4. 数据库查询(如启用)

    • 从 PyPI 元数据获取
  5. 猜测

    • 假设模块名 = 包名

支持的导入类型

导入语句 提取的模块
import numpy numpy
import numpy as np numpy
from PIL import Image PIL
from sklearn.model_selection import train_test_split sklearn.model_selection
from google.cloud import storage google.cloud
from . import utils (相对导入,过滤)
from ..core import base (相对导入,过滤)

版本信息

  • 当前版本: 0.2.0
  • Python 支持: 3.8+
  • 许可证: MIT

获取帮助

# 查看帮助
pyimport2pkg --help
pyimport2pkg analyze --help
pyimport2pkg query --help

# 报告问题
https://github.com/your-repo/pyimport2pkg/issues