Make to_dict dynamic

This commit is contained in:
Lonami Exo 2021-09-26 18:30:08 +02:00
parent 86c47a2771
commit e3b1dc2059
3 changed files with 27 additions and 38 deletions

View File

@ -330,6 +330,17 @@ want to define new attributes.
This also means that the updates from ``events.Raw`` **no longer have** ``update._entities``.
``tlobject.to_dict()`` has changed and is now generated dynamically based on the ``__slots__`.
This may incur a small performance hit (but you shouldn't really be using ``.to_dict()`` when
you can just use attribute access and ``getattr``). In general, this should handle ill-defined
objects more gracefully (for instance, those where you're using a ``tuple`` and not a ``list``
or using a list somewhere it shouldn't be), and have no other observable effects. As an extra
benefit, this slightly cuts down on the amount of bloat.
In ``tlobject.to_dict()``, the special ``_`` key is now also contains the module (so you can
actually distinguish between equally-named classes). If you want the old behaviour, use
``tlobject.__class__.__name__` instead (and add ``Request`` for functions).
// TODO this definitely generated files mapping from the original name to this new one...
// TODO what's the alternative to update._entities? and update._client??

View File

@ -171,7 +171,22 @@ class TLObject:
return TLObject.pretty_format(self, indent=0)
def to_dict(self):
raise NotImplementedError
res = {}
pre = ('', 'fn.')[isinstance(self, TLRequest)]
mod = self.__class__.__module__[self.__class__.__module__.rfind('.') + 1:]
if mod in ('_tl', 'fn'):
res['_'] = f'{pre}{self.__class__.__name__}'
else:
res['_'] = f'{pre}{mod}.{self.__class__.__name__}'
for slot in self.__slots__:
attr = getattr(self, slot)
if isinstance(attr, list):
res[slot] = [val.to_dict() if hasattr(val, 'to_dict') else val for val in attr]
else:
res[slot] = attr.to_dict() if hasattr(attr, 'to_dict') else attr
return res
def to_json(self, fp=None, default=_json_default, **kwargs):
"""

View File

@ -178,7 +178,6 @@ def _write_source_code(tlobject, kind, builder, type_constructors):
"""
_write_class_init(tlobject, kind, type_constructors, builder)
_write_resolve(tlobject, builder)
_write_to_dict(tlobject, builder)
_write_to_bytes(tlobject, builder)
_write_from_reader(tlobject, builder)
_write_read_result(tlobject, builder)
@ -301,42 +300,6 @@ def _write_resolve(tlobject, builder):
builder.end_block()
def _write_to_dict(tlobject, builder):
builder.writeln('def to_dict(self):')
builder.writeln('return {')
builder.current_indent += 1
builder.write("'_': '{}'", tlobject.class_name)
for arg in tlobject.real_args:
builder.writeln(',')
builder.write("'{}': ", arg.name)
if arg.type in BASE_TYPES:
if arg.is_vector:
builder.write('[] if self.{0} is None else self.{0}[:]',
arg.name)
else:
builder.write('self.{}', arg.name)
else:
if arg.is_vector:
builder.write(
'[] if self.{0} is None else [x.to_dict() '
'if isinstance(x, TLObject) else x for x in self.{0}]',
arg.name
)
else:
builder.write(
'self.{0}.to_dict() '
'if isinstance(self.{0}, TLObject) else self.{0}',
arg.name
)
builder.writeln()
builder.current_indent -= 1
builder.writeln("}")
builder.end_block()
def _write_to_bytes(tlobject, builder):
builder.writeln('def _bytes(self):')