NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #2252 most downloaded on PyPI
Generate modern Python clients from OpenAPI
Last release 1 months ago
30 Aug 2026
Ships fairly regularly
a new release about every 4 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
7 years old
106 releases · first in 2020
One column per quarter.
Minimum required attrs version in generated clients is now 21.3.0.
attrs version in generated clients is now 21.3.0..) in them will be different.datetime is now considered a reserved word everywhere, so any properties which were named datetime will now be named datetime_.File uploads can now only accept binary payloads (BinaryIO).attrs version.New and improved docstrings in generated functions and classes [#503, #505, #551]. Thanks @rtaycher!
SSL verify argument to async clients [#533 & #510]. Thanks @fsvenson and @mvaught02!
Improve error messages related to invalid arrays and circular or recursive references [#519].
Add verify_ssl option to generated Client, allowing users to ignore or customize ssl verification (#497). Thanks @rtaycher!
Allow customization of post-generation steps with the post_hooks config option.
post_hooks config option.Expose python_identifier and class_name functions to custom templates to rename with the same behavior as the parser.
python_identifier and class_name functions to custom templates to rename with the same behavior as the parser.true and false as reserved words.Allow path parameters to be positional args [#429 & #464]. Thanks @tsotnikov!
UNSET and None static types for nullable or optional query params [#421, #380, #462]. Thanks @forest-benchling!PathItem can now be overriden in Operation [#458 & #457]. Thanks @mtovts!Support multipart requests with type: array [#452 & #451]. Thanks @csymeonides-mf @slamora and @dpursehouse
Normalize generated module names to allow more tags [#428 & #448]. Thanks @iamnoah & @forest-benchling!
__init__ files. [#442] Thanks @p1-ra!Any instead of None. Thanks @forest-benchling! [#417 & #445]This release is the first release from the new GitHub organization! As such, all the links in the repo have been updated to point at the new URL.
This release is the first release from the new GitHub organization! As such, all the links in the repo have been updated to point at the new URL.
UNSET values from form data [#430]. Thanks @p1-ra!Allow references to non-object, non-enum types [#371][#418][#425]. Thanks @p1-ra!
Some generated names will be different, solving some inconsistencies. (closes #369) (#375) Thanks @ramnes!
allOf, oneOf, or anyOf that referenced generated model will be used directly instead of generating a copy with another name. (#361)id and type will now be renamed in generated clients (#360, #378, #407). Thanks @dblanchette and @forest-benchling!Generated clients will no longer pass through None to query parameters. Previously, any query params set to None would surface as empty strings (per t
None to query parameters. Previously, any query params set to None would surface as empty strings (per the default behavior of httpx). This is contrary to the defaults indicated by the OpenAPI 3.0.3 spec. Ommitting these parameters makes us more compliant. If you require a style of null to be passed to your query parameters, please request support for the OpenAPI "style" attribute. Thank you to @forest-benchling and @bowenwr for a ton of input on this.--meta command line option for specifying what type of metadata should be generated:
poetry is the default value, same behavior you're used to in previous versionssetup will generate a pyproject.toml with no Poetry information, and instead create a setup.py with the
project info.none will not create a project folder at all, only the inner package folder (which won't be inner anymore)--file-encoding command line option (#330). Sets the encoding used when writing generated files (defaults to utf-8). Thanks @dongfangtianyu!python-dateutil to 2.8.0 for improved compatibility (#298 & #299). Thanks @bowenwr!from_dict method on generated models is now a @classmethod instead of @staticmethod (#215 & #292). Thanks @forest-benchling!.jinja, and all python-templates to end in .py.jinja to fix confusion with the latest version of mypy. Note this will break existing custom templates until you update your template file names.My Tag and MyTag are seen as two different tags but are then later unified, causing errors when creating directories. Thanks @p1-ra! (#328)from_dict and to_dict methods of models will now properly handle nullable and not required properties that are themselves generated models (#315). Thanks @forest-benchling!None and Unset properties for all types by unifying the checks (#334). Thanks @forest-benchling!Enum deserialization when the value is UNSET (#306). Thanks @bowenwr!Spacing and extra returns for Union types of additionalProperties (#266 & #268). Thanks @joshzana & @packyg!
additionalProperties (#266 & #268). Thanks @joshzana & @packyg!A bug in handling optional properties that are themselves models (introduced in 0.7.1) (#262). Thanks @packyg!
Support for additionalProperties attribute in OpenAPI schemas and "free-form" objects by adding an additional_properties attribute to generated models
additional_properties attribute to generated models. COMPATIBILITY NOTE: this will prevent any model property with a name that would be coerced to "additional_properties" in the generated client from generating properly (#218 & #252). Thanks @packyg!Any request/response field that is not required and wasn't specified is now set to UNSET instead of None.
required and wasn't specified is now set to UNSET instead of None.UNSET will not be sent along in API callstype=object will now be converted into classes, just like if they were created as ref components.
The previous behavior was a combination of skipping and using generic Dicts for these schemas.bytes when content-type was application/octet-stream will now return a File object if the type of the data is "binary", just like if you were submitting that type instead of receiving it.None.--custom-template-path option for providing custom jinja2 templates (#231 - Thanks @erichulburd!).declare_type param to transform and initial_value param to construct to improve flexibility (#241 - Thanks @packyg!).Union in generated models (#241 - Thanks @packyg!).Generated README instructions (#247 - Thanks @theFong!)
In template macros: added declare_type param to transform and initial_value param to construct to improve flexibility (#241 - Thanks @packyg!).
declare_type param to transform and initial_value param to construct to improve flexibility (#241 - Thanks @packyg!).Union in generated models (#241 - Thanks @packyg!).Fixed issue with non-required fields in a model not being marked as such
Fixed issue with non-required fields in a model not being marked as such
Any request/response field that is not required and wasn't specified is now set to UNSET instead of None.
required and wasn't specified is now set to UNSET instead of None.UNSET will not be sent along in API callstype=object will now be converted into classes, just like if they were created as ref components.
The previous behavior was a combination of skipping and using generic Dicts for these schemas.bytes when content-type was application/octet-stream will now return a File object if the type of the data is "binary", just like if you were submitting that type instead of receiving it.None.--custom-template-path option for providing custom jinja2 templates (#231 - Thanks @erichulburd!).Prefix generated identifiers to allow leading digits in field names (#206 - @kalzoo).
__init__.py imports during generation. (#223 - Thanks @fyhertz!)package_version_override in a config file. (#225 - Thanks @fyhertz!)Use httpx ^0.15.0 in generated clients
This release is the culmination of a ton of feedback around the structure of generated clients. A huge thank you to everyone involved in making these
This release is the culmination of a ton of feedback around the structure of generated clients. A huge thank you to everyone involved in making these improvements. That being said, clients generated with this release are not compatible with clients generated with 0.5.x. Use care when updating existing clients.
async_api will no longer be generated. Each path operation will now
have it's own module under its tag. For example, if there was a generated function api.my_tag.my_function() it is
replaced with api.my_tag.my_function.sync(). The async version can be called with asyncio() instead of sync().
(#167)errors module (and the ApiResponseError therein). Instead of raising an exception on failure,
the sync() and asyncio() functions for a path operation will return None. This means all return types are now
Optional, so mypy will require you to handle potential errors (or explicitly ignore them).models.types generated module up a level, so just types.dataclass now use the attrs package insteadsync_detailed() and asyncio_detailed() function which work like their
non-detailed counterparts, but return a types.Response[T] instead of an Optional[T] (where T is the parsed body type).
types.Response contains status_code, content (bytes of returned content), headers, and parsed (the
parsed return type you would get from the non-detailed function). (#115)Client (e.g. my_client.headers = {"Header": "Value"}) or using
a fluid api (e.g. my_endpoint.sync(my_client.with_cookies({"MyCookie": "cookie"}).with_timeout(10.0))).detailed versions of the endpoint will be generated, where the resulting Response.parsed is always None.
(#141)Negative integers in enums (#185). Thanks @rweinberger!
Changes since previous alpha
All generated classes that were dataclass now use the attrs package instead
Changes since last alpha
dataclass now use the attrs package insteadOnly includes changes since 0.6.0-alpha.1
Only includes changes since 0.6.0-alpha.1
Optional is now properly imported for nullable fields (#177 & #180). Thanks @dtkav!Reorganized api calls in generated clients. async_api will no longer be generated. Each path operation will now have it's own module under its tag. Fo
async_api will no longer be generated. Each path operation will now have it's own module under its tag. For example, if there was a generated function api.my_tag.my_function() it is replaced with api.my_tag.my_function.sync(). The async version can be called with asyncio() instead of sync(). (#167)errors module (and the ApiResponseError therein). Instead of raising an exception on failure, the sync() and asyncio() functions for a path operation will return None. This means all return types are now Optional, so mypy will require you to handle potential errors (or explicitly ignore them).models.types generated module up a level, so just types.Client and AuthenticatedClient are now declared using the attrs package instead of builtin dataclasssync_detailed() and asyncio_detailed() function which work like their non-detailed counterparts, but return a types.Response[T] instead of an Optional[T] (where T is the parsed body type). types.Response contains status_code, content (bytes of returned content), headers, and parsed (the parsed return type you would get from the non-detailed function). (#115)Client (e.g. my_client.headers = {"Header": "Value"}) or using a fluid api (e.g. my_endpoint.sync(my_client.with_cookies({"MyCookie": "cookie"}).with_timeout(10.0))).detailed versions of the endpoint will be generated, where the resulting Response.parsed is always None. (#141)Improved trailing comma handling in endpoint generation (#178 & #179). Thanks @dtkav!
Optional is now properly imported for nullable fields (#177 & #180). Thanks @dtkav!Support for octet-stream content type
All values that become file/directory names are sanitized to address path traversal vulnerabilities (CVE-2020-15141)
RefProperty that doesn't refer to an enum.integer type property, and the function for an endpoint using it would fail to generate and be skipped).Added project_name_override and package_name_override config options to override the name of the generated project/package
project_name_override and package_name_override config options to override the name of the generated project/package (#123)Relative paths are now allowed in securitySchemes/OAuthFlow/tokenUrl (#130).
When encountering a problem, the generator will now differentiate between warnings (things it was able to skip past) and errors (things which halt gen
Support for responses with no content (#63 & #66). Thanks @acgray!
### Additions - Support for Python 3.7
Classes generated to be included within lists will now be named like Item. For example, if a property named "statuses" is an array of enum values, pre
Enum class declared would be called "Statuses". Now it will be called "StatusesItem". If a "title" attribute was used in the OpenAPI document, that should still be respected and used instead of the generated name. You can restore previous names by adding "StatusesItem" to the class_overrides section of a config file.MyEnum, one of them will now be named MyEnum1. Note that the order in which these are processed and therefore named is entirely dependent on the order they are read from the OpenAPI document, so changes to the document could result in swapping the names of conflicting Enums.Dict or List properties will now be properly declared as a field with the default_factory parameter to prevent errors related to mutable defaults.Nothing published for this version
Link to the GitHub repository from PyPI (#26). Thanks @theY4Kman!
Fixed import of errors.py in generated api modules
Update Typer dependency to 0.1.0 and remove click-completion dependency
--version option to print the version of openapi-python-client and exit--config option for passing a config.yml file to override generated class names (#9)Improve handling of optional properties in generated to_dict function for models
to_dict function for modelsFix mypy issue in generated models from_dict with datetime or reference properties
from_dict with datetime or reference propertiesApiResponseError if they receive a response that was not declaredupdate command to update a previously generated client- Initial Release
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →