Skip to main content

A fake Windows registry for testing registry-related code on non-Windows platforms

Project description

fake_winreg

CI CodeQL License: MIT Open in Codespaces PyPI PyPI - Downloads Code Style: Ruff codecov Maintainability Known Vulnerabilities security: bandit

Table of Contents

Why fake_winreg?

Python's winreg module is only available on Windows. If your code reads or writes the Windows registry, you can't test it on Linux or macOS - and you can't run it in CI on Ubuntu runners.
fake_winreg solves this by providing a complete fake registry that works everywhere Python runs. Just replace import winreg with import fake_winreg as winreg and your tests work on any platform. Test your code before it hits the real registry!

You can also export real registry data from Windows via regedit.exe as a .reg file, import it into a SQLite database with fake-winreg convert if=exported.reg of=registry.db, and run your tests against real-world data.

Overview

fake_winreg provides a drop-in replacement for Python's built-in winreg module, enabling testing of Windows registry-dependent code on Linux and macOS without a Windows environment, or to test software without hitting a real registry on Windows.

Key capabilities:

  • All 20 winreg API functions (OpenKey, SetValueEx, EnumKey, etc.) with matching signatures and error behavior
  • Three storage backends: in-memory (default), SQLite (for large registries), JSON (for fixtures)
  • Import and export of Windows .reg files (Version 5.00 and REGEDIT4 formats)
  • CLI commands for querying and modifying persistent SQLite registries (fake-winreg reg)
  • Streaming format conversion between .db, .json, and .reg via CLI or Python API
  • Pre-built test registries mimicking Windows 10, Windows 11 23H2, and Wine environments
  • Positional-only parameter enforcement matching real winreg behavior
  • Clean Architecture with import-linter enforcement, pyright strict mode, high test coverage

Installation

Recommended: uv (fast, isolated)

# install uv if needed
curl -LsSf https://astral.sh/uv/install.sh | sh

# one-shot run without installing
uvx fake_winreg@latest info

# persistent install as CLI tool
uv tool install fake_winreg

# install as project dependency
uv pip install fake_winreg

Via pip

pip install fake_winreg

From source

pip install "git+https://github.com/bitranox/fake_winreg"

See INSTALL.md for all options (pipx, Poetry, PDM, system packages).

Configuration

See CONFIG.md for detailed documentation on the layered configuration system, including precedence rules, profile support, and customization best practices.

Quick Start

# Install
uv tool install fake_winreg

# Verify
fake-winreg --version

# Deploy config files
fake-winreg config-deploy --target user

# Export demo registries (Windows 10, 11, Wine) as .json, .reg, .db
fake-winreg export-demo-registries

# Query a persistent registry
fake-winreg reg --db windows11.db list-keys HKEY_LOCAL_MACHINE\SOFTWARE
fake-winreg reg --db windows11.db get HKEY_LOCAL_MACHINE\SOFTWARE\...\CurrentVersion CurrentBuild

# Convert between formats
fake-winreg convert if=windows11.db of=export.reg

# Show package info
fake-winreg info

Python API

import fake_winreg as winreg

# Load a pre-built Windows 10-like test registry
fake_registry = winreg.fake_reg_tools.get_minimal_windows_testregistry()
winreg.load_fake_registry(fake_registry)

