summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md5
-rw-r--r--gamelocker/api.py21
-rw-r--r--gamelocker/strings.py193
-rw-r--r--tests/gamelocker_test.py95
4 files changed, 76 insertions, 238 deletions
diff --git a/README.md b/README.md
index ed87d78..be279c2 100644
--- a/README.md
+++ b/README.md
@@ -24,3 +24,8 @@ Example usage:
```
[More examples](/examples)
+
+Running the tests:
+```bash
+GAMELOCKER_APIKEY=your.api.key PYTHONPATH=. python -m pytest tests
+```
diff --git a/gamelocker/api.py b/gamelocker/api.py
index 93b1068..8753cce 100644
--- a/gamelocker/api.py
+++ b/gamelocker/api.py
@@ -6,9 +6,9 @@ gamelocker.api
This module implements the Gamelocker API.
"""
+import logging
import requests
import gamelocker.datatypes
-import gamelocker.strings
class Gamelocker(object):
@@ -41,13 +41,19 @@ class Gamelocker(object):
:rtype: dict
"""
headers = {
- "Authorization": "Bearer " + self.apikey,
+ "Authorization": self.apikey,
"X-TITLE-ID": self.title,
"Accept": "application/vnd.api+json"
}
- http = requests.get(self._apiurl + method,
- headers=headers,
- params=params)
+ while True:
+ http = requests.get(self._apiurl + method,
+ headers=headers,
+ params=params)
+ if http.status_code != 429:
+ # 429 -> rate limit, retry
+ break
+ logging.info("You are being rate limited by the API")
+
http.raise_for_status()
return http.json()
@@ -137,7 +143,7 @@ class Gamelocker(object):
See http://developer.vainglorygame.com/docs/#get-a-collection-of-matches
for parameters.
- :param params: (optional) Query parameters.
+ :param params: Query parameters.
:type params: dict
:param region: (optional) Shard to query. Defaults to "na".
:type region: str
@@ -145,6 +151,3 @@ class Gamelocker(object):
:rtype: list of dict
"""
return self._get("matches", params=params, region=region)
-
-
-pretty = gamelocker.strings.pretty
diff --git a/gamelocker/strings.py b/gamelocker/strings.py
deleted file mode 100644
index 6733005..0000000
--- a/gamelocker/strings.py
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-# pylint: disable=invalid-name,missing-docstring
-"""
-gamelocker.strings
-
-(internal) A collection of mappings between strings returned by the API
-and their common names.
-Currently Vainglory-specific only.
-"""
-
-
-# TODO
-class VaingloryStrings(object):
- heroes = {
- "*Adagio*": "Adagio",
- "*Alpha*": "Alpha",
- "*Ardan*": "Ardan",
- "*Baron*": "Baron",
- "*Blackfeather*": "Blackfeather",
- "*Catherine*": "Catherine",
- "*Celeste*": "Celeste",
- "*Flicker*": "Flicker",
- "*Fortress*": "Fortress",
- "*Glaive*": "Glaive",
- "*Gwen*": "Gwen",
- "*Hero009*": "Krul",
- "*Hero010*": "Skaarf",
- "*Hero016*": "Rona",
- "*Idris*": "Idris",
- "*Joule*": "Joule",
- "*Kestrel*": "Kestrel",
- "*Koshka*": "Koshka",
- "*Lance*": "Lance",
- "*Lyra*": "Lyra",
- "*Ozo*": "Ozo",
- "*Petal*": "Petal",
- "*Phinn*": "Phinn",
- "*Reim*": "Reim",
- "*Ringo*": "Ringo",
- "*Samuel*": "Samuel",
- "*SAW*": "SAW",
- "*Sayoc*": "Taka",
- "*Skye*": "Skye",
- "*Vox*": "Vox"
- }
-
- items = {
- "Aftershock": "Aftershock",
- "Armor2": "Coat of Plates",
- "Armor3": "Metal Jacket",
- "Armor Shredder": "Bonesaw",
- "Atlas Pauldron": "Atlas Pauldron",
- "AttackSpeed1": "Swift Shooter",
- "AttackSpeed2": "Blazing Salvo",
- "BarbedNeedle": "Barbed Needle",
- "Boots1": "Sprint Boots",
- "Boots2": "Travel Boots",
- "Boots3": "Journey Boots",
- "BreakingPoint": "Breaking Point",
- "Broken Myth": "Broken Myth",
- "Clockwork": "Clockwork",
- "Cogwheel": "Chronograph",
- "Contraption": "Contraption",
- "Cooldown1": "Hourglass",
- "Critical": "Tyrant's Monocle",
- "Crucible": "Crucible",
- "Crystal1": "Crystal Bit",
- "Crystal2": "Eclipse Prism",
- "Crystal3": "Shatterglass",
- "Crystal Matrix": "Aegis",
- "Echo": "Echo",
- "EveOfHarvest": "Eve of Harvest",
- "Flare": "Flare",
- "Flaregun": "Flare Gun",
- "Fountain of Renewal": "Fountain of Renewal",
- "Frostburn": "Frostburn",
- "Halcyon Chargers": "Halcyon Chargers",
- "Health2": "Dragonheart",
- "Heavy Prism": "Heavy Prism",
- "Heavy Steel": "Heavy Steel",
- "IronguardContract": "Ironguard Contract",
- "Lifewell": "Lifespring",
- "Light Armor": "Light Armor",
- "Light Shield": "Light Shield",
- "LuckyStrike": "Lucky Strike",
- "Minion Candy": "Minion Candy",
- "MinionsFoot": "Minion's Foot",
- "Mulled Wine": "Halcyon Potion",
- "NullwaveGauntlet": "Nullwave Gauntlet",
- "Oakheart": "Oakheart",
- "PiercingShard": "Piercing Shard",
- "PiercingSpear": "Piercing Spear",
- "PoisonedShiv": "Poisoned Shiv",
- "Protector Contract": "Protector Contract",
- "Reflex Block": "Reflex Block",
- "Scout Trap": "Scout Trap",
- "Serpent Mask": "Serpent Mask",
- "Shield 2": "Kinetic Shield",
- "Shiversteel": "Shiversteel",
- "Six Sins": "Six Sins",
- "SlumberingHusk": "Slumbering Husk",
- "Steam Battery": "Energy Battery",
- "Stormcrown": "Stormcrown",
- "StormguardBanner": "Stormguard Banner",
- "Tension Bow": "Tension Bow",
- "Tornado Trigger": "Tornado Trigger",
- "Void Battery": "Void Battery",
- "War Treads": "War Treads",
- "Weapon3": "Sorrowblade",
- "Weapon Blade": "Weapon Blade"
- }
-
- item_ids = {
- "*1000_Item_HalcyonPotion*": "Halcyon Potion",
- "*1002_Item_WeaponBlade*": "Weapon Blade",
- "*1003_Item_CrystalBit*": "Crystal Bit",
- "*1004_Item_SwiftShooter*": "Swift Shooter",
- "*1005_Item_SixSins*": "Six Sins",
- "*1009_Item_EclipsePrism*": "Eclipse Prism",
- "*1010_Item_BlazingSalvo*": " Blazing Salvo",
- "*1012_Item_Sorrowblade*": "Sorrowblade",
- "*1013_Item_Shatterglass*": "Shatterglass",
- "*1014_Item_TornadoTrigger*": "Tornado Trigger",
- "*1015_Item_Oakheart*": "Oakheart",
- "*1016_Item_Dragonheart*": "Dragonheart",
- "*1017_Item_LightArmor*": "Light Armor",
- "*1022_Item_CoatOfPlates*": "Coat of Plates",
- "*1024_Item_MetalJacket*": "Metal Jacket",
- "*1025_Item_EnergyBattery*": "Energy Battery",
- "*1026_Item_Hourglass*": "Hourglass",
- "*1027_Item_VoidBattery*": "Void Battery",
- "*1028_Item_Chronograph*": "Chronograph",
- "*1029_Item_Clockwork*": "Clockwork",
- "*1030_Item_SprintBoots*": "Sprint Boots",
- "*1032_Item_TravelBoots*": "Travel Boots",
- "*1034_Item_SerpentMask*": "Serpent Mask",
- "*1035_Item_TensionBow*": "Tension Bow",
- "*1038_Item_Flare*": "Flare",
- "*1039_Item_Bonesaw*": "Bonesaw",
- "*1041_Item_MinionCandy*": "Minion Candy",
- "*1042_Item_Shiversteel*": "Shiversteel",
- "*1043_Item_ReflexBlock*": "Reflex Block",
- "*1044_Item_Frostburn*": "Frostburn",
- "*1045_Item_FountainOfRenewal*": "Fountain of Renewal",
- "*1046_Item_Crucible*": "Crucible",
- "*1047_Item_JourneyBoots*": "Journey Boots",
- "*1049_Item_TyrantsMonocle*": "Tyrant's Monocle",
- "*1050_Item_Aftershock*": "Aftershock",
- "*1052_Item_WeaponInfusion*": "Weapon Infusion",
- "*1053_Item_CrystalInfusion*": "Crystal Infusion",
- "*1054_Item_ScoutTrap*": "Scout Trap",
- "*1055_Item_BrokenMyth*": "Broken Myth",
- "*1056_Item_WarTreads*": "War Treads",
- "*1057_Item_AtlasPauldron*": "Atlas Pauldron",
- "*1059_Item_BookOfEulogies*": "Book of Eulogies",
- "*1060_Item_BarbedNeedle*": "Barbed Needle",
- "*1061_Item_LightShield*": "Light Shield",
- "*1062_Item_KineticShield*": "Kinetic Shield",
- "*1063_Item_Aegis*": "Aegis",
- "*1064_Item_Lifespring*": "Lifespring",
- "*1065_Item_HeavySteel*": "Heavy Steel",
- "*1066_Item_PiercingSpear*": "Piercing Spear",
- "*1067_Item_BreakingPoint*": "Breaking Point",
- "*1068_Item_LuckyStrike*": "Lucky Strike",
- "*1069_Item_AlternatingCurrent*": "Alternating Current",
- "*1070_Item_PiercingShard*": "Piercing Shard",
- "*1071_Item_EveOfHarvest*": "Eve of Harvest",
- "*1072_Item_HeavyPrism*": "Heavy Prism",
- "*1073_Item_IronguardContract*": "Ironguard Contract",
- "*1074_Item_StormguardBanner*": "Stormguard Banner",
- "*1079_Item_Contraption*": "Contraption",
- "*1080_Item_MinionsFoot*": "Minion's Foot",
- "*1084_Item_ProtectorContract*": "Protector Contract",
- "*1087_Item_HalcyonChargers*": "Halcyon Chargers",
- "*1088_Item_Flaregun*": "Flare Gun",
- "*1090_Item_Stormcrown*": "Stormcrown",
- "*1092_Item_PoisonedShiv*": "Poisoned Shiv",
- "*1095_Item_NullwaveGauntlet*": "Nullwave Gauntlet",
- "*1097_Item_Echo*": "Echo",
- "*1105_Item_SlumberingHusk*": "Slumbering Husk"
- }
-
-
-def pretty(string):
- """Returns prettified hero or item or original string."""
- if string in VaingloryStrings.heroes:
- return VaingloryStrings.heroes[string]
- if string in VaingloryStrings.items:
- return VaingloryStrings.items[string]
- if string in VaingloryStrings.item_ids:
- return VaingloryStrings.item_ids[string]
- return string
diff --git a/tests/gamelocker_test.py b/tests/gamelocker_test.py
index 9fce0a0..c7a27a9 100644
--- a/tests/gamelocker_test.py
+++ b/tests/gamelocker_test.py
@@ -1,16 +1,15 @@
#!/usr/bin/python
+import os
import pytest
import requests
import gamelocker
import datetime
class TestGamelocker:
- apikey = "aaa.bbb.ccc"
-
@pytest.fixture
def api(self):
- return gamelocker.Gamelocker(self.apikey).Vainglory()
+ return gamelocker.Gamelocker(os.environ["GAMELOCKER_APIKEY"]).Vainglory()
def test_req(self, api):
with pytest.raises(requests.exceptions.HTTPError):
@@ -22,44 +21,56 @@ class TestGamelocker:
def test_map(self):
assert gamelocker.datatypes.modulemap()["match"] is gamelocker.datatypes.Match
- def test_strings(self, api):
- assert gamelocker.strings.pretty("notexisting") == "notexisting"
- assert gamelocker.strings.pretty("Boots2") == "Travel Boots"
- assert gamelocker.strings.pretty("*1032_Item_TravelBoots*") == "Travel Boots"
- assert gamelocker.strings.pretty("unknowntestitem") == "unknowntestitem"
-
- match = api.match("91cf2ee4-d7d0-11e6-ad79-062445d3d668")
- assert isinstance(match.rosters[0].participants[0].actor, str)
-
- assert isinstance(match.rosters[0].stats["acesEarned"], int)
- assert isinstance(match.rosters[0].participants[0].stats["items"][0], str)
-
def test_match(self, api):
- match = api.match("91cf2ee4-d7d0-11e6-ad79-062445d3d668")
- assert match.gameMode == "casual"
+ match = api.match("0955b904-fb19-11e6-802d-0667892d829e")
+ assert isinstance(match.gameMode, str)
assert isinstance(match.rosters[0], gamelocker.datatypes.Roster)
assert isinstance(match.rosters[0].participants[0], gamelocker.datatypes.Participant)
assert isinstance(match.rosters[0].participants[0].player, gamelocker.datatypes.Player)
assert isinstance(match.rosters[0].participants[0].player.name, str)
+ assert isinstance(match.rosters[0].participants[0].actor, str)
+ assert isinstance(match.rosters[0].stats["acesEarned"], int)
+ assert isinstance(match.rosters[0].participants[0].stats["items"][0], str)
def test_matches(self, api):
- matches = api.matches()
+ matches = api.matches(params={
+ "filter[createdAt-start]": "2017-02-12T00:00:00Z",
+ "filter[playerNames]": "Kraken"
+ })
assert len(matches) > 0
assert isinstance(matches[0], gamelocker.datatypes.Match)
assert matches[0].duration > 0
def test_region(self, api):
assert len(api.matches(region="na",
- params={"filter[playerNames]": "Kraken"})) > 0
+ params={
+ "filter[createdAt-start]": "2017-02-12T00:00:00Z",
+ "filter[playerNames]": "Kraken"
+ })) > 0
assert len(api.matches(region="eu",
- params={"filter[playerNames]": "Bayu"})) > 0
+ params={
+ "filter[createdAt-start]": "2017-02-12T00:00:00Z",
+ "filter[playerNames]": "shutterfly"
+ })) > 0
assert len(api.matches(region="sg",
- params={"filter[playerNames]": "idmonfish"})) > 0
+ params={
+ "filter[createdAt-start]": "2017-02-12T00:00:00Z",
+ "filter[playerNames]": "idmonfish"
+ })) > 0
def test_matchesfilters(self, api):
- matches1 = api.matches({"page[limit]": 3})
+ matches1 = api.matches({
+ "filter[createdAt-start]": "2017-02-12T00:00:00Z",
+ "filter[playerNames]": "Kraken",
+ "page[limit]": 3
+ })
assert len(matches1) == 3
- matches2 = api.matches({"page[limit]": 3, "page[offset]": 1})
+ matches2 = api.matches({
+ "filter[createdAt-start]": "2017-02-12T00:00:00Z",
+ "filter[playerNames]": "Kraken",
+ "page[limit]": 3,
+ "page[offset]": 1
+ })
commons = 0 # 3 matches each, offset 1 -> 2 overlap
for match1 in matches1:
@@ -68,23 +79,31 @@ class TestGamelocker:
commons += 1
assert commons == 2
- # broken on server side
-# assert len(api.matches({"page[limit]": 42})) == 42
-
-# matches = api.matches({"page[limit]": 10, "sort": "duration"})
-# assert matches[0].duration < matches[9].duration
+ assert len(api.matches(region="eu", params={
+ "filter[createdAt-start]": "2017-02-12T00:00:00Z",
+ "filter[playerNames]": "shutterfly",
+ "page[limit]": 9
+ })) == 9
def fromiso(s):
return datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ")
- start = "2017-01-10T02:25:00Z"
- end = "2017-01-12T02:30:00Z"
- matches = api.matches({"filter[createdAt-start]": start, "filter[createdAt-end]": end})
+ start = "2017-02-20T02:25:00Z"
+ end = "2017-02-22T02:30:00Z"
+ matches = api.matches({
+ "filter[playerNames]": "Kraken",
+ "filter[createdAt-start]": start,
+ "filter[createdAt-end]": end
+ })
for match in matches:
assert fromiso(end) >= fromiso(match.createdAt) >= fromiso(start)
nick = "MMotooks123"
- matches = api.matches({"page[limit]": 5, "filter[playerNames]": nick})
+ matches = api.matches({
+ "filter[createdAt-start]": "2017-02-10T00:00:00Z",
+ "page[limit]": 5,
+ "filter[playerNames]": nick
+ })
for match in matches:
success = False
for roster in match.rosters:
@@ -94,8 +113,12 @@ class TestGamelocker:
break
assert success
- team = "HALO"
- matches = api.matches({"page[limit]": 5, "filter[teamNames]": team})
+ team = "3TB3"
+ matches = api.matches(region="na", params={
+ "filter[createdAt-start]": "2017-02-10T00:00:00Z",
+ "page[limit]": 5,
+ "filter[teamNames]": team
+ })
for match in matches:
success = False
for roster in match.rosters:
@@ -106,5 +129,5 @@ class TestGamelocker:
assert success
def test_player(self, api):
- assert api.player("6abb30de-7cb8-11e4-8bd3-06eb725f8a76").name == "boombastic04"
- assert "lossStreak" in api.player("6abb30de-7cb8-11e4-8bd3-06eb725f8a76").stats
+ assert api.player("57342aac-7ff5-11e5-98bf-0628b69bf6d1").name == "oldchoas"
+ assert "lossStreak" in api.player("57342aac-7ff5-11e5-98bf-0628b69bf6d1").stats