Skip to content

Validator Registry

The registry holds the parsers and checks a schema resolves by name.

Registry

Registry is the public entry point. It groups four ValidatorRegistry instances, one per validator kind.

nyctea.validators.registry.Registry

Bases: BaseModel

Registry containing all validator types.

Attributes:

Name Type Description
column_parsers ValidatorRegistry[ColumnParser]

Registry for column parser validators.

column_checks ValidatorRegistry[ColumnCheck]

Registry for column check validators.

frame_parsers ValidatorRegistry[FrameParser]

Registry for frame parser validators.

frame_checks ValidatorRegistry[FrameCheck]

Registry for frame check validators.

Source code in src/nyctea/validators/registry.py
class Registry(BaseModel):
    """Registry containing all validator types.

    Attributes:
        column_parsers: Registry for column parser validators.
        column_checks: Registry for column check validators.
        frame_parsers: Registry for frame parser validators.
        frame_checks: Registry for frame check validators.
    """

    model_config = ConfigDict(arbitrary_types_allowed=True)

    column_parsers: ValidatorRegistry[ColumnParser] = Field(default_factory=lambda: ValidatorRegistry(ColumnParser))
    column_checks: ValidatorRegistry[ColumnCheck] = Field(default_factory=lambda: ValidatorRegistry(ColumnCheck))
    frame_parsers: ValidatorRegistry[FrameParser] = Field(default_factory=lambda: ValidatorRegistry(FrameParser))
    frame_checks: ValidatorRegistry[FrameCheck] = Field(default_factory=lambda: ValidatorRegistry(FrameCheck))

    def register_column_parser(self, validator: ColumnParser) -> None:
        """Register a column parser validator.

        Args:
            validator: Column parser to register.
        """
        self.column_parsers.register(validator)

    def register_column_check(self, validator: ColumnCheck) -> None:
        """Register a column check validator.

        Args:
            validator: Column check to register.
        """
        self.column_checks.register(validator)

    def register_frame_parser(self, validator: FrameParser) -> None:
        """Register a frame parser validator.

        Args:
            validator: Frame parser to register.
        """
        self.frame_parsers.register(validator)

    def register_frame_check(self, validator: FrameCheck) -> None:
        """Register a frame check validator.

        Args:
            validator: Frame check to register.
        """
        self.frame_checks.register(validator)

    def get_validator_counts(self) -> dict[str, int]:
        """Get count of validators in each registry.

        Returns:
            Dictionary mapping registry name to validator count.
        """
        return {
            "column_parsers": len(self.column_parsers),
            "column_checks": len(self.column_checks),
            "frame_parsers": len(self.frame_parsers),
            "frame_checks": len(self.frame_checks),
        }

    def __repr__(self) -> str:
        """Return string representation of registry."""
        counts = self.get_validator_counts()
        return (
            f"Registry("
            f"column_parsers={counts['column_parsers']}, "
            f"column_checks={counts['column_checks']}, "
            f"frame_parsers={counts['frame_parsers']}, "
            f"frame_checks={counts['frame_checks']})"
        )

__repr__()

Return string representation of registry.

Source code in src/nyctea/validators/registry.py
def __repr__(self) -> str:
    """Return string representation of registry."""
    counts = self.get_validator_counts()
    return (
        f"Registry("
        f"column_parsers={counts['column_parsers']}, "
        f"column_checks={counts['column_checks']}, "
        f"frame_parsers={counts['frame_parsers']}, "
        f"frame_checks={counts['frame_checks']})"
    )

get_validator_counts()

Get count of validators in each registry.

Returns:

Type Description
dict[str, int]

Dictionary mapping registry name to validator count.

Source code in src/nyctea/validators/registry.py
def get_validator_counts(self) -> dict[str, int]:
    """Get count of validators in each registry.

    Returns:
        Dictionary mapping registry name to validator count.
    """
    return {
        "column_parsers": len(self.column_parsers),
        "column_checks": len(self.column_checks),
        "frame_parsers": len(self.frame_parsers),
        "frame_checks": len(self.frame_checks),
    }

register_column_check(validator)

Register a column check validator.

Parameters:

Name Type Description Default
validator ColumnCheck

Column check to register.

required
Source code in src/nyctea/validators/registry.py
def register_column_check(self, validator: ColumnCheck) -> None:
    """Register a column check validator.

    Args:
        validator: Column check to register.
    """
    self.column_checks.register(validator)

register_column_parser(validator)

Register a column parser validator.

Parameters:

Name Type Description Default
validator ColumnParser

Column parser to register.

required
Source code in src/nyctea/validators/registry.py
def register_column_parser(self, validator: ColumnParser) -> None:
    """Register a column parser validator.

    Args:
        validator: Column parser to register.
    """
    self.column_parsers.register(validator)

register_frame_check(validator)

Register a frame check validator.

Parameters:

Name Type Description Default
validator FrameCheck

Frame check to register.

required
Source code in src/nyctea/validators/registry.py
def register_frame_check(self, validator: FrameCheck) -> None:
    """Register a frame check validator.

    Args:
        validator: Frame check to register.
    """
    self.frame_checks.register(validator)

register_frame_parser(validator)

Register a frame parser validator.

Parameters:

Name Type Description Default
validator FrameParser

Frame parser to register.

required
Source code in src/nyctea/validators/registry.py
def register_frame_parser(self, validator: FrameParser) -> None:
    """Register a frame parser validator.

    Args:
        validator: Frame parser to register.
    """
    self.frame_parsers.register(validator)

ValidatorRegistry

nyctea.validators.registry.ValidatorRegistry

Bases: Generic[T]

Type-safe registry for a specific validator type.

Attributes:

Name Type Description
validator_type

The class of validators this registry accepts.

Source code in src/nyctea/validators/registry.py
class ValidatorRegistry(Generic[T]):
    """Type-safe registry for a specific validator type.

    Attributes:
        validator_type: The class of validators this registry accepts.
    """

    def __init__(self, validator_type: type[T]) -> None:
        """Initialize a validator registry for a specific type.

        Args:
            validator_type: The class of validators this registry will accept.
        """
        self.validator_type = validator_type
        self._validators: dict[str, T] = {}
        self._tags: dict[str, list[T]] = {}

    def register(self, validator: T) -> None:
        """Register a validator instance.

        Args:
            validator: The validator to register.

        Raises:
            TypeError: If validator is not of the correct type.
            RegistrationError: If a validator with the same name is already registered.
        """
        if not isinstance(validator, self.validator_type):
            raise TypeError(f"Registry expects {self.validator_type.__name__}, got {type(validator).__name__}")

        if validator.name in self._validators:
            existing = self._validators[validator.name]
            raise RegistrationError(
                f"Validator '{validator.name}' is already registered as "
                f"{existing.__class__.__name__} (version {existing.metadata.version})",
                validator_name=validator.name,
                validator_type=self.validator_type.__name__,
            )

        self._validators[validator.name] = validator

        for tag in validator.metadata.tags:
            if tag not in self._tags:
                self._tags[tag] = []
            self._tags[tag].append(validator)

    def get(self, name: str) -> T:
        """Get a validator by name.

        Args:
            name: Validator name to lookup.

        Returns:
            The validator instance.

        Raises:
            KeyError: If no validator with that name is registered.
        """
        if name not in self._validators:
            raise KeyError(
                f"No validator named '{name}' registered in "
                f"{self.validator_type.__name__} registry. "
                f"Available: {sorted(self._validators.keys())}"
            )
        return self._validators[name]

    def get_by_tag(self, tag: str) -> list[T]:
        """Get all validators with a specific tag.

        Args:
            tag: Tag to search for.

        Returns:
            A copy of the validators with that tag, empty if none found. A copy so a
            caller cannot reach into the registry's own index, the way `list_all` and
            `list_names` already return copies.
        """
        return list(self._tags.get(tag, []))

    def list_all(self) -> list[T]:
        """Get all registered validators.

        Returns:
            List of all registered validators.
        """
        return list(self._validators.values())

    def list_names(self) -> list[str]:
        """Get names of all registered validators.

        Returns:
            Sorted list of validator names.
        """
        return sorted(self._validators.keys())

    def has(self, name: str) -> bool:
        """Check if a validator is registered.

        Args:
            name: Validator name to check.

        Returns:
            True if validator is registered, False otherwise.
        """
        return name in self._validators

    def __len__(self) -> int:
        """Get number of registered validators."""
        return len(self._validators)

    def __repr__(self) -> str:
        """Return string representation of registry."""
        return f"ValidatorRegistry[{self.validator_type.__name__}]({len(self._validators)} validators)"

