Skip to content

Centralize de_json - #5186

Merged
harshil21 merged 20 commits into
masterfrom
simplify-de-json
Jul 30, 2026
Merged

Centralize de_json#5186
harshil21 merged 20 commits into
masterfrom
simplify-de-json

Conversation

@harshil21

@harshil21 harshil21 commented Mar 29, 2026

Copy link
Copy Markdown
Member

Closes #5189

This is the benchmark I used for the results below. It includes a mix of different kind of classes and cases.

Here are the performance results:

Test Case Master (it/s) Master best (s) Master mean (µs) Branch (it/s) Branch best (s) Branch mean (µs) Change (%)
User 169460.781 0.030 5.9 163505.137 0.031 6.2 −3.5
ChatBoost 58043.702 0.086 17.4 54131.579 0.092 19.0 −6.7
BusinessConnection 50168.175 0.100 20.0 42575.756 0.117 23.7 −15.1
CallbackQuery 15806.120 0.316 63.6 18839.647 0.265 53.3 +19.2
ChatJoinRequest 62539.851 0.080 16.1 56644.010 0.088 18.4 −9.4
Message‑minimal 17122.015 0.292 58.6 21057.629 0.237 47.7 +23.0
Message‑medium 9886.712 0.506 101.7 10675.907 0.468 94.1 +8.0
Message‑heavy 4334.172 1.154 232.5 4694.056 1.065 213.5 +8.3
TransactionPartner‑user 63686.830 0.079 15.9 64283.784 0.078 15.7 +0.9
TransactionPartner‑fragment 68899.608 0.073 14.7 72328.266 0.069 13.9 +5.0
ChatMember‑member 77334.824 0.065 13.1 76181.318 0.066 13.2 −1.5
ChatMember‑administrator 56269.916 0.089 17.9 54497.678 0.092 18.5 −3.1
UserProfilePhotos 28991.156 0.172 34.7 27078.124 0.185 37.2 −6.6
InlineKeyboardMarkup 22011.970 0.227 45.6 20940.324 0.239 47.9 −4.9
Update‑message 12580.153 0.397 79.9 15165.953 0.330 66.1 +20.5
Update‑callback 13060.602 0.383 76.8 15791.913 0.317 63.6 +20.9

I'll add tests after initial review.

@harshil21 harshil21 added the 🔌 enhancement pr description: enhancement label Mar 29, 2026
Comment thread src/telegram/_telegramobject.py Fixed
Comment thread src/telegram/_telegramobject.py Fixed
@harshil21 harshil21 added the 🛠 refactor change type: refactor label Mar 31, 2026
@harshil21
harshil21 marked this pull request as ready for review March 31, 2026 11:55
@harshil21 harshil21 added this to the v23 milestone Jun 1, 2026

@aelkheir aelkheir left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! This is really really neat.
I left a couple of suggestions and a questions for my understanding

Comment thread src/telegram/_checklists.py
Comment thread src/telegram/_telegramobject.py Outdated
Comment thread src/telegram/_telegramobject.py Outdated
Comment on lines +96 to +98
return lambda v, b, _c=item_type: ( # type: ignore[misc]
_c.de_list(v, b) if isinstance(v, list) else v
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return lambda v, b, _c=item_type: ( # type: ignore[misc]
_c.de_list(v, b) if isinstance(v, list) else v
)
def transform_fn(
value: object,
bot: "Bot | None",
tg_class: TelegramObject = item_type,
):
if value is None:
return ()
return ( # type: ignore[misc]
tg_class.de_list(value, bot) if isinstance(value, list) else value
)
return transform_fn

the if value is None branch should not matter as parse_sequence_arg will be called on the value again. This is just to keep old behavior of de_list_optional

And btw way argumentparsing's de_list_optional, de_json_optional can be removed i think

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks yeah the lambda's were not really readable..

I'm removing the value is None check because value is guaranteed to not be None (since we explicitly check that - see comment "Should we transform this field?")

Comment thread src/telegram/_telegramobject.py Outdated
Comment on lines +635 to +638
if not isinstance(data[key], dtm.datetime): # Avoid retransformations
data[key] = from_timestamp(data[key], tzinfo=tz)
elif isinstance(target, type): # Target is a TelegramObject subclass → de_json
if not isinstance(data[key], target): # Avoid retransformations

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regarding the avoid retransformations comment, is this measure for classes that override de_json for whatever reason, or is there actually a another place that does pre transformations cause i couldn't find any

@harshil21 harshil21 Jul 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that was actually to accommodate the de_json behaviour happening in PassportFile. The way the PassportFile de_json worked is flawed because the credentials object would already be a FileCredentials object in the de_json call, which is why I had to "avoid retransformations".

I'm now just going to fix the passport side instead to actually have dictionaries when doing a de_json, so we can delete this.

target_cls: Tele_co = dispatch_mapping.get( # type: ignore[assignment]
data.get(dispatch_key) # type: ignore[arg-type]
)
if target_cls is not None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if for some reason the target_cls turned out to be None (for example telegram added a new child class to MessageOrigin) then continuing from this branch to the end of de_json would still produce a MessageOrigin with unknown fields added to api_kwargs?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep that's right. Now that we have a lot of new classes not implemented, it's a perfect test for forward compatibility...

@harshil21

Copy link
Copy Markdown
Member Author

Did more forward compatibility tests with API 10.1/10.2, and they work as intended. Also added tests, which should explain the behavior of de_json at a higher level.

@harshil21 harshil21 changed the title PoC: Start centralizing de_json Centralize de_json Jul 16, 2026
@harshil21
harshil21 requested a review from aelkheir July 16, 2026 07:52
@Poolitzer

Copy link
Copy Markdown
Member

A great undertaking, I dont have any open question.

@harshil21

Copy link
Copy Markdown
Member Author

Alright, merging now!

@harshil21
harshil21 merged commit c72e062 into master Jul 30, 2026
29 of 33 checks passed
@harshil21
harshil21 deleted the simplify-de-json branch July 30, 2026 18:08
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 7, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

🔌 enhancement pr description: enhancement 🛠 refactor change type: refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Centralize all de_json's into TelegramObject

4 participants