diff --git a/readthedocs/misc/v2-migration-guide.rst b/readthedocs/misc/v2-migration-guide.rst index 3a3f18cf..61ccf252 100644 --- a/readthedocs/misc/v2-migration-guide.rst +++ b/readthedocs/misc/v2-migration-guide.rst @@ -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?? diff --git a/telethon/_misc/tlobject.py b/telethon/_misc/tlobject.py index c9e3d425..da2ed6d6 100644 --- a/telethon/_misc/tlobject.py +++ b/telethon/_misc/tlobject.py @@ -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): """ diff --git a/telethon_generator/generators/tlobject.py b/telethon_generator/generators/tlobject.py index 55c580b0..e5a3d07e 100644 --- a/telethon_generator/generators/tlobject.py +++ b/telethon_generator/generators/tlobject.py @@ -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):')