Metadata-Version: 2.4
Name: veriis
Version: 0.1.1
Summary: Official Python client for the Veris OCR API.
Project-URL: Homepage, https://github.com/MohamedNasirS/veris-ocr-recursai
Project-URL: Documentation, https://github.com/MohamedNasirS/veris-ocr-recursai/tree/main/clients/python
Project-URL: Repository, https://github.com/MohamedNasirS/veris-ocr-recursai.git
Project-URL: Issues, https://github.com/MohamedNasirS/veris-ocr-recursai/issues
Author-email: RecursAI Technologies <founders@recursai.com>
License-Expression: LicenseRef-Proprietary
License-File: LICENSE
Keywords: aadhaar,document,mrz,ocr,passport,recursai,resume,veris
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Python: <3.15,>=3.10
Requires-Dist: httpx<1,>=0.27
Requires-Dist: pydantic<3,>=2.8
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: hatchling<2,>=1.27; extra == 'dev'
Requires-Dist: mypy<2,>=1.13; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest-cov>=6; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Requires-Dist: twine>=6; extra == 'dev'
Description-Content-Type: text/markdown

# veriis

Official Python client for the Veris OCR API by RecursAI Technologies. The
service performs passport MRZ extraction, Aadhaar OCR, general document OCR,
and structured resume parsing; this package provides a small typed client for
calling it.

- Synchronous and asynchronous clients
- Typed Pydantic response models
- File paths, raw bytes, binary file objects, and explicit file descriptors
- Typed errors, request timeouts, and bounded retries
- Python 3.10–3.14

## Install

```bash
pip install veriis
```

## Quickstart

```python
from veriis import VerisOCR

with VerisOCR(
    base_url="https://veris.recursai.in",
    api_key="pk_live_...",
) as client:
    passport = client.passport.extract("passport.jpg")
    print(passport.mrz.passport_number, passport.mrz.expiry_date)

    document = client.document.extract("invoice.pdf", lang="eng+fra")
    print(document.page_count, document.pages[0].text)

    resume = client.resume.extract("cv.pdf")
    print(resume.name, resume.total_experience_human, resume.skills)

    aadhaar = client.aadhaar.extract("aadhaar.png")
    print(aadhaar.aadhaar.name, aadhaar.aadhaar.mobile_number)

    queued = client.jobs.submit_many(
        ["aadhaar-1.png", "aadhaar-2.png"],
        mode="aadhaar",
        concurrency=2,
    )
```

The same settings can come from the environment:

```bash
export VERIS_OCR_BASE_URL=https://veris.recursai.in
export VERIS_OCR_API_KEY=pk_live_...
```

```python
from veriis import VerisOCR

client = VerisOCR()
```

## Async client

```python
import asyncio

from veriis import AsyncVerisOCR


async def main() -> None:
    async with AsyncVerisOCR(
        base_url="https://veris.recursai.in",
        api_key="pk_live_...",
    ) as client:
        result = await client.document.extract("invoice.pdf", lang="eng")
        print(result.pages[0].text)


asyncio.run(main())
```

## Configuration

```python
client = VerisOCR(
    base_url="https://veris.recursai.in",  # or VERIS_OCR_BASE_URL
    api_key="pk_live_...",  # or VERIS_OCR_API_KEY
    admin_token="...",  # or VERIS_OCR_ADMIN_TOKEN
    timeout=120.0,  # seconds; OCR can be slow
    max_retries=2,  # transient failures on idempotent operations
    headers={"X-Application": "billing"},
)
```

Every resource method also accepts `timeout=` and `max_retries=` overrides.
Retries apply to idempotent health, history, admin-list, and key-revoke
operations. Extraction and key-creation requests are never automatically
retried because repeating them could create duplicate work or keys. Redirects
are surfaced as errors so API credentials are never forwarded to another
origin. Async requests can be cancelled with normal asyncio task cancellation.

## File inputs

Extraction methods accept:

- a `str` or `pathlib.Path` filesystem path;
- `bytes`, `bytearray`, or `memoryview`;
- a binary file object such as an open file or `io.BytesIO`;
- `FileDescriptor(data=..., filename=..., content_type=...)`.

The SDK detects JPEG, PNG, WEBP, PDF, DOCX, GIF, BMP, and TIFF signatures. The
Veris OCR server accepts JPEG, PNG, WEBP, PDF, and DOCX extraction uploads;
DOCX is available for document and resume extraction.

```python
from veriis import FileDescriptor

result = client.passport.extract(
    FileDescriptor(
        data=image_bytes,
        filename="passport-front.jpg",
        content_type="image/jpeg",
    )
)
```

## Resources

