Skip to content

基本用法

通过简单实用的示例学习 Python Requirements Parser 的基础知识。

概览

本示例演示了 Python Requirements Parser 的核心功能:

  • 解析 requirements.txt 文件
  • 检查解析结果
  • 理解不同的依赖类型

示例代码

这是一个展示基本解析和检查功能的完整示例:

go
package main

import (
    "fmt"
    "log"
    "os"
    "strings"
    
    "github.com/scagogogo/python-requirements-parser/pkg/parser"
    "github.com/scagogogo/python-requirements-parser/pkg/models"
)

func main() {
    fmt.Println("=== Python Requirements Parser - 基本用法 ===")
    fmt.Println()

    // 创建解析器实例
    p := parser.New()

    // 示例 requirements.txt 内容
    content := `# 生产依赖
flask==2.0.1  # Web 框架
django>=3.2.0,<4.0.0  # 另一个 web 框架
requests>=2.25.0  # HTTP 库

# 开发依赖
pytest>=6.0.0  # 测试框架
black==21.9b0  # 代码格式化工具

# 带 extras 的依赖
uvicorn[standard]>=0.15.0  # ASGI 服务器

# 环境标记
pywin32>=1.0; platform_system == "Windows"  # Windows 专用

# VCS 依赖
git+https://github.com/user/project.git#egg=project

# URL 依赖
https://example.com/package.whl

# 文件引用
-r requirements-dev.txt
-c constraints.txt

# 全局选项
--index-url https://pypi.example.com
--trusted-host pypi.example.com`

    fmt.Println("示例 requirements.txt 内容:")
    fmt.Println("================================")
    fmt.Println(content)
    fmt.Println("================================")
    fmt.Println()

    // 解析内容
    reqs, err := p.ParseString(content)
    if err != nil {
        log.Fatalf("解析 requirements 失败: %v", err)
    }

    fmt.Printf("✅ 成功解析 %d\n", len(reqs))
    fmt.Println()

    // 分析和分类 requirements
    analyzeRequirements(reqs)
    
    // 显示每个 requirement 的详细信息
    showDetailedInfo(reqs)
}

func analyzeRequirements(reqs []*models.Requirement) {
    fmt.Println("=== 分析摘要 ===")
    
    stats := struct {
        Total       int
        Packages    int
        Comments    int
        Empty       int
        VCS         int
        URLs        int
        FileRefs    int
        Constraints int
        GlobalOpts  int
        WithExtras  int
        WithMarkers int
    }{}

    for _, req := range reqs {
        stats.Total++
        
        switch {
        case req.IsComment:
            stats.Comments++
        case req.IsEmpty:
            stats.Empty++
        case req.IsVCS:
            stats.VCS++
        case req.IsURL:
            stats.URLs++
        case req.IsFileRef:
            stats.FileRefs++
        case req.IsConstraint:
            stats.Constraints++
        case len(req.GlobalOptions) > 0:
            stats.GlobalOpts++
        case req.Name != "":
            stats.Packages++
            if len(req.Extras) > 0 {
                stats.WithExtras++
            }
            if req.Markers != "" {
                stats.WithMarkers++
            }
        }
    }

    fmt.Printf("📊 总行数: %d\n", stats.Total)
    fmt.Printf("📦 包依赖: %d\n", stats.Packages)
    fmt.Printf("💬 注释: %d\n", stats.Comments)
    fmt.Printf("📄 空行: %d\n", stats.Empty)
    fmt.Printf("🔗 VCS 依赖: %d\n", stats.VCS)
    fmt.Printf("🌐 URL 依赖: %d\n", stats.URLs)
    fmt.Printf("📁 文件引用: %d\n", stats.FileRefs)
    fmt.Printf("🔒 约束: %d\n", stats.Constraints)
    fmt.Printf("⚙️  全局选项: %d\n", stats.GlobalOpts)
    fmt.Printf("🎁 带 extras: %d\n", stats.WithExtras)
    fmt.Printf("🏷️  带 markers: %d\n", stats.WithMarkers)
    fmt.Println()
}

func showDetailedInfo(reqs []*models.Requirement) {
    fmt.Println("=== 详细信息 ===")
    
    for i, req := range reqs {
        fmt.Printf("第 %d 行: ", i+1)
        
        switch {
        case req.IsComment:
            fmt.Printf("💬 注释: %s\n", req.Comment)
            
        case req.IsEmpty:
            fmt.Printf("📄 空行\n")
            
        case req.IsVCS:
            fmt.Printf("🔗 VCS 依赖\n")
            fmt.Printf("   名称: %s\n", req.Name)
            fmt.Printf("   VCS 类型: %s\n", req.VCSType)
            fmt.Printf("   URL: %s\n", req.URL)
            if req.IsEditable {
                fmt.Printf("   可编辑: 是\n")
            }
            
        case req.IsURL:
            fmt.Printf("🌐 URL 依赖\n")
            fmt.Printf("   URL: %s\n", req.URL)
            
        case req.IsFileRef:
            fmt.Printf("📁 文件引用\n")
            fmt.Printf("   文件: %s\n", req.FileRef)
            
        case req.IsConstraint:
            fmt.Printf("🔒 约束文件\n")
            fmt.Printf("   文件: %s\n", req.ConstraintFile)
            
        case len(req.GlobalOptions) > 0:
            fmt.Printf("⚙️  全局选项\n")
            for key, value := range req.GlobalOptions {
                fmt.Printf("   %s: %s\n", key, value)
            }
            
        case req.Name != "":
            fmt.Printf("📦 包: %s\n", req.Name)
            if req.Version != "" {
                fmt.Printf("   版本: %s\n", req.Version)
            }
            if len(req.Extras) > 0 {
                fmt.Printf("   Extras: [%s]\n", strings.Join(req.Extras, ", "))
            }
            if req.Markers != "" {
                fmt.Printf("   Markers: %s\n", req.Markers)
            }
            if req.Comment != "" {
                fmt.Printf("   注释: %s\n", req.Comment)
            }
            
        default:
            fmt.Printf("❓ 未知: %s\n", req.OriginalLine)
        }
        
        fmt.Println()
    }
}

示例输出

运行此示例时,你会看到类似这样的输出:

=== Python Requirements Parser - 基本用法 ===

示例 requirements.txt 内容:
================================
# 生产依赖
flask==2.0.1  # Web 框架
django>=3.2.0,<4.0.0  # 另一个 web 框架
requests>=2.25.0  # HTTP 库

# 开发依赖
pytest>=6.0.0  # 测试框架
black==21.9b0  # 代码格式化工具

# 带 extras 的依赖
uvicorn[standard]>=0.15.0  # ASGI 服务器

# 环境标记
pywin32>=1.0; platform_system == "Windows"  # Windows 专用

# VCS 依赖
git+https://github.com/user/project.git#egg=project

# URL 依赖
https://example.com/package.whl

# 文件引用
-r requirements-dev.txt
-c constraints.txt

# 全局选项
--index-url https://pypi.example.com
--trusted-host pypi.example.com
================================

✅ 成功解析 18 行

=== 分析摘要 ===
📊 总行数: 18
📦 包依赖: 6
💬 注释: 4
📄 空行: 4
🔗 VCS 依赖: 1
🌐 URL 依赖: 1
📁 文件引用: 1
🔒 约束: 1
⚙️  全局选项: 1
🎁 带 extras: 1
🏷️  带 markers: 1

=== 详细信息 ===
第 1 行: 💬 注释: 生产依赖

第 2 行: 📦 包: flask
   版本: ==2.0.1
   注释: Web 框架

第 3 行: 📦 包: django
   版本: >=3.2.0,<4.0.0
   注释: 另一个 web 框架

第 4 行: 📦 包: requests
   版本: >=2.25.0
   注释: HTTP 库

关键概念

1. 解析器创建

go
// 创建基本解析器
p := parser.New()

// 创建支持递归文件解析的解析器
p := parser.NewWithRecursiveResolve()

// 配置解析器选项
p := parser.New()
p.RecursiveResolve = true
p.ProcessEnvVars = true

2. 解析方法

go
// 从字符串解析
reqs, err := p.ParseString(content)

// 从文件解析
reqs, err := p.ParseFile("requirements.txt")

// 从 io.Reader 解析
file, _ := os.Open("requirements.txt")
reqs, err := p.Parse(file)

3. 依赖类型

解析器识别不同类型的依赖:

  • 包依赖: flask==2.0.1
  • 注释: # 这是注释
  • 空行: 用于格式化的空白行
  • VCS 依赖: git+https://github.com/user/project.git
  • URL 依赖: https://example.com/package.whl
  • 文件引用: -r requirements-dev.txt
  • 约束文件: -c constraints.txt
  • 全局选项: --index-url https://pypi.example.com

4. 依赖属性

每个依赖都有各种属性:

go
type Requirement struct {
    Name         string   // 包名
    Version      string   // 版本约束
    Extras       []string // 可选 extras
    Markers      string   // 环境标记
    Comment      string   // 行内注释
    OriginalLine string   // 原始文本
    
    // 类型标志
    IsComment    bool
    IsEmpty      bool
    IsVCS        bool
    IsURL        bool
    IsFileRef    bool
    IsConstraint bool
    IsEditable   bool
    
    // 附加数据
    URL            string
    VCSType        string
    FileRef        string
    ConstraintFile string
    GlobalOptions  map[string]string
    HashOptions    []string
}

错误处理

go
reqs, err := p.ParseFile("requirements.txt")
if err != nil {
    switch {
    case os.IsNotExist(err):
        fmt.Printf("文件未找到: %v\n", err)
    case os.IsPermission(err):
        fmt.Printf("权限被拒绝: %v\n", err)
    default:
        fmt.Printf("解析错误: %v\n", err)
    }
    return
}

过滤依赖

go
// 只获取包依赖
var packages []*models.Requirement
for _, req := range reqs {
    if !req.IsComment && !req.IsEmpty && req.Name != "" {
        packages = append(packages, req)
    }
}

// 只获取注释
var comments []*models.Requirement
for _, req := range reqs {
    if req.IsComment {
        comments = append(comments, req)
    }
}

// 获取 VCS 依赖
var vcsReqs []*models.Requirement
for _, req := range reqs {
    if req.IsVCS {
        vcsReqs = append(vcsReqs, req)
    }
}

下一步

现在你了解了基础知识,可以探索更高级的主题:

相关文档

Released under the MIT License