python-gitea 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitea/__init__.py +9 -0
- gitea/__main__.py +8 -0
- gitea/cli/__init__.py +0 -0
- gitea/cli/main.py +89 -0
- gitea/client/__init__.py +8 -0
- gitea/client/async_gitea.py +88 -0
- gitea/client/base.py +40 -0
- gitea/client/gitea.py +68 -0
- gitea/utils/__init__.py +7 -0
- gitea/utils/log.py +69 -0
- gitea/version.py +13 -0
- python_gitea-0.0.1.dist-info/METADATA +185 -0
- python_gitea-0.0.1.dist-info/RECORD +16 -0
- python_gitea-0.0.1.dist-info/WHEEL +4 -0
- python_gitea-0.0.1.dist-info/entry_points.txt +2 -0
- python_gitea-0.0.1.dist-info/licenses/LICENSE +21 -0
gitea/__init__.py
ADDED
gitea/__main__.py
ADDED
gitea/cli/__init__.py
ADDED
|
File without changes
|
gitea/cli/main.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# ruff: noqa PLC0415
|
|
2
|
+
"""Main entry point for the python-gitea CLI application."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import enum
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class LoggingLevel(str, enum.Enum):
|
|
13
|
+
"""Logging levels for the CLI."""
|
|
14
|
+
|
|
15
|
+
NOTSET = "NOTSET"
|
|
16
|
+
DEBUG = "DEBUG"
|
|
17
|
+
INFO = "INFO"
|
|
18
|
+
WARNING = "WARNING"
|
|
19
|
+
ERROR = "ERROR"
|
|
20
|
+
CRITICAL = "CRITICAL"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Create the main Typer app
|
|
24
|
+
app = typer.Typer(
|
|
25
|
+
name="python-gitea",
|
|
26
|
+
help="Main CLI for python-gitea.",
|
|
27
|
+
rich_markup_mode="rich",
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def setup_logging(level: LoggingLevel = LoggingLevel.INFO) -> None:
|
|
32
|
+
"""Set up logging with Rich handler.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
level: Logging level.
|
|
36
|
+
"""
|
|
37
|
+
import logging
|
|
38
|
+
|
|
39
|
+
from rich.console import Console
|
|
40
|
+
from rich.logging import RichHandler
|
|
41
|
+
|
|
42
|
+
logger = logging.getLogger("python-gitea")
|
|
43
|
+
|
|
44
|
+
logger.setLevel(level.value)
|
|
45
|
+
|
|
46
|
+
console = Console()
|
|
47
|
+
|
|
48
|
+
# Remove any existing handlers to ensure RichHandler is used
|
|
49
|
+
for h in logger.handlers[:]: # Use slice copy to avoid modification during iteration
|
|
50
|
+
logger.removeHandler(h)
|
|
51
|
+
# Add the RichHandler
|
|
52
|
+
|
|
53
|
+
handler = RichHandler(
|
|
54
|
+
console=console,
|
|
55
|
+
rich_tracebacks=True,
|
|
56
|
+
show_time=True,
|
|
57
|
+
show_level=True, # Keep level (e.g., DEBUG, INFO) for clarity
|
|
58
|
+
markup=True, # Enable Rich markup in messages for styling
|
|
59
|
+
level=level.value, # Ensure handler respects the level
|
|
60
|
+
omit_repeated_times=False,
|
|
61
|
+
log_time_format="%H:%M",
|
|
62
|
+
)
|
|
63
|
+
handler.setLevel(level.value)
|
|
64
|
+
logger.addHandler(handler)
|
|
65
|
+
|
|
66
|
+
# Prevent propagation to root logger to avoid duplicate output
|
|
67
|
+
logger.propagate = False
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@app.callback()
|
|
71
|
+
def main(
|
|
72
|
+
verbose: Annotated[
|
|
73
|
+
LoggingLevel,
|
|
74
|
+
typer.Option("--verbose", "-v", help="Set verbosity level."),
|
|
75
|
+
] = LoggingLevel.INFO,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""Main entry point for the CLI application.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
verbose: Verbosity level for logging.
|
|
81
|
+
"""
|
|
82
|
+
setup_logging(verbose)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def register_commands() -> None:
|
|
86
|
+
"""Register CLI commands."""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
register_commands()
|
gitea/client/__init__.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""Asynchronous Gitea API client implementation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from aiohttp import ClientSession, ClientTimeout
|
|
8
|
+
|
|
9
|
+
from gitea.client.base import Client
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AsyncGitea(Client): # pylint: disable=too-few-public-methods
|
|
13
|
+
"""Asynchronous Gitea API client."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, token: str, base_url: str = "https://gitea.com") -> None:
|
|
16
|
+
"""Initialize the asynchronous Gitea client.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
token: The API token for authentication.
|
|
20
|
+
base_url: The base URL of the Gitea instance.
|
|
21
|
+
"""
|
|
22
|
+
super().__init__(token=token, base_url=base_url)
|
|
23
|
+
self.session: ClientSession | None = None
|
|
24
|
+
|
|
25
|
+
async def __aenter__(self) -> AsyncGitea:
|
|
26
|
+
"""Enter the asynchronous context manager.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
The AsyncGitea client instance.
|
|
30
|
+
"""
|
|
31
|
+
if self.session is not None and not self.session.closed:
|
|
32
|
+
raise RuntimeError("AsyncGitea session already open; do not re-enter context manager.")
|
|
33
|
+
self.session = ClientSession(headers=self.headers)
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
37
|
+
"""Exit the asynchronous context manager.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
exc_type: The exception type.
|
|
41
|
+
exc_val: The exception value.
|
|
42
|
+
exc_tb: The traceback.
|
|
43
|
+
"""
|
|
44
|
+
if self.session:
|
|
45
|
+
await self.session.close()
|
|
46
|
+
self.session = None
|
|
47
|
+
|
|
48
|
+
def _get_session(self, headers: dict | None = None, **kwargs) -> ClientSession:
|
|
49
|
+
"""Get or create the aiohttp ClientSession.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
headers: Optional headers to include in the session.
|
|
53
|
+
**kwargs: Additional arguments for ClientSession.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The aiohttp ClientSession instance.
|
|
57
|
+
"""
|
|
58
|
+
return ClientSession(headers=headers, **kwargs)
|
|
59
|
+
|
|
60
|
+
async def _request(
|
|
61
|
+
self, method: str, endpoint: str, headers: dict | None = None, timeout: int = 30, **kwargs
|
|
62
|
+
) -> dict[str, Any]:
|
|
63
|
+
"""Make an asynchronous HTTP request to the Gitea API.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
method: The HTTP method (GET, POST, etc.).
|
|
67
|
+
endpoint: The API endpoint.
|
|
68
|
+
headers: Optional headers to include in the request.
|
|
69
|
+
timeout: Request timeout in seconds.
|
|
70
|
+
**kwargs: Additional arguments for the request.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
The JSON response as a dictionary.
|
|
74
|
+
"""
|
|
75
|
+
if self.session is None:
|
|
76
|
+
raise RuntimeError(
|
|
77
|
+
"AsyncGitea must be used as an async context manager. "
|
|
78
|
+
+ "Use 'async with AsyncGitea(...) as client:' to ensure proper resource cleanup."
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
url = self._build_url(endpoint=endpoint)
|
|
82
|
+
request_headers = {**self.headers, **(headers or {})}
|
|
83
|
+
timeout_obj = ClientTimeout(total=timeout)
|
|
84
|
+
async with self.session.request(
|
|
85
|
+
method=method, url=url, headers=request_headers, timeout=timeout_obj, **kwargs
|
|
86
|
+
) as response:
|
|
87
|
+
response.raise_for_status()
|
|
88
|
+
return await response.json()
|
gitea/client/base.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Base client class for Gitea API interactions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Client: # pylint: disable=too-few-public-methods
|
|
7
|
+
"""Abstract base class for Gitea clients."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, token: str, base_url: str) -> None:
|
|
10
|
+
"""Construct the base client.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
token: The API token for authentication.
|
|
14
|
+
base_url: The base URL of the Gitea instance.
|
|
15
|
+
"""
|
|
16
|
+
self.token = token
|
|
17
|
+
self.base_url = base_url.rstrip("/")
|
|
18
|
+
self.headers = {
|
|
19
|
+
"Authorization": f"token {self.token}",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def api_url(self) -> str:
|
|
24
|
+
"""Return the base API URL.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
str: The base API URL.
|
|
28
|
+
"""
|
|
29
|
+
return f"{self.base_url}/api/v1"
|
|
30
|
+
|
|
31
|
+
def _build_url(self, endpoint: str) -> str:
|
|
32
|
+
"""Construct the full URL for a given endpoint.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
endpoint (str): The API endpoint.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
str: The full URL.
|
|
39
|
+
"""
|
|
40
|
+
return f"{self.api_url}/{endpoint.lstrip('/')}"
|
gitea/client/gitea.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Gitea API client implementation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from gitea.client.base import Client
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Gitea(Client): # pylint: disable=too-few-public-methods
|
|
13
|
+
"""Synchronous Gitea API client."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, token: str, base_url: str = "https://gitea.com") -> None:
|
|
16
|
+
"""Initialize the Gitea client.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
token: The API token for authentication.
|
|
20
|
+
base_url: The base URL of the Gitea instance.
|
|
21
|
+
"""
|
|
22
|
+
super().__init__(token=token, base_url=base_url)
|
|
23
|
+
self.session: requests.Session | None = None
|
|
24
|
+
|
|
25
|
+
def __enter__(self) -> Gitea:
|
|
26
|
+
"""Enter the context manager.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
The Gitea client instance.
|
|
30
|
+
"""
|
|
31
|
+
if self.session is not None:
|
|
32
|
+
raise RuntimeError("Gitea session already open; do not re-enter context manager.")
|
|
33
|
+
self.session = requests.Session()
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
|
|
37
|
+
"""Exit the context manager.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
exc_type: The exception type.
|
|
41
|
+
exc_val: The exception value.
|
|
42
|
+
exc_tb: The traceback.
|
|
43
|
+
"""
|
|
44
|
+
if self.session:
|
|
45
|
+
self.session.close()
|
|
46
|
+
self.session = None
|
|
47
|
+
|
|
48
|
+
def _request(
|
|
49
|
+
self, method: str, endpoint: str, headers: dict | None = None, timeout: int = 30, **kwargs
|
|
50
|
+
) -> dict[str, Any]:
|
|
51
|
+
"""Make an HTTP request to the Gitea API.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
method: The HTTP method (GET, POST, etc.).
|
|
55
|
+
endpoint: The API endpoint.
|
|
56
|
+
headers: Additional headers for the request.
|
|
57
|
+
timeout: Timeout for the request in seconds.
|
|
58
|
+
**kwargs: Additional arguments for the request.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
The JSON response from the API.
|
|
62
|
+
"""
|
|
63
|
+
url = self._build_url(endpoint=endpoint)
|
|
64
|
+
response = self.session.request(
|
|
65
|
+
method, url, headers={**self.headers, **(headers or {})}, timeout=timeout, **kwargs
|
|
66
|
+
)
|
|
67
|
+
response.raise_for_status()
|
|
68
|
+
return response.json()
|
gitea/utils/__init__.py
ADDED
gitea/utils/log.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Utility functions for logging."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from gitea.version import __version__
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_version_information() -> str:
|
|
12
|
+
"""Get the version information.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
str: Version information.
|
|
16
|
+
"""
|
|
17
|
+
return __version__
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def setup_logger(
|
|
21
|
+
outdir: str = ".", label: str | None = None, log_level: str | int = "INFO", print_version: bool = False
|
|
22
|
+
) -> None:
|
|
23
|
+
"""Setup logging output: call at the start of the script to use
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
outdir: Output directory for log file.
|
|
27
|
+
label: Label for log file name. If None, no log file is created.
|
|
28
|
+
log_level: Logging level as string or integer.
|
|
29
|
+
print_version: Whether to print version information to the log.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
if isinstance(log_level, str):
|
|
33
|
+
try:
|
|
34
|
+
level = getattr(logging, log_level.upper())
|
|
35
|
+
except AttributeError as e:
|
|
36
|
+
raise ValueError(f"log_level {log_level} not understood") from e
|
|
37
|
+
else:
|
|
38
|
+
level = int(log_level)
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger("python-gitea")
|
|
41
|
+
logger.propagate = False
|
|
42
|
+
logger.setLevel(level)
|
|
43
|
+
|
|
44
|
+
if not any(
|
|
45
|
+
isinstance(h, logging.StreamHandler) and not isinstance(h, logging.FileHandler) for h in logger.handlers
|
|
46
|
+
):
|
|
47
|
+
stream_handler = logging.StreamHandler()
|
|
48
|
+
stream_handler.setFormatter(
|
|
49
|
+
logging.Formatter("%(asctime)s %(name)s %(levelname)-8s: %(message)s", datefmt="%H:%M")
|
|
50
|
+
)
|
|
51
|
+
stream_handler.setLevel(level)
|
|
52
|
+
logger.addHandler(stream_handler)
|
|
53
|
+
|
|
54
|
+
if not any(isinstance(h, logging.FileHandler) for h in logger.handlers) and label:
|
|
55
|
+
outdir_path = Path(outdir)
|
|
56
|
+
outdir_path.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
log_file = outdir_path / f"{label}.log"
|
|
58
|
+
file_handler = logging.FileHandler(log_file)
|
|
59
|
+
file_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)-8s: %(message)s", datefmt="%H:%M"))
|
|
60
|
+
|
|
61
|
+
file_handler.setLevel(level)
|
|
62
|
+
logger.addHandler(file_handler)
|
|
63
|
+
|
|
64
|
+
for handler in logger.handlers:
|
|
65
|
+
handler.setLevel(level)
|
|
66
|
+
|
|
67
|
+
if print_version:
|
|
68
|
+
version = get_version_information()
|
|
69
|
+
logger.info("Running python-gitea version: %s", version)
|
gitea/version.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A script to infer the version number from the metadata.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
__version__ = version("python-gitea")
|
|
11
|
+
except PackageNotFoundError:
|
|
12
|
+
# Fallback for source checkouts or environments without installed metadata.
|
|
13
|
+
__version__ = "0+unknown"
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-gitea
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A Python package for interacting with the Gitea API, offering a simple interface to access repositories, users, organizations, issues, and more for automation and data management.
|
|
5
|
+
Project-URL: Documentation, https://isaac-cf-wong.github.io/python-gitea
|
|
6
|
+
Project-URL: Source, https://github.com/isaac-cf-wong/python-gitea
|
|
7
|
+
Project-URL: Tracker, https://github.com/isaac-cf-wong/python-gitea/issues
|
|
8
|
+
Project-URL: Home, https://github.com/isaac-cf-wong/python-gitea
|
|
9
|
+
Project-URL: Release Notes, https://github.com/isaac-cf-wong/python-gitea/releases
|
|
10
|
+
Author-email: "Isaac C. F. Wong" <isaac.cf.wong@gmail.com>
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: aiohttp<4.0.0,>=3.8.0
|
|
21
|
+
Requires-Dist: requests<3.0.0,>=2.32.0
|
|
22
|
+
Requires-Dist: typer<1.0.0,>=0.21.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: black; extra == 'dev'
|
|
25
|
+
Requires-Dist: flake8; extra == 'dev'
|
|
26
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
28
|
+
Provides-Extra: docs
|
|
29
|
+
Requires-Dist: mike; extra == 'docs'
|
|
30
|
+
Requires-Dist: mkdocs; extra == 'docs'
|
|
31
|
+
Requires-Dist: mkdocs-gen-files; extra == 'docs'
|
|
32
|
+
Requires-Dist: mkdocs-literate-nav; extra == 'docs'
|
|
33
|
+
Requires-Dist: mkdocs-material; extra == 'docs'
|
|
34
|
+
Requires-Dist: mkdocs-section-index; extra == 'docs'
|
|
35
|
+
Requires-Dist: mkdocstrings[python]; extra == 'docs'
|
|
36
|
+
Provides-Extra: test
|
|
37
|
+
Requires-Dist: bandit[toml]==1.9.2; extra == 'test'
|
|
38
|
+
Requires-Dist: black==25.12.0; extra == 'test'
|
|
39
|
+
Requires-Dist: check-manifest==0.51; extra == 'test'
|
|
40
|
+
Requires-Dist: flake8; extra == 'test'
|
|
41
|
+
Requires-Dist: flake8-bugbear==25.11.29; extra == 'test'
|
|
42
|
+
Requires-Dist: flake8-docstrings; extra == 'test'
|
|
43
|
+
Requires-Dist: flake8-formatter-junit-xml; extra == 'test'
|
|
44
|
+
Requires-Dist: flake8-pyproject; extra == 'test'
|
|
45
|
+
Requires-Dist: pre-commit==4.5.1; extra == 'test'
|
|
46
|
+
Requires-Dist: pytest-asyncio; extra == 'test'
|
|
47
|
+
Requires-Dist: pytest-cov==7.0.0; extra == 'test'
|
|
48
|
+
Requires-Dist: pytest-github-actions-annotate-failures; extra == 'test'
|
|
49
|
+
Requires-Dist: pytest-mock<3.15.2; extra == 'test'
|
|
50
|
+
Requires-Dist: pytest-runner; extra == 'test'
|
|
51
|
+
Requires-Dist: pytest==9.0.2; extra == 'test'
|
|
52
|
+
Requires-Dist: shellcheck-py==0.11.0.1; extra == 'test'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# python-gitea
|
|
56
|
+
|
|
57
|
+
[](https://github.com/isaac-cf-wong/python-gitea/actions/workflows/CI.yml)
|
|
58
|
+
[](https://results.pre-commit.ci/latest/github/isaac-cf-wong/python-gitea/main)
|
|
59
|
+
[](https://isaac-cf-wong.github.io/python-gitea/)
|
|
60
|
+
[](https://codecov.io/gh/isaac-cf-wong/python-gitea)
|
|
61
|
+
[](https://pypi.org/project/python-gitea/)
|
|
62
|
+
[](https://pypi.org/project/package-name-placeholder/)
|
|
63
|
+
[](LICENSE)
|
|
64
|
+
[](https://github.com/PyCQA/bandit)
|
|
65
|
+
[](https://doi.org/10.5281/zenodo.18017404)
|
|
66
|
+
|
|
67
|
+
**Note:** This project is still in progress. The promised features are not fully ready yet, and APIs are subject to change.
|
|
68
|
+
|
|
69
|
+
A Python package for interacting with the Gitea API.
|
|
70
|
+
This package provides a simple and intuitive interface to access Gitea repositories, users, organizations, issues, and more,
|
|
71
|
+
enabling seamless integration with Gitea instances for automation, data retrieval, and management tasks.
|
|
72
|
+
|
|
73
|
+
## Features
|
|
74
|
+
|
|
75
|
+
Full API Coverage: Access to repositories, users, organizations, issues, pull requests, and more.
|
|
76
|
+
|
|
77
|
+
- Easy Authentication: Support for token-based authentication.
|
|
78
|
+
- Asynchronous Support: Built with async/await for non-blocking operations.
|
|
79
|
+
- Type Hints: Full type annotations for better IDE support and code reliability.
|
|
80
|
+
- Comprehensive Documentation: Detailed guides and API reference.
|
|
81
|
+
- Command-Line Interface: Interact with the Gitea API directly from the terminal for
|
|
82
|
+
quick, scriptable operations without writing code.
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
We recommend using `uv` to manage virtual environments for installing `python-gitea`.
|
|
87
|
+
|
|
88
|
+
If you don't have `uv` installed, you can install it with pip. See the project pages for more details:
|
|
89
|
+
|
|
90
|
+
- Install via pip: `pip install --upgrade pip && pip install uv`
|
|
91
|
+
- Project pages: [uv on PyPI](https://pypi.org/project/uv/) | [uv on GitHub](https://github.com/astral-sh/uv)
|
|
92
|
+
- Full documentation and usage guide: [uv docs](https://docs.astral.sh/uv/)
|
|
93
|
+
|
|
94
|
+
### Requirements
|
|
95
|
+
|
|
96
|
+
- Python 3.10 or higher
|
|
97
|
+
- Operating System: Linux, macOS, or Windows
|
|
98
|
+
|
|
99
|
+
### Install from PyPI
|
|
100
|
+
|
|
101
|
+
The recommended way to install `python-gitea` is from PyPI:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Create a virtual environment (recommended with uv)
|
|
105
|
+
uv venv --python 3.10
|
|
106
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
|
107
|
+
uv pip install python-gitea
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Optional Dependencies
|
|
111
|
+
|
|
112
|
+
For development or specific features:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Development dependencies (testing, linting, etc.)
|
|
116
|
+
uv pip install python-gitea[dev]
|
|
117
|
+
|
|
118
|
+
# Documentation dependencies
|
|
119
|
+
uv pip install python-gitea[docs]
|
|
120
|
+
|
|
121
|
+
# All dependencies
|
|
122
|
+
uv pip install python-gitea[dev,docs]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Install from Source
|
|
126
|
+
|
|
127
|
+
For the latest development version:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
git clone git@github.com:isaac-cf-wong/python-gitea.git
|
|
131
|
+
cd python-gitea
|
|
132
|
+
# Create a virtual environment (recommended with uv)
|
|
133
|
+
uv venv --python 3.10
|
|
134
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
|
135
|
+
uv pip install .
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Development Installation
|
|
139
|
+
|
|
140
|
+
To set up for development:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
git clone git@github.com:isaac-cf-wong/python-gitea.git
|
|
144
|
+
cd python-gitea
|
|
145
|
+
|
|
146
|
+
# Create a virtual environment (recommended with uv)
|
|
147
|
+
uv venv --python 3.10
|
|
148
|
+
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
|
149
|
+
uv pip install ".[dev]"
|
|
150
|
+
|
|
151
|
+
# Install the commitlint dependencies
|
|
152
|
+
npm install
|
|
153
|
+
|
|
154
|
+
# Install pre-commit hooks
|
|
155
|
+
pre-commit install
|
|
156
|
+
pre-commit install --hook-type commit-msg
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Verify Installation
|
|
160
|
+
|
|
161
|
+
Check that `python-gitea` is installed correctly:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
gitea-cli --help
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
python -c "import gitea; print(gitea.__version__)"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## License
|
|
172
|
+
|
|
173
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
174
|
+
|
|
175
|
+
## Support
|
|
176
|
+
|
|
177
|
+
For questions, issues, or contributions, please:
|
|
178
|
+
|
|
179
|
+
- Check the [documentation](https://isaac-cf-wong.github.io/python-gitea/)
|
|
180
|
+
- Open an issue on [GitHub](https://github.com/isaac-cf-wong/python-gitea/issues)
|
|
181
|
+
- Join our [discussions](https://github.com/isaac-cf-wong/python-gitea/discussions)
|
|
182
|
+
|
|
183
|
+
## Changelog
|
|
184
|
+
|
|
185
|
+
See [Release Notes](https://github.com/isaac-cf-wong/python-gitea/releases) for version history.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
gitea/__init__.py,sha256=A-KqBpsyLaneujE2QSqtD-xI3HKM5VUMTBZg1m8Cjqo,146
|
|
2
|
+
gitea/__main__.py,sha256=VxrPtOzhGWtiYFtbMf9HZfBOq69f1-6wiZKUgChCi9k,200
|
|
3
|
+
gitea/version.py,sha256=SBY7nWdooBkN0BKqo3R6jRH252I2teqmSdQSZpoCK3Y,349
|
|
4
|
+
gitea/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
gitea/cli/main.py,sha256=3mFRBVcGZnezGoweEiKMtaew5_8ksYMQS8N0GbwTGAk,2062
|
|
6
|
+
gitea/client/__init__.py,sha256=tWyILBf_tdTP1F6tf0NrNtgeEOYDRkc2QlHaga7GIo8,185
|
|
7
|
+
gitea/client/async_gitea.py,sha256=zsL_9oxdK1TLnU4AgVDm5Mnpm-XK65OLE0eASFAXKYU,3101
|
|
8
|
+
gitea/client/base.py,sha256=rmZJOS2fmp4t0Z_9wBv63T2zDJLBWOxEr3wxxsd8YRA,1060
|
|
9
|
+
gitea/client/gitea.py,sha256=Ad4YGnZrBkffjfG-VwGsejsKR19M6SDobqOcCA5Bl_Y,2112
|
|
10
|
+
gitea/utils/__init__.py,sha256=aP0FsAkvhZAoKrlaEWWvx_F7KU0HPqWhKElyBdEyTyk,212
|
|
11
|
+
gitea/utils/log.py,sha256=L11Fx66hPKS7Zvol5iiFSMw-GoDYcJMBlGYW2LqjjWI,2230
|
|
12
|
+
python_gitea-0.0.1.dist-info/METADATA,sha256=zNJDUVdBG5lnVMoCLo0gZDAuchAV5kXCHYDAJFIlQCg,7275
|
|
13
|
+
python_gitea-0.0.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
+
python_gitea-0.0.1.dist-info/entry_points.txt,sha256=m5yt-1RMRZRFMj_M-Un5E4eOkM113S9EppAHp0aCzEY,49
|
|
15
|
+
python_gitea-0.0.1.dist-info/licenses/LICENSE,sha256=4dW9zcCxiQKAu4CyNKJTRmvzdJCCHDxbPGuQ-YALpsY,1137
|
|
16
|
+
python_gitea-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 isaac-cf-wong
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE
|