CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-jsonargparse

Implement minimal boilerplate CLIs derived from type hints and parse from command line, config files and environment variables.

Pending
Overview
Eval results
Files

namespace-management.mddocs/

Namespace Management

Enhanced namespace objects and configuration management utilities that provide nested structure support, dictionary-like access patterns, serialization capabilities, and configuration manipulation tools. The Namespace class extends argparse.Namespace with advanced features for handling complex, hierarchical configurations.

Capabilities

Namespace Class

Extended namespace class that supports nested configuration structures with dictionary-like access patterns and comprehensive manipulation methods.

class Namespace:
    def __init__(self, *args, **kwargs):
        """
        Create a new namespace object.
        
        Args:
            *args: Positional arguments (dicts or namespaces to merge)
            **kwargs: Keyword arguments to set as attributes
        """
    
    def __getitem__(self, key: str) -> Any:
        """
        Get item using dictionary-style access with dot notation support.
        
        Args:
            key: Key to retrieve (supports dot notation like 'a.b.c')
            
        Returns:
            Any: Value at the specified key
            
        Raises:
            KeyError: If key is not found
        """
    
    def __setitem__(self, key: str, value: Any) -> None:
        """
        Set item using dictionary-style access with dot notation support.
        
        Args:
            key: Key to set (supports dot notation like 'a.b.c')
            value: Value to set
        """
    
    def __delitem__(self, key: str) -> None:
        """
        Delete item using dictionary-style access.
        
        Args:
            key: Key to delete (supports dot notation)
            
        Raises:
            KeyError: If key is not found
        """
    
    def __contains__(self, key: str) -> bool:
        """
        Check if key exists in namespace.
        
        Args:
            key: Key to check (supports dot notation)
            
        Returns:
            bool: True if key exists
        """
    
    def as_dict(self) -> Dict[str, Any]:
        """
        Convert namespace to nested dictionary.
        
        Returns:
            Dict[str, Any]: Dictionary representation of namespace
        """
    
    def as_flat(self) -> argparse.Namespace:
        """
        Convert to flat argparse.Namespace with dot-separated keys.
        
        Returns:
            argparse.Namespace: Flattened namespace
        """
    
    def items(self, branches: bool = False) -> Iterator[Tuple[str, Any]]:
        """
        Iterate over namespace items.
        
        Args:
            branches: Whether to include intermediate branch nodes
            
        Yields:
            Tuple[str, Any]: Key-value pairs
        """
    
    def keys(self, branches: bool = False) -> Iterator[str]:
        """
        Iterate over namespace keys.
        
        Args:
            branches: Whether to include intermediate branch keys
            
        Yields:
            str: Namespace keys
        """
    
    def values(self, branches: bool = False) -> Iterator[Any]:
        """
        Iterate over namespace values.
        
        Args:
            branches: Whether to include intermediate branch values
            
        Yields:
            Any: Namespace values
        """
    
    def get_sorted_keys(self, branches: bool = True) -> List[str]:
        """
        Get sorted list of all keys in namespace.
        
        Args:
            branches: Whether to include intermediate branch keys
            
        Returns:
            List[str]: Sorted list of keys
        """
    
    def clone(self) -> "Namespace":
        """
        Create a deep copy of the namespace.
        
        Returns:
            Namespace: Deep copy of this namespace
        """
    
    def update(self, value: Union["Namespace", Any], key: Optional[str] = None) -> "Namespace":
        """
        Update namespace with values from another namespace or dict.
        
        Args:
            value: Values to merge (Namespace, dict, or other object)
            key: Optional key to update specific nested location
            
        Returns:
            Namespace: Updated namespace (self)
        """
    
    def get(self, key: str, default: Any = None) -> Any:
        """
        Get value with default fallback.
        
        Args:
            key: Key to retrieve (supports dot notation)
            default: Default value if key not found
            
        Returns:
            Any: Value at key or default
        """
    
    def pop(self, key: str, default: Any = None) -> Any:
        """
        Remove and return value at key.
        
        Args:
            key: Key to remove (supports dot notation)
            default: Default value if key not found
            
        Returns:
            Any: Removed value or default
        """

