Skip to content

Commit 549a9c8

Browse files
committed
feat: add basic project architecture and basic app
1 parent b2e8f9c commit 549a9c8

27 files changed

+711
-2
lines changed

README.md

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,58 @@
1-
# pyEchoNext
2-
EchoNext is a lightweight, fast and scalable async web framework for Python
1+
# EchoNext
2+
<a id="readme-top"></a>
3+
4+
<div align="center">
5+
<p align="center">
6+
EchoNext is a lightweight, fast and scalable web framework for Python
7+
<br />
8+
<a href="https://alexeev-prog.github.io/pyEchoNext/"><strong>Explore the docs »</strong></a>
9+
<br />
10+
<br />
11+
<a href="#-comparison-with-alternatives">Comparison with Alternatives</a>
12+
.
13+
<a href="#-why-choose-pyechonext">Why Choose pyEchoNext</a>
14+
·
15+
<a href="#-key-features">Key Features</a>
16+
·
17+
<a href="#-getting-started">Getting Started</a>
18+
·
19+
<a href="#-usage-examples">Basic Usage</a>
20+
·
21+
<a href="#-specifications">Specification</a>
22+
·
23+
<a href="https://alexeev-prog.github.io/pyEchoNext/">Documentation</a>
24+
·
25+
<a href="https://github.com/alexeev-prog/pyEchoNext/blob/main/LICENSE">License</a>
26+
</p>
27+
</div>
28+
<br>
29+
<p align="center">
30+
<img src="https://img.shields.io/github/languages/top/alexeev-prog/pyEchoNext?style=for-the-badge">
31+
<img src="https://img.shields.io/github/languages/count/alexeev-prog/pyEchoNext?style=for-the-badge">
32+
<img src="https://img.shields.io/github/license/alexeev-prog/pyEchoNext?style=for-the-badge">
33+
<img src="https://img.shields.io/github/stars/alexeev-prog/pyEchoNext?style=for-the-badge">
34+
<img src="https://img.shields.io/github/issues/alexeev-prog/pyEchoNext?style=for-the-badge">
35+
<img src="https://img.shields.io/github/last-commit/alexeev-prog/pyEchoNext?style=for-the-badge">
36+
</p>
37+
38+
> EchoNext is a lightweight, fast and scalable web framework for Python
39+
40+
---
41+
42+
EchoNext is a lightweight, fast and scalable web framework for Python
43+
Copyright (C) 2024 Alexeev Bronislav (C) 2024
44+
45+
This library is free software; you can redistribute it and/or
46+
modify it under the terms of the GNU Lesser General Public
47+
License as published by the Free Software Foundation; either
48+
version 2.1 of the License, or (at your option) any later version.
49+
50+
This library is distributed in the hope that it will be useful,
51+
but WITHOUT ANY WARRANTY; without even the implied warranty of
52+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
53+
Lesser General Public License for more details.
54+
55+
You should have received a copy of the GNU Lesser General Public
56+
License along with this library; if not, write to the Free Software
57+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
58+
USA