__init__(validator_type)

Initialize a validator registry for a specific type.

Parameters:

Name Type Description Default
validator_type type[T]

The class of validators this registry will accept.

required
Source code in src/nyctea/validators/registry.py
def __init__(self, validator_type: type[T]) -> None:
    """Initialize a validator registry for a specific type.

    Args:
        validator_type: The class of validators this registry will accept.
    """
    self.validator_type = validator_type
    self._validators: dict[str, T] = {}
    self._tags: dict[str, list[T]] = {}

__len__()

Get number of registered validators.

Source code in src/nyctea/validators/registry.py
def __len__(self) -> int:
    """Get number of registered validators."""
    return len(self._validators)

__repr__()

Return string representation of registry.

Source code in src/nyctea/validators/registry.py
def __repr__(self) -> str:
    """Return string representation of registry."""
    return f"ValidatorRegistry[{self.validator_type.__name__}]({len(self._validators)} validators)"

get(name)

Get a validator by name.

Parameters:

Name Type Description Default
name str

Validator name to lookup.

required

Returns:

Type Description
T

The validator instance.

Raises:

Type Description
KeyError

If no validator with that name is registered.

Source code in src/nyctea/validators/registry.py
def get(self, name: str) -> T:
    """Get a validator by name.

    Args:
        name: Validator name to lookup.

    Returns:
        The validator instance.

    Raises:
        KeyError: If no validator with that name is registered.
    """
    if name not in self._validators:
        raise KeyError(
            f"No validator named '{name}' registered in "
            f"{self.validator_type.__name__} registry. "
            f"Available: {sorted(self._validators.keys())}"
        )
    return self._validators[name]

get_by_tag(tag)

Get all validators with a specific tag.

Parameters:

Name Type Description Default
tag str

Tag to search for.

required

Returns:

Type Description
list[T]

A copy of the validators with that tag, empty if none found. A copy so a

list[T]

caller cannot reach into the registry's own index, the way list_all and

list[T]

list_names already return copies.

Source code in src/nyctea/validators/registry.py
def get_by_tag(self, tag: str) -> list[T]:
    """Get all validators with a specific tag.

    Args:
        tag: Tag to search for.

    Returns:
        A copy of the validators with that tag, empty if none found. A copy so a
        caller cannot reach into the registry's own index, the way `list_all` and
        `list_names` already return copies.
    """
    return list(self._tags.get(tag, []))

has(name)

Check if a validator is registered.

Parameters:

Name Type Description Default
name str

Validator name to check.

required

Returns:

Type Description
bool

True if validator is registered, False otherwise.

Source code in src/nyctea/validators/registry.py
def has(self, name: str) -> bool:
    """Check if a validator is registered.

    Args:
        name: Validator name to check.

    Returns:
        True if validator is registered, False otherwise.
    """
    return name in self._validators

list_all()

Get all registered validators.

Returns:

Type Description
list[T]

List of all registered validators.

Source code in src/nyctea/validators/registry.py
def list_all(self) -> list[T]:
    """Get all registered validators.

    Returns:
        List of all registered validators.
    """
    return list(self._validators.values())

list_names()

Get names of all registered validators.

Returns:

Type Description
list[str]

Sorted list of validator names.

