Skip to content

Handling of constraints and type conversions for Telegram classes and methods #2901

@Bibo-Joshi

Description

@Bibo-Joshi

This issue addresses two things that are somewhat related

Enforcement of constraints for arguments

A lot of arguments have constraints - e.g. a maximum message length. I a few rare places, we actually enforce these constraints like here

if ok and (shipping_options is None or error_message is not None):
raise TelegramError(
'answerShippingQuery: If ok is True, shipping_options '
'should not be empty and there should not be error_message'
)
if not ok and (shipping_options is not None or error_message is None):
raise TelegramError(
'answerShippingQuery: If ok is False, error_message '
'should not be empty and there should not be shipping_options'
)

but we don't do that in most cases. Most notably, we don't enforce constraints in all the classes that are usually never constructed by a user, like Message or Chat
IMO we should unify our approach for this and document it. Personally, I'd be in favor of not enforcing the constraints since

  1. less maintenance work & less potentials for bugs
  2. more flexible in case TG changes the restrictions

This line of thought is somewhat related to #2900.
For documenting our approach, it would IMO suffice to put notes in the docstring of the Bot class and the telegram module along the lines "Note that the argument constraints are not enforced by PTB. Instead, Telegram respond with an error message if you don't respect them".

Note that once we drop py3.8, we might be able to type hint some of the constraints (see here and here), but this has usually no runtime effect.

Handling type conversions on __init__

Since we need to convert some types from their JSON representation to the actual type, in a number of __init__ s we have something like this:

# Required
self.longitude = float(longitude)
self.latitude = float(latitude)
# Optionals
self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None
self.live_period = int(live_period) if live_period else None
self.heading = int(heading) if heading else None
self.proximity_alert_radius = (
int(proximity_alert_radius) if proximity_alert_radius else None
)

Note that the respective arguments of the class are documented and typed as float and not Union[float, str]. I would argue that these conversions are actually the job of TelegramObject.de_json and would like to move them there.

In fact, this change might be due anyway once we swich to dataclasses #2698.


Note that I would consider both changes non-breaking since

  • in the first case, an exception is raised either way - either by TG or by us
  • in the second case, we'd only be changing implementation details, not documented behavior

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions