Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b6d268f
feat: adds the generated GRPC code and a basic wrapper around it
snus-kin Aug 7, 2025
e57605b
build: fix pre-commit config
snus-kin Aug 7, 2025
c1c71ea
feat: use asyncio for classify streaming endpoint
snus-kin Aug 7, 2025
7edf165
test: add tests for grpc wrappers
snus-kin Aug 8, 2025
1db086e
ci: fixup the imports before diff
snus-kin Aug 8, 2025
ee1385b
feat: submodule the athena protobufs and modify the compilation scripts
snus-kin Aug 11, 2025
9136fb2
feat: Add async transformers and batching middleware
snus-kin Aug 13, 2025
b934525
ci: omit generated code from coverage checks
snus-kin Aug 13, 2025
fcfcb2a
fix: spelling issue in name of async_transformer
snus-kin Aug 13, 2025
d8a2a0b
ci: produce test reporting
snus-kin Aug 13, 2025
a696d3d
fixup! feat: Add async transformers and batching middleware
snus-kin Aug 13, 2025
8ca9e35
fixup! ci: produce test reporting
snus-kin Aug 13, 2025
fc39a9d
feat: adds tests, example.py now generates random images, more fixes …
snus-kin Aug 18, 2025
55d73f4
feat: improve documentation and typing of async transformer
snus-kin Aug 19, 2025
7daef2b
feat: fixup some code, add better docstrings, better example
snus-kin Aug 20, 2025
b20c851
feat: adds oauth credential helper, better streaming support
snus-kin Aug 26, 2025
c916c5b
feat: bump to latest protobufs
snus-kin Aug 26, 2025
b3ee1d0
feat: use ImageData input type to attach hashes in prep for known csa…
snus-kin Aug 27, 2025
70fdf2b
feat: faster create_image examples
snus-kin Aug 28, 2025
f29d1ae
feat: faster image resizing
snus-kin Aug 28, 2025
0068cd4
Add documentation with Sphinx (#6)
snus-kin Aug 28, 2025
f50fb95
feat: remove gencode from repo for docs
snus-kin Aug 28, 2025
85986c5
feat: better stream handling, docs
snus-kin Sep 4, 2025
274a5b7
fix: fixup the rgb and compression in client
snus-kin Sep 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .coverage
Binary file not shown.
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "weekly"
16 changes: 14 additions & 2 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Initialize submodules
env:
Expand Down Expand Up @@ -72,7 +72,19 @@ jobs:

- name: Run tests
run: |
uv run pytest
uv run pytest --junitxml=pytest.xml --tb=auto --cov-report=term-missing:skip-covered --cov=src tests/ | tee pytest-coverage.txt

- name: Pytest Coverage Comment
uses: MishaKav/pytest-coverage-comment@v1.1.56
with:
junitxml-path: ./pytest.xml

- name: Upload test results
uses: actions/upload-artifact@v4 # upload test results
if: ${{ !cancelled() }} # run this step even if previous step failed
with:
name: test-results
path: pytest.xml

- name: Build package
run: |
Expand Down
93 changes: 93 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: Build and Deploy Documentation

on:
push:
branches: [main, master]
paths:
- "docs/**"
- "src/**"
- "examples/**"
- "README.md"
- "pyproject.toml"
- ".github/workflows/docs.yml"
pull_request:
branches: [main, master]
paths:
- "docs/**"
- "src/**"
- "examples/**"
- "README.md"
- "pyproject.toml"
- ".github/workflows/docs.yml"
workflow_dispatch:
inputs:
reason:
description: "Reason for manual documentation build"
required: false
default: "Manual trigger"

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: "pages"
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true

- name: Set up Python
run: uv python install

- name: Install dependencies
run: uv sync --locked --group docs

- name: Build documentation
run: |
cd docs
uv run make clean
uv run make html

- name: Setup Pages
uses: actions/configure-pages@v4
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
with:
path: docs/_build/html

- name: Upload build artifacts for debugging
uses: actions/upload-artifact@v4
if: failure()
with:
name: docs-build-artifacts
path: |
docs/_build/
docs/*.log

deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
22 changes: 22 additions & 0 deletions .github/workflows/test_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: "Test Report"
on:
workflow_run:
workflows: ["Build and Test"]
types:
- completed

permissions:
contents: read
actions: read
checks: write

jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: dorny/test-reporter@v2
with:
artifact: test-results
name: Tests
path: "*.xml"
reporter: java-junit
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ wheels/

# Virtual environments
.venv
.env

docs/_build/
49 changes: 49 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# AGENTS.md

## Setup commands
- Install deps: `uv sync --dev`
- Build package: `uv build`
- Run tests: `pytest`
- Type check code: `pyright`
- Format code: `ruff format`
- Lint code: `ruff check`
- Install git hooks: `pre-commit install`
- Compile protobufs: `bash scripts/compile_proto.sh` (run from root)

## Code style
- Use Python type hints throughout
- Follow Black formatting (via ruff)
- Async/await for I/O operations
- Document public APIs with docstrings
- Use functional patterns where possible
- Implement proper error handling

## Testing instructions
- Tests live in the `tests/` directory
- Run `pytest` for full test suite
- Run `pytest path/to/test.py` for specific tests
- Run `pytest -k "test_name"` to run by pattern
- Run `pytest --cov=src/athena_client` for coverage
- Add tests for all new code
- Mock external services in tests
- Test both success and error cases

## PR instructions
- Title format: [component] Description
- Run `ruff check`, `pyright`, and `pytest` before committing
- Keep PRs focused on a single change
- Add tests for new functionality
- Update documentation for API changes
- Add proper type hints

## Dev tips
- Use `uv` package manager instead of pip
- Don't use `uv pip` commands, just the base `uv` commands
- Run formatters before committing
- Check generated code in `src/athena_client/generated/`
- Add error handling at each pipeline stage
- Use correlation IDs for request tracing

## Documentation
- Docs are in `docs/`
- Build docs by `cd docs && make clean && make html`
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,79 @@
This is a Python library for interacting with the Athena API (Resolver Unknown
CSAM Detection).

## Authentication

The Athena client supports two authentication methods:

### Static Token Authentication
```python
from athena_client.client.channel import create_channel

# Use a pre-existing authentication token
channel = create_channel(host="your-host", auth_token="your-token")
```

### OAuth Credential Helper (Recommended)
The credential helper automatically handles OAuth token acquisition and refresh:

```python
import asyncio
from athena_client.client.channel import CredentialHelper, create_channel_with_credentials

async def main():
# Create credential helper with OAuth settings
credential_helper = CredentialHelper(
client_id="your-oauth-client-id",
client_secret="your-oauth-client-secret",
auth_url="https://crispthinking.auth0.com/oauth/token", # Optional, this is default
audience="crisp-athena-dev" # Optional, this is default
)

# Create channel with automatic OAuth handling
channel = await create_channel_with_credentials(
host="your-host",
credential_helper=credential_helper
)

asyncio.run(main())
```

#### Environment Variables
For the OAuth example to work, set these environment variables:
```bash
export OAUTH_CLIENT_ID="your-client-id"
export OAUTH_CLIENT_SECRET="your-client-secret"
export ATHENA_HOST="your-athena-host"
```

#### OAuth Features
- **Automatic token refresh**: Tokens are automatically refreshed when they expire
- **Thread-safe**: Multiple concurrent requests will safely share cached tokens
- **Error handling**: Comprehensive error handling for OAuth failures
- **Configurable**: Custom OAuth endpoints and audiences supported

See `examples/oauth_example.py` for a complete working example.

## Examples

- `examples/example.py` - Basic classification example with static token
- `examples/oauth_example.py` - OAuth authentication with credential helper
- `examples/create_image.py` - Image generation utilities

## TODO

### Async pipelines
Make pipeline style invocation of the async interators such that we can

async read file -> async transform -> async classify -> async results

### More async pipeline transformers
Add additional pipeline transformers for:
- Image format conversion
- Metadata extraction
- Error recovery and retry



## Development
This package uses [uv](https://docs.astral.sh/uv/) to manage its packages.
Expand Down
2 changes: 1 addition & 1 deletion athena-protobufs
23 changes: 23 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Minimal makefile for Sphinx documentation

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile clean

# Clean the build directory
clean:
rm -rf $(BUILDDIR)/*

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
1 change: 1 addition & 0 deletions docs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Sphinx documentation configuration package for Athena Client."""
Loading