diff --git a/docs/source/conf.py b/docs/source/conf.py index f1c68c504..27dd879e6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -80,7 +80,9 @@ autodoc_typehints = "none" # Show docstring for special members autodoc_default_options = { "special-members": True, - "exclude-members": "__init__", + # For some reason, __weakref__ can not be ignored by using "inherited-members" in all cases + # so we list it here. + "exclude-members": "__init__, __weakref__", } # Fail on warnings & unresolved references etc diff --git a/docs/source/telegram.bot.rst b/docs/source/telegram.bot.rst index 46f4061cf..93211517e 100644 --- a/docs/source/telegram.bot.rst +++ b/docs/source/telegram.bot.rst @@ -4,4 +4,3 @@ Bot .. autoclass:: telegram.Bot :members: :show-inheritance: - :special-members: __repr__, __reduce__, __deepcopy__ \ No newline at end of file diff --git a/docs/source/telegram.ext.application.rst b/docs/source/telegram.ext.application.rst index eadc28927..4b1a3f259 100644 --- a/docs/source/telegram.ext.application.rst +++ b/docs/source/telegram.ext.application.rst @@ -4,4 +4,3 @@ Application .. autoclass:: telegram.ext.Application :members: :show-inheritance: - :special-members: __repr__ diff --git a/docs/source/telegram.ext.basehandler.rst b/docs/source/telegram.ext.basehandler.rst index 579302c29..9dfd607ce 100644 --- a/docs/source/telegram.ext.basehandler.rst +++ b/docs/source/telegram.ext.basehandler.rst @@ -4,4 +4,3 @@ BaseHandler .. autoclass:: telegram.ext.BaseHandler :members: :show-inheritance: - :special-members: __repr__ diff --git a/docs/source/telegram.ext.conversationhandler.rst b/docs/source/telegram.ext.conversationhandler.rst index bc42914f5..3ec96f1fd 100644 --- a/docs/source/telegram.ext.conversationhandler.rst +++ b/docs/source/telegram.ext.conversationhandler.rst @@ -4,4 +4,3 @@ ConversationHandler .. autoclass:: telegram.ext.ConversationHandler :members: :show-inheritance: - :special-members: __repr__ diff --git a/docs/source/telegram.ext.extbot.rst b/docs/source/telegram.ext.extbot.rst index dee1be3e7..d61a36b07 100644 --- a/docs/source/telegram.ext.extbot.rst +++ b/docs/source/telegram.ext.extbot.rst @@ -4,4 +4,3 @@ ExtBot .. autoclass:: telegram.ext.ExtBot :show-inheritance: :members: insert_callback_data, defaults, rate_limiter, initialize, shutdown, callback_data_cache - :special-members: __repr__ diff --git a/docs/source/telegram.ext.filters.rst b/docs/source/telegram.ext.filters.rst index 24306dca3..7762ab010 100644 --- a/docs/source/telegram.ext.filters.rst +++ b/docs/source/telegram.ext.filters.rst @@ -5,7 +5,7 @@ filters Module The classes in `filters.py` are sorted alphabetically such that :bysource: still is readable .. automodule:: telegram.ext.filters - :inherited-members: BaseFilter, MessageFilter, UpdateFilter + :inherited-members: BaseFilter, MessageFilter, UpdateFilter, object :members: :show-inheritance: :member-order: bysource \ No newline at end of file diff --git a/docs/source/telegram.ext.job.rst b/docs/source/telegram.ext.job.rst index 8406fcb80..0f69756b3 100644 --- a/docs/source/telegram.ext.job.rst +++ b/docs/source/telegram.ext.job.rst @@ -4,4 +4,3 @@ Job .. autoclass:: telegram.ext.Job :members: :show-inheritance: - :special-members: __call__, __repr__ diff --git a/docs/source/telegram.ext.jobqueue.rst b/docs/source/telegram.ext.jobqueue.rst index da347b3be..75658e30d 100644 --- a/docs/source/telegram.ext.jobqueue.rst +++ b/docs/source/telegram.ext.jobqueue.rst @@ -4,4 +4,3 @@ JobQueue .. autoclass:: telegram.ext.JobQueue :members: :show-inheritance: - :special-members: __repr__ diff --git a/docs/source/telegram.ext.updater.rst b/docs/source/telegram.ext.updater.rst index 98daf6e7c..642ddd202 100644 --- a/docs/source/telegram.ext.updater.rst +++ b/docs/source/telegram.ext.updater.rst @@ -4,4 +4,3 @@ Updater .. autoclass:: telegram.ext.Updater :members: :show-inheritance: - :special-members: __repr__ diff --git a/docs/source/telegram.telegramobject.rst b/docs/source/telegram.telegramobject.rst index 65fb7a9cc..7f1e5dbb7 100644 --- a/docs/source/telegram.telegramobject.rst +++ b/docs/source/telegram.telegramobject.rst @@ -4,4 +4,3 @@ TelegramObject .. autoclass:: telegram.TelegramObject :members: :show-inheritance: - :special-members: __repr__, __getitem__, __eq__, __hash__, __setstate__, __getstate__, __deepcopy__, __setattr__, __delattr__ diff --git a/telegram/_bot.py b/telegram/_bot.py index 6d06f32e3..db11b6f97 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -356,12 +356,22 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]): raise TypeError("Bot objects cannot be deepcopied!") def __eq__(self, other: object) -> bool: - if isinstance(other, self.__class__): + """Defines equality condition for the :class:`telegram.Bot` object. + Two objects of this class are considered to be equal if their attributes + :attr:`bot` are equal. + + Returns: + :obj:`True` if both attributes :attr:`bot` are equal. :obj:`False` otherwise. + """ + if isinstance(other, Bot): return self.bot == other.bot - return False + return super().__eq__(other) def __hash__(self) -> int: - return hash((self.__class__, self.bot)) + """See :meth:`telegram.TelegramObject.__hash__`""" + if self._bot_user is None: + return super().__hash__() + return hash((self.bot, Bot)) def __repr__(self) -> str: """Give a string representation of the bot in the form ``Bot[token=...]``. diff --git a/telegram/error.py b/telegram/error.py index 562733283..25502f52e 100644 --- a/telegram/error.py +++ b/telegram/error.py @@ -78,12 +78,30 @@ class TelegramError(Exception): self.message: str = msg def __str__(self) -> str: + """Gives the string representation of exceptions message. + + Returns: + :obj:`str` + """ return self.message def __repr__(self) -> str: + """Gives an unambiguous string representation of the exception. + + Returns: + :obj:`str` + """ return f"{self.__class__.__name__}('{self.message}')" def __reduce__(self) -> Tuple[type, Tuple[str]]: + """Defines how to serialize the exception for pickle. + + .. seealso:: + :py:meth:`object.__reduce__`, :mod:`pickle`. + + Returns: + :obj:`tuple` + """ return self.__class__, (self.message,) diff --git a/telegram/ext/_callbackdatacache.py b/telegram/ext/_callbackdatacache.py index 38e86b0fa..fb718d758 100644 --- a/telegram/ext/_callbackdatacache.py +++ b/telegram/ext/_callbackdatacache.py @@ -69,6 +69,12 @@ class InvalidCallbackData(TelegramError): self.callback_data: Optional[str] = callback_data def __reduce__(self) -> Tuple[type, Tuple[Optional[str]]]: # type: ignore[override] + """Defines how to serialize the exception for pickle. See + :py:meth:`object.__reduce__` for more info. + + Returns: + :obj:`tuple` + """ return self.__class__, (self.callback_data,) diff --git a/telegram/ext/_defaults.py b/telegram/ext/_defaults.py index 3b596e675..845793680 100644 --- a/telegram/ext/_defaults.py +++ b/telegram/ext/_defaults.py @@ -105,6 +105,12 @@ class Defaults: self._api_defaults[kwarg] = value def __hash__(self) -> int: + """Builds a hash value for this object such that the hash of two objects is equal if and + only if the objects are equal in terms of :meth:`__eq__`. + + Returns: + :obj:`int` The hash value of the object. + """ return hash( ( self._parse_mode, @@ -119,6 +125,13 @@ class Defaults: ) def __eq__(self, other: object) -> bool: + """Defines equality condition for the :class:`Defaults` object. + Two objects of this class are considered to be equal if all their parameters + are identical. + + Returns: + :obj:`True` if both objects have all parameters identical. :obj:`False` otherwise. + """ if isinstance(other, Defaults): return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__) return False diff --git a/telegram/ext/_jobqueue.py b/telegram/ext/_jobqueue.py index 67b9d8a3b..07bd678d3 100644 --- a/telegram/ext/_jobqueue.py +++ b/telegram/ext/_jobqueue.py @@ -821,6 +821,20 @@ class Job(Generic[CCT]): self._job = cast("APSJob", None) # skipcq: PTC-W0052 def __getattr__(self, item: str) -> object: + """Overrides :py:meth:`object.__getattr__` to get specific attribute of the + :class:`telegram.ext.Job` object or of its attribute :class:`apscheduler.job.Job`, + if exists. + + Args: + item (:obj:`str`): The name of the attribute. + + Returns: + :object: The value of the attribute. + + Raises: + :exc:`AttributeError`: If the attribute does not exist in both + :class:`telegram.ext.Job` and :class:`apscheduler.job.Job` objects. + """ try: return getattr(self.job, item) except AttributeError as exc: @@ -829,11 +843,25 @@ class Job(Generic[CCT]): ) from exc def __eq__(self, other: object) -> bool: + """Defines equality condition for the :class:`telegram.ext.Job` object. + Two objects of this class are considered to be equal if their + :class:`id ` are equal. + + Returns: + :obj:`True` if both objects have :paramref:`id` parameters identical. + :obj:`False` otherwise. + """ if isinstance(other, self.__class__): return self.id == other.id return False def __hash__(self) -> int: + """Builds a hash value for this object such that the hash of two objects is + equal if and only if the objects are equal in terms of :meth:`__eq__`. + + Returns: + :obj:`int`: The hash value of the object. + """ return hash(self.id) def __repr__(self) -> str: diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py index ab2ecbb9c..c1f9aee94 100644 --- a/telegram/ext/filters.py +++ b/telegram/ext/filters.py @@ -184,18 +184,57 @@ class BaseFilter: self._data_filter = data_filter def __and__(self, other: "BaseFilter") -> "BaseFilter": + """Defines `AND` bitwise operator for :class:`BaseFilter` object. + The combined filter accepts an update only if it is accepted by both filters. + For example, ``filters.PHOTO & filters.CAPTION`` will only accept messages that contain + both a photo and a caption. + + Returns: + :obj:`BaseFilter` + """ return _MergedFilter(self, and_filter=other) def __or__(self, other: "BaseFilter") -> "BaseFilter": + """Defines `OR` bitwise operator for :class:`BaseFilter` object. + The combined filter accepts an update only if it is accepted by any of the filters. + For example, ``filters.PHOTO | filters.CAPTION`` will only accept messages that contain + photo or caption or both. + + Returns: + :obj:`BaseFilter` + """ return _MergedFilter(self, or_filter=other) def __xor__(self, other: "BaseFilter") -> "BaseFilter": + """Defines `XOR` bitwise operator for :class:`BaseFilter` object. + The combined filter accepts an update only if it is accepted by any of the filters and + not both of them. For example, ``filters.PHOTO ^ filters.CAPTION`` will only accept + messages that contain photo or caption, not both of them. + + Returns: + :obj:`BaseFilter` + """ return _XORFilter(self, other) def __invert__(self) -> "BaseFilter": + """Defines `NOT` bitwise operator for :class:`BaseFilter` object. + The combined filter accepts an update only if it is accepted by any of the filters. + For example, ``~ filters.PHOTO`` will only accept messages that do not contain photo. + + Returns: + :obj:`BaseFilter` + """ return _InvertedFilter(self) def __repr__(self) -> str: + """Gives name for this filter. + + .. seealso:: + :meth:`name` + + Returns: + :obj:`str`: + """ return self.name @property diff --git a/tests/test_bot.py b/tests/test_bot.py index d6277cf0e..4ef7f6ebf 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -316,15 +316,16 @@ class TestBotWithoutRequest: async def test_equality(self): async with make_bot(token=FALLBACKS[0]["token"]) as a, make_bot( token=FALLBACKS[0]["token"] - ) as b, make_bot(token=FALLBACKS[1]["token"]) as c, Bot(token=FALLBACKS[0]["token"]) as d: + ) as b, Bot(token=FALLBACKS[0]["token"]) as c, make_bot(token=FALLBACKS[1]["token"]) as d: e = Update(123456789) + f = Bot(token=FALLBACKS[0]["token"]) assert a == b assert hash(a) == hash(b) assert a is not b - assert a != c - assert hash(a) != hash(c) + assert a == c + assert hash(a) == hash(c) assert a != d assert hash(a) != hash(d) @@ -332,6 +333,9 @@ class TestBotWithoutRequest: assert a != e assert hash(a) != hash(e) + # We cant check equality for unintialized Bot object + assert hash(a) != hash(f) + @pytest.mark.parametrize( "attribute", [