CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-dpath

Filesystem-like pathing and searching for dictionaries

Pending
Overview
Eval results
Files

search-operations.mddocs/

Search Operations

Powerful search capabilities for finding paths and values matching glob patterns in nested dictionaries. These operations support filtering, yielding, and flexible result formats for different use cases.

Capabilities

Dictionary Search

Search dictionaries for paths matching glob patterns, returning structured results that preserve the original data hierarchy.

def search(obj, glob, yielded=False, separator="/", afilter=None, dirs=True):
    """
    Search for paths/values matching glob pattern.
    
    Parameters:
    - obj (MutableMapping): Target dictionary to search
    - glob (Glob): Path pattern as string or sequence
    - yielded (bool): If True, return generator of (path, value) tuples instead of dict
    - separator (str): Path separator character (default "/")
    - afilter (Filter): Optional function to filter results by value
    - dirs (bool): Include non-leaf (directory-like) nodes in results (default True)
    
    Returns:
    dict or generator: Dictionary preserving structure, or generator of (path_str, value) tuples if yielded=True
    """

Usage Examples

import dpath

data = {
    "users": {
        "john": {"age": 30, "city": "NYC", "hobbies": ["reading", "gaming"]},
        "jane": {"age": 25, "city": "LA", "hobbies": ["hiking", "cooking"]},
        "bob": {"age": 35, "city": "Chicago"}
    },
    "settings": {"theme": "dark", "lang": "en"}
}

# Search with wildcard - returns structured dict
cities = dpath.search(data, "users/*/city")
# Returns: {'users': {'john': {'city': 'NYC'}, 'jane': {'city': 'LA'}, 'bob': {'city': 'Chicago'}}}

# Search with yielded=True - returns generator of (path, value) pairs
for path, value in dpath.search(data, "users/*/city", yielded=True):
    print(f"{path}: {value}")
# Output:
# users/john/city: NYC
# users/jane/city: LA  
# users/bob/city: Chicago

# Recursive search with **
all_values = dpath.search(data, "**/age")
# Returns all age values regardless of depth

# Search excluding directories (dirs=False) - only leaf values
leaves_only = dpath.search(data, "users/**", dirs=False)
# Excludes intermediate dict objects, only includes final values

# Filter search results
def young_filter(value):
    return isinstance(value, dict) and value.get("age", 0) < 30

young_users = dpath.search(data, "users/*", afilter=young_filter)
# Returns only jane's record

# Complex pattern matching
hobbies = dpath.search(data, "users/*/hobbies/*")  # All individual hobbies
first_hobbies = dpath.search(data, "users/*/hobbies/0")  # First hobby of each user

Value Extraction

Extract just the values that match glob patterns, returning a simple list rather than preserving the dictionary structure.

def values(obj, glob, separator="/", afilter=None, dirs=True):
    """
    Get list of all values matching glob pattern.
    
    Parameters:
    - obj (MutableMapping): Target dictionary to search  
    - glob (Glob): Path pattern as string or sequence
    - separator (str): Path separator character (default "/")
    - afilter (Filter): Optional function to filter results by value
    - dirs (bool): Include non-leaf (directory-like) nodes in results (default True)
    
    Returns:
    list: List of matching values in order found
    """

Usage Examples

import dpath

data = {
    "products": {
        "electronics": {
            "laptop": {"price": 1200, "stock": 5},
            "phone": {"price": 800, "stock": 12}
        },
        "books": {
            "python_guide": {"price": 45, "stock": 20},
            "data_science": {"price": 60, "stock": 8}
        }
    }
}

# Extract all prices as a simple list
prices = dpath.values(data, "products/*/*/price")
# Returns: [1200, 800, 45, 60]

# Extract with filtering
def expensive_filter(price):
    return isinstance(price, (int, float)) and price > 50

expensive_prices = dpath.values(data, "products/*/*/price", afilter=expensive_filter)  
# Returns: [1200, 800, 60]

# Extract all product info (directories included by default)
all_products = dpath.values(data, "products/*/*")
# Returns list of product dictionaries

# Extract only leaf values (dirs=False)
leaf_values = dpath.values(data, "products/**", dirs=False)
# Returns: [1200, 5, 800, 12, 45, 20, 60, 8] (all leaf values)

# Extract with custom separator
values_custom_sep = dpath.values(data, "products.*.price", separator=".")

Advanced Search Patterns

Glob Pattern Syntax

dpath supports rich glob patterns for flexible searching:

# Single-level wildcards
dpath.search(data, "users/*")          # All direct children of users
dpath.search(data, "users/*/age")      # Age field of all users

# Multi-level wildcards  
dpath.search(data, "users/**")         # Everything under users (recursive)
dpath.search(data, "**/age")           # All age fields at any depth

# Character classes and ranges
dpath.search(data, "users/[jb]*")      # Users starting with 'j' or 'b'
dpath.search(data, "item[0-9]")        # Items with single digit suffix

# Complex combinations
dpath.search(data, "*/settings/**/lang")  # Lang settings at any depth under any top-level key

Filtering Functions

Create sophisticated filters to narrow search results:

# Filter by value type
def string_filter(value):
    return isinstance(value, str)

strings = dpath.values(data, "**", afilter=string_filter)

# Filter by value content
def contains_email(value):
    return isinstance(value, str) and "@" in value

emails = dpath.values(data, "**", afilter=contains_email)

# Filter by dictionary structure
def has_required_fields(value):
    if not isinstance(value, dict):
        return False
    return all(field in value for field in ["name", "age", "email"])

valid_users = dpath.search(data, "users/*", afilter=has_required_fields)

# Combine filters
def active_adult_filter(user):
    return (isinstance(user, dict) and 
            user.get("active", False) and 
            user.get("age", 0) >= 18)

Working with Generators

When using yielded=True, work efficiently with large datasets:

# Process results incrementally
def process_large_dataset(data):
    for path, value in dpath.search(data, "records/**", yielded=True):
        # Process one item at a time without loading everything into memory
        if meets_criteria(value):
            yield transform(value)

# Early termination
def find_first_match(data, pattern, condition):
    for path, value in dpath.search(data, pattern, yielded=True):
        if condition(value):
            return path, value
    return None, None

# Collect specific information
paths_and_types = [(path, type(value).__name__) 
                   for path, value in dpath.search(data, "**", yielded=True)]

Integration with Other Operations

Search operations integrate seamlessly with other dpath functions:

# Find then modify
matching_paths = [path for path, _ in dpath.search(data, "users/*/active", yielded=True)]
for path in matching_paths:
    dpath.set(data, path, False)

# Search and extract for processing
user_ages = dpath.values(data, "users/*/age")
average_age = sum(user_ages) / len(user_ages)

# Complex workflows
active_users = dpath.search(data, "users/*", afilter=lambda u: u.get("active"))
for user_path, user_data in dpath.search(active_users, "**", yielded=True):
    # Process each active user
    pass

Install with Tessl CLI

npx tessl i tessl/pypi-dpath

docs

advanced-operations.md

data-manipulation.md

index.md

path-access.md

search-operations.md

tile.json