Skip to content

Commit

Permalink
Add support to manage cookies
Browse files Browse the repository at this point in the history
- ``app/cookies``
- ``app/setCookies``
  • Loading branch information
rmartin16 committed Oct 19, 2024
1 parent 9a4094d commit 6deeca3
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 5 deletions.
14 changes: 12 additions & 2 deletions docs/source/apidoc/app.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ Application
.. autoclass:: qbittorrentapi.app.AppAPIMixIn
:members:
:undoc-members:
:exclude-members: app, application, app_webapiVersion, app_buildInfo, app_setPreferences, app_defaultSavePath, app_networkInterfaceAddressList, app_networkInterfaceList, app_sendTestEmail, app_getDirectoryContent
:exclude-members: app, application, app_webapiVersion, app_buildInfo, app_setPreferences, app_defaultSavePath, app_setCookies, app_networkInterfaceAddressList, app_networkInterfaceList, app_sendTestEmail, app_getDirectoryContent
:show-inheritance:

.. autoclass:: qbittorrentapi.app.Application
:members:
:undoc-members:
:exclude-members: app, application, webapiVersion, buildInfo, setPreferences, defaultSavePath, networkInterfaceAddressList, networkInterfaceList, sendTestEmail, getDirectoryContent
:exclude-members: app, application, webapiVersion, buildInfo, setPreferences, defaultSavePath, setCookies, networkInterfaceAddressList, networkInterfaceList, sendTestEmail, getDirectoryContent

.. autoclass:: qbittorrentapi.app.ApplicationPreferencesDictionary
:members:
Expand All @@ -27,6 +27,16 @@ Application
:undoc-members:
:show-inheritance:

.. autoclass:: qbittorrentapi.app.Cookie
:members:
:undoc-members:
:show-inheritance:

.. autoclass:: qbittorrentapi.app.CookieList
:members:
:undoc-members:
:show-inheritance:

.. autoclass:: qbittorrentapi.app.NetworkInterfaceList
:members:
:undoc-members:
Expand Down
4 changes: 4 additions & 0 deletions src/qbittorrentapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
AppAPIMixIn,
ApplicationPreferencesDictionary,
BuildInfoDictionary,
Cookie,
CookieList,
NetworkInterface,
NetworkInterfaceAddressList,
NetworkInterfaceList,
Expand Down Expand Up @@ -101,6 +103,8 @@
"BuildInfoDictionary",
"Client",
"Conflict409Error",
"Cookie",
"CookieList",
"FileError",
"Forbidden403Error",
"HTTP400Error",
Expand Down
77 changes: 75 additions & 2 deletions src/qbittorrentapi/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
from json import dumps
from logging import Logger, getLogger
from typing import Any, AnyStr, Iterable, Mapping, Union
from typing import Any, AnyStr, Iterable, Mapping, Sequence, Union

