pypi-server

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PyPI Server Setup

PyPI服务器搭建

This skill provides guidance for creating local PyPI servers to host and distribute Python packages.
本技能提供搭建本地PyPI服务器以托管和分发Python包的指导。

When to Use This Skill

适用场景

  • Setting up a local PyPI repository or package index
  • Building Python packages for distribution (wheel/sdist)
  • Serving packages via HTTP for pip installation
  • Testing package installation from custom index URLs
  • 搭建本地PyPI仓库或包索引
  • 构建用于分发的Python包(wheel/sdist格式)
  • 通过HTTP提供包服务以支持pip安装
  • 测试从自定义索引URL安装包

Environment Reconnaissance (First Step)

环境探查(第一步)

Before planning the approach, gather critical environment information:
  1. Check Python version: Run
    python3 --version
    to determine compatibility constraints
    • Python 3.13+ removed the
      cgi
      module, breaking many older tools like
      pypiserver
    • Plan fallback strategies based on available Python version
  2. Check available system tools: Verify what utilities exist
    • Process management:
      which ps pkill lsof kill
    • Network utilities:
      which curl wget nc
    • Package tools:
      pip list
      to see pre-installed packages
  3. Identify port availability: Check if target ports are free before starting servers
在规划实施方案前,先收集关键的环境信息:
  1. 检查Python版本:运行
    python3 --version
    确定兼容性限制
    • Python 3.13及以上版本移除了
      cgi
      模块,导致
      pypiserver
      等许多旧工具无法使用
    • 根据可用的Python版本制定备选方案
  2. 检查可用的系统工具:确认已安装的实用程序
    • 进程管理:
      which ps pkill lsof kill
    • 网络工具:
      which curl wget nc
    • 包管理工具:
      pip list
      查看已预装的包
  3. 确认端口可用性:启动服务器前检查目标端口是否空闲

Approach Selection

方案选择

Decision Framework

决策框架

ConditionRecommended Approach
Python 3.13+Use
python3 -m http.server
with proper directory structure
Python 3.12 or earlierEither
pypiserver
or
http.server
works
Simple single-package hosting
http.server
is sufficient
Full PyPI mirroring neededConsider
pypiserver
or
devpi
条件推荐方案
Python 3.13+使用
python3 -m http.server
并配置正确的目录结构
Python 3.12或更早版本
pypiserver
http.server
均可使用
仅需托管单个简单包
http.server
已足够
需要完整的PyPI镜像考虑使用
pypiserver
devpi

Recommended Default: Python's Built-in HTTP Server

推荐默认方案:Python内置HTTP服务器

For most local PyPI hosting tasks, use
python3 -m http.server
with the correct directory structure. This approach:
  • Has no external dependencies
  • Works across all Python versions
  • Is simpler to configure and debug
对于大多数本地PyPI托管任务,建议使用
python3 -m http.server
并搭配正确的目录结构。该方案:
  • 无外部依赖
  • 支持所有Python版本
  • 配置和调试更简单

Directory Structure Requirements

目录结构要求

Pip expects a specific directory structure when using
--index-url
:
server_root/
└── simple/
    └── <package-name>/
        └── <package-name>-<version>-py3-none-any.whl
Critical Details:
  • The
    simple/
    directory must be at the root of the served directory
  • Package names in the directory should be normalized (lowercase, hyphens to underscores for some cases)
  • The server must be started from the directory containing
    simple/
    , not from within it
使用
--index-url
时,pip要求特定的目录结构:
server_root/
└── simple/
    └── <package-name>/
        └── <package-name>-<version>-py3-none-any.whl
关键细节:
  • simple/
    目录必须位于服务器根目录下
  • 目录中的包名需要规范化(小写,部分情况下将下划线替换为连字符)
  • 必须从包含
    simple/
    的目录启动服务器,而不是从
    simple/
    目录内部启动

Building Python Packages

构建Python包

Standard Package Structure

标准包结构

package_name/
├── setup.py
├── pyproject.toml (optional but recommended)
└── package_name/
    ├── __init__.py
    └── module.py
package_name/
├── setup.py
├── pyproject.toml (optional but recommended)
└── package_name/
    ├── __init__.py
    └── module.py

Minimal setup.py Example

最简setup.py示例

python
from setuptools import setup, find_packages

setup(
    name="package-name",
    version="0.1.0",
    packages=find_packages(),
)
python
from setuptools import setup, find_packages

setup(
    name="package-name",
    version="0.1.0",
    packages=find_packages(),
)

Build Commands

构建命令

bash
undefined
bash
undefined

Build wheel and source distribution

Build wheel and source distribution

python3 -m pip install build python3 -m build
python3 -m pip install build python3 -m build

Output appears in dist/

Output appears in dist/

undefined
undefined

Server Setup Steps

服务器搭建步骤

Step 1: Create Directory Structure

步骤1:创建目录结构

bash
mkdir -p pypi-server/simple/packagename/
cp dist/*.whl pypi-server/simple/packagename/
bash
mkdir -p pypi-server/simple/packagename/
cp dist/*.whl pypi-server/simple/packagename/

Step 2: Start HTTP Server

步骤2:启动HTTP服务器

bash
cd pypi-server
python3 -m http.server 8080
Important: Start the server from the directory that contains
simple/
, not from within
simple/
.
bash
cd pypi-server
python3 -m http.server 8080
注意: 必须从包含
simple/
的目录启动服务器,而不是从
simple/
目录内部启动。

Step 3: Verify Server

步骤3:验证服务器

Test that the structure is correct:
bash
curl http://localhost:8080/simple/
curl http://localhost:8080/simple/packagename/
测试目录结构是否正确:
bash
curl http://localhost:8080/simple/
curl http://localhost:8080/simple/packagename/

Verification Strategy

验证策略

Pre-Installation Checks

安装前检查

  1. Verify server is running:
    curl -I http://localhost:PORT/
  2. Verify simple index exists:
    curl http://localhost:PORT/simple/
  3. Verify package directory exists:
    curl http://localhost:PORT/simple/packagename/
  4. Verify wheel file is accessible:
    curl -I http://localhost:PORT/simple/packagename/file.whl
  1. 验证服务器是否运行:
    curl -I http://localhost:PORT/
  2. 验证simple索引是否存在:
    curl http://localhost:PORT/simple/
  3. 验证包目录是否存在:
    curl http://localhost:PORT/simple/packagename/
  4. 验证wheel文件是否可访问:
    curl -I http://localhost:PORT/simple/packagename/file.whl

Installation Test

安装测试

bash
pip install --index-url http://localhost:PORT/simple packagename==version
bash
pip install --index-url http://localhost:PORT/simple packagename==version

Post-Installation Verification

安装后验证

python
import packagename
python
import packagename

Test core functionality

Test core functionality

undefined
undefined

Common Pitfalls and Solutions

常见问题与解决方案

1. Port Already in Use

1. 端口已被占用

Symptom:
OSError: [Errno 98] Address already in use
Solutions:
  • Use a different port
  • Find and kill the existing process:
    python
    import socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  • Create a custom server script with
    SO_REUSEADDR
    option
症状:
OSError: [Errno 98] Address already in use
解决方案:
  • 使用其他端口
  • 查找并终止占用端口的进程:
    python
    import socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  • 创建带有
    SO_REUSEADDR
    选项的自定义服务器脚本

2. Wrong Directory Structure

2. 目录结构错误

Symptom:
404 Not Found
when pip tries to access
/simple/
Cause: Server started from wrong directory or missing
simple/
prefix
Solution: Verify the URL
http://localhost:PORT/simple/
returns a directory listing
症状: pip访问
/simple/
时返回
404 Not Found
原因: 服务器启动目录错误或缺少
simple/
前缀
解决方案: 验证
http://localhost:PORT/simple/
是否返回目录列表

3. Python 3.13+ Compatibility

3. Python 3.13+兼容性问题

Symptom:
ModuleNotFoundError: No module named 'cgi'
when using pypiserver
Cause: Python 3.13 removed the deprecated
cgi
module
Solution: Use
python3 -m http.server
instead of pypiserver
症状: 使用pypiserver时出现
ModuleNotFoundError: No module named 'cgi'
原因: Python 3.13移除了已弃用的
cgi
模块
解决方案: 使用
python3 -m http.server
替代pypiserver

4. Process Management Without Standard Tools

4. 无标准工具时的进程管理

Symptom: Cannot find or kill background processes (ps/pkill not available)
Solutions:
  • Use Python's process management:
    python
    import subprocess
    proc = subprocess.Popen(['python3', '-m', 'http.server', '8080'])
    # Save proc.pid for later termination
  • Use
    /proc
    filesystem on Linux:
    ls /proc/*/cmdline
  • Track PIDs explicitly when starting background processes
