creatine 0.1.0__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.
- creatine-0.1.0/LICENSE +21 -0
- creatine-0.1.0/PKG-INFO +202 -0
- creatine-0.1.0/README.md +167 -0
- creatine-0.1.0/creatine/__init__.py +19 -0
- creatine-0.1.0/creatine/__main__.py +101 -0
- creatine-0.1.0/creatine/api.py +208 -0
- creatine-0.1.0/creatine/asgi.py +140 -0
- creatine-0.1.0/creatine/exceptions.py +43 -0
- creatine-0.1.0/creatine/log.py +56 -0
- creatine-0.1.0/creatine/middleware.py +56 -0
- creatine-0.1.0/creatine/orm.py +275 -0
- creatine-0.1.0/creatine/response.py +71 -0
- creatine-0.1.0/creatine/route.py +87 -0
- creatine-0.1.0/creatine/utils.py +60 -0
- creatine-0.1.0/creatine.egg-info/PKG-INFO +202 -0
- creatine-0.1.0/creatine.egg-info/SOURCES.txt +28 -0
- creatine-0.1.0/creatine.egg-info/dependency_links.txt +1 -0
- creatine-0.1.0/creatine.egg-info/entry_points.txt +2 -0
- creatine-0.1.0/creatine.egg-info/requires.txt +12 -0
- creatine-0.1.0/creatine.egg-info/top_level.txt +1 -0
- creatine-0.1.0/pyproject.toml +59 -0
- creatine-0.1.0/setup.cfg +4 -0
- creatine-0.1.0/tests/test_asgi.py +122 -0
- creatine-0.1.0/tests/test_error_handler.py +27 -0
- creatine-0.1.0/tests/test_handlers.py +68 -0
- creatine-0.1.0/tests/test_logging.py +21 -0
- creatine-0.1.0/tests/test_middleware.py +31 -0
- creatine-0.1.0/tests/test_orm.py +187 -0
- creatine-0.1.0/tests/test_response.py +61 -0
- creatine-0.1.0/tests/test_routes.py +55 -0
creatine-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Fazliddin
|
|
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.
|
creatine-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: creatine
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight Python web framework with WSGI and ASGI support.
|
|
5
|
+
Author: Fazliddin
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/fazliddinio/creatine
|
|
8
|
+
Project-URL: Repository, https://github.com/fazliddinio/creatine
|
|
9
|
+
Project-URL: Issues, https://github.com/fazliddinio/creatine/issues
|
|
10
|
+
Keywords: web,framework,wsgi,asgi,http
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: Jinja2>=3.1
|
|
24
|
+
Requires-Dist: parse>=1.20
|
|
25
|
+
Requires-Dist: requests>=2.30
|
|
26
|
+
Requires-Dist: requests-wsgi-adapter>=0.4
|
|
27
|
+
Requires-Dist: WebOb>=1.8
|
|
28
|
+
Requires-Dist: whitenoise>=6.5
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
32
|
+
Requires-Dist: gunicorn>=22.0; extra == "dev"
|
|
33
|
+
Requires-Dist: uvicorn>=0.30; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# Creatine
|
|
37
|
+
|
|
38
|
+
A lightweight Python web framework with WSGI and ASGI support.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install creatine
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
For development:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install creatine[dev]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from creatine import Creatine
|
|
56
|
+
|
|
57
|
+
app = Creatine()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@app.route("/")
|
|
61
|
+
def home(req, resp):
|
|
62
|
+
resp.text = "Hello, World!"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@app.route("/greeting/{name}")
|
|
66
|
+
def greeting(req, resp, name):
|
|
67
|
+
resp.text = f"Hello, {name}"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@app.route("/book")
|
|
71
|
+
class BookResource:
|
|
72
|
+
def get(self, req, resp):
|
|
73
|
+
resp.text = "Books Page"
|
|
74
|
+
|
|
75
|
+
def post(self, req, resp):
|
|
76
|
+
resp.text = "Book created"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@app.route("/json")
|
|
80
|
+
def json_handler(req, resp):
|
|
81
|
+
resp.json = {"message": "hello"}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@app.route("/template")
|
|
85
|
+
def template_handler(req, resp):
|
|
86
|
+
resp.html = app.template("index.html", context={"title": "Hello"})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Running the Server
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Built-in dev server
|
|
93
|
+
creatine runserver app:app
|
|
94
|
+
|
|
95
|
+
# With Gunicorn (WSGI)
|
|
96
|
+
gunicorn app:app
|
|
97
|
+
|
|
98
|
+
# With Uvicorn (ASGI)
|
|
99
|
+
uvicorn app:asgi_app
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## ASGI & Async Handlers
|
|
103
|
+
|
|
104
|
+
Creatine supports both sync and async handlers when running under ASGI:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
app = Creatine()
|
|
108
|
+
|
|
109
|
+
asgi_app = app.as_asgi()
|
|
110
|
+
|
|
111
|
+
@app.route("/async")
|
|
112
|
+
async def async_handler(req, resp):
|
|
113
|
+
resp.json = {"async": True}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Middleware
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from creatine import Middleware
|
|
120
|
+
from creatine.log import LoggingMiddleware
|
|
121
|
+
|
|
122
|
+
# Built-in request logging
|
|
123
|
+
app.add_middleware(LoggingMiddleware)
|
|
124
|
+
|
|
125
|
+
# Custom middleware
|
|
126
|
+
class AuthMiddleware(Middleware):
|
|
127
|
+
def process_request(self, req):
|
|
128
|
+
print(f"Auth check: {req.url}")
|
|
129
|
+
|
|
130
|
+
def process_response(self, req, resp):
|
|
131
|
+
print(f"Completed: {resp.status_code}")
|
|
132
|
+
|
|
133
|
+
app.add_middleware(AuthMiddleware)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## ORM
|
|
137
|
+
|
|
138
|
+
Built-in SQLite ORM for simple data persistence:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from creatine import Database, Table, Column, ForeignKey
|
|
142
|
+
|
|
143
|
+
db = Database("./app.db")
|
|
144
|
+
|
|
145
|
+
class Author(Table):
|
|
146
|
+
name = Column(str)
|
|
147
|
+
age = Column(int)
|
|
148
|
+
|
|
149
|
+
class Book(Table):
|
|
150
|
+
title = Column(str)
|
|
151
|
+
author = ForeignKey(Author)
|
|
152
|
+
|
|
153
|
+
db.create(Author)
|
|
154
|
+
db.create(Book)
|
|
155
|
+
|
|
156
|
+
author = Author(name="Jane", age=30)
|
|
157
|
+
db.save(author)
|
|
158
|
+
db.update(author)
|
|
159
|
+
db.delete(Author, id=1)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Features
|
|
163
|
+
|
|
164
|
+
- WSGI and ASGI compatible
|
|
165
|
+
- Async handler support
|
|
166
|
+
- Parameterized and basic routing
|
|
167
|
+
- Class-based and function-based handlers
|
|
168
|
+
- Built-in SQLite ORM with foreign keys
|
|
169
|
+
- Jinja2 templates
|
|
170
|
+
- Static files via WhiteNoise
|
|
171
|
+
- Middleware pipeline with built-in logging
|
|
172
|
+
- Custom exception handlers
|
|
173
|
+
- Test client (based on Requests)
|
|
174
|
+
- CLI (`creatine runserver`)
|
|
175
|
+
- GitHub Actions CI with pytest and mypy
|
|
176
|
+
|
|
177
|
+
## Tests
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
pytest
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Project Structure
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
creatine/
|
|
187
|
+
├── __init__.py # Package exports and version
|
|
188
|
+
├── __main__.py # CLI entry point
|
|
189
|
+
├── api.py # Core Creatine application class
|
|
190
|
+
├── asgi.py # ASGI adapter
|
|
191
|
+
├── exceptions.py # HTTPError
|
|
192
|
+
├── log.py # Logging middleware
|
|
193
|
+
├── middleware.py # Middleware base class
|
|
194
|
+
├── orm.py # SQLite ORM
|
|
195
|
+
├── response.py # Response wrapper
|
|
196
|
+
├── route.py # Route matching and dispatch
|
|
197
|
+
└── utils.py # Static file and test helpers
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## License
|
|
201
|
+
|
|
202
|
+
MIT
|
creatine-0.1.0/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Creatine
|
|
2
|
+
|
|
3
|
+
A lightweight Python web framework with WSGI and ASGI support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install creatine
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For development:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install creatine[dev]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from creatine import Creatine
|
|
21
|
+
|
|
22
|
+
app = Creatine()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@app.route("/")
|
|
26
|
+
def home(req, resp):
|
|
27
|
+
resp.text = "Hello, World!"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.route("/greeting/{name}")
|
|
31
|
+
def greeting(req, resp, name):
|
|
32
|
+
resp.text = f"Hello, {name}"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@app.route("/book")
|
|
36
|
+
class BookResource:
|
|
37
|
+
def get(self, req, resp):
|
|
38
|
+
resp.text = "Books Page"
|
|
39
|
+
|
|
40
|
+
def post(self, req, resp):
|
|
41
|
+
resp.text = "Book created"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@app.route("/json")
|
|
45
|
+
def json_handler(req, resp):
|
|
46
|
+
resp.json = {"message": "hello"}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@app.route("/template")
|
|
50
|
+
def template_handler(req, resp):
|
|
51
|
+
resp.html = app.template("index.html", context={"title": "Hello"})
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Running the Server
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Built-in dev server
|
|
58
|
+
creatine runserver app:app
|
|
59
|
+
|
|
60
|
+
# With Gunicorn (WSGI)
|
|
61
|
+
gunicorn app:app
|
|
62
|
+
|
|
63
|
+
# With Uvicorn (ASGI)
|
|
64
|
+
uvicorn app:asgi_app
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## ASGI & Async Handlers
|
|
68
|
+
|
|
69
|
+
Creatine supports both sync and async handlers when running under ASGI:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
app = Creatine()
|
|
73
|
+
|
|
74
|
+
asgi_app = app.as_asgi()
|
|
75
|
+
|
|
76
|
+
@app.route("/async")
|
|
77
|
+
async def async_handler(req, resp):
|
|
78
|
+
resp.json = {"async": True}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Middleware
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from creatine import Middleware
|
|
85
|
+
from creatine.log import LoggingMiddleware
|
|
86
|
+
|
|
87
|
+
# Built-in request logging
|
|
88
|
+
app.add_middleware(LoggingMiddleware)
|
|
89
|
+
|
|
90
|
+
# Custom middleware
|
|
91
|
+
class AuthMiddleware(Middleware):
|
|
92
|
+
def process_request(self, req):
|
|
93
|
+
print(f"Auth check: {req.url}")
|
|
94
|
+
|
|
95
|
+
def process_response(self, req, resp):
|
|
96
|
+
print(f"Completed: {resp.status_code}")
|
|
97
|
+
|
|
98
|
+
app.add_middleware(AuthMiddleware)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## ORM
|
|
102
|
+
|
|
103
|
+
Built-in SQLite ORM for simple data persistence:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from creatine import Database, Table, Column, ForeignKey
|
|
107
|
+
|
|
108
|
+
db = Database("./app.db")
|
|
109
|
+
|
|
110
|
+
class Author(Table):
|
|
111
|
+
name = Column(str)
|
|
112
|
+
age = Column(int)
|
|
113
|
+
|
|
114
|
+
class Book(Table):
|
|
115
|
+
title = Column(str)
|
|
116
|
+
author = ForeignKey(Author)
|
|
117
|
+
|
|
118
|
+
db.create(Author)
|
|
119
|
+
db.create(Book)
|
|
120
|
+
|
|
121
|
+
author = Author(name="Jane", age=30)
|
|
122
|
+
db.save(author)
|
|
123
|
+
db.update(author)
|
|
124
|
+
db.delete(Author, id=1)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Features
|
|
128
|
+
|
|
129
|
+
- WSGI and ASGI compatible
|
|
130
|
+
- Async handler support
|
|
131
|
+
- Parameterized and basic routing
|
|
132
|
+
- Class-based and function-based handlers
|
|
133
|
+
- Built-in SQLite ORM with foreign keys
|
|
134
|
+
- Jinja2 templates
|
|
135
|
+
- Static files via WhiteNoise
|
|
136
|
+
- Middleware pipeline with built-in logging
|
|
137
|
+
- Custom exception handlers
|
|
138
|
+
- Test client (based on Requests)
|
|
139
|
+
- CLI (`creatine runserver`)
|
|
140
|
+
- GitHub Actions CI with pytest and mypy
|
|
141
|
+
|
|
142
|
+
## Tests
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
pytest
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Project Structure
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
creatine/
|
|
152
|
+
├── __init__.py # Package exports and version
|
|
153
|
+
├── __main__.py # CLI entry point
|
|
154
|
+
├── api.py # Core Creatine application class
|
|
155
|
+
├── asgi.py # ASGI adapter
|
|
156
|
+
├── exceptions.py # HTTPError
|
|
157
|
+
├── log.py # Logging middleware
|
|
158
|
+
├── middleware.py # Middleware base class
|
|
159
|
+
├── orm.py # SQLite ORM
|
|
160
|
+
├── response.py # Response wrapper
|
|
161
|
+
├── route.py # Route matching and dispatch
|
|
162
|
+
└── utils.py # Static file and test helpers
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Creatine — A lightweight Python web framework."""
|
|
2
|
+
|
|
3
|
+
from .api import Creatine
|
|
4
|
+
from .exceptions import HTTPError
|
|
5
|
+
from .middleware import Middleware
|
|
6
|
+
from .orm import Database, Table, Column, ForeignKey
|
|
7
|
+
from .response import Response
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
10
|
+
__all__ = [
|
|
11
|
+
"Creatine",
|
|
12
|
+
"HTTPError",
|
|
13
|
+
"Middleware",
|
|
14
|
+
"Database",
|
|
15
|
+
"Table",
|
|
16
|
+
"Column",
|
|
17
|
+
"ForeignKey",
|
|
18
|
+
"Response",
|
|
19
|
+
]
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""CLI entry point for the Creatine framework.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
python -m creatine runserver app:app
|
|
5
|
+
python -m creatine runserver app:app --host 0.0.0.0 --port 5000
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import importlib
|
|
10
|
+
import logging
|
|
11
|
+
import sys
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def import_app(app_path: str) -> Any:
|
|
16
|
+
"""Import an application from a 'module:attribute' path.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
app_path: Import path like 'app:app' or 'myapp.main:application'.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
The imported application object.
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
SystemExit: If the module or attribute cannot be found.
|
|
26
|
+
"""
|
|
27
|
+
module_path, _, attr = app_path.partition(":")
|
|
28
|
+
if not attr:
|
|
29
|
+
attr = "app"
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
module = importlib.import_module(module_path)
|
|
33
|
+
except ImportError as e:
|
|
34
|
+
print(f"Error: Could not import module '{module_path}': {e}")
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
return getattr(module, attr)
|
|
39
|
+
except AttributeError:
|
|
40
|
+
print(f"Error: Module '{module_path}' has no attribute '{attr}'")
|
|
41
|
+
sys.exit(1)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def runserver(args: argparse.Namespace) -> None:
|
|
45
|
+
"""Start the development server using wsgiref."""
|
|
46
|
+
from wsgiref.simple_server import make_server
|
|
47
|
+
|
|
48
|
+
# Configure logging so LoggingMiddleware output is visible
|
|
49
|
+
logging.basicConfig(
|
|
50
|
+
level=logging.INFO,
|
|
51
|
+
format="%(asctime)s [%(name)s] %(message)s",
|
|
52
|
+
datefmt="%H:%M:%S",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
app = import_app(args.app)
|
|
56
|
+
|
|
57
|
+
print(f"\n Creatine dev server")
|
|
58
|
+
print(f" http://{args.host}:{args.port}")
|
|
59
|
+
print(f" Press Ctrl+C to stop.\n")
|
|
60
|
+
|
|
61
|
+
server = make_server(args.host, args.port, app)
|
|
62
|
+
try:
|
|
63
|
+
server.serve_forever()
|
|
64
|
+
except KeyboardInterrupt:
|
|
65
|
+
print("\nServer stopped.")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def main() -> None:
|
|
69
|
+
"""Parse CLI arguments and dispatch to the appropriate command."""
|
|
70
|
+
parser = argparse.ArgumentParser(
|
|
71
|
+
prog="creatine",
|
|
72
|
+
description="Creatine — A Python Web Framework",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
76
|
+
|
|
77
|
+
# runserver command
|
|
78
|
+
server_parser = subparsers.add_parser(
|
|
79
|
+
"runserver", help="Start the development server"
|
|
80
|
+
)
|
|
81
|
+
server_parser.add_argument(
|
|
82
|
+
"app",
|
|
83
|
+
help="Application path (module:attribute), e.g. app:app",
|
|
84
|
+
)
|
|
85
|
+
server_parser.add_argument(
|
|
86
|
+
"--host", default="127.0.0.1", help="Host to bind to (default: 127.0.0.1)"
|
|
87
|
+
)
|
|
88
|
+
server_parser.add_argument(
|
|
89
|
+
"--port", type=int, default=8000, help="Port to bind to (default: 8000)"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
args = parser.parse_args()
|
|
93
|
+
|
|
94
|
+
if args.command == "runserver":
|
|
95
|
+
runserver(args)
|
|
96
|
+
else:
|
|
97
|
+
parser.print_help()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
main()
|