Skip to content

Commit 5488307

Browse files
authored
fix: Allow parameters named "client" and "url" [#758, #762, #765]. Thanks @truenicoco & @juanber84!
* fix: Allow parameters named "client" and "url" * chore: Cleanup unused import * chore: Hold mypy's hand --------- Co-authored-by: Dylan Anthony <[email protected]>
1 parent e4a1c5a commit 5488307

File tree

4 files changed

+160
-3
lines changed

4 files changed

+160
-3
lines changed

end_to_end_tests/custom-templates-golden-record/my_test_api_client/api/default/__init__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import types
44

5-
from . import get_common_parameters, post_common_parameters
5+
from . import get_common_parameters, post_common_parameters, reserved_parameters
66

77

88
class DefaultEndpoints:
@@ -13,3 +13,7 @@ def get_common_parameters(cls) -> types.ModuleType:
1313
@classmethod
1414
def post_common_parameters(cls) -> types.ModuleType:
1515
return post_common_parameters
16+
17+
@classmethod
18+
def reserved_parameters(cls) -> types.ModuleType:
19+
return reserved_parameters
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from http import HTTPStatus
2+
from typing import Any, Dict, Optional
3+
4+
import httpx
5+
6+
from ... import errors
7+
from ...client import Client
8+
from ...types import UNSET, Response
9+
10+
11+
def _get_kwargs(
12+
*,
13+
client: Client,
14+
client_query: str,
15+
url_query: str,
16+
) -> Dict[str, Any]:
17+
url = "{}/naming/reserved-parameters".format(client.base_url)
18+
19+
headers: Dict[str, str] = client.get_headers()
20+
cookies: Dict[str, Any] = client.get_cookies()
21+
22+
params: Dict[str, Any] = {}
23+
params["client"] = client_query
24+
25+
params["url"] = url_query
26+
27+
params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
28+
29+
return {
30+
"method": "get",
31+
"url": url,
32+
"headers": headers,
33+
"cookies": cookies,
34+
"timeout": client.get_timeout(),
35+
"follow_redirects": client.follow_redirects,
36+
"params": params,
37+
}
38+
39+
40+
def _parse_response(*, client: Client, response: httpx.Response) -> Optional[Any]:
41+
if response.status_code == HTTPStatus.OK:
42+
return None
43+
if client.raise_on_unexpected_status:
44+
raise errors.UnexpectedStatus(response.status_code, response.content)
45+
else:
46+
return None
47+
48+
49+
def _build_response(*, client: Client, response: httpx.Response) -> Response[Any]:
50+
return Response(
51+
status_code=HTTPStatus(response.status_code),
52+
content=response.content,
53+
headers=response.headers,
54+
parsed=_parse_response(client=client, response=response),
55+
)
56+
57+
58+
def sync_detailed(
59+
*,
60+
client: Client,
61+
client_query: str,
62+
url_query: str,
63+
) -> Response[Any]:
64+
"""
65+
Args:
66+
client_query (str):
67+
url_query (str):
68+
69+
Raises:
70+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
71+
httpx.TimeoutException: If the request takes longer than Client.timeout.
72+
73+
Returns:
74+
Response[Any]
75+
"""
76+
77+
kwargs = _get_kwargs(
78+
client=client,
79+
client_query=client_query,
80+
url_query=url_query,
81+
)
82+
83+
response = httpx.request(
84+
verify=client.verify_ssl,
85+
**kwargs,
86+
)
87+
88+
return _build_response(client=client, response=response)
89+
90+
91+
async def asyncio_detailed(
92+
*,
93+
client: Client,
94+
client_query: str,
95+
url_query: str,
96+
) -> Response[Any]:
97+
"""
98+
Args:
99+
client_query (str):
100+
url_query (str):
101+
102+
Raises:
103+
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
104+
httpx.TimeoutException: If the request takes longer than Client.timeout.
105+
106+
Returns:
107+
Response[Any]
108+
"""
109+
110+
kwargs = _get_kwargs(
111+
client=client,
112+
client_query=client_query,
113+
url_query=url_query,
114+
)
115+
116+
async with httpx.AsyncClient(verify=client.verify_ssl) as _client:
117+
response = await _client.request(**kwargs)
118+
119+
return _build_response(client=client, response=response)

end_to_end_tests/openapi.json

+29
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,35 @@
11501150
}
11511151
}
11521152
},
1153+
"/naming/reserved-parameters": {
1154+
"description": "Ensure that parameters can't be named things that the code generator needs as variables",
1155+
"get": {
1156+
"operationId": "reserved-parameters",
1157+
"parameters": [
1158+
{
1159+
"name": "client",
1160+
"in": "query",
1161+
"required": true,
1162+
"schema": {
1163+
"type": "string"
1164+
}
1165+
},
1166+
{
1167+
"name": "url",
1168+
"in": "query",
1169+
"required": true,
1170+
"schema": {
1171+
"type": "string"
1172+
}
1173+
}
1174+
],
1175+
"responses": {
1176+
"200": {
1177+
"description": ""
1178+
}
1179+
}
1180+
}
1181+
},
11531182
"/parameter-references/{path_param}": {
11541183
"get": {
11551184
"tags": [

openapi_python_client/parser/openapi.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from ..utils import PythonIdentifier, get_content_type
1515
from .errors import GeneratorError, ParseError, PropertyError
1616
from .properties import (
17+
AnyProperty,
1718
Class,
1819
EnumProperty,
1920
ModelProperty,
@@ -346,11 +347,15 @@ def add_parameters(
346347
endpoint = deepcopy(endpoint)
347348

348349
unique_parameters: Set[Tuple[str, oai.ParameterLocation]] = set()
349-
parameters_by_location = {
350+
parameters_by_location: Dict[str, Dict[str, Property]] = {
350351
oai.ParameterLocation.QUERY: endpoint.query_parameters,
351352
oai.ParameterLocation.PATH: endpoint.path_parameters,
352353
oai.ParameterLocation.HEADER: endpoint.header_parameters,
353354
oai.ParameterLocation.COOKIE: endpoint.cookie_parameters,
355+
"RESERVED": { # These can't be param names because codegen needs them as vars, the properties don't matter
356+
"client": AnyProperty("client", True, False, None, PythonIdentifier("client", ""), None, None),
357+
"url": AnyProperty("url", True, False, None, PythonIdentifier("url", ""), None, None),
358+
},
354359
}
355360

356361
for param in data.parameters:
@@ -412,7 +417,7 @@ def add_parameters(
412417
continue
413418
existing_prop: Property = parameters_dict[prop.name]
414419
# Existing should be converted too for consistency
415-
endpoint.used_python_identifiers.remove(existing_prop.python_name)
420+
endpoint.used_python_identifiers.discard(existing_prop.python_name)
416421
existing_prop.set_python_name(new_name=f"{existing_prop.name}_{location}", config=config)
417422

418423
if existing_prop.python_name in endpoint.used_python_identifiers:

0 commit comments

Comments
 (0)