Skip to main content

pywsl2

A Python wrapper for the Windows Subsystem for Linux API (wslapi.h)


Goal

pywsl2 lets you control WSL distributions and the processes running inside them from Python, without shelling out to wsl.exe and parsing its UTF-16 output. It calls the native WSL API directly, and its process interface feels like subprocess.

How?

The design follows pydia3:

  • Every wslapi.h function is wrapped by a C++ function in WslLib, which handles all handle and memory management (pipes, process handles, CoTaskMemFreed configuration strings) and turns failing HRESULTs into exceptions.
  • pywsl2 (the native extension) exposes WslLib as C-API Python classes. It never calls the WSL API directly, and it releases the GIL around every blocking call.
  • wslapi.dll is loaded lazily, so import pywsl2 works on any Windows machine. If WSL is missing, the first API call raises WslNotAvailableError.

Installation

pywsl2 is Windows-only (x64) and supports CPython 3.12, 3.13, 3.14 and 3.15. WSL must be installed (wsl --install).

pip install pywsl2

Usage

import pywsl2

print(pywsl2.list_distributions())  # [pywsl2.Distribution('Ubuntu'), ...]
ubuntu = pywsl2.default_distribution()  # or pywsl2.Distribution("Ubuntu")

# Run a command to completion, like subprocess.run (output is always captured).
result = ubuntu.run("uname -a", text=True, check=True)
print(result.stdout)

# Feed it input; large inputs and outputs are pumped concurrently, so nothing deadlocks.
print(ubuntu.run("sort", input="b\na\n", text=True).stdout)

# Start a process and talk to it.
process = ubuntu.launch(
    "read name; echo hello $name", stdin=pywsl2.PIPE, stdout=pywsl2.PIPE
)
process.write(b"world\n")
print(process.read_stdout())  # b'hello world\n'
print(process.wait())  # 0

# Or let communicate() handle the I/O, with an optional timeout.
with ubuntu.launch("cat", stdin=pywsl2.PIPE, stdout=pywsl2.PIPE) as process:
    stdout, _ = process.communicate(b"data", timeout=10)

# Attach a command (or, with no command, the default shell) to the current console.
ubuntu.launch_interactive("htop")

# Inspect and change the distribution's configuration.
config = ubuntu.configuration
print(config.version, config.default_uid, config.flags, config.default_environment)
ubuntu.configure(flags=config.flags & ~pywsl2.DistributionFlags.APPEND_NT_PATH)

See Examples/ for more.

API overview

wslapi.h pywsl2
WslIsDistributionRegistered Distribution.is_registered
WslGetDistributionConfiguration Distribution.configuration (and version, default_uid, flags, default_environment)
WslConfigureDistribution Distribution.configure(default_uid=..., flags=...)
WslLaunch Distribution.launch(...) → Process, Distribution.run(...)
WslLaunchInteractive Distribution.launch_interactive(...)
WslRegisterDistribution Distribution.register(name, tar_gz_path)
WslUnregisterDistribution Distribution.unregister()
(registry, HKCU\...\Lxss) list_distributions(), default_distribution()

Streams passed to launch() are None (inherit this process's stream, the default), PIPE or DEVNULL; the values are the same as in subprocess. Errors raise WslError (an OSError carrying .hresult), DistributionNotFoundError, WslNotAvailableError or TimeoutExpired (also a TimeoutError).

Limitations

  • Windows only allows WslRegisterDistribution from a distribution's packaged launcher app. From a regular process it fails with WslError (E_ACCESSDENIED, 0x80070005). Use wsl --import to register a root file system from a script.
  • Process.pid and terminate() refer to the Windows-side host process. Killing it ends the session, so the Linux command is terminated too.
  • A Process is not safe to use from several threads at once, except that one thread may write to stdin while another reads stdout or stderr.

Building from source

Prerequisites

  • Windows x64.
  • Visual Studio 2022 or later (or the Build Tools) with the Desktop development with C++ workload, which includes the Windows SDK that provides wslapi.h.
  • CPython 3.12–3.15 x64.

Build, install and test

python -m pip install -e . pytest
python -m pytest                         # unit tests only
$env:PYWSL2_TEST_DISTRIBUTION = "Ubuntu" # also run integration tests inside this distribution
python -m pytest

To build a wheel instead: python -m pip install build; python -m build --wheel.

Linting

python -m pip install -r requirements-dev.txt
python -m ruff check .
python -m ruff format --check .
git ls-files '*.cpp' '*.h' | ForEach-Object { clang-format --dry-run --Werror $_ }

Metadata

Release files for pywsl2 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pywsl2 0.1.0
File Size Uploaded
pywsl2-0.1.0.tar.gz 31.2 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for pywsl2 0.1.0
File Interpreter ABI Platform
pywsl2-0.1.0-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details
pywsl2-0.1.0-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details
pywsl2-0.1.0-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details

Total release size: 172.7 kB

Release files / pywsl2-0.1.0.tar.gz

Download URL pywsl2-0.1.0.tar.gz
Size 31.2 kB
Tags Source
SHA-256 checksum
How to use checksums
c533e45922a668fe4aa4bbaefe73c649005204bf898015b15016c3f80f1dd93a
BLAKE2b-256 checksum
How to use checksums
465093661cd08507ef0345e4c3ea499bf01ffceb8a61d19110008f855aca093e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / pywsl2-0.1.0-cp314-cp314-win_amd64.whl

Download URL pywsl2-0.1.0-cp314-cp314-win_amd64.whl
Size 48.0 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
58eec48fe2c74b3cbb32fa657b1906a23a9258642356d0045ffa5bb8112afeb2
BLAKE2b-256 checksum
How to use checksums
17d6b57c9a393af01c0d0519999aaa3a6898ea224d9b29020446e0e9c53a44f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / pywsl2-0.1.0-cp313-cp313-win_amd64.whl

Download URL pywsl2-0.1.0-cp313-cp313-win_amd64.whl
Size 46.7 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
c70d1688c4f9bdfbce03c3a301f2457e9ccaedf08fe6f12e6c66c1f049c4b439
BLAKE2b-256 checksum
How to use checksums
75ed16b302c68836e793b32016f67d9cfa97b5441e6c8589d0da6140a96fdb9e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / pywsl2-0.1.0-cp312-cp312-win_amd64.whl

Download URL pywsl2-0.1.0-cp312-cp312-win_amd64.whl
Size 46.7 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
3b36510d61b26dcdbacbebad24ba4a6ebfa91716bd542bc1c77373197421f4a3
BLAKE2b-256 checksum
How to use checksums
6556765817c5766b6b10eb8111bff6cd6a25b236780fac627bcc213b6093e6cd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release history Release notifications | RSS feed

This release

0.1.0 This release

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page