2025, Nov 01 23:00

How to build Streamlink with uv from source and avoid GPL dependencies using STREAMLINK_USE_PYCOUNTRY

Learn to build Streamlink from source with uv and avoid GPL dependencies by passing STREAMLINK_USE_PYCOUNTRY via pyproject.toml extra-build-variables.

Packaging Streamlink in a corporate environment often comes with strict compliance requirements. Two constraints tend to surface right away: the package must be built from source and it must avoid GPL-licensed dependencies. With pip this is straightforward by combining a source build with the STREAMLINK_USE_PYCOUNTRY=1 environment variable. The friction starts when migrating the workflow to uv, where the package build runs in an isolated environment and silently ignores shell-provided variables during add or pip operations.

Reproducing the issue

In a pip-based setup, the following command installs Streamlink from source and switches the dependency choice away from GPL components:

STREAMLINK_USE_PYCOUNTRY=1 pip install streamlink==1.3.1 --no-binary streamlink

Attempting to perform the equivalent with uv by exporting the variable inline does not work. The commands execute, but the build resolves to iso-639 and iso3166 instead of pycountry, which cannot be shipped under the given policy.

STREAMLINK_USE_PYCOUNTRY=1 uv add --group streamlink streamlink==1.3.1 --no-binary-package streamlink
STREAMLINK_USE_PYCOUNTRY=1 uv pip install streamlink==1.3.1 --no-binary streamlink

The flag for source builds behaves correctly, but the environment variable is ignored during package addition and installation via uv.

What is actually happening

The Streamlink build script reads STREAMLINK_USE_PYCOUNTRY during the build step, so the variable must be visible inside the build environment. While uv supports environment management for execution with uv run and an env file, that facility is explicitly scoped to running commands. As documented, uv pip does not read environment variables intended for the traditional pip configuration surface. More importantly here, the goal is to pass a variable into the package’s build process rather than to pip itself. uv separates these concerns and builds packages in an isolated environment, which explains why an inline export in your shell does not propagate into that build context.

The fix with uv

uv provides a dedicated mechanism to inject build-time environment variables. Defining extra-build-variables in pyproject.toml ensures the variable is available inside the isolated build environment when Streamlink is compiled from source.

This will ensure that the environment variable is injected into the isolated build environment used by uv for building Streamlink.

[tool.uv]
extra-build-variables = { streamlink = { STREAMLINK_USE_PYCOUNTRY = "1" } }

With this configuration in place, keep using the source-only build switch as before. The no-binary control already works correctly with uv, so you can proceed with your add or pip command and the build will see STREAMLINK_USE_PYCOUNTRY inside the isolated environment.

Why this matters

Enterprise packaging workflows depend on predictable and compliant builds. When a build script expects a toggle like STREAMLINK_USE_PYCOUNTRY to decide between dependency graphs, failing to pass that variable at build time can silently introduce disallowed licenses. Relying on uv’s build-time injection keeps the process reproducible, auditable, and aligned with policy without resorting to ad hoc environment manipulation.

Summary and practical advice

If Streamlink must be built from source and steered away from GPL-licensed dependencies, configure uv to inject STREAMLINK_USE_PYCOUNTRY during the build. Put the variable under [tool.uv].extra-build-variables in pyproject.toml and continue using the source-only install flag. Remember that UV_ENV_FILE and similar mechanisms relate to uv run, not installing packages, and that uv pip intentionally does not consume general pip environment configuration. Keeping the variable in extra-build-variables makes the behavior explicit and stable across environments.

The article is based on a question from StackOverflow by Zul and an answer by Hericks.