Library for generating type stubs for Swagger clients generated by Bravado
Project description
bravado-types
Tool to generate MyPy type stubs for Bravado-generated classes to support static type checking.
Motivation
Bravado is a Python client library for interacting with APIs defined by Swagger 2.0 schemas. Bravado parses a given API schema at runtime and dynamically generates classes to represent the data types defined by the schema. This is a nice Pythonic approach, but it means that static type-checking tools like MyPy have limited ability to type-check code that uses Bravado since the attributes and method signatures of objects generated by Bravado are not known until runtime.
Bravado-types addresses this problem by pre-generating type information about the generated data for a given schema at build time. Using the generated type stubs, MyPy can statically detect errors such as calling a nonexistent operation method on a resource, failing to specify a required operation parameter, or assigning a wrongly-typed value to a model attribute. This allows for a much higher level of confidence in the correctness of code that uses Bravado clients than would otherwise be possible.
The validity of this approach relies on the assumption that the same version of the schema is used during code generation as at runtime. Without this assumption it is nearly impossible to make any useful assertions about the runtime behavior of generated clients.
Installation
pip install bravado-types
To install the latest master version directly from GitHub:
pip install https://github.com/nickgaya/bravado-types/tarball/master
Usage
Code generation
To start using bravado-types, invoke the CLI against your Swagger schema of choice:
python3 -m bravado_types \
--url 'https://petstore.swagger.io/v2/swagger.json' \
--name PetStore --path petstore.py
This command will download the PetStore example schema and generate a Python 3 module, petstore.py, along with a MyPy stub file petstore.pyi, for that schema. The generated module and stub file can then be used in your package. The generated code only depends on bravado, not on bravado-types, so you do not need to include the latter as a runtime package dependency.
Code generation can also be done programmatically.
from bravado import SwaggerClient
from bravado_types import RenderConfig, generate_module
client = SwaggerClient.from_url(
"https://petstore.swagger.io/v2/swagger.json")
config = RenderConfig(name='PetStore', path='petstore.py')
generate_module(client, config)
Bravado-types supports several optional parameters to customize code
generation. See the bravado_types.render.RenderConfig
docstring or the CLI
help output (python -m bravado_types --help
) for details.
Using the generated module
To create a type-aware client, import the relevant name from the generated
module and use its from_url()
or from_spec()
method to create an instance.
from petstore import PetStoreClient
client = PetStoreClient.from_url(
"https://petstore.swagger.io/v2/swagger.json")
reveal_type(client) # petstore.PetStoreClient
You can use the client like a regular Bravado client to instantiate model objects and make API calls with them.
Pet = client.get_model('Pet')
reveal_type(Pet) # Type[petstore.Pet]
frank = Pet(name='Frank', photoUrls=[])
reveal_type(frank) # petstore.Pet
pet123 = client.pet.getPetById(id=123).response().result
reveal_type(pet123) # petstore.Pet
The generated module also provides importable types for use in type annotations.
from petstore import Pet as TPet
def get_name(pet: TPet) -> str:
reveal_type(pet) # petstore.Pet
return pet.name
Generated model, resource, and operation types are only used for static type checking and must not be used for runtime interactions.
# Placeholder for static type-checking
from petstore import Pet as TPet
# Use placeholder for type annotations and casts
pet: TPet = ...
typing.cast(TPet, ...)
# Runtime model class
Pet = client.get_model('Pet')
# Use runtime class for model instantiation and runtime type checks
pet = Pet(name='Boots', photoUrls=[])
assert isinstance(pet, Pet)
Caveats
Operation response types
Operations often have multiple different response schemas for different status
codes, which presents an obstacle to static type analysis. Bravado-types
offers three different options for response type annotations, specified by the
response_types
configuration parameter.
-
'success'
: The response type will be declared as the union of all response types with 2xx status. This is unsound, but may be useful if you are primarily concerned with responses when the request was successful. -
'union'
: The response type will be declared as the union of all response types defined in the schema. This is probably the most correct but is cumbersome, as the developer must perform manual type checks or casts to obtain a useable type. -
'any'
: The response type will be declared asAny
. This gives maximum flexibility but requires the developer to manually add type hints if they want any type checking on the result of an operation.
By default, bravado-types uses the 'success'
option as it is felt to be the
most pragmatic option, although the least sound.
Custom formats
If bravado-types encounters a primitive type spec with an unrecognized 'format' property, it emits a warning and assigning the variable a type based on the 'type' property alone.
Future versions of this tool may add support for custom user-defined formats.
Model inheritance
Swagger allows composing model definitions with the allOf
schema property.
This can be interpreted as a subclass relationship between models. Bravado
implements this to some extent in its model metaclass,
bravado_core.model.ModelMeta
.
By default, bravado-types does not mirror this implied type hierarchy in its
generated types. To enable this functionality, set the model_inheritance
configuration parameter to True
.
Additional model properties
Bravado-types does not currently support accessing or setting additional properties as attributes of model instances. If you need to set or access additional properties, you can use dict-like syntax instead.
For example, given this model schema...
x-model: APModel
type: object
additionalProperties:
type: int
...you can add a property called "something" like this:
model = APModel()
model['something'] = 123
MyPy will not type-check additional properties.
File parameters and responses
Bravado's handling of parameters and responses with type: file
is
complicated. This tool simply annotates such values with the Any
type.
Development
This project uses Tox to manage virtual environments for unit tests and other self-checks. Unit tests are written with the Pytest framework.
Note: This project is not affiliated with Yelp or the Bravado project.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file bravado-types-0.1.0.tar.gz
.
File metadata
- Download URL: bravado-types-0.1.0.tar.gz
- Upload date:
- Size: 25.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/2.0.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.4.0 requests-toolbelt/0.9.1 tqdm/4.37.0 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7404bbbd252568c5866936af83c4164fe064befd35dbc52ce0725a5e10d6dbfc |
|
MD5 | f90a10269afaabc70466a76c6bde2832 |
|
BLAKE2b-256 | fcfd870c6026b6c0bf5c33f1f07d29b214ffc7e54153585cf2a23ad8ae4a8edc |
File details
Details for the file bravado_types-0.1.0-py3-none-any.whl
.
File metadata
- Download URL: bravado_types-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/2.0.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.4.0 requests-toolbelt/0.9.1 tqdm/4.37.0 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bc24caa1d4f9a8b52446d6ba7c19d791b1a42468024f1f9992cbaaba3b9598f9 |
|
MD5 | 5c4a165c8021217933e19eb99614c844 |
|
BLAKE2b-256 | b10b22d3eda1bfff49a0b8489a0e43e49c3be23a2fbf72802fc6759369c9e35a |