# PyPI 发布指南

本文档介绍如何将 `bstart-trb` 包发布到 PyPI。

## 准备工作

### 1. 确保代码已更新并测试通过

```bash
# 运行测试
uv run python test_install.py
```

### 2. 更新版本号

编辑以下两个文件中的版本号：
- `pyproject.toml` - 第 3 行的 `version`
- `slice_wrapper/__init__.py` - 最后一行的 `__version__`

版本号格式：`major.minor.patch`
- **major**: 重大功能更新或不兼容的 API 变更
- **minor**: 新增功能或模块（向下兼容）
- **patch**: Bug 修复、代码优化、小改动

示例：
```
0.1.0 -> 0.1.1  (Bug 修复)
0.1.1 -> 0.2.0  (新增功能)
0.2.0 -> 1.0.0  (重大更新)
```

### 3. 确保 `.pyd` 文件是最新的

如果修改了 Fortran 代码，需要重新编译：

```bash
cd slice_wrapper
uv run python build.py
```

## 构建包

### 1. 清理旧的构建产物

```bash
Remove-Item -Path "dist" -Recurse -Force -ErrorAction SilentlyContinue
```

### 2. 构建 wheel 和 sdist

```bash
uv build
```

这将在 `dist/` 目录下生成两个文件：
- `bstart_trb-{version}-py3-none-any.whl` - wheel 包（包含预编译的 .pyd）
- `bstart_trb-{version}.tar.gz` - 源码发行版

### 3. 验证构建的包

检查 wheel 内容：
```bash
python -m zipfile -l dist\bstart_trb-{version}-py3-none-any.whl
```

确认包含以下文件：
- ✅ `slice_wrapper/__init__.py`
- ✅ `slice_wrapper/models.py`
- ✅ `slice_wrapper/wrapper.py`
- ✅ `slice_wrapper/_taper_slice.pyi`
- ✅ `slice_wrapper/py.typed`
- ✅ `slice_wrapper/_taper_slice.cp312-win_amd64.pyd`  ← **重要！预编译的二进制文件**
- ❌ `taper_slice.f90` - **应该被排除**
- ❌ `build.py` - **应该被排除**

## 发布到 PyPI

### 1. 注册 PyPI 账号

- 生产环境：https://pypi.org/account/register/
- 测试环境：https://test.pypi.org/account/register/

### 2. 创建 API Token

1. 登录 PyPI
2. 进入账户设置 -> API tokens
3. 创建新的 token（选择 "Entire account" 或指定项目）
4. 保存 token（只显示一次！）

### 3. 配置 twine

创建 `~/.pypirc` 文件（Windows: `C:\Users\{用户名}\.pypirc`）：

```ini
[distutils]
index-servers =
    pypi
    testpypi

[pypi]
username = __token__
password = pypi-AgEIcHlwaS5vcmcC...你的token...

[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi-AgENdGVzdC5weXBpLm9yZwI...你的token...
```

**注意**：将 `.pypirc` 添加到 `.gitignore`，不要提交到 Git！

### 4. 上传到测试 PyPI（推荐先测试）

```bash
uv run twine upload --repository testpypi dist/*
```

测试安装：
```bash
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ bstart-trb
```

### 5. 上传到生产 PyPI

确认测试无误后：

```bash
uv run twine upload dist/*
```

## 发布后

### 1. 测试安装

```bash
# 在新的虚拟环境中测试
pip install bstart-trb
```

### 2. 创建 Git 标签

```bash
git add pyproject.toml slice_wrapper/__init__.py
git commit -m "v0.1.0  发布到 PyPI"
git tag v0.1.0
git push origin main --tags
```

### 3. 创建 GitHub Release（可选）

1. 前往 GitHub 仓库的 "Releases" 页面
2. 点击 "Create a new release"
3. 选择刚才创建的标签
4. 编写 Release Notes
5. 附加构建的 wheel 文件

## 常见问题

### Q: 如何支持多个 Python 版本？

A: 当前包只包含 Python 3.12 的编译文件（`cp312`）。如需支持其他版本：
1. 在不同 Python 版本下重新编译 `.pyd` 文件
2. 将所有 `.pyd` 文件添加到 `slice_wrapper/` 目录
3. 重新构建包

### Q: 如何支持 Linux 和 macOS？

A: 需要在对应平台上编译：
1. 在 Linux 上运行 `python build.py`，生成 `.so` 文件
2. 在 macOS 上运行 `python build.py`，生成 `.so` 文件
3. 将所有编译文件添加到包中
4. 重新构建并上传

### Q: 上传失败：文件已存在

A: PyPI 不允许覆盖已发布的版本。解决方案：
1. 递增版本号（如 0.1.0 -> 0.1.1）
2. 重新构建并上传

### Q: 用户安装后提示找不到 Fortran 模块

A: 检查：
1. 用户的 Python 版本是否为 3.12（当前只支持 3.12）
2. 用户的操作系统是否为 Windows x64
3. 包是否正确包含了 `.pyd` 文件

## 自动化发布（高级）

可以使用 GitHub Actions 自动发布：

```yaml
# .github/workflows/publish.yml
name: Publish to PyPI

on:
  release:
    types: [published]

jobs:
  deploy:
    runs-on: windows-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v4
      with:
        python-version: '3.12'
    - name: Install dependencies
      run: |
        pip install uv
        uv pip install hatchling twine
    - name: Build package
      run: uv build
    - name: Publish to PyPI
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: uv run twine upload dist/*
```

## 参考链接

- [PyPI 官方文档](https://packaging.python.org/tutorials/packaging-projects/)
- [Twine 文档](https://twine.readthedocs.io/)
- [PEP 517 构建系统](https://peps.python.org/pep-0517/)