docs/ru/index.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# pyEchoNext / Документация
2+
3+
## Содержание
4+
5+
+ [Устройство веб-фреймворка](./webframework_design.md)
6+
7+
## Дополнительные материалы
8+
9+
+ [ASGI Documentation](https://asgi.readthedocs.io/_/downloads/en/stable/pdf/)
10+
+ [PEP 333](https://peps.python.org/pep-0333/#the-application-framework-side)

docs/ru/webframework_design.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# pyEchoNext / устройство веб-фреймворков
2+
3+
Наиболее важными частями веб-фрейморков являются:
4+
5+
+ Обработчики маршрутизации (routes):
6+
- Простые: `/index`
7+
- Параметризованные: `/article/{article_id}`
8+
+ Обработчики запросов (views, handlers).
9+
10+
Основное требование: веб-фреймворк должен поддерживаться быстрым, легким и эффективным сервером (например gunicorn). Для этого в Python есть руководство по WSGI.
11+
12+
## Устройство веб-сервера на Python
13+
14+
```
15+
ЗАПРОС
16+
CLIENT <--------------> [HTTP (80) или HTTPS (443)] Сервер
17+
ОТВЕТ
18+
19+
> Приложение с логикой
20+
> Преобразование данных для python-приложения <-- Зона интересов веб-фреймвока (обеспечение работы gunicorn с ним)
21+
> Gunicorn
22+
> Преобразованные данные
23+
СЕРВЕР -> NGINX
24+
> Маршрутизация данных
25+
```
26+
27+
При разработки web-приложения на python мы сталкиваемся со следующими проблемами:
28+
29+
+ Многие фреймворки (ex. django) не умеют маршрутизировать ответные запросы.
30+
+ Приложения являются небезопасными, и могут быть подвержены DDoS-атаке (Distributed Denial of Service, распределенный отказ в обслуживании).
31+
+ Нет балансировки нагрузки между несколькими серверами.
32+
+ Проблему балансировки нагрузки решает NGINX, но он не умеет запускать и общаться с Python-приложениями.
33+
34+
Поэтому и возникает нужда в использовании WSGI-сервера (Web Server Gateway Interface) и прокси-сервера (такого как NGINX).
35+
36+
## WSGI
37+
В настоящее время Python может похвастаться широким спектром фреймворков веб-приложений, таких как Zope, Quixote, Webware, SkunkWeb, PSO и Twisted Web — вот лишь некоторые из них. Такое широкое разнообразие вариантов может стать проблемой для новых пользователей Python, поскольку, как правило, их выбор веб-фреймворка ограничит их выбор используемых веб-серверов, и наоборот.
38+
39+
Напротив, хотя Java имеет столько же доступных фреймворков веб-приложений, API «servlet» Java позволяет приложениям, написанным с помощью любого фреймворка веб-приложений Java, работать на любом веб-сервере, который поддерживает API сервлетов.
40+
41+
Доступность и широкое использование такого API в веб-серверах для Python — независимо от того, написаны ли эти серверы на Python (например, Medusa), встроен ли Python (например, mod_python) или вызывают Python через протокол шлюза (например, CGI, FastCGI и т. д.) — отделит выбор фреймворка от выбора веб-сервера, позволяя пользователям выбирать подходящую им пару, в то же время освобождая разработчиков фреймворка и сервера для сосредоточения на их предпочтительной области специализации.
42+
43+
Таким образом, этот PEP предлагает простой и универсальный интерфейс между веб-серверами и веб-приложениями или фреймворками: интерфейс шлюза веб-сервера Python (WSGI).
44+
45+
Но само существование спецификации WSGI ничего не делает для решения существующего состояния серверов и фреймворков для веб-приложений Python. Авторы и сопровождающие серверов и фреймворков должны фактически реализовать WSGI, чтобы это имело какой-либо эффект.
46+
47+
Однако, поскольку ни один из существующих серверов или фреймворков не поддерживает WSGI, автор, который реализует поддержку WSGI, не получит немедленного вознаграждения.Таким образом, WSGI должен быть прост в реализации, чтобы первоначальные инвестиции автора в интерфейс могли быть достаточно низкими.
48+
49+
Таким образом, простота реализации как на стороне сервера, так и на стороне фреймворка интерфейса абсолютно критична для полезности интерфейса WSGI и, следовательно, является основным критерием для любых проектных решений.
50+
51+
Однако следует отметить, что простота реализации для автора фреймворка — это не то же самое, что простота использования для автора веб-приложения. WSGI представляет абсолютно «без излишеств» интерфейс для автора фреймворка, потому что такие навороты, как объекты ответа и обработка файлов cookie, просто помешают существующим фреймворкам решать эти проблемы. Опять же, цель WSGI — облегчить простое взаимодействие существующих серверов и приложений или фреймворков, а не создать новый веб-фреймворк.
52+
53+
Также следует отметить, что эта цель не позволяет WSGI требовать ничего, что еще не доступно в развернутых версиях Python. Поэтому новые модули стандартной библиотеки не предлагаются и не требуются этой спецификацией, и ничто в WSGI не требует версии Python выше 2.2.2. (Однако было бы неплохо, чтобы будущие версии Python включали поддержку этого интерфейса в веб-серверах, предоставляемых стандартной библиотекой.)
54+
55+
Помимо простоты реализации для существующих и будущих фреймворков и серверов, также должно быть легко создавать препроцессоры запросов, постпроцессоры ответов и другие компоненты «промежуточного программного обеспечения» на основе WSGI, которые выглядят как приложение для своего содержащего сервера, при этом выступая в качестве сервера для своих содержащихся приложений.Если промежуточное ПО может быть одновременно простым и надежным, а WSGI широко доступен в серверах и фреймворках, это допускает возможность совершенно нового типа фреймворка веб-приложений Python: состоящего из слабосвязанных компонентов промежуточного ПО WSGI. Действительно, существующие авторы фреймворков могут даже выбрать рефакторинг существующих служб своих фреймворков, чтобы они предоставлялись таким образом, становясь больше похожими на библиотеки, используемые с WSGI, и меньше на монолитные фреймворки. Это тогда позволило бы разработчикам приложений выбирать «лучшие в своем классе» компоненты для определенной функциональности, вместо того, чтобы брать на себя все плюсы и минусы одного фреймворка.
56+
57+
Конечно, на момент написания этой статьи этот день, несомненно, довольно далек. В то же время, это является достаточной краткосрочной целью для WSGI, чтобы обеспечить использование любого фреймворка с любым сервером.
58+
59+
Наконец, следует упомянуть, что текущая версия WSGI не предписывает какой-либо конкретный механизм для «развертывания» приложения для использования с веб-сервером или серверным шлюзом. В настоящее время это обязательно определяется реализацией сервера или шлюза. После того, как достаточное количество серверов и фреймворков внедрит WSGI для обеспечения практического опыта с различными требованиями к развертыванию, может иметь смысл создать еще один PEP, описывающий
60+
61+
---
62+
63+
[Содержание](./index.md)

docsconf.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
project = "pyechonext"
2+
author = "Alexeev Bronislav"
3+
version = "0.1"
4+
release = "0.1.0"
5+
6+
extensions = [
7+
"sphinx.ext.autodoc",
8+
"sphinx.ext.viewcode",
9+
"sphinx.ext.napoleon",
10+
"sphinx.ext.coverage",
11+
"sphinx.ext.ifconfig",
12+
"sphinx.ext.graphviz",
13+
]
14+
15+
html_theme = "sphinx_rtd_theme"
16+
html_static_path = ["_static"]
17+
todo_include_todos = True
18+
19+
autodock_mock_imports = []

examples/simple_app.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from pyechonext.app import ApplicationType, EchoNext
2+
from sqlsymphony_orm.datatypes.fields import IntegerField, RealField, TextField
3+
from sqlsymphony_orm.models.session_models import SessionModel
4+
from sqlsymphony_orm.models.session_models import SQLiteSession
5+
from sqlsymphony_orm.queries import QueryBuilder
6+
7+
8+
echonext = EchoNext(__name__, application_type=ApplicationType.HTML)
9+
session = SQLiteSession("echonext.db")
10+
11+
12+
class User(SessionModel):
13+
__tablename__ = "Users"
14+
15+
id = IntegerField(primary_key=True)
16+
name = TextField(null=False)
17+
cash = RealField(null=False, default=0.0)
18+
19+
def __repr__(self):
20+
return f"<User {self.pk}>"
21+
22+
23+
@echonext.route_page("/")
24+
def home(request, response):
25+
user = User(name='John', cash=100.0)
26+
session.add(user)
27+
session.commit()
28+
response.body = "Hello from the HOME page"
29+
30+
31+
@echonext.route_page("/users")
32+
def about(request, response):
33+
users = session.get_all_by_model(User)
34+
35+
response.body = f"Users: {[f'{user.name}: {user.cash}$' for user in users]}"

format-code.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#!/usr/bin/env python3
2+
# Python program to format python code
3+
import os
4+
import sys
5+
import subprocess
6+
7+
# Define color codes for output
8+
RED = "\033[31m"
9+
GREEN = "\033[32m"
10+
YELLOW = "\033[33m"
11+
NC = "\033[0m" # No Color
12+
BOLD = "\033[1m" # No Color
13+
14+
# File Extension filter. You can add new extension
15+
py_extensions = (".py",)
16+
IGNORED_DIRS = ["dist", ".git", "docs"]
17+
18+
RUFF = "ruff"
19+
SPACETABS = "./space-tabs.sh"
20+
21+
print(f'libnumerixpp code-formatter: {RUFF}; Extensions: {" ".join(py_extensions)}')
22+
23+
24+
def print_usage():
25+
"""Print the usage instructions."""
26+
print(f"{YELLOW}Usage: convert_tabs(file_path, tab_size, conversion_type){NC}")
27+
print("<conversion_type>: 'spaces' or 'tabs'")
28+
29+
30+
def print_error(message):
31+
"""Print error messages."""
32+
print(f"{RED}Error: {message}{NC}")
33+
34+
35+
def validate_positive_integer(value):
36+
"""Validate if the value is a positive integer."""
37+
try:
38+
int_value = int(value)
39+
if int_value < 1:
40+
raise ValueError
41+
return int_value
42+
except ValueError:
43+
print_error("Tab size must be a positive integer.")
44+
return None
45+
46+
47+
def file_exists(file_path):
48+
"""Check if the file exists."""
49+
if not os.path.isfile(file_path):
50+
print_error(f"File not found: {file_path}")
51+
return False
52+
return True
53+
54+
55+
def convert_tabs(file_path, tab_size, conversion_type):
56+
"""Convert tabs to spaces or spaces to tabs based on conversion type."""
57+
try:
58+
if conversion_type == "spaces":
59+
print(f"{BOLD}Converting tabs to spaces...{NC}")
60+
subprocess.run(
61+
["expand", "-t", str(tab_size), file_path],
62+
stdout=open(f"{file_path}.tmp", "w"),
63+
)
64+
elif conversion_type == "tabs":
65+
print(f"{BOLD}Converting spaces to tabs...{NC}")
66+
subprocess.run(
67+
["unexpand", "-t", str(tab_size), file_path],
68+
stdout=open(f"{file_path}.tmp", "w"),
69+
)
70+
else:
71+
print_error(
72+
f"Invalid conversion type: {conversion_type}. Use 'spaces' or 'tabs'."
73+
)
74+
return
75+
76+
os.replace(f"{file_path}.tmp", file_path)
77+
print(f"{GREEN}Conversion completed successfully: {file_path}{NC}")
78+
except Exception as e:
79+
print_error(f"Conversion failed: {str(e)}")
80+
81+
82+
def convert_file(file_path, tab_size, conversion_type):
83+
"""Main function to manage conversion."""
84+
tab_size = validate_positive_integer(tab_size)
85+
if tab_size is None:
86+
return
87+
88+
if not file_exists(file_path):
89+
return
90+
91+
convert_tabs(file_path, tab_size, conversion_type)
92+
93+
94+
def main():
95+
# Set the current working directory for scanning c/c++ sources (including
96+
# header files) and apply the clang formatting
97+
# Please note "-style" is for standard style options
98+
# and "-i" is in-place editing
99+
100+
if len(sys.argv) > 1:
101+
print(f"{BOLD}Format {sys.argv[1]}{NC}")
102+
os.system(f"{RUFF} check {sys.argv[1]} --fix")
103+
os.system(f"{RUFF} format {sys.argv[1]}")
104+
print(f"{GREEN}Formatting completed successfully: {sys.argv[1]}{NC}")
105+
convert_file(f"{sys.argv[1]}", "4", "tabs")
106+
return
107+
108+
for root, dirs, files in os.walk(os.getcwd()):
109+
if len(set(root.split("/")).intersection(IGNORED_DIRS)) > 0:
110+
continue
111+
for file in files:
112+
if file.endswith(py_extensions):
113+
print(f"{BOLD}Format {file}: {root}/{file}{NC}")
114+
os.system(f"{RUFF} check {root}/{file} --fix")
115+
os.system(f"{RUFF} format {root}/{file}")
116+
print(f"{GREEN}Formatting completed successfully: {root}/{file}{NC}")
117+
convert_file(f"{root}/{file}", "4", "tabs")
118+
119+
120+
if __name__ == "__main__":
121+
main()

pyechonext/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
EchoNext is a lightweight, fast and scalable web framework for Python
3+
Copyright (C) 2024 Alexeev Bronislav (C) 2024
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
18+
USA
19+
"""
20+
21+
from rich.traceback import install
22+
from pyechonext.logging import setup_logger
23+
24+
install(show_locals=True)
25+
26+
27+
setup_logger()

0 commit comments

Comments
 (0)