openapi-python-client 0.18.0__py3-none-any.whl → 0.19.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- """ Generate modern Python clients from OpenAPI """
1
+ """Generate modern Python clients from OpenAPI"""
2
2
 
3
3
  import json
4
4
  import mimetypes
@@ -35,6 +35,7 @@ class ConfigFile(BaseModel):
35
35
  """
36
36
 
37
37
  class_overrides: Optional[Dict[str, ClassOverride]] = None
38
+ content_type_overrides: Optional[Dict[str, str]] = None
38
39
  project_name_override: Optional[str] = None
39
40
  package_name_override: Optional[str] = None
40
41
  package_version_override: Optional[str] = None
@@ -70,6 +71,7 @@ class Config:
70
71
  http_timeout: int
71
72
  document_source: Union[Path, str]
72
73
  file_encoding: str
74
+ content_type_overrides: Dict[str, str]
73
75
 
74
76
  @staticmethod
75
77
  def from_sources(
@@ -91,6 +93,7 @@ class Config:
91
93
  config = Config(
92
94
  meta_type=meta_type,
93
95
  class_overrides=config_file.class_overrides or {},
96
+ content_type_overrides=config_file.content_type_overrides or {},
94
97
  project_name_override=config_file.project_name_override,
95
98
  package_name_override=config_file.package_name_override,
96
99
  package_version_override=config_file.package_version_override,
@@ -1,4 +1,4 @@
1
- """ Classes representing the data in the OpenAPI schema """
1
+ """Classes representing the data in the OpenAPI schema"""
2
2
 
3
3
  __all__ = ["GeneratorData", "import_string_from_class"]
4
4
 
@@ -56,7 +56,7 @@ def body_from_data(
56
56
  prefix_type_names = len(body_content) > 1
57
57
 
58
58
  for content_type, media_type in body_content.items():
59
- simplified_content_type = get_content_type(content_type)
59
+ simplified_content_type = get_content_type(content_type, config)
60
60
  if simplified_content_type is None:
61
61
  bodies.append(
62
62
  ParseError(
@@ -26,7 +26,7 @@ from .properties import (
26
26
  from .properties.schemas import parameter_from_reference
27
27
  from .responses import Response, response_from_data
28
28
 
29
- _PATH_PARAM_REGEX = re.compile("{([a-zA-Z_][a-zA-Z0-9_]*)}")
29
+ _PATH_PARAM_REGEX = re.compile("{([a-zA-Z_-][a-zA-Z0-9_-]*)}")
30
30
 
31
31
 
32
32
  def import_string_from_class(class_: Class, prefix: str = "") -> str:
@@ -114,8 +114,7 @@ class RequestBodyParser(Protocol):
114
114
 
115
115
  def __call__(
116
116
  self, *, body: oai.RequestBody, schemas: Schemas, parent_name: str, config: Config
117
- ) -> Tuple[Union[Property, PropertyError, None], Schemas]:
118
- ... # pragma: no cover
117
+ ) -> Tuple[Union[Property, PropertyError, None], Schemas]: ... # pragma: no cover
119
118
 
120
119
 
121
120
  @dataclass
@@ -380,6 +379,8 @@ class Endpoint:
380
379
  return ParseError(
381
380
  detail=f"Incorrect path templating for {endpoint.path} (Path parameters do not match with path)",
382
381
  )
382
+ for parameter in endpoint.path_parameters:
383
+ endpoint.path = endpoint.path.replace(f"{{{parameter.name}}}", f"{{{parameter.python_name}}}")
383
384
  return endpoint
384
385
 
385
386
  @staticmethod
@@ -78,8 +78,7 @@ class ConstProperty(PropertyProtocol):
78
78
 
79
79
  @staticmethod
80
80
  @overload
81
- def _convert_value(value: Any) -> Value:
82
- ... # pragma: no cover
81
+ def _convert_value(value: Any) -> Value: ... # pragma: no cover
83
82
 
84
83
  @staticmethod
85
84
  def _convert_value(value: Any) -> Value | None:
@@ -61,8 +61,7 @@ class StringProperty(PropertyProtocol):
61
61
 
62
62
  @classmethod
63
63
  @overload
64
- def convert_value(cls, value: Any) -> Value:
65
- ... # pragma: no cover
64
+ def convert_value(cls, value: Any) -> Value: ... # pragma: no cover
66
65
 
67
66
  @classmethod
68
67
  def convert_value(cls, value: Any) -> Value | None:
@@ -37,8 +37,8 @@ class Response:
37
37
  data: Union[oai.Response, oai.Reference] # Original data which created this response, useful for custom templates
38
38
 
39
39
 
40
- def _source_by_content_type(content_type: str) -> Optional[_ResponseSource]:
41
- parsed_content_type = utils.get_content_type(content_type)
40
+ def _source_by_content_type(content_type: str, config: Config) -> Optional[_ResponseSource]:
41
+ parsed_content_type = utils.get_content_type(content_type, config)
42
42
  if parsed_content_type is None:
43
43
  return None
44
44
 
@@ -114,7 +114,7 @@ def response_from_data(
114
114
  )
115
115
 
116
116
  for content_type, media_type in content.items():
117
- source = _source_by_content_type(content_type)
117
+ source = _source_by_content_type(content_type, config)
118
118
  if source is not None:
119
119
  schema_data = media_type.media_type_schema
120
120
  break
@@ -37,13 +37,13 @@ class Client:
37
37
  """
