Claude Code for winreg: Python Windows Registry Access — Claude Skills 360 Blog
Blog / AI / Claude Code for winreg: Python Windows Registry Access
AI

Claude Code for winreg: Python Windows Registry Access

Published: January 13, 2029
Read time: 5 min read
By: Claude Skills 360

Python’s winreg module (Windows only, also _winreg in Python 2) provides access to the Windows Registry. import winreg. Open: winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\MyApp") → key handle (context manager). Read: winreg.QueryValueEx(key, "Setting")(data, type_int). Write: winreg.SetValueEx(key, "Setting", 0, winreg.REG_SZ, "value"). Create: winreg.CreateKey(winreg.HKEY_CURRENT_USER, r"Software\MyApp"). Delete value: winreg.DeleteValue(key, "Setting"). Delete key (no subkeys): winreg.DeleteKey(key, "SubkeyName"). Enumerate subkeys: winreg.EnumKey(key, i) — iterate i = 0, 1, … until OSError. Enumerate values: winreg.EnumValue(key, i)(name, data, type). Key info: winreg.QueryInfoKey(key)(num_subkeys, num_values, last_write_time). Root hives: HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, HKEY_CLASSES_ROOT, HKEY_USERS, HKEY_CURRENT_CONFIG. Type constants: REG_SZ (string), REG_DWORD (32-bit int), REG_BINARY, REG_EXPAND_SZ (string with env vars), REG_MULTI_SZ (list of strings), REG_QWORD (64-bit int). Claude Code reads installed software paths, environment variables, startup programs, application settings, and Windows system configuration.

CLAUDE.md for winreg

## winreg Stack
- Stdlib: import winreg   (Windows only)
- Root:   winreg.HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE
- Open:   with winreg.OpenKey(root, path) as key: ...
- Read:   data, typ = winreg.QueryValueEx(key, "Name")
- Write:  winreg.SetValueEx(key, "Name", 0, winreg.REG_SZ, "val")
- Create: with winreg.CreateKey(root, path) as key: ...
- Delete: winreg.DeleteValue(key, "Name")
-         winreg.DeleteKey(key, "SubkeyName")   # no children
- Enum:   winreg.EnumKey(key, i) / EnumValue(key, i)
- Info:   winreg.QueryInfoKey(key)  → (n_subkeys, n_values, mtime)

winreg Registry Pipeline

# app/winregutil.py — read, write, enumerate, app settings, startup, installer check
from __future__ import annotations

import os
import time
from contextlib import contextmanager
from dataclasses import dataclass, field
from typing import Any, Iterator

# Only import winreg on Windows
_WINREG_AVAILABLE = False
if os.name == "nt":
    try:
        import winreg as _wr
        _WINREG_AVAILABLE = True
    except ImportError:
        pass


# ─────────────────────────────────────────────────────────────────────────────
# 1. Low-level open / read / write helpers
# ─────────────────────────────────────────────────────────────────────────────

def _root(hive: str = "HKCU"):
    """Map short hive name to winreg constant."""
    if not _WINREG_AVAILABLE:
        return None
    mapping = {
        "HKCU": _wr.HKEY_CURRENT_USER,
        "HKLM": _wr.HKEY_LOCAL_MACHINE,
        "HKCR": _wr.HKEY_CLASSES_ROOT,
        "HKU":  _wr.HKEY_USERS,
        "HKCC": _wr.HKEY_CURRENT_CONFIG,
    }
    return mapping.get(hive.upper(), _wr.HKEY_CURRENT_USER)


def read_value(path: str, name: str, hive: str = "HKCU") -> Any:
    """
    Read a named value from the registry.  Returns None if not found.

    Example:
        val = read_value(r"Software\\MyApp", "Version")
        val = read_value(r"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
                         "ProductName", hive="HKLM")
    """
    if not _WINREG_AVAILABLE:
        return None
    try:
        with _wr.OpenKey(_root(hive), path) as key:
            data, _ = _wr.QueryValueEx(key, name)
            return data
    except OSError:
        return None


def write_value(path: str, name: str, data: Any, reg_type: int | None = None,
                hive: str = "HKCU") -> bool:
    """
    Write a named value to the registry, creating the key if needed.
    reg_type defaults to REG_SZ for str, REG_DWORD for int, REG_BINARY for bytes.

    Example:
        write_value(r"Software\\MyApp", "Version", "1.0.0")
        write_value(r"Software\\MyApp", "MaxItems", 100)
        write_value(r"Software\\MyApp", "Flag", b"\\x01\\x00")
    """
    if not _WINREG_AVAILABLE:
        return False
    if reg_type is None:
        if isinstance(data, str):
            reg_type = _wr.REG_SZ
        elif isinstance(data, int):
            reg_type = _wr.REG_DWORD
        elif isinstance(data, bytes):
            reg_type = _wr.REG_BINARY
        elif isinstance(data, list):
            reg_type = _wr.REG_MULTI_SZ
        else:
            reg_type = _wr.REG_SZ
            data = str(data)
    try:
        with _wr.CreateKey(_root(hive), path) as key:
            _wr.SetValueEx(key, name, 0, reg_type, data)
        return True
    except OSError:
        return False


def delete_value(path: str, name: str, hive: str = "HKCU") -> bool:
    """
    Delete a named value. Returns True on success, False if not found.

    Example:
        delete_value(r"Software\\MyApp", "OldSetting")
    """
    if not _WINREG_AVAILABLE:
        return False
    try:
        with _wr.OpenKey(_root(hive), path,
                         access=_wr.KEY_SET_VALUE) as key:
            _wr.DeleteValue(key, name)
        return True
    except OSError:
        return False


def key_exists(path: str, hive: str = "HKCU") -> bool:
    """
    Return True if the registry key exists.

    Example:
        if key_exists(r"Software\\MyApp"):
            print("key exists")
    """
    if not _WINREG_AVAILABLE:
        return False
    try:
        with _wr.OpenKey(_root(hive), path):
            return True
    except OSError:
        return False


# ─────────────────────────────────────────────────────────────────────────────
# 2. Enumeration helpers
# ─────────────────────────────────────────────────────────────────────────────

def list_subkeys(path: str, hive: str = "HKCU") -> list[str]:
    """
    Return all subkey names under path.

    Example:
        subkeys = list_subkeys(r"Software\\MyApp")
    """
    if not _WINREG_AVAILABLE:
        return []
    results: list[str] = []
    try:
        with _wr.OpenKey(_root(hive), path) as key:
            i = 0
            while True:
                try:
                    results.append(_wr.EnumKey(key, i))
                    i += 1
                except OSError:
                    break
    except OSError:
        pass
    return results


@dataclass
class RegValue:
    name:  str
    data:  Any
    type:  int
    type_name: str = ""

    def __post_init__(self) -> None:
        if not self.type_name:
            self.type_name = _TYPE_NAMES.get(self.type, f"REG_{self.type}")


_TYPE_NAMES: dict[int, str] = {}
if _WINREG_AVAILABLE:
    _TYPE_NAMES = {
        _wr.REG_SZ:        "REG_SZ",
        _wr.REG_DWORD:     "REG_DWORD",
        _wr.REG_BINARY:    "REG_BINARY",
        _wr.REG_EXPAND_SZ: "REG_EXPAND_SZ",
        _wr.REG_MULTI_SZ:  "REG_MULTI_SZ",
        _wr.REG_QWORD:     "REG_QWORD",
        _wr.REG_NONE:      "REG_NONE",
    }


def list_values(path: str, hive: str = "HKCU") -> list[RegValue]:
    """
    Return all named values under path as RegValue objects.

    Example:
        for v in list_values(r"Software\\MyApp"):
            print(v.name, v.type_name, repr(v.data))
    """
    if not _WINREG_AVAILABLE:
        return []
    results: list[RegValue] = []
    try:
        with _wr.OpenKey(_root(hive), path) as key:
            i = 0
            while True:
                try:
                    name, data, typ = _wr.EnumValue(key, i)
                    results.append(RegValue(name=name, data=data, type=typ))
                    i += 1
                except OSError:
                    break
    except OSError:
        pass
    return results


# ─────────────────────────────────────────────────────────────────────────────
# 3. Application settings store
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class AppSettings:
    """
    Persist application settings in the Windows Registry under
    HKCU\\Software\\<company>\\<app>.

    Example:
        cfg = AppSettings("Acme", "MyTool")
        cfg.set("theme", "dark")
        cfg.set("window_width", 1024)
        print(cfg.get("theme"))          # "dark"
        print(cfg.get("missing", "N/A")) # "N/A"
        print(cfg.all())
    """
    company: str
    app: str
    hive: str = "HKCU"

    @property
    def _path(self) -> str:
        return rf"Software\{self.company}\{self.app}"

    def get(self, name: str, default: Any = None) -> Any:
        val = read_value(self._path, name, self.hive)
        return val if val is not None else default

    def set(self, name: str, data: Any, reg_type: int | None = None) -> bool:
        return write_value(self._path, name, data, reg_type, self.hive)

    def delete(self, name: str) -> bool:
        return delete_value(self._path, name, self.hive)

    def all(self) -> dict[str, Any]:
        return {v.name: v.data for v in list_values(self._path, self.hive)}

    def exists(self) -> bool:
        return key_exists(self._path, self.hive)


# ─────────────────────────────────────────────────────────────────────────────
# 4. Installed software inventory
# ─────────────────────────────────────────────────────────────────────────────

_UNINSTALL_PATH = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
_UNINSTALL_PATH_32 = r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"


@dataclass
class InstalledApp:
    name:        str
    version:     str = ""
    publisher:   str = ""
    install_dir: str = ""
    uninstall:   str = ""


