Update changelog with pickle improvement; update Attribute docs

This commit is contained in:
Griatch 2022-06-01 22:08:37 +02:00
parent 825d5d49e7
commit d9cd9e59f3
2 changed files with 142 additions and 95 deletions

View file

@ -162,6 +162,8 @@ Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10
way to override features on all ObjectDB-inheriting objects easily.
- Add `TagProperty`, `AliasProperty` and `PermissionProperty` to assign these
data in a similar way to django fields.
- The db pickle-serializer now checks for methods `__serialize_dbobjs__` and `__deserialize_dbobjs__`
to allow custom packing/unpacking of nested dbobjs, to allow storing in Attribute.
## Evennia 0.9.5

View file

@ -328,13 +328,13 @@ values into a string representation before storing it to the database. This is d
With a single object, we mean anything that is *not iterable*, like numbers, strings or custom class
instances without the `__iter__` method.
* You can generally store any non-iterable Python entity that can be pickled.
* You can generally store any non-iterable Python entity that can be _pickled_.
* Single database objects/typeclasses can be stored, despite them normally not being possible
to pickle. Evennia wil convert them to an internal representation using their classname,
to pickle. Evennia will convert them to an internal representation using theihr classname,
database-id and creation-date with a microsecond precision. When retrieving, the object
instance will be re-fetched from the database using this information.
* To convert the database object, Evennia must know it's there. If you *hide* a database object
inside a non-iterable class, you will run into errors - this is not supported!
* If you 'hide' a db-obj as a property on a custom class, Evennia will not be
able to find it to serialize it. For that you need to help it out (see below).
```{code-block} python
:caption: Valid assignments
@ -345,16 +345,55 @@ obj.db.test1 = False
# a database object (will be stored as an internal representation)
obj.db.test2 = myobj
```
As mentioned, Evennia will not be able to automatically serialize db-objects
'hidden' in arbitrary properties on an object. This will lead to an error
when saving the Attribute.
```{code-block} python
:caption: Invalid, 'hidden' dbobject
# example of an invalid, "hidden" dbobject
# example of storing an invalid, "hidden" dbobject in Attribute
class Container:
def __init__(self, mydbobj):
# no way for Evennia to know this is a database object!
self.mydbobj = mydbobj
# let's assume myobj is a db-object
container = Container(myobj)
obj.db.invalid = container # will cause error!
obj.db.mydata = container # will raise error!
```
By adding two methods `__serialize_dbobjs__` and `__deserialize_dbobjs__` to the
object you want to save, you can pre-serialize and post-deserialize all 'hidden'
objects before Evennia's main serializer gets to work. Inside these methods, use Evennia's
[evennia.utils.dbserialize.dbserialize](api:evennia.utils.dbserialize.dbserialize) and
[dbunserialize](api:evennia.utils.dbserialize.dbunserialize) functions to safely
serialize the db-objects you want to store.
```{code-block} python
:caption: Fixing an invalid 'hidden' dbobj for storing in Attribute
from evennia.utils import dbserialize # important
class Container:
def __init__(self, mydbobj):
# A 'hidden' db-object
self.mydbobj = mydbobj
def __serialize_dbobjs__(self):
"""This is called before serialization and allows
us to custom-handle those 'hidden' dbobjs"""
self.mydbobj = dbserialize.dbserialize(self.mydbobj
def __deserialize_dbobjs__(self):
"""This is called after deserialization and allows you to
restore the 'hidden' dbobjs you serialized before"""
self.mydbobj = dbserialize.dbunserialize(self.mydbobj)
# let's assume myobj is a db-object
container = Container(myobj)
obj.db.mydata = container # will now work fine!
```
### Storing multiple objects
@ -404,6 +443,12 @@ obj.db.test8[2]["test"] = 5
# test8 is now [4,2,{"test":5}]
```
Note that if make some advanced iterable object, and store an db-object on it in
a way such that it is _not_ returned by iterating over it, you have created a
'hidden' db-object. See [the previous section](#storing-single-objects) for how
to tell Evennia how to serialize such hidden objects safely.
### Retrieving Mutable objects
A side effect of the way Evennia stores Attributes is that *mutable* iterables (iterables that can