Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions serpapi/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ def search(self, params: dict = None, **kwargs):

**Learn more**: https://serpapi.com/search-api
"""
if params is None:
params = {}
params = dict(params) if params is not None else {}

# These are arguments that should be passed to the underlying requests.request call.
request_kwargs = {}
Expand All @@ -63,8 +62,7 @@ def search_archive(self, params: dict = None, **kwargs):

**Learn more**: https://serpapi.com/search-archive-api
"""
if params is None:
params = {}
params = dict(params) if params is not None else {}

# These are arguments that should be passed to the underlying requests.request call.
request_kwargs = {}
Expand Down Expand Up @@ -141,8 +139,7 @@ def locations(self, params: dict = None, **kwargs):

**Learn more**: https://serpapi.com/locations-api
"""
if params is None:
params = {}
params = dict(params) if params is not None else {}

# These are arguments that should be passed to the underlying requests.request call.
request_kwargs = {}
Expand Down Expand Up @@ -171,8 +168,7 @@ def account(self, params: dict = None, **kwargs):
**Learn more**: https://serpapi.com/account-api
"""

if params is None:
params = {}
params = dict(params) if params is not None else {}

# These are arguments that should be passed to the underlying requests.request call.
request_kwargs = {}
Expand Down
3 changes: 3 additions & 0 deletions serpapi/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ def __init__(self, *, api_key=None, timeout=None):
self.session = requests.Session()

def request(self, method, path, params, *, assert_200=True, **kwargs):
# Keep API key injection local to this request.
params = dict(params)

# Inject the API Key into the params.
request_data = kwargs.get("data")
api_key_in_data = isinstance(request_data, dict) and "api_key" in request_data
Expand Down
79 changes: 79 additions & 0 deletions tests/test_parameter_reuse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import copy
from urllib.parse import parse_qs, urlsplit

import pytest
import requests

from serpapi import Client


PARAMS = {
"search": {"q": "coffee"},
"search_archive": {"search_id": "example-search"},
"locations": {"q": "Austin"},
"account": {},
}


def capture_requests(monkeypatch, client):
sent = []

def send(request, **kwargs):
sent.append(request)
response = requests.Response()
response.status_code = 200
response.headers["Content-Type"] = "application/json"
response._content = b'{}'
response.request = request
return response

monkeypatch.setattr(client.session, "send", send)
return sent


@pytest.mark.parametrize("method", list(PARAMS))
@pytest.mark.parametrize("explicit_key", [False, True])
def test_reused_params_keep_each_clients_key(monkeypatch, method, explicit_key):
first = Client(api_key="client-one")
second = Client(api_key="client-two")
first_sent = capture_requests(monkeypatch, first)
second_sent = capture_requests(monkeypatch, second)
params = dict(PARAMS[method])
if explicit_key:
params["api_key"] = "caller-key"
original = copy.deepcopy(params)
getattr(first, method)(params)
getattr(second, method)(params)
expected = ["caller-key", "caller-key"] if explicit_key else ["client-one", "client-two"]
actual = [parse_qs(urlsplit(sent[0].url).query)["api_key"][0] for sent in (first_sent, second_sent)]
assert actual == expected
assert params == original


@pytest.mark.parametrize("method,override", [
("search", {"q": "tea"}),
("search_archive", {"output": "json"}),
("locations", {"limit": 2}),
("account", {"api_key": "caller-key"}),
])
def test_keyword_overrides_do_not_mutate_params(monkeypatch, method, override):
client = Client(api_key="client-key")
sent = capture_requests(monkeypatch, client)
params = dict(PARAMS[method])
original = copy.deepcopy(params)
getattr(client, method)(params, **override)
query = parse_qs(urlsplit(sent[0].url).query)
for key, value in override.items():
assert query[key] == [str(value)]
assert params == original


@pytest.mark.parametrize("explicit_key", [False, True])
def test_direct_request_does_not_mutate_params(monkeypatch, explicit_key):
client = Client(api_key="client-key")
sent = capture_requests(monkeypatch, client)
params = {"api_key": "caller-key"} if explicit_key else {}
original = dict(params)
client.request("GET", "/search", params)
assert parse_qs(urlsplit(sent[0].url).query)["api_key"] == ["caller-key" if explicit_key else "client-key"]
assert params == original