Add Docstring to Dunder Methods (#3929)

This commit is contained in:
Aditya Yadav 2023-12-10 19:17:11 +00:00 committed by GitHub
parent 67b0706116
commit fd6a0fe899
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 128 additions and 17 deletions

View file

@ -80,7 +80,9 @@ autodoc_typehints = "none"
# Show docstring for special members # Show docstring for special members
autodoc_default_options = { autodoc_default_options = {
"special-members": True, "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 # Fail on warnings & unresolved references etc

View file

@ -4,4 +4,3 @@ Bot
.. autoclass:: telegram.Bot .. autoclass:: telegram.Bot
:members: :members:
:show-inheritance: :show-inheritance:
:special-members: __repr__, __reduce__, __deepcopy__

View file

@ -4,4 +4,3 @@ Application
.. autoclass:: telegram.ext.Application .. autoclass:: telegram.ext.Application
:members: :members:
:show-inheritance: :show-inheritance:
:special-members: __repr__

View file

@ -4,4 +4,3 @@ BaseHandler
.. autoclass:: telegram.ext.BaseHandler .. autoclass:: telegram.ext.BaseHandler
:members: :members:
:show-inheritance: :show-inheritance:
:special-members: __repr__

View file

@ -4,4 +4,3 @@ ConversationHandler
.. autoclass:: telegram.ext.ConversationHandler .. autoclass:: telegram.ext.ConversationHandler
:members: :members:
:show-inheritance: :show-inheritance:
:special-members: __repr__

View file

@ -4,4 +4,3 @@ ExtBot
.. autoclass:: telegram.ext.ExtBot .. autoclass:: telegram.ext.ExtBot
:show-inheritance: :show-inheritance:
:members: insert_callback_data, defaults, rate_limiter, initialize, shutdown, callback_data_cache :members: insert_callback_data, defaults, rate_limiter, initialize, shutdown, callback_data_cache
:special-members: __repr__

View file

@ -5,7 +5,7 @@ filters Module
The classes in `filters.py` are sorted alphabetically such that :bysource: still is readable The classes in `filters.py` are sorted alphabetically such that :bysource: still is readable
.. automodule:: telegram.ext.filters .. automodule:: telegram.ext.filters
:inherited-members: BaseFilter, MessageFilter, UpdateFilter :inherited-members: BaseFilter, MessageFilter, UpdateFilter, object
:members: :members:
:show-inheritance: :show-inheritance:
:member-order: bysource :member-order: bysource

View file

@ -4,4 +4,3 @@ Job
.. autoclass:: telegram.ext.Job .. autoclass:: telegram.ext.Job
:members: :members:
:show-inheritance: :show-inheritance:
:special-members: __call__, __repr__

View file

@ -4,4 +4,3 @@ JobQueue
.. autoclass:: telegram.ext.JobQueue .. autoclass:: telegram.ext.JobQueue
:members: :members:
:show-inheritance: :show-inheritance:
:special-members: __repr__

View file

@ -4,4 +4,3 @@ Updater
.. autoclass:: telegram.ext.Updater .. autoclass:: telegram.ext.Updater
:members: :members:
:show-inheritance: :show-inheritance:
:special-members: __repr__

View file

@ -4,4 +4,3 @@ TelegramObject
.. autoclass:: telegram.TelegramObject .. autoclass:: telegram.TelegramObject
:members: :members:
:show-inheritance: :show-inheritance:
:special-members: __repr__, __getitem__, __eq__, __hash__, __setstate__, __getstate__, __deepcopy__, __setattr__, __delattr__

View file

@ -356,12 +356,22 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]):
raise TypeError("Bot objects cannot be deepcopied!") raise TypeError("Bot objects cannot be deepcopied!")
def __eq__(self, other: object) -> bool: 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 self.bot == other.bot
return False return super().__eq__(other)
def __hash__(self) -> int: 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: def __repr__(self) -> str:
"""Give a string representation of the bot in the form ``Bot[token=...]``. """Give a string representation of the bot in the form ``Bot[token=...]``.

View file

@ -78,12 +78,30 @@ class TelegramError(Exception):
self.message: str = msg self.message: str = msg
def __str__(self) -> str: def __str__(self) -> str:
"""Gives the string representation of exceptions message.
Returns:
:obj:`str`
"""
return self.message return self.message
def __repr__(self) -> str: def __repr__(self) -> str:
"""Gives an unambiguous string representation of the exception.
Returns:
:obj:`str`
"""
return f"{self.__class__.__name__}('{self.message}')" return f"{self.__class__.__name__}('{self.message}')"
def __reduce__(self) -> Tuple[type, Tuple[str]]: 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,) return self.__class__, (self.message,)

