CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-types-pyyaml

Type stubs for PyYAML, a full-featured YAML framework for Python

Overview
Eval results
Files

registration.mddocs/

Registration Functions

Functions for registering custom constructors, representers, and resolvers to extend YAML processing capabilities. These functions allow you to customize how PyYAML handles specific data types and tags.

Capabilities

Constructor Registration

Functions for registering custom constructors that convert YAML nodes to Python objects.

def add_constructor(tag: str, constructor: Callable, Loader=None) -> None:
    """
    Register a constructor for a specific YAML tag.
    
    Parameters:
    - tag: YAML tag to handle (e.g., '!custom', 'tag:yaml.org,2002:python/tuple')
    - constructor: Function that takes (loader, node) and returns Python object
    - Loader: Loader class to register with (defaults to global registration)
    
    The constructor function signature:
    def constructor(loader, node) -> Any
    """

def add_multi_constructor(tag_prefix: str, multi_constructor: Callable, Loader=None) -> None:
    """
    Register a multi-constructor for YAML tags with a common prefix.
    
    Parameters:
    - tag_prefix: YAML tag prefix to handle (e.g., '!python/', 'tag:example.com,2002:')
    - multi_constructor: Function that takes (loader, tag_suffix, node) and returns Python object
    - Loader: Loader class to register with (defaults to global registration)
    
    The multi-constructor function signature:
    def multi_constructor(loader, tag_suffix, node) -> Any
    """

Representer Registration

Functions for registering custom representers that convert Python objects to YAML nodes.

def add_representer(data_type: type, representer: Callable, Dumper=None) -> None:
    """
    Register a representer for a specific Python type.
    
    Parameters:
    - data_type: Python type to handle (e.g., MyClass, datetime.date)
    - representer: Function that takes (dumper, data) and returns YAML node
    - Dumper: Dumper class to register with (defaults to global registration)
    
    The representer function signature:
    def representer(dumper, data) -> Node
    """

def add_multi_representer(data_type: type, multi_representer: Callable, Dumper=None) -> None:
    """
    Register a multi-representer for a type and its subclasses.
    
    Parameters:
    - data_type: Base Python type to handle (will also handle subclasses)
    - multi_representer: Function that takes (dumper, data) and returns YAML node
    - Dumper: Dumper class to register with (defaults to global registration)
    
    The multi-representer function signature:
    def multi_representer(dumper, data) -> Node
    """

Resolver Registration

Functions for registering custom resolvers that determine YAML tags for values.

def add_implicit_resolver(tag: str, regexp: Pattern[str], first=None, Loader=None, Dumper=None) -> None:
    """
    Register an implicit resolver that assigns tags based on value patterns.
    
    Parameters:
    - tag: YAML tag to assign when pattern matches
    - regexp: Compiled regular expression pattern to match against scalar values
    - first: Set of possible first characters (optimization hint)
    - Loader: Loader class to register with (defaults to global registration)
    - Dumper: Dumper class to register with (defaults to global registration)
    """

def add_path_resolver(tag: str, path: Iterable[Any], kind=None, Loader=None, Dumper=None) -> None:
    """
    Register a path resolver that assigns tags based on document path.
    
    Parameters:
    - tag: YAML tag to assign when path matches
    - path: Sequence describing the path in the document structure
    - kind: Node kind to match (ScalarNode, SequenceNode, MappingNode)
    - Loader: Loader class to register with (defaults to global registration)
    - Dumper: Dumper class to register with (defaults to global registration)
    """

Usage Examples

Custom Constructor Registration

import yaml
import re
from datetime import datetime

# Constructor for custom date format
def date_constructor(loader, node):
    """Construct datetime from custom date format."""
    value = loader.construct_scalar(node)
    return datetime.strptime(value, '%Y-%m-%d %H:%M:%S')

# Register constructor for custom tag
yaml.add_constructor('!datetime', date_constructor, Loader=yaml.SafeLoader)

# Test custom constructor
yaml_input = """
created: !datetime 2024-01-15 14:30:00
modified: !datetime 2024-01-16 09:15:30
"""

data = yaml.load(yaml_input, Loader=yaml.SafeLoader)
print(f"Created: {data['created']} (type: {type(data['created'])})")
print(f"Modified: {data['modified']} (type: {type(data['modified'])})")

