Skip to main content

PyTokenCalc

PyPI CI Python 3.9+ License: Apache 2.0

LLM token counting and cost estimation across cloud, local, and custom providers.

What it is

PyTokenCalc counts tokens across OpenAI, Anthropic, Google, Cohere, Azure-hosted OpenAI models, HuggingFace/open-source models, Ollama, and custom endpoints, then estimates the dollar cost of a request from a maintained per-model pricing table. It is pure Python — the speed comes from the tiktoken and HuggingFace tokenizers libraries it wraps, not from compiled code in PyTokenCalc itself. It installs and imports as pytokencalc.

Features / Highlights

  • Multi-provider — OpenAI, Anthropic Claude, Google Gemini, Cohere, Azure-hosted OpenAI models, HuggingFace/open-source models, Ollama, and any custom HTTP endpoint you register.
  • Provider-accurate tokenization — tiktoken for OpenAI and Azure-hosted OpenAI models, the HuggingFace transformers tokenizer, and live count-tokens endpoints for Anthropic/Google/Cohere.
  • Pricing freshness — pricing_status() reports the snapshot's age and flags it stale after 90 days; load_pricing_override(path) loads a local JSON pricing file for newer/private models. pytokencalc pricing exposes it.
  • Real cost estimation — estimate_cost() is backed by a per-model USD pricing table (input vs. output rates), not a guess; see pytokencalc/pricing.py for sources and last-updated date.
  • Fast local counting — sub-millisecond for local (tiktoken/HuggingFace) providers on typical hardware.
  • Batch processing — count tokens for many prompts in one call.
  • Custom / BYOM models — register your own provider or fine-tuned model (see CUSTOM_PROVIDERS.md).
  • Streaming/incremental counting — counter.streaming(model) gives a running token count as chunks of a live LLM response arrive, correct across chunk/BPE-merge boundaries (not a naive per-chunk sum).
  • Encoding drift detection — get_tokenizer_info()["drift_warnings"] flags if an installed encoding's tokenization has changed since it was last verified.
  • CLI — pytokencalc and the pycount shortcut, installed automatically.

Who it's for / Use cases

  • Budget tracking — count a prompt and price the input/output before sending a request.
  • Preventing cost overruns — reject requests above a cost threshold.
  • Comparing providers — price the same prompt across models before choosing one.
  • Streaming cost awareness — track tokens as a response streams in.

What it is not

  • MCP transport is optional. pytokencalc.TokenCalculator has real handlers (token counts from the tokenizer registry, costs from the pricing table), and the FastMCP transport ships only with pip install "pytokencalc[mcp]"; without that extra, building a server raises an actionable install error. Budget/usage tools are in-memory and process-scoped.
  • No committed benchmark result. The performance numbers are informal local observations, not a checked-in benchmark; there is no results file backing a specific claim. For OpenAI models PyTokenCalc is tiktoken under the hood, with a roughly 2–5% wrapper overhead, not a speedup.
  • Lint/type coverage is partial. ruff check runs in CI, but black formatting and mypy typing are configured yet not enforced (separate passes).
  • Anthropic/Google/Cohere counting makes a live network call to the provider's API, so those paths need the relevant package installed and an API key set.
  • Provider coverage is a maintained table, not exhaustive. See docs/MODELS.md for exactly which models are covered.

Project status

Beta. Current version 1.4.1 (Development Status :: 5 - Production/Stable in pyproject.toml). The local OpenAI/HuggingFace counting path is well covered by tests; provider-specific paths require their optional dependencies. See ROADMAP_HONEST.md for the full honest status and technical-debt list.

MCP server

The 12 MCP tools are now served over a real FastMCP transport:

pip install "pytokencalc[mcp]"

# stdio (Claude Desktop, Cursor, etc.)
pytokencalc-mcp --transport stdio

# HTTP
pytokencalc-mcp --transport http --host 127.0.0.1 --port 8778
from pytokencalc import TokenCalculator

server = TokenCalculator().create_mcp_server()
server.run(transport="stdio")

The tools are the same real handlers documented in _mcp_tools.py; no external dab binary or separate service is involved. Budget/usage state is process-scoped, as documented.

Installation

pip install pytokencalc
# or with uv
uv pip install pytokencalc

# with local tokenizer support (tiktoken + HuggingFace transformers)
pip install "pytokencalc[tokenizers]"

Requires Python 3.9+.

Quick start

from pytokencalc import count_tokens, estimate_cost

# Count tokens instantly (runs locally via tiktoken — no API key needed)
tokens = count_tokens("Tell me a story about a robot", model="gpt-4o")
print(f"Tokens: {tokens}")

# Estimate cost from the pricing table
cost = estimate_cost("gpt-4o", input_tokens=tokens)
print(f"Cost: ${cost:.6f}")

Usage

Budget tracking (Anthropic/Google/Cohere models require the relevant package and an API key; OpenAI/GPT models work offline out of the box):

from pytokencalc import count_tokens, estimate_cost

prompt = "Hello"
reply_tokens_estimate = 50  # however you estimate expected output length

input_tokens = count_tokens(prompt, model="claude-3-opus")
cost = estimate_cost("claude-3-opus", input_tokens, reply_tokens_estimate)
print(f"Estimated cost: ${cost:.4f}")

