openrig.naming package

Naming package for OpenRig.

This package provides a configurable system for building, parsing, and validating names according to a defined convention.

The main entry point is get_manager(), which returns a singleton Manager instance pre-configured with the rules and normalizers declared in naming/config.json.

Public API:
  • get_manager() -> Manager: returns the singleton manager.

  • Manager: the naming manager class.

  • Normalizer: type alias for normalizer callables.

Example

>>> from openrig.naming import get_manager
>>> manager = get_manager()
>>> manager.build_name(descriptor="arm", side="l", usage="jnt")
'arm_l_jnt'
class openrig.naming.Manager(tokens: Sequence[str] | None = None, separator: str | None = None, rules: dict[str, RegexRule | ListRule | CallableRule] | None = None, normalizers: dict[str, Callable[[object], str]] | None = None, global_rules: GlobalRules | None = None)[source]

Bases: object

Manages naming conventions by validating and operating on strings.

Builds, parses, and validates names according to a configurable token structure. All token values are normalized to plain strings before validation, so callers may pass raw str or Enum members.

tokens

Ordered list of token name strings.

Type:

list[str]

separator

Character used to join token values.

Type:

str

rules

Mapping of token name to its ConcreteRule.

Type:

dict[str, openrig.naming.types.RegexRule | openrig.naming.types.ListRule | openrig.naming.types.CallableRule]

normalizers

Mapping of token name to its normalizer callable.

Type:

dict[str, Callable[[object], str]]

global_rules

Global constraints applied to every built name.

Type:

openrig.naming.types.GlobalRules

Example

>>> from openrig.naming.types import RegexRule, ListRule, GlobalRules
>>> manager = Manager(
...     tokens=["descriptor", "side", "usage"],
...     separator="_",
...     rules={
...         "descriptor": RegexRule(pattern=r"^[a-z][a-zA-Z0-9]*$"),
...         "side": ListRule(allowed=frozenset({"l", "r", "c"})),
...     },
...     global_rules=GlobalRules(max_length=80),
... )
>>> manager.build_name(descriptor="arm", side="l", usage="jnt")
'arm_l_jnt'
__init__(tokens: Sequence[str] | None = None, separator: str | None = None, rules: dict[str, RegexRule | ListRule | CallableRule] | None = None, normalizers: dict[str, Callable[[object], str]] | None = None, global_rules: GlobalRules | None = None) None[source]

Initializes the naming Manager.

Parameters:
  • tokens – Ordered sequence of token name strings.

  • separator – Character used to join token values. Must not be empty.

  • rules – Mapping of token name to its ConcreteRule. Tokens without a rule accept any value.

  • normalizers – Mapping of token name to its normalizer callable. Normalizers are applied before validation.

  • global_rules – Global constraints (max length, forbidden patterns). Defaults to an unconstrained GlobalRules instance.

Raises:

NamingConfigError – If separator is None or empty.

tokens: list[str]
separator: str
rules: dict[str, RegexRule | ListRule | CallableRule]
normalizers: dict[str, Callable[[object], str]]
global_rules: GlobalRules
__repr__() str[source]

Returns a developer-friendly string representation.

classmethod from_dict(data: ManagerConfig) Manager[source]

Creates a Manager instance from a ManagerConfig dictionary.

Parameters:

data – A ManagerConfig typed dict containing the configuration.

Returns:

A new Manager instance.

to_dict() ManagerConfig[source]

Exports the current configuration as a ManagerConfig dictionary.

Returns:

A ManagerConfig typed dict representing the current state.

is_valid(name: str) bool[source]

Returns True if name is fully valid against all tokens.

A name is fully valid when it contains a non-empty, rule-conforming value for every token defined in the convention. For partial validation use get_data and inspect individual token values.

Parameters:

name – The candidate name string.

Returns:

True if the name is strictly valid, False otherwise.

is_valid_token(token: str, value: str) bool[source]

Returns True if value is valid for the given token.

Checks that the value does not contain the separator, then delegates to the token’s ConcreteRule.validate method.

Parameters:
  • token – The token name.

  • value – The normalized (post-normalization) string value.

Returns:

True if valid, False otherwise.

get_data(name: str) dict[str, str][source]

Extracts token values from a name string using the matching regex.

Parameters:

name – The name string to parse.

Returns:

A TokenData dict mapping every token name to its extracted value, or "" for tokens not present in the name.