View file

@ -69,6 +69,12 @@ class InvalidCallbackData(TelegramError):
self.callback_data: Optional[str] = callback_data self.callback_data: Optional[str] = callback_data
def __reduce__(self) -> Tuple[type, Tuple[Optional[str]]]: # type: ignore[override] 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,) return self.__class__, (self.callback_data,)

View file

@ -105,6 +105,12 @@ class Defaults:
self._api_defaults[kwarg] = value self._api_defaults[kwarg] = value
def __hash__(self) -> int: 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( return hash(
( (
self._parse_mode, self._parse_mode,
@ -119,6 +125,13 @@ class Defaults:
) )
def __eq__(self, other: object) -> bool: 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): if isinstance(other, Defaults):
return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__) return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__)
return False return False

View file

@ -821,6 +821,20 @@ class Job(Generic[CCT]):
self._job = cast("APSJob", None) # skipcq: PTC-W0052 self._job = cast("APSJob", None) # skipcq: PTC-W0052
def __getattr__(self, item: str) -> object: 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: try:
return getattr(self.job, item) return getattr(self.job, item)
except AttributeError as exc: except AttributeError as exc:
@ -829,11 +843,25 @@ class Job(Generic[CCT]):
) from exc ) from exc
def __eq__(self, other: object) -> bool: 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__): if isinstance(other, self.__class__):
return self.id == other.id return self.id == other.id
return False return False
def __hash__(self) -> int: 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) return hash(self.id)
def __repr__(self) -> str: def __repr__(self) -> str:

View file

@ -184,18 +184,57 @@ class BaseFilter:
self._data_filter = data_filter self._data_filter = data_filter
def __and__(self, other: "BaseFilter") -> "BaseFilter": 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) return _MergedFilter(self, and_filter=other)
def __or__(self, other: "BaseFilter") -> "BaseFilter": 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) return _MergedFilter(self, or_filter=other)
def __xor__(self, other: "BaseFilter") -> "BaseFilter": 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) return _XORFilter(self, other)
def __invert__(self) -> "BaseFilter": 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) return _InvertedFilter(self)
def __repr__(self) -> str: def __repr__(self) -> str:
"""Gives name for this filter.
.. seealso::
:meth:`name`
Returns:
:obj:`str`:
"""
return self.name return self.name
@property @property

View file

@ -316,15 +316,16 @@ class TestBotWithoutRequest:
async def test_equality(self): async def test_equality(self):
async with make_bot(token=FALLBACKS[0]["token"]) as a, make_bot( async with make_bot(token=FALLBACKS[0]["token"]) as a, make_bot(
token=FALLBACKS[0]["token"] 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) e = Update(123456789)
f = Bot(token=FALLBACKS[0]["token"])
assert a == b assert a == b
assert hash(a) == hash(b) assert hash(a) == hash(b)
assert a is not b assert a is not b
assert a != c assert a == c
assert hash(a) != hash(c) assert hash(a) == hash(c)
assert a != d assert a != d
assert hash(a) != hash(d) assert hash(a) != hash(d)
@ -332,6 +333,9 @@ class TestBotWithoutRequest:
assert a != e assert a != e
assert hash(a) != hash(e) assert hash(a) != hash(e)
# We cant check equality for unintialized Bot object
assert hash(a) != hash(f)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"attribute", "attribute",
[ [