summaryrefslogtreecommitdiff
path: root/gamelocker/api.py
diff options
context:
space:
mode:
Diffstat (limited to 'gamelocker/api.py')
-rw-r--r--gamelocker/api.py376
1 files changed, 67 insertions, 309 deletions
diff --git a/gamelocker/api.py b/gamelocker/api.py
index 4595ce5..dee307d 100644
--- a/gamelocker/api.py
+++ b/gamelocker/api.py
@@ -1,6 +1,5 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
-# pylint: disable=too-few-public-methods,fixme
# TODO: generate documentation
"""
@@ -9,310 +8,10 @@ requests.api
This module implements the Gamelocker API.
"""
+import inspect
import requests
-
-
-class Utils(object):
- """Utility functions."""
-
- def search_dict(self, dic, attr, val):
- """Find a key-value pair recursively in a dictionary.
-
- :param dic: Dictionary to search.
- :type dic: dict
- :param attr: Key to look for.
- :type attr: str
- :param val: Value the key needs to have.
- :param val: object
- :returns: (bool) Whether the dictionary contains the pair.
- :rtype: bool
- """
- for key in dic:
- if isinstance(dic[key], dict):
- if self.search_dict(dic[key], attr, val):
- return True
- else:
- if key == attr and dic[key] == val:
- return True
-
- return False
-
-
-class Response(object):
- """A generic API response object.
-
- :param errors: `errors` as returned by the API.
- :param data: `errors` as returned by the API.
- :param links: `links` as returned by the API.
- :param included: `included` as returned by the API.
- :param raw: Raw response.
- :type raw: dict
- """
-
- def __init__(self, data):
- """Constructs a :class:`Response <Response>`.
-
- :param data: Dictionary from API response JSON.
- :type data: dict
- :return: :class:`Response <Response>` object
- :rtype: gamelocker.Response
- """
- if "errors" in data:
- self.errors = data["errors"]
- else:
- self.errors = None
- if "data" in data:
- self.data = data["data"]
- else:
- self.data = None
- if "links" in data:
- self.links = data["links"]
- else:
- self.links = None
- if "included" in data:
- self.included = data["included"]
- else:
- self.included = None
- self.raw = data
- if self.errors:
- raise AttributeError(
- "API returned errors: {errors}".format(
- errors=repr(self.errors)))
-
- def filter(self, fid, ftype):
- """Returns an element from `data` matching the criteria.
-
- :param fid: ID to look for.
- :type fid: str
- :param ftype: Obect type to look for.
- :type ftype: str
- :return: Element matching the filter criteria
- :rtype: dict
- """
- for include in self.included:
- if include["id"] == fid and include["type"] == ftype:
- return include
- for datum in self.data:
- if datum["id"] == fid and datum["type"] == ftype:
- return datum
-
- return None
-
-
-# TODO: implement a Matches.players()
-class Matches(object):
- """A collection of :class:`Match <Match>` objects.
-
- :param matches: A list of matches.
- :type matches: list
- :param length: The number of matches.
- :type length: int
- """
-
- def __init__(self, data, matches=None):
- """Constructs a :class:`Matches <Matches>`.
-
- :param data: API data.
- :type data: gamelocker.Response
- :param matches: (optional) List of matches to construct
- collection from. Overrides `data` matches.
- :type matches: list of :class:`Matches`
- :return: :class:`Matches <Matches>` object
- :rtype: gamelocker.Matches
- """
- self._data = data
- self.matches = []
- if matches is not None:
- self.matches = matches
- else:
- for match in self._data.data:
- self.matches.append(Match(self._data, match["id"]))
- self.length = len(self.matches)
-
- def __getitem__(self, key):
- return self.matches[key]
-
- def where(self, attribute, value):
- """Searches for matches where the condition is met.
-
- :param attribute: Attribute to look for.
- :type attribute: str
- :param value: Requested value for that attribute.
- :type value: str, int, object
- :return: Collection of :class:`Match` matching the criteria.
- :rtype: gamelocker.Matches
- """
- matches = []
- for match in self.matches:
- if match.has(attribute, value):
- matches.append(match)
- return Matches(self._data, matches)
-
-
-class Match(object):
- """A Match record.
-
- :param attributes: `attributes` as returned by the API.
- :param rosters: List of :class:`Roster <Roster>` objects
- related to the match.
- :type rosters: list
- """
-
- def __init__(self, data, mid):
- """Constructs a :class:`Match <Match>` from a :class:`Response`.
-
- :param data: API data.
- :type data: gamelocker.Response
- :param mid: Match ID.
- :type mid: str
- :return: :class:`Match <Match>` object
- :rtype: gamelocker.Match
- """
- self._data = data
- self._id = mid
- match = self._data.filter(mid, "match")
- self.attributes = match["attributes"]
- self.rosters = [Roster(self._data, r["id"])
- for r in match["relationships"]["rosters"]["data"]]
-
- # TODO refactor duplicated code
- def has(self, attribute, value, recurse=True):
- """Checks whether Match or (optionally) a child owns an `attribute`
- with `value`.
-
- :param attribute: Attribute to look for.
- :type attribute: str
- :param value: Requested value for that attribute.
- :type value: str, int, object
- :param recurse: Whether to search relationships or not.
- :type recurse: bool
- :return: bool
- :rtype: bool
- """
- if Utils().search_dict(self.attributes, attribute, value):
- return True
- if recurse:
- for roster in self.rosters:
- if roster.has(attribute, value):
- return True
-
- return False
-
-
-class Roster(object):
- """A Roster object.
-
- :param attributes: `attributes` as returned by the API.
- :param participants: List of :class:`Participant <Participant>` objects
- related to the roster.
- :type rosters: list
- """
-
- def __init__(self, data, rid):
- """Constructs a specified :class:`Roster <Roster>` from a :class:`Response`.
-
- :param data: API data.
- :type data: gamelocker.Response
- :param rid: Roster ID.
- :type rid: str
- :return: :class:`Roster <Roster>` object
- :rtype: gamelocker.Roster
- """
- self._data = data
- self._id = rid
- roster = self._data.filter(rid, "roster")
- self.attributes = roster["attributes"]
- self.participants = [
- Participant(self._data, p["id"])
- for p in roster["relationships"]["participants"]["data"]
- ]
-
- def has(self, attribute, value, recurse=True):
- """Checks whether Roster or (optionally) a child owns an `attribute`
- with `value`.
-
- :param attribute: Attribute to look for.
- :type attribute: str
- :param value: Requested value for that attribute.
- :type value: str, int, object
- :param recurse: Whether to search relationships or not.
- :type recurse: bool
- :return: bool
- :rtype: bool
- """
- if Utils().search_dict(self.attributes, attribute, value):
- return True
- if recurse:
- for participant in self.participants:
- if participant.has(attribute, value):
- return True
-
- return False
-
-
-class Participant(object):
- """A Participant object.
-
- :param attributes: `attributes` as returned by the API.
- :param player: :class:`Player <Player>` object related to the participant.
- :type player: gamelocker.Player
- """
-
- def __init__(self, data, pid):
- """Constructs a specified :class:`Participant <Participant>`
- from a :class:`Response`.
-
- :param data: API data.
- :type data: gamelocker.Response
- :param pid: Participant ID.
- :type pid: str
- :return: :class:`Participant <Participant>` object
- :rtype: gamelocker.Participant
- """
- self._data = data
- self._id = pid
- participant = self._data.filter(pid, "participant")
- self.attributes = participant["attributes"]
- self.player = Player(self._data,
- participant["relationships"]["player"]
- ["data"]["id"])
-
- def has(self, attribute, value):
- """Checks whether Participant or (optionally) owns an `attribute`
- with `value`.
-
- :param attribute: Attribute to look for.
- :type attribute: str
- :param value: Requested value for that attribute.
- :type value: str, int, object
- :return: bool
- :rtype: bool
- """
- if Utils().search_dict(self.attributes, attribute, value):
- return True
- return False
-
-
-class Player(object):
- """A Player object.
-
- :param attributes: `attributes` as returned by the API.
- """
-
- def __init__(self, data, pid):
- """Constructs a specified :class:`Player <Player>` from a :class:`Response`.
-
- :param data: API data.
- :type data: gamelocker.Response
- :param pid: Player ID.
- :type pid: str
- :return: :class:`Player <Player>` object
- :rtype: gamelocker.Player
- """
- self._data = data
- self._id = pid
- player = self._data.filter(pid, "player")
- self.attributes = player["attributes"]
+import requests_jwt
+import gamelocker.datatypes
class Gamelocker(object):
@@ -349,7 +48,9 @@ class Gamelocker(object):
"""Sends a GET request to the API endpoint.
:param method: Method to query.
+ :type method: str
:param params: (optional) Parameters to send.
+ :type params: dict
:return: Parsed JSON object.
:rtype: dict
"""
@@ -362,7 +63,44 @@ class Gamelocker(object):
headers=headers,
params=params)
http.raise_for_status()
- return Response(http.json())
+ return http.json()
+
+ def _get(self, endpoint, elid="", params=None):
+ """Returns an object or a list of objects from the API.
+
+ :param endpoint: API slug to use.
+ :type endpoint: str
+ :param elid: (optional) ID of the object to query for.
+ :type elid: str
+ :param params: (optional) Parameters to pass with the http request.
+ :type params: dict
+ :return: Data object.
+ :rtype: :class:`janus.DataMessage`
+ """
+ data = self._req(endpoint + "/" + elid, params=params)
+
+ # collect related data
+ includes = []
+ if "included" in data:
+ for incl in data["included"]:
+ element = gamelocker.datatypes.data_to_object(incl)
+ includes.append(element)
+
+ # main data object
+ if isinstance(data["data"], (list, tuple)):
+ elements = []
+ for dat in data["data"]:
+ element = gamelocker.datatypes.data_to_object(dat)
+ # link related data
+ element = gamelocker.datatypes.link_to_object(
+ element, includes)
+ elements.append(element)
+ return elements
+ else:
+ element = gamelocker.datatypes.data_to_object(data["data"])
+ # link related data
+ element = gamelocker.datatypes.link_to_object(element, includes)
+ return element
def vainglory(self):
"""Sets title to Vainglory.
@@ -374,12 +112,32 @@ class Gamelocker(object):
return self
def status(self):
- """Returns the API version.
+ """Returns the API status JSON string.
- :return: API version.
+ :return: API status JSON.
:rtype: str
"""
- return self._req("status").raw["version"]
+ return self._req("status")
+
+ def match(self, elid):
+ """Returns a match.
+
+ :param elid: ID of the match.
+ :type elid: str
+ :return: A match with the given ID.
+ :rtype: :class:`Match`
+ """
+ return self._get("matches", elid)
+
+ def player(self, elid):
+ """Returns a player.
+
+ :param elid: ID of the player.
+ :type elid: str
+ :return: A player with the given ID.
+ :rtype: :class:`Player`
+ """
+ return self._get("players", elid)
def matches(self, limit=None, offset=None, sort=None):
"""Returns a list of recent matches.
@@ -401,4 +159,4 @@ class Gamelocker(object):
params["page[offset]"] = offset
if sort: # TODO make this nice and usable
params["sort"] = sort
- return Matches(self._req("matches", params))
+ return self._get("matches", params=params)