Metadata-Version: 2.4
Name: fastspec
Version: 0.1.1
Summary: Dynamic OpenAPI and discovery spec client for Python — turn any API spec into a fully-typed async client with attribute chaining, streaming, and file uploads
Author-email: Kerem Turgutlu <keremturgutlu@gmail.com>
License-Expression: Apache-2.0
Project-URL: Repository, https://github.com/AnswerDotAI/fastspec
Project-URL: Documentation, https://AnswerDotAI.github.io/fastspec/
Keywords: nbdev
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastcore>=1.14.6
Requires-Dist: httpx
Provides-Extra: dev
Requires-Dist: safepyrun>=0.2.3; extra == "dev"
Requires-Dist: pyskills>=0.0.17; extra == "dev"
Dynamic: license-file

# fastspec


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Install

``` sh
pip install fastspec
```

## Quick Start

fastspec turns any OpenAPI (or Google Discovery) spec into a fully async Python client. Load a spec, create a client, and call any endpoint with attribute chaining.

### Loading Specs

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

``` python
import yaml
```

``` python
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=79))

### Creating Clients

Pass a parsed spec and any required auth headers to [`OpenAPIClient`](https://AnswerDotAI.github.io/fastspec/oapi.html#openapiclient):

``` python
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

Every client organizes endpoints into groups. Use `doc()` to browse what’s available:

``` python
ant_cli.messages
```

<div class="prose" markdown="1">

- [messages.messages_post](https://docs.claude.com/en/docs/initial-setup)(model, messages, max_tokens, cache_control, container, inference_geo, metadata, output_config, service_tier, stop_sequences, stream, system, temperature, thinking, tool_choice, tools, top_k, top_p): *Create a Message*
- [messages.message_batches_post](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(requests): *Create a Message Batch*
- [messages.message_batches_list](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(before_id, after_id, limit): *List Message Batches*
- [messages.message_batches_retrieve](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(message_batch_id): *Retrieve a Message Batch*
- [messages.message_batches_delete](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(message_batch_id): *Delete a Message Batch*
- [messages.message_batches_cancel](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(message_batch_id): *Cancel a Message Batch*
- [messages.message_batches_results](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(message_batch_id): *Retrieve Message Batch results*
- [messages.messages_count_tokens_post](https://docs.claude.com/en/docs/build-with-claude/token-counting)(messages, model, cache_control, output_config, system, thinking, tool_choice, tools): *Count tokens in a Message*
- [messages.beta_message_batches_post](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(requests): *Create a Message Batch*
- [messages.beta_message_batches_list](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(before_id, after_id, limit): *List Message Batches*
- [messages.beta_message_batches_retrieve](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(message_batch_id): *Retrieve a Message Batch*
- [messages.beta_message_batches_delete](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(message_batch_id): *Delete a Message Batch*
- [messages.beta_message_batches_cancel](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(message_batch_id): *Cancel a Message Batch*
- [messages.beta_message_batches_results](https://docs.claude.com/en/docs/build-with-claude/batch-processing)(message_batch_id): *Retrieve Message Batch results*
- [messages.beta_messages_count_tokens_post](https://docs.claude.com/en/docs/build-with-claude/token-counting)(messages, model, cache_control, context_management, mcp_servers, output_config, output_format, speed, system, thinking, tool_choice, tools): *Count tokens in a Message*

</div>

Drill into any operation to see its full signature and parameter docs:

``` python
ant_cli.models.models_get
```

<div class="prose" markdown="1">

Get a Model

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

</div>

## Anthropic

A simple message request:

``` python
resp = await ant_cli.messages.messages_post(
    model="claude-sonnet-4-20250514",
    messages=[{"role": "user", "content": "What is FastSpec?"}],
    max_tokens=64,)
resp['content'][0]['text']
```

    "FastSpec could refer to a few different things depending on the context. Here are the most likely meanings:\n\n## 1. **Testing Framework**\nFastSpec is a testing framework, particularly associated with Scala development. It's designed to provide:\n- Fast test execution\n- Clear, readable test syntax"

With streaming — just pass `stream=True` and iterate:

``` python
resp = await ant_cli.messages.messages_post(
    model="claude-sonnet-4-20250514",
    messages=[{"role": "user", "content": "Say hello in 3 languages."}],
    max_tokens=128, stream=True)
async for ev in resp: 
    if ct:= nested_idx(ev,'delta','text'): print(ct, end=' ')
```

    Hello! Here are gr eetings in 3 languages:

    1. **English**: Hello!
    2. **Spanish**: ¡Hola!
    3 . **French**: Bonjour! 

## OpenAI

### Chat Completion

``` python
resp = await oai_cli.chat.create_chat_completion(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "What is fastspec?"}],
    max_tokens=64)
resp['choices'][0]['message']['content']
```

    'As of my last update in October 2023, "fastspec" is not widely known or associated with a specific standalone technology, product, or concept in public discourse. However, the term could refer to various topics depending on the context, such as:\n\n1. **Software or Libraries**: It might denote a'

### Text-to-Speech (file output)

``` python
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)

``` python
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:

``` python
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, 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 between models, including tuned models. Refer to the [model guide](https://ai.google.dev/gemini-api/docs/models/gemini) and '

``` python
resp = await gem_cli.models.generate_content(
    model="models/gemini-2.5-flash",
    contents=[{"parts": [{"text": "What is fastspec?"}]}])
resp['candidates'][0]['content']['parts'][0]['text'][:200]
```

    '**FastSpec** is a Ruby Gem designed to significantly speed up your local RSpec test suite execution by intelligently identifying and running only the specs relevant to your recent code changes.\n\n### T'

Nested resource groups are accessed with attribute chaining:

``` python
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.
- 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:

``` python
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', 1101)

``` python
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.

## AI Tool Integration (`python`)

fastspec clients can be made available to AI assistants via [solveit](https://github.com/AnswerDotAI/solveit)’s `python` sandbox using `allow()`. Registering an op lets the sandboxed code call it (including the network access it needs); everything else stays blocked. Four levels of access are supported:

**Single method access** — lock down to specific operations:

``` python
allow(oai_cli.images.create_image)
```

**Single group access** — only specific groups:

``` python
allow(oai_cli.chat)
```

**Single client access** — all groups on one specific client:

``` python
allow(oai_cli)
```

**Full API access** — every operation on every client (any [`OpFunc`](https://AnswerDotAI.github.io/fastspec/oapi.html#opfunc) may run):

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