py-flexo 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.
@@ -0,0 +1,391 @@
1
+ Metadata-Version: 2.4
2
+ Name: py-flexo
3
+ Version: 0.1.0
4
+ Summary: Python Web Framework built for learning purposes
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: gunicorn>=26.0.0
8
+ Requires-Dist: jinja2>=3.1.6
9
+ Requires-Dist: parse>=1.22.1
10
+ Requires-Dist: requests-wsgi-adapter>=0.4.1
11
+ Requires-Dist: webob>=1.8.10
12
+ Requires-Dist: whitenoise>=6.12.0
13
+
14
+ # PyFlexo
15
+
16
+ <p align="center">
17
+ A modern, lightweight and extensible WSGI web framework for Python.
18
+ </p>
19
+
20
+ <p align="center">
21
+
22
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
23
+ ![License](https://img.shields.io/badge/license-MIT-green)
24
+ ![Tests](https://img.shields.io/badge/tests-passing-success)
25
+ ![Version](https://img.shields.io/badge/version-0.1.0-orange)
26
+
27
+ </p>
28
+
29
+ ---
30
+
31
+ ## Why PyFlexo?
32
+
33
+ PyFlexo is a lightweight WSGI web framework focused on simplicity, readability, and extensibility.
34
+
35
+ Instead of hiding how web applications work, PyFlexo provides a clean API while remaining close to the WSGI specification. It is suitable for learning, small services, REST APIs, and custom web applications.
36
+
37
+ ## Features
38
+
39
+ * Simple and intuitive routing
40
+ * Function-based views
41
+ * Class-based views
42
+ * Dynamic URL parameters
43
+ * Built-in template rendering (Jinja2)
44
+ * Static file serving
45
+ * JSON response helper
46
+ * Global exception handlers
47
+ * Middleware support
48
+ * Pure Python implementation
49
+ * WSGI compatible
50
+ * Easy to extend
51
+
52
+ ---
53
+
54
+ # Installation
55
+
56
+ Using pip
57
+
58
+ ```bash
59
+ pip install py_flexo
60
+ ```
61
+
62
+ Using uv
63
+
64
+ ```bash
65
+ uv add py_flexo
66
+ ```
67
+
68
+ ---
69
+
70
+ # Quick Start
71
+ main.py
72
+ ```python
73
+ from py_flexo.app import PyFlexoApp
74
+
75
+ app = PyFlexoApp()
76
+
77
+
78
+ @app.route("/")
79
+ def home(request, response):
80
+ response.text = "Hello, PyFlexo!"
81
+ ```
82
+
83
+ Run your application with any WSGI server.
84
+
85
+ Example:
86
+
87
+ ```bash
88
+ gunicorn main:app
89
+ ```
90
+
91
+ ---
92
+
93
+ # Routing
94
+
95
+ ## Function Based View
96
+
97
+ ```python
98
+ @app.route("/")
99
+ def index(request, response):
100
+ response.text = "Hello World"
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Route Parameters
106
+
107
+ ```python
108
+ @app.route("/hello/{name}")
109
+ def hello(request, response, name):
110
+ response.text = f"Hello {name}"
111
+ ```
112
+
113
+ Example
114
+
115
+ ```
116
+ GET /hello/Alice
117
+ ```
118
+
119
+ Response
120
+
121
+ ```
122
+ Hello Alice
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Class Based Views
128
+
129
+ ```python
130
+ @app.route("/books")
131
+ class Book:
132
+
133
+ def get(self, request, response):
134
+ response.text = "Book List"
135
+
136
+ def post(self, request, response):
137
+ response.text = "Create Book"
138
+ ```
139
+
140
+ Supported methods
141
+
142
+ * GET
143
+ * POST
144
+ * PUT
145
+ * PATCH
146
+ * DELETE
147
+
148
+ ---
149
+
150
+ # Templates
151
+
152
+ Directory
153
+
154
+ ```
155
+ project/
156
+
157
+ templates/
158
+ home.html
159
+ ```
160
+
161
+ Route
162
+
163
+ ```python
164
+ @app.route("/home")
165
+ def home(request, response):
166
+ response.html = app.template(
167
+ "home.html",
168
+ context={
169
+ "title": "PyFlexo",
170
+ "header": "Welcome"
171
+ }
172
+ )
173
+ ```
174
+
175
+ Template
176
+
177
+ ```html
178
+ <!DOCTYPE html>
179
+ <html>
180
+ <head>
181
+ <title>{{ title }}</title>
182
+ </head>
183
+
184
+ <body>
185
+
186
+ <h1>{{ header }}</h1>
187
+
188
+ </body>
189
+ </html>
190
+ ```
191
+
192
+ ---
193
+
194
+ # JSON Responses
195
+
196
+ ```python
197
+ @app.route("/api")
198
+ def api(request, response):
199
+
200
+ response.json = {
201
+ "framework": "PyFlexo",
202
+ "version": "0.1.0"
203
+ }
204
+ ```
205
+
206
+ Output
207
+
208
+ ```json
209
+ {
210
+ "framework": "PyFlexo",
211
+ "version": "0.1.0"
212
+ }
213
+ ```
214
+
215
+ ---
216
+
217
+ # Middleware
218
+
219
+ ```python
220
+ from py_flexo.middleware import Middleware
221
+
222
+
223
+ class LoggingMiddleware(Middleware):
224
+
225
+ def process_request(self, request):
226
+ print(request.method, request.path)
227
+
228
+ def process_response(self, response):
229
+ print(response.status_code)
230
+
231
+
232
+ app.add_middleware(LoggingMiddleware)
233
+ ```
234
+
235
+ ---
236
+
237
+ # Exception Handling
238
+
239
+ ```python
240
+ def exception_handler(request, response, exception):
241
+
242
+ response.status_code = 500
243
+ response.text = "Internal Server Error"
244
+
245
+
246
+ app.add_exception_handler(exception_handler)
247
+ ```
248
+
249
+ ---
250
+
251
+ # Static Files
252
+
253
+ Directory
254
+
255
+ ```
256
+ project/
257
+
258
+ static/
259
+
260
+ style.css
261
+ app.js
262
+ logo.png
263
+ ```
264
+
265
+ Static files are automatically available under
266
+
267
+ ```
268
+ /static/
269
+ ```
270
+
271
+ Example
272
+
273
+ ```
274
+ /static/style.css
275
+ ```
276
+
277
+ ---
278
+
279
+ # Project Structure
280
+
281
+ ```
282
+ project/
283
+
284
+
285
+
286
+ ├── main.py
287
+
288
+ ├── templates/
289
+
290
+ │ └── home.html
291
+
292
+
293
+
294
+ ├── static/
295
+
296
+ │ ├── style.css
297
+
298
+ │ └── app.js
299
+
300
+
301
+
302
+ └── pyproject.toml
303
+ ```
304
+
305
+ ---
306
+
307
+ # Complete Example
308
+
309
+ ```python
310
+ from py_flexo.app import PyFlexoApp
311
+ from py_flexo.middleware import Middleware
312
+
313
+ app = PyFlexoApp()
314
+
315
+
316
+ @app.route("/")
317
+ def index(request, response):
318
+ response.text = "Welcome to PyFlexo"
319
+
320
+
321
+ @app.route("/hello/{name}")
322
+ def hello(request, response, name):
323
+ response.text = f"Hello {name}"
324
+
325
+
326
+ @app.route("/books")
327
+ class Book:
328
+
329
+ def get(self, request, response):
330
+ response.text = "Book List"
331
+
332
+
333
+ @app.route("/home")
334
+ def home(request, response):
335
+ response.html = app.template(
336
+ "home.html",
337
+ context={
338
+ "title": "PyFlexo",
339
+ "header": "Welcome"
340
+ }
341
+ )
342
+
343
+
344
+ @app.route("/api")
345
+ def api(request, response):
346
+ response.json = {
347
+ "message": "Hello JSON"
348
+ }
349
+
350
+
351
+ class LoggingMiddleware(Middleware):
352
+
353
+ def process_request(self, request):
354
+ print(request.path)
355
+
356
+ def process_response(self, response):
357
+ print(response.status_code)
358
+
359
+
360
+ app.add_middleware(LoggingMiddleware)
361
+ ```
362
+
363
+ ---
364
+
365
+ # Roadmap
366
+
367
+ * Cookies
368
+ * Sessions
369
+ * Authentication
370
+ * Blueprint support
371
+ * Request validation
372
+ * CLI
373
+ * Dependency Injection
374
+ * OpenAPI
375
+ * ASGI support
376
+ * WebSocket support
377
+
378
+ ---
379
+
380
+
381
+ # Contributing
382
+
383
+ Contributions are welcome.
384
+
385
+ Please open an issue before submitting large changes.
386
+
387
+ ---
388
+
389
+ # Author
390
+
391
+ PyFlexo is an open-source project created for developers who enjoy building fast and elegant Python web applications.
@@ -0,0 +1,378 @@
1
+ # PyFlexo
2
+
3
+ <p align="center">
4
+ A modern, lightweight and extensible WSGI web framework for Python.
5
+ </p>
6
+
7
+ <p align="center">
8
+
9
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
10
+ ![License](https://img.shields.io/badge/license-MIT-green)
11
+ ![Tests](https://img.shields.io/badge/tests-passing-success)
12
+ ![Version](https://img.shields.io/badge/version-0.1.0-orange)
13
+
14
+ </p>
15
+
16
+ ---
17
+
18
+ ## Why PyFlexo?
19
+
20
+ PyFlexo is a lightweight WSGI web framework focused on simplicity, readability, and extensibility.
21
+
22
+ Instead of hiding how web applications work, PyFlexo provides a clean API while remaining close to the WSGI specification. It is suitable for learning, small services, REST APIs, and custom web applications.
23
+
24
+ ## Features
25
+
26
+ * Simple and intuitive routing
27
+ * Function-based views
28
+ * Class-based views
29
+ * Dynamic URL parameters
30
+ * Built-in template rendering (Jinja2)
31
+ * Static file serving
32
+ * JSON response helper
33
+ * Global exception handlers
34
+ * Middleware support
35
+ * Pure Python implementation
36
+ * WSGI compatible
37
+ * Easy to extend
38
+
39
+ ---
40
+
41
+ # Installation
42
+
43
+ Using pip
44
+
45
+ ```bash
46
+ pip install py_flexo
47
+ ```
48
+
49
+ Using uv
50
+
51
+ ```bash
52
+ uv add py_flexo
53
+ ```
54
+
55
+ ---
56
+
57
+ # Quick Start
58
+ main.py
59
+ ```python
60
+ from py_flexo.app import PyFlexoApp
61
+
62
+ app = PyFlexoApp()
63
+
64
+
65
+ @app.route("/")
66
+ def home(request, response):
67
+ response.text = "Hello, PyFlexo!"
68
+ ```
69
+
70
+ Run your application with any WSGI server.
71
+
72
+ Example:
73
+
74
+ ```bash
75
+ gunicorn main:app
76
+ ```
77
+
78
+ ---
79
+
80
+ # Routing
81
+
82
+ ## Function Based View
83
+
84
+ ```python
85
+ @app.route("/")
86
+ def index(request, response):
87
+ response.text = "Hello World"
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Route Parameters
93
+
94
+ ```python
95
+ @app.route("/hello/{name}")
96
+ def hello(request, response, name):
97
+ response.text = f"Hello {name}"
98
+ ```
99
+
100
+ Example
101
+
102
+ ```
103
+ GET /hello/Alice
104
+ ```
105
+
106
+ Response
107
+
108
+ ```
109
+ Hello Alice
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Class Based Views
115
+
116
+ ```python
117
+ @app.route("/books")
118
+ class Book:
119
+
120
+ def get(self, request, response):
121
+ response.text = "Book List"
122
+
123
+ def post(self, request, response):
124
+ response.text = "Create Book"
125
+ ```
126
+
127
+ Supported methods
128
+
129
+ * GET
130
+ * POST
131
+ * PUT
132
+ * PATCH
133
+ * DELETE
134
+
135
+ ---
136
+
137
+ # Templates
138
+
139
+ Directory
140
+
141
+ ```
142
+ project/
143
+
144
+ templates/
145
+ home.html
146
+ ```
147
+
148
+ Route
149
+
150
+ ```python
151
+ @app.route("/home")
152
+ def home(request, response):
153
+ response.html = app.template(
154
+ "home.html",
155
+ context={
156
+ "title": "PyFlexo",
157
+ "header": "Welcome"
158
+ }
159
+ )
160
+ ```
161
+
162
+ Template
163
+
164
+ ```html
165
+ <!DOCTYPE html>
166
+ <html>
167
+ <head>
168
+ <title>{{ title }}</title>
169
+ </head>
170
+
171
+ <body>
172
+
173
+ <h1>{{ header }}</h1>
174
+
175
+ </body>
176
+ </html>
177
+ ```
178
+
179
+ ---
180
+
181
+ # JSON Responses
182
+
183
+ ```python
184
+ @app.route("/api")
185
+ def api(request, response):
186
+
187
+ response.json = {
188
+ "framework": "PyFlexo",
189
+ "version": "0.1.0"
190
+ }
191
+ ```
192
+
193
+ Output
194
+
195
+ ```json
196
+ {
197
+ "framework": "PyFlexo",
198
+ "version": "0.1.0"
199
+ }
200
+ ```
201
+
202
+ ---
203
+
204
+ # Middleware
205
+
206
+ ```python
207
+ from py_flexo.middleware import Middleware
208
+
209
+
210
+ class LoggingMiddleware(Middleware):
211
+
212
+ def process_request(self, request):
213
+ print(request.method, request.path)
214
+
215
+ def process_response(self, response):
216
+ print(response.status_code)
217
+
218
+
219
+ app.add_middleware(LoggingMiddleware)
220
+ ```
221
+
222
+ ---
223
+
224
+ # Exception Handling
225
+
226
+ ```python
227
+ def exception_handler(request, response, exception):
228
+
229
+ response.status_code = 500
230
+ response.text = "Internal Server Error"
231
+
232
+
233
+ app.add_exception_handler(exception_handler)
234
+ ```
235
+
236
+ ---
237
+
238
+ # Static Files
239
+
240
+ Directory
241
+
242
+ ```
243
+ project/
244
+
245
+ static/
246
+
247
+ style.css
248
+ app.js
249
+ logo.png
250
+ ```
251
+
252
+ Static files are automatically available under
253
+
254
+ ```
255
+ /static/
256
+ ```
257
+
258
+ Example
259
+
260
+ ```
261
+ /static/style.css
262
+ ```
263
+
264
+ ---
265
+
266
+ # Project Structure
267
+
268
+ ```
269
+ project/
270
+
271
+
272
+
273
+ ├── main.py
274
+
275
+ ├── templates/
276
+
277
+ │ └── home.html
278
+
279
+
280
+
281
+ ├── static/
282
+
283
+ │ ├── style.css
284
+
285
+ │ └── app.js
286
+
287
+
288
+
289
+ └── pyproject.toml
290
+ ```
291
+
292
+ ---
293
+
294
+ # Complete Example
295
+
296
+ ```python
297
+ from py_flexo.app import PyFlexoApp
298
+ from py_flexo.middleware import Middleware
299
+
300
+ app = PyFlexoApp()
301
+
302
+
303
+ @app.route("/")
304
+ def index(request, response):
305
+ response.text = "Welcome to PyFlexo"
306
+
307
+
308
+ @app.route("/hello/{name}")
309
+ def hello(request, response, name):
310
+ response.text = f"Hello {name}"
311
+
312
+
313
+ @app.route("/books")
314
+ class Book:
315
+
316
+ def get(self, request, response):
317
+ response.text = "Book List"
318
+
319
+
320
+ @app.route("/home")
321
+ def home(request, response):
322
+ response.html = app.template(
323
+ "home.html",
324
+ context={
325
+ "title": "PyFlexo",
326
+ "header": "Welcome"
327
+ }
328
+ )
329
+
330
+
331
+ @app.route("/api")
332
+ def api(request, response):
333
+ response.json = {
334
+ "message": "Hello JSON"
335
+ }
336
+
337
+
338
+ class LoggingMiddleware(Middleware):
339
+
340
+ def process_request(self, request):
341
+ print(request.path)
342
+
343
+ def process_response(self, response):
344
+ print(response.status_code)
345
+
346
+
347
+ app.add_middleware(LoggingMiddleware)
348
+ ```
349
+
350
+ ---
351
+
352
+ # Roadmap
353
+
354
+ * Cookies
355
+ * Sessions
356
+ * Authentication
357
+ * Blueprint support
358
+ * Request validation
359
+ * CLI
360
+ * Dependency Injection
361
+ * OpenAPI
362
+ * ASGI support
363
+ * WebSocket support
364
+
365
+ ---
366
+
367
+
368
+ # Contributing
369
+
370
+ Contributions are welcome.
371
+
372
+ Please open an issue before submitting large changes.
373
+
374
+ ---
375
+
376
+ # Author
377
+
378
+ PyFlexo is an open-source project created for developers who enjoy building fast and elegant Python web applications.
File without changes
@@ -0,0 +1,111 @@
1
+ from webob import Request
2
+ from .response import Response
3
+ from parse import parse
4
+ import requests
5
+ import wsgiadapter
6
+ import inspect
7
+ from jinja2 import Environment, FileSystemLoader
8
+ import os
9
+ from whitenoise import WhiteNoise
10
+ from .middleware import Middleware
11
+
12
+
13
+ class PyFlexoApp:
14
+ def __init__(self, templates_dir="templates", static_dir = "static"):
15
+ self._routes = {}
16
+ self.template_env = Environment(
17
+ loader = FileSystemLoader(os.path.abspath(templates_dir))
18
+ )
19
+ self.exception_handler = None
20
+
21
+ self.whitenoise = WhiteNoise(self.wsgi_app, root=static_dir, prefix='/static')
22
+ self.middleware = Middleware(self)
23
+
24
+ def __call__(self, environ, start_response):
25
+ path_info = environ["PATH_INFO"]
26
+ if path_info.startswith('/static'):
27
+ return self.whitenoise(environ, start_response)
28
+ return self.middleware(environ, start_response)
29
+
30
+ def wsgi_app(self, environ, start_response):
31
+ request = Request(environ)
32
+ response = self.handle_request(request)
33
+ return response(environ, start_response)
34
+
35
+ def handle_request(self, request):
36
+ response = Response()
37
+
38
+ handler_data, kwargs = self.find_handler(request.path)
39
+
40
+ if handler_data:
41
+ handler = handler_data["handler"]
42
+ allow_methods = handler_data["allow_methods"]
43
+ if inspect.isclass(handler):
44
+ handler = getattr(handler(), request.method.lower(), None)
45
+ if handler:
46
+ handler(request, response, **kwargs)
47
+ else:
48
+ self.method_not_allowed_response(response)
49
+ else:
50
+ if request.method.lower() not in allow_methods:
51
+ self.method_not_allowed_response(response)
52
+ try:
53
+ handler(request, response, **kwargs)
54
+ except Exception as e:
55
+ if self.exception_handler is not None:
56
+ self.exception_handler(request, response, e)
57
+ else:
58
+ raise e
59
+ else:
60
+ self.default_response(response)
61
+ return response
62
+
63
+ def find_handler(self, path):
64
+ for route, handler_data in self._routes.items():
65
+ result = parse(route, path)
66
+ if result:
67
+ return handler_data, result.named
68
+ if route == path:
69
+ return handler_data, None
70
+ return None, None
71
+
72
+ def default_response(self, response):
73
+ response.status_code = 404
74
+ response.text = 'Not Found'
75
+ return response
76
+
77
+ def method_not_allowed_response(self, res):
78
+ res.status_code = 405
79
+ res.text = 'Method Not Allowed'
80
+ return res
81
+
82
+ def add_route(self, path, handler, allow_methods = None):
83
+ assert path not in self._routes, "Duplicate url. Please change the URL"
84
+
85
+ if allow_methods is None:
86
+ allow_methods = ["get", "post", "put", "path", "head", "options", "delete"]
87
+
88
+ self._routes[path] = {"handler":handler, "allow_methods": allow_methods}
89
+
90
+ def route(self, path, allow_methods = None):
91
+ def decorator(handler):
92
+ self.add_route(path, handler, allow_methods)
93
+ return handler
94
+ return decorator
95
+
96
+
97
+ def test_session(self):
98
+ session = requests.Session()
99
+ session.mount('http://testserver', wsgiadapter.WSGIAdapter(self))
100
+ return session
101
+
102
+ def template(self, template_name, context = None):
103
+ if context is None:
104
+ context = {}
105
+ return self.template_env.get_template(template_name).render(**context).encode()
106
+
107
+ def add_exception_handler(self, handler):
108
+ self.exception_handler = handler
109
+
110
+ def add_middleware(self, middleware_cls):
111
+ self.middleware.add(middleware_cls)
@@ -0,0 +1,26 @@
1
+ from webob import Request
2
+
3
+ class Middleware:
4
+ def __init__(self, app):
5
+ self.app = app
6
+
7
+ def add(self, middleware_cls):
8
+ self.app = middleware_cls(self.app)
9
+
10
+ def process_request(self, req):
11
+ pass
12
+
13
+ def process_response(self, resp):
14
+ pass
15
+
16
+ def handle_request(self, request):
17
+ self.process_request(request)
18
+ response = self.app.handle_request(request)
19
+ self.process_response(response)
20
+
21
+ return response
22
+
23
+ def __call__(self, environ, start_response):
24
+ request = Request(environ)
25
+ response = self.app.handle_request(request)
26
+ return response(environ, start_response)
@@ -0,0 +1,35 @@
1
+ from webob import Response as WebResponse
2
+ import json
3
+
4
+ class Response:
5
+ def __init__(self):
6
+ self.json = None
7
+ self.html = None
8
+ self.text = None
9
+ self.content_type = None
10
+ self.body = b''
11
+ self.status_code = 200
12
+
13
+ def set_body_and_content_type(self):
14
+ if self.json:
15
+ self.body = json.dumps(self.json).encode()
16
+ self.content_type = "application/json"
17
+
18
+ if self.html:
19
+ self.body = self.html.encode()
20
+ self.content_type = "text/html"
21
+
22
+ if self.text:
23
+ self.body = self.text
24
+ self.content_type = "text/plain"
25
+
26
+
27
+ def __call__(self, environ, start_response):
28
+ self.set_body_and_content_type()
29
+ response = WebResponse(
30
+ body = self.body,
31
+ content_type=self.content_type,
32
+ status = self.status_code
33
+ )
34
+
35
+ return response(environ, start_response)
@@ -0,0 +1,391 @@
1
+ Metadata-Version: 2.4
2
+ Name: py-flexo
3
+ Version: 0.1.0
4
+ Summary: Python Web Framework built for learning purposes
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: gunicorn>=26.0.0
8
+ Requires-Dist: jinja2>=3.1.6
9
+ Requires-Dist: parse>=1.22.1
10
+ Requires-Dist: requests-wsgi-adapter>=0.4.1
11
+ Requires-Dist: webob>=1.8.10
12
+ Requires-Dist: whitenoise>=6.12.0
13
+
14
+ # PyFlexo
15
+
16
+ <p align="center">
17
+ A modern, lightweight and extensible WSGI web framework for Python.
18
+ </p>
19
+
20
+ <p align="center">
21
+
22
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
23
+ ![License](https://img.shields.io/badge/license-MIT-green)
24
+ ![Tests](https://img.shields.io/badge/tests-passing-success)
25
+ ![Version](https://img.shields.io/badge/version-0.1.0-orange)
26
+
27
+ </p>
28
+
29
+ ---
30
+
31
+ ## Why PyFlexo?
32
+
33
+ PyFlexo is a lightweight WSGI web framework focused on simplicity, readability, and extensibility.
34
+
35
+ Instead of hiding how web applications work, PyFlexo provides a clean API while remaining close to the WSGI specification. It is suitable for learning, small services, REST APIs, and custom web applications.
36
+
37
+ ## Features
38
+
39
+ * Simple and intuitive routing
40
+ * Function-based views
41
+ * Class-based views
42
+ * Dynamic URL parameters
43
+ * Built-in template rendering (Jinja2)
44
+ * Static file serving
45
+ * JSON response helper
46
+ * Global exception handlers
47
+ * Middleware support
48
+ * Pure Python implementation
49
+ * WSGI compatible
50
+ * Easy to extend
51
+
52
+ ---
53
+
54
+ # Installation
55
+
56
+ Using pip
57
+
58
+ ```bash
59
+ pip install py_flexo
60
+ ```
61
+
62
+ Using uv
63
+
64
+ ```bash
65
+ uv add py_flexo
66
+ ```
67
+
68
+ ---
69
+
70
+ # Quick Start
71
+ main.py
72
+ ```python
73
+ from py_flexo.app import PyFlexoApp
74
+
75
+ app = PyFlexoApp()
76
+
77
+
78
+ @app.route("/")
79
+ def home(request, response):
80
+ response.text = "Hello, PyFlexo!"
81
+ ```
82
+
83
+ Run your application with any WSGI server.
84
+
85
+ Example:
86
+
87
+ ```bash
88
+ gunicorn main:app
89
+ ```
90
+
91
+ ---
92
+
93
+ # Routing
94
+
95
+ ## Function Based View
96
+
97
+ ```python
98
+ @app.route("/")
99
+ def index(request, response):
100
+ response.text = "Hello World"
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Route Parameters
106
+
107
+ ```python
108
+ @app.route("/hello/{name}")
109
+ def hello(request, response, name):
110
+ response.text = f"Hello {name}"
111
+ ```
112
+
113
+ Example
114
+
115
+ ```
116
+ GET /hello/Alice
117
+ ```
118
+
119
+ Response
120
+
121
+ ```
122
+ Hello Alice
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Class Based Views
128
+
129
+ ```python
130
+ @app.route("/books")
131
+ class Book:
132
+
133
+ def get(self, request, response):
134
+ response.text = "Book List"
135
+
136
+ def post(self, request, response):
137
+ response.text = "Create Book"
138
+ ```
139
+
140
+ Supported methods
141
+
142
+ * GET
143
+ * POST
144
+ * PUT
145
+ * PATCH
146
+ * DELETE
147
+
148
+ ---
149
+
150
+ # Templates
151
+
152
+ Directory
153
+
154
+ ```
155
+ project/
156
+
157
+ templates/
158
+ home.html
159
+ ```
160
+
161
+ Route
162
+
163
+ ```python
164
+ @app.route("/home")
165
+ def home(request, response):
166
+ response.html = app.template(
167
+ "home.html",
168
+ context={
169
+ "title": "PyFlexo",
170
+ "header": "Welcome"
171
+ }
172
+ )
173
+ ```
174
+
175
+ Template
176
+
177
+ ```html
178
+ <!DOCTYPE html>
179
+ <html>
180
+ <head>
181
+ <title>{{ title }}</title>
182
+ </head>
183
+
184
+ <body>
185
+
186
+ <h1>{{ header }}</h1>
187
+
188
+ </body>
189
+ </html>
190
+ ```
191
+
192
+ ---
193
+
194
+ # JSON Responses
195
+
196
+ ```python
197
+ @app.route("/api")
198
+ def api(request, response):
199
+
200
+ response.json = {
201
+ "framework": "PyFlexo",
202
+ "version": "0.1.0"
203
+ }
204
+ ```
205
+
206
+ Output
207
+
208
+ ```json
209
+ {
210
+ "framework": "PyFlexo",
211
+ "version": "0.1.0"
212
+ }
213
+ ```
214
+
215
+ ---
216
+
217
+ # Middleware
218
+
219
+ ```python
220
+ from py_flexo.middleware import Middleware
221
+
222
+
223
+ class LoggingMiddleware(Middleware):
224
+
225
+ def process_request(self, request):
226
+ print(request.method, request.path)
227
+
228
+ def process_response(self, response):
229
+ print(response.status_code)
230
+
231
+
232
+ app.add_middleware(LoggingMiddleware)
233
+ ```
234
+
235
+ ---
236
+
237
+ # Exception Handling
238
+
239
+ ```python
240
+ def exception_handler(request, response, exception):
241
+
242
+ response.status_code = 500
243
+ response.text = "Internal Server Error"
244
+
245
+
246
+ app.add_exception_handler(exception_handler)
247
+ ```
248
+
249
+ ---
250
+
251
+ # Static Files
252
+
253
+ Directory
254
+
255
+ ```
256
+ project/
257
+
258
+ static/
259
+
260
+ style.css
261
+ app.js
262
+ logo.png
263
+ ```
264
+
265
+ Static files are automatically available under
266
+
267
+ ```
268
+ /static/
269
+ ```
270
+
271
+ Example
272
+
273
+ ```
274
+ /static/style.css
275
+ ```
276
+
277
+ ---
278
+
279
+ # Project Structure
280
+
281
+ ```
282
+ project/
283
+
284
+
285
+
286
+ ├── main.py
287
+
288
+ ├── templates/
289
+
290
+ │ └── home.html
291
+
292
+
293
+
294
+ ├── static/
295
+
296
+ │ ├── style.css
297
+
298
+ │ └── app.js
299
+
300
+
301
+
302
+ └── pyproject.toml
303
+ ```
304
+
305
+ ---
306
+
307
+ # Complete Example
308
+
309
+ ```python
310
+ from py_flexo.app import PyFlexoApp
311
+ from py_flexo.middleware import Middleware
312
+
313
+ app = PyFlexoApp()
314
+
315
+
316
+ @app.route("/")
317
+ def index(request, response):
318
+ response.text = "Welcome to PyFlexo"
319
+
320
+
321
+ @app.route("/hello/{name}")
322
+ def hello(request, response, name):
323
+ response.text = f"Hello {name}"
324
+
325
+
326
+ @app.route("/books")
327
+ class Book:
328
+
329
+ def get(self, request, response):
330
+ response.text = "Book List"
331
+
332
+
333
+ @app.route("/home")
334
+ def home(request, response):
335
+ response.html = app.template(
336
+ "home.html",
337
+ context={
338
+ "title": "PyFlexo",
339
+ "header": "Welcome"
340
+ }
341
+ )
342
+
343
+
344
+ @app.route("/api")
345
+ def api(request, response):
346
+ response.json = {
347
+ "message": "Hello JSON"
348
+ }
349
+
350
+
351
+ class LoggingMiddleware(Middleware):
352
+
353
+ def process_request(self, request):
354
+ print(request.path)
355
+
356
+ def process_response(self, response):
357
+ print(response.status_code)
358
+
359
+
360
+ app.add_middleware(LoggingMiddleware)
361
+ ```
362
+
363
+ ---
364
+
365
+ # Roadmap
366
+
367
+ * Cookies
368
+ * Sessions
369
+ * Authentication
370
+ * Blueprint support
371
+ * Request validation
372
+ * CLI
373
+ * Dependency Injection
374
+ * OpenAPI
375
+ * ASGI support
376
+ * WebSocket support
377
+
378
+ ---
379
+
380
+
381
+ # Contributing
382
+
383
+ Contributions are welcome.
384
+
385
+ Please open an issue before submitting large changes.
386
+
387
+ ---
388
+
389
+ # Author
390
+
391
+ PyFlexo is an open-source project created for developers who enjoy building fast and elegant Python web applications.
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ py_flexo/__init__.py
4
+ py_flexo/app.py
5
+ py_flexo/middleware.py
6
+ py_flexo/response.py
7
+ py_flexo.egg-info/PKG-INFO
8
+ py_flexo.egg-info/SOURCES.txt
9
+ py_flexo.egg-info/dependency_links.txt
10
+ py_flexo.egg-info/requires.txt
11
+ py_flexo.egg-info/top_level.txt
@@ -0,0 +1,6 @@
1
+ gunicorn>=26.0.0
2
+ jinja2>=3.1.6
3
+ parse>=1.22.1
4
+ requests-wsgi-adapter>=0.4.1
5
+ webob>=1.8.10
6
+ whitenoise>=6.12.0
@@ -0,0 +1 @@
1
+ py_flexo
@@ -0,0 +1,32 @@
1
+ [project]
2
+ name = "py-flexo"
3
+ version = "0.1.0"
4
+ description = "Python Web Framework built for learning purposes"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "gunicorn>=26.0.0",
9
+ "jinja2>=3.1.6",
10
+ "parse>=1.22.1",
11
+ "requests-wsgi-adapter>=0.4.1",
12
+ "webob>=1.8.10",
13
+ "whitenoise>=6.12.0"
14
+ ]
15
+
16
+ [dependency-groups]
17
+ dev = [
18
+ "pytest>=9.1.1",
19
+ "twine>=6.2.0",
20
+ "wheel>=0.47.0"
21
+ ]
22
+
23
+ [tool.setuptools]
24
+ include-package-data = true
25
+
26
+ [tool.setuptools.packages.find]
27
+ include = ["py_flexo*"]
28
+ exclude = ["static*", "templates*", "tests*"]
29
+
30
+ [build-system]
31
+ requires = ["setuptools>=68", "wheel"]
32
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+