Skip to content

Commit a752964

Browse files
committed
feat/docs: add jinja2 template engine, add middleware (with session cookie middleware), improve request&response, improve docs
1 parent dd9aaac commit a752964

File tree

21 files changed

+630
-77
lines changed

21 files changed

+630
-77
lines changed

README.md

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,22 @@ Welcome to **EchoNext**, where innovation meets simplicity! Are you tired of the
6363

6464
## 🌟 Comparison with Alternatives
6565

66-
| Feature | **pyEchoNext**| Flask | FastAPI | Django | Starlette |
67-
|--------------------------------|---------------|---------------|-------------|----------------|--------------------|
68-
| Asynchronous Capabilities | COMING SOON || ✔️ || ✔️ |
69-
| Performance | 🔥 High | 🐢 Moderate | 🚀 Very High | 🐢 Moderate | 🚀 Very High |
70-
| Framework Weight | ✔️ | ✔️ | ✔️ | ❌ Heavy | ✔️ |
71-
| Ecosystem | 🛠️ Modular | 🎨 Flexible | 🎨 Modular | ⚙️ Monolithic | ⚙️ Modular |
72-
| Ease of Use | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
73-
| Configurability | ✔️ | ✔️ | ✔️ | | ✔️ |
74-
| Documentation Quality | 📚 Excellent | 📚 Good | 📚 Excellent | 📚 Very Good | 📚 Good |
75-
| Flexible Deployments | 🌍 Flexible | 🌍 Standard | 🌍 Standard | 🌍 Standard | 🌍 Flexible |
76-
| Testing Support | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
77-
| Community Size | 📢 Growing | 📢 Large | 📢 Growing | 📢 Large | 📢 Emerging |
78-
| Built-in Template Engine | ✔️ Jinja2 | ✔️ Jinja2 | ✔️ Jinja2 | ✔️ Django | ✔️ Jinja2 |
79-
| Task Queue Integration | ✔️ Celery | ✔️ Celery | ✔️ Celery | ✔️ Celery | ✔️ Celery |
80-
| Static File Serving | 🚀 Built-in | 🌍 Manual | 🚀 Built-in | 🚀 Built-in | 🚀 Built-in |
81-
| Analytics Integration | ✔️ Easy | 🛠️ Manual | ✔️ Easy || ✔️ Easy |
66+
| Feature | **pyEchoNext** | Flask | FastAPI | Django | Starlette |
67+
|---------------------------|---------------------|--------------|--------------|---------------|--------------|
68+
| Asynchronous Capabilities | COMING SOON || ✔️ || ✔️ |
69+
| Performance | 🔥 High | 🐢 Moderate | 🚀 Very High | 🐢 Moderate | 🚀 Very High |
70+
| Framework Weight | ✔️ | ✔️ | ✔️ | ❌ Heavy | ✔️ |
71+
| Ecosystem | 🛠️ Modular | 🎨 Flexible | 🎨 Modular | ⚙️ Monolithic | ⚙️ Modular |
72+
| Ease of Use | ✔️ | ✔️ | ✔️ | | ✔️ |
73+
| Configurability | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
74+
| Documentation Quality | 📚 Excellent | 📚 Good | 📚 Excellent | 📚 Very Good | 📚 Good |
75+
| Flexible Deployments | 🌍 Flexible | 🌍 Standard | 🌍 Standard | 🌍 Standard | 🌍 Flexible |
76+
| Testing Support | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
77+
| Community Size | 📢 Growing | 📢 Large | 📢 Growing | 📢 Large | 📢 Emerging |
78+
| Built-in Template Engine | ✔️ Jinja2 & builtin | ✔️ Jinja2 | ✔️ Jinja2 | ✔️ Django | ✔️ Jinja2 |
79+
| Task Queue Integration | | ✔️ Celery | ✔️ Celery | ✔️ Celery | ✔️ Celery |
80+
| Static File Serving | 🌍 Manual | 🌍 Manual | 🚀 Built-in | 🚀 Built-in | 🚀 Built-in |
81+
| Analytics Integration | ✔️ Easy | 🛠️ Manual | ✔️ Easy || ✔️ Easy |
8282

8383
📈 Note: Echonext excels in performance while staying lightweight, making it a top-notch choice for your next project!
8484

@@ -129,7 +129,9 @@ from pyechonext.app import ApplicationType, EchoNext
129129
from pyechonext.views import View
130130
from pyechonext.urls import URL, IndexView
131131
from pyechonext.config import Settings
132-
from pyechonext.template_engine.builtin import render_template
132+
from pyechonext.template_engine.builtin import render_template # built-in (alpha)
133+
# OR
134+
from pyechonext.template_engine.jinja import render_template
133135

