# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
-import os
+import pathlib
import sys
-sys.path.insert(0, os.path.abspath('../../'))
+sys.path.insert(0, pathlib.Path(__file__).parents[2].resolve().as_posix())
from mpdaio.const import VERSION
project = 'musicpdaio'
.. _python-musicpd: https://kaliko.gitlab.io/python-musicpd
.. _Semantic Versioning: https://semver.org/spec/v2.0.0.html
.. _snake case: https://en.wikipedia.org/wiki/Snake_case
-
+.. |mpdaio.MPDClient| replace:: :py:class:`mpdaio.MPDClient<mpdaio.client.MPDClient>`
"""
+autodoc_typehints = 'description'
+autodoc_member_order = 'bysource'
+
# -- Options for intersphinx extension ---------------------------------------
# https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#configuration
command with optional arguments. In the example above the client sends a
`setvol` command with the string argument `42`.
-MPD commands are exposed as :py:class:`mpdaio.MPDClient` methods. Methods
+MPD commands are exposed as |mpdaio.MPDClient| methods. Methods
**arguments are python strings**. Some commands are composed of more than one word
(ie "**tagtypes [disable|enable|all]**"), for these use a `snake case`_ style to
access the method. Then **"tagtypes enable"** command is called with
written to the socket. To avoid confusion use regular string instead of relying
on object string representation.
-:py:class:`mpdaio.MPDClient` methods returns different kinds of objects
+|mpdaio.MPDClient| methods returns different kinds of objects
depending on the command. Could be :py:obj:`None`, a single object as a
:py:obj:`str` or a :py:obj:`dict`, a list of :py:obj:`dict`.
-Then :py:class:`mpdaio.MPDClient` **methods signatures** are not hard coded
+Then |mpdaio.MPDClient| **methods signatures** are not hard coded
within this module since the protocol is handled on the server side. Please
refer to the protocol and MPD commands in `MPD protocol documentation`_ to
learn how to call commands and what kind of arguments they expect.
Some examples are provided for the most common cases, see :ref:`tutorial`.
**musicpdaio** tries to come with sane defaults, then running
-:py:class:`mpdaio.MPDClient` with no explicit argument will try default values
+|mpdaio.MPDClient| with no explicit argument will try default values
to connect to MPD. Cf. :ref:`reference` for more about
:ref:`defaults<default_settings>`.
**musicpdaio** uses a connection pool internally to keep already opened socket
and reuse it.
-When first instantiated :py:class:`mpdaio.MPDClient` comes with an empty pool,
+When first instantiated |mpdaio.MPDClient| comes with an empty pool,
when the first MPD command is called a connection is opened, saved and
potentially reused later. In case a concurrent MPD command is called while the
connection is still in use a new connection is made and kept in the pool.
Environment variables
---------------------
-:py:class:`mpdaio.MPDClient` honors the following environment variables:
+:py:class:`mpdaio.MPDClient<mpdaio.client.MPDClient>` honors the following environment variables:
.. envvar:: MPD_HOST
* use :envvar:`MPD_TIMEOUT` if set
* else use :py:obj:`mpdaio.const.CONNECTION_TIMEOUT`
-
Supported commands
------------------
.. include:: commands.rst
+
+Module documentation
+--------------------
+
+MPDClient class
+^^^^^^^^^^^^^^^
+
+.. automodule:: mpdaio.client
+ :members:
+
+Constants
+^^^^^^^^^
+
+.. automodule:: mpdaio.const
+ :members:
+
+.. vim: spell spelllang=en
.. index:: single: command; password
+**musicpdaio** tries to come with sane defaults, then running
+:py:class:`mpdaio.MPDClient` with no explicit argument will try default values
+to connect to MPD. Cf. :ref:`reference` for more about
+:ref:`defaults<default_settings>`.
+
**Using a specific host, port and a password.**
-The password is sent when a connection is made, no need to explicitly send the
-password command.
+The password is sent when a connection is made, no need to explicitly use the
+password command. In the following code a client is constructed with a password argument, then when the ping method is called:
+ * the client fetch a connection from the pool
+ * then a password command is sent with the password
+ * finally the ping command is sent.
.. sourcecode:: python
class MPDClient:
+ """:synopsis: Main class to instanciate building an MPD client.
- def __init__(self, host: str | None = None, port: str | int | None = None, password: str | None = None):
+ :param host: MPD server IP|FQDN to connect to
+ :param port: MPD port to connect to
+ :param password: MPD password
+
+ **musicpdaio** tries to come with sane defaults, then running
+ |mpdaio.MPDClient| with no explicit argument will try default values
+ to connect to MPD. Cf. :ref:`reference` for more about
+ :ref:`defaults<default_settings>`.
+
+ The class is also exposed in mpdaio namespace.
+
+ >>> import mpdaio
+ >>> cli = mpdaio.MPDClient(host='example.org')
+ >>> print(await cli.currentsong())
+ >>> await cli.close()
+ """
+
+ def __init__(self, host: str | None = None,
+ port: str | int | None = None,
+ password: str | None = None):
+ #: Connection pool
self._pool = ConnectionPool(max_connections=CONNECTION_MAX)
self._get_envvars()
- #: host used with the current connection (:py:obj:`str`)
+ #: Host used to make connections (:py:obj:`str`)
self.host = host or self.server_discovery[0]
- #: password detected in :envvar:`MPD_HOST` environment variable (:py:obj:`str`)
+ #: password used to connect (:py:obj:`str`)
self.pwd = password or self.server_discovery[2]
#: port used with the current connection (:py:obj:`int`, :py:obj:`str`)
self.port = port or self.server_discovery[1]
+ #: connection timeout
self.mpd_timeout = CONNECTION_TIMEOUT
log.info('Using %s:%s to connect', self.host, self.port)
return lambda *args: wrapper(command, args)
@property
- def version(self):
- """MPD protocol version"""
+ def version(self) -> str:
+ """MPD protocol version
+ """
host = (self.host, self.port)
version = {_.version for _ in self.connections}
if not version:
return version.pop()
@property
- def connections(self):
- """Open connections"""
+ def connections(self) -> list[Connection]:
+ """connections in the pool"""
host = (self.host, self.port)
return self._pool._connections.get(host, [])
- async def close(self):
+ async def close(self) -> None:
+ """:synopsis: Close connections in the pool"""
await self._pool.close()
ERROR_PREFIX = 'ACK '
SUCCESS = 'OK'
NEXT = 'list_OK'
-#: Module version
VERSION = '0.1.0b0'
#: Seconds before a connection attempt times out
#: (overriden by :envvar:`MPD_TIMEOUT` env. var.)