Skip to main content

Add dot notation to Python dicts.

Project description

dotdict3

A lightweight Python package for accessing dictionary keys and list elements using dot notation with automatic recursive conversion of nested structures.

Installation

pip install dotdict3
>>> from dotdict3 import DotDict
>>> d = DotDict({"a": "b"})
>>> d.a
'b'

Features

  • Dot notation access: Access dictionary keys as attributes (data.key instead of data['key'])
  • Automatic conversion: Nested dictionaries and iterables are automatically converted to DotDict and DotList
  • Recursive processing: Works seamlessly with deeply nested structures
  • Standard compatibility: Fully compatible with built-in dict and list operations

Quick Start

from dotdict3 import DotDict

data = DotDict({
    'name': 'John',
    'age': 30,
    'address': {
        'city': 'New York',
        'zipcode': '10001'
    }
})

# Access with dot notation
print(data.name)              # 'John'
print(data.address.city)      # 'New York'

# Still works with bracket notation
print(data['age'])            # 30

Classes

DotDict

A dictionary subclass that allows attribute-style access to keys.

Features

  • Attribute access: Get, set, and delete keys using dot notation
  • Automatic nesting: Nested dictionaries are automatically converted to DotDict
  • Iterable conversion: Lists, tuples, sets, and ranges are converted to DotList
  • Dict compatibility: All standard dict methods work as expected

Usage

from dotdict3 import DotDict

# Basic usage
user = DotDict({'name': 'Alice', 'role': 'admin'})
print(user.name)  # 'Alice'

# Setting values
user.email = 'alice@example.com'
print(user.email)  # 'alice@example.com'

# Nested dictionaries
config = DotDict({
    'database': {
        'host': 'localhost',
        'port': 5432
    }
})
print(config.database.host)  # 'localhost'

# Deleting keys
del user.role

DotList

A list subclass that automatically converts nested dictionaries and iterables.

Features

  • Automatic conversion: Dictionaries in the list become DotDict instances
  • Nested iterables: Lists, tuples, sets, and ranges become DotList instances
  • List compatibility: All standard list methods work as expected

Usage

from dotdict3 import DotList

# Basic usage
items = DotList([1, 2, 3])
print(items[0])  # 1

# Lists with dictionaries
users = DotList([
    {'name': 'Alice', 'age': 30},
    {'name': 'Bob', 'age': 25}
])
print(users[0].name)  # 'Alice'

# Nested lists
matrix = DotList([[1, 2], [3, 4]])
print(matrix[0][1])  # 2

# Appending
users.append({'name': 'Charlie', 'age': 35})
print(users[2].name)  # 'Charlie'

Advanced Usage

Complex Nested Structures

from dotdict3 import DotDict

data = DotDict({
    'users': [
        {
            'name': 'Alice',
            'scores': [95, 87, 92],
            'metadata': {
                'joined': '2024-01-01',
                'tags': ['admin', 'active']
            }
        },
        {
            'name': 'Bob',
            'scores': [88, 90, 85],
            'metadata': {
                'joined': '2024-02-15',
                'tags': ['user']
            }
        }
    ],
    'settings': {
        'theme': 'dark',
        'notifications': True
    }
})

# Access deeply nested data
print(data.users[0].name)                    # 'Alice'
print(data.users[0].scores[1])               # 87
print(data.users[0].metadata.tags[0])        # 'admin'
print(data.settings.theme)                   # 'dark'

Working with JSON

Perfect for working with JSON data:

import json
from dotdict3 import DotDict

# Load JSON
with open('config.json') as f:
    config = DotDict(json.load(f))

# Access nested configuration
db_host = config.database.host
api_key = config.api.credentials.key

Dynamic Updates

from dotdict3 import DotDict

data = DotDict({})

# Add nested structure dynamically
data['user'] = {
    'profile': {
        'name': 'Alice',
        'preferences': ['email', 'sms']
    }
}