38
38
  {% macro attributes() %}
39
39
  raise_on_unexpected_status: bool = field(default=False, kw_only=True)
40
- _base_url: str
41
- _cookies: Dict[str, str] = field(factory=dict, kw_only=True)
42
- _headers: Dict[str, str] = field(factory=dict, kw_only=True)
43
- _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True)
44
- _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True)
45
- _follow_redirects: bool = field(default=False, kw_only=True)
46
- _httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True)
40
+ _base_url: str = field(alias="base_url")
41
+ _cookies: Dict[str, str] = field(factory=dict, kw_only=True, alias="cookies")
42
+ _headers: Dict[str, str] = field(factory=dict, kw_only=True, alias="headers")
43
+ _timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True, alias="timeout")
44
+ _verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True, alias="verify_ssl")
45
+ _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects")
46
+ _httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args")
47
47
  _client: Optional[httpx.Client] = field(default=None, init=False)
48
48
  _async_client: Optional[httpx.AsyncClient] = field(default=None, init=False)
49
49
  {% endmacro %}{{ attributes() }}
@@ -163,4 +163,4 @@ class AuthenticatedClient:
163
163
  auth_header_name: str = "Authorization"
164
164
 
165
165
  {{ builders("AuthenticatedClient") }}
166
- {{ httpx_stuff("AuthenticatedClient", "self._headers[self.auth_header_name] = f\"{self.prefix} {self.token}\" if self.prefix else self.token") }}
166
+ {{ httpx_stuff("AuthenticatedClient", "self._headers[self.auth_header_name] = f\"{self.prefix} {self.token}\" if self.prefix else self.token") }}
@@ -31,7 +31,7 @@ def _get_kwargs(
31
31
  {% if endpoint.path_parameters %}
32
32
  "url": "{{ endpoint.path }}".format(
33
33
  {%- for parameter in endpoint.path_parameters -%}
34
- {{parameter.name}}={{parameter.python_name}},
34
+ {{parameter.python_name}}={{parameter.python_name}},
35
35
  {%- endfor -%}
36
36
  ),
37
37
  {% else %}
@@ -7,6 +7,8 @@ class UnexpectedStatus(Exception):
7
7
  self.status_code = status_code
8
8
  self.content = content
9
9
 
10
- super().__init__(f"Unexpected status code: {status_code}")
10
+ super().__init__(
11
+ f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}"
12
+ )
11
13
 
