Skip to content

Commit bd3fdbf

Browse files
committed
fix: Allow parameters named "client" and "url"
1 parent 7e8d627 commit bd3fdbf

File tree

4 files changed

+159
-3
lines changed

4 files changed

+159
-3
lines changed

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

Lines changed: 5 additions & 1 deletion
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
Lines changed: 119 additions & 0 deletions
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

Lines changed: 29 additions & 0 deletions
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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
Schemas,
2323
build_parameters,
2424
build_schemas,
25-
property_from_data,
25+
property_from_data, NoneProperty, AnyProperty,
2626
)
2727
from .properties.schemas import parameter_from_reference
2828
from .responses import Response, response_from_data
@@ -351,6 +351,10 @@ def add_parameters(
351351
oai.ParameterLocation.PATH: endpoint.path_parameters,
352352
oai.ParameterLocation.HEADER: endpoint.header_parameters,
353353
oai.ParameterLocation.COOKIE: endpoint.cookie_parameters,
354+
"RESERVED": { # These can't be param names because codegen needs them as vars, the properties don't matter
355+
"client": AnyProperty("client", True, False, None, PythonIdentifier("client", ""), None, None),
356+
"url": AnyProperty("url", True, False, None, PythonIdentifier("url", ""), None, None),
357+
},
354358
}
355359

356360
for param in data.parameters:
@@ -412,7 +416,7 @@ def add_parameters(
412416
continue
413417
existing_prop: Property = parameters_dict[prop.name]
414418
# Existing should be converted too for consistency
415-
endpoint.used_python_identifiers.remove(existing_prop.python_name)
419+
endpoint.used_python_identifiers.discard(existing_prop.python_name)
416420
existing_prop.set_python_name(new_name=f"{existing_prop.name}_{location}", config=config)
417421

418422
if existing_prop.python_name in endpoint.used_python_identifiers:

0 commit comments

Comments
 (0)