```python
client.passport.extract(file)
client.aadhaar.extract(file)
client.document.extract(file, lang="eng")
client.resume.extract(file)

client.jobs.submit(file, mode="aadhaar", idempotency_key="message/file")
client.jobs.submit_many(files, mode="aadhaar", concurrency=4)
client.jobs.get(job_id)

client.history.list(mode="passport", limit=50, offset=0)
client.history.get(item_id)
client.history.delete(item_id)
client.history.clear()

client.health.check()  # no API key required
```

Admin operations use `admin_token`, not `api_key`:

```python
created = client.admin.create_key(
    customer_email="developer@example.com",
    customer_name="Example Developer",
    key_name="production",
    allowed_ocr_modes=["passport", "document"],
)
print(created.key)  # returned only once

keys = client.admin.list_keys(include_revoked=False)
client.admin.revoke_key(created.api_key_id)
```

## Response models

Successful responses are Pydantic models. Access fields as attributes or
convert them back to JSON-compatible dictionaries:

```python
result = client.passport.extract("passport.jpg")
print(result.request_id)
print(result.model_dump(mode="json"))
```

Models allow unknown response fields so compatible server additions do not
break older client versions.

## Errors

HTTP, timeout, connection, and invalid-response failures derive from
`VerisOCRError`:

```python
from veriis import VerisOCRBadRequestError, VerisOCRRateLimitError

try:
    client.passport.extract("passport.jpg")
except VerisOCRRateLimitError as exc:
    print(f"Retry after {exc.retry_after} seconds")
except VerisOCRBadRequestError as exc:
    print(exc.code, exc.request_id, str(exc))
```

Available subclasses:

- `VerisOCRBadRequestError` for 400 and 413
- `VerisOCRAuthenticationError` for 401 and 403
- `VerisOCRNotFoundError` for 404
- `VerisOCRValidationError` for 422
- `VerisOCRRateLimitError` for 429
- `VerisOCRServerError` for 5xx
- `VerisOCRTimeoutError` for request timeouts
- `VerisOCRConnectionError` for network and connection failures

Local input failures stay idiomatic: missing paths raise `FileNotFoundError`,
unsupported file values raise `TypeError`, and invalid admin-key parameters
raise Pydantic `ValidationError` before any request is sent.

## Development and release

Run these commands from `clients/python`. The locked environment is the source
of the build tools used to create release artifacts:

```bash
uv sync --locked --extra dev --python 3.12
uv run --locked ruff format --check .
uv run --locked ruff check .
uv run --locked mypy
uv run --locked pytest --cov
uv run --locked python -m build --no-isolation
uv run --locked twine check --strict dist/*
uv run --locked python scripts/check_dist.py
```

Remove existing files from `dist/` before making a release build so the
distribution validator sees exactly one wheel and one source distribution.

TestPyPI can be used as an optional manual validation step. Configure a
TestPyPI API token for Twine, upload the freshly validated artifacts, install
the exact candidate version, and run an import smoke test:

```bash
python -m twine upload --repository testpypi dist/*
python -m pip install --index-url https://test.pypi.org/simple/ \
  --extra-index-url https://pypi.org/simple/ veriis==0.1.1
python -c "from veriis import VerisOCR, __version__; print(__version__)"
```

Production releases use only the repository's Trusted Publishing workflow; do
not upload production artifacts manually. Because the bundled license permits
use and redistribution only under a separate written agreement, obtain the
appropriate business/legal approval before making the artifacts public.
Before the first automated release, create the `veriis` project on
PyPI or configure a pending publisher with these exact settings:

- GitHub owner: `MohamedNasirS`
- Repository: `veris-ocr-recursai`
- Workflow: `python-client-release.yml`
- Environment: `pypi`

A pending publisher does not reserve the project name until its first
successful upload. Protect the GitHub `pypi` environment with a required
reviewer. Also add a repository ruleset for tags matching `python-v*` that
restricts tag creation, updates, and deletion to release maintainers.

For each release:

1. Update `src/veriis/_version.py` and `CHANGELOG.md`.
2. Regenerate `uv.lock` if dependency metadata changed, then run
   `uv lock --check`.
3. Remove old artifacts, run the development and distribution checks above,
   and verify both clean-environment smoke installs.
4. Merge the release commit to protected `main` and wait for Python client CI
   to pass.
5. Create and push an annotated tag whose version exactly matches
   `__version__`:

```bash
git tag -a python-v0.1.1 -m "Python client 0.1.1"
git push origin python-v0.1.1
```

The workflow rejects release commits that are not reachable from `main`,
checks that the tag equals `__version__`, runs linting, typing, and tests,
builds and validates the wheel and source distribution once, smoke-installs
both artifacts, and publishes that exact artifact through PyPI's OpenID
Connect trusted-publisher flow.

## License

Proprietary — © RecursAI Technologies.
