third_party/py_deps/README.md
This directory contains the Python packages needed by the repository setup and
tooling paths that previously came from tools/vpython_tools/requirements.txt.
In the template-assembler repository this lives at lynx/third_party/py_deps.
When the lynx/ directory is synced as the standalone Lynx repository, it lives
at third_party/py_deps.
The packages are loaded by adding this directory to PYTHONPATH from Lynx's
tools/env.sh / tools/envsetup.* scripts. Downstream repositories should
delegate to the Lynx env script instead of duplicating this path. Repository
setup no longer installs these packages from a network package index.
Run the update from the repository root. In template-assembler, set
dest_dir=lynx/third_party/py_deps; in the standalone Lynx repository, set
dest_dir=third_party/py_deps.
pkg="package-name==version"
dest_dir="lynx/third_party/py_deps"
workdir="$(mktemp -d)"
python3 -m pip download \
--dest "$workdir/wheels" \
--only-binary=:all: \
--platform any \
--implementation py \
--python-version 3 \
--abi none \
"$pkg"
# This includes transitive dependencies. Every downloaded wheel must be pure
# Python. The command should print nothing.
find "$workdir/wheels" -type f ! -name '*-none-any.whl' -print
python3 -m pip install \
--no-index \
--find-links "$workdir/wheels" \
--only-binary=:all: \
--no-compile \
--target "$workdir/site" \
"$pkg"
# If updating existing packages, remove their old package directories and
# matching *.dist-info directories from "$dest_dir" before copying.
rsync -a "$workdir/site/" "$dest_dir/"
After copying, verify that no native or generated artifacts were vendored. These commands should print nothing:
find "$dest_dir" -type f \
\( -name '*.so' -o -name '*.pyd' -o -name '*.dll' -o -name '*.dylib' \
-o -name '*.pyc' -o -name '*.pyo' \
-o -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' \) \
-print
find "$dest_dir" -type d -name '__pycache__' -print
Then run an import smoke test and update the full vendored package list below, including any transitive dependencies:
tools/env.sh python3 -c "import package_name"
python3 -m pip list --path "$workdir/site" --format=freeze
Vendored packages:
beautifulsoup4==4.14.2bs4==0.0.2certifi==2026.1.4charset-normalizer==3.4.4doxmlparser==1.14.0idna==3.11jinja2==3.1.6json5==0.9.28markupsafe==3.0.3pyyaml==6.0.3qrcode==8.2requests==2.32.5six==1.17.0soupsieve==2.8typing-extensions==4.15.0urllib3==2.6.3Native extension artifacts (*.so, *.pyd, *.dll, *.dylib) are intentionally
not vendored here. doxmlparser falls back to Python's standard
xml.etree.ElementTree parser when lxml is unavailable; the Doxygen API
parser adds a small compatibility wrapper for lxml-only element attributes.