症状: 无法查找或终止后台进程(ps/pkill不可用)
解决方案:
  • 使用Python的进程管理功能:
    python
    import subprocess
    proc = subprocess.Popen(['python3', '-m', 'http.server', '8080'])
    # Save proc.pid for later termination
  • 在Linux系统上使用
    /proc
    文件系统:
    ls /proc/*/cmdline
  • 启动后台进程时显式记录PID

5. Shell Compatibility

5. Shell兼容性问题

Symptom:
source: not found
when sourcing files
Cause: Using
source
in sh shell (source is a bash feature)
Solution: Use
.
instead of
source
for POSIX compatibility:
bash
. ./venv/bin/activate
症状: 执行source命令时出现
source: not found
原因: 在sh shell中使用source命令(source是bash的特性)
解决方案: 为了兼容POSIX标准,使用
.
替代
source
bash
. ./venv/bin/activate

6. Package Name Normalization

6. 包名规范化问题

Symptom: Package not found despite correct structure
Cause: Pip normalizes package names (underscores to hyphens, lowercase)
Solution: Use lowercase names and be consistent with hyphens/underscores
症状: 目录结构正确但找不到包
原因: Pip会对包名进行规范化处理(下划线替换为连字符,转为小写)
解决方案: 使用小写包名,保持连字符/下划线的一致性

Custom Server Script (Robust Alternative)

自定义服务器脚本(更可靠的替代方案)

For better process control and port reuse, consider a custom server script:
python
#!/usr/bin/env python3
import http.server
import socketserver
import os

PORT = 8080
DIRECTORY = "/path/to/pypi-server"

os.chdir(DIRECTORY)

class ReuseAddrServer(socketserver.TCPServer):
    allow_reuse_address = True

handler = http.server.SimpleHTTPRequestHandler
with ReuseAddrServer(("", PORT), handler) as httpd:
    print(f"Serving at port {PORT}")
    httpd.serve_forever()
为了更好地控制进程和实现端口复用,可以使用自定义服务器脚本:
python
#!/usr/bin/env python3
import http.server
import socketserver
import os

PORT = 8080
DIRECTORY = "/path/to/pypi-server"

os.chdir(DIRECTORY)

class ReuseAddrServer(socketserver.TCPServer):
    allow_reuse_address = True

handler = http.server.SimpleHTTPRequestHandler
with ReuseAddrServer(("", PORT), handler) as httpd:
    print(f"Serving at port {PORT}")
    httpd.serve_forever()

Checklist Before Starting

启动前检查清单

  • Verified Python version and tool compatibility
  • Created correct directory structure with
    simple/
    prefix
  • Built package successfully (wheel exists in dist/)
  • Copied wheel to correct location under
    simple/packagename/
  • Confirmed target port is available
  • Plan for process management (how to stop the server later)
  • 已验证Python版本和工具兼容性
  • 已创建带
    simple/
    前缀的正确目录结构
  • 已成功构建包(dist/目录下存在wheel文件)
  • 已将wheel文件复制到
    simple/packagename/
    下的正确位置
  • 已确认目标端口可用
  • 已规划进程管理方案(后续如何停止服务器)