koji_habitude.namespace

koji_habitude.namespace

A Namespace is a platform for converting YAML documents into instances of core types. It controls the direct unmarshaling, as well as the resolution logic for defining and expanding templates.

author:

Christopher O’Brien <obriencj@gmail.com>

license:

GNU General Public License v3

ai-assistant:

Claude 3.5 Sonnet via Cursor

class koji_habitude.namespace.ExpanderNamespace(coretypes: ~typing.Mapping[str, ~typing.Type[~koji_habitude.models.base.CoreObject]] | ~typing.Iterable[~typing.Type[~koji_habitude.models.base.CoreObject]] = {'archive-type': <class 'koji_habitude.models.archive_type.ArchiveType'>, 'build-type': <class 'koji_habitude.models.build_type.BuildType'>, 'channel': <class 'koji_habitude.models.channel.Channel'>, 'content-generator': <class 'koji_habitude.models.content_generator.ContentGenerator'>, 'external-repo': <class 'koji_habitude.models.external_repo.ExternalRepo'>, 'group': <class 'koji_habitude.models.group.Group'>, 'host': <class 'koji_habitude.models.host.Host'>, 'permission': <class 'koji_habitude.models.permission.Permission'>, 'tag': <class 'koji_habitude.models.tag.Tag'>, 'target': <class 'koji_habitude.models.target.Target'>, 'user': <class 'koji_habitude.models.user.User'>}, redefine: ~koji_habitude.namespace.Redefine = Redefine.ERROR, logger: ~logging.Logger | None = None)

Bases: Namespace

A namespace that expands all core types to basic BaseObject instances. This avoids schema validation, and enables us to guarantee template expansion. Useful for when a user want to see the raw expanded output of their templates.

class koji_habitude.namespace.Namespace(coretypes: ~typing.Mapping[str, ~typing.Type[~koji_habitude.models.base.CoreObject]] | ~typing.Iterable[~typing.Type[~koji_habitude.models.base.CoreObject]] = {'archive-type': <class 'koji_habitude.models.archive_type.ArchiveType'>, 'build-type': <class 'koji_habitude.models.build_type.BuildType'>, 'channel': <class 'koji_habitude.models.channel.Channel'>, 'content-generator': <class 'koji_habitude.models.content_generator.ContentGenerator'>, 'external-repo': <class 'koji_habitude.models.external_repo.ExternalRepo'>, 'group': <class 'koji_habitude.models.group.Group'>, 'host': <class 'koji_habitude.models.host.Host'>, 'permission': <class 'koji_habitude.models.permission.Permission'>, 'tag': <class 'koji_habitude.models.tag.Tag'>, 'target': <class 'koji_habitude.models.target.Target'>, 'user': <class 'koji_habitude.models.user.User'>}, enable_templates: bool = True, redefine: ~koji_habitude.namespace.Redefine = Redefine.ERROR, logger: ~logging.Logger | None = None)

Bases: object

add(obj: CoreObject) → None

Add an object to the namespace. This is called during the expand method as objects are loaded from the feed queue.

Parameters:

obj – The base object to add

Raises:

TypeError – If the object is a Template or TemplateCall

add_template(template: Template)

Add a template to the namespace. This is called during the expand method as templates are loaded from the feed queue.

Parameters:

template – The template to add

Raises:

TypeError – If the object is not a Template

expand() → None

Process the queue of objects that have been fed into this namespace via the feed or feedall methods. At this point any templates in the queue will be added to the namespace, and any template calls will be expanded. This is the final step in the loading process.

The redefine semantics are applied as objects are processed, so this method will raise an exception if a redefinition is encountered and the redefine setting is ERROR.

Raises:
  • ExpansionError – If the maximum depth is reached when attempting to expand a recursively expanding template

  • AssertionError – If the first deferal is not a TemplateCall when no further objects can be added to the namespace (indicates a bug)

feed(obj: CoreObject | Template | TemplateCall)

Appends an object to the queue of objects to be added to this namespace. This queue is processed via the expand() method.

Parameters:

obj – The core object to add to the queue

feed_raw(data: Dict[str, Any]) → None

Add raw data to the queue of objects to be added to this namespace. The data will be converted to an object via the to_object method. This queue is processed via the expand() method.

Parameters:

data – The raw data dictionary to add

feedall(sequence: Iterable[CoreObject | Template | TemplateCall]) → None

Appends all objects in sequence into the queue of objects to be added to this namespace. This queue is processed via the expand() method.

Parameters:

sequence – The sequence of core objects to add to the queue

feedall_raw(datasequence: Iterable[Dict[str, Any]]) → None

Add a sequence of raw data to the queue of objects to be added to this namespace. The data will be converted to an object via the to_object method. This queue is processed via the expand() method.

Parameters:

datasequence – The sequence of raw data dictionaries to add

get(key: Tuple[str, str], default: Any | None = None) → CoreObject | None

Return the object in the namespace with the given key.

Parameters:
  • key – The base key to look up

  • default – Default value to return if key not found

