Skip to main content

fastspec

fastspec builds async Python clients from API schemas. It supports OpenAPI, Google Discovery, and GraphQL, with operations accessed through attribute chaining. Schemas supply operation signatures and parameter documentation; the clients handle requests, streaming responses, and file uploads.

Client packages can ship compact, pre-parsed schemas instead of the original specification. This supports broad API coverage without maintaining a handwritten method for each endpoint. ghapi uses this approach for GitHub’s REST and GraphQL APIs.

Install

pip install fastspec

Quick Start

Load a specification, construct a client with authentication headers, and call an operation. The examples use the specifications in this repository’s specs/ directory.

Loading Specs

fastspec supports both OpenAPI (JSON/YAML) and Google Discovery specs:

from fastcore.utils import *
from fastspec.oapi import *
from fastspec.spec import *
import json, yaml
specs_path = Path('../specs/')

# OpenAPI specs (Anthropic, OpenAI, GitHub, Stripe)
ant_spec  = SpecParser.from_openapi(dict2obj(yaml.safe_load((specs_path/'anthropic.yml').read_text())))
oai_spec  = SpecParser.from_openapi(dict2obj(yaml.safe_load((specs_path/'openai.with-code-samples.yml').read_text())))
gh_spec   = SpecParser.from_openapi(dict2obj(json.loads((specs_path/'github.json').read_text())))

# Google Discovery spec (Gemini)
gem_spec  = SpecParser.from_discovery(dict2obj(json.loads((specs_path/'gemini.json').read_text())))

ant_spec, oai_spec, gh_spec, gem_spec
(SpecParser(base_url='https://api.anthropic.com', ops=47),
 SpecParser(base_url='https://api.openai.com/v1', ops=241),
 SpecParser(base_url='https://api.github.com', ops=1112),
 SpecParser(base_url='https://generativelanguage.googleapis.com/', ops=81))

Creating Clients

Pass the parsed specification and authentication headers to OpenAPIClient. The examples read ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, and GITHUB_TOKEN from the environment. Set the variables for the providers you use:

ant_cli = OpenAPIClient(ant_spec, headers={"x-api-key": os.environ["ANTHROPIC_API_KEY"], "anthropic-version": "2023-06-01"})
oai_cli = OpenAPIClient(oai_spec, headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"})
gh_cli  = OpenAPIClient(gh_spec,  headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}"})

Exploring Operations

Each client organizes operations into groups. Display a group to browse its operations:

ant_cli.messages

Read the actual operation with doc(ant_cli.models.models_get) or its bare display for parameter descriptions, bound defaults, request controls, and async usage. Inspecting the operation’s class cannot show its generated signature. xdir(group, pattern) filters large groups by name. Documentation and discovery send no requests:

ant_cli.models.models_get

Get a Model

Parameters:

  • model_id (str, required): Model identifier or alias.

Anthropic

A simple message request:

resp = await ant_cli.messages.messages_post(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "Translate hello into French. Return only the translation."}],
    max_tokens=64,)
resp['content'][0]['text']
'Bonjour'

Pass stream=True and iterate over the response events:

resp = await ant_cli.messages.messages_post(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "Translate hello into French, Spanish, and Japanese. Return only the translations."}],
    max_tokens=128, stream=True)
async for ev in resp: 
    if ct:= nested_idx(ev,'delta','text'): print(ct, end='')
Bonjour
Hola
こんにちは

OpenAI

Chat Completion

resp = await oai_cli.chat.create_chat_completion(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Translate hello into French. Return only the translation."}],
    max_tokens=64)
resp['choices'][0]['message']['content']
'Bonjour'

Text-to-Speech (file output)

resp = await oai_cli.audio.create_speech(model="tts-1", input="Hello from fastspec!", voice="alloy")
Path("hello.mp3").write_bytes(resp)
print(f"Saved {len(resp)} bytes to hello.mp3")
Saved 26400 bytes to hello.mp3

Transcription (file upload + streaming)

resp = await oai_cli.audio.create_transcription(
    file=open("hello.mp3", "rb"), model="gpt-4o-transcribe", stream=True)
async for ev in resp: print(ev.get('delta', ''), end='')
Hello from Fastbec.

Gemini

Google Discovery specs use nested resource groups with attribute chaining:

gem_cli = OpenAPIClient(gem_spec, headers={"x-goog-api-key": os.environ["GEMINI_API_KEY"]})
str(gem_cli.models)[:500]
'- models.generate_content(model, contents, access_token, alt, callback, fields, key, oauth_token, pretty_print, quota_user, upload_protocol, upload_type, xgafv, system_instruction, tools, tool_config, safety_settings, generation_config, cached_content, service_tier, store): *Generates a model response given an input `GenerateContentRequest`. Refer to the [text generation guide](https://ai.google.dev/gemini-api/docs/text-generation) for detailed usage information. Input capabilities differ betwee'
resp = await gem_cli.models.generate_content(
    model="models/gemini-3-flash-preview",
    contents=[{"parts": [{"text": "Translate hello into French. Return only the translation."}]}])
resp['candidates'][0]['content']['parts'][0]['text']
'Bonjour'

Nested resource groups are accessed with attribute chaining:

gem_cli.tuned_models.permissions.create

Create a permission to a specific resource.

Parameters:

  • parent (str, required): Required. The parent resource of the Permission. Formats: tunedModels/{tuned_model} corpora/{corpus}
  • role (str, required): Required. The role granted by this permission.
  • access_token (str, optional): OAuth access token.
  • alt (str, optional): Data format for response.
  • callback (str, optional): JSONP
  • fields (str, optional): Selector specifying which fields to include in a partial response.
  • key (str, optional): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.
  • oauth_token (str, optional): OAuth 2.0 token for the current user.
  • pretty_print (bool, optional): Returns response with indentations and line breaks.
  • quota_user (str, optional): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters.
  • upload_protocol (str, optional): Upload protocol for media (e.g. “raw”, “multipart”).
  • upload_type (str, optional): Legacy upload protocol for media (e.g. “media”, “multipart”).
  • xgafv (str, optional): V1 error format.
  • name (str, optional): Output only. Identifier. The permission name. A unique name will be generated on create. Examples: tunedModels/{tuned_model}/permissions/{permission} corpora/{corpus}/permissions/{permission} Output only.
  • grantee_type (str, optional): Optional. Immutable. The type of the grantee.
  • email_address (str, optional): Optional. Immutable. The email address of the user of group which this permission refers. Field is not set when permission’s grantee type is EVERYONE.

GitHub

Route parameters (like {owner} and {repo}) are passed as regular function arguments:

resp = await gh_cli.repos.get(owner="AnswerDotAI", repo="fastcore")
resp['full_name'], resp['description'], resp['stargazers_count']
('AnswerDotAI/fastcore', 'Python supercharged for the fastai library', 1100)
gh_cli.repos.get

Get a repository

Docs: https://docs.github.com/rest/repos/repos#get-a-repository

Parameters:

  • owner (str, required): The account owner of the repository. The name is not case sensitive.
  • repo (str, required): The name of the repository without the .git extension. The name is not case sensitive.

GraphQL

GqlSpec stores a parsed introspection response. GqlClient uses it to check queries against the schema. Supply arguments as keyword arguments and select fields through attribute chaining. batch combines queries into one request.

This example reads the head commit of three repositories in one request. See the GraphQL documentation for discovery, raw queries, and error handling:

from fastspec.gql import GqlSpec, GqlClient, INTROSPECT
from fasttransport.core import AsyncTransport
gh_hdrs = {"Authorization": f"bearer {os.environ['GITHUB_TOKEN']}"}
raw = await AsyncTransport(base_headers=gh_hdrs).request('POST', 'https://api.github.com/graphql', json=dict(query=INTROSPECT))
gql = GqlClient(GqlSpec.from_introspection(raw), 'https://api.github.com/graphql', headers=gh_hdrs)
await gql.batch(*[gql.repository(owner='AnswerDotAI', name=n).defaultBranchRef.target.oid
    for n in ('fastcore', 'fasthtml', 'ghapi')])
['25c4f3228ccac3c5a63da71b5eaa4be3c428f602',
 'e5d967ae627c63035e296e6f319f220e278327e7',
 '4ca8469d7c2ccc42cb71e30a576c719f306b5cf7']

AI Tool Integration (python)

In solveit’s python sandbox, allow() registers fastspec operations that the assistant can call, including their network access. Choose the required scope:

Allow one operation:

allow(oai_cli.images.create_image)

Allow one group:

allow(oai_cli.chat)

Allow one client:

allow(oai_cli)

Allow OpFunc calls on all clients:

allow({OpFunc: ['__call__']})

Compact schemas and transports

Use SpecParser.to_dict, save, and from_dict to serialize and load compact specifications. A package can include the parsed form and avoid loading the multi-megabyte original at runtime. GqlSpec provides compact storage for GraphQL schemas.

Requests use fasttransport. Provider failures pass through the error layer.

Metadata

Release files for fastspec 0.2.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastspec 0.2.6
File Size Uploaded Provenance Actions
fastspec-0.2.6.tar.gz 30.4 kB Without provenance Details for fastspec-0.2.6.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fastspec 0.2.6
File Interpreter ABI Platform Actions
fastspec-0.2.6-py3-none-any.whl Python 3 none any Details for fastspec-0.2.6-py3-none-any.whl

Total release size: 58.3 kB

Release files / fastspec-0.2.6.tar.gz

Download URL fastspec-0.2.6.tar.gz
Size 30.4 kB
Tags Source
SHA-256 checksum
How to use checksums
675025b7e0596af986ac1eec961790b6a129f3b80ac74dc7eca8b2d80d34b3c5
BLAKE2b-256 checksum
How to use checksums
94475bfdc91796ab98013cf74a9a7bd945598c5ed43ef5756970b8fda785de80
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / fastspec-0.2.6-py3-none-any.whl

Download URL fastspec-0.2.6-py3-none-any.whl
Size 27.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cdbcfe3ebe129cbccde8182a9456332b5cf5c5db75ea14321f464f0a1c31f20e
BLAKE2b-256 checksum
How to use checksums
2edfc37a03ce9ef09953767c8f790e082c30e165a822af9c4df2de66761216e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Security for fastspec 0.2.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page