Multi-Constructor Registration

import yaml
import importlib

def python_object_constructor(loader, tag_suffix, node):
    """Construct Python objects from module.class notation."""
    if tag_suffix == 'object':
        # Handle !!python/object:module.Class
        class_name = loader.construct_scalar(node)
        module_name, class_name = class_name.rsplit('.', 1)
        module = importlib.import_module(module_name)
        cls = getattr(module, class_name)
        return cls()
    elif tag_suffix == 'apply':
        # Handle !!python/apply:function [args]
        function_name = node.value[0].value
        args = loader.construct_sequence(node.value[1])
        module_name, func_name = function_name.rsplit('.', 1)
        module = importlib.import_module(module_name)
        func = getattr(module, func_name)
        return func(*args)
    else:
        raise yaml.constructor.ConstructorError(
            None, None, f"Unknown python tag suffix: {tag_suffix}", node.start_mark
        )

# Register multi-constructor for python tags
yaml.add_multi_constructor('tag:yaml.org,2002:python/', 
                          python_object_constructor, 
                          Loader=yaml.UnsafeLoader)

# Test (UNSAFE - only for demonstration)
yaml_input = """
date_func: !!python/object:datetime.date
result: !!python/apply:datetime.date [2024, 1, 15]
"""

# This would work with UnsafeLoader (not recommended for untrusted input)
# data = yaml.load(yaml_input, Loader=yaml.UnsafeLoader)

Custom Representer Registration

import yaml
from decimal import Decimal

def decimal_representer(dumper, data):
    """Represent Decimal as a scalar with custom tag."""
    return dumper.represent_scalar('!decimal', str(data))

def decimal_constructor(loader, node):
    """Construct Decimal from scalar value."""
    value = loader.construct_scalar(node)
    return Decimal(value)

# Register representer and constructor
yaml.add_representer(Decimal, decimal_representer, Dumper=yaml.SafeDumper)
yaml.add_constructor('!decimal', decimal_constructor, Loader=yaml.SafeLoader)

# Test custom Decimal handling
data = {
    'price': Decimal('19.99'),
    'tax_rate': Decimal('0.0825'),
    'total': Decimal('21.64')
}

yaml_output = yaml.dump(data, Dumper=yaml.SafeDumper)
print("YAML output:")
print(yaml_output)
# Output:
# price: !decimal '19.99'
# tax_rate: !decimal '0.0825'
# total: !decimal '21.64'

loaded_data = yaml.load(yaml_output, Loader=yaml.SafeLoader)
print(f"Loaded price: {loaded_data['price']} (type: {type(loaded_data['price'])})")

Multi-Representer Registration

import yaml
from pathlib import Path

def path_representer(dumper, data):
    """Represent Path objects as strings with custom tag."""
    return dumper.represent_scalar('!path', str(data))

def path_constructor(loader, node):
    """Construct Path from string value."""
    value = loader.construct_scalar(node)
    return Path(value)

# Register for Path and all its subclasses
yaml.add_multi_representer(Path, path_representer, Dumper=yaml.SafeDumper)
yaml.add_constructor('!path', path_constructor, Loader=yaml.SafeLoader)

# Test with different Path types
from pathlib import WindowsPath, PosixPath

data = {
    'config_file': Path('/etc/myapp/config.yaml'),
    'data_dir': Path('/var/lib/myapp'),
    'log_file': Path('/var/log/myapp.log')
}

yaml_output = yaml.dump(data, Dumper=yaml.SafeDumper)
print("YAML output:")
print(yaml_output)

loaded_data = yaml.load(yaml_output, Loader=yaml.SafeLoader)
print(f"Config file: {loaded_data['config_file']} (type: {type(loaded_data['config_file'])})")

Implicit Resolver Registration

import yaml
import re
from ipaddress import IPv4Address, IPv6Address

# IPv4 address pattern
ipv4_pattern = re.compile(r'^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$')

def ipv4_constructor(loader, node):
    value = loader.construct_scalar(node) 
    return IPv4Address(value)

def ipv4_representer(dumper, data):
    return dumper.represent_scalar('!ipv4', str(data))

