SimplifiedObject

Overview

SimplifiedObject is a lightweight Python object that provides safe attribute-style (dot) access to nested data. You can create it directly with its constructor or by loading JSON using loads_simplified() or load_simplified().

Missing attributes never raise errors—they return the special Undefined object for safe, error-free deep access.

How to Create

You can create a SimplifiedObject in two ways:

1. Directly from Python data:

from jsify.simplify import SimplifiedObject, Undefined

obj = SimplifiedObject(a=1, b=2, c={'x': 5})

print(obj.a)         # 1
print(obj.c['x'])    # 5 (if c is a dict)
print(obj.missing)   # Undefined

Note: When created directly, nested dicts like c remain plain dicts and are not automatically converted to SimplifiedObject instances. Use loads_simplified() or load_simplified() for recursive conversion.

2. By parsing JSON (auto-recursive conversion):

from jsify.simplify import loads_simplified

s = '{"user": {"profile": {}, "age": 25}}'  # Changed null to empty dict
obj = loads_simplified(s)

print(obj.user.age)          # 25
print(obj.user.profile)      # SimplifiedObject({})
print(obj.user.profile.foo)  # Undefined

# All nested dicts become SimplifiedObject for full dot-access!

Deep Attribute Access and Undefined

Any missing attribute at any depth returns the special Undefined object:

name = obj.user.profile.name
if name is Undefined:
    print("Name is not available")

# Deep chaining is always safe:
print(obj.x.y.z)  # Always returns Undefined

Falsy and Comparison Behavior

  • Undefined is falsy in boolean context.

  • It compares as equal to None, but is not identical to None.

if not obj.some.missing.attribute:
    print("Not present or falsy")

assert obj.unknown is Undefined
assert obj.unknown == None
assert obj.unknown is not None

Serialization

Serialize SimplifiedObject instances to JSON using simplified_dumps() or simplified_dump():

from jsify.simplify import simplified_dumps, simplified_dump

d = SimplifiedObject(a=1, b=None, c=Undefined)
print(simplified_dumps(d))
# Outputs: {"a": 1, "b": null, "c": null}

# Undefined attributes serialize as null.

# To dump to a file:

import io
f = io.StringIO()
simplified_dump(d, f)  # Correct argument order: object, file
f.seek(0)
print(f.read())

Working with Nested Structures and Recursive Dot Access

Nested dicts stay as dicts unless you wrap them. For recursive dot access at every depth, you have two main options:

  • Manually nest SimplifiedObjects:

    inner = SimplifiedObject(x=5)
    outer = SimplifiedObject(a=1, b=inner)
    print(outer.b.x)  # 5
    

    If you want lists of dot-access objects:

    obj = SimplifiedObject(items=[SimplifiedObject(x=1), SimplifiedObject(x=2)])
    print(obj.items[0].x)  # 1
    
  • Auto-recursive dot access:

    For automatic recursive wrapping of all nested dicts and lists, use the Jsify Object system:

    from jsify.cjsify import jsify
    
    obj = jsify({'user': {'name': 'Alice', 'age': 30}})
    print(obj.user.name)  # Alice
    

Manual Construction Tips

  • You can pass any keyword arguments; they become attributes.

  • You can assign new attributes after creation, but nested dicts remain plain dicts unless wrapped.

obj = SimplifiedObject(foo={'bar': 123})
print(obj.foo['bar'])  # 123
# But obj.foo is a dict, not a SimplifiedObject, unless you wrap it manually

Limitations and Gotchas

  • Direct constructor use: Only the top level is a SimplifiedObject—nested dicts remain plain dicts unless you wrap them yourself.

  • Using ``loads_simplified`` or ``load_simplified``: The entire nested structure is recursively converted—all dicts become SimplifiedObject, so you always have dot-access at every level.

  • No item access on top-level: SimplifiedObject inherits from SimpleNamespace, which does not support item access (obj[‘key’]) at the top level. Use attribute access (obj.key) instead. If you need dictionary-like access, convert to dict with obj.__dict__ or use loads_simplified and work with the original JSON dicts.

  • Undefined is not None: Treat Undefined as a special “missing” value. It is falsy and compares equal to None, but it is a distinct singleton and not identical to None.

  • Importing Undefined: Remember to import Undefined explicitly from jsify.simplify when you want to compare or check for missing values.

See Also

  • Jsify Objects — For fully automatic, deep, recursive dot access, mutation support, and C-extension speed.


SimplifiedObject is ideal for quick, simple, error-free dot-access to shallow or partially known data—either from JSON or built manually.