Namespace Utilities

Utility functions for converting between namespaces and dictionaries, and for cleaning configuration objects.

def dict_to_namespace(obj: Dict[str, Any]) -> Namespace:
    """
    Convert nested dictionary to nested namespace.
    
    Args:
        obj: Dictionary to convert
        
    Returns:
        Namespace: Converted namespace object
    """

def strip_meta(cfg: Union[Namespace, Dict]) -> Union[Namespace, Dict]:
    """
    Remove all metadata keys from configuration object.
    
    Args:
        cfg: Configuration object (Namespace or dict)
        
    Returns:
        Union[Namespace, Dict]: Configuration with metadata removed
    """

Usage Examples

Basic Namespace Operations

from jsonargparse import Namespace

# Create namespace
config = Namespace()

# Set values using attribute access
config.model_name = "resnet50"
config.epochs = 100

# Set nested values using dot notation
config["training.learning_rate"] = 0.001
config["training.batch_size"] = 32
config["data.train_path"] = "/data/train"
config["data.val_path"] = "/data/val"

# Access values multiple ways
print(config.model_name)  # Attribute access
print(config["epochs"])   # Dictionary access
print(config["training.learning_rate"])  # Dot notation

# Check if keys exist
if "training.learning_rate" in config:
    print("Learning rate is set")

# Convert to dictionary
config_dict = config.as_dict()
print(config_dict)
# {
#   "model_name": "resnet50",
#   "epochs": 100,
#   "training": {"learning_rate": 0.001, "batch_size": 32},
#   "data": {"train_path": "/data/train", "val_path": "/data/val"}
# }

Nested Configuration Management

from jsonargparse import Namespace

# Create nested configuration
config = Namespace({
    "model": {
        "type": "cnn",
        "layers": 5,
        "activation": "relu"
    },
    "training": {
        "optimizer": "adam",
        "learning_rate": 0.001,
        "epochs": 100
    },
    "data": {
        "batch_size": 32,
        "shuffle": True
    }
})

# Access nested values
print(f"Model type: {config.model.type}")
print(f"Learning rate: {config['training.learning_rate']}")

# Update nested values
config.model.layers = 10
config["training.epochs"] = 200

# Add new nested section
config["logging.level"] = "INFO"
config["logging.file"] = "training.log"

print(config.logging.level)  # INFO
print(config.logging.file)   # training.log

Configuration Merging and Updates

from jsonargparse import Namespace

# Base configuration
base_config = Namespace({
    "model": {"type": "resnet", "layers": 18},
    "training": {"epochs": 100, "learning_rate": 0.001},
    "data": {"batch_size": 32}
})

# User overrides
user_config = Namespace({
    "model": {"layers": 50},  # Override layers
    "training": {"epochs": 200},  # Override epochs
    "evaluation": {"metrics": ["accuracy", "f1"]}  # Add new section
})

# Merge configurations
base_config.update(user_config)

print(base_config.as_dict())
# {
#   "model": {"type": "resnet", "layers": 50},
#   "training": {"epochs": 200, "learning_rate": 0.001},
#   "data": {"batch_size": 32},
#   "evaluation": {"metrics": ["accuracy", "f1"]}
# }

Namespace Iteration

from jsonargparse import Namespace

config = Namespace({
    "model": {"type": "cnn", "layers": 5},
    "training": {"epochs": 100, "lr": 0.001},
    "debug": True
})

# Iterate over all key-value pairs (leaf nodes only)
print("All configuration values:")
for key, value in config.items():
    print(f"  {key}: {value}")
# Output:
#   model.type: cnn
#   model.layers: 5
#   training.epochs: 100
#   training.lr: 0.001
#   debug: True

# Iterate including branch nodes
print("\nAll keys including branches:")
for key in config.keys(branches=True):
    print(f"  {key}")