Source code in src/nyctea/validators/registry.py
def list_names(self) -> list[str]:
    """Get names of all registered validators.

    Returns:
        Sorted list of validator names.
    """
    return sorted(self._validators.keys())

register(validator)

Register a validator instance.

Parameters:

Name Type Description Default
validator T

The validator to register.

required

Raises:

Type Description
TypeError

If validator is not of the correct type.

RegistrationError

If a validator with the same name is already registered.

Source code in src/nyctea/validators/registry.py
def register(self, validator: T) -> None:
    """Register a validator instance.

    Args:
        validator: The validator to register.

    Raises:
        TypeError: If validator is not of the correct type.
        RegistrationError: If a validator with the same name is already registered.
    """
    if not isinstance(validator, self.validator_type):
        raise TypeError(f"Registry expects {self.validator_type.__name__}, got {type(validator).__name__}")

    if validator.name in self._validators:
        existing = self._validators[validator.name]
        raise RegistrationError(
            f"Validator '{validator.name}' is already registered as "
            f"{existing.__class__.__name__} (version {existing.metadata.version})",
            validator_name=validator.name,
            validator_type=self.validator_type.__name__,
        )

    self._validators[validator.name] = validator

    for tag in validator.metadata.tags:
        if tag not in self._tags:
            self._tags[tag] = []
        self._tags[tag].append(validator)

Decorators

nyctea.validators.decorators.checker(func=None, *, name=None, description='', version='1.0.0', tags=None, author='', registry=None)

checker(func: _ColumnFn) -> _ColumnFn
checker(
    func: None = None,
    *,
    name: str | None = None,
    description: str = "",
    version: str = "1.0.0",
    tags: Sequence[str] | None = None,
    author: str = "",
    registry: Registry | None = None,
) -> Callable[[_ColumnFn], _ColumnFn]

Declare a function as a column check.

Works bare (@checker), which infers the check's name from the function, or parameterized (@checker(...)) for an explicit name or the rest of the contract. Arguments after name are keyword-only and are checked against a schema's arguments before any data is read.

Parameters:

Name Type Description Default
func _ColumnFn | None

The decorated function. Only present for the bare form; leave it out and call with keyword arguments for the parameterized form.

None
name str | None

Check name. Bare form infers it from the function's __name__.

None
description str

Human-readable description. Defaults to the function's docstring.

''
version str

Validator version.

'1.0.0'
tags Sequence[str] | None

Optional tags for discovery.

None
author str

Validator author.

''
registry Registry | None

Register immediately into this registry. Without it the check is declared into CATALOGUE and registered by register_builtins.

None

Returns:

Type Description
Any

The function unchanged (bare form), or a decorator that returns it unchanged

Any

(parameterized form).

Source code in src/nyctea/validators/decorators.py
def checker(
    func: _ColumnFn | None = None,
    *,
    name: str | None = None,
    description: str = "",
    version: str = "1.0.0",
    tags: Sequence[str] | None = None,
    author: str = "",
    registry: Registry | None = None,
) -> Any:
    """Declare a function as a column check.

    Works bare (`@checker`), which infers the check's name from the function, or
    parameterized (`@checker(...)`) for an explicit name or the rest of the
    contract. Arguments after `name` are keyword-only and are checked against a
    schema's arguments before any data is read.

    Args:
        func: The decorated function. Only present for the bare form; leave it out
            and call with keyword arguments for the parameterized form.
        name: Check name. Bare form infers it from the function's `__name__`.
        description: Human-readable description. Defaults to the function's docstring.
        version: Validator version.
        tags: Optional tags for discovery.
        author: Validator author.
        registry: Register immediately into this registry. Without it the check is
            declared into `CATALOGUE` and registered by `register_builtins`.

    Returns:
        The function unchanged (bare form), or a decorator that returns it unchanged
        (parameterized form).
    """
    return _dispatch(
        "column_check",
        func,
        name=name,
        description=description,
        version=version,
        tags=tags,
        author=author,
        registry=registry,
    )

nyctea.validators.decorators.parser(func=None, *, name=None, description='', version='1.0.0', tags=None, author='', registry=None)

parser(func: _ColumnFn) -> _ColumnFn
parser(
    func: None = None,
    *,
    name: str | None = None,
    description: str = "",
    version: str = "1.0.0",
    tags: Sequence[str] | None = None,
    author: str = "",
    registry: Registry | None = None,
) -> Callable[[_ColumnFn], _ColumnFn]

Declare a function as a column parser.

Works bare (@parser), which infers the parser's name from the function, or parameterized (@parser(...)) for an explicit name or the rest of the contract. Arguments after name are keyword-only and are checked against a schema's arguments before any data is read.

Parameters:

Name Type Description Default
func _ColumnFn | None

The decorated function. Only present for the bare form; leave it out and call with keyword arguments for the parameterized form.

None
name str | None

Parser name. Bare form infers it from the function's __name__.

None
description str

Human-readable description. Defaults to the function's docstring.

''
version str

Validator version.

'1.0.0'
tags Sequence[str] | None

Optional tags for discovery.

None
author str

Validator author.

''
registry Registry | None

Register immediately into this registry. Without it the parser is declared into CATALOGUE and registered by register_builtins.

None

Returns:

Type Description
Any

The function unchanged (bare form), or a decorator that returns it unchanged

Any

(parameterized form).

Source code in src/nyctea/validators/decorators.py
def parser(
    func: _ColumnFn | None = None,
    *,
    name: str | None = None,
    description: str = "",
    version: str = "1.0.0",
    tags: Sequence[str] | None = None,
    author: str = "",
    registry: Registry | None = None,
) -> Any:
    """Declare a function as a column parser.

    Works bare (`@parser`), which infers the parser's name from the function, or
    parameterized (`@parser(...)`) for an explicit name or the rest of the contract.
    Arguments after `name` are keyword-only and are checked against a schema's
    arguments before any data is read.

    Args:
        func: The decorated function. Only present for the bare form; leave it out
            and call with keyword arguments for the parameterized form.
        name: Parser name. Bare form infers it from the function's `__name__`.
        description: Human-readable description. Defaults to the function's docstring.
        version: Validator version.
        tags: Optional tags for discovery.
        author: Validator author.
        registry: Register immediately into this registry. Without it the parser is
            declared into `CATALOGUE` and registered by `register_builtins`.

    Returns:
        The function unchanged (bare form), or a decorator that returns it unchanged
        (parameterized form).
    """
    return _dispatch(
        "column_parser",
        func,
        name=name,
        description=description,
        version=version,
        tags=tags,
        author=author,
        registry=registry,
    )

nyctea.validators.decorators.frame_checker(func=None, *, name=None, description='', version='1.0.0', tags=None, author='', registry=None)

frame_checker(func: _FrameFn) -> _FrameFn
frame_checker(
    func: None = None,
    *,
    name: str | None = None,
    description: str = "",
    version: str = "1.0.0",
    tags: Sequence[str] | None = None,
    author: str = "",
    registry: Registry | None = None,
) -> Callable[[_FrameFn], _FrameFn]

Declare a function as a frame check.

Works bare (@frame_checker), which infers the check's name from the function, or parameterized (@frame_checker(...)) for an explicit name or the rest of the contract. Arguments after name are keyword-only and are checked against a schema's arguments before any data is read.

Parameters:

Name Type Description Default
func _FrameFn | None

The decorated function. Only present for the bare form; leave it out and call with keyword arguments for the parameterized form.

None
name str | None

Check name. Bare form infers it from the function's __name__.

None
description str

Human-readable description. Defaults to the function's docstring.

''
version str

Validator version.

'1.0.0'
tags Sequence[str] | None

Optional tags for discovery.

None
author str

Validator author.

''
registry Registry | None

Register immediately into this registry. Without it the check is declared into CATALOGUE and registered by register_builtins.

None

Returns:

Type Description
Any

The function unchanged (bare form), or a decorator that returns it unchanged

Any

(parameterized form).