12
14
  __all__ = ["UnexpectedStatus"]
@@ -25,7 +25,7 @@ dependencies = [
25
25
  ]
26
26
 
27
27
  [tool.pdm]
28
- package-type = "library"
28
+ distribution = true
29
29
  {% endif %}
30
30
  {% if poetry %}
31
31
 
@@ -6,6 +6,8 @@ from email.message import Message
6
6
  from keyword import iskeyword
7
7
  from typing import Any
8
8
 
9
+ from .config import Config
10
+
9
11
  DELIMITERS = r"\. _-"
10
12
 
11
13
 
@@ -105,10 +107,11 @@ def remove_string_escapes(value: str) -> str:
105
107
  return value.replace('"', r"\"")
106
108
 
107
109
 
108
- def get_content_type(content_type: str) -> str | None:
110
+ def get_content_type(content_type: str, config: Config) -> str | None:
109
111
  """
110
112
  Given a string representing a content type with optional parameters, returns the content type only
111
113
  """
114
+ content_type = config.content_type_overrides.get(content_type, content_type)
112
115
  message = Message()
113
116
  message.add_header("Content-Type", content_type)
114
117
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: openapi-python-client
3
- Version: 0.18.0
3
+ Version: 0.19.1
4
4
  Summary: Generate modern Python clients from OpenAPI
5
5
  Project-URL: repository, https://github.com/openapi-generators/openapi-python-client
6
6
  Author-email: Dylan Anthony <contact@dylananthony.com>
@@ -26,9 +26,9 @@ Requires-Dist: jinja2<4.0.0,>=3.0.0
26
26
  Requires-Dist: pydantic<3.0.0,>=2.1.1
27
27
  Requires-Dist: python-dateutil<3.0.0,>=2.8.1
28
28
  Requires-Dist: pyyaml<7.0,>=6.0
29
- Requires-Dist: ruff<0.3,>=0.2
29
+ Requires-Dist: ruff<0.4,>=0.2
30
30
  Requires-Dist: shellingham<2.0.0,>=1.3.2
31
- Requires-Dist: typer<0.10,>0.6
31
+ Requires-Dist: typer<0.12,>0.6
32
32
  Requires-Dist: typing-extensions<5.0.0,>=4.8.0
33
33
  Description-Content-Type: text/markdown
34
34
 
@@ -190,6 +190,16 @@ If this option results in conflicts, you will need to manually override class na
190
190
 
191
191
  By default, the timeout for retrieving the schema file via HTTP is 5 seconds. In case there is an error when retrieving the schema, you might try and increase this setting to a higher value.
192
192
 
193
+ ### content_type_overrides
194
+
195
+ Normally, `openapi-python-client` will skip any bodies or responses that it doesn't recognize the content type for.
196
+ This config tells the generator to treat a given content type like another.
197
+
198
+ ```yaml
199
+ content_type_overrides:
200
+ application/zip: application/octet-stream
201
+ ```
202
+
193
203
  [changelog.md]: CHANGELOG.md
194
204
  [poetry]: https://python-poetry.org/
195
205
  [PDM]: https://pdm-project.org/latest/
@@ -1,18 +1,18 @@
1
- openapi_python_client/__init__.py,sha256=SC1bT_ZWzCc5TP3ZwPaRRcxf_H8wCOMbj353hLtgXlE,14144
1
+ openapi_python_client/__init__.py,sha256=qbA68XeTN8YjMcHxLk2T2CtaKMbqRbOYyahpUmikNEA,14142
2
2
  openapi_python_client/__main__.py,sha256=wcCrL4PjG51r5wVKqJhcoJPTLfHW0wNbD31DrUN0MWI,28
3
3
  openapi_python_client/cli.py,sha256=xechvVovBJOpknubtm_Fd5NP4vT1-J96F4cMofpzaVo,6073
