Migrating from 0.4.x to 0.5.x
apmodel 0.5.x introduces a significant rewrite of the library's core, migrating from Python's dataclasses to Pydantic. This change enhances type validation, serialization, and overall robustness. However, it introduces several breaking changes.
Key Changes
- Migration to Pydantic: All models now inherit from
pydantic.BaseModelinstead of beingdataclasses. This provides automatic type validation and more powerful data handling. - Serialization Method: The
dump()function and.to_json()methods have been removed. Use the newapmodel.to_dict()function for serializing models to JSON-LD dictionaries. _extraField Renamed: The field for storing unknown properties has been renamed from_extratomodel_extra. You can access it viamodel.model_extra.UndefinedClass Removed: TheUndefinedclass has been removed. Optional fields that are not present will now beNone.LDContext.jsonProperty Removed: The.jsonproperty onLDContextinstances is removed. Use the.definitionsproperty to access the context dictionary directly.- Key Management: Key handling in
CryptographicKeyandMultikeyhas been improved. Key fields are now automatically serialized and deserialized from/to their respective string/object formats.
Migration Guide
1. Model Serialization
The global dump() function and the .to_json() method on models are no longer available. Use the new apmodel.to_dict() function.
Before (v0.4.x):
import apmodel
from apmodel.vocab import Note
note = Note(content="Hello")
json_dict = note.to_json()
# or
json_string = apmodel.dump(note)
After (v0.5.x):
import apmodel
from apmodel.vocab import Note
note = Note(content="Hello")
json_dict = apmodel.to_dict(note)
2. Accessing Extra/Unknown Properties
If you relied on accessing properties not defined in the model, you need to update the field name from _extra to model_extra.
Before (v0.4.x):
data = {"type": "Note", "content": "A note", "myCustomField": 123}
note = apmodel.load(data)
custom_value = note._extra["myCustomField"]
After (v0.5.x):
data = {"type": "Note", "content": "A note", "myCustomField": 123}
note = apmodel.load(data)
# Pydantic's `extra` is accessed via `model_extra`
custom_value = note.model_extra["myCustomField"]
3. Checking for Optional Fields
Fields that were previously Undefined will now be None if they are not provided. Update your checks accordingly.
Before (v0.4.x):
from apmodel.types import Undefined
if note.summary is not Undefined:
# ...
After (v0.5.x):
if note.summary is not None:
# ...
4. LDContext Usage
The .json property for accessing the dictionary part of a context is removed. Use .definitions.
Before (v0.4.x):
from apmodel import LDContext
ctx = LDContext([{"myTerm": "http://example.com/term"}])
defs = ctx.json # -> {"myTerm": "http://example.com/term"}
After (v0.5.x):
from apmodel.context import LDContext
ctx = LDContext([{"myTerm": "http://example.com/term"}])
defs = ctx.definitions # -> {"myTerm": "http://example.com/term"}
5. Renaming variables
In apmodel 0.5.x, the names of values used to access models have been changed from camel case to snake case. However, they are automatically converted back to camel case during loading and output.
Before (v0.4.x):
actor = apmodel.load(data)
public_key = actor.publicKey
Before (v0.5.x):
actor = apmodel.load(data)
public_key = actor.public_key
6. Access keys
Key access via CryptographicKey and Multikey has been improved.
Instead of accessing via the traditional publicKeyPem or publicKeyMultibase, you can access the public key by accessing the public_key of each model, allowing you to access the loaded public key as before.
Before (v0.4.x):
actor = apmodel.load(data)
crypto_key = actor.publicKey
public_key = crypto_key.publicKeyPem
Before (v0.5.x):
actor = apmodel.load(data)
crypto_key = actor.public_key
public_key = crypto_key.public_key