首页
/ PostHog 无 flox 环境后端测试搭建指南:Claude Code for web 中从零运行 pytest 的完整方案

PostHog 无 flox 环境后端测试搭建指南:Claude Code for web 中从零运行 pytest 的完整方案

2026-09-09 18:14:24作者:范靓好Udolf

本篇指南面向需要在 Claude Code for web(或其他没有 flox 的开发容器)中运行 PostHog 后端测试的开发者,核心解决 uv sync 因 Python 版本不匹配而失败的问题。读完你将掌握:如何从 python-build-standalone 下载与 pyproject.toml 锁定版本一致的 Python 解释器、如何完成 uv sync 依赖安装、如何启动 Docker 测试依赖服务、如何配置 /etc/hosts 与测试环境变量,以及如何用 hogli test / pytest 精确运行单个测试或整个目录。文中所有步骤均已对照当前仓库的 pyproject.tomlpytest.ini.github/workflows/ci-backend.yml 等真实配置逐一验证。

问题背景:为什么 uv sync 会在受限环境中失败

PostHog 在 pyproject.toml 中通过 requires-python = "==3.13.13" 将 Python 版本精确锁定到完整的 主版本.次版本.补丁版本,注释明确写道:"Pin full version to control Python upgrades explicitly"(显式固定完整版本以控制 Python 升级)。这一策略带来三个连锁约束:

  1. 系统 Python 版本不匹配:Claude Code for web 等托管容器中预装的系统 Python 往往是通用版本,几乎不可能恰好是 3.13.13。
  2. uv python install 可能失效uv sync 依赖 uv 的 Python 索引,当所需版本尚未被 uv 收录(例如版本过新)时,uv python install <version> 会直接失败。
  3. uv sync 强制执行精确约束:uv 会严格校验解释器版本与 requires-python 的一致性,只要系统 Python 不是 3.13.13,uv sync 就会报错退出,导致整个测试环境无法建立。

因此,问题的本质是:在这个仓库里,"找到恰好 3.13.13 的解释器" 是运行任何后端测试的前置条件。这也解释了为什么仓库的 CI(.github/workflows/ci-backend.yml)中所有测试 Job 都通过 setup-python-cached action 显式安装 python-version: 3.13.13,例如 product 测试矩阵中的 "Set up Python" 步骤。本地与 CI 使用完全一致的解释器版本,是保证测试行为一致的前提。

解决方案:从 python-build-standalone 下载精确版本的 Python

由于没有 flox(PostHog 团队常用的环境管理工具)可用,替代方案是直接从 astral-sh/python-build-standalone 的 GitHub Releases 下载与 pyproject.toml 精确匹配的 CPython 独立构建(install_only 精简包)。下面的脚本会自动完成版本探测、Release 查询、匹配与下载解压的全过程:

# Auto-detect the required version from pyproject.toml
REQUIRED_VERSION=$(grep requires-python pyproject.toml | grep -oP '[\d.]+')
echo "Required Python: $REQUIRED_VERSION"

# Get the latest release tag from python-build-standalone
RELEASE_TAG=$(curl -sL "https://api.github.com/repos/astral-sh/python-build-standalone/releases/latest" | grep '"tag_name"' | cut -d'"' -f4)

# Find and download the matching build
DOWNLOAD_URL=$(curl -sL "https://api.github.com/repos/astral-sh/python-build-standalone/releases/latest" | \
  grep "browser_download_url" | grep "$REQUIRED_VERSION" | grep "x86_64-unknown-linux-gnu-install_only.tar.gz" | head -1 | cut -d'"' -f4)

mkdir -p /tmp/python-install && cd /tmp/python-install
curl -L -o python.tar.gz "$DOWNLOAD_URL"
tar -xzf python.tar.gz

# Verify
/tmp/python-install/python/bin/python3 --version

脚本各步骤的说明:

  • 版本探测grep requires-python pyproject.toml 提取 pyproject.toml 中的 requires-python 行(当前为 ==3.13.13),再用正则 [\d.]+ 抽出 3.13.13 这一精确版本号,保证与锁定版本零偏差。
  • Release 查询:调用 GitHub API 获取 python-build-standalone 的最新 Release 元数据。
  • 资产匹配:从 browser_download_url 列表中筛选同时满足"包含目标版本号"与"x86_64-unknown-linux-gnu-install_only.tar.gz 后缀"的资产,这正是 x86_64 Linux 上的精简安装包。
  • 验证:下载解压后执行 python3 --version 确认解释器可用。

手动兜底:如果自动探测没有找到匹配的 URL(例如锁定版本太新、尚未发布对应构建),可以打开 python-build-standalone 的 Releases 页面手动查找形如 cpython-<version>+<tag>-x86_64-unknown-linux-gnu-install_only.tar.gz 的资产,把 URL 填入 DOWNLOAD_URL 后重跑下载解压部分即可。本仓库当前锁定 3.13.13,通常能直接命中。

安装依赖并运行测试

拿到正确的解释器后,用 --python 参数让 uv 使用该解释器完成同步,然后激活虚拟环境并运行测试:

cd /home/user/posthog
uv sync --python /tmp/python-install/python/bin/python3
source .venv/bin/activate

# Run a specific test (if hogli is available)
hogli test path/to/test.py::TestClass::test_method -v

# Or use pytest directly
pytest path/to/test.py::TestClass::test_method -v

# Run all tests in a directory
hogli test posthog/hogql/test/ -v

几点实践细节:

  • uv sync --python <path> 显式指定解释器路径,绕过了 uv 自带的 Python 下载/发现逻辑,直接把 python-build-standalone 的构建作为项目解释器;该命令同时会依据 pyproject.toml[dependency-groups] 安装 dev 依赖组(pytest~=8.4.2pytest-django~=4.14.0hogli 等均在 dev 组中)。
  • hogli 是 PostHog 的开发者 CLI(声明于 [dependency-groups] dev 中,工作区成员见 pyproject.toml[tool.uv.workspace]members = ["tools/hogli", "tools/owners"])。如果 hogli 不可用,直接用 pytest 是等价的替代路径。
  • 运行整目录测试时,posthog/hogql 是典型的可执行用例,hogli test posthog/hogql/test/ -v 会递归收集该目录下所有测试。
  • CI 中的等价做法(.github/workflows/ci-backend.yml)是 UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync --frozen --dev,其中 --frozen 表示严格按 uv.lock 锁定文件安装,不重新解析依赖——本地如果希望与 CI 完全一致,也可以加上 --frozen

Docker 服务:大多数测试的前置依赖

PostHog 的后端测试大量依赖外部中间件(Kafka、ClickHouse、Redis、对象存储、Temporal 等)。如果环境中有 Docker,用以下命令一次性拉起测试所需的全部服务:

docker compose -f docker-compose.dev.yml up -d

服务清单以 docker-compose.dev.yml 为准(该文件头部注释即写明 "docker-compose file used ONLY for local development")。从文件的服务定义可以看到完整的测试依赖栈:

  • proxy:Caddy 反向代理,将 /e/batch/i/v0/* 等路径路由到 capture 等服务(docker-compose.dev.yml)。
  • capture / capture-ai / capture-logs / capture-apm-metrics:PostHog 的 Rust 事件采集服务(image: ghcr.io/posthog/posthog/capture:${POSTHOG_CAPTURE_TAG:-master})。
  • posthog-node 系列:Node 侧能力服务(ghcr.io/posthog/posthog-node:${POSTHOG_NODE_TAG:-master})。
  • browserless:Chromium 容器(ghcr.io/browserless/chromium:v2.51.2),用于热图截图与图片导出类测试。
  • valkey / redis:缓存与消息队列(valkey/valkey:8.1-alpineredis:7.2)。
  • redpanda:Kafka 协议兼容的消息代理(docker.io/redpandadata/redpanda:v25.1.9),测试中的 kafka 主机名即指向它。
  • webhook-tester / curl / otel-collector-local / jaeger-local / dynamodb-main / seaweedfs-main / etcd 等辅助服务。

部分测试目录还有自己特殊的服务要求,通常记录在各测试目录自身的配置文件或对应 CI 中,例如 ci-backend.ymlCOMPOSE_PROFILES: temporal,azure 表明 Temporal 与 Azure 相关服务通过 profile 按需启用。

Hosts 文件配置

测试代码中会以固定的主机名访问上述服务,因此这些主机名必须解析到 localhost:

echo "127.0.0.1 kafka clickhouse clickhouse-coordinator objectstorage" | sudo tee -a /etc/hosts

这一行为与 CI 完全一致:在 .github/workflows/ci-backend.yml 中可以看到 CI 执行的是 echo "127.0.0.1 db redis7 kafka clickhouse clickhouse-coordinator objectstorage temporal" | sudo tee -a /etc/hosts——本地环境可以按需对照补充 dbredis7temporal 等主机名,具体以你要运行的测试所连接的服务为准。

环境变量:对齐 CI 与本地默认值

测试运行所需的绝大多数环境变量都定义在 .github/workflows/ci-backend.yml 顶部的 env: 区块。以下是当前仓库 CI 中实际设置的关键变量(可作为本地测试的最小可运行参考集):

变量 值(CI) 用途
SECRET_KEY '6b01eee4...'(测试专用假密钥) Django 签名密钥,仅测试用
DATABASE_URL postgres://posthog:posthog@localhost:5432/posthog PostgreSQL 连接串
REDIS_URL redis://localhost Redis 连接
CLICKHOUSE_HOST / CLICKHOUSE_SECURE / CLICKHOUSE_VERIFY localhost / False / False ClickHouse 连接与 TLS 开关
CLICKHOUSE_TEST_CLUSTER_HOST / _DATABASE / _USER / _PASSWORD localhost / posthog_test / autoresearch / autoresearchpass 测试专用 ClickHouse 集群(用户定义于 docker/clickhouse/users-dev.xml
TEST 1 测试模式标志
OBJECT_STORAGE_ENABLED / _ENDPOINT / _ACCESS_KEY_ID / _SECRET_ACCESS_KEY True / http://localhost:19000 / object_storage_root_user / object_storage_root_password 对象存储(SeaweedFS)配置
DISPLAY ':99.0' 无头显示(CI 用于规避退出码 134 的偶发问题)
OIDC_RSA_PRIVATE_KEY / SANDBOX_JWT_PRIVATE_KEY 假密钥 OIDC / 沙箱 JWT 签名

此外,可以复制 .env.example.env 获取本地开发默认值。需要特别留意的是,.env.example 头部有醒目警告:其中包含的 OIDC_RSA_PRIVATE_KEYSANDBOX_JWT_PRIVATE_KEY公开已知的、仅限本地开发的假密钥,任何人拿到它都可以在未保护环境下伪造合法 token,严禁在任意生产环境复用

附加设置:前端产物占位与 SAML 依赖

前端 dist 占位文件

部分测试(例如涉及模板渲染、URL 反转的 Django 测试)要求 frontend/dist 下存在构建产物文件,即便内容为空也可以。这与 CI 的做法(.github/workflows/ci-backend.yml 中的 "Set up needed files" 步骤)一致:

mkdir -p frontend/dist
touch frontend/dist/index.html
touch frontend/dist/layout.html
touch frontend/dist/exporter.html

SAML 依赖(按需)

仅当要运行与 SAML 单点登录相关的功能(涉及 python3-samlxmlsec,二者均为 pyproject.toml 的运行时依赖)时才需要安装系统级 XML 安全库。CI 中的安装命令为(.github/workflows/ci-backend.yml):

sudo apt-get update
sudo apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl

pytest 配置:pythonpath、Django 与默认忽略项

测试行为由 pytest.ini 统一控制,其关键配置如下:

  • pythonpath = . common tools/hogli-commands tools/owners tools/query-performance-ai:将仓库根目录、common 以及多个工具目录加入模块搜索路径,保证 posthogeeproducts 等顶层包可被导入。
  • env = DEBUG=1, TEST=1:pytest 启动时自动注入 DEBUG=1TEST=1 两个环境变量。
  • DJANGO_SETTINGS_MODULE = posthog.settings:指定 Django 设置模块,pytest-django 据此完成 django.setup()
  • 默认忽略项addopts 中通过 --ignore= 排除了 posthog/user_scriptsservices/llm-gatewayservices/stripe-mockcommon/ingestion/acceptance_teststools/hoglitools/hogli-commandstools/ownerstools/traffic-simtools/query-performance-aiproducts/desktopproducts/stamphog/packages 等目录,这些目录要么是独立维护的测试套件,要么不适合进入主 Django 测试流程。
  • 其他值得了解的 addopts--reuse-db(复用测试数据库,加速多次运行)、--pytest-durations=0(默认关闭耗时统计插件)、-p pytest_boot_gc(在 pytest-django 执行 django.setup() 前开启引导期 GC 窗口),以及 -p no:warnings -p no:tach -p no:langsmith_plugin -p no:faker 等插件禁用项(各禁用项均有注释说明性能原因)。
  • markers 与 asyncio:定义了 eeclickhouse_onlyskip_on_multitenancyasync_migrationsrequires_secretsquarantinepersons_db_direct 等标记;asyncio_mode = auto 使 async 测试自动按 asyncio 运行。

排错指南:以 CI 配置为权威参照

如果测试环境搭建遇到问题,第一参照物是 .github/workflows/ci-backend.yml——它是 PostHog 后端测试在 CI 中的权威配置来源,从中可以查到:

  • CI 使用的精确 Python 版本3.13.13(与 pyproject.tomlrequires-python 完全一致),通过 setup-python-cached 安装。
  • 系统依赖libxml2-dev libxmlsec1-dev libxmlsec1-openssl(SAML 相关)、sqlx-cli(Rust 迁移工具)等。
  • 环境变量全集:上文表格中列出的全部 env: 项。
  • Docker 服务配置COMPOSE_FILE: docker-compose.dev.yml:docker-compose.profiles.ymlCOMPOSE_PROFILES: temporal,azure,以及 bin/ci-wait-for-docker launch --background --down db redis7 clickhouse zookeeper kafka objectstorage temporal elasticsearch objectstorage-azure 的服务启动清单。
  • 测试执行命令:各 Job 中 UV_PROJECT_ENVIRONMENT=$pythonLocation uv sync --frozen --dev 之后执行的 pytest 命令(含 --reuse-db、junit 输出、pytest-split 分片等参数)。

排查顺序建议:先对照 pyproject.toml 确认解释器版本 → 用 python3 --version 验证下载的 Python → uv sync 是否成功 → Docker 服务是否健康(docker compose ps)→ hosts 是否包含测试所需主机名 → 环境变量是否齐全 → 最后再看 pytest 报错本身。

已知限制

在 Claude Code for web 这类受限环境中搭建测试环境,需要清醒认识以下边界:

  • Docker 不可用:若环境未提供 Docker,所有依赖外部服务的测试(Kafka、ClickHouse、Redis 等)都无法运行,只能执行不触碰外部中间件的纯单元测试。
  • 网络限制:从 python-build-standalone 下载 Python、从 Docker Hub 拉取镜像、从 PyPI 安装依赖都要求能访问外网;网络受限时整个流程无法进行。
  • Temporal 相关测试:需要额外的 Temporal 服务搭建(对应 CI 中 COMPOSE_PROFILES: temporal 的 profile 与 python manage.py register_temporal_search_attributes 等步骤),默认的 dev compose 栈不足以支撑这类测试。

若在按本指南操作时卡住,建议把遇到的问题连同报错信息反馈给用户,并推动更新 .agents/skills/setup-web-tests/SKILL.md 本身,让这份指南随环境演进持续完善。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
docsdocs
暂无描述
Markdown
899
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.03 K
525
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395