From 22e536025785b610dafa775b7d6ee55bf513a71e Mon Sep 17 00:00:00 2001 From: Aditya Date: Fri, 29 Sep 2023 17:32:53 +0530 Subject: [PATCH 1/6] add docs for ctx managers --- docs/source/conf.py | 7 +++++++ docs/substitutions/global.rst | 2 ++ telegram/_bot.py | 18 ++++++++++++++++++ telegram/ext/_application.py | 18 ++++++++++++++++-- telegram/ext/_baseupdateprocessor.py | 18 ++++++++++++++++-- telegram/ext/_updater.py | 20 ++++++++++++++++++-- telegram/request/_baserequest.py | 17 +++++++++++++++++ 7 files changed, 94 insertions(+), 6 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index bcbc33e9e8f..c27eb8ef18c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -77,6 +77,13 @@ # and we document the types anyway autodoc_typehints = "none" +# Show docstring for special members +autodoc_special_members = ["__aenter__", "__aexit__"] + +autodoc_default_options = { + "special-members": True, +} + # Fail on warnings & unresolved references etc nitpicky = True diff --git a/docs/substitutions/global.rst b/docs/substitutions/global.rst index 151e347afd7..bc5fc74e130 100644 --- a/docs/substitutions/global.rst +++ b/docs/substitutions/global.rst @@ -61,3 +61,5 @@ .. |removed_thumb_url_note| replace:: Removed the deprecated argument and attribute ``thumb_url``. .. |removed_thumb_wildcard_note| replace:: Removed the deprecated arguments and attributes ``thumb_*``. + +.. |async_context_manager| replace:: Asynchronous context manager which \ No newline at end of file diff --git a/telegram/_bot.py b/telegram/_bot.py index 799c57c520e..de79755339a 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -310,6 +310,18 @@ def __init__( self._freeze() async def __aenter__(self: BT) -> BT: + """ + |async_context_manager| initializes the Bot. + + If no exceptions are raised during initialization, returns the Bot instance. + If an exception is raised, shuts down the Bot and re-raises the exception. + + Returns: + The initialized Bot instance. + + Raises: + :exc:`Exception`: If an exception is raised during initialization. + """ try: await self.initialize() return self @@ -323,6 +335,12 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: + """ + |async_context_manager| shuts down the Bot. + + This function is called when exiting the context manager. + It shuts down the Bot and does not suppress any exceptions. + """ # Make sure not to return `True` so that exceptions are not suppressed # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ await self.shutdown() diff --git a/telegram/ext/_application.py b/telegram/ext/_application.py index e7970975ce9..5b4bd059670 100644 --- a/telegram/ext/_application.py +++ b/telegram/ext/_application.py @@ -345,7 +345,17 @@ def __init__( self.__create_task_tasks: Set[asyncio.Task] = set() # Used for awaiting tasks upon exit async def __aenter__(self: _AppType) -> _AppType: # noqa: PYI019 - """Simple context manager which initializes the App.""" + """|async_context_manager| initializes the App. + + If no exceptions are raised during initialization, returns the App instance. + If an exception is raised, shuts down the App and re-raises the exception. + + Returns: + The initialized App instance. + + Raises: + :exc:`Exception`: If an exception is raised during initialization. + """ try: await self.initialize() return self @@ -359,7 +369,11 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: - """Shutdown the App from the context manager.""" + """|async_context_manager| shuts down the App. + + This function is called when exiting the context manager. + It shuts down the App and does not suppress any exceptions. + """ # Make sure not to return `True` so that exceptions are not suppressed # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ await self.shutdown() diff --git a/telegram/ext/_baseupdateprocessor.py b/telegram/ext/_baseupdateprocessor.py index 42baa02da9d..32470156066 100644 --- a/telegram/ext/_baseupdateprocessor.py +++ b/telegram/ext/_baseupdateprocessor.py @@ -49,7 +49,17 @@ def __init__(self, max_concurrent_updates: int): self._semaphore = BoundedSemaphore(self.max_concurrent_updates) async def __aenter__(self) -> "BaseUpdateProcessor": - """Simple context manager which initializes the Processor.""" + """|async_context_manager| initializes the Processor. + + If no exceptions are raised during initialization, returns the Processor instance. + If an exception is raised, shuts down the Processor and re-raises the exception. + + Returns: + The initialized Processor instance. + + Raises: + :exc:`Exception`: If an exception is raised during initialization. + """ try: await self.initialize() return self @@ -63,7 +73,11 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: - """Simple context manager which shuts down the Processor.""" + """|async_context_manager| shuts down the Processor. + + This function is called when exiting the context manager. + It shuts down the Processor and does not suppress any exceptions. + """ await self.shutdown() @property diff --git a/telegram/ext/_updater.py b/telegram/ext/_updater.py index 740ca60d4ea..4490144cfcd 100644 --- a/telegram/ext/_updater.py +++ b/telegram/ext/_updater.py @@ -126,7 +126,18 @@ def __init__( self.__polling_cleanup_cb: Optional[Callable[[], Coroutine[Any, Any, None]]] = None async def __aenter__(self: _UpdaterType) -> _UpdaterType: # noqa: PYI019 - """Simple context manager which initializes the Updater.""" + """ + |async_context_manager| initializes the Updater. + + If no exceptions are raised during initialization, returns the Updater instance. + If an exception is raised, shuts down the Updater and re-raises the exception. + + Returns: + The initialized Updater instance. + + Raises: + :exc:`Exception`: If an exception is raised during initialization. + """ try: await self.initialize() return self @@ -140,7 +151,12 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: - """Shutdown the Updater from the context manager.""" + """ + |async_context_manager| shuts down the Updater. + + This function is called when exiting the context manager. + It shuts down the Updater and does not suppress any exceptions. + """ # Make sure not to return `True` so that exceptions are not suppressed # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ await self.shutdown() diff --git a/telegram/request/_baserequest.py b/telegram/request/_baserequest.py index 28404ca2347..4ab1144eac0 100644 --- a/telegram/request/_baserequest.py +++ b/telegram/request/_baserequest.py @@ -99,6 +99,17 @@ class BaseRequest( """ async def __aenter__(self: RT) -> RT: + """|async_context_manager| initializes the Request. + + If no exceptions are raised during initialization, returns the Request instance. + If an exception is raised, shuts down the Request and re-raises the exception. + + Returns: + The initialized Request instance. + + Raises: + :exc:`Exception`: If an exception is raised during initialization. + """ try: await self.initialize() return self @@ -112,6 +123,12 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: + """ + |async_context_manager| shuts down the Request. + + This function is called when exiting the context manager. + It shuts down the Request and does not suppress any exceptions. + """ # Make sure not to return `True` so that exceptions are not suppressed # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ await self.shutdown() From 565ed971fac70b5e7961f0b5d08a09b8f14715ca Mon Sep 17 00:00:00 2001 From: Aditya Date: Sat, 30 Sep 2023 18:20:39 +0530 Subject: [PATCH 2/6] adress review --- docs/source/conf.py | 1 + telegram/_bot.py | 12 ++---------- telegram/ext/_application.py | 11 ++--------- telegram/ext/_baseupdateprocessor.py | 11 ++--------- telegram/ext/_updater.py | 12 ++---------- telegram/request/_baserequest.py | 12 ++---------- 6 files changed, 11 insertions(+), 48 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c27eb8ef18c..9b37fe2aa0c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -82,6 +82,7 @@ autodoc_default_options = { "special-members": True, + "exclude-members": "__init__", } # Fail on warnings & unresolved references etc diff --git a/telegram/_bot.py b/telegram/_bot.py index de79755339a..16ce451d3f1 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -311,10 +311,7 @@ def __init__( async def __aenter__(self: BT) -> BT: """ - |async_context_manager| initializes the Bot. - - If no exceptions are raised during initialization, returns the Bot instance. - If an exception is raised, shuts down the Bot and re-raises the exception. + |async_context_manager| :meth:`initializes ` the Bot. Returns: The initialized Bot instance. @@ -335,12 +332,7 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: - """ - |async_context_manager| shuts down the Bot. - - This function is called when exiting the context manager. - It shuts down the Bot and does not suppress any exceptions. - """ + """|async_context_manager| :meth:`shuts down ` the Bot.""" # Make sure not to return `True` so that exceptions are not suppressed # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ await self.shutdown() diff --git a/telegram/ext/_application.py b/telegram/ext/_application.py index 5b4bd059670..68335875318 100644 --- a/telegram/ext/_application.py +++ b/telegram/ext/_application.py @@ -345,10 +345,7 @@ def __init__( self.__create_task_tasks: Set[asyncio.Task] = set() # Used for awaiting tasks upon exit async def __aenter__(self: _AppType) -> _AppType: # noqa: PYI019 - """|async_context_manager| initializes the App. - - If no exceptions are raised during initialization, returns the App instance. - If an exception is raised, shuts down the App and re-raises the exception. + """|async_context_manager| :meth:`initializes ` the App. Returns: The initialized App instance. @@ -369,11 +366,7 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: - """|async_context_manager| shuts down the App. - - This function is called when exiting the context manager. - It shuts down the App and does not suppress any exceptions. - """ + """|async_context_manager| :meth:`shuts down ` the App.""" # Make sure not to return `True` so that exceptions are not suppressed # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ await self.shutdown() diff --git a/telegram/ext/_baseupdateprocessor.py b/telegram/ext/_baseupdateprocessor.py index 32470156066..4baaff16e70 100644 --- a/telegram/ext/_baseupdateprocessor.py +++ b/telegram/ext/_baseupdateprocessor.py @@ -49,10 +49,7 @@ def __init__(self, max_concurrent_updates: int): self._semaphore = BoundedSemaphore(self.max_concurrent_updates) async def __aenter__(self) -> "BaseUpdateProcessor": - """|async_context_manager| initializes the Processor. - - If no exceptions are raised during initialization, returns the Processor instance. - If an exception is raised, shuts down the Processor and re-raises the exception. + """|async_context_manager| :meth:`initializes ` the Processor. Returns: The initialized Processor instance. @@ -73,11 +70,7 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: - """|async_context_manager| shuts down the Processor. - - This function is called when exiting the context manager. - It shuts down the Processor and does not suppress any exceptions. - """ + """|async_context_manager| :meth:`shuts down ` the Processor.""" await self.shutdown() @property diff --git a/telegram/ext/_updater.py b/telegram/ext/_updater.py index 4490144cfcd..3d98737ce33 100644 --- a/telegram/ext/_updater.py +++ b/telegram/ext/_updater.py @@ -127,10 +127,7 @@ def __init__( async def __aenter__(self: _UpdaterType) -> _UpdaterType: # noqa: PYI019 """ - |async_context_manager| initializes the Updater. - - If no exceptions are raised during initialization, returns the Updater instance. - If an exception is raised, shuts down the Updater and re-raises the exception. + |async_context_manager| :meth:`initializes ` the Updater. Returns: The initialized Updater instance. @@ -151,12 +148,7 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: - """ - |async_context_manager| shuts down the Updater. - - This function is called when exiting the context manager. - It shuts down the Updater and does not suppress any exceptions. - """ + """|async_context_manager| :meth:`shuts down ` the Updater.""" # Make sure not to return `True` so that exceptions are not suppressed # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ await self.shutdown() diff --git a/telegram/request/_baserequest.py b/telegram/request/_baserequest.py index 4ab1144eac0..4c67f2b58b6 100644 --- a/telegram/request/_baserequest.py +++ b/telegram/request/_baserequest.py @@ -99,10 +99,7 @@ class BaseRequest( """ async def __aenter__(self: RT) -> RT: - """|async_context_manager| initializes the Request. - - If no exceptions are raised during initialization, returns the Request instance. - If an exception is raised, shuts down the Request and re-raises the exception. + """|async_context_manager| :meth:`initializes ` the Request. Returns: The initialized Request instance. @@ -123,12 +120,7 @@ async def __aexit__( exc_val: Optional[BaseException], exc_tb: Optional[TracebackType], ) -> None: - """ - |async_context_manager| shuts down the Request. - - This function is called when exiting the context manager. - It shuts down the Request and does not suppress any exceptions. - """ + """|async_context_manager| :meth:`shuts down ` the Request.""" # Make sure not to return `True` so that exceptions are not suppressed # https://docs.python.org/3/reference/datamodel.html?#object.__aexit__ await self.shutdown() From 07d4e0870c78a7e516c66b2a72806e7acc6f51cc Mon Sep 17 00:00:00 2001 From: Aditya Date: Mon, 2 Oct 2023 19:23:01 +0530 Subject: [PATCH 3/6] review2 --- telegram/_bot.py | 5 ++++- telegram/ext/_application.py | 5 ++++- telegram/ext/_baseupdateprocessor.py | 22 +++++++++++++++++++++- telegram/ext/_updater.py | 5 ++++- telegram/request/_baserequest.py | 5 ++++- 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/telegram/_bot.py b/telegram/_bot.py index 16ce451d3f1..aaefe0eda36 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -149,6 +149,8 @@ class Bot(TelegramObject, AsyncContextManager["Bot"]): finally: await bot.shutdown() + .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. + Note: * Most bot methods have the argument ``api_kwargs`` which allows passing arbitrary keywords to the Telegram API. This can be used to access new features of the API before they are @@ -317,7 +319,8 @@ async def __aenter__(self: BT) -> BT: The initialized Bot instance. Raises: - :exc:`Exception`: If an exception is raised during initialization. + :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` + is called in this case. """ try: await self.initialize() diff --git a/telegram/ext/_application.py b/telegram/ext/_application.py index 68335875318..93151e00abf 100644 --- a/telegram/ext/_application.py +++ b/telegram/ext/_application.py @@ -149,6 +149,8 @@ class Application(Generic[BT, CCT, UD, CD, BD, JQ], AsyncContextManager["Applica finally: await application.shutdown() + .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. + Examples: :any:`Echo Bot ` @@ -351,7 +353,8 @@ async def __aenter__(self: _AppType) -> _AppType: # noqa: PYI019 The initialized App instance. Raises: - :exc:`Exception`: If an exception is raised during initialization. + :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` + is called in this case. """ try: await self.initialize() diff --git a/telegram/ext/_baseupdateprocessor.py b/telegram/ext/_baseupdateprocessor.py index 4baaff16e70..efb89a7e53e 100644 --- a/telegram/ext/_baseupdateprocessor.py +++ b/telegram/ext/_baseupdateprocessor.py @@ -27,6 +27,25 @@ class BaseUpdateProcessor(ABC): """An abstract base class for update processors. You can use this class to implement your own update processor. + Instances of this class can be used as asyncio context managers, where + + .. code:: python + + async with processor: + # code + + is roughly equivalent to + + .. code:: python + + try: + await processor.initialize() + # code + finally: + await processor.shutdown() + + .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. + .. seealso:: :wiki:`Concurrency` .. versionadded:: 20.4 @@ -55,7 +74,8 @@ async def __aenter__(self) -> "BaseUpdateProcessor": The initialized Processor instance. Raises: - :exc:`Exception`: If an exception is raised during initialization. + :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` + is called in this case """ try: await self.initialize() diff --git a/telegram/ext/_updater.py b/telegram/ext/_updater.py index 3d98737ce33..9f2789dd2bf 100644 --- a/telegram/ext/_updater.py +++ b/telegram/ext/_updater.py @@ -78,6 +78,8 @@ class Updater(AsyncContextManager["Updater"]): finally: await updater.shutdown() + .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. + .. seealso:: :wiki:`Architecture Overview `, :wiki:`Builder Pattern ` @@ -133,7 +135,8 @@ async def __aenter__(self: _UpdaterType) -> _UpdaterType: # noqa: PYI019 The initialized Updater instance. Raises: - :exc:`Exception`: If an exception is raised during initialization. + :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` + is called in this case. """ try: await self.initialize() diff --git a/telegram/request/_baserequest.py b/telegram/request/_baserequest.py index 4c67f2b58b6..488333447ff 100644 --- a/telegram/request/_baserequest.py +++ b/telegram/request/_baserequest.py @@ -70,6 +70,8 @@ class BaseRequest( finally: await request_object.shutdown() + .. seealso:: :meth:`__aenter__` and :meth:`__aexit__`. + Tip: JSON encoding and decoding is done with the standard library's :mod:`json` by default. To use a custom library for this, you can override :meth:`parse_json_payload` and implement @@ -105,7 +107,8 @@ async def __aenter__(self: RT) -> RT: The initialized Request instance. Raises: - :exc:`Exception`: If an exception is raised during initialization. + :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` + is called in this case. """ try: await self.initialize() From 76b191adf60ab43223c7245819813160df9f76b9 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 5 Oct 2023 20:13:38 +0530 Subject: [PATCH 4/6] remove useless list --- docs/source/conf.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index dc46d069c8d..5cc6d15b6cc 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -78,8 +78,6 @@ autodoc_typehints = "none" # Show docstring for special members -autodoc_special_members = ["__aenter__", "__aexit__"] - autodoc_default_options = { "special-members": True, "exclude-members": "__init__", From 4bb2108c944bc01b86bb4484cd3912a2090a2795 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 5 Oct 2023 21:23:51 +0530 Subject: [PATCH 5/6] fix sphinx --- docs/source/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 5cc6d15b6cc..9de40c67fb6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -85,6 +85,7 @@ # Fail on warnings & unresolved references etc nitpicky = True +nitpick_ignore = [("py:class", "type")] # Paramlink style paramlinks_hyperlink_param = "name" From 3ad33f064f15ffe924f7bfb0e7e39bf7b36fee28 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 5 Oct 2023 22:07:03 +0530 Subject: [PATCH 6/6] fix really (sphinx warnings weird) --- docs/source/conf.py | 1 - telegram/_bot.py | 2 +- telegram/ext/_application.py | 2 +- telegram/ext/_baseupdateprocessor.py | 2 +- telegram/ext/_updater.py | 2 +- telegram/request/_baserequest.py | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 9de40c67fb6..5cc6d15b6cc 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -85,7 +85,6 @@ # Fail on warnings & unresolved references etc nitpicky = True -nitpick_ignore = [("py:class", "type")] # Paramlink style paramlinks_hyperlink_param = "name" diff --git a/telegram/_bot.py b/telegram/_bot.py index a3669f40000..a798a2b39e7 100644 --- a/telegram/_bot.py +++ b/telegram/_bot.py @@ -320,7 +320,7 @@ async def __aenter__(self: BT) -> BT: Raises: :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. + is called in this case. """ try: await self.initialize() diff --git a/telegram/ext/_application.py b/telegram/ext/_application.py index 93151e00abf..99a5e32f328 100644 --- a/telegram/ext/_application.py +++ b/telegram/ext/_application.py @@ -354,7 +354,7 @@ async def __aenter__(self: _AppType) -> _AppType: # noqa: PYI019 Raises: :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. + is called in this case. """ try: await self.initialize() diff --git a/telegram/ext/_baseupdateprocessor.py b/telegram/ext/_baseupdateprocessor.py index efb89a7e53e..36807de0ac4 100644 --- a/telegram/ext/_baseupdateprocessor.py +++ b/telegram/ext/_baseupdateprocessor.py @@ -75,7 +75,7 @@ async def __aenter__(self) -> "BaseUpdateProcessor": Raises: :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case + is called in this case. """ try: await self.initialize() diff --git a/telegram/ext/_updater.py b/telegram/ext/_updater.py index 9f2789dd2bf..01d3ec524be 100644 --- a/telegram/ext/_updater.py +++ b/telegram/ext/_updater.py @@ -136,7 +136,7 @@ async def __aenter__(self: _UpdaterType) -> _UpdaterType: # noqa: PYI019 Raises: :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. + is called in this case. """ try: await self.initialize() diff --git a/telegram/request/_baserequest.py b/telegram/request/_baserequest.py index 488333447ff..39214c82079 100644 --- a/telegram/request/_baserequest.py +++ b/telegram/request/_baserequest.py @@ -108,7 +108,7 @@ async def __aenter__(self: RT) -> RT: Raises: :exc:`Exception`: If an exception is raised during initialization, :meth:`shutdown` - is called in this case. + is called in this case. """ try: await self.initialize()