134136

135137
class UsersView(View):
@@ -306,7 +308,7 @@ class IndexView(View):
306308
:param kwargs: The keywords arguments
307309
:type kwargs: dictionary
308310
"""
309-
return Response(body="Hello World!")
311+
return Response(request, body="Hello World!")
310312

311313
def post(self, request: Request, response: Response, **kwargs):
312314
"""
@@ -321,7 +323,7 @@ class IndexView(View):
321323
:param kwargs: The keywords arguments
322324
:type kwargs: dictionary
323325
"""
324-
return Response(body="Message has accepted!")
326+
return Response(request, body="Message has accepted!")
325327
```
326328

327329
## 💬 Support

SECURITY.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ currently being supported with security updates.
77

88
| Version | Supported |
99
| ------- | ------------------ |
10-
| 0.4.1 | :white_check_mark: |
11-
| 0.3.1 | :white_check_mark: |
12-
| 0.3.1 | :white_check_mark: |
13-
| 0.2.1 | :white_check_mark: |
14-
| 0.1.1 | :white_check_mark: |
15-
| 0.1.0 | :x: |
10+
| 0.4.1 | :white_check_mark: |
11+
| 0.3.1 | :white_check_mark: |
12+
| 0.3.1 | :white_check_mark: |
13+
| 0.2.1 | :white_check_mark: |
14+
| 0.1.1 | :white_check_mark: |
15+
| 0.1.0 | :x: |
1616

1717
## Reporting a Vulnerability
1818

docs/ru/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
## Содержание
44

5-
+ [Устройство веб-фреймворка](./webframework_design.md)
6-
+ [Создание веб-приложения](./webapp_creation.md)
5+
1. [Устройство веб-фреймворка](./webframework_design.md)
6+
2. [Создание веб-приложения](./webapp_creation.md)
7+
3. [Создание маршрутов (routes&views)](./routes_and_views.md)
78

89
## Дополнительные материалы
910

docs/ru/routes_and_views.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# pyEchoNext / Создание маршрутов (routes&views)
2+
3+
Маршруты - основа веб приложения.
4+
5+
В pyEchoNext есть два метода создания маршрутов веб-страниц:
6+
7+
+ Django-like: создание наследника класса View, помещение его в датакласс URL и передача в виде аргумента urls в объект класса главного приложения EchoNext
8+
+ Flask-like: создание функций с декоратором EchoNext.route_page.
9+
10+
Пример flask-like:
11+
12+
```python
13+
import os
14+
from pyechonext.app import ApplicationType, EchoNext
15+
from pyechonext.config import Settings
16+
from sqlsymphony_orm.datatypes.fields import IntegerField, RealField, TextField
17+
from sqlsymphony_orm.models.session_models import SessionModel
18+
from sqlsymphony_orm.models.session_models import SQLiteSession
19+
from pyechonext.middleware import middlewares
20+
21+
22+
settings = Settings(
23+
BASE_DIR=os.path.dirname(os.path.abspath(__file__)), TEMPLATES_DIR="templates"
24+
)
25+
echonext = EchoNext(__name__, settings, middlewares, application_type=ApplicationType.HTML)
26+
session = SQLiteSession("echonext.db")
27+
28+
29+
class User(SessionModel):
30+
__tablename__ = "Users"
31+
32+
id = IntegerField(primary_key=True)
33+
name = TextField(null=False)
34+
cash = RealField(null=False, default=0.0)
35+
36+
def __repr__(self):
37+
return f"<User {self.pk}>"
38+
39+
40+
@echonext.route_page("/")
41+
def home(request, response):
42+
user = User(name="John", cash=100.0)
43+
session.add(user)
44+
session.commit()
45+
return "Hello from the HOME page"
46+
47+
48+
@echonext.route_page("/users")
49+
def about(request, response):
50+
users = session.get_all_by_model(User)
51+
52+
return f"Users: {[f'{user.name}: {user.cash}$' for user in users]}"
53+
```
54+
55+
Пример django-like и flask-like:
56+
57+
```python
58+
import os
59+
from pyechonext.utils.exceptions import MethodNotAllow
60+
from pyechonext.app import ApplicationType, EchoNext
61+
from pyechonext.views import View
62+
from pyechonext.urls import URL, IndexView
63+
from pyechonext.config import Settings
64+
from pyechonext.template_engine.jinja import render_template
65+
from pyechonext.middleware import middlewares
66+
67+
68+
class UsersView(View):
69+
def get(self, request, response, **kwargs):
70+
return render_template(
71+
request, "index.html", user_name="User", session_id=request.session_id, friends=["Bob", "Anna", "John"]
72+
)
73+
74+
def post(self, request, response, **kwargs):
75+
raise MethodNotAllow(f'Request {request.path}: method not allow')
76+
77+
78+
url_patterns = [URL(url="/", view=IndexView), URL(url="/users", view=UsersView)]
79+
settings = Settings(
80+
BASE_DIR=os.path.dirname(os.path.abspath(__file__)), TEMPLATES_DIR="templates"
81+
)
82+
echonext = EchoNext(
83+
__name__, settings, middlewares, urls=url_patterns, application_type=ApplicationType.HTML
84+
)
85+
86+
87+
@echonext.route_page("/book")
88+
class BooksResource(View):
89+
def get(self, request, response, **kwargs):
90+
return f"GET Params: {request.GET}"
91+
92+
def post(self, request, response, **kwargs):
93+
return f"POST Params: {request.POST}"
94+
```
95+
96+
Оба метода можно смешивать, но мы рекомендуем использовать только один в одном веб-приложении.
97+
98+
---
99+
100+
[Содержание](./index.md)

docs/ru/webapp_creation.md

Lines changed: 128 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,111 @@
88
```python
99
echonext = Echonext(app_name: str,
1010
settings: Settings,
11+
middlewaries: List[BaseMiddleware]
1112
urls: Optional[List[URL]],
1213
application_type: Optional[ApplicationType])
1314
```
1415

16+
## Settings
17+
Данный аргумент является экземпляром датакласса Settings (pyechonext.config).
18+
19+
```python
20+
@dataclass
21+
class Settings:
22+
"""
23+
This class describes settings.
24+
"""
25+
26+
BASE_DIR: str
27+
TEMPLATES_DIR: str
28+
```
29+
30+
Создайте экземпляр:
31+
32+
```python
33+
settings = Settings(
34+
BASE_DIR=os.path.dirname(os.path.abspath(__file__)), TEMPLATES_DIR="templates"
35+
)
36+
```
37+
38+
BASE_DIR - базовая директория файла приложения, TEMPLATES_DIR - директория html-шаблонов (для встроенного шаблонизатора или Jinja2).
39+
40+
## Middlewares
41+
Middlewares - "промежуточное ПО". Класс BaseMiddleware имеет следующий вид:
42+
43+
```python
44+
class BaseMiddleware(ABC):
45+
"""
46+
This abstract class describes a base middleware.
47+
"""
48+
49+
@abstractmethod
50+
def to_request(self, request: Request):
51+
"""
52+
To request method
53+
54+
:param request: The request
55+
:type request: Request
56+
"""
57+
raise NotImplementedError
58+
59+
@abstractmethod
60+
def to_response(self, response: Response):
61+
"""
62+
To response method
63+
64+
:param response: The response
65+
:type response: Response
66+
"""
67+
raise NotImplementedError
68+
```
69+
70+
Для создания своего Middleware вам нужно создать новый класс на основе этого класса и обязательно реализовать методы to_request и to_response. В pyEchoNext существует базовый Middleware для создания сессий:
71+
72+
```python
73+
class SessionMiddleware(BaseMiddleware):
74+
"""
75+
This class describes a session (cookie) middleware.
76+
"""
77+
78+
def to_request(self, request: Request):
79+
"""
80+
Set to request
81+
82+
:param request: The request
83+
:type request: Request
84+
"""
85+
cookie = request.environ.get('HTTP_COOKIE', None)
86+
87+
if not cookie:
88+
return
89+
90+
session_id = parse_qs(cookie)['session_id'][0]
91+
request.extra['session_id'] = session_id
92+
93+
def to_response(self, response: Response):
94+
"""
95+
Set to response
96+
97+
:param response: The response
98+
:type response: Response
99+
"""
100+
if not response.request.session_id:
101+
response.add_headers([
102+
("Set-Cookie", f'session_id={uuid4()}'),
103+
])
104+
```
105+
106+
Также в pyechonext.middleware есть базовый список `middlewares`, для передачи в аргументы EchoNext:
107+
108+
```python
109+
middlewares = [
110+
SessionMiddleware
111+
]
112+
```
113+
114+
Таким образом вы можете импортирвать его и использовать или дополнить.
115+
15116
## URLS
16117
По умолчанию `urls` равен пустому списку. urls содержит в себе экземпляры датакласса URL (pyechonext.urls):
17118

@@ -123,7 +224,7 @@ class IndexView(View):
123224
:param kwargs: The keywords arguments
124225
:type kwargs: dictionary
125226
"""
126-
return Response(body='Hello World!')
227+
return Response(request, body='Hello World!')
127228

