Metadata-Version: 2.4
Name: bjapi
Version: 0.3.1
Summary: Unofficial read-only client for the Mojira public bug tracker (bugs.mojang.com)
Home-page: https://bugs.mojang.com
License: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.20
Provides-Extra: test
Requires-Dist: pytest>=7.0; extra == "test"
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license
Dynamic: license-file
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# bjapi

`bjapi` is an unofficial, read-only client for **Mojira**, Mojang's public bug
tracker at [bugs.mojang.com](https://bugs.mojang.com). It wraps the site's
`/api/*` endpoints into a small Python object for crawling issues, comments,
attachments and more.

> This is a third-party reverse-engineered read-only client, not an official
> Mojang library. Please keep request rates reasonable.

## Features

- Anonymous access - no login or API token required
- Covers all 15 known `/api/*` endpoints
- High-level helpers: search, single issue, comments, attachments, pagination
- Low-level `post()` / `get()` for any endpoint, including future ones
- Basic and advanced JQL search
- Only depends on `requests`; `src` layout; Python 3.8+

## Installation

```bash
pip install bjapi
```

Or install from source:

```bash
pip install .
```

Editable development install:

```bash
pip install -e .
```

## Quick start

```python
from bjapi import Mojira

client = Mojira()

# Site info
site = client.site_info()

# Basic search: unresolved "zombie" issues in the MC project
data = client.search(project="MC", search="zombie", filter="open")
for issue in data["issues"]:
    print(issue["key"], issue["fields"]["summary"])

# Advanced JQL search
data = client.search(advanced=True, search="project = MC AND resolution = Fixed")

# Single issue (project is derived from the key prefix automatically)
issue = client.issue("MC-1")

# Comments (oldest to newest)
comments = client.comments("MC-1")

# Attachment bytes
content = client.attachment("596851")
with open("out.png", "wb") as f:
    f.write(content)

# Paginate through all results automatically
all_issues = client.all_issues(project="MC", filter="open")
```

## API overview

### Low-level methods

| Method | Description |
| --- | --- |
| `post(endpoint, payload=None)` | POST to `/api/{endpoint}`, returns a raw `requests.Response` |
| `get(endpoint, params=None)` | GET from `/api/{endpoint}`, returns a raw `requests.Response` |

Optionally pass `workspace_id` to the constructor. It is injected into the body
as `workspaceId` and into the `resource-id` header. Leave it empty for anonymous
access.

### High-level helpers

| Method | Description |
| --- | --- |
| `search(project="", search="", advanced=False, ...)` | Search issues, returns parsed JSON |
| `issue(issue_key, project="")` | Get a single issue, or `None` if not found |
| `comments(issue_key)` | Get the comment list |
| `attachment(attachment_id)` | Get attachment bytes |
| `all_issues(...)` | Automatically paginate through all issues |

### Endpoint wrappers

Each endpoint has a same-named method (with `-` replaced by `_`):

`site_info`, `user_details`, `record_rating`, `get_rating`,
`list_service_desks`, `get_service_desk`, `list_queues`, `list_issues`,
`jql_search_get`, `jql_search_post`, `basic_search_get`, `issue_comment_get`,
`project_search_get`, `service_desk_get`, `issue_attachment_get`.

Endpoints that currently return data:

- `site_info` -> `{"siteUrl": "https://mojira.atlassian.net"}`
- `jql_search_post` -> issue search (core)
- `issue_comment_get` -> comments
- `issue_attachment_get` -> attachment bytes

The other endpoints (`user-details`, `list-service-desks`, etc.) currently
return 404 from the backend. The wrappers return the error JSON as-is and do not
raise.

## Search parameters

`search()` translates its arguments into the JQL the backend expects:

- `advanced=False` (basic): `search` is keyword text, translated to
  `text ~ "...";` `filter` defaults to `open`
- `advanced=True` (advanced): `search` is raw JQL; `filter` defaults to `all`
- `sort_field`: `created` / `updated` / `priority` / `status`
- `sort_asc`: `False` means descending (newest first)
- `filter`: `open` (unresolved only) or `all`
- `page`: zero-based; `max_results`: page size

Note: the backend always appends `organizations = 'Players'`, so only
player-visible public issues are returned. In advanced mode, do not add your own
`ORDER BY` or duplicate `project =`, or you will get a 500.

## Response structure

`jql_search_post` returns:

```json
{
  "issues": [ { "key": "MC-1", "fields": {}, "renderedFields": {} } ],
  "names": { "summary": "Summary", "status": "Status" },
  "nextPageToken": "...",
  "isLast": false,
  "pagination": { "currentPage": 0, "pageSize": 25, "hasNextPage": true },
  "cacheRefreshed": true
}
```

Each issue contains both:

- `fields`: raw Jira v3 structured data (description is ADF JSON, dates are ISO
  strings)
- `renderedFields`: display-ready data (description is HTML, dates are friendly
  strings, attachment sizes are human-readable strings)

## Project reference

| Project key | Name |
| --- | --- |
| `MC` | Minecraft: Java Edition |
| `MCPE` | Minecraft (Bedrock codebase) |
| `MCD` | Minecraft Dungeons |
| `MCL` | Minecraft Launcher |
| `MCLG` | Minecraft Legends |
| `REALMS` | Minecraft Realms |
| `BDS` | Bedrock Dedicated Server |
| `WEB` | Mojang Web Services |

## Development

```bash
pip install -e .[test]
pytest
```

## License

MIT, see [LICENSE](LICENSE).
