Skip to content

Commit

Permalink
Improve docs for new methods
Browse files Browse the repository at this point in the history
Document new methods and update other documentation to use new methods.
  • Loading branch information
tylertian123 committed Oct 1, 2020
1 parent d4e36bd commit b0e9bb4
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 44 deletions.
10 changes: 3 additions & 7 deletions docs/_snippets/frontpage1.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async def main():
await my_friend.send_message("hello there")

# connect to the websockets interface
async with ryver.get_live_session() as session:
async with ryver.get_live_session(auto_reconnect=True) as session:
@session.on_chat
async def on_message(msg: pyryver.WSChatMessageData):
print(msg.text) # print out the message's text
Expand All @@ -25,12 +25,8 @@ async def on_message(msg: pyryver.WSChatMessageData):
# This could be either a user (for a private message) or a forum/team
chat = ryver.get_chat(jid=msg.to_jid)
await chat.send_message("hi")

@session.on_connection_loss
async def on_connection_loss():
await session.close()

# run until session.close() is called

# run until session.terminate() is called
await session.run_forever()

asyncio.get_event_loop().run_until_complete(main())
4 changes: 2 additions & 2 deletions docs/_snippets/quickstart5.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async def on_chat(msg: pyryver.WSChatMessageData):

@session.on_connection_loss
async def on_connection_loss():
# Make sure that the session is closed and run_forever() returns on connection loss
await session.close()
# Make sure that the session is terminated and run_forever() returns on connection loss
await session.terminate()

await session.run_forever()
19 changes: 16 additions & 3 deletions docs/api_realtime.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,36 @@ Realtime Client

.. automethod:: send_presence_change

.. automethod:: is_connected
.. automethod:: set_auto_reconnect

.. automethod:: run_forever
.. automethod:: terminate

.. note::
If you use this class as an ``async with`` context manager, you don't need to call
these two methods, unless you want to break out of a `RyverWS.run_forever()`.
the following two methods.

.. automethod:: start
.. automethod:: close

.. automethod:: run_forever

.. autoclass:: RyverWSTyping
:members:
:undoc-members:


.. autoclass:: WSConnectionError
:members:
:show-inheritance:

.. autoclass:: ClosedError
:members:
:show-inheritance:

.. autoclass:: ConnectionLossError
:members:
:show-inheritance:


Callback Task Data Types
------------------------
Expand Down
4 changes: 2 additions & 2 deletions docs/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ This is because the websocket system uses JIDs to refer to chats. Using this inf
If you still wish to access the raw data of the message, all message objects passed to callbacks have a ``raw_data`` attribute that contains the dict. In v0.3.2, ``__getitem__()`` was implemented for message objects
to directly access the ``raw_data`` dict, providing (partial) backwards compatibility.

Here we also added a connection loss handler with the `pyryver.ryver_ws.RyverWS.on_connection_loss()` decorator. The connection loss handler closes the session, which causes ``run_forever()`` to terminate, allowing the program to
exit on connection loss instead of waiting forever. It is recommended to always have a connection loss handler if you're using ``run_forever()``.
Here we also added a connection loss handler with the `pyryver.ryver_ws.RyverWS.on_connection_loss()` decorator. The connection loss handler calls ``terminate()``, which causes ``run_forever()`` to return, allowing the program to
exit on connection loss instead of waiting forever. Alternatively, you could also make the session auto-reconnect by doing `ryver.get_live_session(auto_reconnect=True)` when starting the session.

It's important to note here that although the non-realtime API is perfectly accessible (and sometimes necessary) to use in event callbacks, it's often faster to use corresponding methods in the `pyryver.ryver_ws.RyverWS` instance
whenever possible. For some ephemeral actions like typing indicators and presence statuses, the realtime API is the *only* way to accomplish certain tasks.
Expand Down
6 changes: 3 additions & 3 deletions pyryver/ryver.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def get_user(self, **kwargs) -> User:
try:
return get_obj_by_field(self.users, FIELD_NAMES[field], value, case_sensitive)
except KeyError:
raise ValueError("Invalid query parameter!")
raise ValueError("Invalid query parameter!") # pylint: disable=raise-missing-from