Prevent overruns:

tokens = count_tokens(prompt, model="gpt-4")
if estimate_cost("gpt-4", tokens) > 0.10:
    print("Request too expensive, rejected")

Compare providers:

prompt = "Explain quantum computing in one paragraph."
for model in ["gpt-4o", "gpt-4-turbo", "gpt-3.5-turbo"]:
    tokens = count_tokens(prompt, model=model)
    cost = estimate_cost(model, tokens)
    print(f"{model}: {tokens} tokens, ${cost:.6f}")

Streaming/incremental counting — recomputes against the full accumulated text on each chunk, so it stays correct across BPE chunk boundaries:

from pytokencalc import TokenCounterRegistry

registry = TokenCounterRegistry()
stream = registry.get_counter("openai").streaming(model="gpt-4o")

for chunk in live_response_chunks:  # e.g. OpenAI SSE deltas
    delta = stream.add_chunk(chunk or "")
    print(f"+{delta} tokens, {stream.total_tokens} total")

Historical baseline estimates (opt-in, not exact) — if you have saved samples for a provider/model/task, estimate_from_baseline() extrapolates total tokens from the historical output/input ratio. This is a planning estimate, not a tokenizer count, and count_tokens()/estimate_cost() never use it:

from pathlib import Path
from pytokencalc import OKFTokenBaselines, TokenBaseline, estimate_from_baseline

store = OKFTokenBaselines(baseline_dir=Path("token_baselines"))
store.save_baseline(TokenBaseline(
    provider="openai", model="gpt-4o", task_type="chat",
    avg_input_tokens=100, avg_output_tokens=50, samples=200,
    percentile_95_input=250, percentile_95_output=140,
))

estimate = estimate_from_baseline("openai", "gpt-4o", "chat", 1000)
print(estimate.total_tokens)  # 1500 -- baseline estimate, not exact
print(estimate.p95_output_tokens)           # stored historical p95 output
print(estimate.predicted_p95_output_tokens) # p95 scaled to the 1000-token input

BaselineEstimate also exposes p95_output_tokens (the stored historical 95th-percentile output) and predicted_p95_output_tokens (that p95 scaled by input_tokens / avg_input_tokens, matching the mean prediction). Both are planning estimates for tail behavior, not guarantees.

Save baselines from real (prompt, output_tokens) samples with the CLI. Prompts are tokenized with the exact counter for the given model; output tokens should come from your own request logs. Samples are never fabricated or padded.

# JSONL: one object per line
# {"prompt": "Explain BPE", "output_tokens": 120}
pytokencalc baseline from-jsonl samples.jsonl \
    --provider openai --model gpt-4o --task-type chat

# JSON: an array, or {"provider": ..., "model": ..., "task_type": ..., "samples": [...]}
pytokencalc baseline save --samples samples.json \
    --provider openai --model gpt-4o --task-type chat

pytokencalc baseline list --provider openai
pytokencalc baseline compare --provider openai --task-type chat

baseline compare reports averages plus p95_input_tokens, p95_output_tokens, and p95_total_tokens for each model. All commands accept --baseline-dir DIR (default: ./token_baselines).

Returns None when no baseline exists. For exact counts use count_tokens().

CLI:

pytokencalc --help
pycount "Tell me a story about a robot" --model gpt-4o

Documentation

Known issues and deferred work

Blocked / failed:

  • Automated upstream price feed (deliberately out of scope).
  • Complete current-generation model coverage.

Rejected / deferred:

  • Bundling the MCP transport (FastMCP) as a mandatory dependency.

Full shipped/blocked/rejected detail: QUEUE_STATUS.md.

Contributing

Contributions are welcome. See CONTRIBUTING.md and CODE_OF_CONDUCT.md. Report security issues per SECURITY.md.

pip install -e ".[dev,tokenizers]"
pytest tests/ -v --cov=pytokencalc
ruff check .

License

This project is licensed under the Apache License 2.0.

Metadata

Release files for pytokencalc 1.4.2

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

Source distribution (sdist)

Source distribution for pytokencalc 1.4.2
File Size Uploaded Provenance Actions
pytokencalc-1.4.2.tar.gz 101.8 kB Without provenance Details for pytokencalc-1.4.2.tar.gz

Built distribution (wheel)

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

Total release size: 184.2 kB

Release files / pytokencalc-1.4.2.tar.gz

Download URL pytokencalc-1.4.2.tar.gz
Size 101.8 kB
Tags Source
SHA-256 checksum
How to use checksums
81bf5fd143302d3bc4efb15219e948ab758987074df9c037d53501f0c9e01db7
BLAKE2b-256 checksum
How to use checksums
1cc9f3dca13b405ab3acb6b3d6f34e2bfbdce548e0697fd9e03cee0ed145a1c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / pytokencalc-1.4.2-py3-none-any.whl

Download URL pytokencalc-1.4.2-py3-none-any.whl
Size 82.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f9ee2bfe8c80c04ab08634b43d6d24deed6a69deec3b14cc0549ad3fd1e5291e
BLAKE2b-256 checksum
How to use checksums
0d8e2865a96dfbba8169e9b53a8f2944b578117661a120e297ebab52efda0efb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Security for pytokencalc 1.4.2

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