diff --git a/pageviewapi/client.py b/pageviewapi/client.py index e55c852..589e734 100644 --- a/pageviewapi/client.py +++ b/pageviewapi/client.py @@ -11,6 +11,7 @@ from importlib.metadata import PackageNotFoundError, version from typing import Any +from urllib.parse import quote, unquote import requests @@ -100,7 +101,7 @@ def per_article( """ args = PA_ARGS.format( project=project, - page=page, + page=_quote_article_name(page), start=start, end=end, access=access, @@ -199,3 +200,7 @@ def _api(end_point: str, args: str, api_url: str = API_BASE_URL) -> dict[str, An else: response.raise_for_status() return {} # unreachable, satisfies type checker + + +def _quote_article_name(page: str) -> str: + return quote(unquote(page), safe="") diff --git a/tests/test_client.py b/tests/test_client.py index 5d4271d..d0b431b 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -11,6 +11,7 @@ ThrottlingException, ZeroOrDataNotLoadedException, _api, + _quote_article_name, aggregate, legacy_pagecounts, per_article, @@ -209,3 +210,26 @@ def test_api_returns_pageview_response(ok_response): with patch("requests.get", return_value=ok_response): result = per_article("en.wikipedia", "Paris", "20151106", "20151120") assert isinstance(result, PageviewResponse) + + +def test_quote_article_name_plain(): + assert _quote_article_name("Paris") == "Paris" + + +def test_quote_article_name_slash(): + assert _quote_article_name("AC/DC") == "AC%2FDC" + + +def test_per_article_encodes_space_in_page_name(ok_response): + with patch("requests.get", return_value=ok_response) as mock_get: + per_article("en.wikipedia", "New York", "20200101", "20200131") + url = mock_get.call_args[0][0] + assert "New%20York" in url + assert "New York" not in url + + +def test_per_article_encodes_slash_in_page_name(ok_response): + with patch("requests.get", return_value=ok_response) as mock_get: + per_article("en.wikipedia", "AC/DC", "20200101", "20200131") + url = mock_get.call_args[0][0] + assert "AC%2FDC" in url