Module breakdown
File -> What it does pyproject.toml --> PyPI-ready packaging with optional extras: pip install sentiz[openai], [anthropic], [langchain], [all] _version.py --> Single version source — reflected in User-Agent headers and every span envelope models.py --> Pydantic v2 data models: Span, Session, InteractionEvent, DecisionEvent, EventEnvelope config.py --> SentizConfig dataclass with env-var fallbacks for every field — zero code changes needed for containerised deploys masking.py --> PiiMasker — built-in patterns for credit cards, SSNs, API keys, phones; field-name redaction; custom regex; deep recursive on dicts/lists costs.py --> 30+ models priced (GPT-4o, Claude Opus 4, Gemini 2.5, Llama, Mistral); register_model_pricing() for custom models context.py --> ContextVar-based session/span propagation — works correctly in both asyncio and threads (threading.local would break asyncio) utils.py --> Stack-walking source location; git SHA from 8 CI env vars with subprocess fallback; safe JSON repr transport/http.py --> httpx-based sync + async HTTP client; custom JSON encoder for datetimes/UUIDs/Pydantic models transport/consumer.py --> Daemon thread (modelled on Langfuse's pattern); size + time dual flush triggers; exponential backoff with backoff; drops on 4xx, retries on 5xx; sentinel-based graceful shutdown transport/queue.py --> QueueManager — Queue(maxsize=) drop-on-full; atexit hook for process-exit drain; flush() / shutdown() client.py --> SentizClient (sync) + AsyncSentizClient (async, wraps sync via asyncio.to_thread); all capture methods; update_batch_settings() at runtime decorators.py --> @session, @trace — both auto-detect sync vs async at decoration time integrations/openai.py --> Patches Completions.create and AsyncCompletions.create; handles streaming wrappers that capture token counts post-stream integrations/anthropic.py --> Patches Messages.create and AsyncMessages.create integrations/langchain/handler.py --> SentizCallbackHandler(BaseCallbackHandler) — captures chain, LLM, tool, and agent-decision events; auto-manages session lifecycle
Three key design decisions:
Daemon thread + ContextVar — the consumer thread won't block process exit, and ContextVar means concurrent async sessions never bleed into each other. Both are patterns copied from production-proven SDKs. Fail-silent everywhere — every external path (enqueue, HTTP, instrumentation patch, before_send hook) is wrapped in try/except. The SDK's contract: it will never raise into the host application. enabled=False is a true no-op — when disabled, no thread is started, no queue is created, all capture calls return immediately. Safe to leave instrumentation in production code and toggle off via SENTIZ_ENABLED=false.
Root level — just pyproject.toml. Everything else lives inside the sentiz/ package. sentiz/ — five layers: init.py + client.py are the public surface. Everything else is an implementation detail. Users only ever touch what's in init.py. config.py / models.py / context.py are the data layer — configuration, Pydantic wire-format models, and ContextVar-based session propagation. masking.py / costs.py / utils.py are standalone utilities — no cross-dependencies, easy to unit test in isolation. transport/ is the reliability layer — queue.py owns the in-memory buffer and atexit hook, consumer.py is the background daemon thread that drains it with retry, http.py is the thin httpx wrapper that does the actual POST. integrations/ is the zero-code-change layer — openai.py and anthropic.py monkey-patch those SDKs on init, langchain/handler.py implements BaseCallbackHandler for chain/LLM/tool/agent events. Dependency direction: integrations → client → transport → http. The masking, costs, context, and utils modules are leaves with no upward dependencies — any layer can use them without creating cycles.integrations/mcp/init.py --> Clean exports: SentizMcpClientMiddleware, instrument_mcp_server, mcp_tool, patch_mcp_client integrations/mcp/client.py --> SentizMcpClientMiddleware wraps mcp.ClientSession — traces every call_tool() as a SpanKind.MCP span + McpCallEvent; captures server name/version from initialize(); patch_mcp_client() for global auto-patch integrations/mcp/server.py --> instrument_mcp_server() patches FastMCP (_tool_manager) and low-level mcp.Server; traces every tool execution as SpanKind.MCP_SERVER span integrations/mcp/decorators.py --> @mcp_tool per-function decorator; auto-detects sync vs async; captures args (PII-masked), result, and errors
v0.2.0 additions:
- MCP instrumentation: SpanKind.MCP + SpanKind.MCP_SERVER added to models; McpTransport enum (stdio/sse/http); McpCallEvent dedicated wire type
- client.capture_mcp_call() — explicit API consistent with capture_tool_call / capture_llm_call
- sentiz.capture_mcp_call() — global proxy
- Install with: pip install "sentiz[mcp]"
To publish to Artifactory:
One-time setup
cp .pypirc.template ~/.pypirc
Edit ~/.pypirc with your Artifactory URL and credentials
Build and publish
make publish-artifactory
Or in CI/CD (no ~/.pypirc needed)
TWINE_REPOSITORY_URL=https://company.jfrog.io/artifactory/api/pypi/sentiz/ TWINE_USERNAME=ci-user TWINE_PASSWORD=api-key make publish-ci
Filling Template Files:
A few notes on filling these in: .pypirc.template — copy to ~/.pypirc (never commit the filled-in version to git). Replace:
YOUR-COMPANY — your JFrog subdomain (e.g. acme) YOUR-PYPI-REPO — the name of your PyPI virtual or local repo in Artifactory (e.g. sentiz-pypi) YOUR-ARTIFACTORY-USERNAME — your Artifactory username or service account YOUR-ARTIFACTORY-API-KEY-OR-TOKEN — your Artifactory API key or identity token (found under your Artifactory profile → API Key)
pip.conf.template — copy to ~/.config/pip/pip.conf on Linux/Mac, or %APPDATA%\pip\pip.ini on Windows. The extra-index-url = https://pypi.org/simple/ line is important — it means pip falls back to public PyPI for packages not in your Artifactory repo (like httpx, pydantic, etc.). Without it, installing sentiz[openai] would fail to resolve openai from Artifactory unless you also mirror it there.
Metadata
Release files for sentiz-python-sdk 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sentiz_python_sdk-0.1.0.tar.gz | 49.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sentiz_python_sdk-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 98.8 kB
Release files / sentiz_python_sdk-0.1.0.tar.gz
| Download URL | sentiz_python_sdk-0.1.0.tar.gz |
|---|---|
| Size | 49.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7e338ae949966d53c4518febd2e8543be0f571fbc1f50d815526c431ebfabc41
|
|
BLAKE2b-256 checksum How to use checksums |
21820e055f4bfd456fb10960766221ef0f19f628a63b2efa74e3b96942b9dd19
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.0
|
Release files / sentiz_python_sdk-0.1.0-py3-none-any.whl
| Download URL | sentiz_python_sdk-0.1.0-py3-none-any.whl |
|---|---|
| Size | 49.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5ab1dde572903b0db08f218e6eae424db8a2c96985bc1f0b1c0d63b1d87bfc21
|
|
BLAKE2b-256 checksum How to use checksums |
865bb85571940f7b044011c95a90a205955f3cc26ec9667dabd4ec6fa6711c93
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.0
|
Security for sentiz-python-sdk 0.1.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.