SyntaxUtils: Syntax Utilities#

class my.utils.SyntaxUtils.SyntaxUtils#

Methods for syntax-y tasks (i.e. related to data’s form rather than its content).

I Normalization#

classmethod SyntaxUtils.fill_tree(tree: dict[T, C]) → None#

Recursively replace None values with empty dicts in a nested tree structure.

Modifies tree in-place.

Parameters:

tree – Nested dictionary tree to fill.

Examples

Backfill empty leaves at any depth:

>>> from my import ut
>>> tree = {'a': None, 'b': {'c': None}}
>>> ut.fill_tree(tree)
>>> tree
{'a': {}, 'b': {'c': {}}}
classmethod SyntaxUtils.tree_size(tree: object) → int#

Calculate total number of leaf nodes in a nested tree structure.

Parameters:

tree – Tree structure (dict of dicts, or leaf value).

Returns:

Total count of leaf nodes (non-dict values).

Examples

Count the leaves, not the branches:

>>> from my import ut
>>> ut.tree_size({'a': {'b': 1, 'c': 2}, 'd': 3})
3

II Annotation#

static SyntaxUtils.pyd_schemify(tvar: type) → GetPydanticSchema#

Create Pydantic schema validator for instance type checking.

Parameters:

tvar – Type to create validator for.

Returns:

GetPydanticSchema validator for use with Annotated types.

Examples

Let a Pydantic model carry compiled patterns:

>>> from typing import Annotated
>>> import pydantic, regex
>>> from my import ut
>>> class Cfg(pydantic.BaseModel):
...     rgx: Annotated[regex.Pattern, ut.pyd_schemify(regex.Pattern)]
>>> Cfg(rgx=regex.compile(r'\d+')).rgx.pattern
'\\d+'

III Reflection#

static SyntaxUtils.instance_fields(cls: type) → dict[str, Any]#

Extract instance field names and annotations from a Pydantic model or typeddict.

Parameters:

cls – Pydantic BaseModel class to inspect.

Returns:

Dictionary mapping lowercase field names to their type annotations.

Examples

Inspect a model’s instance fields:

>>> import pydantic
>>> from my import ut
>>> class User(pydantic.BaseModel):
...     name: str
...     age: int = 0
>>> ut.instance_fields(User)
{'name': <class 'str'>, 'age': <class 'int'>}
SyntaxUtils.instance_aliases() → dict[str, Any]#

Extract field aliases and types from a Pydantic model with caching.

Resolves field aliases including validation aliases and alias choices, converting AliasPath objects to string representations.

Parameters:

cls – Pydantic BaseModel class to inspect.

Returns:

Dictionary mapping field aliases to their type annotations.

Examples

Aliases replace raw field names where declared:

>>> import pydantic
>>> from my import ut
>>> class Row(pydantic.BaseModel):
...     full_name: str = pydantic.Field(alias='fullName')
>>> ut.instance_aliases(Row)
{'fullName': <class 'str'>}
classmethod SyntaxUtils.nested_replace(obj: Collection | BaseModel, old: Any, new: Any, depth: int = 0, max_depth: int = 10) → bool#

Recursively search and replace a single value in nested data structures.

Supports sequences (list, tuple, deque, set), mappings (dict), and Pydantic models. Recursively traverses nested structures up to depth limit.

A tuple is immutable, so a value found directly among a tuple’s own elements cannot be replaced in place; that case reports False rather than a false success. Mutable containers (list, dict, model, …) nested inside a tuple are still replaced normally, since the tuple’s reference to them is untouched.

Parameters:
  • obj – Collection or Pydantic model to search within.

  • old – Value to find and replace.

  • new – Replacement value.

  • depth – Current recursion depth, up to a hard max of 100.

  • max_depth – Maximum recursion depth.

Returns:

True if value was found and replaced, False otherwise.

Examples

Replace a value wherever it hides; immutable tuples report failure:

>>> from my import ut
>>> data = {'a': [1, 2, {'b': 'old'}]}
>>> ut.nested_replace(data, 'old', 'new')
True
>>> data
{'a': [1, 2, {'b': 'new'}]}
>>> ut.nested_replace(('x',), 'x', 'y')
False
static SyntaxUtils.import_module(file: Annotated[Path, PathType(path_type=file)], root: Annotated[Path, PathType(path_type=dir)]) → ModuleType#

Dynamically import a Python module from a file path.

Converts file path to module dotted notation and imports it.

Parameters:
  • file – Path to Python file to import.

  • root – Root directory for relative import path calculation.

Returns:

Imported ModuleType object.

Examples

Import src/pkg/mod.py as the module pkg.mod:

>>> from pathlib import Path
>>> from my import ut
>>> ut.import_module(Path('src/pkg/mod.py'), Path('src'))
<module 'pkg.mod' from 'src/pkg/mod.py'>

IV Caching#

static SyntaxUtils.clear_cached_properties(inst: object, *properties: str) → None#

Clear cached properties from an object instance.

If no properties specified, clears all properties listed in instance’s CACHED_PROPERTIES attribute.

Parameters:
  • inst – Object instance to clear cached properties from.

  • *properties – Property names to clear. If empty, uses inst.CACHED_PROPERTIES.

Examples

Invalidate a functools.cached_property:

>>> import functools
>>> from my import ut
>>> class Report:
...     @functools.cached_property
...     def total(self):
...         return sum(range(5))
>>> report = Report()
>>> report.total
10
>>> ut.clear_cached_properties(report, 'total')
>>> 'total' in report.__dict__
False