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 filterkeys_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 filterkeys_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 updateupdate(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
-
Clone the repository
-
Install dependencies:
uv sync
Running Tests
uv run pytest
Code Quality
uv run ruff check .
uv run ruff format .
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run the test suite
- 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)
| File | Size | Uploaded | |
|---|---|---|---|
| magiccionary-1.1.0.tar.gz | 8.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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}
|