def get_groupchat(self, **kwargs) -> GroupChat:
"""
Expand Down Expand Up @@ -318,7 +318,7 @@ def get_groupchat(self, **kwargs) -> GroupChat:
try:
return get_obj_by_field(self.forums + self.teams, FIELD_NAMES[field], value, case_sensitive)
except KeyError:
raise ValueError("Invalid query parameter!")
raise ValueError("Invalid query parameter!") # pylint: disable=raise-missing-from

def get_chat(self, **kwargs) -> Chat:
"""
Expand Down Expand Up @@ -350,7 +350,7 @@ def get_chat(self, **kwargs) -> Chat:
try:
return get_obj_by_field(self.forums + self.teams + self.users, FIELD_NAMES[field], value, case_sensitive)
except KeyError:
raise ValueError("Invalid query parameter!")
raise ValueError("Invalid query parameter!") # pylint: disable=raise-missing-from

async def get_notifs(self, unread: bool = False, top: int = -1, skip: int = 0) -> typing.AsyncIterator[Notification]:
"""
Expand Down
62 changes: 36 additions & 26 deletions pyryver/ryver_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ async def _typing_task(self):
except asyncio.CancelledError:
await self._rws.send_clear_typing(self._to)

def start(self):
def start(self) -> None:
"""
Start sending the typing indicator.
"""
self._typing_task_handle = asyncio.ensure_future(self._typing_task())

async def stop(self):
async def stop(self) -> None:
"""
Stop sending the typing indicator.
Expand Down Expand Up @@ -228,7 +228,6 @@ def set_auto_reconnect(self, auto_reconnect: bool) -> None:
"""
Set whether the live session should attempt to auto-reconnect on connection loss.
TODO
:param auto_reconnect: Whether to automatically reconnect.
"""
self._auto_reconnect = auto_reconnect
Expand Down Expand Up @@ -422,17 +421,19 @@ def on_connection_loss(self, func: typing.Callable[[], typing.Awaitable]):
every 10 seconds, and if the response takes over 5 seconds, this coroutine will
be started. (These numbers roughly match those used by the official web client.)
Applications are suggested to clean up and terminate immediately when the
connection is lost, especially when using :py:meth:`RyverWS.run_forever()`.
A simple but typical implementation is shown below:
TODO: Update
If auto-reconnect is enabled, no action needs to be taken. Otherwise,
applications are suggested to clean up and terminate, or try to reconnect using
:py:meth:`RyverWS.try_reconnect()`. If :py:meth:`RyverWS.run_forever()` is used,
:py:meth:`RyverWS.terminate()` should be called to make it return, unless you
wish to reconnect.
A simple but typical implementation is shown below for applications that do not
wish to recover:
.. code-block:: python
async with ryver.get_live_session() as session:
@session.on_connection_loss
async def on_connection_loss():
await session.close()
await session.terminate()
"""
self._on_connection_loss = func
return func
Expand Down Expand Up @@ -497,7 +498,7 @@ def _on_msg_type_inner(func: typing.Callable[[WSMessageData], typing.Awaitable])
return func
return _on_msg_type_inner

async def send_chat(self, to_chat: typing.Union[Chat, str], msg: str):
async def send_chat(self, to_chat: typing.Union[Chat, str], msg: str) -> None:
"""
Send a chat message to a chat.
Expand All @@ -512,7 +513,7 @@ async def send_chat(self, to_chat: typing.Union[Chat, str], msg: str):
}
return await self._ws_send_msg(data)

