Repository: pseudonym117/Riot-Watcher

Issue:
champion_master is outdated, updated from encrypted_summoner_id to puuid
When trying to get champion mastery, it still asks for `encrypted_summoner_id` when the API now asks for `puuid`

When running:

`lol_watcher.champion_mastery.by_summoner_by_champion('na1', 'b4rpqbmfbERhRH3cDPiPLhN0WW0Azxa8oc8jWEHWqqD7mzs', 105)`

I get the error:

`HTTPError: 403 Client Error: Forbidden for url: https://na1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-summoner/b4rpqbmfbERhRH3cDPiPLhN0WW0Azxa8oc8jWEHWqqD7mzs/by-champion/105`

And after surveying the API it is noted that they updated to puuid (https://developer.riotgames.com/apis#champion-mastery-v4/GET_getChampionMasteryByPUUID)

So the correct request would be:

`https://na1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/`

instead of

`https://na1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-summoner/`



Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/pseudonym117/Riot-Watcher/pull/236?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 93.47%. Comparing base [(`cd913a8`)](https://app.codecov.io/gh/pseudonym117/Riot-Watcher/commit/cd913a8fddca64e86b3b8bbc26579383d4b9a111?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) to head [(`91c41a0`)](https://app.codecov.io/gh/pseudonym117/Riot-Watcher/pull/236?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #236      +/-   ##
==========================================
+ Coverage   93.45%   93.47%   +0.01%     
==========================================
  Files          88       88              
  Lines        1100     1103       +3     
  Branches      123      123              
==========================================
+ Hits         1028     1031       +3     
  Misses         47       47              
  Partials       25       25              
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/pseudonym117/Riot-Watcher/pull/236?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).


Patch:
diff --git a/src/riotwatcher/_apis/league_of_legends/ChampionMasteryApiV4.py b/src/riotwatcher/_apis/league_of_legends/ChampionMasteryApiV4.py
index d86dc7f..5f5d2e3 100644
--- a/src/riotwatcher/_apis/league_of_legends/ChampionMasteryApiV4.py
+++ b/src/riotwatcher/_apis/league_of_legends/ChampionMasteryApiV4.py
@@ -18,60 +18,75 @@ class ChampionMasteryApiV4(NamedEndpoint):
         """
         super().__init__(base_api, self.__class__.__name__)
 
-    def by_summoner(self, region: str, encrypted_summoner_id: str):
+    def by_puuid(self, region: str, puuid: str):
         """
         Get all champion mastery entries.
 
-        :param string region:                   the region to execute this request on
-        :param string encrypted_summoner_id:    Summoner ID associated with the player
+        :param string region:               the region to execute this request on
+        :param string puuid:                PUUID associated with the player
 
         :returns: List[ChampionMasteryDTO]: This object contains a list of Champion
                                             Mastery information for player and champion
                                             combination.
         """
         return self._request_endpoint(
-            self.by_summoner.__name__,
+            self.by_puuid.__name__,
             region,
-            ChampionMasteryApiV4Urls.by_summoner,
-            encrypted_summoner_id=encrypted_summoner_id,
+            ChampionMasteryApiV4Urls.by_puuid,
+            puuid=puuid,
         )
 
-    def by_summoner_by_champion(
-        self, region: str, encrypted_summoner_id: str, champion_id: int
-    ):
+    def by_puuid_by_champion(self, region: str, puuid: str, champion_id: int):
         """
         Get a champion mastery by player ID and champion ID.
 
-        :param string region:                   the region to execute this
-                                                request on
-        :param string encrypted_summoner_id:    Summoner ID associated with the player
-        :param long champion_id:                Champion ID to retrieve Champion
-                                                Mastery for
+        :param string region:         the region to execute this request on
+        :param string puuid:          PUUID associated with the player
+        :param long champion_id:      Champion ID to retrieve Champion Mastery for
 
         :returns: ChampionMasteryDTO: This object contains single Champion Mastery
                                       information for player and champion combination.
         """
         return self._request_endpoint(
-            self.by_summoner_by_champion.__name__,
+            self.by_puuid_by_champion.__name__,
             region,
-            ChampionMasteryApiV4Urls.by_summoner_by_champion,
-            encrypted_summoner_id=encrypted_summoner_id,
+            ChampionMasteryApiV4Urls.by_puuid_by_champion,
+            puuid=puuid,
             champion_id=champion_id,
         )
 
-    def scores_by_summoner(self, region: str, encrypted_summoner_id: str):
+    def top_by_puuid(self, region: str, puuid: str, count: int = None):
+        """
+        Get specified number of top champion mastery entries sorted by number of champion
+        points descending.
+
+        :param string region:   the region to execute this request on
+        :param string puuid:    PUUID associated with the player
+        :param int count:       Number of entries to retrieve, defaults to 3.
+
+        :returns: List[ChampionMasteryDto]
+        """
+        return self._request_endpoint(
+            self.top_by_puuid.__name__,
+            region,
+            ChampionMasteryApiV4Urls.top_by_puuid,
+            puuid=puuid,
+            count=count,
+        )
+
+    def scores_by_puuid(self, region: str, puuid: str):
         """
         Get a player's total champion mastery score, which is the sum of individual
         champion mastery levels
 
-        :param string region:                   the region to execute this request on
-        :param string encrypted_summoner_id:    Summoner ID associated with the player
+        :param string region:   the region to execute this request on
+        :param string puuid:    PUUID of the player
 
         :returns: int
         """
         return self._request_endpoint(
-            self.scores_by_summoner.__name__,
+            self.scores_by_puuid.__name__,
             region,
-            ChampionMasteryApiV4Urls.scores_by_summoner,
-            encrypted_summoner_id=encrypted_summoner_id,
+            ChampionMasteryApiV4Urls.scores_by_puuid,
+            puuid=puuid,
         )
diff --git a/src/riotwatcher/_apis/league_of_legends/urls/ChampionMasteryApiUrls.py b/src/riotwatcher/_apis/league_of_legends/urls/ChampionMasteryApiUrls.py
index 928b6a8..570b4f9 100644
--- a/src/riotwatcher/_apis/league_of_legends/urls/ChampionMasteryApiUrls.py
+++ b/src/riotwatcher/_apis/league_of_legends/urls/ChampionMasteryApiUrls.py
@@ -8,12 +8,11 @@ class ChampionMasteryV4Endpoint(LeagueEndpoint):
 
 
 class ChampionMasteryApiV4Urls:
-    by_summoner = ChampionMasteryV4Endpoint(
-        "/champion-masteries/by-summoner/{encrypted_summoner_id}"
+    by_puuid = ChampionMasteryV4Endpoint("/champion-masteries/by-puuid/{puuid}")
+    by_puuid_by_champion = ChampionMasteryV4Endpoint(
+        "/champion-masteries/by-puuid/{puuid}/by-champion/{champion_id}"
     )
-    by_summoner_by_champion = ChampionMasteryV4Endpoint(
-        "/champion-masteries/by-summoner/{encrypted_summoner_id}/by-champion/{champion_id}"
-    )
-    scores_by_summoner = ChampionMasteryV4Endpoint(
-        "/scores/by-summoner/{encrypted_summoner_id}"
+    top_by_puuid = ChampionMasteryV4Endpoint(
+        "/champion-masteries/by-puuid/{puuid}/top", count=int
     )
+    scores_by_puuid = ChampionMasteryV4Endpoint("/scores/by-puuid/{puuid}")


Test patch:
diff --git a/tests/_apis/league_of_legends/test_ChampionMasteryApiV4.py b/tests/_apis/league_of_legends/test_ChampionMasteryApiV4.py
index 37e7b27..6cd9f91 100644
--- a/tests/_apis/league_of_legends/test_ChampionMasteryApiV4.py
+++ b/tests/_apis/league_of_legends/test_ChampionMasteryApiV4.py
@@ -8,67 +8,108 @@ from riotwatcher._apis.league_of_legends import ChampionMasteryApiV4
 @pytest.mark.lol
 @pytest.mark.unit
 class TestChampionMasteryApiV4:
-    def test_by_summoner(self):
+    def test_by_puuid(self):
         mock_base_api = MagicMock()
         expected_return = object()
         mock_base_api.raw_request.return_value = expected_return
 
         mastery = ChampionMasteryApiV4(mock_base_api)
-        region = "afas"
-        encrypted_summoner_id = "15462"
+        region = "sfsfa"
+        puuid = "15357"
 
-        ret = mastery.by_summoner(region, encrypted_summoner_id)
+        ret = mastery.by_puuid(region, puuid)
 
         mock_base_api.raw_request.assert_called_once_with(
             ChampionMasteryApiV4.__name__,
-            mastery.by_summoner.__name__,
+            mastery.by_puuid.__name__,
             region,
-            f"https://{region}.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-summoner/{encrypted_summoner_id}",
+            f"https://{region}.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}",
             {},
         )
 
         assert ret is expected_return
 
-    def test_summoner_by_champion(self):
+    def test_by_puuid_by_champion(self):
         mock_base_api = MagicMock()
         expected_return = object()
         mock_base_api.raw_request.return_value = expected_return
 
         mastery = ChampionMasteryApiV4(mock_base_api)
         region = "fsgs"
-        encrypted_summoner_id = "53526"
+        puuid = "53526"
         champion_id = 7
 
-        ret = mastery.by_summoner_by_champion(
-            region, encrypted_summoner_id, champion_id
-        )
+        ret = mastery.by_puuid_by_champion(region, puuid, champion_id)
 
         mock_base_api.raw_request.assert_called_once_with(
             ChampionMasteryApiV4.__name__,
-            mastery.by_summoner_by_champion.__name__,
+            mastery.by_puuid_by_champion.__name__,
             region,
-            f"https://{region}.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-summoner/{encrypted_summoner_id}/by-champion/{champion_id}",
+            f"https://{region}.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}/by-champion/{champion_id}",
             {},
         )
 
         assert ret is expected_return
 
-    def test_scored_by_summoner(self):
+    def test_top_by_puuid(self):
         mock_base_api = MagicMock()
         expected_return = object()
         mock_base_api.raw_request.return_value = expected_return
 
         mastery = ChampionMasteryApiV4(mock_base_api)
-        region = "fsgs"
-        encrypted_summoner_id = "6243"
+        region = "fdsfs"
+        puuid = "123415r"
+        count = 15
+
+        ret = mastery.top_by_puuid(region, puuid, count=count)
+
+        mock_base_api.raw_request.assert_called_once_with(
+            ChampionMasteryApiV4.__name__,
+            mastery.top_by_puuid.__name__,
+            region,
+            f"https://{region}.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}/top",
+            {"count": count},
+        )
+
+        assert ret is expected_return
+
+    def test_top_by_puuid_default_count(self):
+        mock_base_api = MagicMock()
+        expected_return = object()
+        mock_base_api.raw_request.return_value = expected_return
+
+        mastery = ChampionMasteryApiV4(mock_base_api)
+        region = "fdsfs"
+        puuid = "123415r"
+
+        ret = mastery.top_by_puuid(region, puuid)
+
+        mock_base_api.raw_request.assert_called_once_with(
+            ChampionMasteryApiV4.__name__,
+            mastery.top_by_puuid.__name__,
+            region,
+            f"https://{region}.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}/top",
+            {"count": None},
+        )
+
+        assert ret is expected_return
+
+    def test_scores_by_puuid(self):
+        mock_base_api = MagicMock()
+        expected_return = object()
+        mock_base_api.raw_request.return_value = expected_return
+
+        mastery = ChampionMasteryApiV4(mock_base_api)
+        region = "fdsfs"
+        puuid = "123415r"
 
-        ret = mastery.scores_by_summoner(region, encrypted_summoner_id)
+        ret = mastery.scores_by_puuid(region, puuid)
 
         mock_base_api.raw_request.assert_called_once_with(
             ChampionMasteryApiV4.__name__,
-            mastery.scores_by_summoner.__name__,
+            mastery.scores_by_puuid.__name__,
             region,
-            f"https://{region}.api.riotgames.com/lol/champion-mastery/v4/scores/by-summoner/{encrypted_summoner_id}",
+            f"https://{region}.api.riotgames.com/lol/champion-mastery/v4/scores/by-puuid/{puuid}",
             {},
         )
 
diff --git a/tests/integration/league_of_legends/test_ChampionMasteryApiV4.py b/tests/integration/league_of_legends/test_ChampionMasteryApiV4.py
index f32ccfb..8de47c0 100644
--- a/tests/integration/league_of_legends/test_ChampionMasteryApiV4.py
+++ b/tests/integration/league_of_legends/test_ChampionMasteryApiV4.py
@@ -21,43 +21,56 @@ import pytest
         "pbe1",
     ],
 )
-@pytest.mark.parametrize("encrypted_summoner_id", ["50", "424299938281", "rtbf12345"])
+@pytest.mark.parametrize("puuid", ["50", "rtbf12345"])
 class TestChampionMasteryApiV4(object):
-    def test_by_summoner(self, lol_context, region, encrypted_summoner_id):
-        actual_response = lol_context.watcher.champion_mastery.by_summoner(
-            region, encrypted_summoner_id
-        )
+    def test_by_puuid(self, lol_context, region, puuid):
+        actual_response = lol_context.watcher.champion_mastery.by_puuid(region, puuid)
 
         lol_context.verify_api_call(
             region,
-            f"/lol/champion-mastery/v4/champion-masteries/by-summoner/{encrypted_summoner_id}",
+            f"/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}",
             {},
             actual_response,
         )
 
     @pytest.mark.parametrize("champion_id", [0, 1, 9999999999, 150])
-    def test_by_summoner_by_champion(
-        self, lol_context, region, encrypted_summoner_id, champion_id
-    ):
-        actual_response = lol_context.watcher.champion_mastery.by_summoner_by_champion(
-            region, encrypted_summoner_id, champion_id
+    def test_by_puuid_by_champion(self, lol_context, region, puuid, champion_id):
+        actual_response = lol_context.watcher.champion_mastery.by_puuid_by_champion(
+            region, puuid, champion_id
         )
 
         lol_context.verify_api_call(
             region,
-            f"/lol/champion-mastery/v4/champion-masteries/by-summoner/{encrypted_summoner_id}/by-champion/{champion_id}",
+            f"/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}/by-champion/{champion_id}",
             {},
             actual_response,
         )
 
-    def test_scores_by_summoner(self, lol_context, region, encrypted_summoner_id):
-        actual_response = lol_context.watcher.champion_mastery.scores_by_summoner(
-            region, encrypted_summoner_id
+    @pytest.mark.parametrize("count", [None, 1, 20])
+    def test_top_by_puuid(self, lol_context, region, puuid, count):
+        params = {}
+        if count is not None:
+            params["count"] = count
+
+        actual_response = lol_context.watcher.champion_mastery.top_by_puuid(
+            region, puuid, **params
+        )
+
+        lol_context.verify_api_call(
+            region,
+            f"/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}/top",
+            params,
+            actual_response,
+        )
+
+    def test_scores_by_puuid(self, lol_context, region, puuid):
+        actual_response = lol_context.watcher.champion_mastery.scores_by_puuid(
+            region, puuid
         )
 
         lol_context.verify_api_call(
             region,
-            f"/lol/champion-mastery/v4/scores/by-summoner/{encrypted_summoner_id}",
+            f"/lol/champion-mastery/v4/scores/by-puuid/{puuid}",
             {},
             actual_response,
         )