Skip to content

Commit

Permalink
implement api/player/autocomplete (#48) (client.users.get_by_autocomp…
Browse files Browse the repository at this point in the history
…lete)

* implement api/player/autocomplete

* Autocomplete: rename `object`->`as_object` parameter and add optional `only_followed_players` parameter

* rename `get_player_by_autocomplete` -> `get_by_autocomplete`

* Implement test for `users.get_by_autocomplete`

* fix readme, create changelog entry

---------

Co-authored-by: Liaoshousan <[email protected]>
Co-authored-by: kraktus <[email protected]>
  • Loading branch information
3 people authored Oct 28, 2023
1 parent d607907 commit 8b8b8b0
Show file tree
Hide file tree
Showing 13 changed files with 286 additions and 22 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
=========

To be released
--------------

* Add `client.users.get_by_autocomplete`

Thanks to @handsamtw and @Anupya for their contributions to this release.

v0.13 (2023-09-29)
--------------------

Expand Down
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,5 +200,6 @@ Most of the API is available:
client.users.get_rating_history
client.users.get_crosstable
client.users.get_user_performance
client.users.get_by_autocomplete
Details for each function can be found in the `documentation <https://lichess-org.github.io/berserk/>`_.
4 changes: 3 additions & 1 deletion berserk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


from .clients import Client
from .types import Team, OpeningStatistic, PaginatedTeams
from .types import Team, OpeningStatistic, PaginatedTeams, LightUser, OnlineLightUser
from .session import TokenSession
from .session import Requestor
from .formats import JSON
Expand All @@ -23,6 +23,8 @@