4
- openapi_python_client/config.py,sha256=L-yVu65cY3Fe1D6IjjLRNtkEM10AD7r2n_0YXpIl3dI,3410
4
+ openapi_python_client/config.py,sha256=9pxDar4EmiE0rnyZfXOEOWIDPJHNii_icn-VO-0OYgk,3590
5
5
  openapi_python_client/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
6
- openapi_python_client/utils.py,sha256=EvstEcRMP_SBGR0rhqHmxxA8qQj-BCakzNS8hgpB-JA,3823
7
- openapi_python_client/parser/__init__.py,sha256=nd03to3C55KDOL3sg63VYc5O_HOA7OuYfz8Ok471b6w,179
8
- openapi_python_client/parser/bodies.py,sha256=n26CjME-kA1PMH8gbqjFpmyXWd8SQTrHTz19PgPM4KU,3825
6
+ openapi_python_client/utils.py,sha256=BuobeCxNjKe28GcqCezeropyCfKKMutMUJDoUGQq-nM,3948
7
+ openapi_python_client/parser/__init__.py,sha256=dpY1jYmWFPBubtjKCZIlg2uHC_DLC-KpfuMNdQF8RUc,177
8
+ openapi_python_client/parser/bodies.py,sha256=OdUKHlUUIZxpXZT7e_angecetMSXOL44hN9hDrIXt10,3833
9
9
  openapi_python_client/parser/errors.py,sha256=TPyvRDreHGD3qGHHaKO4LVDWEPqay4BzIEf0MONwhMI,1225
10
- openapi_python_client/parser/openapi.py,sha256=y8hA-VjRiVk_hZhuEb23DEH11n1iONWkCUVGNcVHDZU,21824
11
- openapi_python_client/parser/responses.py,sha256=YOEGmcGTVNgjgIQtBidZWf8E9HCVsaUkzyUiecVtpM0,4354
10
+ openapi_python_client/parser/openapi.py,sha256=lLz-mQLqZ0ylZAmgJ8YgbNySbm8LddmSWvo5nt1BP9s,21976
11
+ openapi_python_client/parser/responses.py,sha256=hrxI5pRqeyCEJTJPCwrs85wYpAm4HSD-jiFTi2bSzXs,4386
12
12
  openapi_python_client/parser/properties/__init__.py,sha256=uu_9MWrnKLU58V6mqTtRRFoXBJ583NJZafW6dnC6ihA,15191
13
13
  openapi_python_client/parser/properties/any.py,sha256=7fR8qDNjMH4vd4vS2UjkJhgneLnid8UwSJmNH9Mktho,1187
14
14
  openapi_python_client/parser/properties/boolean.py,sha256=6TRRJMfZq3tA1JjJ3CCDfDcqIvSMm-nu19sJHXJOpAA,1955
15
- openapi_python_client/parser/properties/const.py,sha256=Qb3_oLIvVtQyLqzardqxcVE61SyWmb17OaQuWy5yv0o,3794
15
+ openapi_python_client/parser/properties/const.py,sha256=6vsHJkyDjHQwY5aJC4SeGCKKfAgGJtZ5Ge_6HmZ9nEo,3786
16
16
  openapi_python_client/parser/properties/date.py,sha256=TiB1J5SLsIilER3TIk-SjAkI4SV1SGRaofg0uUEeQFQ,2325
17
17
  openapi_python_client/parser/properties/datetime.py,sha256=H1NgfeGcIyErC-6nJg3YAyUYL9dSbhGZkcJla-zKmEg,2353
18
18
  openapi_python_client/parser/properties/enum_property.py,sha256=ileLJkiRP35LxRpwiLUjpuWufSEcCEy3hmFmBZRa0Is,8215
