Skip to main content

pnotp

Official Python client for the P¬P platform. One account API key drives the whole platform: create projects and models, train (with pause / resume / cancel), deploy models, and call live inference endpoints.

Install

pip install pnotp

Authenticate

Mint an account API key in Studio → Settings → API keys (it starts with pnotp_sk_ and is shown once). Then:

export PNOTP_API_KEY="pnotp_sk_..."
import pnotp
px = pnotp.Client()                       # reads PNOTP_API_KEY
# or: px = pnotp.Client(api_key="pnotp_sk_...")

Point it at a local dev server with base_url= or PNOTP_BASE_URL (e.g. http://localhost:8000/v1). The default is the hosted backend.

Train a model end to end

import pnotp
px = pnotp.Client()

project = px.projects.create(name="Chest X-ray", task_type="binary_image_classification")

model = px.models.create(
    project["id"],
    name="cnn-v1",
    architecture=pnotp.architectures.image_classifier(num_classes=2),
)

# dataset = a .zip of class-named folders (image) or a .csv (tabular)
job = px.train(model.id, dataset="train.zip", epochs=5)
job.wait(on_progress=lambda j: print(j.status))

# pause / resume / cancel any time
# job.pause(); job.resume(); job.cancel()

Deploy + call inference

dep = px.deployments.upload(project["id"], name="prod", checkpoint="model.pt")
deployment_id = dep["deployment"]["id"]

result = px.predict(deployment_id, "xray.jpg")
print(result)                              # {"predictions": [...], "class_names": [...]}

px.deployments.stats(deployment_id, window="24h")

External consumers can call your endpoint with a per-deployment key (pnp_...):

key = px.deployments.create_key(deployment_id)["api_key"]
px.deployments.predict(deployment_id, "xray.jpg", api_key=key)

Data-compliant inference (zero retention)

Pass compliant=True at deploy time to make an endpoint data-compliant. The platform then guarantees, on every call to that endpoint:

  • Zero retention — the input you send is never persisted; the temp file is deleted before the response returns.
  • Redacted monitoring — error text is kept out of the stats/monitoring log (only status code and latency are recorded).
  • An audit receipt — each response carries a compliance block ({"compliant": true, "retention": "none", "deployment_id", "timestamp"}).
dep = px.deployments.upload(project["id"], name="prod", checkpoint="model.pt", compliant=True)
# or a catalog model:
dep = px.deployments.deploy_open_source(project["id"], "mobilenet_v3_small", compliant=True)
# or flip it on an existing endpoint:
px.deployments.set_compliant(deployment_id, True)

result = px.predict(deployment_id, "xray.jpg")
print(result["compliance"])   # {'compliant': True, 'retention': 'none', ...}

It's a platform capability: compliant=True raises APIError (409) when the platform hasn't enabled it. Probe first with px.deployments.compliance_available(). compliant=False (the default) is unchanged behaviour.

Agents inherit it for free. pnotp.model runs inference through the same path, so an agent that calls a compliant endpoint is itself data-compliant — compliance is a property of the deployment, not the agent or the call site. To ship a data-compliant agent into a customer's process, deploy its models with compliant=True; nothing else changes. See docs/data-compliance.md.

Data-compliant LLM + agents

PnotP also hosts a zero-retention LLM brain. The inference layer stores nothing — neither the prompt nor the completion — and each call returns a receipt you can keep as the audit artifact:

out = px.chat("In one sentence, what is a master's degree?")
print(out["completion"])
print(out["receipt"])   # {"mode": "compliant", "zero_retention": True,
                        #  "plaintext_stored": "none", "cost": {...}}

Use the same brain for an agent with model="pnotp-compliant" (build + run in four lines):

a   = px.agents.create("Advisor")
px.agents.publish(a["id"], model="pnotp-compliant", tools=["programs_db"])
run = px.agents.run(a["id"], "I love AI and maths — which programs fit?", wait=True)
print(run.final_answer())

A compliant agent run keeps no question, no reasoning, and no loop state — only metered metadata + the final answer (resume of a compliant run is rejected). A BYO-key brain still routes tokens to that vendor. Tool-calling works via the SDK (px.chat(..., tools=[...])) or the OpenAI-compatible POST /v1/chat/completions (drop-in for the Vercel AI SDK / LangChain / openai — base URL <api>/v1, model pnotp-compliant). Pricing is $1.11/1M output, $0.11/1M input (≈1.8× under OpenRouter), metered per token — billed against your credits (metering is live; an empty balance returns 402). Live rates (no key): GET /v1/llm/pricing. Full guide: docs/data-compliance.md.

Vision (multimodal). The served brain is a vision model (Qwen3-VL-8B), so an image is understood VISUALLY — it sees the picture, not just text in it. Documents are parsed and audio is speech-to-text. Image bytes go straight to our own GPU and are never stored or logged.

px.chat("What is in this image?", image="photo.jpg")     # real vision
px.chat("Summarize this contract", file="contract.pdf")  # document parse
px.chat("What does the customer want?", audio="voicenote.ogg")  # speech-to-text
# or the standard OpenAI image_url content-part form:
px.chat([{"role": "user", "content": [
    {"type": "text", "text": "Describe this"},
    {"type": "image_url", "image_url": {"url": "data:image/png;base64,...."}}]}])

Agents

An agent is a BYO reasoning model (the "brain") driving a tool-calling loop over tools you register, plus platform built-ins. PnotP hosts no LLMs — the brain is your Gemini / DeepSeek key (any OpenAI-style /chat/completions with tool-calling), or a text-gen model you deployed on PnotP.

import pnotp

agent = pnotp.Agent("gemini:gemini-2.5-pro",          # reads GEMINI_API_KEY
                    system="You are a careful research assistant.")

@agent.tool
def search_pubmed(query: str, max_results: int = 5) -> list[dict]:
    "Search PubMed and return the top hits."          # docstring -> tool description
    return my_client.search(query, k=max_results)     # JSON Schema is derived from the signature

run = agent.run("Recent trials on pediatric pneumonia from chest X-rays?")
print(run.output, run.stop_reason)                    # final answer + "stop" | "max_steps"

# stream events for a live UI
for event in agent.stream("..."):
    ...   # TextDelta / ToolCallStarted / ToolCallFinished / StepBoundary / Done

The pnotp.model built-in lets the agent call any model you've deployed (Tier 1; billed per platform inference). The brain can be your own deployment via pnotp.endpoints.deployed("my-llm") or the "pnotp:<deployment_id>" shorthand. Structured output: pass response_format=MyDataclass to parse the final answer.

The loop is bounded and observable: max_steps, per-tool tool_timeout, max_tool_retries (a schema-invalid or timed-out call is re-asked without spending the step budget), and on_tool_error ("return" feeds the error back to the brain — the resilient default — or "raise").

Help & Toby

The SDK documents itself — offline, no API key, no network. It's the fastest way for you (or a coding agent like Claude Code / Codex) to get unstuck:

import pnotp

pnotp.help()                       # overview + the list of topics
pnotp.help("agents")               # a topic page
pnotp.help.search("pause a training job")   # search topics + the live API reference
pnotp.help(pnotp.Agent)            # any symbol's real signature + docstring
pnotp.help.errors                  # the exception catalog

The API reference is generated by introspection, so it always matches your installed version. Every exception also carries a .help pointer.

Toby is the hosted assistant — natural-language answers, authenticated by your account key (needs credits). It falls back to local doc search when there's no key/credits/network, so it never raises:

print(pnotp.help.toby("How do I deploy a model and then call it?"))

chat = pnotp.help.toby.session()   # multi-turn
chat.ask("How do I make an image classifier?")
chat.ask("And how do I pause its training?")

Inside a runtime agent, let the brain self-serve docs when it's unsure:

agent = pnotp.Agent("gemini:gemini-2.5-pro", tools=[pnotp.help.as_tool()])

See AGENTS.md for a coding-agent-oriented cheat sheet.

Surface

Area Calls
Projects projects.list/create/get
Models models.create/list/get/add_version/versions · model.train(...)
Training train(...) → TrainingJob · job.wait/progress/pause/resume/cancel · jobs.list/get
Deployments deployments.upload/list/get/predict/stats/pause/resume/delete · create_key/list_keys/revoke_key
Compliant LLM chat(text_or_messages, ...) → {completion, usage, model, receipt} (zero-retention; pricing MODELED)
Hosted agents agents.create/get/list/publish(model="pnotp-compliant", tools=, ...)/run(..., wait=) → run.final_answer/steps/progress
Credits credits.balance()
API keys api_keys.create/list/revoke
Agents Agent(model, tools=, system=, ...) · agent.run/stream · @agent.tool / @pnotp.tool · pnotp.endpoints.gemini/deepseek/openai_compatible/deployed · pnotp.model
Help help() / help("topic") / help(symbol) · help.search/topics/errors · help.toby("...") / help.toby.session() · help.as_tool()

Errors raise pnotp.APIError subclasses: AuthError (401/403), NotFoundError (404), InsufficientCreditsError (402). Agent-loop failures raise pnotp.AgentError subclasses: MaxStepsExceeded, ToolError, ModelEndpointError.


The legacy pnotp_api package (a standalone PathoVision wrapper) still lives in this repo and is unrelated to the platform client above.

Metadata

Release files for pnotp 0.4.0

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

Source distribution (sdist)

Source distribution for pnotp 0.4.0
File Size Uploaded Provenance Actions
pnotp-0.4.0.tar.gz 107.7 kB Without provenance Details for pnotp-0.4.0.tar.gz

Built distribution (wheel)

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

Total release size: 193.4 kB

Release files / pnotp-0.4.0.tar.gz

Download URL pnotp-0.4.0.tar.gz
Size 107.7 kB
Tags Source
SHA-256 checksum
How to use checksums
ba18c935e5dba0d2fba8a3159f67c6ff8a482f84135fac4748aa01435cb01ea8
BLAKE2b-256 checksum
How to use checksums
d2919110d608a8fea1aca01e99195b08617c349f463bbb1345518715bb089c5b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.14

Release files / pnotp-0.4.0-py3-none-any.whl

Download URL pnotp-0.4.0-py3-none-any.whl
Size 85.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0a137be077b6f717a5a3e17adb7ec2901630f457453ba59968270d0c04e62395
BLAKE2b-256 checksum
How to use checksums
e378addea260b66e76cbd1284c36dea774bb8e025b6064ad3f634f9b5ad03123
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.14

Security for pnotp 0.4.0

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