Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@
# 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
Expand Down
1 change: 0 additions & 1 deletion docs/source/telegram.bot.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ Bot
.. autoclass:: telegram.Bot
:members:
:show-inheritance:
:special-members: __repr__, __reduce__, __deepcopy__
1 change: 0 additions & 1 deletion docs/source/telegram.ext.application.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ Application
.. autoclass:: telegram.ext.Application
:members:
:show-inheritance:
:special-members: __repr__
1 change: 0 additions & 1 deletion docs/source/telegram.ext.basehandler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ BaseHandler
.. autoclass:: telegram.ext.BaseHandler
:members:
:show-inheritance:
:special-members: __repr__
1 change: 0 additions & 1 deletion docs/source/telegram.ext.conversationhandler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ ConversationHandler
.. autoclass:: telegram.ext.ConversationHandler
:members:
:show-inheritance:
:special-members: __repr__
1 change: 0 additions & 1 deletion docs/source/telegram.ext.extbot.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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__
2 changes: 1 addition & 1 deletion docs/source/telegram.ext.filters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 0 additions & 1 deletion docs/source/telegram.ext.job.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ Job
.. autoclass:: telegram.ext.Job
:members:
:show-inheritance:
:special-members: __call__, __repr__
1 change: 0 additions & 1 deletion docs/source/telegram.ext.jobqueue.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ JobQueue
.. autoclass:: telegram.ext.JobQueue
:members:
:show-inheritance:
:special-members: __repr__
1 change: 0 additions & 1 deletion docs/source/telegram.ext.updater.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ Updater
.. autoclass:: telegram.ext.Updater
:members:
:show-inheritance:
:special-members: __repr__
1 change: 0 additions & 1 deletion docs/source/telegram.telegramobject.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ TelegramObject
.. autoclass:: telegram.TelegramObject
:members:
:show-inheritance:
:special-members: __repr__, __getitem__, __eq__, __hash__, __setstate__, __getstate__, __deepcopy__, __setattr__, __delattr__
16 changes: 13 additions & 3 deletions telegram/_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,12 +356,22 @@ def __deepcopy__(self, memodict: Dict[int, object]) -> NoReturn:
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=...]``.
Expand Down
18 changes: 18 additions & 0 deletions telegram/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,30 @@ def __init__(self, message: str):
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,)


Expand Down
6 changes: 6 additions & 0 deletions telegram/ext/_callbackdatacache.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ def __init__(self, callback_data: Optional[str] = None) -> None:
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,)


Expand Down
13 changes: 13 additions & 0 deletions telegram/ext/_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ def __init__(
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,
Expand All @@ -119,6 +125,13 @@ def __hash__(self) -> int:
)

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
Expand Down
28 changes: 28 additions & 0 deletions telegram/ext/_jobqueue.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,20 @@ def __init__(
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:
Expand All @@ -829,11 +843,25 @@ def __getattr__(self, item: str) -> object:
) 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 <apscheduler.job.Job>` 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:
Expand Down
39 changes: 39 additions & 0 deletions telegram/ext/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,57 @@ def __init__(self, name: Optional[str] = None, data_filter: bool = False):
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
Expand Down
10 changes: 7 additions & 3 deletions tests/test_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,22 +316,26 @@ async def shutdown():
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)

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",
[
Expand Down