Returns:

The base object or default value

get_template(name: str) → Template | None

Return the template in the namespace with the given name.

Parameters:

name – The template name

Returns:

The template object or None

get_type(typename: str, or_call: bool = True) → Type[CoreObject] | Type[Template] | Type[TemplateCall] | None

Return the type for the given typename. If or_call is True (the default), will return a TemplateCall for missing type names. If or_call is False, or if the Namespace was not created with templates enabled, then this will return None for missing type names.

Parameters:
  • typename – The type name to look up

  • or_call – Whether to return a TemplateCall for missing types

Returns:

The type class or None

items() → Iterable[Tuple[Tuple[str, str], CoreObject]]

Return an iterator over the items in the namespace.

Returns:

Iterator over (key, object) tuples

keys() → Iterable[Tuple[str, str]]

Return an iterator over the keys in the namespace.

Returns:

Iterator over base keys

merge_templates(other: Namespace, redefine: Redefine | None = None) → None

Merge the templates from another namespace into this one, following the redefine semantics of this namespace. If redefine is provided, use those rules instead.

Parameters:
  • other – The namespace to merge templates from

  • redefine – Optional redefine setting to override the instance setting

templates() → Iterable[Template]

Return an iterator over the templates in the namespace.

Returns:

Iterator over template objects

to_object(objdict: Dict[str, Any]) → CoreObject | Template | TemplateCall

Convert a dictionary into a Resolvable object instance. Types are resolved from the type key. An exception is raised if no type key is present.

If templates are enabled, then the type key may be template in order to define a new template. Any other unknown type is assumed to be a template call.

If templates are not enabled, then any unknown type is an error.

Parameters:

objdict – The dictionary to convert

Returns:

A resolvable object instance

Raises:
  • ValueError – If no type key is present, or if no type handler is found for the type

  • ValidationError – If pydantic validation fails for the object

to_objects(objseq: Iterable[Dict[str, Any]]) → Iterable[CoreObject | Template | TemplateCall]

Convert a sequence of dictionaries into a sequence of Resolvable object instances, via the to_object method.

Parameters:

objseq – The sequence of dictionaries to convert

Returns:

Sequence of resolvable object instances

values() → Iterable[CoreObject]

Return an iterator over the values in the namespace.

Returns:

Iterator over base objects

class koji_habitude.namespace.Redefine(value)

Bases: Enum

Represents the options for how we want Namespace.add and Namespace.add_template to behave when the newly added item conflicts with a previously added entry

ALLOW = 4

this means redefinition is allowed

ALLOW_WARN = 5

this means redefinition is allowed but produces a warning

ERROR = 1

this means redefinition raises an exception

IGNORE = 2

this means redefinition is ignored

IGNORE_WARN = 3

this means redefinition is ignored but produces a warning

class koji_habitude.namespace.TemplateNamespace(coretypes: ~typing.Mapping[str, ~typing.Type[~koji_habitude.models.base.CoreObject]] | ~typing.Iterable[~typing.Type[~koji_habitude.models.base.CoreObject]] = {'archive-type': <class 'koji_habitude.models.archive_type.ArchiveType'>, 'build-type': <class 'koji_habitude.models.build_type.BuildType'>, 'channel': <class 'koji_habitude.models.channel.Channel'>, 'content-generator': <class 'koji_habitude.models.content_generator.ContentGenerator'>, 'external-repo': <class 'koji_habitude.models.external_repo.ExternalRepo'>, 'group': <class 'koji_habitude.models.group.Group'>, 'host': <class 'koji_habitude.models.host.Host'>, 'permission': <class 'koji_habitude.models.permission.Permission'>, 'tag': <class 'koji_habitude.models.tag.Tag'>, 'target': <class 'koji_habitude.models.target.Target'>, 'user': <class 'koji_habitude.models.user.User'>}, redefine: ~koji_habitude.namespace.Redefine = Redefine.ERROR, logger: ~logging.Logger | None = None)

Bases: Namespace

A namespace that only allows templates to be added and expanded. Discards all other objects.

add(obj: CoreObject) → None

Does nothing in this subclass

to_object(data: Dict[str, Any]) → CoreObject | Template | TemplateCall | None

Convert a dictionary into a Resolvable object instance. Types are resolved from the type key. An exception is raised if no type key is present.

If templates are enabled, then the type key may be template in order to define a new template. Any other unknown type is assumed to be a template call.

If templates are not enabled, then any unknown type is an error.

Parameters:

objdict – The dictionary to convert

Returns:

A resolvable object instance

Raises:
  • ValueError – If no type key is present, or if no type handler is found for the type

  • ValidationError – If pydantic validation fails for the object

to_objects(dataseq: Iterable[Dict[str, Any]]) → Iterable[CoreObject | Template | TemplateCall]

Convert a sequence of dictionaries into a sequence of Resolvable object instances, via the to_object method.

Parameters:

objseq – The sequence of dictionaries to convert

Returns:

Sequence of resolvable object instances