Skip to main content

Magiccionary

A Python library for powerful dictionary and list manipulation with support for nested structures, wildcards, and complex path expressions.

Features

  • Remove keys from nested dictionaries and lists using dot notation or path arrays
  • Keep specific keys while removing everything else
  • Wildcard support (*) for operating on all dictionary keys
  • List traversal ([]) for operating on all list items
  • Nested updates for merging dictionary structures
  • Empty key removal for cleaning up data structures

Installation

pip install magiccionary

Or using uv:

uv add magiccionary

Quick Start

from magiccionary import remove_keys, keep_keys

# Sample data
data = {
    "user": {
        "profile": {
            "name": "John",
            "email": "john@example.com",
            "settings": {
                "theme": "dark",
                "notifications": True
            }
        },
        "posts": [
            {"title": "Post 1", "content": "Hello", "draft": True},
            {"title": "Post 2", "content": "World", "draft": False}
        ]
    }
}

# Remove specific keys
cleaned = remove_keys(data, [
    "user.profile.email",
    ["user", "posts", "[]", "draft"]
])

# Keep only specific keys
filtered = keep_keys(data, [
    "user.profile.name",
    ["user", "posts", "[]", "title"]
])

API Reference

remove_keys(data, keys_to_remove, separator=".")

Removes specified keys from a nested dictionary/list structure.

Parameters:

  • data (dict/list): The data structure to filter
  • keys_to_remove (list): List of keys to remove (strings or path arrays)
  • separator (str): Separator for dot notation (default: ".")

Returns:

  • A new data structure with specified keys removed

Examples:

# Simple key removal
data = {"a": 1, "b": 2, "c": 3}
result = remove_keys(data, ["b", "c"])
# Result: {"a": 1}
# Original data unchanged: {"a": 1, "b": 2, "c": 3}

# Nested key removal
data = {"user": {"profile": {"name": "John", "email": "john@example.com"}}}
result = remove_keys(data, ["user.profile.email"])
# Result: {"user": {"profile": {"name": "John"}}}
# Original data unchanged

# Remove from all list items
data = {
    "posts": [
        {"title": "Post 1", "draft": True, "content": "Hello"},
        {"title": "Post 2", "draft": False, "content": "World"}
    ]
}
result = remove_keys(data, [["posts", "[]", "draft"]])
# Result: {"posts": [{"title": "Post 1", "content": "Hello"}, {"title": "Post 2", "content": "World"}]}
# Original data unchanged

# Wildcard removal (remove from all dictionary keys)
data = {
    "user1": {"name": "John", "email": "john@example.com"},
    "user2": {"name": "Jane", "email": "jane@example.com"}
}
result = remove_keys(data, [["*", "email"]])
# Result: {"user1": {"name": "John"}, "user2": {"name": "Jane"}}
# Original data unchanged

keep_keys(data, keys_to_keep, separator=".")

Keeps only specified keys from a nested dictionary/list structure.

Parameters:

  • data (dict/list): The data structure to filter
  • keys_to_keep (list): List of keys to keep (strings or path arrays)
  • separator (str): Separator for dot notation (default: ".")

Returns:

  • New data structure with only specified keys

Examples:

# Keep specific keys
data = {"a": 1, "b": 2, "c": 3}
result = keep_keys(data, ["a", "b"])
# Result: {"a": 1, "b": 2}

# Keep nested keys
data = {"user": {"profile": {"name": "John", "email": "john@example.com"}}}
result = keep_keys(data, ["user.profile.name"])
# Result: {"user": {"profile": {"name": "John"}}}

# Keep from all list items
data = {
    "posts": [
        {"title": "Post 1", "draft": True, "content": "Hello"},
        {"title": "Post 2", "draft": False, "content": "World"}
    ]
}
result = keep_keys(data, [["posts", "[]", "title"]])
# Result: {"posts": [{"title": "Post 1"}, {"title": "Post 2"}]}

# Wildcard keeping
data = {
    "user1": {"name": "John", "email": "john@example.com", "age": 30},
    "user2": {"name": "Jane", "email": "jane@example.com", "age": 25}
}
result = keep_keys(data, [["*", "name"]])
# Result: {"user1": {"name": "John"}, "user2": {"name": "Jane"}}

remove_empty_keys(data)

Removes keys with empty values (None, empty dicts, empty strings) from a nested structure.

Parameters:

  • data (dict): The dictionary to clean

Returns:

  • A new dictionary with empty keys removed

Examples:

data = {
    "name": "John",
    "email": None,
    "settings": {},
    "posts": [
        {"title": "Post 1", "content": ""},
        {"title": "Post 2", "content": "Hello"}
    ]
}
result = remove_empty_keys(data)
# Result: {
#     "name": "John",
#     "posts": [
#         {"title": "Post 1"},
#         {"title": "Post 2", "content": "Hello"}
#     ]
# }
# Original data unchanged

nested_update(original, update)

Updates a nested dictionary with another dictionary, merging nested structures.

Parameters:

  • original (dict): The original dictionary to update
  • update (dict): The dictionary with updates to apply

Returns:

  • A new dictionary with the merged data

Examples:

original = {"user": {"name": "John", "settings": {"theme": "light"}}}
update = {"user": {"email": "john@example.com", "settings": {"notifications": True}}}
result = nested_update(original, update)
# Result: {
#     "user": {
#         "name": "John",
#         "email": "john@example.com",
#         "settings": {"theme": "light", "notifications": True}
#     }
# }
# Original data unchanged

Path Syntax

Magiccionary supports two path formats:

1. Dot Notation (String)

Use dots to separate nested keys:

"user.profile.name"  # Access user -> profile -> name

2. Path Arrays (List)

Use arrays for more complex operations:

["user", "posts", "[]", "title"]  # Access user -> posts -> all items -> title

Special Tokens

  • "*" - Wildcard for all dictionary keys
  • "[]" - Wildcard for all list items

Complex Examples

# Remove 'draft' field from all posts in all users
data = {
    "users": [
        {
            "name": "John",
            "posts": [{"title": "Post 1", "draft": True}, {"title": "Post 2", "draft": False}]
        },
        {
            "name": "Jane", 
            "posts": [{"title": "Post 3", "draft": True}]
        }
    ]
}

# Remove draft field from all posts in all users
result = remove_keys(data, [["users", "[]", "posts", "[]", "draft"]])

# Keep only names and post titles
result = keep_keys(data, [
    ["users", "[]", "name"],
    ["users", "[]", "posts", "[]", "title"]
])

Advanced Usage

Working with API Responses

# Clean API response by removing unnecessary fields
api_response = {
    "data": {
        "users": [
            {
                "id": 1,
                "name": "John",
                "email": "john@example.com",
                "created_at": "2023-01-01",
                "updated_at": "2023-01-02",
                "internal_notes": "Some notes"
            }
        ]
    },
    "meta": {
        "pagination": {"page": 1, "total": 100},
        "debug_info": {"request_id": "abc123"}
    }
}

# Remove internal fields and keep only essential data
cleaned = remove_keys(api_response, [
    ["data", "users", "[]", "internal_notes"],
    ["data", "users", "[]", "created_at"],
    ["data", "users", "[]", "updated_at"],
    ["meta", "debug_info"]
])

# Or keep only specific fields
filtered = keep_keys(api_response, [
    ["data", "users", "[]", "name"],
    ["data", "users", "[]", "email"]
])

Data Transformation

# Transform complex nested data
complex_data = {
    "departments": {
        "engineering": {
            "employees": [
                {"name": "Alice", "role": "developer", "salary": 80000, "manager": "Bob"},
                {"name": "Charlie", "role": "designer", "salary": 75000, "manager": "Bob"}
            ]
        },
        "marketing": {
            "employees": [
                {"name": "Diana", "role": "manager", "salary": 90000, "manager": None}
            ]
        }
    }
}

# Create a flat list of employees with only name and role
employees = keep_keys(complex_data, [
    ["departments", "*", "employees", "[]", "name"],
    ["departments", "*", "employees", "[]", "role"]
])

# Remove salary information from all employees
result = remove_keys(complex_data, [
    ["departments", "*", "employees", "[]", "salary"]
])

Development

Setup

  1. Clone the repository

  2. Install dependencies:

    uv sync
    

Running Tests

uv run pytest

Code Quality

uv run ruff check .
uv run ruff format .

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality
  5. Run the test suite
  6. Submit a pull request

License

This project is licensed under the MIT License - see the license file for details.

Metadata

Release files for magiccionary 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for magiccionary 1.1.0
File Size Uploaded
magiccionary-1.1.0.tar.gz 8.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for magiccionary 1.1.0
File Interpreter ABI Platform
magiccionary-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 14.4 kB

Release files / magiccionary-1.1.0.tar.gz

Download URL magiccionary-1.1.0.tar.gz
Size 8.2 kB
Tags Source
SHA-256 checksum
How to use checksums
d107bd99bddcbd6647b4f2acdba7f2e1407ae6d6f862b70c095dd4c4e8fe063c
BLAKE2b-256 checksum
How to use checksums
4ea2ead780d0bbacca167e0bb2346ecf8c827bcc7758bfbbecb3151a681cd070
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / magiccionary-1.1.0-py3-none-any.whl

Download URL magiccionary-1.1.0-py3-none-any.whl
Size 6.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8eb17ff3362a4debf2fa783307b7b3202a9fddc242bc9d128be6202011f6f01f
BLAKE2b-256 checksum
How to use checksums
ee54788b0f1421ba68448929a312553aadc878ce88ca11c4e42b554ea0e42858
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page