Repository: meraki-analytics/cassiopeia

Issue:
Pull match history for entire season 10
Hi!

I wanted to run `match_history(seasons={Season.season_9}, queues={Queue.ranked_solo_fives})` for season 10 and I found that this only works up to season 9. I found that in `.../cassiopeia/transformers/data.py` the `Season` class is not updated for season 10 and I wanted to ask if the needed fix would be to just update the aforementioned class.

PS: Thank you for this amazing framework! :D

Discussion:

Patch:
diff --git a/cassiopeia/__init__.py b/cassiopeia/__init__.py
index 93b9568..2ec915b 100644
--- a/cassiopeia/__init__.py
+++ b/cassiopeia/__init__.py
@@ -82,7 +82,6 @@ from .data import (
     MasteryTree,
     Tier,
     Division,
-    Season,
     GameType,
     Lane,
     Role,
diff --git a/cassiopeia/cassiopeia.py b/cassiopeia/cassiopeia.py
index b18e4b7..57daa2b 100644
--- a/cassiopeia/cassiopeia.py
+++ b/cassiopeia/cassiopeia.py
@@ -2,7 +2,7 @@ from typing import List, Set, Dict, Union, TextIO
 import arrow
 import datetime
 
-from .data import Region, Queue, Season, Tier, Division, Continent, Platform, MatchType
+from .data import Region, Queue, Tier, Division, Continent, Platform, MatchType
 from .core import (
     Champion,
     Summoner,
diff --git a/cassiopeia/core/match.py b/cassiopeia/core/match.py
index 1b2b995..e65388a 100644
--- a/cassiopeia/core/match.py
+++ b/cassiopeia/core/match.py
@@ -26,7 +26,6 @@ from ..data import (
     MatchType,
     Queue,
     Side,
-    Season,
     Lane,
     Role,
     Key,
@@ -353,6 +352,9 @@ class ParticipantData(CoreData):
         }
         self.stats = ParticipantStatsData(**stats)
 
+        # TODO: I don't think this is supported anymore, same for the attributes relying on this (role, lane, ...)
+        if "timeline" in kwargs:
+            self.timeline = ParticipantTimelineData(**kwargs.pop("timeline"))
         if "teamId" in kwargs:
             self.side = Side(kwargs.pop("teamId"))
 
@@ -521,6 +523,10 @@ class MatchHistory(CassiopeiaLazyList):  # type: List[Match]
 
         return query
 
+    # For type hints
+    def __getitem__(self, item: Union[str, int]) -> "Match":
+        return super().__getitem__(item)
+
     @classmethod
     def from_generator(cls, generator: Generator, **kwargs):
         self = cls.__new__(cls)
@@ -1625,11 +1631,11 @@ class Participant(CassiopeiaObject):
 
     @property
     def lane(self) -> Lane:
-        return Lane.from_match_naming_scheme(self._data[ParticipantData].individualPosition)
+        return Lane.from_match_naming_scheme(self._data[ParticipantData].timeline.lane)
 
     @property
     def role(self) -> Role:
-        return Role.from_match_naming_scheme(self._data[ParticipantData].stats.role)
+        return Role.from_match_naming_scheme(self._data[ParticipantData].timeline.role)
 
     @property
     def skill_order(self) -> List[Key]:
@@ -1740,16 +1746,6 @@ class Participant(CassiopeiaObject):
             region=self.__match.region,
         )
 
-    @lazy_property
-    @load_match_on_attributeerror
-    def rank_last_season(self) -> Tier:
-        return Tier(self._data[ParticipantData].rankLastSeason)
-
-    @property
-    @load_match_on_attributeerror
-    def match_history_uri(self) -> str:
-        return self._data[ParticipantData].matchHistoryUri
-
     @lazy_property
     @load_match_on_attributeerror
     def champion(self) -> "Champion":
diff --git a/cassiopeia/core/patch.py b/cassiopeia/core/patch.py
index bc703d1..38fd2c5 100644
--- a/cassiopeia/core/patch.py
+++ b/cassiopeia/core/patch.py
@@ -12,7 +12,7 @@ try:
 except ImportError:
     import json
 
-from ..data import Region, Season
+from ..data import Region
 
 
 def pairwise(iterable):
@@ -29,7 +29,6 @@ class Patch(object):
     def __init__(
         self,
         region: Union[str, Region],
-        season: Season,
         name: str,
         start: Union[arrow.Arrow, float],
         end: Optional[Union[arrow.Arrow, float]],
@@ -41,7 +40,6 @@ class Patch(object):
         if not isinstance(region, Region):
             region = Region(region)
         self._region = region
-        self._season = season
         self._name = name
         self._start = start
         self._end = end
@@ -62,7 +60,7 @@ class Patch(object):
             raise ValueError("Unknown patch name {}".format(string))
 
     @classmethod
-    def from_date(cls, date: Union[arrow.Arrow], region: Union[Region, str]) -> "Patch":
+    def from_date(cls, date: arrow.Arrow, region: Union[Region, str]) -> "Patch":
         if not cls.__patches:
             cls.__load__()
         if not isinstance(region, Region):
@@ -93,13 +91,12 @@ class Patch(object):
                 start = arrow.get(patch["start"] + shifts[region.platform.value]).to(
                     region.timezone
                 )
-                season = Season.from_id(patch["season"])
                 name = patch["name"]
                 end = arrow.get(next_patch["start"] + shifts[region.platform.value]).to(
                     region.timezone
                 )
                 cls.__patches[region][i] = Patch(
-                    region=region, season=season, name=name, start=start, end=end
+                    region=region, name=name, start=start, end=end
                 )
 
         # Since pairwise skips the last patch in the list, add it manually here
@@ -108,11 +105,10 @@ class Patch(object):
             start = arrow.get(patch["start"] + shifts[region.platform.value]).to(
                 region.timezone
             )
-            season = Season.from_id(patch["season"])
             name = patch["name"]
             end = None
             cls.__patches[region][-1] = Patch(
-                region=region, season=season, name=name, start=start, end=end
+                region=region, name=name, start=start, end=end
             )
 
         # Sort each region's patches by start date
@@ -123,10 +119,6 @@ class Patch(object):
     def region(self) -> Region:
         return self._region
 
-    @property
-    def season(self) -> Season:
-        return self._season
-
     @property
     def name(self) -> str:
         return self._name
diff --git a/cassiopeia/core/summoner.py b/cassiopeia/core/summoner.py
index 20baf68..586af34 100644
--- a/cassiopeia/core/summoner.py
+++ b/cassiopeia/core/summoner.py
@@ -229,17 +229,12 @@ class Summoner(CassiopeiaGhost):
         return CurrentMatch(summoner=self, region=self.region)
 
     @property
-    def league_entries(self) -> "SummonerLeagues":
+    def league_entries(self) -> "LeagueSummonerEntries":
         from .league import LeagueSummonerEntries
 
         leagues = LeagueSummonerEntries(summoner=self)
         return leagues
 
-    @lazy_property
-    def rank_last_season(self):
-        most_recent_match = self.match_history[0]
-        return most_recent_match.participants[self.name].rank_last_season
-
     @property
     def verification_string(self) -> str:
         from .thirdpartycode import VerificationString
@@ -253,3 +248,11 @@ class Summoner(CassiopeiaGhost):
         for position in self.league_entries:
             ranks[position.queue] = Rank(tier=position.tier, division=position.division)
         return ranks
+
+
+# Add circular references at the bottom
+from .championmastery import ChampionMasteries
+from .match import MatchHistory
+from .spectator import CurrentMatch
+from .league import LeagueSummonerEntries
+from .thirdpartycode import VerificationString
diff --git a/cassiopeia/data.py b/cassiopeia/data.py
index 0326306..f0a84b6 100644
--- a/cassiopeia/data.py
+++ b/cassiopeia/data.py
@@ -304,64 +304,6 @@ class Rank:
         return self.tuple >= other.tuple
 
 
-class Season(Enum):
-    preseason_3 = "PRESEASON3"
-    season_3 = "SEASON3"
-    preseason_4 = "PRESEASON2014"
-    season_4 = "SEASON2014"
-    preseason_5 = "PRESEASON2015"
-    season_5 = "SEASON2015"
-    preseason_6 = "PRESEASON2016"
-    season_6 = "SEASON2016"
-    preseason_7 = "PRESEASON2017"
-    season_7 = "SEASON2017"
-    preseason_8 = "PRESEASON2018"
-    season_8 = "SEASON2018"
-    preseason_9 = "PRESEASON2019"
-    season_9 = "SEASON2019"
-
-    @property
-    def id(self):
-        return SEASON_IDS[self]
-
-    def from_id(id: int):
-        return {i: season for season, i in SEASON_IDS.items()}[id]
-
-    def start(self, region: Region) -> arrow.Arrow:
-        from .core import Patch
-
-        if Patch._Patch__patches is None:
-            Patch.__load__()
-        for patch in Patch._Patch__patches[region]:
-            if patch.season == self:
-                return patch.start
-
-    def end(self, region: Region) -> arrow.Arrow:
-        from .core import Patch
-
-        for patch in reversed(Patch._Patch__patches[region]):
-            if patch.season == self:
-                return patch.end
-
-
-SEASON_IDS = {
-    Season.preseason_3: 0,
-    Season.season_3: 1,
-    Season.preseason_4: 2,
-    Season.season_4: 3,
-    Season.preseason_5: 4,
-    Season.season_5: 5,
-    Season.preseason_6: 6,
-    Season.season_6: 7,
-    Season.preseason_7: 8,
-    Season.season_7: 9,
-    Season.preseason_8: 10,
-    Season.season_8: 11,
-    Season.preseason_9: 12,
-    Season.season_9: 13,
-}
-
-
 class GameType(Enum):
     custom = "CUSTOM_GAME"
     tutorial = "TUTORIAL_GAME"
@@ -530,7 +472,6 @@ class Tower(Enum):
 # https://developer.riotgames.com/game-constants.html
 # https://discussion.developer.riotgames.com/articles/3482/multiple-queueids-are-being-updated-with-patch-719.html
 # https://github.com/stelar7/L4J8/blob/master/src/main/java/no/stelar7/api/l4j8/basic/constants/types/GameQueueType.java
-# https://github.com/RiotGames/developer-relations/issues/574
 class Queue(Enum):
     custom = "CUSTOM"  # 0
     deprecated_blind_fives = "NORMAL_5x5_BLIND"  # 2
@@ -609,10 +550,8 @@ class Queue(Enum):
     odyssey_crewmember = "ODYSSEY_CREWMEMBER"  # 1050
     odyssey_captain = "ODYSSEY_CAPTAIN"  # 1060
     odyssey_onslaught = "ODYSSEY_ONSLAUGHT"  # 1070
-    normal_tft = "NORMAL_TFT"  # 1090
     ranked_tft = "RANKED_TFT"  # 1100
-    ranked_tft_pairs = "RANKED_TFT_PAIRS"  # 1150
-    ranked_tft_double_up = "RANKED_TFT_DOUBLE_UP"  # 1160
+    normal_tft = "NORMAL_TFT"  # 1090
     deprecated_nexus_blitz = "NEXUS_BLITZ"  # 1200
     nexus_blitz = "NEXUS_BLITZ"  # 1300
     ultimate_spellbook = "ULTIMATE_SPELLBOOK"  # 1400
@@ -621,7 +560,7 @@ class Queue(Enum):
     tutorial3 = "TUTORIAL_3"  # Summoner's Rift  Tutorial 3
 
     def from_id(id: int):
-        return {i: season for season, i in QUEUE_IDS.items()}[id]
+        return {i: queue for queue, i in QUEUE_IDS.items()}[id]
 
     @property
     def id(self):
@@ -701,10 +640,8 @@ QUEUE_IDS = {
     Queue.odyssey_crewmember: 1050,  # Odyssey: Extraction
     Queue.odyssey_captain: 1060,  # Odyssey: Extraction
     Queue.odyssey_onslaught: 1070,  # Odyssey: Extraction
-    Queue.normal_tft: 1090,  #  Convergence, Normal Teamfight Tactics games
     Queue.ranked_tft: 1100,  #  Convergence, Ranked Teamfight Tactics games
-    Queue.ranked_tft_pairs: 1150,  # Convergence, Teamfight Tactics (Double Up Beta) games
-    Queue.ranked_tft_double_up: 1160,  # Convergence, Teamfight Tactics Double Up
+    Queue.normal_tft: 1090,  #  Convergence, Normal Teamfight Tactics games
     Queue.deprecated_nexus_blitz: 1200,  # Nexus Blitz map    Nexus Blitz Deprecated in patch 9.2 in favor of queueId 1300
     Queue.nexus_blitz: 1300,  # Nexus Blitz map    Nexus Blitz
     Queue.ultimate_spellbook: 1400,  # Summoner's Rift   Ultimate Spellbook
@@ -724,6 +661,4 @@ RANKED_QUEUES = {
     Queue.ranked_flex_fives,  # Summoner's Rift    5v5 Ranked Flex games
     Queue.ranked_flex_threes,  # Twisted Treeline    3v3 Ranked Flex games
     Queue.ranked_tft,  # Convergence  Ranked Teamfight Tactics games
-    Queue.ranked_tft_pairs,  # Convergence  Ranked Teamfight Tactics (Double Up Beta) games
-    Queue.ranked_tft_double_up,  # Convergence  Ranked Teamfight Tactics Double Up games
 }
diff --git a/cassiopeia/datastores/kernel/match.py b/cassiopeia/datastores/kernel/match.py
index 6b98b86..90f3079 100644
--- a/cassiopeia/datastores/kernel/match.py
+++ b/cassiopeia/datastores/kernel/match.py
@@ -13,7 +13,7 @@ from datapipelines import (
 )
 
 from .common import KernelSource, APINotFoundError
-from ...data import Platform, Season, Queue, SEASON_IDS, QUEUE_IDS
+from ...data import Platform, Queue, QUEUE_IDS
 from ...dto.match import MatchDto, MatchListDto, TimelineDto
 from ..uniquekeys import convert_region_to_platform
 
@@ -113,8 +113,6 @@ class MatchAPI(KernelSource):
         .as_(int)
         .also.has("maxNumberOfMatches")
         .as_(float)
-        .also.can_have("seasons")
-        .as_(Iterable)
         .also.can_have("champion.ids")
         .as_(Iterable)
         .also.can_have("queues")
@@ -183,12 +181,6 @@ class MatchAPI(KernelSource):
             )
             parameters["endIndex"] = int(parameters["endIndex"])
 
-        if "seasons" in query:
-            seasons = {Season(season) for season in query["seasons"]}
-            parameters["season"] = {SEASON_IDS[season] for season in seasons}
-        else:
-            seasons = set()
-
         if "champion.ids" in query:
             champions = query["champion.ids"]
             parameters["champion"] = champions
@@ -211,7 +203,6 @@ class MatchAPI(KernelSource):
 
         data["accountId"] = query["accountId"]
         data["region"] = query["platform"].region.value
-        data["season"] = seasons
         data["champion"] = champions
         data["queue"] = queues
         if calling_method == "by_index":
@@ -239,8 +230,6 @@ class MatchAPI(KernelSource):
         .as_(int)
         .also.can_have("endIndex")
         .as_(int)
-        .also.can_have("seasons")
-        .as_(Iterable)
         .also.can_have("champion.ids")
         .as_(Iterable)
         .also.can_have("queues")
@@ -260,12 +249,6 @@ class MatchAPI(KernelSource):
         if "endIndex" in query:
             parameters["endIndex"] = query["endIndex"]
 
-        if "seasons" in query:
-            seasons = {Season(season) for season in query["seasons"]}
-            parameters["season"] = {SEASON_IDS[season] for season in seasons}
-        else:
-            seasons = set()
-
         if "champion.ids" in query:
             parameters["champion"] = {query["champion.ids"]}
 
@@ -291,8 +274,6 @@ class MatchAPI(KernelSource):
                     data["beginIndex"] = query["beginIndex"]
                 if "endIndex" in query:
                     data["endIndex"] = query["endIndex"]
-                if "seasons" in query:
-                    data["seasons"] = seasons
                 if "champion.ids" in query:
                     data["champion"] = parameters["champion"]
                 if "queues" in query:
diff --git a/examples/match.py b/examples/match.py
index ce6160d..651f278 100644
--- a/examples/match.py
+++ b/examples/match.py
@@ -1,6 +1,6 @@
 import cassiopeia as cass
 from cassiopeia import Summoner, Match
-from cassiopeia.data import Season, Queue
+from cassiopeia.data import Queue
 from collections import Counter
 
 


Test patch:
diff --git a/test/test_examples.py b/test/test_examples.py
index d5f3504..c46db96 100644
--- a/test/test_examples.py
+++ b/test/test_examples.py
@@ -3,7 +3,6 @@ import random
 
 import cassiopeia as cass
 from cassiopeia import (
-    Season,
     Queue,
     Summoner,
     Match,
@@ -50,7 +49,7 @@ def test_match():
 
     match_history = cass.get_match_history(summoner, queues={Queue.ranked_solo_fives})
     match_history = summoner.match_history
-    match_history(seasons={Season.season_7}, queues={Queue.ranked_solo_fives})
+    match_history(queues={Queue.ranked_solo_fives})
 
     champion_id_to_name_mapping = {
         champion.id: champion.name for champion in cass.get_champions(region=region)
diff --git a/test/test_matchhistory.py b/test/test_matchhistory.py
index 5a1aa6d..1b7d6d8 100644
--- a/test/test_matchhistory.py
+++ b/test/test_matchhistory.py
@@ -1,7 +1,7 @@
 import arrow
 
 import cassiopeia as cass
-from cassiopeia import Season, Queue, Summoner
+from cassiopeia import Queue, Summoner
 
 
 def test_match_history_1():
@@ -18,7 +18,6 @@ def test_match_history_2():
     summoner = Summoner(name="Kalturi", region=region)
     match_history = cass.get_match_history(
         summoner=summoner,
-        seasons={Season.season_9},
         queues={Queue.ranked_solo_fives},
         begin_time=arrow.now().shift(days=-140),
         end_time=arrow.now(),
@@ -43,7 +42,6 @@ def test_match_history_5():
     summoner = Summoner(name="Kalturi", region=region)
     match_history = cass.get_match_history(
         summoner=summoner,
-        seasons={Season.season_9},
         queues={Queue.ranked_solo_fives},
         begin_time=arrow.get(2019, 1, 1),
         end_time=arrow.now(),
@@ -68,7 +66,6 @@ def test_match_history_7():
     summoner = Summoner(name="Kalturi", region=region)
     match_history = cass.get_match_history(
         summoner=summoner,
-        seasons={Season.season_9},
         queues={Queue.ranked_solo_fives},
         begin_time=arrow.get(2019, 10, 1),
     )
diff --git a/test/test_patches.py b/test/test_patches.py
index 5a67b6e..8ff4fc7 100644
--- a/test/test_patches.py
+++ b/test/test_patches.py
@@ -1,6 +1,6 @@
 import pytest
 
-from cassiopeia import Patch, Season, Region
+from cassiopeia import Patch, Region
 
 
 def test_known_patches():
@@ -14,14 +14,6 @@ def test_unknown_patch_raises():
         Patch.from_str("unknown patch")
 
 
-def test_season_start_end_using_patches():
-    assert (
-        Season.season_7.start(Region.north_america)
-        == Patch.from_str("7.1", region=Region.north_america).start
-    )
-    assert Season.season_8.end(Region.north_america) == None
-
-
 def test_patch_relational_operators():
     assert Patch.from_str("9.9", region="NA") < Patch.from_str("9.10", region="NA")
     assert Patch.from_str("8.20", region="NA") > Patch.from_str("8.11", region="NA")
diff --git a/test/test_summoner.py b/test/test_summoner.py
index 46deae2..45c8295 100644
--- a/test/test_summoner.py
+++ b/test/test_summoner.py
@@ -41,7 +41,6 @@ class TestSummoner(unittest.TestCase):
         self.assertIsNotNone(s.champion_masteries)
         self.assertIsNotNone(s.match_history)
         self.assertIsNotNone(s.league_entries)
-        # self.assertIsNotNone(s.rank_last_season)
 
     def test_equality(self):
         from_name = cassiopeia.get_summoner(name=SUMMONER_NAME, region="NA")