128229
def post(self, request: Request, response: Response, **kwargs) -> Union[Response, Any]:
129230
"""
@@ -138,7 +239,7 @@ class IndexView(View):
138239
:param kwargs: The keywords arguments
139240
:type kwargs: dictionary
140241
"""
141-
return Response(body='Message has accepted!')
242+
return Response(request, body='Message has accepted!')
142243
```
143244

144245
Можно комбинировать эти два способа. По их использованию есть следующие рекомендации:
@@ -152,8 +253,31 @@ class IndexView(View):
152253

153254
Также вместо возвращения результата можно вызывать исключения WebError: URLNotFound и MethodNotAllow. В таком случае приложение не прекратит свою работу, а будет выводить ошибку на стороне веб-страницы. В случае же другого исключения приложение прекратит свою работу.
154255

155-
## Settings
156-
Данный аргумент является экземпляром датакласса Settings (pyechonext.config)
256+
В pyechonext.urls также существует базовый список для передачи его в аргументы EchoNext:
257+
258+
```python
259+
url_patterns = [URL(url="/", view=IndexView)]
260+
```
261+
262+
IndexView здесь - это встроенный View, который вы могли увидеть выше.
263+
264+
## application_type
265+
application_type - тип приложения. Аргумент принимает enum-класс ApplicationType:
266+
267+
```python
268+
class ApplicationType(Enum):
269+
"""
270+
This enum class describes an application type.
271+
"""
272+
273+
JSON = "application/json"
274+
HTML = "text/html"
275+
PLAINTEXT = "text/plain"
276+
```
277+
278+
Пока поддерживается: ApplicationType.JSON, ApplicationType.HTML, ApplicationType.PLAINTEXT.
279+
280+
По умолчанию равен ApplicationType.JSON.
157281

158282
---
159283

docs/ru/webframework_design.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,25 @@ CLIENT <--------------> [HTTP (80) или HTTPS (443)] Сервер
5858

5959
Наконец, следует упомянуть, что текущая версия WSGI не предписывает какой-либо конкретный механизм для «развертывания» приложения для использования с веб-сервером или серверным шлюзом. В настоящее время это обязательно определяется реализацией сервера или шлюза. После того, как достаточное количество серверов и фреймворков внедрит WSGI для обеспечения практического опыта с различными требованиями к развертыванию, может иметь смысл создать еще один PEP, описывающий
6060

61+
## Цели pyEchoNext
62+
pyEchoNext - универсальный инструмент с возможностью сделать монолитное веб-приложение, или наоборот, модульное веб-приложение. Django для нас был слишком большой и неповоротливый, flask или fastapi слишком маленький. Поэтому мы решили взять некоторые фичи из django и flask/fastapi, соединить их и сделать так чтобы все это было в симбиозе. Так, чтобы можно было и сделать большой монолитный проект, так и маленький сервис. И чтобы превратить маленький сервис в большое приложение или наоборот требовалось минимум усилий.
63+
64+
Также нашими целями было сделать все это максимально понятным, дружественным к разработчику и добавить возможности интеграции сторонних библиотек.
65+
66+
В итоге, основная характеристика проекта такая:
67+
68+
1. Цель: Создать универсальный многогранный веб-фреймворк на python
69+
2. Задачи:
70+
+ Найти хорошие и плохие стороны Flask, FastAPI
71+
+ Найти хорошие и плохие стороны Django
72+
+ Сравнить возможности существующих фреймворков
73+
+ Выбор лучших фич
74+
+ Симбиоз фич в одно целое
75+
+ Построить код проекта согласно SOLID и принципам ООП, легко расширяемым, масштабируемым и дополняемым.
76+
+ Сделать код быстрым и производительным, дать свободу пользователю и разработчику
77+
3. Проблема: на данный момент очень мало универсальных фреймворков, дающих создать как и большое монолитное приложение, так и быстрый маленький сервис.
78+
4. Актуальность: веб-сфера в данное время очень сильно популярна, умение работать с веб-фреймворками, абстракциями, знать устройство сайтов поможет всем.
79+
6180
---
6281

6382
[Содержание](./index.md)

0 commit comments

Comments
 (0)