from qbittorrentapi.auth import AuthAPIMixIn
from qbittorrentapi.definitions import (
Expand Down Expand Up @@ -36,6 +36,17 @@ class BuildInfoDictionary(Dictionary[Union[str, int]]):
""" # noqa: E501


class Cookie(ListEntry):
"""Item in :class:`CookieList`"""


class CookieList(List[Cookie]):
"""Response for :meth:`~AppAPIMixIn.app_cookies`"""

def __init__(self, list_entries: ListInputT, client: AppAPIMixIn | None = None):
super().__init__(list_entries, entry_class=Cookie)


class NetworkInterface(ListEntry):
"""Item in :class:`NetworkInterfaceList`"""

Expand Down Expand Up @@ -139,7 +150,7 @@ def app_preferences(self, **kwargs: APIKwargsT) -> ApplicationPreferencesDiction

def app_set_preferences(
self,
prefs: Mapping[str, Any] | None = None,
prefs: ApplicationPreferencesDictionary | Mapping[str, Any] | None = None,
**kwargs: APIKwargsT,
) -> None:
"""
Expand Down Expand Up @@ -168,6 +179,53 @@ def app_default_save_path(self, **kwargs: APIKwargsT) -> str:

app_defaultSavePath = app_default_save_path

def app_cookies(self, **kwargs: APIKwargsT) -> CookieList:
"""Retrieve current cookies."""
return self._get_cast(
_name=APINames.Application,
_method="cookies",
response_class=CookieList,
version_introduced="2.11.3",
**kwargs,
)

def app_set_cookies(
self,
cookies: CookieList | Sequence[Mapping[str, str | int]] | None = None,
**kwargs: APIKwargsT,
) -> None:
"""
Set cookies.
.. highlight:: python
.. code-block:: python
cookies = [
{
'domain': 'example.com',
'path': '/example/path',
'name': 'cookie name',
'value': 'cookie value',
'expirationDate': 1729366667,
},
]
:param cookies: list of cookies to set
"""
data = {
# coerce to types that are known to be JSON serializable
"cookies": dumps(list(map(dict, cookies or ())), separators=(",", ":")),
}
self._post(
_name=APINames.Application,
_method="setCookies",
data=data,
version_introduced="2.11.3",
**kwargs,
)

app_setCookies = app_set_cookies

def app_network_interface_list(self, **kwargs: APIKwargsT) -> NetworkInterfaceList:
"""
The list of network interfaces on the host.
Expand Down Expand Up @@ -317,6 +375,21 @@ def default_save_path(self) -> str:

defaultSavePath = default_save_path

@property
def cookies(self) -> CookieList:
"""Implements :meth:`~AppAPIMixIn.app_cookies`."""
return self._client.app_cookies()

def set_cookies(
self,
cookies: CookieList | Sequence[Mapping[str, str | int]] | None = None,
**kwargs: APIKwargsT,
) -> None:
"""Implements :meth:`~AppAPIMixIn.app_set_cookies`."""
self._client.app_set_cookies(cookies=cookies, **kwargs)

setCookies = set_cookies

@property
def network_interface_list(self) -> NetworkInterfaceList:
"""Implements :meth:`~AppAPIMixIn.app_network_interface_list`."""
Expand Down
66 changes: 65 additions & 1 deletion tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import pytest

from qbittorrentapi import APINames
from qbittorrentapi import APINames, CookieList
from qbittorrentapi._attrdict import AttrDict
from qbittorrentapi.app import (
DirectoryContentList,
Expand Down Expand Up @@ -60,6 +60,9 @@ def test_preferences(client):
assert dht is not client.app.preferences.dht
client.app_set_preferences(prefs=dict(dht=dht))
assert dht is client.app.preferences.dht
before_prefs = client.app.preferences
client.app.set_preferences(client.app.preferences)
assert before_prefs == client.app.preferences


def test_default_save_path(client):
Expand All @@ -68,6 +71,67 @@ def test_default_save_path(client):
assert "download" in client.app.default_save_path.lower()


@pytest.mark.skipif_before_api_version("2.11.3")
@pytest.mark.parametrize(
"set_cookies_func",
[
"app_set_cookies",
"app_setCookies",
"app.set_cookies",
"app.setCookies",
],
)
def test_cookies(client, set_cookies_func):
client.func(set_cookies_func)()
assert client.app_cookies() == CookieList([])

cookie_one = {
"domain": "example.com",
"path": "/example/path",
"name": "cookie name",
"value": "cookie value",
"expirationDate": 1729366667,
}
cookie_two = {
"domain": "yahoo.jp",
"path": "/path",
"name": "name cookie",
"value": "value cookie",
"expirationDate": 1429366667,
}

client.app_set_cookies([cookie_two])
assert client.app.cookies == CookieList([cookie_one])

client.func(set_cookies_func)([cookie_two])
assert client.app.cookies == CookieList([cookie_two])

client.func(set_cookies_func)(CookieList([cookie_one, cookie_two]))
assert client.app.cookies == CookieList([cookie_one, cookie_two])

client.func(set_cookies_func)([])
assert client.app_cookies() == CookieList([])


@pytest.mark.skipif_after_api_version("2.11.3")
@pytest.mark.parametrize(
"set_cookies_func",
[
"app_set_cookies",
"app_setCookies",
"app.set_cookies",
"app.setCookies",
],
)
def test_cookies_not_implemented(client, set_cookies_func):
with pytest.raises(NotImplementedError):
_ = client.app_cookies()
with pytest.raises(NotImplementedError):
_ = client.app.cookies
with pytest.raises(NotImplementedError):
client.func(set_cookies_func)([])


@pytest.mark.skipif_before_api_version("2.3")
def test_network_interface_list(client):
assert isinstance(client.app_network_interface_list(), NetworkInterfaceList)
Expand Down

0 comments on commit 6deeca3

Please sign in to comment.