__all__ = [
"Client",
"LightUser",
"OnlineLightUser",
"TokenSession",
"Team",
"PaginatedTeams",
Expand Down
28 changes: 26 additions & 2 deletions berserk/clients/users.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from __future__ import annotations

from typing import Iterator, Dict, List, Any
from typing import Iterator, Dict, List, Any, cast
from deprecated import deprecated

from .. import models
from .base import BaseClient
from ..formats import JSON_LIST, LIJSON, NDJSON
from ..types.common import PerfType
from ..types.common import OnlineLightUser, PerfType
from ..session import Params


Expand Down Expand Up @@ -55,6 +55,30 @@ def get_all_top_10(self) -> Dict[str, Any]:
path = "/api/player"
return self._r.get(path, fmt=LIJSON)

def get_by_autocomplete(
self,
partial_username: str,
only_followed_players: bool = False,
as_object: bool = False,
) -> List[str] | List[OnlineLightUser]:
"""Provides autocompletion options for an incomplete username.
:param partial_username: the beginning of a username, must provide >= 3 characters
:param only_followed_players: whether to return matching followed players only, if any exist
:param as_object: if false, returns an array of usernames else, returns an object with matching users
:return: followed players matching term if any, else returns other players. Requires OAuth.
"""
path = "/api/player/autocomplete"
params: Params = {
"term": partial_username,
"object": as_object,
"friend": only_followed_players,
}
response = self._r.get(path, fmt=LIJSON, params=params)
if as_object:
return cast(List[OnlineLightUser], response.get("result", []))
return cast(List[str], response)

def get_leaderboard(self, perf_type: PerfType, count: int = 10):
"""Get the leaderboard for one speed or variant.
Expand Down
4 changes: 3 additions & 1 deletion berserk/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from .account import AccountInformation, Perf, Preferences, Profile, StreamerInfo
from .bulk_pairings import BulkPairing, BulkPairingGame
from .common import ClockConfig
from .common import ClockConfig, LightUser, OnlineLightUser
from .opening_explorer import (
OpeningExplorerRating,
OpeningExplorerVariant,
Expand All @@ -16,6 +16,8 @@
"BulkPairing",
"BulkPairingGame",
"ClockConfig",
"LightUser",
"OnlineLightUser",
"OpeningExplorerRating",
"OpeningExplorerVariant",
"OpeningStatistic",
Expand Down
25 changes: 23 additions & 2 deletions berserk/types/common.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from __future__ import annotations

from typing import Union
from typing import Union, Literal

from typing_extensions import Literal, TypedDict, TypeAlias
from typing_extensions import Literal, TypedDict, TypeAlias, NotRequired


class ClockConfig(TypedDict):
Expand All @@ -26,6 +26,27 @@ class ClockConfig(TypedDict):
"fromPosition",
]

Title = Literal[
"GM", "WGM", "IM", "WIM", "FM", "WFM", "NM", "CM", "WCM", "WNM", "LM", "BOT"
]


class LightUser(TypedDict):
# The id of the user
id: str
# The name of the user
name: str
# The title of the user
title: NotRequired[Title]
# The patron of the user
patron: NotRequired[bool]


class OnlineLightUser(LightUser):
# Whether the user is online
online: NotRequired[bool]


Variant: TypeAlias = Union[GameType, Literal["standard"]]

PerfType: TypeAlias = Union[
Expand Down
17 changes: 2 additions & 15 deletions berserk/types/team.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from __future__ import annotations

from typing import Literal, List
from typing import List
from typing_extensions import TypedDict, NotRequired

Title = Literal[
"GM", "WGM", "IM", "WIM", "FM", "WFM", "NM", "CM", "WCM", "WNM", "LM", "BOT"
]
from .common import LightUser


class Team(TypedDict):
Expand All @@ -29,17 +27,6 @@ class Team(TypedDict):
requested: NotRequired[bool]


class LightUser(TypedDict):
# The id of the user
id: str
# The name of the user
name: str
# The title of the user
title: NotRequired[Title]
# The patron of the user
patron: NotRequired[bool]


class PaginatedTeams(TypedDict):
# The current page
currentPage: int
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
interactions:
- request:
body: null
headers:
Accept:
- application/vnd.lichess.v3+json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.31.0
method: GET
uri: https://lichess.org/api/player/autocomplete?term=thisisatest&object=False&friend=False
response:
body:
string: '["thisisatest","thisisatesty","thisisatest24","thisisatesttt","thisisatest333","thisisatest666","thisisatest1234","thisisatest8083","thisisatest12345","thisisatestlololol","thisisatestaccount13"]'
headers:
Access-Control-Allow-Headers:
- Origin, Authorization, If-Modified-Since, Cache-Control, Content-Type
Access-Control-Allow-Methods:
- OPTIONS, GET, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Type:
- application/json
Date:
- Sat, 28 Oct 2023 17:17:24 GMT
Permissions-Policy:
- interest-cohort=()
Server:
- nginx
Strict-Transport-Security:
- max-age=63072000; includeSubDomains; preload
Transfer-Encoding:
- chunked
Vary:
- Origin
X-Frame-Options:
- DENY
content-length:
- '195'
status:
code: 200
message: OK
version: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
interactions:
- request:
body: null
headers:
Accept:
- application/vnd.lichess.v3+json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.31.0
method: GET
uri: https://lichess.org/api/player/autocomplete?term=thisisatest&object=True&friend=False
response:
body:
string: '{"result":[{"name":"Thisisatest","id":"thisisatest"},{"name":"thisisatesty","id":"thisisatesty"},{"name":"thisisatest24","id":"thisisatest24"},{"name":"Thisisatesttt","id":"thisisatesttt"},{"name":"thisisatest333","id":"thisisatest333"},{"name":"thisisatest666","id":"thisisatest666"},{"name":"Thisisatest1234","id":"thisisatest1234"},{"name":"thisisatest8083","id":"thisisatest8083"},{"name":"ThisIsATest12345","id":"thisisatest12345"},{"name":"thisisatestlololol","id":"thisisatestlololol"},{"name":"thisisatestaccount13","id":"thisisatestaccount13"}]}'
headers:
Access-Control-Allow-Headers:
- Origin, Authorization, If-Modified-Since, Cache-Control, Content-Type
Access-Control-Allow-Methods:
- OPTIONS, GET, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Type:
- application/json
Date:
- Sat, 28 Oct 2023 17:17:23 GMT
Permissions-Policy:
- interest-cohort=()
Server:
- nginx
Strict-Transport-Security:
- max-age=63072000; includeSubDomains; preload
Transfer-Encoding:
- chunked
Vary:
- Origin
X-Frame-Options:
- DENY
content-length:
- '554'
status:
code: 200
message: OK
version: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
interactions:
- request:
body: null
headers:
Accept:
- application/vnd.lichess.v3+json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.31.0
method: GET
uri: https://lichess.org/api/player/autocomplete?term=username_not_found__&object=True&friend=False
response:
body:
string: '{"result":[]}'
headers:
Access-Control-Allow-Headers:
- Origin, Authorization, If-Modified-Since, Cache-Control, Content-Type
Access-Control-Allow-Methods:
- OPTIONS, GET, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Length:
- '13'
Content-Type:
- application/json
Date:
- Sat, 28 Oct 2023 19:26:35 GMT
Permissions-Policy:
- interest-cohort=()
Server:
- nginx
Strict-Transport-Security:
- max-age=63072000; includeSubDomains; preload
Vary:
- Origin
X-Frame-Options:
- DENY
status:
code: 200
message: OK
version: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
interactions:
- request:
body: null
headers:
Accept:
- application/vnd.lichess.v3+json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
User-Agent:
- python-requests/2.31.0
method: GET
uri: https://lichess.org/api/player/autocomplete?term=username_not_found__&object=False&friend=False
response:
body:
string: '[]'
headers:
Access-Control-Allow-Headers:
- Origin, Authorization, If-Modified-Since, Cache-Control, Content-Type
Access-Control-Allow-Methods:
- OPTIONS, GET, POST, PUT, DELETE
Access-Control-Allow-Origin:
- '*'
Connection:
- keep-alive
Content-Length:
- '2'
Content-Type:
- application/json
Date:
- Sat, 28 Oct 2023 19:26:34 GMT
Permissions-Policy:
- interest-cohort=()
Server:
- nginx
Strict-Transport-Security:
- max-age=63072000; includeSubDomains; preload
Vary:
- Origin
X-Frame-Options:
- DENY
status:
code: 200
message: OK
version: 1
31 changes: 31 additions & 0 deletions tests/clients/test_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest

from berserk import Client, OnlineLightUser
from typing import List, Dict
from utils import validate, skip_if_older_3_dot_10


class TestLichessGames:
@skip_if_older_3_dot_10
@pytest.mark.vcr
def test_get_by_autocomplete_as_object(self):
res = Client().users.get_by_autocomplete("thisisatest", as_object=True)
validate(List[OnlineLightUser], res)

@skip_if_older_3_dot_10
@pytest.mark.vcr
def test_get_by_autocomplete(self):
res = Client().users.get_by_autocomplete("thisisatest")
validate(List[str], res)

@skip_if_older_3_dot_10
@pytest.mark.vcr
def test_get_by_autocomplete_not_found(self):
res = Client().users.get_by_autocomplete("username_not_found__")
validate(List[str], res)

@skip_if_older_3_dot_10
@pytest.mark.vcr
def test_get_by_autocomplete_as_object_not_found(self):
res = Client().users.get_by_autocomplete("username_not_found__", as_object=True)
validate(List[OnlineLightUser], res)
Loading

0 comments on commit 8b8b8b0

Please sign in to comment.