# Automatically converted
print(data.user.profile.name)                # 'Alice'
print(data.user.profile.preferences[0])      # 'email'

Important Notes

Reserved Names

Be careful with dictionary method names. Since DotDict inherits from dict, built-in method names will shadow your keys:

data = DotDict({'items': [1, 2, 3]})

# This returns the dict.items() method, not your data!
print(data.items)  # <built-in method items>

# Use bracket notation instead
print(data['items'])  # DotList([1, 2, 3])

Common reserved names to avoid:

  • clear
  • copy
  • get
  • items
  • keys
  • pop
  • setdefault
  • update
  • values

Type Checking

The classes include automatic type checking to prevent double conversion:

from dotdict3 import DotDict

inner = DotDict({'a': 1})
outer = DotDict({'inner': inner})

# inner is not converted again
assert outer['inner'] is inner  # True

Iterable Conversion

All iterables (except strings and bytes) are converted to DotList:

data = DotDict({
    'list': [1, 2, 3],
    'tuple': (4, 5, 6),
    'set': {7, 8, 9},
    'range': range(10, 13)
})

# All become DotList
assert isinstance(data['list'], DotList)   # True
assert isinstance(data['tuple'], DotList)  # True
assert isinstance(data['set'], DotList)    # True
assert isinstance(data['range'], DotList)  # True

Compatibility

  • Python 3.6+
  • Compatible with all standard dict and list operations

Use Cases

  • Configuration management: Easy access to nested config files
  • API responses: Simplify working with JSON API responses
  • Data processing: Cleaner code when working with nested data structures
  • Settings objects: Create intuitive settings/options objects

Limitations

  • String keys only (dictionary keys must be valid Python identifiers for dot notation)
  • Watch out for reserved dictionary/list method names
  • Dot notation won't work for keys with spaces or special characters

License

MIT License

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Examples

Example 1: Configuration File

from dotdict3 import DotDict
import yaml

with open('config.yaml') as f:
    config = DotDict(yaml.safe_load(f))

# Easy access to nested config
database_url = f"{config.database.host}:{config.database.port}"
log_level = config.logging.level

Example 2: API Response

from dotdict3 import DotDict
import requests

response = requests.get('https://api.example.com/users/1')
user = DotDict(response.json())

print(f"{user.name} - {user.email}")
print(f"City: {user.address.city}")

Example 3: Test Data

from dotdict3 import DotDict

test_data = DotDict({
    'scenarios': [
        {'name': 'happy_path', 'expected': 200},
        {'name': 'not_found', 'expected': 404},
        {'name': 'server_error', 'expected': 500}
    ]
})

for scenario in test_data.scenarios:
    assert response.status_code == scenario.expected

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dotdict3-1.4.1.tar.gz (6.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dotdict3-1.4.1-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

Details for the file dotdict3-1.4.1.tar.gz.

File metadata

  • Download URL: dotdict3-1.4.1.tar.gz
  • Upload date:
  • Size: 6.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","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}

File hashes

Hashes for dotdict3-1.4.1.tar.gz
Algorithm Hash digest
SHA256 4ff249808188d3a71ffcac3cb146267cf1492384c6e9e81d0999402520af7804
MD5 b706f45259d29eb7a60c2e6e8ec63cf0
BLAKE2b-256 b4b87af7881a2f26d4e18502642e055d4ee3a14c780cf2a8e0b6ab1edc7a1ab3

See more details on using hashes here.

File details

Details for the file dotdict3-1.4.1-py3-none-any.whl.

File metadata

  • Download URL: dotdict3-1.4.1-py3-none-any.whl
  • Upload date:
  • Size: 5.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","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}

File hashes

Hashes for dotdict3-1.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2ed15121532422d20317c1512e177ac13daf74cec15cf04b80cef1f3e6ce8821
MD5 3b27da54641fbd66c40e0a4f8cae98cd
BLAKE2b-256 5ba0a12af68e4b9eaa6be004112e2658d5f767adb33ea594a842189cc283621c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page