# Output:
#   model
#   model.type
#   model.layers
#   training
#   training.epochs
#   training.lr
#   debug

# Get sorted keys
sorted_keys = config.get_sorted_keys(branches=False)
print(f"\nSorted leaf keys: {sorted_keys}")

Dictionary Conversion

from jsonargparse import Namespace, dict_to_namespace

# Convert dict to namespace
config_dict = {
    "database": {
        "host": "localhost",
        "port": 5432,
        "credentials": {
            "username": "user",
            "password": "pass"
        }
    },
    "cache": {
        "enabled": True,
        "ttl": 3600
    }
}

config = dict_to_namespace(config_dict)

# Access with dot notation
print(config.database.host)  # localhost
print(config["database.credentials.username"])  # user
print(config.cache.enabled)  # True

# Convert back to dict
result_dict = config.as_dict()
print(result_dict == config_dict)  # True

Namespace Cloning and Manipulation

from jsonargparse import Namespace

# Original configuration
original = Namespace({
    "model": {"type": "resnet", "layers": 18},
    "training": {"epochs": 100}
})

# Create independent copy
copy = original.clone()

# Modify copy without affecting original
copy.model.layers = 50
copy.training.epochs = 200
copy["new_section.value"] = "added"

print(f"Original layers: {original.model.layers}")  # 18
print(f"Copy layers: {copy.model.layers}")          # 50

# Use get() with defaults
batch_size = original.get("training.batch_size", 32)
print(f"Batch size: {batch_size}")  # 32 (default)

# Pop values
epochs = copy.pop("training.epochs", 100)
print(f"Popped epochs: {epochs}")  # 200
print(f"Epochs after pop: {copy.get('training.epochs', 'missing')}")  # missing

Configuration Cleaning

from jsonargparse import Namespace, strip_meta

# Configuration with metadata
config = Namespace({
    "model": {"type": "cnn", "layers": 5},
    "training": {"epochs": 100},
    "__metadata__": {"version": "1.0", "created": "2023-01-01"},
    "_internal_config": {"debug": True}
})

# Remove metadata keys
clean_config = strip_meta(config)

print("Original keys:", list(config.keys(branches=True)))
print("Clean keys:", list(clean_config.keys(branches=True)))

# Metadata keys starting with _ or __ are removed

Flat Namespace Conversion

from jsonargparse import Namespace

# Nested namespace
nested = Namespace({
    "model": {"type": "cnn", "layers": 5},
    "training": {"epochs": 100, "lr": 0.001}
})

# Convert to flat namespace with dot-separated keys
flat = nested.as_flat()

print(f"model.type: {flat.model.type}")        # AttributeError - no nesting
print(f"model.type: {getattr(flat, 'model.type')}")  # cnn
print(f"training.epochs: {getattr(flat, 'training.epochs')}")  # 100

# Useful for integrating with systems expecting flat namespaces

Advanced Namespace Usage

from jsonargparse import Namespace

# Complex nested configuration
config = Namespace()

# Build configuration programmatically
config["experiments.exp1.model.type"] = "resnet"
config["experiments.exp1.model.layers"] = 18
config["experiments.exp1.training.epochs"] = 100

config["experiments.exp2.model.type"] = "densenet"
config["experiments.exp2.model.layers"] = 121
config["experiments.exp2.training.epochs"] = 150

# Access experiments
for exp_name in ["exp1", "exp2"]:
    exp_config = config[f"experiments.{exp_name}"]
    print(f"{exp_name}: {exp_config.model.type}-{exp_config.model.layers}")
    print(f"  Epochs: {exp_config.training.epochs}")

# Delete entire experiment
del config["experiments.exp1"]

print("Remaining experiments:", list(config.experiments.keys()))

Install with Tessl CLI

npx tessl i tessl/pypi-jsonargparse

docs

advanced-actions.md

cli-creation.md

core-parser.md

index.md

namespace-management.md

settings.md

signature-arguments.md

types-validation.md

utilities.md

tile.json