# Use exactly like the real winreg module
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
key = winreg.OpenKey(reg, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion")
value, value_type = winreg.QueryValueEx(key, "CurrentBuild")

API Reference

All functions mirror the signatures and behavior of Python's built-in winreg module.

Registry Functions

Connection

ConnectRegistry(computer_name: str | None, key: Handle, /) -> PyHKEY

Establish a connection to a predefined registry handle. Pass None for computer_name to connect to the local (fake) registry.

Key Operations

CreateKey(key: Handle, sub_key: str | None, /) -> PyHKEY

Create or open a registry key, returning a handle.

CreateKeyEx(key: Handle, sub_key: str, reserved: int = 0, access: int = KEY_WRITE, /) -> PyHKEY

Create or open a registry key with explicit access control.

OpenKey(key: Handle, sub_key: str | None, reserved: int = 0, access: int = KEY_READ) -> PyHKEY

Open an existing registry key. Does not create the key if it does not exist.

OpenKeyEx(key: Handle, sub_key: str | None, reserved: int = 0, access: int = KEY_READ) -> PyHKEY

Open an existing registry key with explicit access. Equivalent to OpenKey.

DeleteKey(key: Handle, sub_key: str, /) -> None

Delete a registry key. The key must have no subkeys.

DeleteKeyEx(key: Handle, sub_key: str, access: int = KEY_WOW64_64KEY, reserved: int = 0, /) -> None

Delete a registry key (64-bit variant).

CloseKey(hkey: int | HKEYType, /) -> None

Close a previously opened registry key.

FlushKey(key: Handle, /) -> None

Write all attributes of a key to the registry. No-op in the fake implementation since data is already in memory.

Value Operations

SetValue(key: Handle, sub_key: str | None, type: int, value: str, /) -> None

Set the default (unnamed) value of a key. Only REG_SZ is accepted for type.

SetValueEx(key: Handle, value_name: str | None, reserved: int, type: int, value: RegData, /) -> None

Store data in a named value of an open registry key. Supports all registry value types.

QueryValue(key: Handle, sub_key: str | None, /) -> str

Retrieve the default (unnamed) value of a key as a string.

QueryValueEx(key: Handle, value_name: str | None, /) -> tuple[RegData, int]

Retrieve value data and its type code for a named value. Returns (data, type).

DeleteValue(key: Handle, value: str | None, /) -> None

Remove a named value from a registry key.

Enumeration

EnumKey(key: Handle, index: int, /) -> str

Enumerate subkeys of an open key by zero-based index. Raises OSError when index exceeds the number of subkeys.

EnumValue(key: Handle, index: int, /) -> tuple[str, RegData, int]

Enumerate values of an open key by zero-based index. Returns (name, data, type). Raises OSError when index exceeds the number of values.

QueryInfoKey(key: Handle, /) -> tuple[int, int, int]

Return information about a key: (num_subkeys, num_values, last_modified_timestamp).

Utility

ExpandEnvironmentStrings(string: str, /) -> str

Expand %VAR%-style environment variable references in a string. Works on all platforms.

DisableReflectionKey(key: Handle, /) -> None
EnableReflectionKey(key: Handle, /) -> None
QueryReflectionKey(key: Handle, /) -> bool

Registry reflection stubs. No-op in the fake implementation; QueryReflectionKey always returns True.

Backend Management

fake_winreg supports multiple storage backends. The default is an in-memory backend.

import fake_winreg as winreg

# Default: in-memory (created automatically if no backend is set)
winreg.use_backend(winreg.InMemoryBackend())

# SQLite: for large registries or persistent storage
winreg.use_backend(winreg.SqliteBackend("/path/to/registry.db"))

# JSON: load from a JSON file, work in memory
winreg.use_backend(winreg.JsonBackend("/path/to/registry.json"))

# Backward-compatible: load a FakeRegistry object directly
fake_registry = winreg.fake_reg_tools.get_minimal_windows_testregistry()
winreg.load_fake_registry(fake_registry)

Import/Export

Exchange registry data between formats. All exports produce deterministic, alphabetically sorted output — keys and values are ordered by name regardless of which backend is active.

import fake_winreg as winreg

# JSON format (always UTF-8, per RFC 8259)
winreg.export_json("/path/to/snapshot.json")
winreg.import_json("/path/to/fixture.json")

# Windows .reg format (Version 5.00, UTF-16 LE with BOM by default)
winreg.export_reg("/path/to/export.reg")
winreg.import_reg("/path/to/import.reg")

# REGEDIT4 format (legacy, ANSI encoding)
winreg.export_reg("/path/to/export.reg", version=4)

# Override encoding for human-readable .reg files
winreg.export_reg("/path/to/export.reg", encoding="utf-8")

# Convert between formats (streaming, memory-efficient for large registries)
winreg.convert_registry("source.db", "target.reg")
winreg.convert_registry("source.reg", "target.json")

Character Encoding

Format Default Encoding Notes
.json UTF-8 Per RFC 8259. Binary values are base64-encoded.
.reg export (v5) UTF-16 LE with BOM Default. Matches Windows regedit.exe. Override with encoding="utf-8".
.reg export (v4) ASCII export_reg(path, version=4). Legacy REGEDIT4 format, no Unicode.
.reg import Auto-detected UTF-16 LE if BOM (FF FE) present, otherwise UTF-8. Both v4 and v5 supported.
.db (SQLite) N/A Binary format. String values stored as SQLite TEXT (UTF-8 internally).

The Windows registry stores all strings as UTF-16 LE internally. Values encoded as hex(2): (REG_EXPAND_SZ) and hex(7): (REG_MULTI_SZ) in .reg files use UTF-16 LE byte sequences regardless of the file encoding.

Constants

All constants from the winreg module are available.

Hive keys:

Constant Description
HKEY_CLASSES_ROOT Registry entries for file associations and COM
HKEY_CURRENT_USER Settings for the current user
HKEY_LOCAL_MACHINE System-wide settings
HKEY_USERS Settings for all user profiles
HKEY_CURRENT_CONFIG Current hardware profile
HKEY_PERFORMANCE_DATA Performance counters
HKEY_DYN_DATA Dynamic data (Windows 95/98)

Value types:

Constant Description
REG_NONE No defined value type
REG_SZ Null-terminated string
REG_EXPAND_SZ String with unexpanded environment variable refs
REG_BINARY Binary data
REG_DWORD 32-bit integer (little-endian)
REG_DWORD_BIG_ENDIAN 32-bit integer (big-endian)
REG_LINK Symbolic link (Unicode)
REG_MULTI_SZ Array of null-terminated strings
REG_QWORD 64-bit integer (little-endian)
REG_RESOURCE_LIST Device driver resource list
REG_FULL_RESOURCE_DESCRIPTOR Hardware resource descriptor
REG_RESOURCE_REQUIREMENTS_LIST Hardware resource requirements

Access rights:

Constant Description
KEY_READ Read access
KEY_WRITE Write access
KEY_ALL_ACCESS Full access
KEY_EXECUTE Execute access (same as KEY_READ)
KEY_QUERY_VALUE Query subkey values
KEY_SET_VALUE Set subkey values
KEY_CREATE_SUB_KEY Create subkeys
KEY_ENUMERATE_SUB_KEYS Enumerate subkeys
KEY_NOTIFY Change notification
KEY_CREATE_LINK Create symbolic link
KEY_WOW64_64KEY Access 64-bit registry view
KEY_WOW64_32KEY Access 32-bit registry view

Data Types

# All possible types of data that registry values can hold
RegData = None | bytes | int | str | list[str]

# Handle types accepted by all API functions
Handle = int | HKEYType | PyHKEY

# Registry data structures
FakeRegistry       # Top-level registry container (holds hive roots)
FakeRegistryKey    # A single registry key with subkeys and values
FakeRegistryValue  # A named value with data and type code

PyHKEY supports the context manager protocol:

with winreg.OpenKey(reg, r"SOFTWARE\Microsoft") as key:
    value, vtype = winreg.QueryValueEx(key, "SomeName")

Test Registries

Pre-built registry fixtures for common test scenarios. See docs/registry_values.md for a detailed reference of all registry values, version detection logic, and branch codenames.

import fake_winreg as winreg

# Windows 10 (build 18363)
reg = winreg.fake_reg_tools.get_minimal_windows_testregistry()

# Windows 11 23H2 Pro (build 22631)
reg = winreg.fake_reg_tools.get_minimal_windows11_testregistry()

# Wine environment (build 7601)
reg = winreg.fake_reg_tools.get_minimal_wine_testregistry()

CLI Usage

# Query a persistent SQLite registry
fake-winreg reg --db registry.db list-keys HKEY_LOCAL_MACHINE\SOFTWARE
fake-winreg reg --db registry.db list-values HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft
fake-winreg reg --db registry.db get HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\...\CurrentVersion CurrentBuild
fake-winreg reg --db registry.db info HKEY_LOCAL_MACHINE\SOFTWARE

# Modify a persistent registry
fake-winreg reg --db registry.db create-key HKEY_LOCAL_MACHINE\SOFTWARE\MyApp
fake-winreg reg --db registry.db set HKEY_LOCAL_MACHINE\SOFTWARE\MyApp Name "hello"
fake-winreg reg --db registry.db set HKEY_LOCAL_MACHINE\SOFTWARE\MyApp Count 42 --type REG_DWORD
fake-winreg reg --db registry.db delete-value HKEY_LOCAL_MACHINE\SOFTWARE\MyApp Name
fake-winreg reg --db registry.db delete-key HKEY_LOCAL_MACHINE\SOFTWARE\MyApp

# Convert between registry formats
fake-winreg convert if=registry.db of=export.reg
fake-winreg convert if=export.reg of=registry.json

# Export demo registries (Windows 10 + 11 + Wine) as .json, .reg, .db
fake-winreg export-demo-registries

# Show package information
fake-winreg info

The --db option can be replaced by configuring registry.db_path via TOML config, .env file (REGISTRY__DB_PATH=/path/to/db), or environment variable (FAKE_WINREG___REGISTRY__DB_PATH=/path/to/db).

Development

Run the full test suite (lint, type-check, tests with coverage):

make test

See DEVELOPMENT.md for the complete development setup guide.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fake_winreg-1.8.2.tar.gz (143.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fake_winreg-1.8.2-py3-none-any.whl (91.2 kB view details)

Uploaded Python 3

File details

Details for the file fake_winreg-1.8.2.tar.gz.

File metadata

  • Download URL: fake_winreg-1.8.2.tar.gz
  • Upload date:
  • Size: 143.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fake_winreg-1.8.2.tar.gz
Algorithm Hash digest
SHA256 7cfd2231868337fccccd3e9fc72cb69c3b65cbf6f06f00f5d9d6d541147dd3de
MD5 133cb546ef98419ceef0699a8d84b5ee
BLAKE2b-256 d91d0099ec5ec3f85ff6bb3e0020867e05d53cf2aa32c9de6ce8aeadd5a99e8d

See more details on using hashes here.

File details

Details for the file fake_winreg-1.8.2-py3-none-any.whl.

File metadata

  • Download URL: fake_winreg-1.8.2-py3-none-any.whl
  • Upload date:
  • Size: 91.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fake_winreg-1.8.2-py3-none-any.whl
Algorithm Hash digest
SHA256 ab86e9c9d145d566800193c356a2d86bb72ca10ddd179a9adcc971cad8e7f568
MD5 e7d866a8211cd307ba45bad328646378
BLAKE2b-256 6add7e1066e933b1491dcbcffe0110971974cf1fc27daeb505eda6c46880cfbb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page