parse(name: str) dict[str, str] | str[source]

Attempts to parse a name into its constituent token values.

Tries in order: 1. Regex-based extraction (strict structural match). 2. Split-based extraction (loose positional match). 3. Returns the original string if both fail.

Parameters:

name – The name string to parse.

Returns:

A TokenData dict if parsing succeeds, or the original str if the name does not conform to the convention.

get_token_value(name: str, token_name: str) str[source]

Returns the value of a specific token extracted from a name.

Parameters:
  • name – The name string to extract from.

  • token_name – The name of the token to retrieve.

Returns:

The extracted token value, or "" if not present.

Raises:

NamingValidationError – If token_name is not defined in this manager’s token list.

get_errors(name: str) list[str][source]

Returns a list of human-readable validation errors for a name.

Parameters:

name – The name string to validate.

Returns:

A list of error message strings. Empty if the name is valid.

get_matching_regex(capture_groups: bool = False, full_match: bool = True, strict: bool = False) str[source]

Generates a regex pattern matching names against this convention.

Tokens are optional from right to left: for tokens ["descriptor", "side", "usage"] the pattern matches "arm", "arm_l", and "arm_l_jnt", but never "arm__jnt".

The pattern for each token is derived from its ConcreteRule via rule.to_regex_pattern(). Tokens without a rule use a catch-all pattern that excludes the separator.

Results are cached by (capture_groups, full_match, strict).

Parameters:
  • capture_groups – If True, wraps each token in a named capture group (?P<token_name>...).

  • full_match – If True, anchors the pattern with ^ / $.

  • strict – If True, all tokens are required (no optional groups).

Returns:

The assembled regex pattern string.

add_rule(token: str, rule: RegexRule | ListRule | CallableRule) None[source]

Adds or replaces the validation rule for a token.

Clears the regex cache because the pattern depends on all rules.

Parameters:
  • token – The token name.

  • rule – The ConcreteRule instance to associate with the token.

remove_rule(token: str) None[source]

Removes the validation rule for a token, if present.

Clears the regex cache because the pattern depends on all rules.

Parameters:

token – The token name whose rule should be removed.

build_name(**kwargs: str | Enum) str[source]

Builds a name string from token values.

Normalizes each provided value, validates it against the token’s rule, joins all non-empty values with the separator, and then checks the result against the global rules.

Parameters:

**kwargs – Token values keyed by token name. Values may be str or Enum members; they are normalized before validation.

Returns:

The assembled name string.

Raises:

NamingValidationError – If unknown tokens are provided, if a normalized value fails its rule, or if the assembled name violates a global constraint.

update_name(name: str, **kwargs: str | Enum) str[source]

Updates specific token values in an existing name.

Parses name into its token values, applies kwargs as overrides, then rebuilds the name.

If name cannot be parsed against the full convention, it is treated as a bare descriptor (first token) provided it passes the first token’s rule.

Parameters:
  • name – The existing name string to update.

  • **kwargs – Token values to override. Same rules as build_name.

Returns:

The updated name string.

Raises:

NamingValidationError – If name cannot be interpreted and is not empty, or if the updated values are invalid.

resolve_name(value: str | dict[str, str] | Sequence[str | Enum], tokens: list[str] | None = None, rules: dict[str, RegexRule | ListRule | CallableRule] | None = None, normalizers: dict[str, Callable[[object], str]] | None = None) str[source]

Resolves a flexible input into a final name string.

Provides a unified entry point for callers that may supply names as dicts, sequences, or plain strings. When tokens, rules, or normalizers overrides are provided, a temporary Manager is created with those overrides applied on top of the current config.

Supported value types: - dict (TokenData): passed directly to build_name. - list / tuple (Sequence[TokenValue]): values are

mapped positionally to tokens, then passed to build_name.

  • str: returned as-is (no building or validation).

Parameters:
  • value – The input to resolve.

  • tokens – Optional token list override.

  • rules – Optional rules override.

  • normalizers – Optional normalizers override.

Returns:

The resolved name string.

Raises:

NamingValidationError – If a sequence input has more items than there are tokens.

openrig.naming.get_manager() Manager[source]

Returns the pre-configured singleton Manager instance.

Builds the instance on first call using the convention defined in naming/config.json (via rules.py). Subsequent calls return the same instance.

Returns:

The singleton Manager instance.

Submodules