Package: bravado-types
bravado-typesTool to generate MyPy type stubs for Bravado-generated classes to support
static type checking.MotivationBravadois 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.Installationpip install bravado-typesTo install the latest master version directly from GitHub:pip install -U git+https://github.com/nickgaya/bravado-types.gitUsageCode generationTo start using bravado-types, invoke the CLI against your Swagger schema of
choice:bravado-types --url 'https://petstore.swagger.io/v2/swagger.json' \
    --name PetStore --path petstore.pyThis command will download the PetStore example schema and generate a Python 3
module,petstore.py, along with a MyPy stub filepetstore.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 Config, generate_module

client = SwaggerClient.from_url(
    "https://petstore.swagger.io/v2/swagger.json")
config = Config(name='PetStore', path='petstore.py')
generate_module(client, config)Bravado-types supports several optional parameters to customize code
generation. See thebravado_types.config.Configdocstring or the CLI help
output (bravado-types --help) for details.Using the generated moduleTo create a type-aware client, import the relevant name from the generated
module and use itsfrom_url()orfrom_spec()method to create an instance.from petstore import PetStoreSwaggerClient

client = PetStoreSwaggerClient.from_url(
    "https://petstore.swagger.io/v2/swagger.json")
reveal_type(client)  # petstore.PetStoreSwaggerClientYou 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.PetModel]

frank = Pet(name='Frank', photoUrls=[])
reveal_type(frank)  # petstore.PetModel

pet123 = client.pet.getPetById(id=123).response().result
reveal_type(pet123)  # petstore.PetModelThe generated module also provides importable model, resource, and operation
types for use in type annotations.from petstore import PetModel

def get_name(pet: PetModel) -> str:
    reveal_type(pet)  # petstore.PetModel
    return pet.nameGenerated 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 PetModel

# Use placeholder for type annotations and casts
pet: PetModel = ...
pet2 = typing.cast(PetModel, ...)

# 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)Usage notesOperation response typesOperations 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 theresponse_typesconfiguration 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.'all': 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.Array typesBravado accepts either lists or tuples when marshaling values withtype: arrayin the Swagger schema, and creates lists when unmarshaling. There
are a few ways we could represent this in the type annotations:The most precise description would beUnion[List[T], Tuple[T, ...]]but
this is rather verbose and awkward.A less precise but more concise alternative is to useSequence[T]. This has
the downside that MyPy considersstra subtype ofSequence[str], which can
lead to buggy code that passes type-checking but fails schema validation at
runtime.A third alternative is to use onlyList[T]and forbid the use of tuples.
This is overly restrictive, but leads to simpler annotated types.By default, we useList[T]to represent array types, but this behavior can be
overridden via thearray_typesconfiguration parameter.User-defined formatsIf using Bravado'suser-defined
formatsfeature,
use thecustom_formatsconfiguration parameter to specify the python type for
each user-defined format value in the schema, as well as any extra package
imports required to resolve the type annotation.For example, if you define abravado_core.formatter.SwaggerFormatwhich
converts values withtype: stringandformat: ipv4toipaddress.IPv4Addressobjects, you should supply the following CLI flags tobravado-typesto ensure the correct type annotations:--custom-format string:ipv4:ipaddress.IPv4Address
--custom-format-package ipaddressBravado-types will emit warnings for unknown formats encountered while
processing the schema.Model inheritanceSwagger allows composing model definitions with theallOfschema 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 themodel_inheritanceconfiguration parameter toTrue.Additional model propertiesBravado-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: APExample
type: object
additionalProperties:
  type: int...you can add a property called "something" to a model instance like this:model: APExampleModel
model['something'] = 123MyPy will not type-check additional properties.File parameters and responsesBravado's handling of parameters and responses withtype: fileis
complicated.  This tool simply annotates such values with theAnytype.DevelopmentThis 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.