def list_installed(include_32bit: bool = True) -> list[InstalledApp]:
    """
    Return a list of installed applications by reading the registry
    Uninstall keys for both 64-bit and (optionally) 32-bit apps.

    Example:
        apps = list_installed()
        for app in apps:
            print(app.name, app.version)
    """
    if not _WINREG_AVAILABLE:
        return []

    results: list[InstalledApp] = []
    paths = [(_UNINSTALL_PATH, "HKLM")]
    if include_32bit:
        paths.append((_UNINSTALL_PATH_32, "HKLM"))

    seen: set[str] = set()

    for base_path, hive in paths:
        for subkey_name in list_subkeys(base_path, hive):
            full_path = rf"{base_path}\{subkey_name}"
            vals = {v.name: v.data for v in list_values(full_path, hive)}
            name = vals.get("DisplayName", "")
            if not name or name in seen:
                continue
            seen.add(name)
            results.append(InstalledApp(
                name=name,
                version=vals.get("DisplayVersion", ""),
                publisher=vals.get("Publisher", ""),
                install_dir=vals.get("InstallLocation", ""),
                uninstall=vals.get("UninstallString", ""),
            ))

    results.sort(key=lambda a: a.name.lower())
    return results


# ─────────────────────────────────────────────────────────────────────────────
# 5. Startup entry manager
# ─────────────────────────────────────────────────────────────────────────────

_RUN_PATH = r"Software\Microsoft\Windows\CurrentVersion\Run"


def list_startup_entries() -> dict[str, str]:
    """
    Return {name: command} for all HKCU Run entries (current user startup).

    Example:
        for name, cmd in list_startup_entries().items():
            print(name, "→", cmd)
    """
    return {v.name: v.data for v in list_values(_RUN_PATH, "HKCU")}


def add_startup_entry(name: str, command: str) -> bool:
    """
    Add or update a startup entry in HKCU Run.

    Example:
        add_startup_entry("MyApp", r'C:\\Program Files\\MyApp\\myapp.exe --silent')
    """
    return write_value(_RUN_PATH, name, command, hive="HKCU")


def remove_startup_entry(name: str) -> bool:
    """Remove a startup entry. Returns True on success."""
    return delete_value(_RUN_PATH, name, hive="HKCU")


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== winreg demo ===")
    print(f"  Windows available: {_WINREG_AVAILABLE}")

    if not _WINREG_AVAILABLE:
        print("  (non-Windows: showing stub results only)")

    # ── AppSettings ───────────────────────────────────────────────────────────
    print("\n--- AppSettings ---")
    cfg = AppSettings("ClaudeSkills360Demo", "TestApp")
    if _WINREG_AVAILABLE:
        cfg.set("theme", "dark")
        cfg.set("max_items", 42)
        cfg.set("tags", ["python", "windows", "registry"])
        print(f"  theme     = {cfg.get('theme')!r}")
        print(f"  max_items = {cfg.get('max_items')!r}")
        print(f"  tags      = {cfg.get('tags')!r}")
        print(f"  missing   = {cfg.get('missing', 'N/A')!r}")
        print(f"  all keys  = {list(cfg.all().keys())}")
        # clean up demo key
        cfg.delete("theme")
        cfg.delete("max_items")
        cfg.delete("tags")
    else:
        print("  (skipped — Windows only)")

    # ── read Windows ProductName ───────────────────────────────────────────────
    print("\n--- read HKLM ProductName ---")
    product = read_value(
        r"SOFTWARE\Microsoft\Windows NT\CurrentVersion",
        "ProductName",
        hive="HKLM",
    )
    print(f"  ProductName = {product!r}")

    # ── list_installed (first 5) ───────────────────────────────────────────────
    print("\n--- list_installed (first 5) ---")
    apps = list_installed()
    for app in apps[:5]:
        print(f"  {app.name[:40]:40s}  {app.version}")
    print(f"  ... ({len(apps)} total)")

    # ── startup entries ────────────────────────────────────────────────────────
    print("\n--- startup entries (HKCU Run) ---")
    entries = list_startup_entries()
    if entries:
        for name, cmd in list(entries.items())[:3]:
            print(f"  {name[:30]:30s}  {cmd[:50]}")
    else:
        print("  (no startup entries found)")

    print("\n=== done ===")

For the regedit / reg.exe subprocess alternative — subprocess.run(["reg", "query", r"HKCU\Software\MyApp", "/v", "Setting"], capture_output=True) lets you call the Windows reg.exe command-line tool — use reg.exe via subprocess for one-off scripts or when you need to avoid the winreg import; use winreg directly when you need structured data types (REG_DWORD, REG_MULTI_SZ), enumeration, or performance in loops. For the winreg + ctypes advanced alternative — ctypes.windll.advapi32.RegNotifyChangeKeyValue(...) provides asynchronous registry change notification events that winreg does not expose — use ctypes + advapi32 directly when you need to watch a key for changes in real time; use winreg for all standard read/write/enumerate operations. The Claude Skills 360 bundle includes winreg skill sets covering read_value()/write_value()/delete_value()/key_exists() primitives, list_subkeys()/list_values()/RegValue dataclass enumerators, AppSettings persistent settings store, list_installed()/InstalledApp software inventory, and list_startup_entries()/add_startup_entry()/remove_startup_entry() Run-key manager. Start with the free tier to try Windows Registry patterns and winreg pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free