Repository: pseudonym117/Riot-Watcher

Issue:
Match v5 support?
We're making match-v5 available on Development API keys. Production access will follow in the coming weeks/month. We'll be deprecating match-v4 on Monday, June 14th. This begins our typical 60 day deprecation period. https://riot.com/3g7BoEl


Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#177](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (6a3f981) into [master](https://codecov.io/gh/pseudonym117/Riot-Watcher/commit/f07a035a4379c4ec8c1fece332582d61ad2ecc1f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (f07a035) will **increase** coverage by `0.02%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177/graphs/tree.svg?width=650&height=150&src=pr&token=a5BzeJ4fPu&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

```diff
@@            Coverage Diff             @@
##           master     #177      +/-   ##
==========================================
+ Coverage   94.18%   94.20%   +0.02%     
==========================================
  Files          83       83              
  Lines         997     1001       +4     
  Branches       68       68              
==========================================
+ Hits          939      943       +4     
  Misses         38       38              
  Partials       20       20              
```


| [Impacted Files](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [src/riotwatcher/LolWatcher.py](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3Jpb3R3YXRjaGVyL0xvbFdhdGNoZXIucHk=) | `100.00% <100.00%> (ø)` | |
| [src/riotwatcher/\_\_version\_\_.py](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3Jpb3R3YXRjaGVyL19fdmVyc2lvbl9fLnB5) | `100.00% <100.00%> (ø)` | |
| [src/riotwatcher/\_apis/BaseApi.py](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL3Jpb3R3YXRjaGVyL19hcGlzL0Jhc2VBcGkucHk=) | `88.00% <0.00%> (-0.24%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Last update [f07a035...6a3f981](https://codecov.io/gh/pseudonym117/Riot-Watcher/pull/177?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).


Patch:
diff --git a/README.rst b/README.rst
index bfbc117..98cdd27 100644
--- a/README.rst
+++ b/README.rst
@@ -1,4 +1,4 @@
-RiotWatcher v3.1.1
+RiotWatcher v3.1.2
 ==================
 
 |pypi| |docs| |coverage| |lgmt| |black|
@@ -7,7 +7,7 @@ Check for full (read: slightly better) documentation `here <http://riot-watcher.
 
 RiotWatcher is a thin wrapper on top of the `Riot Games API for League
 of Legends <https://developer.riotgames.com/>`__. All public methods as
-of 10/3/2020 are supported in full.
+of 7/4/2021 are supported in full.
 
 RiotWatcher by default supports a naive rate limiter. This rate limiter will
 try to stop you from making too many requests, and in a single threaded test
@@ -84,6 +84,42 @@ raised as HTTPError exceptions from the Requests library.
         else:
             raise
 
+MatchApiV5
+----------
+
+As of 7/4/2021, both the v4 and v5 versions of the Match API are supported by Riot. As such, RiotWatcher provides a
+method to use both. By default, the v4 API will be used for backwards compatibility.
+
+To use the v5 API by default, use the following to initialize your LolWatcher instance:
+
+.. code:: python
+
+    from riotwatcher import LolWatcher
+
+    lol_watcher = LolWatcher('<your-api-key>', default_default_match_v5=True)
+
+    # example call
+    matchlist = lol_watcher.match.matchlist_by_puuid('AMERICAS', 'fake-puuid')
+
+To explicitly use v4 or v5 during the deprecation period, you can use the following properties:
+
+.. code:: python
+
+    from riotwatcher import LolWatcher
+
+    lol_watcher = LolWatcher('<your-api-key>')
+
+    # use v5 explicitly
+    matchlist = lol_watcher.match_v5.matchlist_by_puuid('AMERICAS', 'fake-puuid')
+
+    # use v4 explicitly
+    old_matchlist = lol_watcher.match_v4.matchlist_by_account('na1', 'fake-account-id')
+
+Note: this will not be supported after v4 is completely deprecated! Both match_v4 and match_v5 properties will be removed,
+and the change will happen with a minor version increase. If you desire seamless backwards compatibility, do not use these
+properies.
+
+
 Use with kernel
 ---------------
 
@@ -113,11 +149,15 @@ Rate limiter has some race conditions when used concurrently.
 
 Changelog
 ---------
-v3.1.1 - TBD
+v3.1.2 - 7/4/2021
 ~~~~~~~~~~~~
+Add support for LoL MatchAPI v5
+
+v3.1.1 - 10/4/2020
+~~~~~~~~~~~~~~~~~~
 Add support for Valorant recent match API.
 
-Add support for LoR MatchAPI. 
+Add support for LoR MatchAPI.
 
 v3.1.0 - 9/1/2020
 ~~~~~~~~~~~~~~~~~
diff --git a/docs/index.rst b/docs/index.rst
index db800ed..a35cdb6 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -4,7 +4,7 @@ Welcome to RiotWatcher's documentation!
 
 RiotWatcher is a thin wrapper on top of the `Riot Games API for League
 of Legends <https://developer.riotgames.com/>`__. All public methods as
-of 10/3/2020 are supported in full.
+of 7/4/2021 are supported in full.
 
 RiotWatcher by default supports a naive rate limiter. This rate limiter will
 try to stop you from making too many requests, and in a single threaded test
@@ -80,6 +80,41 @@ raised as HTTPError exceptions from the Requests library.
         else:
             raise
 
+MatchApiV5
+----------
+
+As of 7/4/2021, both the v4 and v5 versions of the Match API are supported by Riot. As such, RiotWatcher provides a
+method to use both. By default, the v4 API will be used for backwards compatibility.
+
+To use the v5 API by default, use the following to initialize your LolWatcher instance:
+
+.. code:: python
+
+    from riotwatcher import LolWatcher
+
+    lol_watcher = LolWatcher('<your-api-key>', default_default_match_v5=True)
+
+    # example call
+    matchlist = lol_watcher.match.matchlist_by_puuid('AMERICAS', 'fake-puuid')
+
+To explicitly use v4 or v5 during the deprecation period, you can use the following properties:
+
+.. code:: python
+
+    from riotwatcher import LolWatcher
+
+    lol_watcher = LolWatcher('<your-api-key>')
+
+    # use v5 explicitly
+    matchlist = lol_watcher.match_v5.matchlist_by_puuid('AMERICAS', 'fake-puuid')
+
+    # use v4 explicitly
+    old_matchlist = lol_watcher.match_v4.matchlist_by_account('na1', 'fake-account-id')
+
+Note: this will not be supported after v4 is completely deprecated! Both match_v4 and match_v5 properties will be removed,
+and the change will happen with a minor version increase. If you desire seamless backwards compatibility, do not use these
+properies.
+
 
 Use with kernel
 ---------------
diff --git a/docs/riotwatcher/LeagueOfLegends/MatchApiV5.rst b/docs/riotwatcher/LeagueOfLegends/MatchApiV5.rst
new file mode 100644
index 0000000..f9bfce4
--- /dev/null
+++ b/docs/riotwatcher/LeagueOfLegends/MatchApiV5.rst
@@ -0,0 +1,8 @@
+MatchApiV4
+==========
+
+.. py:currentmodule:: riotwatcher
+
+.. autoclass:: riotwatcher._apis.league_of_legends.MatchApiV5
+    :members:
+    :undoc-members:
diff --git a/docs/riotwatcher/LeagueOfLegends/index.rst b/docs/riotwatcher/LeagueOfLegends/index.rst
index 17b010c..aa811f9 100644
--- a/docs/riotwatcher/LeagueOfLegends/index.rst
+++ b/docs/riotwatcher/LeagueOfLegends/index.rst
@@ -21,6 +21,7 @@ All APIs
    LeagueApiV4.rst
    LolStatusApiV3.rst
    MatchApiV4.rst
+   MatchApiV5.rst
    SpectatorApiV4.rst
    SummonerApiV4.rst
    ThirdPartyCodeApiV4.rst
diff --git a/src/riotwatcher/LolWatcher.py b/src/riotwatcher/LolWatcher.py
index 0be0016..e3fa631 100644
--- a/src/riotwatcher/LolWatcher.py
+++ b/src/riotwatcher/LolWatcher.py
@@ -1,3 +1,4 @@
+from typing import Union
 from .Deserializer import Deserializer
 from .RateLimiter import RateLimiter
 
@@ -24,7 +25,7 @@ from ._apis.league_of_legends import (
     SpectatorApiV4,
     SummonerApiV4,
     MatchApiV5,
-    ThirdPartyCodeApiV4,    
+    ThirdPartyCodeApiV4,
 )
 
 
@@ -40,6 +41,7 @@ class LolWatcher:
         kernel_url: str = None,
         rate_limiter: RateLimiter = BasicRateLimiter(),
         deserializer: Deserializer = DictionaryDeserializer(),
+        default_match_v5: bool = False,
     ):
         """
         Initialize a new instance of the RiotWatcher class.
@@ -88,13 +90,13 @@ class LolWatcher:
         self._clash = ClashApiV1(self._base_api)
         self._champion_mastery = ChampionMasteryApiV4(self._base_api)
         self._league = LeagueApiV4(self._base_api)
-        self._match = MatchApiV4(self._base_api)        
+        self._match_v4 = MatchApiV4(self._base_api)
+        self._match_v5 = MatchApiV5(self._base_api)
         self._spectator = SpectatorApiV4(self._base_api)
         self._summoner = SummonerApiV4(self._base_api)
-                   
-        self._matchv5 = MatchApiV5(self._base_api)
-       
-        self._third_party_code = ThirdPartyCodeApiV4(self._base_api)        
+        self._third_party_code = ThirdPartyCodeApiV4(self._base_api)
+
+        self._match = self._match_v5 if default_match_v5 else self._match_v4
         # todo: tournament-stub
         # todo: tournament
 
@@ -144,14 +146,34 @@ class LolWatcher:
         return self._lol_status
 
     @property
-    def match(self) -> MatchApiV4:
+    def match(self) -> Union[MatchApiV4, MatchApiV5]:
         """
         Interface to the Match Endpoint
 
+        :rtype: league_of_legends.MatchApiV5
+        """
+        return self._match
+
+    @property
+    def match_v4(self) -> MatchApiV4:
+        """
+        Temporary explicit interface to match-v4 endpoint.
+        Will be removed when matchv4 is deprecated.
+
         :rtype: league_of_legends.MatchApiV4
         """
         return self._match
-        
+
+    @property
+    def match_v5(self) -> MatchApiV5:
+        """
+        Temporary explicit interface to match-v5 endpoint.
+        Will be removed when matchv4 is deprecated.
+
+        :rtype: league_of_legends.MatchApiV5
+        """
+        return self._match_v5
+
     @property
     def spectator(self) -> SpectatorApiV4:
         """
@@ -178,15 +200,6 @@ class LolWatcher:
         :rtype: league_of_legends.SummonerApiV4
         """
         return self._summoner
-        
-    @property
-    def matchv5(self) -> MatchApiV5:
-        """
-        Interface to the Match Endpoint
-
-        :rtype: league_of_legends.MatchApiV5
-        """
-        return self._matchv5
 
     @property
     def third_party_code(self) -> ThirdPartyCodeApiV4:
@@ -195,4 +208,4 @@ class LolWatcher:
 
         :rtype: league_of_legends.ThirdPartyCodeApiV4
         """