# Register IPv4 handling
yaml.add_constructor('!ipv4', ipv4_constructor, Loader=yaml.SafeLoader)
yaml.add_representer(IPv4Address, ipv4_representer, Dumper=yaml.SafeDumper)

# Register implicit resolver - automatically detect IPv4 addresses
yaml.add_implicit_resolver('!ipv4', ipv4_pattern, ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
                          Loader=yaml.SafeLoader, Dumper=yaml.SafeDumper)

# Test automatic IPv4 detection
yaml_input = """
server: 192.168.1.1
database: 10.0.0.5
client: not.an.ip.address
"""

data = yaml.load(yaml_input, Loader=yaml.SafeLoader)
print(f"Server: {data['server']} (type: {type(data['server'])})")
print(f"Database: {data['database']} (type: {type(data['database'])})")
print(f"Client: {data['client']} (type: {type(data['client'])})")

# Dump back to YAML
yaml_output = yaml.dump(data, Dumper=yaml.SafeDumper)
print("\nYAML output:")
print(yaml_output)

Path Resolver Registration

import yaml

def special_string_constructor(loader, node):
    """Constructor for special strings in specific locations."""
    value = loader.construct_scalar(node)
    return f"SPECIAL: {value}"

# Register constructor
yaml.add_constructor('!special', special_string_constructor, Loader=yaml.SafeLoader)

# Register path resolver - apply !special tag to strings at specific paths
yaml.add_path_resolver('!special', ['config', 'database', 'password'], str,
                      Loader=yaml.SafeLoader)
yaml.add_path_resolver('!special', ['secrets', None], str,  # Any key under 'secrets'
                      Loader=yaml.SafeLoader)

# Test path-based tag resolution
yaml_input = """
config:
  database:
    host: localhost
    password: secret123  # Will get !special tag
    port: 5432
  app:
    name: MyApp
    debug: true
secrets:
  api_key: abc123      # Will get !special tag
  token: xyz789        # Will get !special tag
normal_password: plain  # Won't get !special tag
"""

data = yaml.load(yaml_input, Loader=yaml.SafeLoader)
print("Loaded data:")
print(f"Database password: {data['config']['database']['password']}")
print(f"API key: {data['secrets']['api_key']}")
print(f"Token: {data['secrets']['token']}")
print(f"Normal password: {data['normal_password']}")

Complete Custom Type System

import yaml
from typing import NamedTuple
from enum import Enum

class Priority(Enum):
    LOW = 1
    MEDIUM = 2
    HIGH = 3
    CRITICAL = 4

class Task(NamedTuple):
    title: str
    priority: Priority
    completed: bool = False

# Priority enum handling
def priority_representer(dumper, data):
    return dumper.represent_scalar('!priority', data.name.lower())

def priority_constructor(loader, node):
    value = loader.construct_scalar(node)
    return Priority[value.upper()]

# Task handling  
def task_representer(dumper, data):
    return dumper.represent_mapping('!task', {
        'title': data.title,
        'priority': data.priority,
        'completed': data.completed
    })

def task_constructor(loader, node):
    data = loader.construct_mapping(node)
    return Task(**data)

# Register all custom types
yaml.add_representer(Priority, priority_representer, Dumper=yaml.SafeDumper)
yaml.add_constructor('!priority', priority_constructor, Loader=yaml.SafeLoader)
yaml.add_representer(Task, task_representer, Dumper=yaml.SafeDumper)
yaml.add_constructor('!task', task_constructor, Loader=yaml.SafeLoader)

# Test complete type system
tasks = [
    Task("Fix critical bug", Priority.CRITICAL, False),
    Task("Write documentation", Priority.MEDIUM, True),
    Task("Code review", Priority.HIGH, False)
]

yaml_output = yaml.dump(tasks, Dumper=yaml.SafeDumper)
print("YAML output:")
print(yaml_output)

loaded_tasks = yaml.load(yaml_output, Loader=yaml.SafeLoader)
print("Loaded tasks:")
for task in loaded_tasks:
    print(f"  {task.title}: {task.priority.name} ({'✓' if task.completed else '✗'})")

Install with Tessl CLI

npx tessl i tessl/pypi-types-pyyaml

docs

advanced-components.md

c-extensions.md

custom-objects.md

dumping.md

errors.md

index.md

loaders-dumpers.md

loading.md

low-level.md

registration.md

tile.json