Modern Python Jira client — sync and async — powered by HTTPX
Project description
jirapi
Modern, type-safe Python client for the Jira Cloud REST API — built on HTTPX for first-class sync and async support.
Features
- Sync and async — identical API surface via
Jira(sync) andAsyncJira(async) - Full API coverage — auto-generated resource methods for 580+ Jira Cloud REST endpoints
- Type-safe — Pydantic v2 models for every request and response payload
- Composition pattern — resource groups (
issues,projects,users, …) exposed as lazy@cached_propertyattributes - Pagination helpers — built-in iterators for offset, PageBean, and cursor pagination
- Semantic exceptions —
AuthenticationError,NotFoundError,RateLimitError, etc. - Modern Python — 3.11+, built-in generics, union types, no legacy
typingimports - Minimal dependencies — just
httpxandpydantic
Installation
pip install jirapi
# or
uv add jirapi
Quick Start
Synchronous
from jirapi import Jira
jira = Jira(
url="https://yoursite.atlassian.net",
email="you@example.com",
api_token="your-api-token",
)
# Fetch a single issue
issue = jira.issues.get_issue("PROJ-123")
print(issue.fields.summary)
# Search projects
page = jira.projects.search_projects(query="backend", max_results=10)
# Always close when done (or use a context manager)
jira.close()
Context Manager
from jirapi import Jira
with Jira(url="https://yoursite.atlassian.net", email="...", api_token="...") as jira:
issue = jira.issues.get_issue("PROJ-123")
Asynchronous
import asyncio
from jirapi import AsyncJira
async def main():
async with AsyncJira(
url="https://yoursite.atlassian.net",
email="you@example.com",
api_token="your-api-token",
) as jira:
issue = await jira.issues.get_issue("PROJ-123")
print(issue.fields.summary)
asyncio.run(main())
Resource Groups
All API endpoints are organised into resource groups accessible as properties on the client:
jira.issues # Issues, changelogs, transitions
jira.projects # Projects CRUD and search
jira.users # User lookup and management
jira.issue_search # JQL search
jira.dashboards # Dashboard operations
jira.filters # Saved filter management
jira.workflows # Workflow definitions
jira.permissions # Permission checks
jira.server_info # Jira instance metadata
# … 60+ resource groups in total
Each method returns a strongly-typed Pydantic model:
from jirapi.models import IssueUpdateDetails
# Create an issue
created = jira.issues.create_issue(
body=IssueUpdateDetails.model_validate({
"fields": {
"project": {"key": "PROJ"},
"summary": "New issue from jirapi",
"issuetype": {"name": "Task"},
}
})
)
print(created.key)
Error Handling
All API errors are mapped to typed exceptions:
from jirapi import Jira, NotFoundError, RateLimitError, AuthenticationError
import time
jira = Jira(url="...", email="...", api_token="...")
try:
jira.issues.get_issue("DOES-NOT-EXIST")
except NotFoundError as e:
print(f"Issue not found: {e}")
except RateLimitError as e:
print(f"Rate limited — retry after {e.retry_after}s")
time.sleep(e.retry_after or 60)
except AuthenticationError:
print("Check your credentials")
| Status Code | Exception |
|---|---|
| 400 | ValidationError |
| 401 | AuthenticationError |
| 403 | ForbiddenError |
| 404 | NotFoundError |
| 409 | ConflictError |
| 429 | RateLimitError |
| 5xx | ServerError |
Pagination
jirapi provides pagination helpers for all three patterns used by the Jira API:
from jirapi.pagination import paginate_offset, paginate_page_bean
# Offset-based (e.g. issue search)
for issue in paginate_offset(jira._request, "GET", "/rest/api/3/search", results_key="issues"):
print(issue["key"])
# PageBean-based (e.g. project search)
for project in paginate_page_bean(jira._request, "GET", "/rest/api/3/project/search"):
print(project["name"])
Configuration
| Parameter | Description | Default |
|---|---|---|
url |
Jira Cloud instance URL | — |
email |
Account email for Basic auth | — |
api_token |
API token from id.atlassian.com | — |
timeout |
Request timeout in seconds | 30.0 |
**httpx_client_kwargs |
Extra kwargs passed to the underlying HTTPX client | — |
Development
# Install dependencies
task setup # uv sync --all-groups
# Run quality checks
task check # lint + format check + tests
# Run tests with coverage
task test:cov # uv run pytest --cov=jirapi tests/unit
# Regenerate models from OpenAPI spec
uv run python scripts/generate_models.py
# Regenerate resource classes and client wiring
uv run python scripts/generate_resources.py
Architecture
jirapi/
├── __init__.py # Public API exports
├── client.py # Jira (sync) + AsyncJira — entry points
├── _base_client.py # Shared HTTP logic, auth, error checking
├── _resource.py # SyncAPIResource / AsyncAPIResource bases
├── _types.py # Type aliases (JSON, Params, T)
├── exceptions.py # Exception hierarchy
├── pagination.py # Offset / PageBean / cursor iterators
├── models/ # 967 auto-generated Pydantic v2 models
│ └── __init__.py
└── resources/ # 60+ auto-generated resource modules
├── __init__.py
├── issues.py # Issues + AsyncIssues
├── projects.py # Projects + AsyncProjects
└── ...
scripts/
├── generate_models.py # OpenAPI → Pydantic models
└── generate_resources.py # OpenAPI → resource classes + client wiring
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jirapi-0.1.0.tar.gz.
File metadata
- Download URL: jirapi-0.1.0.tar.gz
- Upload date:
- Size: 517.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e29ea0c0c611e93311ab2d5daa236e0fd75f5c6892472e4826f0b3d3c27b6ddc
|
|
| MD5 |
83adcfdf3d1f83071082550c20846cc7
|
|
| BLAKE2b-256 |
5df6ba976188c55f3c640e781f35acbbbbb938a23effae456d724f6a2045aa88
|
File details
Details for the file jirapi-0.1.0-py3-none-any.whl.
File metadata
- Download URL: jirapi-0.1.0-py3-none-any.whl
- Upload date:
- Size: 220.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8861d698c5c373bb39891009220e5b412fbb90a2d048a7618c0339ec8ecfc42
|
|
| MD5 |
a3c34639e9c43c8089dd42e1335fb162
|
|
| BLAKE2b-256 |
06d61388c6b683eb00bdeccc6f20aa56fdfe1116e5ce8604a7f1776ece6f6909
|