Source code in src/nyctea/validators/decorators.py
def frame_checker(
    func: _FrameFn | None = None,
    *,
    name: str | None = None,
    description: str = "",
    version: str = "1.0.0",
    tags: Sequence[str] | None = None,
    author: str = "",
    registry: Registry | None = None,
) -> Any:
    """Declare a function as a frame check.

    Works bare (`@frame_checker`), which infers the check's name from the function,
    or parameterized (`@frame_checker(...)`) for an explicit name or the rest of the
    contract. Arguments after `name` are keyword-only and are checked against a
    schema's arguments before any data is read.

    Args:
        func: The decorated function. Only present for the bare form; leave it out
            and call with keyword arguments for the parameterized form.
        name: Check name. Bare form infers it from the function's `__name__`.
        description: Human-readable description. Defaults to the function's docstring.
        version: Validator version.
        tags: Optional tags for discovery.
        author: Validator author.
        registry: Register immediately into this registry. Without it the check is
            declared into `CATALOGUE` and registered by `register_builtins`.

    Returns:
        The function unchanged (bare form), or a decorator that returns it unchanged
        (parameterized form).
    """
    return _dispatch(
        "frame_check",
        func,
        name=name,
        description=description,
        version=version,
        tags=tags,
        author=author,
        registry=registry,
    )

nyctea.validators.decorators.frame_parser(func=None, *, name=None, description='', version='1.0.0', tags=None, author='', registry=None)

frame_parser(func: _FrameFn) -> _FrameFn
frame_parser(
    func: None = None,
    *,
    name: str | None = None,
    description: str = "",
    version: str = "1.0.0",
    tags: Sequence[str] | None = None,
    author: str = "",
    registry: Registry | None = None,
) -> Callable[[_FrameFn], _FrameFn]

Declare a function as a frame parser.

Works bare (@frame_parser), which infers the parser's name from the function, or parameterized (@frame_parser(...)) for an explicit name or the rest of the contract. Arguments after name are keyword-only and are checked against a schema's arguments before any data is read.

Parameters:

Name Type Description Default
func _FrameFn | None

The decorated function. Only present for the bare form; leave it out and call with keyword arguments for the parameterized form.

None
name str | None

Parser name. Bare form infers it from the function's __name__.

None
description str

Human-readable description. Defaults to the function's docstring.

''
version str

Validator version.

'1.0.0'
tags Sequence[str] | None

Optional tags for discovery.

None
author str

Validator author.

''
registry Registry | None

Register immediately into this registry. Without it the parser is declared into CATALOGUE and registered by register_builtins.

None

Returns:

Type Description
Any

The function unchanged (bare form), or a decorator that returns it unchanged

Any

(parameterized form).

Source code in src/nyctea/validators/decorators.py
def frame_parser(
    func: _FrameFn | None = None,
    *,
    name: str | None = None,
    description: str = "",
    version: str = "1.0.0",
    tags: Sequence[str] | None = None,
    author: str = "",
    registry: Registry | None = None,
) -> Any:
    """Declare a function as a frame parser.

    Works bare (`@frame_parser`), which infers the parser's name from the function,
    or parameterized (`@frame_parser(...)`) for an explicit name or the rest of the
    contract. Arguments after `name` are keyword-only and are checked against a
    schema's arguments before any data is read.

    Args:
        func: The decorated function. Only present for the bare form; leave it out
            and call with keyword arguments for the parameterized form.
        name: Parser name. Bare form infers it from the function's `__name__`.
        description: Human-readable description. Defaults to the function's docstring.
        version: Validator version.
        tags: Optional tags for discovery.
        author: Validator author.
        registry: Register immediately into this registry. Without it the parser is
            declared into `CATALOGUE` and registered by `register_builtins`.

    Returns:
        The function unchanged (bare form), or a decorator that returns it unchanged
        (parameterized form).
    """
    return _dispatch(
        "frame_parser",
        func,
        name=name,
        description=description,
        version=version,
        tags=tags,
        author=author,
        registry=registry,
    )