-        return self._third_party_code           
+        return self._third_party_code
diff --git a/src/riotwatcher/__version__.py b/src/riotwatcher/__version__.py
index be3c421..af847c3 100644
--- a/src/riotwatcher/__version__.py
+++ b/src/riotwatcher/__version__.py
@@ -1,3 +1,3 @@
-__version__ = "3.1.1"
+__version__ = "3.1.2"
 __author__ = "pseudonym117"
 __title__ = "RiotWatcher"


Test patch:
diff --git a/tests/integration/league_of_legends/test_MatchApiV4.py b/tests/integration/league_of_legends/test_MatchApiV4.py
index e9cdcd5..4a2b02e 100644
--- a/tests/integration/league_of_legends/test_MatchApiV4.py
+++ b/tests/integration/league_of_legends/test_MatchApiV4.py
@@ -24,7 +24,7 @@ import pytest
 class TestMatchApiV4:
     @pytest.mark.parametrize("match_id", [12345, 54321, 2, 222222222222222222222])
     def test_by_id(self, lol_context, region, match_id):
-        actual_response = lol_context.watcher.match.by_id(region, match_id)
+        actual_response = lol_context.watcher.match_v4.by_id(region, match_id)
 
         lol_context.verify_api_call(
             region, f"/lol/match/v4/matches/{match_id}", {}, actual_response,
@@ -56,7 +56,7 @@ class TestMatchApiV4:
         begin_time, end_time = begin_end_time
         begin_index, end_index = begin_end_index
 
-        actual_response = lol_context.watcher.match.matchlist_by_account(
+        actual_response = lol_context.watcher.match_v4.matchlist_by_account(
             region,
             encrypted_account_id,
             queue=queue,
@@ -93,7 +93,9 @@ class TestMatchApiV4:
 
     @pytest.mark.parametrize("match_id", [0, 54321, 3232323232323223])
     def test_timeline_by_match(self, lol_context, region, match_id):
-        actual_response = lol_context.watcher.match.timeline_by_match(region, match_id)
+        actual_response = lol_context.watcher.match_v4.timeline_by_match(
+            region, match_id
+        )
 
         lol_context.verify_api_call(
             region, f"/lol/match/v4/timelines/by-match/{match_id}", {}, actual_response,
diff --git a/tests/integration/league_of_legends/test_MatchApiV5.py b/tests/integration/league_of_legends/test_MatchApiV5.py
index 952b614..4f6114c 100644
--- a/tests/integration/league_of_legends/test_MatchApiV5.py
+++ b/tests/integration/league_of_legends/test_MatchApiV5.py
@@ -4,17 +4,14 @@ import pytest
 @pytest.mark.lol
 @pytest.mark.integration
 @pytest.mark.parametrize(
-    "region",
-    [
-        "EUROPE",
-        "AMERICAS",
-        "ASIA",       
-    ],
+    "region", ["EUROPE", "AMERICAS", "ASIA",],
 )
 class TestMatchApiV5:
-    @pytest.mark.parametrize("match_id", ["EUW1_12345", "EUW1_54321", "EUW1_1", "EUW_1222222222222222222222"])
+    @pytest.mark.parametrize(
+        "match_id", ["EUW1_12345", "EUW1_54321", "EUW1_1", "EUW_1222222222222222222222"]
+    )
     def test_by_id(self, lol_context, region, match_id):
-        actual_response = lol_context.watcher.matchv5.by_id(region, match_id)
+        actual_response = lol_context.watcher.match_v5.by_id(region, match_id)
 
         lol_context.verify_api_call(
             region, f"/lol/match/v5/matches/{match_id}", {}, actual_response,
@@ -22,28 +19,20 @@ class TestMatchApiV5:
 
     @pytest.mark.parametrize("puuid", ["12345", "3333333333333333333"])
     @pytest.mark.parametrize("count", [None, 20])
-    @pytest.mark.parametrize("start", [None, 0])    
+    @pytest.mark.parametrize("start", [None, 0])
     def test_matchlist_by_account(
-        self,
-        lol_context,
-        region,
-        puuid,
-        start,
-        count,       
-    ):        
-
-        actual_response = lol_context.watcher.matchv5.matchlist_by_puuid(
-            region,
-            puuid,
-            start=start,
-            count=count,            
+        self, lol_context, region, puuid, start, count,
+    ):
+
+        actual_response = lol_context.watcher.match_v5.matchlist_by_puuid(
+            region, puuid, start=start, count=count,
         )
 
         expected_params = {}
         if count is not None:
             expected_params["count"] = count
         if start is not None:
-            expected_params["start"] = start        
+            expected_params["start"] = start
 
         lol_context.verify_api_call(
             region,
@@ -52,9 +41,13 @@ class TestMatchApiV5:
             actual_response,
         )
 
-    @pytest.mark.parametrize("match_id", ["EUW1_12345", "EUW1_54321", "EUW1_1", "EUW_1222222222222222222222"])
+    @pytest.mark.parametrize(
+        "match_id", ["EUW1_12345", "EUW1_54321", "EUW1_1", "EUW_1222222222222222222222"]
+    )
     def test_timeline_by_match(self, lol_context, region, match_id):
-        actual_response = lol_context.watcher.matchv5.timeline_by_match(region, match_id)
+        actual_response = lol_context.watcher.match_v5.timeline_by_match(
+            region, match_id
+        )
 
         lol_context.verify_api_call(
             region, f"/lol/match/v5/matches/{match_id}/timeline", {}, actual_response,
diff --git a/tests/test_LolWatcher.py b/tests/test_LolWatcher.py
index fa30ab5..2c011c4 100644
--- a/tests/test_LolWatcher.py
+++ b/tests/test_LolWatcher.py
@@ -1,6 +1,7 @@
 import pytest
 
 from riotwatcher import LolWatcher
+from riotwatcher._apis.league_of_legends import MatchApiV4, MatchApiV5
 
 
 @pytest.mark.lol
@@ -18,3 +19,15 @@ class TestLolWatcher:
 
     def test_allows_kernel_url(self):
         LolWatcher(kernel_url="https://fake-kernel-server")
+
+    def test_defaults_match_v4(self):
+        watcher = LolWatcher(api_key="RGAPI-this-is-a-fake")
+        assert isinstance(watcher.match, MatchApiV4)
+
+    def test_uses_match_v4_when_false(self):
+        watcher = LolWatcher(api_key="RGAPI-this-is-a-fake", default_match_v5=False)
+        assert isinstance(watcher.match, MatchApiV4)
+
+    def test_uses_match_v5_when_true(self):
+        watcher = LolWatcher(api_key="RGAPI-this-is-a-fake", default_match_v5=True)
+        assert isinstance(watcher.match, MatchApiV5)