@@ -25,7 +25,7 @@ openapi_python_client/parser/properties/none.py,sha256=3Q9kQcDD9JPfsRLJQQaq6GxEp
25
25
  openapi_python_client/parser/properties/property.py,sha256=qxD7T58txbjjz8MKgsP2wDAV5qpogcAxspZNVG94lkk,869
26
26
  openapi_python_client/parser/properties/protocol.py,sha256=qs1kjTowjzUaxcpwDz6npQE6mK3izc5xnkAPkMXEXeQ,7014
27
27
  openapi_python_client/parser/properties/schemas.py,sha256=rNpsP-wyuW9EUXLJP4DCKsY1QNGdb1ED3LjuvtGjSBY,8267
28
- openapi_python_client/parser/properties/string.py,sha256=8idAQDos_nsr3yY8mfUsf3fcmf_f1wZtylP3yxzBS1g,2004
28
+ openapi_python_client/parser/properties/string.py,sha256=9yN2tUdlebwzTxSb0JjD8J13adD1PTwYVEHL-HnMuxg,1996
29
29
  openapi_python_client/parser/properties/union.py,sha256=SjvnzPsA1jvKWw1JZEPUSNysdsZbzy8WaqcTmi-h7dk,8086
30
30
  openapi_python_client/schema/3.0.3.md,sha256=0a25-q_HFDVcsxOnMOGeTo67K4FtLHqMfI5U8VwneJg,126244
31
31
  openapi_python_client/schema/3.1.0.md,sha256=O4SlQ2wux5Sa68Q9jrCcZYEJ5RcqXniJ9pSixtR15Rc,131397
@@ -68,17 +68,17 @@ openapi_python_client/schema/openapi_schema_pydantic/xml.py,sha256=-qME-ijLKa4bh
68
68
  openapi_python_client/templates/.gitignore.jinja,sha256=SwZvl9qyKaHN9YjwaQrBsmpAclN11usf9Gohz1SFVg8,195
69
69
  openapi_python_client/templates/README.md.jinja,sha256=Ht7n3bEff22HtCt892wqZf9xClqNLWPvQ83a8nyz_Jc,5047
70
70
  openapi_python_client/templates/api_init.py.jinja,sha256=87ApBzKyGb5zsgTMOkQXDqsLZCmaSFoJMwbGzCDQZMw,47
71
- openapi_python_client/templates/client.py.jinja,sha256=mZ6j6DztHBzyHftYosiZnyswmYx0NIpOw6ohVvox684,7249
71
+ openapi_python_client/templates/client.py.jinja,sha256=tBr7gtf6PcTTWZSnsvFvKNWfssnLNW4URvFZwP_9QDc,7393
72
72
  openapi_python_client/templates/endpoint_init.py.jinja,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
73
  openapi_python_client/templates/endpoint_macros.py.jinja,sha256=rCmoHFbLP5gw40quYt-fdhjM1WPkGqYZ7P6gfo2HRpY,6155
74
- openapi_python_client/templates/endpoint_module.py.jinja,sha256=uYnWvEjYoVftUfEdlYIie2LuGv-8m1x1gJk29orkja8,5106
75
- openapi_python_client/templates/errors.py.jinja,sha256=_GGQR07QqeoL_GBsWLovjjU6H220cg5N3hcTbgivSGw,468
74
+ openapi_python_client/templates/endpoint_module.py.jinja,sha256=pTh7NaeCa2g-7x66k6hlKWVeDl9O2txjQC6MUQ4Yjfw,5113
75
+ openapi_python_client/templates/errors.py.jinja,sha256=trp-p5qn1_JLRxGZhdHtICaNPaCrcDCe4TgIihBravk,546
76
76
  openapi_python_client/templates/helpers.jinja,sha256=vNYu1mL_cfrV3c4eMvVlUhl8Tzb-k6GNCWK7FUFAsuw,257
77
77
  openapi_python_client/templates/int_enum.py.jinja,sha256=z4d2hVsdgmlxUB1fbVs4w8tJaq2SdmhLjs4mjbZ5GLw,224
