API Reference
nestedutils.access ¶
get_at ¶
get_at(data: Any, path: Union[str, List[Any]], *, default: Any = MISSING) -> Any
Retrieve a value from a nested data structure.
Navigates through nested dictionaries, lists, and tuples using a path specified as either
a dot-notation string or a list of keys/indices. By default, raises PathError if the path
does not exist. Use the default parameter to return a value instead of raising.
Supports negative indexing for lists and tuples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data |
Any
|
The data structure to navigate (dict, list, tuple, or nested combinations). |
required |
path |
Union[str, List[Any]]
|
Path to the value. Accepts either a dot-separated string (e.g., "a.b.0.name") or a list of keys/indices (e.g., ["a", "b", 0, "name"]). Indices may be integers or strings representing integers (including negative indices). |
required |
default |
Any
|
Value to return if the path does not exist. If not provided, raises PathError for missing paths. |
MISSING
|
Returns:
| Type | Description |
|---|---|
Any
|
The value at the specified path, or |
Any
|
|
Raises:
| Type | Description |
|---|---|
PathError
|
If the path is malformed, empty, contains empty keys, or path doesn't exist (when default is not provided). |
Examples:
data = {"a": {"b": {"c": 5}}}
get_at(data, "a.b.c") # Returns: 5
# Missing paths raise by default
get_at(data, "a.b.d") # Raises: PathError
# Explicit default for optional values
get_at(data, "a.b.d", default=99) # Returns: 99
data = {"items": [{"name": "apple"}, {"name": "banana"}]}
get_at(data, "items.1.name") # Returns: 'banana'
get_at(data, "items.-1.name") # Returns: 'banana'
get_at(data, "items.-5.name", default="not found") # Returns: 'not found'
data = (10, 20, 30)
get_at(data, "-1") # Returns: 30
set_at ¶
set_at(data: Any, path: Union[str, List[Any]], value: Any, *, create: bool = False) -> None
Set a value in a nested data structure.
Navigates to the specified path and sets the value. By default (create=False), raises PathError if any intermediate key is missing. With create=True, automatically creates missing intermediate containers (dicts for string keys, lists for numeric keys).
List indexing rules: - Positive indices can append (index == len(list)) but NOT create gaps (index > len(list)) - Negative indices can only modify existing elements - Out-of-bounds negative indices raise PathError - Index cannot exceed MAX_LIST_SIZE (10000)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data |
Any
|
The mutable data structure to modify (dict or list). The root container must already exist and be mutable. |
required |
path |
Union[str, List[Any]]
|
Path where to set the value. Accepts either a dot-separated string (e.g., "a.b.0.name") or a list of keys/indices (e.g., ["a", "b", 0, "name"]). |
required |
value |
Any
|
The value to set at the specified path. |
required |
create |
bool
|
If True, automatically create missing intermediate containers. If False (default), raise PathError if path doesn't exist. |
False
|
Returns:
| Type | Description |
|---|---|
None
|
None. The function modifies |
Raises:
| Type | Description |
|---|---|
PathError
|
If path is malformed, path doesn't exist (when create=False), attempts to modify tuple, uses out-of-bounds negative index, or would create sparse list. |
Examples:
# create=False (default) - path must exist
data = {"user": {"profile": {}}}
set_at(data, "user.profile.name", "Alice") # OK - path exists
# data is now: {'user': {'profile': {'name': 'Alice'}}}
data = {}
set_at(data, "user.name", "Bob") # PathError - path doesn't exist
# create=True - auto-create missing parts
data = {}
set_at(data, "user.profile.name", "Alice", create=True)
# data is now: {'user': {'profile': {'name': 'Alice'}}}
# List operations - sequential only (no gaps)
data = {}
set_at(data, "items.0", "first", create=True) # OK - creates list
# data is now: {'items': ['first']}
set_at(data, "items.1", "second", create=True) # OK - appends
# data is now: {'items': ['first', 'second']}
set_at(data, "items.5", "x", create=True) # PathError - would create gap
# Negative indices - modify existing only
data = {"items": [1, 2, 3]}
set_at(data, "items.-1", 99) # OK - modifies last element
# data is now: {'items': [1, 2, 99]}
set_at(data, "items.-5", 0) # PathError - out of bounds
# Modifying existing nested structures
data = {"a": [{"x": 1}]}
set_at(data, "a.0.y", 2, create=True) # Adds key to existing dict
# data is now: {'a': [{'x': 1, 'y': 2}]}
delete_at ¶
delete_at(data: Any, path: Union[str, List[Any]], *, allow_list_mutation: bool = False) -> Any
Delete a value from a nested data structure and return it.
Removes the item at the specified path. For dictionaries, the key-value pair is removed. For lists, deletion is disabled by default to prevent accidental index shifting that could break subsequent code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data |
Any
|
The mutable data structure to modify (dict or list). |
required |
path |
Union[str, List[Any]]
|
Path to the value to delete. Accepts either a dot-separated string (e.g., "a.b.0") or a list of keys/indices (e.g., ["a", "b", 0]). |
required |
allow_list_mutation |
bool
|
If True, allows deletion from lists using |
False
|
Returns:
| Type | Description |
|---|---|
Any
|
The deleted value. |
Raises:
| Type | Description |
|---|---|
PathError
|
If the path does not exist, is malformed, attempts deletion from a tuple,
attempts list deletion without |
Examples:
data = {"a": {"b": 1, "c": 2}}
delete_at(data, "a.b") # Returns: 1
# data is now: {'a': {'c': 2}}
data = {"items": [1, 2, 3]}
delete_at(data, "items.1", allow_list_mutation=True) # Returns: 2
# data is now: {'items': [1, 3]}
delete_at(data, "items.-1", allow_list_mutation=True) # Returns: 3
# data is now: {'items': [1]}
# Without allow_list_mutation=True, list deletion raises PathError
delete_at(data, "items.0") # Raises: PathError: List deletion disabled...
exists_at ¶
exists_at(data: Any, path: Union[str, List[Any]]) -> bool
Check if a path exists in a nested data structure.
Navigates through nested dictionaries, lists, and tuples. Returns True if the full path exists and is accessible, False otherwise (including out-of-bounds indices). Supports negative indexing for lists and tuples.
This function never raises PathError for missing paths - it returns False instead. PathError is only raised for malformed paths.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data |
Any
|
The data structure to navigate (dict, list, tuple, or nested combinations). |
required |
path |
Union[str, List[Any]]
|
Path to check. Accepts either a dot-separated string (e.g., "a.b.0.name") or a list of keys/indices (e.g., ["a", "b", 0, "name"]). |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the path exists and is accessible, False otherwise. |
Raises:
| Type | Description |
|---|---|
PathError
|
Only if the path format is invalid (empty, malformed, exceeds max depth). |
Examples:
data = {"a": {"b": {"c": 5}}}
exists_at(data, "a.b.c") # Returns: True
exists_at(data, "a.b.d") # Returns: False
data = {"items": [{"name": "apple"}, {"name": "banana"}]}
exists_at(data, "items.1.name") # Returns: True
exists_at(data, "items.-1.name") # Returns: True
exists_at(data, "items.-5.name") # Returns: False
exists_at(data, "items.10.name") # Returns: False
data = (10, 20, 30)
exists_at(data, "2") # Returns: True
exists_at(data, "5") # Returns: False
# Even None values return True if path exists
data = {"a": {"b": None}}
exists_at(data, "a.b") # Returns: True
exists_at(data, "a.b.c") # Returns: False (can't navigate into None)
nestedutils.introspection ¶
Introspection utilities for nested data structures.
This module provides functions to inspect and analyze nested data structures without modifying them. All functions are pure and support dict, list, and tuple. Other container types (set, frozenset, deque, etc.) are treated as leaf values.
get_depth ¶
get_depth(data: Any) -> int
Return the maximum nesting depth of a nested structure.
Supports dict, list, and tuple. Other types are treated as leaves (depth 0).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data |
Any
|
Any nested structure (dict, list, tuple, or primitive). |
required |
Returns:
| Type | Description |
|---|---|
int
|
Integer depth. Primitives return 0, empty containers return 1. |
Examples:
>>> get_depth(42)
0
>>> get_depth({})
1
>>> get_depth({"a": 1})
1
>>> get_depth({"a": {"b": 1}})
2
>>> get_depth({"a": {"b": {"c": 1}}})
3
>>> get_depth([1, [2, [3]]])
3
count_leaves ¶
count_leaves(data: Any) -> int
Count the total number of leaf values in a nested structure.
A leaf is any value that is not a dict, list, or tuple. Empty containers count as 0 leaves.
Supports dict, list, and tuple. Other container types (set, frozenset, etc.) are treated as single leaf values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data |
Any
|
Any nested structure. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Integer count of leaf values. |
Examples:
>>> count_leaves(42)
1
>>> count_leaves({})
0
>>> count_leaves({"a": 1, "b": 2})
2
>>> count_leaves({"a": {"b": 1, "c": 2}, "d": 3})
3
>>> count_leaves([1, 2, [3, 4]])
4
get_all_paths ¶
get_all_paths(data: Any) -> List[List[Union[str, int]]]
Return all paths to leaf values in a nested structure.
Supports dict, list, and tuple. Other container types are treated as leaves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data |
Any
|
Any nested structure. |
required |
Returns:
| Type | Description |
|---|---|
List[List[Union[str, int]]]
|
List of paths, where each path is a list of keys/indices. |
Examples:
>>> get_all_paths({"a": 1, "b": 2})
[["a"], ["b"]]
>>> get_all_paths({"a": {"b": 1, "c": 2}})
[["a", "b"], ["a", "c"]]
>>> get_all_paths({"users": [{"name": "Alice"}, {"name": "Bob"}]})
[["users", 0, "name"], ["users", 1, "name"]]
>>> get_all_paths({})
[]
>>> get_all_paths(42)
[[]]
nestedutils.constants ¶
Constants for nestedutils library.
nestedutils.enums ¶
Enumerations for nestedutils library.
This module defines error codes used throughout the nestedutils library for consistent error handling.
PathErrorCode ¶
Bases: Enum
Error codes for path-related exceptions.
Example
from nestedutils import get_at, PathError, PathErrorCode
data = {"a": {"b": 1}}
try:
result = get_at(data, "a.c.d")
# get_at raises PathError for missing paths in v2.0
except PathError as e:
if e.code == PathErrorCode.MISSING_KEY:
print("Key not found")
INVALID_INDEX
class-attribute
instance-attribute
¶
INVALID_INDEX = 'INVALID_INDEX'
Raised when a list index is invalid (non-numeric, out of bounds, or would create sparse list).
MISSING_KEY
class-attribute
instance-attribute
¶
MISSING_KEY = 'MISSING_KEY'
Raised when a required key doesn't exist (in set_at with create=False or delete_at).
EMPTY_PATH
class-attribute
instance-attribute
¶
EMPTY_PATH = 'EMPTY_PATH'
Raised when path is empty or contains empty keys.
IMMUTABLE_CONTAINER
class-attribute
instance-attribute
¶
IMMUTABLE_CONTAINER = 'IMMUTABLE_CONTAINER'
Raised when attempting to modify an immutable container (tuple).
INVALID_PATH
class-attribute
instance-attribute
¶
INVALID_PATH = 'INVALID_PATH'
Raised when path format is invalid (wrong type, exceeds max depth, etc.).
NON_NAVIGABLE_TYPE
class-attribute
instance-attribute
¶
NON_NAVIGABLE_TYPE = 'NON_NAVIGABLE_TYPE'
Raised when attempting to navigate into a non-container type (e.g., None, int, str).
OPERATION_DISABLED
class-attribute
instance-attribute
¶
OPERATION_DISABLED = 'OPERATION_DISABLED'
Raised when an operation is disabled by configuration (e.g., list mutation without allow_list_mutation=True).
nestedutils.exceptions ¶
Custom exceptions for the nestedutils library.
This module defines all custom exceptions used throughout the nestedutils library. The main exception class is PathError, which includes error codes for detailed error handling.
PathError ¶
PathError(message: str, code: Optional[PathErrorCode] = None)
Bases: Exception
Raised when a nested path cannot be navigated or modified.
Attributes:
| Name | Type | Description |
|---|---|---|
message |
Human-readable error message. |
|
code |
Optional PathErrorCode for programmatic error handling. |
Example
from nestedutils import set_at, PathError, PathErrorCode
data = {"a": {"b": 1}}
# set_at raises when path doesn't exist (create=False is default)
try:
set_at(data, "a.c.d", "value")
except PathError as e:
if e.code == PathErrorCode.MISSING_KEY:
print(f"Path doesn't exist: {e.message}")
# get_at raises for missing paths in v2.0 - use default= for optional values
from nestedutils import get_at
result = get_at(data, "a.c.d", default="not found")
print(result) # "not found"