xitzin 0.1.2__tar.gz
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.
- xitzin-0.1.2/PKG-INFO +118 -0
- xitzin-0.1.2/README.md +87 -0
- xitzin-0.1.2/pyproject.toml +58 -0
- xitzin-0.1.2/src/xitzin/__init__.py +78 -0
- xitzin-0.1.2/src/xitzin/application.py +548 -0
- xitzin-0.1.2/src/xitzin/auth.py +152 -0
- xitzin-0.1.2/src/xitzin/cgi.py +555 -0
- xitzin-0.1.2/src/xitzin/exceptions.py +138 -0
- xitzin-0.1.2/src/xitzin/middleware.py +219 -0
- xitzin-0.1.2/src/xitzin/py.typed +0 -0
- xitzin-0.1.2/src/xitzin/requests.py +150 -0
- xitzin-0.1.2/src/xitzin/responses.py +235 -0
- xitzin-0.1.2/src/xitzin/routing.py +381 -0
- xitzin-0.1.2/src/xitzin/templating.py +222 -0
- xitzin-0.1.2/src/xitzin/testing.py +267 -0
xitzin-0.1.2/PKG-INFO
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: xitzin
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: A Gemini Application Framework
|
|
5
|
+
Keywords: gemini,protocol,framework,async,geminispace
|
|
6
|
+
Author: Alan Velasco
|
|
7
|
+
Author-email: Alan Velasco <alanvelasco.a@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Internet
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Dist: jinja2>=3.1.0
|
|
21
|
+
Requires-Dist: nauyaca>=0.3.2
|
|
22
|
+
Requires-Dist: rich>=14.2.0
|
|
23
|
+
Requires-Dist: typing-extensions>=4.15.0
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Project-URL: Changelog, https://xitzin.readthedocs.io/changelog/
|
|
26
|
+
Project-URL: Documentation, https://xitzin.readthedocs.io
|
|
27
|
+
Project-URL: Homepage, https://github.com/alanbato/xitzin
|
|
28
|
+
Project-URL: Issues, https://github.com/alanbato/xitzin/issues
|
|
29
|
+
Project-URL: Repository, https://github.com/alanbato/xitzin.git
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Xitzin
|
|
33
|
+
|
|
34
|
+
**Application Framework for the Geminispace**
|
|
35
|
+
|
|
36
|
+
Xitzin brings a modern Python developer experience to the [Gemini protocol](https://geminiprotocol.net/). Build Gemini capsules with familiar patterns: decorators for routing and type-annotated path parameters.
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from xitzin import Xitzin, Request
|
|
40
|
+
|
|
41
|
+
app = Xitzin()
|
|
42
|
+
|
|
43
|
+
@app.gemini("/")
|
|
44
|
+
def home(request: Request):
|
|
45
|
+
return "# Welcome to my capsule!"
|
|
46
|
+
|
|
47
|
+
@app.gemini("/user/{username}")
|
|
48
|
+
def profile(request: Request, username: str):
|
|
49
|
+
return f"# {username}'s Profile"
|
|
50
|
+
|
|
51
|
+
@app.input("/search", prompt="Enter query:")
|
|
52
|
+
def search(request: Request, query: str):
|
|
53
|
+
return f"# Results for: {query}"
|
|
54
|
+
|
|
55
|
+
if __name__ == "__main__":
|
|
56
|
+
app.run()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Features
|
|
60
|
+
|
|
61
|
+
- **Decorator-based routing** with `@app.gemini()` and automatic path parameter extraction
|
|
62
|
+
- **User input handling** via `@app.input()` for Gemini's status 10/11 prompts
|
|
63
|
+
- **Certificate authentication** with `@require_certificate` and fingerprint whitelisting
|
|
64
|
+
- **Jinja2 templates** with Gemtext-aware filters (links, headings, lists)
|
|
65
|
+
- **Middleware support** for logging, rate limiting, and custom processing
|
|
66
|
+
- **Testing utilities** with in-memory `TestClient`
|
|
67
|
+
- **Async support** for both sync and async handlers
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install xitzin
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv add xitzin
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Quick Start
|
|
82
|
+
|
|
83
|
+
1. Create `app.py`:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from xitzin import Xitzin, Request
|
|
87
|
+
|
|
88
|
+
app = Xitzin()
|
|
89
|
+
|
|
90
|
+
@app.gemini("/")
|
|
91
|
+
def home(request: Request):
|
|
92
|
+
return "# Hello, Geminispace!"
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
app.run()
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
2. Generate TLS certificates:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
3. Run your capsule:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
python app.py
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
4. Visit `gemini://localhost/` with a Gemini client like [Astronomo](https://github.com/alanbato/astronomo/).
|
|
111
|
+
|
|
112
|
+
## Documentation
|
|
113
|
+
|
|
114
|
+
Full documentation is available at [xitzin.readthedocs.io](https://xitzin.readthedocs.io/).
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
MIT
|
xitzin-0.1.2/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Xitzin
|
|
2
|
+
|
|
3
|
+
**Application Framework for the Geminispace**
|
|
4
|
+
|
|
5
|
+
Xitzin brings a modern Python developer experience to the [Gemini protocol](https://geminiprotocol.net/). Build Gemini capsules with familiar patterns: decorators for routing and type-annotated path parameters.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from xitzin import Xitzin, Request
|
|
9
|
+
|
|
10
|
+
app = Xitzin()
|
|
11
|
+
|
|
12
|
+
@app.gemini("/")
|
|
13
|
+
def home(request: Request):
|
|
14
|
+
return "# Welcome to my capsule!"
|
|
15
|
+
|
|
16
|
+
@app.gemini("/user/{username}")
|
|
17
|
+
def profile(request: Request, username: str):
|
|
18
|
+
return f"# {username}'s Profile"
|
|
19
|
+
|
|
20
|
+
@app.input("/search", prompt="Enter query:")
|
|
21
|
+
def search(request: Request, query: str):
|
|
22
|
+
return f"# Results for: {query}"
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
app.run()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- **Decorator-based routing** with `@app.gemini()` and automatic path parameter extraction
|
|
31
|
+
- **User input handling** via `@app.input()` for Gemini's status 10/11 prompts
|
|
32
|
+
- **Certificate authentication** with `@require_certificate` and fingerprint whitelisting
|
|
33
|
+
- **Jinja2 templates** with Gemtext-aware filters (links, headings, lists)
|
|
34
|
+
- **Middleware support** for logging, rate limiting, and custom processing
|
|
35
|
+
- **Testing utilities** with in-memory `TestClient`
|
|
36
|
+
- **Async support** for both sync and async handlers
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install xitzin
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv add xitzin
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
1. Create `app.py`:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from xitzin import Xitzin, Request
|
|
56
|
+
|
|
57
|
+
app = Xitzin()
|
|
58
|
+
|
|
59
|
+
@app.gemini("/")
|
|
60
|
+
def home(request: Request):
|
|
61
|
+
return "# Hello, Geminispace!"
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
app.run()
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
2. Generate TLS certificates:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
3. Run your capsule:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python app.py
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
4. Visit `gemini://localhost/` with a Gemini client like [Astronomo](https://github.com/alanbato/astronomo/).
|
|
80
|
+
|
|
81
|
+
## Documentation
|
|
82
|
+
|
|
83
|
+
Full documentation is available at [xitzin.readthedocs.io](https://xitzin.readthedocs.io/).
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "xitzin"
|
|
3
|
+
version = "0.1.2"
|
|
4
|
+
description = "A Gemini Application Framework"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = { text = "MIT" }
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Alan Velasco", email = "alanvelasco.a@gmail.com" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
keywords = ["gemini", "protocol", "framework", "async", "geminispace"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.10",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Internet",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"jinja2>=3.1.0",
|
|
27
|
+
"nauyaca>=0.3.2",
|
|
28
|
+
"rich>=14.2.0",
|
|
29
|
+
"typing-extensions>=4.15.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/alanbato/xitzin"
|
|
34
|
+
Documentation = "https://xitzin.readthedocs.io"
|
|
35
|
+
Repository = "https://github.com/alanbato/xitzin.git"
|
|
36
|
+
Issues = "https://github.com/alanbato/xitzin/issues"
|
|
37
|
+
Changelog = "https://xitzin.readthedocs.io/changelog/"
|
|
38
|
+
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["uv_build>=0.9.10,<0.10.0"]
|
|
41
|
+
build-backend = "uv_build"
|
|
42
|
+
|
|
43
|
+
[dependency-groups]
|
|
44
|
+
dev = [
|
|
45
|
+
"pre-commit>=4.5.1",
|
|
46
|
+
"pytest>=9.0.2",
|
|
47
|
+
"pytest-asyncio>=0.24.0",
|
|
48
|
+
"pytest-cov>=7.0.0",
|
|
49
|
+
"ruff>=0.14.10",
|
|
50
|
+
"ty>=0.0.8",
|
|
51
|
+
]
|
|
52
|
+
docs = [
|
|
53
|
+
"mkdocs>=1.6.1",
|
|
54
|
+
"mkdocs-material>=9.5.0",
|
|
55
|
+
"mkdocstrings[python]>=0.24.0",
|
|
56
|
+
"mkdocs-git-revision-date-localized-plugin>=1.2.0",
|
|
57
|
+
"pymdown-extensions>=10.20",
|
|
58
|
+
]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Xitzin - A Gemini Application Framework.
|
|
2
|
+
|
|
3
|
+
Xitzin is a framework for building Gemini protocol applications.
|
|
4
|
+
It uses Nauyaca for Gemini protocol communication.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
from xitzin import Xitzin, Request
|
|
8
|
+
|
|
9
|
+
app = Xitzin()
|
|
10
|
+
|
|
11
|
+
@app.gemini("/")
|
|
12
|
+
def home(request: Request):
|
|
13
|
+
return "# Welcome to Gemini!"
|
|
14
|
+
|
|
15
|
+
@app.gemini("/user/{username}")
|
|
16
|
+
def profile(request: Request, username: str):
|
|
17
|
+
return f"# {username}'s Profile"
|
|
18
|
+
|
|
19
|
+
if __name__ == "__main__":
|
|
20
|
+
app.run()
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from .application import Xitzin
|
|
24
|
+
from .cgi import CGIConfig, CGIHandler, CGIScript
|
|
25
|
+
from .exceptions import (
|
|
26
|
+
BadRequest,
|
|
27
|
+
CertificateNotAuthorized,
|
|
28
|
+
CertificateNotValid,
|
|
29
|
+
CertificateRequired,
|
|
30
|
+
CGIError,
|
|
31
|
+
GeminiException,
|
|
32
|
+
Gone,
|
|
33
|
+
InputRequired,
|
|
34
|
+
NotFound,
|
|
35
|
+
PermanentFailure,
|
|
36
|
+
ProxyError,
|
|
37
|
+
ProxyRequestRefused,
|
|
38
|
+
SensitiveInputRequired,
|
|
39
|
+
ServerUnavailable,
|
|
40
|
+
SlowDown,
|
|
41
|
+
TemporaryFailure,
|
|
42
|
+
)
|
|
43
|
+
from .requests import Request
|
|
44
|
+
from .responses import Input, Link, Redirect, Response
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
# Main application
|
|
48
|
+
"Xitzin",
|
|
49
|
+
# Request/Response
|
|
50
|
+
"Request",
|
|
51
|
+
"Response",
|
|
52
|
+
"Input",
|
|
53
|
+
"Redirect",
|
|
54
|
+
"Link",
|
|
55
|
+
# CGI support
|
|
56
|
+
"CGIConfig",
|
|
57
|
+
"CGIHandler",
|
|
58
|
+
"CGIScript",
|
|
59
|
+
# Exceptions
|
|
60
|
+
"GeminiException",
|
|
61
|
+
"InputRequired",
|
|
62
|
+
"SensitiveInputRequired",
|
|
63
|
+
"TemporaryFailure",
|
|
64
|
+
"ServerUnavailable",
|
|
65
|
+
"CGIError",
|
|
66
|
+
"ProxyError",
|
|
67
|
+
"SlowDown",
|
|
68
|
+
"PermanentFailure",
|
|
69
|
+
"NotFound",
|
|
70
|
+
"Gone",
|
|
71
|
+
"ProxyRequestRefused",
|
|
72
|
+
"BadRequest",
|
|
73
|
+
"CertificateRequired",
|
|
74
|
+
"CertificateNotAuthorized",
|
|
75
|
+
"CertificateNotValid",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
__version__ = "0.1.0"
|