78
78
  openapi_python_client/templates/model.py.jinja,sha256=aQwzT5g_4YVNaTQ_YnyOgzYfV9bJ5GZi6xH9PGQlJL0,7336
79
79
  openapi_python_client/templates/models_init.py.jinja,sha256=T2Sj1uGxWlYb5Vc8G3cC65KMDk-mtnEH0g5Xp0xE1Ro,233
80
80
  openapi_python_client/templates/package_init.py.jinja,sha256=EMOU4q7ceaoKJItVKu52vrRTD-BzhrNBjB8VZHN5LgY,196
81
- openapi_python_client/templates/pyproject.toml.jinja,sha256=GsnEjHcjr005M60x2Ey959D5yvZ2p5EVgr4nl3WIA3w,1058
81
+ openapi_python_client/templates/pyproject.toml.jinja,sha256=M3cndKCCO1grCCD6HGpOs1D5i5wx7CC8pWezlxcxUhE,1053
82
82
  openapi_python_client/templates/pyproject_ruff.toml.jinja,sha256=OgFfCd9Ca3YsU8WdCxqJoJdCJEtzADpxAxfMghqzn80,74
83
83
  openapi_python_client/templates/setup.py.jinja,sha256=65P9kjUtLBijLbRnehigDdyE1qvmRf2gobkv-uftqq4,611
84
84
  openapi_python_client/templates/str_enum.py.jinja,sha256=5SxGRu_sZxEILC425D45YSu8s12vJGM2PWwYWjOUl8M,232
@@ -96,8 +96,8 @@ openapi_python_client/templates/property_templates/list_property.py.jinja,sha256
96
96
  openapi_python_client/templates/property_templates/model_property.py.jinja,sha256=a5wC34bkUbgP7KT4qMSrWqdrvf4s0jHI8fIzWp6MIns,1300
97
97
  openapi_python_client/templates/property_templates/property_macros.py.jinja,sha256=s0DqGOc8rbEKptUtH1tAht08wahN3xXpaGfyzVa3Kog,580
98
98
  openapi_python_client/templates/property_templates/union_property.py.jinja,sha256=fOpNOlmhGgUfJDYJDOnu5ZIMVvjn5fYpa2osxbIucWM,3388
99
- openapi_python_client-0.18.0.dist-info/METADATA,sha256=Y6I89wrQGpNLBNV8WtuhjJGX6wBu2Lvwg-BBY_a3-Xw,9797
100
- openapi_python_client-0.18.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
101
- openapi_python_client-0.18.0.dist-info/entry_points.txt,sha256=iRfSdN2foASZXr8GghkYa6KRXkDgO0EFfLut5IXoBTU,72
102
- openapi_python_client-0.18.0.dist-info/licenses/LICENSE,sha256=4dpxQYqY0DB3aTauRrqYRuu6BVNsPSJdYeUT3sH6pQY,1075
103
- openapi_python_client-0.18.0.dist-info/RECORD,,
99
+ openapi_python_client-0.19.1.dist-info/METADATA,sha256=vuhgn_jkHEnCNprvaRboQoJ37khkrcDDzjjaszemaK8,10099
100
+ openapi_python_client-0.19.1.dist-info/WHEEL,sha256=uNdcs2TADwSd5pVaP0Z_kcjcvvTUklh2S7bxZMF8Uj0,87
101
+ openapi_python_client-0.19.1.dist-info/entry_points.txt,sha256=iRfSdN2foASZXr8GghkYa6KRXkDgO0EFfLut5IXoBTU,72
102
+ openapi_python_client-0.19.1.dist-info/licenses/LICENSE,sha256=4dpxQYqY0DB3aTauRrqYRuu6BVNsPSJdYeUT3sH6pQY,1075
103
+ openapi_python_client-0.19.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.21.1
2
+ Generator: hatchling 1.22.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any