No description
Find a file
2026-03-06 12:44:53 +01:00
api_spec update api specs 2026-03-03 21:44:01 +01:00
pyforgejo regenerate client 2026-03-03 22:50:42 +01:00
tests update tests 2026-03-03 23:09:52 +01:00
LICENSE add MIT license 2024-02-22 14:34:25 +01:00
pyproject.toml update pyproject.toml 2026-03-03 23:30:42 +01:00
README.md update dev steps 2026-03-06 12:44:53 +01:00
uv.lock update uv.lock 2026-03-03 23:30:52 +01:00

pyforgejo

A Python client library for accessing the Forgejo API.

⚠️ pyforgejo 2.0 introduces significant changes. If you're using 1.0, you can view docs on the 1.0 branch.

Usage

  1. Create an .env file in your project directory with the BASE_URL and your API_KEY:
BASE_URL=https://codeberg.org/api/v1
API_KEY=your_api_key
  1. Create a client and call an endpoint:
from pyforgejo import PyforgejoApi

client = PyforgejoApi()

# get a specific repo
repo = client.repository.repo_get(owner='harabat', repo='pyforgejo')

repo
# Repository(allow_fast_forward_only_merge=False, allow_merge_commits=True, allow_rebase=True, ...)

repo.dict()
# {'allow_fast_forward_only_merge': False,
#  'allow_merge_commits': True,
#  'allow_rebase': True,
#  ...
# }

# list issues for the repo
issues = client.issue.list_issues(owner=repo.owner.login, repo=repo.name)

[issue.title for issue in issues]
# ['Normalize option model names',
#  'Calling methods from client',
#  '`parsed` is None for most methods',
#  '`openapi-python-client` does not support `text/plain` requests']

The client follows this pattern for calling endpoints:

client.<resource>.<operation_id>(args)

where:

  • <resource>: the API resource (e.g., repository, issue, user)
  • <operation_id>: the specific operation, derived from the OpenAPI spec's operationId (converted to snake_case)

You can find the resource and operation_id either in the Swagger spec or in the API reference.

Installation

pip install pyforgejo

Forgejo API Resources

Development

Using fern

pyforgejo is generated with fern, based on a patched Forgejo OpenAPI spec.

The user experience and code architecture of the fern-generated client follow best practice. As the library is tested by users, we will identify any issues inherent to fern that prove limiting to pyforgejo: if we find such issues and cannot patch them upstream, the current codebase provides a good foundation for further development and any divergence from fern would not affect the vast majority of usecases.

Because the client has to apply to a specific Forgejo release, pyforgejo tracks Codeberg. If you need a client for a different Forgejo release, you can generate your own by following the steps below.

Generating the client with fern

  1. Download Forgejo's Swagger API spec and convert it to OpenAPI v3 via https://converter.swagger.io/.
mkdir api_spec
wget https://converter.swagger.io/api/convert\?url\=https%3A%2F%2Fcode.forgejo.org%2Fswagger.v1.json --output-document=api_spec/openapi.json
  1. Edit both swagger.v1.json and openapi.json to keep only AuthorizationHeaderToken in security definitions.
"securityDefinitions": {
  "AuthorizationHeaderToken": {
    "description": "API tokens must be prepended with \"token\" followed by a space.",
    "type": "apiKey",
    "name": "Authorization",
    "in": "header"
  }
},
"security": [
  {
    "AuthorizationHeaderToken": []
  }
]
  1. Modify endpoints with multiple return types in openapi.json.
    "/repos/{owner}/{repo}/contents/{filepath}": {
      "get": {
        // ...
        "responses": {
          "200": {
-            "$ref": "#/components/responses/ContentsResponse"
+            "description": "A single file's contents or a directory listing",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "oneOf": [
+                    {
+                      "$ref": "#/components/schemas/ContentsResponse"
+                    },
+                    {
+                      "type": "array",
+                      "items": {
+                        "$ref": "#/components/schemas/ContentsResponse"
+                      }
+                    }
+                  ]
+                }
+              },
+              "text/html": {
+                "schema": {
+                  "oneOf": [
+                    {
+                      "$ref": "#/components/schemas/ContentsResponse"
+                    },
+                    {
+                      "type": "array",
+                      "items": {
+                        "$ref": "#/components/schemas/ContentsResponse"
+                      }
+                    }
+                  ]
+                }
+              }
+            }
          },
          // ...
        }
      },
    },
  1. Install fern, initialise a new workspace, and specify pyforgejo as the name of your organisation (= client).
npm install -g fern-api

fern init --openapi api_spec/openapi.json
# Please enter your organization: pyforgejo
  1. Add the Python SDK generator.
fern add fernapi/fern-python-sdk
  1. Remove other generators and set the output directory to pyforgejo.
# yaml-language-server: $schema=https://schema.buildwithfern.dev/generators-yml.json
api:
  specs:
    - openapi: openapi/openapi.json
default-group: local
groups:
  local:
    generators:
-      - name: fernapi/fern-typescript-sdk
-        # ...
      - name: fernapi/fern-python-sdk
        version: x.x.x
        output:
          location: local-file-system
-          path: ../sdks/python
+          path: ../sdks/pyforgejo
  1. Generate the client (output will be in sdks/pyforgejo).
fern generate
# you'll have to login to GitHub
  1. Create a .env file in sdks/pyforgejo with your BASE_URL and API_KEY.
BASE_URL=https://codeberg.org/api/v1
API_KEY="token your_api_key"
  1. Modify the PyforgejoApi and AsyncPyforgejoApi classes in sdks/pyforgejo/client.py to use environment variables.
# ...
from .user.client import AsyncUserClient, UserClient
+import os
+from dotenv import load_dotenv
+
+load_dotenv()
+
+BASE_URL = os.getenv("BASE_URL", "")
+API_KEY = os.getenv("API_KEY", "")

class PyforgejoApi:
# ...
    base_url : typing.Optional[str]
-        The base url to use for requests from the client.
+        The base url to use for requests from the client. Defaults to BASE_URL from .env file.
# ...
-    api_key : str
+    api_key : typing.Optional[str]
+        The API key to use for authentication. Defaults to API_KEY from .env file.
# ...
    def __init__(
# ...
-        api_key: str,
+        api_key: typing.Optional[str] = None,
# ...
     ):
+        base_url = base_url or BASE_URL
+        api_key = api_key or API_KEY
+
+        if not base_url:
+            raise ValueError("base_url must be provided either as an .env variable or as an argument")
+        if not api_key:
+            raise ValueError("api_key must be provided either as an .env variable or as an argument")
# same for AsyncPyforgejoApi
  1. Update handling of api_key in core/client_wrapper.py.
    def get_headers(self) -> typing.Dict[str, str]:
        headers: typing.Dict[str, str] = {
            "X-Fern-Language": "Python",
        }
-        headers["Authorization"] = self.api_key
+        headers["Authorization"] = f"token {self.api_key.replace('token ', '')}"
        return headers
  1. Create a virtual environment and install dependencies.
wget https://codeberg.org/harabat/pyforgejo/raw/branch/main/pyproject.toml

uv venv
uv pip install -e '.[dev]'
uv sync --dev
uv run ruff format .

  1. Use the client as shown in the Usage section.
# uv pip install ipython
# uv run ipython

from pyforgejo import PyforgejoApi

client = PyforgejoApi()

user = client.user.get_current()
  1. Run tests.
wget https://codeberg.org/harabat/pyforgejo/archive/main:tests.zip
unzip tests.zip
rm tests.zip

uv run pytest -v tests/test_client.py