async def send_presence_change(self, presence: str):
async def send_presence_change(self, presence: str) -> None:
"""
Send a presence change message.
Expand All @@ -526,7 +527,7 @@ async def send_presence_change(self, presence: str):
"presence": presence,
})

async def send_typing(self, to_chat: typing.Union[Chat, str]):
async def send_typing(self, to_chat: typing.Union[Chat, str]) -> None:
"""
Send a typing indicator to a chat.
Expand All @@ -547,7 +548,7 @@ async def send_typing(self, to_chat: typing.Union[Chat, str]):
"to": to_chat.get_jid() if isinstance(to_chat, Chat) else to_chat
})

async def send_clear_typing(self, to_chat: typing.Union[Chat, str]):
async def send_clear_typing(self, to_chat: typing.Union[Chat, str]) -> None:
"""
Clear the typing indicator for a chat.
Expand Down Expand Up @@ -581,7 +582,7 @@ def typing(self, to_chat: Chat) -> RyverWSTyping:
"""
return RyverWSTyping(self, to_chat)

async def start(self, timeout: float = None):
async def start(self, timeout: float = None) -> None:
"""
Start the session, or reconnect after a connection loss.
Expand Down Expand Up @@ -637,15 +638,20 @@ async def try_reconnect(self, timeout: float = None) -> bool:
except (aiohttp.ClientConnectionError, aiohttp.ClientResponseError, asyncio.TimeoutError):
return False

async def close(self, cancel_rx: bool = True, cancel_ping: bool = True):
async def close(self, cancel_rx: bool = True, cancel_ping: bool = True) -> None:
"""
Close the session.
Any future operation after closing will result in a :py:exc:`ClosedError` being
raised, unless the session is reconnected using :py:meth:`RyverWS.start()` or
:py:meth:`RyverWS.try_reconnect()`.
TODO: Clarify terminate()
When used as an async context manager, this method does not need to be called.
.. note::
Since v0.4.0, this method no longer causes :py:meth:`RyverWS.run_forever()` to
return. Use :py:meth:`RyverWS.terminate()` if you want to close the session
and exit ``run_forever()``.
:param cancel_rx: Whether to cancel the rx task. For internal use only.
:param cancel_ping: Whether to cancel the ping task. For internal use only.
Expand All @@ -669,26 +675,30 @@ async def close(self, cancel_rx: bool = True, cancel_ping: bool = True):
elif cancel_ping:
await self._ping_task_handle

async def terminate(self):
async def terminate(self) -> None:
"""
TODO
Close the session and cause :py:meth:`RyverWS.run_forever()` to return.
This method will have no effect if called twice.
"""
if not self._closed:
await self.close()
if not self._done.done():
self._done.set_result(None)

async def run_forever(self):
async def run_forever(self) -> None:
"""
Run forever, or until the connection is closed explicitly.
Run forever, or until :py:meth:`RyverWS.terminate()` is called.
TODO: Update
.. note::
Since v0.4.0, this method will no longer return if :py:meth:`RyverWS.close()`
is called. :py:meth:`RyverWS.terminate()` must be called instead, which closes
the session if it is unclosed.
.. note::
By default, when the connection is lost, the session will *not* be
automatically closed. As a result, if no action is taken, this coroutine will
*not* exit on a connection loss. :py:meth:`RyverWS.close()` needs to be called
explicitly to make this coroutine return.
By default, this method will only return if a fatal connection loss occurs and
auto-reconnect is not enabled. If the connection loss is recoverable, this
method will not return even if auto-reconnect is off.
You should use the :py:meth:`RyverWS.on_connection_loss()` decorator if you want
to automatically close the connection and return on connection loss. See its
Expand All @@ -698,7 +708,7 @@ async def run_forever(self):
await self._done

@staticmethod
def _create_id():
def _create_id() -> str:
"""
Create a random message ID.
Expand Down
2 changes: 1 addition & 1 deletion pyryver/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
this way the version can be obtained without having to import everything else, which may
not be possible due to missing dependencies, thus breaking `setup.py install`.
"""
__version__ = "0.3.3"
__version__ = "0.4.0a0"

0 comments on commit b0e9bb4

Please sign in to comment.