{"id":443184,"date":"2024-12-26T05:56:55","date_gmt":"2024-12-26T05:56:55","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=443184"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=443184","title":{"rendered":"<span>\u041a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 Python<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a, \u0445\u0430\u0431\u0440! \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0432\u043e\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 Python \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c gunicorn.<\/p>\n<p>\u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0433\u043a\u0438\u043c, \u0438\u043c\u0435\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b. \u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (views), \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044e, Middleware, i18n \u0438 l10n, Request\/Response, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 html-\u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u043c \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0438\u0437\u0443\u0447\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 WSGI \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0418 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0433\u0447\u0435 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432: flask, django.<\/p>\n<p>\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u0432\u0430\u0441 \u043c\u043e\u0433\u0443\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0447\u0442\u043e \u043c\u044b \u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0435\u043c \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434. \u0410 \u044f \u0432 \u043e\u0442\u0432\u0435\u0442 \u0441\u043a\u0430\u0436\u0443 \u2014 \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043b\u0438 \u0432\u044b \u043f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441, \u0431\u0435\u0437 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a, \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u043f\u0430\u043c\u044f\u0442\u0438, \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434 \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a?<\/p>\n<hr\/>\n<p>\u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0432\u0430\u0436\u043d\u044b\u043c\u0438 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u043e\u0440\u043a\u043e\u0432 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f:<\/p>\n<ul>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438 (routes): <\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0441\u0442\u044b\u0435: <code>\/index<\/code><\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435: <code>\/article\/{article_id}<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (views).<\/p>\n<\/li>\n<li>\n<p>Middleware<\/p>\n<\/li>\n<li>\n<p>Request\/Response<\/p>\n<\/li>\n<li>\n<p>i18n\/l10n<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435: \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u044b\u043c, \u043b\u0435\u0433\u043a\u0438\u043c \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 gunicorn). \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 Python \u0435\u0441\u0442\u044c \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e WSGI.<\/p>\n<p>\u041d\u0430\u0448 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f pyEchoNext. <a href=\"https:\/\/github.com\/alexeev-prog\/pyEchoNext\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.<\/a><\/p>\n<h2>\u276f \u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 Python<\/h2>\n<pre><code>            \u0417\u0410\u041f\u0420\u041e\u0421 CLIENT &lt;--------------&gt; [HTTP (80) \u0438\u043b\u0438 HTTPS (443)] \u0421\u0435\u0440\u0432\u0435\u0440              \u041e\u0422\u0412\u0415\u0422             &gt; \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439         &gt; \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f python-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f  &lt;-- \u0417\u043e\u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u043a\u0430 (\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b gunicorn \u0441 \u043d\u0438\u043c)         &gt; Gunicorn         &gt; \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0421\u0415\u0420\u0412\u0415\u0420 -&gt; NGINX         &gt; \u041c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 <\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 python \u043c\u044b \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>\u041c\u043d\u043e\u0433\u0438\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438 (ex. django) \u043d\u0435 \u0443\u043c\u0435\u044e\u0442 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c\u0438, \u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0434\u0432\u0435\u0440\u0436\u0435\u043d\u044b DDoS-\u0430\u0442\u0430\u043a\u0435 (Distributed Denial of Service, \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u043a\u0430\u0437 \u0432 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0438).<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0442 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043c\u0435\u0436\u0434\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0440\u0435\u0448\u0430\u0435\u0442 NGINX, \u043d\u043e \u043e\u043d \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0438 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441 Python-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0443\u0436\u0434\u0430 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 WSGI-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 (Web Server Gateway Interface) \u0438 \u043f\u0440\u043e\u043a\u0441\u0438-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 (\u0442\u0430\u043a\u043e\u0433\u043e \u043a\u0430\u043a NGINX).<\/p>\n<h2>\u276f WSGI<\/h2>\n<p>\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f Python \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0445\u0432\u0430\u0441\u0442\u0430\u0442\u044c\u0441\u044f \u0448\u0438\u0440\u043e\u043a\u0438\u043c \u0441\u043f\u0435\u043a\u0442\u0440\u043e\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a Zope, Quixote, Webware, SkunkWeb, PSO \u0438 Twisted Web \u2014 \u0432\u043e\u0442 \u043b\u0438\u0448\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445. \u0422\u0430\u043a\u043e\u0435 \u0448\u0438\u0440\u043e\u043a\u043e\u0435 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u0434\u043b\u044f \u043d\u043e\u0432\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 Python, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0438\u0445 \u0432\u044b\u0431\u043e\u0440 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442 \u0438\u0445 \u0432\u044b\u0431\u043e\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432, \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442.<\/p>\n<p>\u041d\u0430\u043f\u0440\u043e\u0442\u0438\u0432, \u0445\u043e\u0442\u044f Java \u0438\u043c\u0435\u0435\u0442 \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, API \u00abservlet\u00bb Java \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043b\u044e\u0431\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 Java, \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 API \u0441\u0435\u0440\u0432\u043b\u0435\u0442\u043e\u0432.<\/p>\n<p>\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c \u0438 \u0448\u0438\u0440\u043e\u043a\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u043a\u043e\u0433\u043e API \u0432 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445 \u0434\u043b\u044f Python \u2014 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u043e\u0433\u043e, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043b\u0438 \u044d\u0442\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u044b \u043d\u0430 Python (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Medusa), \u0432\u0441\u0442\u0440\u043e\u0435\u043d \u043b\u0438 Python (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, mod_python) \u0438\u043b\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 Python \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0448\u043b\u044e\u0437\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, CGI, FastCGI \u0438 \u0442. \u0434.) \u2014 \u043e\u0442\u0434\u0435\u043b\u0438\u0442 \u0432\u044b\u0431\u043e\u0440 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0443\u044e \u0438\u043c \u043f\u0430\u0440\u0443, \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043b\u044f \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0438\u0445 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u044d\u0442\u043e\u0442 PEP \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043c\u0435\u0436\u0434\u0443 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438 \u0438 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u0438\u043b\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438: \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0448\u043b\u044e\u0437\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 Python (WSGI).<\/p>\n<p>\u041d\u043e \u0441\u0430\u043c\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 WSGI \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u0442 \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0434\u043b\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 Python. \u0410\u0432\u0442\u043e\u0440\u044b \u0438 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c WSGI, \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0438\u043c\u0435\u043b\u043e \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u044d\u0444\u0444\u0435\u043a\u0442.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0438 \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438\u043b\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 WSGI, \u0430\u0432\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 WSGI, \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u043e\u0437\u043d\u0430\u0433\u0440\u0430\u0436\u0434\u0435\u043d\u0438\u044f.\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, WSGI \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0441\u0442 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0432\u0435\u0441\u0442\u0438\u0446\u0438\u0438 \u0430\u0432\u0442\u043e\u0440\u0430 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043c\u043e\u0433\u043b\u0438 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043d\u0438\u0437\u043a\u0438\u043c\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u0430\u043a \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0442\u0430\u043a \u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0441\u0442\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 WSGI \u0438, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u043c \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u2014 \u044d\u0442\u043e \u043d\u0435 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. WSGI \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u00ab\u0431\u0435\u0437 \u0438\u0437\u043b\u0438\u0448\u0435\u0441\u0442\u0432\u00bb \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0430\u043a\u0438\u0435 \u043d\u0430\u0432\u043e\u0440\u043e\u0442\u044b, \u043a\u0430\u043a \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 cookie, \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043c\u0435\u0448\u0430\u044e\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c \u0440\u0435\u0448\u0430\u0442\u044c \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041e\u043f\u044f\u0442\u044c \u0436\u0435, \u0446\u0435\u043b\u044c WSGI \u2014 \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043b\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432, \u0430 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u0430 \u0446\u0435\u043b\u044c \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 WSGI \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e, \u0447\u0442\u043e \u0435\u0449\u0435 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u0432 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445 Python. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u043e\u0432\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0435 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u044d\u0442\u043e\u0439 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439, \u0438 \u043d\u0438\u0447\u0442\u043e \u0432 WSGI \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u0435\u0440\u0441\u0438\u0438 Python \u0432\u044b\u0448\u0435 2.2.2. (\u043e\u0434\u043d\u0430\u043a\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u0447\u0442\u043e\u0431\u044b \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 Python \u0432\u043a\u043b\u044e\u0447\u0430\u043b\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439).<\/p>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0438 \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432, \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043b\u0435\u0433\u043a\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u043e\u0441\u0442\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u00ab\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f\u00bb \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 WSGI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043a\u0430\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0445\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0435 \u041f\u041e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u043c, \u0430 WSGI \u0448\u0438\u0440\u043e\u043a\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u0445, \u044d\u0442\u043e \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 Python: \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e \u0438\u0437 \u0441\u043b\u0430\u0431\u043e\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u041f\u041e WSGI. \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u044b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0434\u0430\u0436\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u043b\u0443\u0436\u0431 \u0441\u0432\u043e\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0438\u0441\u044c \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u0445\u043e\u0436\u0438\u043c\u0438 \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0441 WSGI, \u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u043d\u0430 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438. \u042d\u0442\u043e \u0442\u043e\u0433\u0434\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0431\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u00ab\u043b\u0443\u0447\u0448\u0438\u0435 \u0432 \u0441\u0432\u043e\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0435\u00bb \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0431\u0440\u0430\u0442\u044c \u043d\u0430 \u0441\u0435\u0431\u044f \u0432\u0441\u0435 \u043f\u043b\u044e\u0441\u044b \u0438 \u043c\u0438\u043d\u0443\u0441\u044b \u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044d\u0442\u043e\u0442 \u0434\u0435\u043d\u044c, \u043d\u0435\u0441\u043e\u043c\u043d\u0435\u043d\u043d\u043e, \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u043b\u0435\u043a. \u0412 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f, \u044d\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0439 \u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0440\u043e\u0447\u043d\u043e\u0439 \u0446\u0435\u043b\u044c\u044e \u0434\u043b\u044f WSGI, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0441 \u043b\u044e\u0431\u044b\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c.<\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f WSGI \u043d\u0435 \u043f\u0440\u0435\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u043b\u044f \u00ab\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f\u00bb \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u043c \u0448\u043b\u044e\u0437\u043e\u043c. \u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u044d\u0442\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438\u043b\u0438 \u0448\u043b\u044e\u0437\u0430. \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0432\u043d\u0435\u0434\u0440\u0438\u0442 WSGI \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043e\u043f\u044b\u0442\u0430 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c\u0438 \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044e, \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u043c\u044b\u0441\u043b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d PEP, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0439<\/p>\n<h2>\u276f \u0426\u0435\u043b\u0438 pyEchoNext<\/h2>\n<p>pyEchoNext \u2014 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u043e\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0438\u043b\u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. Django \u0434\u043b\u044f \u043d\u0430\u0441 \u0431\u044b\u043b \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438 \u043d\u0435\u043f\u043e\u0432\u043e\u0440\u043e\u0442\u043b\u0438\u0432\u044b\u0439, flask \u0438\u043b\u0438 fastapi \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0432\u0437\u044f\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0444\u0438\u0447\u0438 \u0438\u0437 django \u0438 flask\/fastapi, \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u0445 \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0432 \u0441\u0438\u043c\u0431\u0438\u043e\u0437\u0435. \u0422\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u0442\u0430\u043a \u0438 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441. \u0418 \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0432 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0443\u0441\u0438\u043b\u0438\u0439.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u0448\u0438\u043c\u0438 \u0446\u0435\u043b\u044f\u043c\u0438 \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c, \u0434\u0440\u0443\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a.<\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435, \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0442\u0430\u043a\u0430\u044f:<\/p>\n<ol>\n<li>\n<p>\u0426\u0435\u043b\u044c: \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u043d\u043e\u0433\u043e\u0433\u0440\u0430\u043d\u043d\u044b\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 python.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0434\u0430\u0447\u0438:<\/p>\n<\/li>\n<\/ol>\n<ul>\n<li>\n<p>\u041d\u0430\u0439\u0442\u0438 \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u0438 \u043f\u043b\u043e\u0445\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b Flask, FastAPI<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0439\u0442\u0438 \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u0438 \u043f\u043b\u043e\u0445\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b Django<\/p>\n<\/li>\n<li>\n<p>\u0421\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0431\u043e\u0440 \u043b\u0443\u0447\u0448\u0438\u0445 \u0444\u0438\u0447<\/p>\n<\/li>\n<li>\n<p>\u0421\u0438\u043c\u0431\u0438\u043e\u0437 \u0444\u0438\u0447 \u0432 \u043e\u0434\u043d\u043e \u0446\u0435\u043b\u043e\u0435<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e SOLID \u0438 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c \u041e\u041e\u041f, \u043b\u0435\u0433\u043a\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u044b\u043c, \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u044b\u043c \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u044b\u0441\u0442\u0440\u044b\u043c \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c, \u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0431\u043e\u0434\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443<\/p>\n<\/li>\n<\/ul>\n<ol start=\"3\">\n<li>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432, \u0434\u0430\u044e\u0449\u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u0430\u043a \u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0442\u0430\u043a \u0438 \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441.<\/p>\n<\/li>\n<li>\n<p>\u0410\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c: \u0432\u0435\u0431-\u0441\u0444\u0435\u0440\u0430 \u0432 \u0434\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430, \u0443\u043c\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438, \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f\u043c\u0438, \u0437\u043d\u0430\u0442\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441\u0430\u0439\u0442\u043e\u0432 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0441\u0435\u043c.<\/p>\n<\/li>\n<\/ol>\n<h2>\u276f \u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 gunicorn<\/h2>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 <code>gunicorn<\/code> \u0438 <code>pysocks<\/code> \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b app.py:<\/p>\n<pre><code class=\"python\">from socks import method   def app(environ: dict, start_response: method): response_body = b'Hello, Habr!' status = \"200 OK\" start_response(status, headers=[]) return iter([response_body]) <\/code><\/pre>\n<p>\u0418 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 gunicorn:<\/p>\n<pre><code class=\"bash\">gunicorn app:app # gunicorn &lt;\u0444\u0430\u0439\u043b&gt;:&lt;callable-\u043a\u043b\u0430\u0441\u0441 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430&gt; <\/code><\/pre>\n<p>\u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0432\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 &#8212; environ \u0438 start_response. \u0412 environ \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0432\u0435\u0431-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a user-agent, \u043f\u0443\u0442\u044c, \u043c\u0435\u0442\u043e\u0434, GET \u0438 POST \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438 \u0434\u0440\u0443\u0433\u0438\u0435. \u0412\u0442\u043e\u0440\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u2014 start_response, \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0439 \u043e\u0442\u0432\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0441\u044b\u043b\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0433\u0430\u0435\u043c\u044b\u0439 \u043e\u0442\u0432\u0435\u0442.<\/p>\n<p>\u041d\u043e \u0431\u043e\u043b\u0435\u0435 \u0445\u043e\u0440\u043e\u0448\u043e\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c callable-\u043a\u043b\u0430\u0441\u0441:<\/p>\n<pre><code class=\"python\">class App: def __call__(self, environ: dict, start_response: method): response_body = b'Hello, Habr!' status = \"200 OK\" start_response(status, headers=[]) return iter([response_body])   app = App() <\/code><\/pre>\n<p>\u041c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 <code>__call__<\/code> \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u043c\u0438.<\/p>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"bash\">gunicorn app:app # gunicorn &lt;\u0444\u0430\u0439\u043b&gt;:&lt;callable-\u043a\u043b\u0430\u0441\u0441 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430&gt; <\/code><\/pre>\n<p>\u041d\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442, \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u044f \u0435\u0433\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0447\u043d\u0435\u043c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 poetry.<\/p>\n<h2>\u276f \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>Poetry \u2014 \u044d\u0442\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u0441\u0431\u043e\u0440\u043a\u043e\u0439 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432 Python. \u0410 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 Poetry \u043e\u0447\u0435\u043d\u044c \u043b\u0435\u0433\u043a\u043e \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043d\u0430 PyPi!<\/p>\n<p>\u0412 Poetry \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u043e\u043b\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438 \u043d\u0430 Python. \u0412 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u0441\u0431\u043e\u0440\u043a\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 \u044f\u0437\u044b\u043a\u0430, \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432.<\/p>\n<p>\u0412\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044e Poetry \u0421\u0435\u0431\u0430\u0441\u0442\u044c\u0435\u043d\u0443 \u042e\u0441\u0442\u0430\u0441\u0443 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0441\u044f \u0435\u0434\u0438\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438 \u043e\u0442 \u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e \u043a\u043e\u043d\u0446\u0430, \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0438 \u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u043c\u043e\u0433 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430. \u041e\u0434\u043d\u043e\u0433\u043e \u043b\u0438\u0448\u044c \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0431\u044b\u043b\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432, \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0438 \u0432\u0441\u0435\u043c \u0441\u043e\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c. \u042d\u0442\u043e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0437\u0430 \u0433\u0440\u0430\u043d\u044c\u044e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043d\u044b\u0445 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a Pip \u0438\u043b\u0438 Conda. \u0422\u0430\u043a \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f Python Poetry.<\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c poetry \u043c\u043e\u0436\u043d\u043e \u0447\u0435\u0440\u0435\u0437 pipx: <code>pipx install poetry<\/code> \u0438 \u0447\u0435\u0440\u0435\u0437 pip: <code>pip install poetry --break-system-requirements<\/code>. \u042d\u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 poetry \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e \u0432\u043e \u0432\u0441\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 poetry \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code class=\"bash\">poetry new &lt;\u0438\u043c\u044f_\u043f\u0440\u043e\u0435\u043a\u0442\u0430&gt; cd &lt;\u0438\u043c\u044f_\u043f\u0440\u043e\u0435\u043a\u0442\u0430&gt; poetry shell poetry add ruff loguru pysocks fire python-dotenv jinja2 parse gunicorn configparser <\/code><\/pre>\n<h3>\u276f \u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<p>\u0423 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code>pyechonext\/ \u251c\u2500\u2500 apidoc_ui \u2502   \u251c\u2500\u2500 api_documentation.py \u2502   \u2514\u2500\u2500 __init__.py \u251c\u2500\u2500 app.py \u251c\u2500\u2500 config.py \u251c\u2500\u2500 docsgen \u2502   \u251c\u2500\u2500 document.py \u2502   \u251c\u2500\u2500 __init__.py \u2502   \u2514\u2500\u2500 projgen.py \u251c\u2500\u2500 i18n_l10n \u2502   \u251c\u2500\u2500 i18n.py \u2502   \u2514\u2500\u2500 l10n.py \u251c\u2500\u2500 __init__.py \u251c\u2500\u2500 logging \u2502   \u251c\u2500\u2500 __init__.py \u2502   \u2514\u2500\u2500 logger.py \u251c\u2500\u2500 __main__.py \u251c\u2500\u2500 middleware.py \u251c\u2500\u2500 request.py \u251c\u2500\u2500 response.py \u251c\u2500\u2500 template_engine \u2502   \u251c\u2500\u2500 builtin.py \u2502   \u251c\u2500\u2500 __init__.py \u2502   \u2514\u2500\u2500 jinja.py \u251c\u2500\u2500 urls.py \u251c\u2500\u2500 utils \u2502   \u251c\u2500\u2500 exceptions.py \u2502   \u2514\u2500\u2500 __init__.py \u2514\u2500\u2500 views.py <\/code><\/pre>\n<ul>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f apidoc_ui \u2014 \u044d\u0442\u043e \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f OpenAPI \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f docsgen \u2014 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f i18n_l10n \u2014 \u0438\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f logging \u2014 \u043b\u043e\u0433\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f template_engine \u2014 \u0434\u0432\u0438\u0436\u043a\u0438 html-\u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f utils \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0439\u043b app.py \u2014 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0439\u043b config.py \u2014 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0439\u043b <code>__main__.py<\/code> \u2014 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c, \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 <code>python3 -m pyechonext<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0439\u043b middleware.py \u2014 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0435 \u041f\u041e.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0439\u043b request.py \u2014 \u043a\u043b\u0430\u0441\u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0439\u043b response.py \u2014 \u043a\u043b\u0430\u0441\u0441 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0439\u043b urls.py \u2014 URL (\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438).<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0439\u043b views.py \u2014 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<h2>\u276f \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u2014 \u043d\u0435\u043e\u0442\u044a\u0435\u043c\u043b\u0438\u043c\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u042f \u0440\u0435\u0448\u0438\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>pyEchoNextException \u2014 \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>WebError \u2014 \u0432\u0435\u0431-\u043e\u0448\u0438\u0431\u043a\u0430 (\u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0442 pyEchoNextException). \u041e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u0438\u043c\u0435\u0435\u0442 HTTP-\u043a\u043e\u0434 \u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f-\u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u0438 pyEchoNextException:<\/p>\n<ul>\n<li>\n<p>InternationalizationNotFound \u2014 \u0444\u0430\u0439\u043b \u0438\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d.<\/p>\n<\/li>\n<li>\n<p>LocalizationNotFound \u2014 \u0444\u0430\u0439\u043b \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d.<\/p>\n<\/li>\n<li>\n<p>TemplateNotFileError \u2014 \u0448\u0430\u0431\u043b\u043e\u043d \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0430\u0439\u043b\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>RoutePathExistsError \u2014 \u043f\u0443\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f-\u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u0438 WebError:<\/p>\n<ul>\n<li>\n<p>URLNotFound \u2014 URL \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d (404).<\/p>\n<\/li>\n<li>\n<p>MethodNotAllow \u2014 \u043c\u0435\u0442\u043e\u0434 \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f (405).<\/p>\n<\/li>\n<li>\n<p>TeapotError \u2014 \u0441\u0435\u0440\u0432\u0435\u0440 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0430\u0439\u043d\u0438\u043a\u043e\u043c (418).<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from loguru import logger   class pyEchoNextException(Exception): \"\"\" Exception for signaling pyechonext errors. \"\"\"  def __init__(self, *args): \"\"\" Constructs a new instance.  :paramargs:  The arguments :typeargs:  list \"\"\" if args: self.message = args[0] else: self.message = None  def get_explanation(self) -&gt; str: \"\"\" Gets the explanation.  :returns:The explanation. :rtype:str \"\"\" return f\"Message: {self.message if self.message else 'missing'}\"  def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"pyEchoNextException has been raised. {self.get_explanation()}\"   class WebError(pyEchoNextException): code = 400  def get_explanation(self) -&gt; str: \"\"\" Gets the explanation.  :returns:The explanation. :rtype:str \"\"\" return ( f\"Code: {self.code}. Message: {self.message if self.message else 'missing'}\" )  def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"WebError has been raised. {self.get_explanation()}\"   class InternationalizationNotFound(pyEchoNextException): def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"InternationalizationNotFound has been raised. {self.get_explanation()}\"   class LocalizationNotFound(pyEchoNextException): def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"LocalizationNotFound has been raised. {self.get_explanation()}\"   class TemplateNotFileError(pyEchoNextException): def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"TemplateNotFileError has been raised. {self.get_explanation()}\"   class RoutePathExistsError(pyEchoNextException): def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"RoutePathExistsError has been raised. {self.get_explanation()}\"   class URLNotFound(WebError): code = 404  def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"URLNotFound has been raised. {self.get_explanation()}\"   class MethodNotAllow(WebError): code = 405  def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"MethodNotAllow has been raised. {self.get_explanation()}\"   class TeapotError(WebError): code = 418  def __str__(self): \"\"\" Returns a string representation of the object.  :returns:String representation of the object. :rtype:str \"\"\" logger.error(f\"{self.__class__.__name__}: {self.get_explanation()}\") return f\"The server refuses to make coffee because he is a teapot. {self.get_explanation()}\" <\/code><\/pre>\n<\/div>\n<\/details>\n<h2>\u276f \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e<\/h2>\n<p>i18n \u2014 \u044d\u0442\u043e \u0441\u043e\u043a\u0440\u0430\u0449\u0451\u043d\u043d\u043e\u0435 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0438\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<br \/> l10n &#8212; \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u0442\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u044b \u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0434\u0430\u0442, \u0434\u0435\u043d\u0435\u0436\u043d\u044b\u0445 \u0441\u0443\u043c\u043c, \u0447\u0438\u0441\u0435\u043b.<\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0435\u0433\u043e \u043a\u043e\u0434 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c \u043e\u0442 \u043b\u044e\u0431\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u0445 \u0438 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u043d\u044b\u0445 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0440\u0435\u0433\u0438\u043e\u043d\u0430 \u0438\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u044b. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0433\u0438\u0431\u043a\u0438\u043c \u0438 \u043c\u043e\u0436\u0435\u0442 \u043b\u0435\u0433\u043a\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u0434 \u0440\u0430\u0437\u043d\u044b\u0435 \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u0435 \u0438 \u043a\u0443\u043b\u044c\u0442\u0443\u0440\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438.<\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442 \u043d\u0430 \u0440\u0430\u043d\u043d\u0438\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u043a \u0431\u0443\u0434\u0443\u0449\u0435\u0439 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0412\u043e \u0432\u0440\u0435\u043c\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u043b\u043e\u043a\u0430\u043b\u0435\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0435\u043a\u0441\u0442, \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f) \u0438 \u0432\u044b\u043d\u043e\u0441\u044f\u0442 \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u044b.<\/p>\n<p>18 \u0432 \u0430\u0431\u0431\u0440\u0435\u0432\u0438\u0430\u0442\u0443\u0440\u0435 i18n \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0431\u0443\u043a\u0432 \u043c\u0435\u0436\u0434\u0443 \u043f\u0435\u0440\u0432\u043e\u0439 \u0431\u0443\u043a\u0432\u043e\u0439 i \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0431\u0443\u043a\u0432\u043e\u0439 n \u0432 \u0441\u043b\u043e\u0432\u0435 \u00abinternationalization\u00bb.<\/p>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 i18n.py \u0431\u0443\u0434\u0435\u0442 \u0434\u0432\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 \u2014 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 i18nInterface. \u041e\u043d \u0438\u043c\u0435\u0435\u0442 \u0434\u0432\u0430 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u0430 \u2014 load_locale \u0438 get_string.<\/p>\n<p>\u041e\u0442 \u043d\u0435\u0433\u043e \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441 JSONi18nLoader, \u043e\u043d \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u0437 json-\u0444\u0430\u0439\u043b\u0430. \u041d\u043e \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e:<\/p>\n<pre><code class=\"python\">DEFAULT_LOCALE = { \"title\": \"pyEchoNext Example Website\", \"description\": \"This web application is an example of the pyEchonext web framework.\", } <\/code><\/pre>\n<p>json-\u0444\u0430\u0439\u043b \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0442\u0430\u043a\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435: <code>&lt;\u043b\u043e\u043a\u0430\u043b\u044c&gt;.json<\/code>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f RU_RU: <code>RU_RU.json<\/code>. \u0418 \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<pre><code class=\"json\">{ \"i18n\": { \"title\": \"pyEchoNext \u0412\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u044e\", \"example one\": \"\u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0434\u0438\u043d\" }, \"l10n\": { \"date_format\": \"%Y-%m-%d\", \"time_format\": \"%H:%M\", \"date_time_fromat\": \"%Y-%m-%d %H:%M\", \"thousands_separator\": \",\", \"decimal_separator\": \".\", \"currency_symbol\": \"$\", \"currency_format\": \"{symbol}{amount}\" } } <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u044b \u0432\u0438\u0434\u0438\u0442\u0435, \u0432 \u043e\u0434\u043d\u043e\u043c json-\u0444\u0430\u0439\u043b\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0438 i18n, \u0438 l10n.<\/p>\n<p>\u0422\u0430\u043a\u0430\u044f \u0436\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0438 \u0443 \u0444\u0430\u0439\u043b\u0430 l10n.py \u2014 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 LocalizationInterface \u0441 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 load_locale, format_date, format_number, format_currency, get_current_settings \u0438 update_settings.<\/p>\n<p>\u0418 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441 JSONLocalizationLoader (\u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430). \u041e\u043d \u0443\u0436\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:<\/p>\n<pre><code class=\"python\">DEFAULT_LOCALE = { \"date_format\": \"%Y-%m-%d\", \"time_format\": \"%H:%M\", \"date_time_fromat\": \"%Y-%m-%d %H:%M\", \"thousands_separator\": \",\", \"decimal_separator\": \".\", \"currency_symbol\": \"$\", \"currency_format\": \"{symbol}{amount}\", } <\/code><\/pre>\n<p>\u042d\u0442\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b \u0432 \u0444\u0430\u0439\u043b\u0435 \u043b\u043e\u043a\u0430\u043b\u0438, \u0438\u043d\u0430\u0447\u0435 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u043d\u0430 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439.<\/p>\n<details class=\"spoiler\">\n<summary>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 i18n.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import json import os from abc import ABC, abstractmethod from typing import Dict from loguru import logger from pyechonext.utils.exceptions import InternationalizationNotFound   class i18nInterface(ABC): \"\"\" This class describes a locale interface. \"\"\"  @abstractmethod def get_string(self, key: str) -&gt; str: \"\"\" Gets the string.  :paramkey:  The key :typekey:  str  :returns:The string. :rtype:str \"\"\" raise NotImplementedError  @abstractmethod def load_locale(self, locale: str, directory: str) -&gt; Dict[str, str]: \"\"\" Loads a locale.  :paramlocale:The locale :typelocale:str :paramdirectory:The directory :typedirectory:str  :returns:locale translations :rtype:Dict[str, str] \"\"\" raise NotImplementedError   class JSONi18nLoader(i18nInterface): \"\"\" This class describes a json locale loader. \"\"\"  DEFAULT_LOCALE = { \"title\": \"pyEchoNext Example Website\", \"description\": \"This web application is an example of the pyEchonext web framework.\", }  def __init__(self, locale: str, directory: str): \"\"\" Constructs a new instance.  :paramlocale:The locale :typelocale:str :paramdirectory:The directory :typedirectory:str \"\"\" self.locale: str = locale self.directory: str = directory self.translations: Dict[str, str] = self.load_locale( self.locale, self.directory )  def load_locale(self, locale: str, directory: str) -&gt; Dict[str, str]: \"\"\" Loads a locale.  :paramlocale:The locale :typelocale:str :paramdirectory:The directory :typedirectory:str  :returns:locale dictionary :rtype:Dict[str, str] \"\"\" if self.locale == \"DEFAULT\": return self.DEFAULT_LOCALE  file_path = os.path.join(self.directory, f\"{self.locale}.json\")  try: logger.info(f\"Load locale: {file_path} [{self.locale}]\") with open(file_path, \"r\", encoding=\"utf-8\") as file: i18n = json.load(file).get(\"i18n\", None) if i18n is None: return json.load(file) else: return i18n except FileNotFoundError: raise InternationalizationNotFound( f\"[i18n] i18n file at {file_path} not found\" )  def get_string(self, key: str, **kwargs) -&gt; str: \"\"\" Gets the string.  :paramkey: The key :typekey: str :paramkwargs: The keywords arguments :typekwargs: dictionary  :returns:The string. :rtype:str \"\"\" result = \"\"  for word in key.split(\" \"): result += f\"{self.translations.get(word, word)} \"  if kwargs: for name, value in kwargs.items(): result = result.replace(f'{f\"%{{{name}}}\"}', value)  return result.strip()   class LanguageManager: \"\"\" This class describes a language manager. \"\"\"  def __init__(self, loader: i18nInterface): \"\"\" Constructs a new instance.  :paramloader: The loader :typeloader: i18nInterface \"\"\" self.loader = loader  def translate(self, key: str) -&gt; str: \"\"\" Translate  :paramkey:  The key :typekey:  str  :returns:translated string :rtype:str \"\"\" return self.loader.get_string(key) <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 l10n.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import json import os from datetime import datetime from abc import ABC, abstractmethod from typing import Dict, Any, Optional from loguru import logger from pyechonext.utils.exceptions import LocalizationNotFound   class LocalizationInterface(ABC): \"\"\" This class describes a locale interface. \"\"\"  @abstractmethod def load_locale(self, locale: str, directory: str) -&gt; Dict[str, str]: \"\"\" Loads a locale.  :paramlocale:The locale :typelocale:str :paramdirectory:The directory :typedirectory:str  :returns:locale translations :rtype:Dict[str, str] \"\"\" raise NotImplementedError  @abstractmethod def format_date(self, date: datetime, date_format: Optional[str] = None) -&gt; str: \"\"\" Format date  :paramdate:  The date :typedate:  datetime  :returns:formatted date :rtype:str \"\"\" raise NotImplementedError  @abstractmethod def format_number(self, number: float, decimal_places: int = 2) -&gt; str: \"\"\" Format number  :paramnumber: The number :typenumber: float :paramdecimal_places: The decimal places :typedecimal_places: int  :returns:formatted number :rtype:str \"\"\" raise NotImplementedError  @abstractmethod def format_currency(self, amount: float) -&gt; str: \"\"\" Format currency  :paramamount: The amount :typeamount: float  :returns:formatted currency :rtype:str \"\"\" raise NotImplementedError  @abstractmethod def get_current_settings(self) -&gt; Dict[str, Any]: \"\"\" Gets the current settings.  :returns:The current settings. :rtype:Dict[str, Any] \"\"\" raise NotImplementedError  @abstractmethod def update_settings(self, settings: Dict[str, Any]): \"\"\" Update settings  :paramsettings:  The settings :typesettings:  Dict[str, Any] \"\"\" raise NotImplementedError   class JSONLocalizationLoader(LocalizationInterface): \"\"\" This class describes a json localization loader. \"\"\"  DEFAULT_LOCALE = { \"date_format\": \"%Y-%m-%d\", \"time_format\": \"%H:%M\", \"date_time_fromat\": \"%Y-%m-%d %H:%M\", \"thousands_separator\": \",\", \"decimal_separator\": \".\", \"currency_symbol\": \"$\", \"currency_format\": \"{symbol}{amount}\", }  def __init__( self, locale: str, directory: str, custom_settings: Optional[Dict[str, Any]] = None, ): \"\"\" Constructs a new instance.  :paramlocale:  The locale :typelocale:  str :paramdirectory:  The directory :typedirectory:  str :paramcustom_settings:  The custom settings :typecustom_settings:  Optional[Dict[str, Any]] \"\"\" self.locale: str = locale self.directory: str = directory self.locale_settings: Dict[str, Any] = self.load_locale(locale, directory)  if custom_settings: self.update_settings(custom_settings)  def load_locale(self, locale: str, directory: str) -&gt; Dict[str, str]: \"\"\" Loads a locale.  :paramlocale:The locale :typelocale:str :paramdirectory:The directory :typedirectory:str  :returns:locale dictionary :rtype:Dict[str, str] \"\"\" if self.locale == \"DEFAULT\": return self.DEFAULT_LOCALE  file_path = os.path.join(self.directory, f\"{self.locale}.json\")  try: logger.info(f\"Load locale: {file_path} [{self.locale}]\") with open(file_path, \"r\", encoding=\"utf-8\") as file: l10n = json.load(file).get(\"l10n\", None) if l10n is None: return json.load(file) else: return l10n except FileNotFoundError: raise LocalizationNotFound(f\"[l10n] l10n file at {file_path} not found\")  def format_date(self, date: datetime, date_format: Optional[str] = None) -&gt; str: \"\"\" Format date  :paramdate:  The date :typedate:  datetime :paramdate_format:  The date format :typedate_format:  Optional[str]  :returns:formatted date :rtype:str \"\"\" date_time_fromat = ( self.locale_settings.get( \"date_time_fromat\", self.DEFAULT_LOCALE[\"date_time_fromat\"] ) if date_format is None else date_format )  formatted_date = date_time_fromat.strftime(date_time_fromat)  return formatted_date  def format_number(self, number: float, decimal_places: int = 2) -&gt; str: \"\"\" Format number  :paramnumber: The number :typenumber: float :paramdecimal_places: The decimal places :typedecimal_places: int  :returns:formatted number :rtype:str \"\"\" thousands_separator = self.locale_settings.get( \"thousands_separator\", self.DEFAULT_LOCALE[\"thousands_separator\"] ) decimal_separator = self.locale_settings.get( \"decimal_separator\", self.DEFAULT_LOCALE[\"decimal_separator\"] )  formatted_number = ( f\"{number:,.{decimal_places}f}\".replace(\",\", \"TEMP\") .replace(\".\", decimal_separator) .replace(\"TEMP\", thousands_separator) ) return formatted_number  def format_currency(self, amount: float) -&gt; str: \"\"\" Format currency  :paramamount: The amount :typeamount: float  :returns:formatted currency :rtype:str \"\"\" currency_symbol = self.locale_settings.get( \"currency_symbol\", self.DEFAULT_LOCALE[\"currency_symbol\"] ) currency_format = self.locale_settings.get( \"currency_format\", self.DEFAULT_LOCALE[\"currency_format\"] )  return currency_format.format( symbol=currency_symbol, amount=self.format_number(amount) )  def update_settings(self, settings: Dict[str, Any]): \"\"\" Update settings  :paramsettings: The settings :typesettings: Dict[str, Any]  :raisesValueError: setting is not recognized \"\"\" for key, value in settings.items(): if key in self.locale_settings: self.locale_settings[key] = value elif key in self.DEFAULT_LOCALE: self.DEFAULT_LOCALE[key] = value else: raise ValueError(f'[l10n] Setting \"{key}\" is not recognized.')  def get_current_settings(self) -&gt; Dict[str, Any]: \"\"\" Gets the current settings.  :returns:The current settings. :rtype:Dict[str, Any] \"\"\" return { \"locale\": self.locale, \"directory\": self.directory, **self.locale_settings, **self.DEFAULT_LOCALE, } <\/code><\/pre>\n<\/div>\n<\/details>\n<h2>\u276f \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043b\u043e\u0433\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h2>\n<p>\u041c\u044b \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438 <code>from logger import loguru<\/code>, \u043d\u043e \u044f \u043d\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u043b \u0447\u0442\u043e \u044d\u0442\u043e. Loguru \u2014 \u044d\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u0430\u044f \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430-\u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0432\u043e\u043a\u0440\u0443\u0433 logging. \u0414\u043b\u044f \u0435\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b logging\/logger.py:<\/p>\n<pre><code class=\"python\">import logging from typing import Union, List from loguru import logger   class InterceptHandler(logging.Handler): \"\"\" This class describes an intercept handler. \"\"\"  def emit(self, record) -&gt; None: \"\"\" Get corresponding Loguru level if it exists  :paramrecord: The record :typerecord: record  :returns:None :rtype:None \"\"\" try: level = logger.level(record.levelname).name except ValueError: level = record.levelno  frame, depth = logging.currentframe(), 2  while frame.f_code.co_filename == logging.__file__: frame = frame.f_back depth += 1  logger.opt(depth=depth, exception=record.exc_info).log( level, record.getMessage() )   def setup_logger(level: Union[str, int] = \"DEBUG\", ignored: List[str] = \"\") -&gt; None: \"\"\" Setup logger  :paramlevel:  The level :typelevel:  str :paramignored:  The ignored :typeignored:  List[str] \"\"\" logging.basicConfig( handlers=[InterceptHandler()], level=logging.getLevelName(level) )  for ignore in ignored: logger.disable(ignore)  logger.add(\"pyechonext.log\")  logger.info(\"Logging is successfully configured\") <\/code><\/pre>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u0432\u044b\u0448\u0435 \u043c\u044b \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u043c \u0444\u0430\u0439\u043b \u043b\u043e\u0433\u0430, \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e.<\/p>\n<h2>\u276f \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u0438\u0432\u0435\u0442 \u0438\u0437 \u043c\u043e\u0435\u0439 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u0440\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 python.<\/p>\n<p>\u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u043a\u043e\u0434, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043a \u0441\u0435\u0431\u0435 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u0438\u0437 <a href=\"https:\/\/habr.com\/ru\/companies\/timeweb\/articles\/848584\">\u043c\u043e\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438<\/a>.<\/p>\n<p>\u041d\u043e \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b \u2014 docsgen\/projgen.py, \u043e\u043d \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e:<\/p>\n<pre><code class=\"python\">from typing import Callable, Any from pyechonext.app import EchoNext from pyechonext.docsgen.document import ( InitiationSection, DocumentFolder, ProjectManager, ProjectTemplate, RoutesSubsection, DocumentSection, )   class ProjDocumentation: \"\"\" This class describes an api documentation. \"\"\"  def __init__(self, echonext_app: EchoNext): \"\"\" Constructs a new instance.  :paramechonext_app:  The echonext application :typeechonext_app:  EchoNext \"\"\" self.app = echonext_app self.app_name = echonext_app.app_name self.pages = {}  def generate_documentation(self): \"\"\" Generate documentation \"\"\" section = self._generate_introduction() self._generate_subsections(section) folder = DocumentFolder( \"api\", f\"{self.app_name}\/docs\", [ section, ], )  project_manager = ProjectManager( f\"{self.app_name}\", \"Project Web Application\", \"Project application based on pyEchoNext web-framework\", f\"{self.app_name}\", f\"{self.app_name}\", f\"{self.app_name}\", ProjectTemplate.BASE, [folder], [section], )  project_manager.process_project()  def _generate_introduction(self) -&gt; InitiationSection: \"\"\" Generate introduction  :returns:The initiation section. :rtype:InitiationSection \"\"\" section = InitiationSection( f\"Project {self.app_name}\", f\"Project Documentation for {self.app_name}\", {\"Routes\": \", \".join(self.app.routes.keys())}, ) return section  def _generate_subsections(self, section: DocumentSection): \"\"\" Generate subsections  :paramsection:  The section :typesection:  DocumentSection \"\"\" subsections = []  for path, data in self.pages.items(): subsections.append( RoutesSubsection( path, { \"Route\": f'Methods: {data[\"methods\"]}\\n\\nReturn type: {data[\"return_type\"]}', \"Extra\": f'Extra: {\"\\n\".join([f\" + {key}: {value}\" for key, value in data[\"extra\"].items()])}', }, section, ) )  for subsection in subsections: section.link_new_subsection(subsection)  def documentate_route( self, page_path: str, return_type: Any, params: dict, methods: list, extra: dict = {}, ) -&gt; Callable: \"\"\" Add routed page to documentation  :parampage_path:  The page path :typepage_path:  str :paramreturn_type:  The return type :typereturn_type:  Any :paramparams:  The parameters :typeparams:  dict :parammethods:  The methods :typemethods:  list :paramextra:  The extra :typeextra:  dict  :returns:wrapper handler :rtype:Callable \"\"\" if page_path in self.pages: return  def wrapper(handler): \"\"\" Wrapper for handler  :paramhandler:  The handler :typehandler:  callable  :returns:handler :rtype:callable \"\"\" self.pages[page_path] = { \"page_path\": page_path, \"doc\": handler.__doc__, \"funcname\": handler.__name__, \"return_type\": return_type, \"params\": params, \"methods\": methods, \"extra\": extra, } return handler  return wrapper <\/code><\/pre>\n<p>\u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0440\u043e\u0443\u0442\u0430 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u0441\u0442\u043e \u043a \u043d\u0443\u0436\u043d\u043e\u043c\u0443 \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u0443 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 documentate_route, \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">@projdoc.documentate_route('\/book', str, {}, ['GET', 'POST']) <\/code><\/pre>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0441\u0435\u043a\u0446\u0438\u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0440\u043e\u0443\u0442\u044b.<\/p>\n<h3>\u276f \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 API<\/h3>\n<p>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f API \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0432 \u0434\u0432\u0443\u0445 \u044d\u0442\u0430\u043f\u0430\u0445: \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0441\u043f\u0435\u0444\u0438\u043a\u0430\u0446\u0438\u0438 OpenAPI \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043a \u043d\u0435\u043c\u0443 html-\u0448\u0430\u0431\u043b\u043e\u043d\u0430.<\/p>\n<p>OpenAPI \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f (OAS, OpenAPI Specification) \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0444\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a REST API \u0441\u0440\u0435\u0432\u0438\u0441\u0443 \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 REST-\u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0431\u0435\u0437 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0435\u0433\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u043e\u0434\u0443 \u0438\u043b\u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438.<\/p>\n<p><a href=\"https:\/\/spec.openapis.org\/oas\/v3.0.0.html\">\u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f 3.0.0 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435.<\/a><\/p>\n<p>\u0412 \u043d\u0430\u0448\u0435\u043c \u043a\u043e\u0434\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">spec = { \"openapi\": \"3.0.0\", \"info\": { \"title\": self._app.app_name, \"version\": self._app.settings.VERSION, \"description\": self._app.settings.DESCRIPTION, }, \"paths\": {  }, } <\/code><\/pre>\n<p>\u0412 paths \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0443\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">class APIDocumentation: \"\"\" This class describes an API documentation. \"\"\"  def __init__(self, app: \"EchoNext\"): \"\"\" Constructs a new instance.  :paramapp:  The application :typeapp:  EchoNext \"\"\" self._app = app  def init_app(self, app: \"EchoNext\"): \"\"\" Initializes the application.  :paramapp:  The application :typeapp:  EchoNext \"\"\" self._app = app  def generate_spec(self) -&gt; str: \"\"\" Generate OpenAPI specficiation from app routes&amp;views  :returns:jsonfied openAPI API specification :rtype:str \"\"\" spec = { \"openapi\": \"3.0.0\", \"info\": { \"title\": self._app.app_name, \"version\": self._app.settings.VERSION, \"description\": self._app.settings.DESCRIPTION, }, \"paths\": {}, }  for url in self._app.urls: spec[\"paths\"][url.url] = { \"get\": { \"summary\": str(f'{url.view.__doc__}. {url.view.get.__doc__}').replace('\\n', '&lt;br&gt;') .strip(), \"responses\": {\"200\": {\"description\": \"Successful response\"}, \"405\": {\"description\": \"Method not allow\"}}, }, \"post\": { \"summary\": str(f'{url.view.__doc__}. {url.view.post.__doc__}').replace('\\n', '&lt;br&gt;') .strip(), \"responses\": {\"200\": {\"description\": \"Successful response\"}, \"405\": {\"description\": \"Method not allow\"}}, } }  for path, handler in self._app.routes.items(): spec[\"paths\"][path] = { \"get\": { \"summary\": str(handler.__doc__) .strip() .replace(\"\\n\", \".\") .replace(\"\\t\", \";\"), \"responses\": {\"200\": {\"description\": \"Successful response\"}, \"405\": {\"description\": \"Method not allow\"}}, }, \"post\": { \"summary\": str(handler.__doc__) .strip() .replace(\"\\n\", \".\") .replace(\"\\t\", \";\"), \"responses\": {\"200\": {\"description\": \"Successful response\"}, \"405\": {\"description\": \"Method not allow\"}}, } }  return spec <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0410 \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043c\u044b \u043c\u043e\u0433\u043b\u0438 \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 html-\u0448\u0430\u0431\u043b\u043e\u043d\u0430<\/p>\n<details class=\"spoiler\">\n<summary>\u0413\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 HTML-\u0448\u0430\u0431\u043b\u043e\u043d\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">   class APIDocUI: \"\"\" This class describes an api document ui. \"\"\"  def __init__(self, specification: dict): \"\"\" Constructs a new instance.  :param      specification:  The specification :type       specification:  dict \"\"\" self.specification = specification  def generate_section(self, route: str, summary_get: str,  summary_post: str, get_responses: dict, post_responses: dict) -&gt; str: \"\"\" generate section  :param      route:           The route :type       route:           str :param      summary_get:     The summary get :type       summary_get:     str :param      summary_post:    The summary post :type       summary_post:    str :param      get_responses:   The get responses :type       get_responses:   dict :param      post_responses:  The post responses :type       post_responses:  dict  :returns:   template section :rtype:     str \"\"\"  template = f''' &lt;div class=\"section\"&gt; &lt;div class=\"section-header\"&gt; &lt;span&gt;{route}&lt;\/span&gt; &lt;span class=\"collapse-icon\"&gt;\u27a1\ufe0f&lt;\/span&gt; &lt;\/div&gt; &lt;div class=\"section-content\"&gt; &lt;div class=\"method\"&gt; &lt;strong&gt;GET&lt;\/strong&gt; &lt;p&gt;{summary_get}&lt;\/p&gt; &lt;div class=\"responses\"&gt; {\"\".join([f\"&lt;div class='response-item'&gt;{key}: {value[\"description\"]}.&lt;\/div&gt;\" for key, value in get_responses.items()])} &lt;\/div&gt; &lt;\/div&gt; &lt;div class=\"method\"&gt; &lt;strong&gt;POST&lt;\/strong&gt; &lt;p&gt;{summary_post}&lt;\/p&gt; &lt;div class=\"responses\"&gt; &lt;div class=\"responses\"&gt; {\"\".join([f\"&lt;div class='response-item'&gt;{key}: {value[\"description\"]}.&lt;\/div&gt;\" for key, value in post_responses.items()])} &lt;\/div&gt; &lt;\/div&gt; &lt;\/div&gt; &lt;\/div&gt; &lt;\/div&gt;            '''  return template  def generate_html_page(self) -&gt; str: \"\"\" Generate html page template  :returns:   template :rtype:     str \"\"\" template = ''' &lt;!DOCTYPE html&gt; &lt;html lang=\"en\"&gt; &lt;head&gt; &lt;meta charset=\"UTF-8\"&gt; &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt; &lt;title&gt;API Documentation&lt;\/title&gt; &lt;style&gt; body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f9f9f9; color: #333; } h1, h2, h3 { margin: 0; padding: 10px 0; } .container { max-width: 800px; margin: 40px auto; padding: 20px; background: #fff; border-radius: 8px; box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1); } .version { font-size: 14px; color: #555; margin-bottom: 20px; } .info-section { border-bottom: 1px solid #ddd; padding-bottom: 20px; margin-bottom: 20px; } .section { border-radius: 5px; overflow: hidden; margin-bottom: 20px; transition: box-shadow 0.3s ease; } .section-header { padding: 15px; background: #007bff; color: white; cursor: pointer; position: relative; font-weight: bold; display: flex; justify-content: space-between; align-items: center; } .section-content { padding: 15px; display: none; overflow: hidden; background-color: #f1f1f1; } .method { border-bottom: 1px solid #ddd; padding: 10px 0; } .method:last-child { border-bottom: none; } .responses { margin-top: 10px; padding-left: 15px; font-size: 14px; color: #555; } .response-item { margin-bottom: 5px; } .collapse-icon { transition: transform 0.3s; } .collapse-icon.collapsed { transform: rotate(90deg); } .section:hover { box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); } &lt;\/style&gt; &lt;\/head&gt; &lt;body&gt;  &lt;div class=\"container\"&gt; &lt;h1&gt;OpenAPI Documentation&lt;\/h1&gt; &lt;h2&gt;PyEchoNext Web Application&lt;\/h2&gt; &lt;div class=\"version\"&gt;OpenAPI Version: {{openapi-version}}&lt;\/div&gt; &lt;div class=\"info-section\"&gt; &lt;h2&gt;Application Information&lt;\/h2&gt; &lt;p&gt;&lt;strong&gt;Title:&lt;\/strong&gt; {{info_title}}&lt;\/p&gt; &lt;p&gt;&lt;strong&gt;Version:&lt;\/strong&gt; {{info_version}}&lt;\/p&gt; &lt;p&gt;&lt;strong&gt;Description:&lt;\/strong&gt; {{info_description}}&lt;\/p&gt; &lt;\/div&gt;  {{sections}}  &lt;script&gt; document.querySelectorAll('.section-header').forEach(header =&gt; { header.addEventListener('click', () =&gt; { const content = header.nextElementSibling; const icon = header.querySelector('.collapse-icon');  if (content.style.display === \"block\") { content.style.display = \"none\"; icon.classList.add('collapsed'); } else { content.style.display = \"block\"; icon.classList.remove('collapsed'); } }); }); &lt;\/script&gt;  &lt;\/body&gt; &lt;\/html&gt;    '''  content = { '{{openapi-version}}': self.specification['openapi'], \"{{info_title}}\": self.specification[\"info\"][\"title\"], \"{{info_version}}\": self.specification[\"info\"][\"version\"], \"{{info_description}}\": self.specification[\"info\"][\"description\"], \"{{sections}}\": \"\\n\".join([self.generate_section(path, value['get']['summary'], value['post']['summary'],  value['get']['responses'],  value['post']['responses']) for path, value in self.specification[\"paths\"].items()]) }  for key, value in content.items(): template = template.replace(key, value)  return template <\/code><\/pre>\n<\/div>\n<\/details>\n<h2>\u276f \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a<\/h2>\n<p>\u041d\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043d\u0443\u0436\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u043c\u0435\u0442\u0430-\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0438\u043b\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u0435\u0449\u0435\u0439.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0439 \u2014 \u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438\u0437 .ini, \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\u043b\u0438 python-\u0444\u0430\u0439\u043b\u0430.<\/p>\n<p>\u0421\u0430\u043c \u043a\u043b\u0430\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u043d \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">@dataclass class Settings: \"\"\" This class describes settings. \"\"\"  BASE_DIR: str TEMPLATES_DIR: str SECRET_KEY: str VERSION: str = \"1.0.0\" DESCRIPTION: str = \"Echonext webapp\" LOCALE: str = \"DEFAULT\" LOCALE_DIR: str = None <\/code><\/pre>\n<ul>\n<li>\n<p>BASE_DIR &#8212; \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u0434\u0438\u0440\u0435\u0442\u043a\u043e\u0440\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>TEMPLATES_DIR &#8212; \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f html-\u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>SECRET_KEY &#8212; \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447<\/p>\n<\/li>\n<li>\n<p>VERSION &#8212; \u0432\u0435\u0440\u0441\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>DESCRIPTION &#8212; \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>LOCALE &#8212; \u043a\u043e\u0434 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>LOCALE_DIR &#8212; \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 .ini \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c configparser, \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f python-dotenv, \u0430 \u0434\u043b\u044f python-\u0444\u0430\u0439\u043b\u043e\u0432 importlib.<\/p>\n<details class=\"spoiler\">\n<summary>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 config.py<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import os import importlib from pathlib import Path from dataclasses import dataclass from enum import Enum from configparser import ConfigParser from dotenv import load_dotenv   def dynamic_import(module: str): \"\"\" Dynamic import with importlib  :parammodule: The module :typemodule: str  :returns:module :rtype:module \"\"\" return importlib.import_module(str(module))   @dataclass class Settings: \"\"\" This class describes settings. \"\"\"  BASE_DIR: str TEMPLATES_DIR: str SECRET_KEY: str VERSION: str = \"1.0.0\" DESCRIPTION: str = \"Echonext webapp\" LOCALE: str = \"DEFAULT\" LOCALE_DIR: str = None   class SettingsConfigType(Enum): \"\"\" This class describes a settings configuration type. \"\"\"  INI = \"ini\" DOTENV = \"dotenv\" PYMODULE = \"pymodule\"   class SettingsLoader: \"\"\" This class describes a settings loader. \"\"\"  def __init__(self, config_type: SettingsConfigType, filename: str = None): \"\"\" Constructs a new instance.  :paramconfig_type:  The configuration type :typeconfig_type:  SettingsConfigType :paramfilename:  The filename :typefilename:  str \"\"\" self.config_type: SettingsConfigType = config_type self.filename: str = filename  self.filename: Path = Path(self.filename)  if not self.filename.exists(): raise FileNotFoundError(f'Config file \"{self.filename}\" don\\'t exists.')  def _load_ini_config(self) -&gt; dict: \"\"\" Loads a .ini config file  :returns:config dictionary :rtype:dict \"\"\" config = ConfigParser() config.read(self.filename)  return config[\"Settings\"]  def _load_env_config(self) -&gt; dict: \"\"\" Loads an environment configuration.  :returns:config dictionary :rtype:dict \"\"\" load_dotenv(self.filename)  config = { \"BASE_DIR\": os.environ.get(\"PEN_BASE_DIR\"), \"TEMPLATES_DIR\": os.environ.get(\"PEN_TEMPLATES_DIR\"), \"SECRET_KEY\": os.environ.get(\"PEN_SECRET_KEY\"), \"LOCALE\": os.environ.get(\"PEN_LOCALE\", \"DEFAULT\"), \"LOCALE_DIR\": os.environ.get(\"PEN_LOCALE_DIR\", None), \"VERSION\": os.environ.get(\"PEN_VERSION\", \"1.0.0\"), \"DESCRIPTION\": os.environ.get(\"PEN_DESCRIPTION\", \"EchoNext webapp\"), }  return config  def _load_pymodule_config(self) -&gt; dict: \"\"\" Loads a pymodule configuration.  :returns:config dictionary :rtype:dict \"\"\" config_module = dynamic_import(str(self.filename).replace(\".py\", \"\"))  return { \"BASE_DIR\": config_module.BASE_DIR, \"TEMPLATES_DIR\": config_module.TEMPLATES_DIR, \"SECRET_KEY\": config_module.SECRET_KEY, \"LOCALE\": config_module.LOCALE, \"LOCALE_DIR\": config_module.LOCALE_DIR, \"VERSION\": config_module.VERSION, \"DESCRIPTION\": config_module.DESCRIPTION, }  def get_settings(self) -&gt; Settings: \"\"\" Gets the settings.  :returns:The settings. :rtype:Settings \"\"\" if self.config_type == SettingsConfigType.INI: self.config = self._load_ini_config() elif self.config_type == SettingsConfigType.DOTENV: self.config = self._load_env_config() elif self.config_type == SettingsConfigType.PYMODULE: self.config = self._load_pymodule_config()  return Settings( BASE_DIR=self.config.get(\"BASE_DIR\", \".\"), TEMPLATES_DIR=self.config.get(\"TEMPLATES_DIR\", \"templates\"), SECRET_KEY=self.config.get(\"SECRET_KEY\", \"\"), LOCALE=self.config.get(\"LOCALE\", \"DEFAULT\"), LOCALE_DIR=self.config.get(\"LOCALE_DIR\", None), VERSION=self.config.get(\"VERSION\", \"1.0.0\"), DESCRIPTION=self.config.get(\"DESCRIPTION\", \"EchoNext webapp\"), ) <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0430:<\/p>\n<h4>DOTENV<\/h4>\n<pre><code class=\"python\">config_loader = SettingsLoader(SettingsConfigType.DOTENV, 'example_env') settings = config_loader.get_settings() <\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b example_env:<\/p>\n<pre><code>PEN_BASE_DIR=. PEN_TEMPLATES_DIR=templates PEN_SECRET_KEY=secret-key PEN_LOCALE=RU_RU PEN_LOCALE_DIR=locales PEN_VERSION=1.0.0 PEN_DESCRIPTION=Example <\/code><\/pre>\n<h4>INI<\/h4>\n<pre><code class=\"python\">config_loader = SettingsLoader(SettingsConfigType.INI, 'example_ini.ini') settings = config_loader.get_settings() <\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b example_ini.ini:<\/p>\n<pre><code>[Settings] BASE_DIR=. TEMPLATES_DIR=templates SECRET_KEY=secret-key LOCALE=DEFAULT VERSION=1.0.0 DESCRIPTION=Example <\/code><\/pre>\n<h4>PyModule<\/h4>\n<pre><code class=\"python\">config_loader = SettingsLoader(SettingsConfigType.PYMODULE, 'example_module.py') settings = config_loader.get_settings() <\/code><\/pre>\n<p>\u0424\u0430\u0439\u043b example_module.py:<\/p>\n<pre><code class=\"python\">import os  BASE_DIR = os.path.dirname(os.path.abspath(__file__)) TEMPLATES_DIR = 'templates' SECRET_KEY = 'secret-key' VERSION = '1.0.0' DESCRIPTION = 'Echonext webapp' LOCALE = 'DEFAULT' LOCALE_DIR = None <\/code><\/pre>\n<h2>\u0420\u0435\u043d\u0434\u0435\u0440 html-\u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432<\/h2>\n<p>\u042f \u0440\u0435\u0448\u0438\u043b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0434\u0432\u0438\u0436\u043e\u043a \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c Jinja2.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 regex-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u0445. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u0434\u0432\u0430:<\/p>\n<pre><code class=\"python\">FOR_BLOCK_PATTERN = re.compile( r\"{% for (?P&lt;variable&gt;[a-zA-Z]+) in (?P&lt;seq&gt;[a-zA-Z]+) %}(?P&lt;content&gt;[\\S\\s]+)(?={% endfor %}){% endfor %}\" ) VARIABLE_PATTERN = re.compile(r\"{{ (?P&lt;variable&gt;[a-zA-Z_]+) }}\") <\/code><\/pre>\n<p>\u041e\u043d \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 Jinja2. \u0414\u043b\u044f for-\u0446\u0438\u043a\u043b\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044e <code>{% for ... in ... %}{% endfor %}<\/code>, \u0430 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 <code>{{ &lt;\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f&gt; }}<\/code>.<\/p>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u043c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.<\/p>\n<p>\u0414\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>render_template(request: Request, template_name: str, **kwargs)<\/code>. \u0415\u0439 \u043d\u0443\u0436\u0435\u043d Request, \u0438\u043c\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430 (\u0431\u0435\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438), \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 &#8212; \u0442\u043e \u0435\u0441\u0442\u044c kwargs. \u0422\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 <code>render_template(request, 'index.html', name=\"Vasya\")<\/code> \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e name.<\/p>\n<details class=\"spoiler\">\n<summary>\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">import os import re from loguru import logger from pyechonext.request import Request from pyechonext.utils.exceptions import TemplateNotFileError  FOR_BLOCK_PATTERN = re.compile( r\"{% for (?P&lt;variable&gt;[a-zA-Z]+) in (?P&lt;seq&gt;[a-zA-Z]+) %}(?P&lt;content&gt;[\\S\\s]+)(?={% endfor %}){% endfor %}\" ) VARIABLE_PATTERN = re.compile(r\"{{ (?P&lt;variable&gt;[a-zA-Z_]+) }}\")   class TemplateEngine: \"\"\" This class describes a built-in template engine. \"\"\"  def __init__(self, base_dir: str, templates_dir: str): \"\"\" Constructs a new instance.  :parambase_dir:The base dir :typebase_dir:str :paramtemplates_dir:The templates dir :typetemplates_dir:str \"\"\" self.templates_dir = os.path.join(base_dir, templates_dir)  def _get_template_as_string(self, template_name: str) -&gt; str: \"\"\" Gets the template as string.  :paramtemplate_name:   The template name :typetemplate_name:   str  :returns:The template as string. :rtype:str  :raisesTemplateNotFileError:  Template is not a file \"\"\" template_name = os.path.join(self.templates_dir, template_name)  if not os.path.isfile(template_name): raise TemplateNotFileError(f'Template \"{template_name}\" is not a file')  with open(template_name, \"r\") as file: content = file.read()  return content  def _build_block_of_template(self, context: dict, raw_template_block: str) -&gt; str: \"\"\" Builds a block of template.  :paramcontext: The context :typecontext: dict :paramraw_template_block: The raw template block :typeraw_template_block: str  :returns:The block of template. :rtype:str \"\"\" used_vars = VARIABLE_PATTERN.findall(raw_template_block)  if used_vars is None: return raw_template_block  for var in used_vars: var_in_template = \"{{ %s }}\" % (var) processed_template_block = re.sub( var_in_template, str(context.get(var, \"\")), raw_template_block )  return processed_template_block  def _build_statement_for_block(self, context: dict, raw_template_block: str) -&gt; str: \"\"\" Build statement `for` block  :paramcontext: The context :typecontext: dict :paramraw_template_block: The raw template block :typeraw_template_block: str  :returns:The statement for block. :rtype:str \"\"\" statement_for_block = FOR_BLOCK_PATTERN.search(raw_template_block)  if statement_for_block is None: return raw_template_block  builded_statement_block_for = \"\"  for variable in context.get(statement_for_block.group(\"seq\"), []): builded_statement_block_for += self._build_block_of_template( {**context, statement_for_block.group(\"variable\"): variable}, statement_for_block.group(\"content\"), )  processed_template_block = FOR_BLOCK_PATTERN.sub( builded_statement_block_for, raw_template_block )  return processed_template_block  def build(self, context: dict, template_name: str) -&gt; str: \"\"\" Build template  :paramcontext:The context :typecontext:dict :paramtemplate_name:The template name :typetemplate_name:str  :returns:raw template string :rtype:str \"\"\" raw_template = self._get_template_as_string(template_name)  processed_template = self._build_statement_for_block(context, raw_template)  return self._build_block_of_template(context, processed_template)   def render_template(request: Request, template_name: str, **kwargs) -&gt; str: \"\"\" Render template  :paramrequest: The request :typerequest: Request :paramtemplate_name: The template name :typetemplate_name: str :paramkwargs: The keywords arguments :typekwargs: dictionary  :returns:raw template string :rtype:str  :raisesAssertionError: BASE_DIR and TEMPLATES_DIR is empty \"\"\" logger.warn( \"Built-in template engine is under development and may be unstable or contain bugs\" )  assert request.settings.BASE_DIR assert request.settings.TEMPLATES_DIR  engine = TemplateEngine(request.settings.BASE_DIR, request.settings.TEMPLATES_DIR)  context = kwargs  logger.debug(f\"Built-in template engine: render {template_name} ({request.path})\")  return engine.build(context, template_name) <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f Jinja2 \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436\u0438\u0439 \u043a\u043e\u0434, \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 Jinja2<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">from os.path import join, exists, getmtime from jinja2 import BaseLoader, TemplateNotFound from jinja2 import Environment, select_autoescape from loguru import logger from pyechonext.request import Request   class TemplateLoader(BaseLoader): \"\"\" This class describes a jinja2 template loader. \"\"\"  def __init__(self, path: str): \"\"\" Constructs a new instance.  :parampath:  The path :typepath:  str \"\"\" self.path = path  def get_source(self, environment, template): path = join(self.path, template)  if not exists(path): raise TemplateNotFound(template)  mtime = getmtime(path)  with open(path) as f: source = f.read()  return source, path, lambda: mtime == getmtime(path)   class TemplateEngine: \"\"\" This class describes a jinja template engine. \"\"\"  def __init__(self, base_dir: str, templates_dir: str): \"\"\" Constructs a new instance.  :parambase_dir:The base dir :typebase_dir:str :paramtemplates_dir:The templates dir :typetemplates_dir:str \"\"\" self.base_dir = base_dir self.templates_dir = join(base_dir, templates_dir) self.env = Environment( loader=TemplateLoader(self.templates_dir), autoescape=select_autoescape() )  def build(self, template_name: str, **kwargs): template = self.env.get_template(template_name)  return template.render(**kwargs)   def render_template(request: Request, template_name: str, **kwargs) -&gt; str: \"\"\" Render template  :paramrequest: The request :typerequest: Request :paramtemplate_name: The template name :typetemplate_name: str :paramkwargs: The keywords arguments :typekwargs: dictionary  :returns:raw template string :rtype:str  :raisesAssertionError: BASE_DIR and TEMPLATES_DIR is empty \"\"\" assert request.settings.BASE_DIR assert request.settings.TEMPLATES_DIR  engine = TemplateEngine(request.settings.BASE_DIR, request.settings.TEMPLATES_DIR)  logger.debug(f\"Jinja2 template engine: render {template_name} ({request.path})\")  return engine.build(template_name, **kwargs) <\/code><\/pre>\n<\/div>\n<\/details>\n<h2>\u276f \u041e\u0442\u0432\u0435\u0442-\u0437\u0430\u043f\u0440\u043e\u0441<\/h2>\n<blockquote>\n<p>\u0411\u0443\u0434\u044c \u0442\u044b \u0432 \u0420\u044b\u0431\u0430\u0446\u043a\u0438\u043d\u043e, \u0438\u043b\u0438 \u044e\u0436\u043d\u044b\u0439 \u0411\u0440\u043e\u043c\u0441. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0440\u0435\u043a\u0432\u0435\u0441\u0442, \u0437\u043d\u0430\u0447\u0438\u0442 \u0435\u0441\u0442\u044c \u0440\u0435\u0441\u043f\u043e\u043d\u0441.<\/p>\n<\/blockquote>\n<p>\u0412 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u043a\u0435 \u0437\u0430\u043f\u0440\u043e\u0441-\u043e\u0442\u0432\u0435\u0442 \u0438\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441-\u0440\u0435\u043f\u043b\u0438\u043a\u0430 \u2014 \u044d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430\u043c\u0438 \u0434\u043b\u044f \u0441\u0432\u044f\u0437\u0438 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u0432 \u0441\u0435\u0442\u0438, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441. \u0411\u043e\u043b\u0435\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e, \u044d\u0442\u043e \u0448\u0430\u0431\u043b\u043e\u043d \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0449\u0438\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u0435-\u043e\u0442\u0432\u0435\u0442\u0447\u0438\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0441\u0447\u0435\u0442\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u043e\u0442\u0432\u0435\u0442. \u042d\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043d\u043e\u043c\u0443 \u0437\u0432\u043e\u043d\u043a\u0443, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0430\u0431\u043e\u043d\u0435\u043d\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0434\u043e\u0436\u0434\u0430\u0442\u044c\u0441\u044f, \u043f\u043e\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044c \u0432\u043e\u0437\u044c\u043c\u0435\u0442 \u0442\u0440\u0443\u0431\u043a\u0443, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0447\u0442\u043e-\u043b\u0438\u0431\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c.<\/p>\n<h3>\u276f Request<\/h3>\n<p><strong>Request<\/strong> \u2014 \u044d\u0442\u043e \u0437\u0430\u043f\u0440\u043e\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 API: \u0431\u0430\u0437\u043e\u0432\u044b\u0439 URL, \u043a\u043e\u043d\u0435\u0447\u043d\u0443\u044e \u0442\u043e\u0447\u043a\u0443, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u043c\u0435\u0442\u043e\u0434, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0438 \u0442. \u0434.<\/p>\n<p>\u0421\u0430\u043c \u043a\u043b\u0430\u0441\u0441 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">class Request: \"\"\" This class describes a request. \"\"\"  def __init__(self, environ: dict, settings: Settings): \"\"\" Constructs a new instance.  :paramenviron:  The environ :typeenviron:  dict \"\"\" self.environ: dict = environ self.settings: Settings = settings self.method: str = self.environ[\"REQUEST_METHOD\"] self.path: str = self.environ[\"PATH_INFO\"] self.GET: dict = self._build_get_params_dict(self.environ[\"QUERY_STRING\"]) self.POST: dict = self._build_post_params_dict(self.environ[\"wsgi.input\"].read()) self.user_agent: str = self.environ[\"HTTP_USER_AGENT\"] self.extra: dict = {}  logger.debug(f\"New request created: {self.method} {self.path}\")  def __getattr__(self, item: Any) -&gt; Union[Any, None]: \"\"\" Magic method for get attrs (from extra)  :paramitem:  The item :typeitem:  Any  :returns:Item from self.extra or None :rtype:Union[Any, None] \"\"\" return self.extra.get(item, None)  def _build_get_params_dict(self, raw_params: str): \"\"\" Builds a get parameters dictionary.  :paramraw_params: The raw parameters :typeraw_params: str \"\"\" return parse_qs(raw_params)  def _build_post_params_dict(self, raw_params: bytes): \"\"\" Builds a post parameters dictionary.  :paramraw_params: The raw parameters :typeraw_params: bytes \"\"\" return parse_qs(raw_params.decode()) <\/code><\/pre>\n<p>Request \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f:<\/p>\n<ul>\n<li>\n<p>environ (\u0441\u043b\u043e\u0432\u0430\u0440\u044c) \u2014 \u0432\u0435\u0431-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 (\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f gunicorn).<\/p>\n<\/li>\n<li>\n<p>settings (\u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u0430\u0442\u0430\u043a\u043b\u0430\u0441\u0441\u0430 pyechonext.config.Settings).<\/p>\n<\/li>\n<\/ul>\n<p>Request \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>environ (\u0441\u043b\u043e\u0432\u0430\u0440\u044c) \u2014 \u0432\u0435\u0431-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>settings (\u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u0430\u0442\u0430\u043a\u043b\u0430\u0441\u0441\u0430 pyechonext.config.Settings).<\/p>\n<\/li>\n<li>\n<p>method (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 http-\u043c\u0435\u0442\u043e\u0434.<\/p>\n<\/li>\n<li>\n<p>path (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 \u043f\u0443\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>GET (\u0441\u043b\u043e\u0432\u0430\u0440\u044c) \u2014 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b get-\u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>POST (\u0441\u043b\u043e\u0432\u0430\u0440\u044c) \u2014 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b post-\u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>user_agent (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 User-Agent.<\/p>\n<\/li>\n<li>\n<p>extra (\u0441\u043b\u043e\u0432\u0430\u0440\u044c) \u2014 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f middleware).<\/p>\n<\/li>\n<\/ul>\n<p>Request \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b:<\/p>\n<ul>\n<li>\n<p><code>__getattr__<\/code> \u2014 \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 (\u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u0437 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 extra).<\/p>\n<\/li>\n<li>\n<p><code>_build_get_params_dict<\/code> \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 get-\u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p><code>_build_post_params_dict<\/code> \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 post-\u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<\/ul>\n<h3>\u276f Response<\/h3>\n<p><strong>Response<\/strong> \u2014 \u044d\u0442\u043e \u043e\u0442\u0432\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u043a\u043e\u0434 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438.<\/p>\n<pre><code class=\"python\">import json from typing import Dict, Iterable, Union, Any, List, Tuple, Optional from socks import method from loguru import logger from pyechonext.request import Request   class Response: \"\"\" This dataclass describes a response. \"\"\"  default_content_type: str = \"text\/html\" default_charset: str = \"UTF-8\" unicode_errors: str = \"strict\" default_conditional_response: bool = False default_body_encoding: str = \"UTF-8\"  def __init__( self, request: Request, use_i18n: bool = False, status_code: Optional[int] = 200, body: Optional[str] = None, headers: Optional[Dict[str, str]] = {}, content_type: Optional[str] = None, charset: Optional[str] = None, **kwargs, ): \"\"\" Constructs a new instance.  :paramrequest:   The request :typerequest:   Request :paramuse_i18n:   The use i 18 n :typeuse_i18n:   bool :paramstatus_code:   The status code :typestatus_code:   int :parambody:   The body :typebody:   str :paramheaders:   The headers :typeheaders:   Dict[str, str] :paramcontent_type:  The content type :typecontent_type:  str :paramcharset:   The charset :typecharset:   str :paramkwargs:   The keywords arguments :typekwargs:   dictionary \"\"\" if status_code == 200: self.status_code: str = \"200 OK\" else: self.status_code: str = str(status_code)  if content_type is None: self.content_type: str = self.default_content_type else: self.content_type: str = content_type  if charset is None: self.charset: str = self.default_charset else: self.charset: str = charset  if body is not None: self.body: str = body else: self.body: str = \"\"  self._headerslist: list = headers self._added_headers: list = [] self.request: Request = request self.extra: dict = {}  self.use_i18n: bool = use_i18n self.i18n_kwargs = kwargs  self._update_headers()  def __getattr__(self, item: Any) -&gt; Union[Any, None]: \"\"\" Magic method for get attrs (from extra)  :paramitem:  The item :typeitem:  Any  :returns:Item from self.extra or None :rtype:Union[Any, None] \"\"\" return self.extra.get(item, None)  def _structuring_headers(self, environ): headers = { \"Host\": environ[\"HTTP_HOST\"], \"Accept\": environ[\"HTTP_ACCEPT\"], \"User-Agent\": environ[\"HTTP_USER_AGENT\"], }  for name, value in headers.items(): self._headerslist.append((name, value))  for header_tuple in self._added_headers: self._headerslist.append(header_tuple)  def _update_headers(self) -&gt; None: \"\"\" Sets the headers by environ.  :paramenviron:  The environ :typeenviron:  dict \"\"\" self._headerslist = [ (\"Content-Type\", f\"{self.content_type}; charset={self.charset}\"), (\"Content-Length\", str(len(self.body))), ]  def add_headers(self, headers: List[Tuple[str, str]]): \"\"\" Adds new headers.  :paramheaders:  The headers :typeheaders:  List[Tuple[str, str]] \"\"\" for header in headers: self._added_headers.append(header)  def _encode_body(self): \"\"\" Encodes a body. \"\"\" if self.content_type.split(\"\/\")[-1] == \"json\": self.body = str(self.json)  try: self.body = self.body.encode(\"UTF-8\") except AttributeError: self.body = str(self.body).encode(\"UTF-8\")  def __call__(self, environ: dict, start_response: method) -&gt; Iterable: \"\"\" Makes the Response object callable.  :paramenviron: The environ :typeenviron: dict :paramstart_response: The start response :typestart_response: method  :returns:response body :rtype:Iterable \"\"\" self._encode_body()  self._update_headers() self._structuring_headers(environ)  logger.debug( f\"[{environ['REQUEST_METHOD']} {self.status_code}] Run response: {self.content_type}\" )  start_response(status=self.status_code, headers=self._headerslist)  return iter([self.body])  @property def json(self) -&gt; dict: \"\"\" Parse request body as JSON.  :returns:json body :rtype:dict \"\"\" if self.body: if self.content_type.split(\"\/\")[-1] == \"json\": return json.dumps(self.body) else: return json.dumps(self.body.decode(\"UTF-8\"))  return {}  def __repr__(self): \"\"\" Returns a unambiguous string representation of the object (for debug...).  :returns:String representation of the object. :rtype:str \"\"\" return f\"&lt;{self.__class__.__name__} at 0x{abs(id(self)):x} {self.status_code}&gt;\" <\/code><\/pre>\n<p>Response \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>request (\u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 Request) \u2014 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<li>\n<p>[\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e] status_code (\u0446\u0435\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435) \u2014 \u0441\u0442\u0430\u0442\u0443\u0441-\u043a\u043e\u0434 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>[\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e] body (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>[\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e] headers (\u0441\u043b\u043e\u0432\u0430\u0440\u044c) \u2014 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>[\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e] content_type (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 \u0442\u0438\u043f \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>[\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e] charset (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>[\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e] use_i18n (\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435) \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u0438 i18n (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e False).<\/p>\n<\/li>\n<\/ul>\n<p>Response \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>status_code (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 \u0441\u0442\u0430\u0442\u0443\u0441-\u043a\u043e\u0434 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e &#171;200 OK&#187;).<\/p>\n<\/li>\n<li>\n<p>content_type (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 \u043a\u043e\u043d\u0442\u0435\u043d\u0442-\u0442\u0438\u043f (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0440\u0430\u0432\u0435\u043d \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e default_content_type).<\/p>\n<\/li>\n<li>\n<p>charset (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0430 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0440\u0430\u0432\u0435\u043d \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e default_charset).<\/p>\n<\/li>\n<li>\n<p>body (\u0441\u0442\u0440\u043e\u043a\u0430) \u2014 \u0442\u0435\u043b\u043e \u043e\u0432\u0442\u0435\u0442\u0430 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0440\u0430\u0432\u0435\u043d \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435).<\/p>\n<\/li>\n<li>\n<p><code>_headerslist<\/code> (\u0441\u043f\u0438\u0441\u043e\u043a) \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>_added_headers<\/code> (\u0441\u043f\u0438\u0441\u043e\u043a) \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>request (\u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 Request) \u2014 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<li>\n<p>extra (\u0441\u043b\u043e\u0432\u0430\u0440\u044c) \u2014 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b.<\/p>\n<\/li>\n<\/ul>\n<p>Response \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u044b:<\/p>\n<ul>\n<li>\n<p><code>__getattr__<\/code> \u2014 \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 (\u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u0437 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 extra).<\/p>\n<\/li>\n<li>\n<p><code>_structuring_headers<\/code> \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0438\u0437 \u0432\u0435\u0431-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><code>_update_headers<\/code> \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f (\u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u044f) \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><code>add_headers<\/code> \u2014 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><code>_encode_body<\/code> \u2014 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><code>__call__<\/code> \u2014 \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434, \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 Response \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u043c.<\/p>\n<\/li>\n<li>\n<p><code>json<\/code> \u2014 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u043b\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u0432 \u0432\u0438\u0434\u0435 json.<\/p>\n<\/li>\n<\/ul>\n<h2>\u276f Views (\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438)<\/h2>\n<p>View \u2014 \u044d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0441\u0430\u0439\u0442\u0430 (django-like). \u041e\u043d \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0434\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430: <code>get<\/code> \u0438 <code>post<\/code> (\u0434\u043b\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0430 get \u0438 post \u0437\u0430\u043f\u0440\u043e\u0441\u044b). \u042d\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0438\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u041b\u0418:<\/p>\n<ul>\n<li>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 Response (pyechonext.response)<\/p>\n<\/li>\n<\/ul>\n<p>View \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 View:<\/p>\n<pre><code class=\"python\">class View(ABC): \"\"\" Page view \"\"\"  @abstractmethod def get( self, request: Request, response: Response, *args, **kwargs ) -&gt; Union[Response, Any]: \"\"\" Get  :paramrequest:   The request :typerequest:   Request :paramresponse:  The response :typeresponse:  Response :paramargs:   The arguments :typeargs:   list :paramkwargs:   The keywords arguments :typekwargs:   dictionary \"\"\" raise NotImplementedError  @abstractmethod def post( self, request: Request, response: Response, *args, **kwargs ) -&gt; Union[Response, Any]: \"\"\" Post  :paramrequest:   The request :typerequest:   Request :paramresponse:  The response :typeresponse:  Response :paramargs:   The arguments :typeargs:   list :paramkwargs:   The keywords arguments :typekwargs:   dictionary \"\"\" raise NotImplementedError <\/code><\/pre>\n<p>\u0418 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u043f\u0440\u0438\u043c\u0435\u0440 View:<\/p>\n<pre><code class=\"python\">class IndexView(View): def get( self, request: Request, response: Response, **kwargs ) -&gt; Union[Response, Any]: \"\"\" Get  :paramrequest:   The request :typerequest:   Request :paramresponse:  The response :typeresponse:  Response :paramargs:   The arguments :typeargs:   list :paramkwargs:   The keywords arguments :typekwargs:   dictionary \"\"\" return \"Welcome to pyEchoNext webapplication!\"  def post( self, request: Request, response: Response, **kwargs ) -&gt; Union[Response, Any]: \"\"\" Post  :paramrequest:   The request :typerequest:   Request :paramresponse:  The response :typeresponse:  Response :paramargs:   The arguments :typeargs:   list :paramkwargs:   The keywords arguments :typekwargs:   dictionary \"\"\" return \"Message has accepted!\" <\/code><\/pre>\n<h2>\u276f URLS<\/h2>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c Views \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e, \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043b\u043e\u0439 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438 &#8212; \u0434\u0430\u0442\u0430\u043a\u043b\u0430\u0441\u0441 URL, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u043f\u0443\u0442\u044c \u0438 \u0441\u0430\u043c \u043a\u043b\u0430\u0441\u0441 View. \u041f\u0440\u0438\u0447\u0435\u043c View \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0431\u0435\u0437 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0442\u043e \u0435\u0441\u0442\u044c \u0441\u0430\u043c \u043a\u043b\u0430\u0441\u0441.<\/p>\n<pre><code class=\"python\">from dataclasses import dataclass from typing import Type from pyechonext.views import View, IndexView   @dataclass class URL: \"\"\" This dataclass describes an url. \"\"\"  url: str view: Type[View]   url_patterns = [URL(url=\"\/\", view=IndexView)] <\/code><\/pre>\n<p>url_patterns \u2014 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 IndexView.<\/p>\n<h2>\u276f Middleware (\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0435 \u041f\u041e)<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, cookie \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0440\u0435\u043a\u0432\u0435\u0441\u0442-\u0440\u0435\u0441\u043f\u043e\u043d\u0441\u043e\u043c \u0432\u043e \u0432\u0440\u0435\u0431\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044e \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u041f\u041e.<\/p>\n<pre><code class=\"python\">class BaseMiddleware(ABC): \"\"\" This abstract class describes a base middleware. \"\"\"  @abstractmethod def to_request(self, request: Request): \"\"\" To request method  :paramrequest:  The request :typerequest:  Request \"\"\" raise NotImplementedError  @abstractmethod def to_response(self, response: Response): \"\"\" To response method  :paramresponse:  The response :typeresponse:  Response \"\"\" raise NotImplementedError <\/code><\/pre>\n<p>\u041e\u043d \u0438\u043c\u0435\u0435\u0442 \u0434\u0432\u0430 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u0430 \u2014 to_request \u0438 to_response.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 Middleware \u0441\u0435\u0441\u0441\u0438\u0438 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f cookie:<\/p>\n<pre><code class=\"python\">class SessionMiddleware(BaseMiddleware): \"\"\" This class describes a session (cookie) middleware. \"\"\"  def to_request(self, request: Request): \"\"\" Set to request  :paramrequest:  The request :typerequest:  Request \"\"\" cookie = request.environ.get(\"HTTP_COOKIE\", None)  if not cookie: return  session_id = parse_qs(cookie)[\"session_id\"][0] logger.debug( f\"Set session_id={session_id} for request {request.method} {request.path}\" ) request.extra[\"session_id\"] = session_id  def to_response(self, response: Response): \"\"\" Set to response  :paramresponse:  The response :typeresponse:  Response \"\"\" if not response.request.session_id: session_id = uuid4() logger.debug( f\"Set session_id={session_id} for response {response.status_code} {response.request.path}\" ) response.add_headers( [ (\"Set-Cookie\", f\"session_id={session_id}\"), ] )   middlewares = [SessionMiddleware] # \u0421\u043f\u0438\u0441\u043e\u043a \u043c\u0438\u0434\u043b\u0432\u0430\u0440\u0435\u0439 <\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0441\u0430\u043c\u0438\u043c app.py \u2014 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c.<\/p>\n<h2>\u276f \u0423\u0442\u0438\u043b\u0438\u0442\u044b<\/h2>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0430\u0439\u043b <code>utils\/__init__.py<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>_prepare_url<\/code>. \u041e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0435\u0437\u0430\u0442\u044c URL \u043e\u0442 \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u043d\u0435\u0433\u043e:<\/p>\n<pre><code class=\"python\">from datetime import datetime   def get_current_datetime() -&gt; str: \"\"\" Gets the current datetime.  :returns:The current datetime. :rtype:str \"\"\" date = datetime.now() return date.strftime(\"%Y-%m-%d %H:%M:%S\")   def _prepare_url(url: str) -&gt; str: \"\"\" Prepare URL (remove ending \/)  :paramurl:  The url :typeurl:  str  :returns:prepared url :rtype:str \"\"\" try: if url[-1] == \"\/\" and len(url) &gt; 1: return url[:-1] except IndexError: return \"\/\"  return url <\/code><\/pre>\n<h2>\u276f \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041e\u0441\u043d\u043e\u0432\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441 EchoNext (pyechonext.app).<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0433\u043e.<\/p>\n<p>\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0432\u0441\u0435 \u043d\u0443\u0436\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438:<\/p>\n<pre><code class=\"python\">import inspect from enum import Enum from typing import Iterable, Callable, List, Type, Tuple, Optional, Union from dataclasses import dataclass from socks import method from parse import parse from loguru import logger from pyechonext.urls import URL from pyechonext.views import View from pyechonext.request import Request from pyechonext.response import Response from pyechonext.utils.exceptions import ( RoutePathExistsError, MethodNotAllow, URLNotFound, WebError, TeapotError, ) from pyechonext.utils import _prepare_url from pyechonext.config import Settings from pyechonext.middleware import BaseMiddleware from pyechonext.i18n_l10n.i18n import JSONi18nLoader from pyechonext.i18n_l10n.l10n import JSONLocalizationLoader <\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0430\u0442\u0430\u043a\u043b\u0430\u0441\u0441 \u0442\u0438\u043f\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"python\">class ApplicationType(Enum): \"\"\" This enum class describes an application type. \"\"\"  JSON = \"application\/json\" HTML = \"text\/html\" PLAINTEXT = \"text\/plain\" TEAPOT = \"server\/teapot\" <\/code><\/pre>\n<ul>\n<li>\n<p>JSON \u2014 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043b\u044f API.<\/p>\n<\/li>\n<li>\n<p>HTML \u2014 \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>PLAINTEXT \u2014 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0435\u043a\u0441\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0430\u0442\u0430\u043a\u043b\u0430\u0441\u0441 HistoryEntry \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432-\u043e\u0442\u0432\u0435\u0442\u043e\u0432:<\/p>\n<pre><code class=\"python\">@dataclass class HistoryEntry: request: Request response: Response <\/code><\/pre>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0447\u043d\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"python\">class EchoNext: \"\"\" This class describes an EchoNext WSGI Application. \"\"\"  __slots__ = ( \"app_name\", \"settings\", \"middlewares\", \"application_type\", \"urls\", \"routes\", \"i18n_loader\", \"l10n_loader\", \"history\", ) <\/code><\/pre>\n<p><code>__slots__<\/code> \u2014 \u044d\u0442\u043e \u0441\u043b\u043e\u0442\u044b (\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u044b \u0432 \u043a\u043e\u0440\u0442\u0435\u0436\u0435). \u042d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u0438 \u0438 \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c \u043a\u043b\u0430\u0441\u0441\u0430. \u041a\u043e\u0433\u0434\u0430 \u0432\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0435 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 \u0432 Python, \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440 \u0432\u044b\u0434\u0435\u043b\u044f\u0435\u0442 \u043f\u0430\u043c\u044f\u0442\u044c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430:<\/p>\n<pre><code class=\"python\">def __init__( self, app_name: str, settings: Settings, middlewares: List[Type[BaseMiddleware]], urls: Optional[List[URL]] = [], application_type: Optional[ApplicationType] = ApplicationType.JSON, ): \"\"\" Constructs a new instance.  :paramapp_name:   The application name :typeapp_name:   str :paramsettings:   The settings :typesettings:   Settings :parammiddlewares:   The middlewares :typemiddlewares:   List[BaseMiddleware] :paramurls:   The urls :typeurls:   List[URL] :paramapplication_type:  The application type :typeapplication_type:  Optional[ApplicationType] \"\"\" self.app_name = app_name self.settings = settings self.middlewares = middlewares self.application_type = application_type self.routes = {} self.urls = urls self.history: List[HistoryEntry] = [] self.i18n_loader = JSONi18nLoader( self.settings.LOCALE, self.settings.LOCALE_DIR ) self.l10n_loader = JSONLocalizationLoader( self.settings.LOCALE, self.settings.LOCALE_DIR ) logger.debug(f\"Application {self.application_type.value}: {self.app_name}\")  if self.application_type == ApplicationType.TEAPOT: raise TeapotError(\"Where's my coffie?\") <\/code><\/pre>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>app_name \u2014 \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>settings \u2014 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0434\u0430\u0442\u0430\u043a\u043b\u0430\u0441\u0441\u0430 Settings.<\/p>\n<\/li>\n<li>\n<p>middlewares \u2014 \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u0438\u0434\u0434\u043b\u0432\u0430\u0440\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>application_type \u2014 \u0442\u0438\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>routes \u2014 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b\u043b\u0438 \u0437\u0430\u0434\u0430\u043d\u044b \u0447\u0435\u0440\u0435\u0437 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 route_page (flask-like \u043f\u0443\u0442\u044c, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u0437\u0436\u0435).<\/p>\n<\/li>\n<li>\n<p>urls \u2014 \u0441\u043f\u0438\u0441\u043e\u043a URLs (\u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 View).<\/p>\n<\/li>\n<li>\n<p>history \u2014 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437 HistoryEntry. \u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432-\u043e\u0442\u0432\u0435\u0442\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>i18n_loader \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a i18n.<\/p>\n<\/li>\n<li>\n<p>l10n_loader \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a l10n.<\/p>\n<\/li>\n<\/ul>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0442\u043e\u0434:<\/p>\n<pre><code class=\"python\">def _find_view(self, raw_url: str) -&gt; Union[Type[URL], None]: \"\"\" Finds a view by raw url.  :paramraw_url:  The raw url :typeraw_url:  str  :returns:URL dataclass :rtype:Type[URL] \"\"\" url = _prepare_url(raw_url)  for path in self.urls: if url == _prepare_url(path.url): return path  return None <\/code><\/pre>\n<p>\u041e\u043d \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f view \u043f\u043e \u0441\u044b\u0440\u043e\u043c\u0443 URL. \u0415\u0441\u043b\u0438 \u043e\u043d \u043d\u0430\u0439\u0434\u0435\u043d, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c URL, \u0438\u043d\u0430\u0447\u0435 None.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <code>_check_request_method<\/code>:<\/p>\n<pre><code class=\"python\">def _check_request_method(self, view: View, request: Request): \"\"\" Check request method for view  :paramview: The view :typeview: View :paramrequest: The request :typerequest: Request  :raisesMethodNotAllow: Method not allow \"\"\" if not hasattr(view, request.method.lower()): raise MethodNotAllow(f\"Method not allow: {request.method}\") <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043b\u0438 \u043c\u0435\u0442\u043e\u0434 \u0432 View.<\/p>\n<pre><code class=\"python\">def _get_view(self, request: Request) -&gt; View: \"\"\" Gets the view.  :paramrequest:  The request :typerequest:  Request  :returns:The view. :rtype:View \"\"\" url = request.path  return self._find_view(url) <\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 \u0432\u044b\u0448\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u043e \u043f\u0443\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 View.<\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043e\u0442\u0432\u0435\u0442:<\/p>\n<pre><code class=\"python\">def _get_request(self, environ: dict) -&gt; Request: \"\"\" Gets the request.  :paramenviron:  The environ :typeenviron:  dict  :returns:The request. :rtype:Request \"\"\" return Request(environ, self.settings)  def _get_response(self, request: Request) -&gt; Response: \"\"\" Gets the response.  :returns:The response. :rtype:Response \"\"\" return Response(request, content_type=self.application_type.value) <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 route_page:<\/p>\n<pre><code class=\"python\">def route_page(self, page_path: str) -&gt; Callable: \"\"\" Creating a New Page Route  :parampage_path:The page path :typepage_path:str  :returns:wrapper handler :rtype:Callable \"\"\" if page_path in self.routes: raise RoutePathExistsError(\"Such route already exists.\")  def wrapper(handler): \"\"\" Wrapper for handler  :paramhandler:  The handler :typehandler:  callable  :returns:handler :rtype:callable \"\"\" self.routes[page_path] = handler return handler  return wrapper <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u0438\u0434\u0434\u043b\u0432\u0430\u0440\u0435\u0439 \u043a \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0443:<\/p>\n<pre><code class=\"python\">def _apply_middleware_to_request(self, request: Request): \"\"\" Apply middleware to request  :paramrequest:  The request :typerequest:  Request \"\"\" for middleware in self.middlewares: middleware().to_request(request)  def _apply_middleware_to_response(self, response: Response): \"\"\" Apply middleware to response  :paramresponse:  The response :typeresponse:  Response \"\"\" for middleware in self.middlewares: middleware().to_response(response) <\/code><\/pre>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u0435\u0442\u0430. \u0422\u043e \u0435\u0441\u0442\u044c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0440\u0435\u0441\u043f\u043e\u043d\u0441\u0443 \u043a\u043e\u0434 404 \u0435\u0441\u043b\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430:<\/p>\n<pre><code class=\"python\">def _default_response(self, response: Response, error: WebError) -&gt; None: \"\"\" Get default response (404)  :paramresponse:  The response :typeresponse:  Response \"\"\" response.status_code = str(error.code) response.body = str(error) <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0445\u0435\u043d\u0434\u043b\u0435\u0440\u0430. \u041a\u0441\u0442\u0430\u0442\u0438, \u0443 \u043c\u0435\u043d\u044f View \u0438\u043c\u0435\u044e\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u0439 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u0447\u0435\u043c routes:<\/p>\n<pre><code class=\"python\">def _find_handler(self, request: Request) -&gt; Tuple[Callable, str]: \"\"\" Finds a handler.  :paramrequest_path:  The request path :typerequest_path:  str  :returns:handler function and parsed result :rtype:Tuple[Callable, str] \"\"\" url = _prepare_url(request.path)  for path, handler in self.routes.items(): parse_result = parse(path, url) if parse_result is not None: return handler, parse_result.named  view = self._get_view(request)  if view is not None: parse_result = parse(view.url, url)  if parse_result is not None: return view.view, parse_result.named  return None, None <\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0435\u0442\u043e\u0434 \u0441\u0432\u0438\u0442\u0447\u0430 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 &#171;\u043d\u0430 \u043b\u0435\u0442\u0443&#187;:<\/p>\n<pre><code class=\"python\">def switch_locale(self, locale: str, locale_dir: str): \"\"\" Switch to another locale i18n  :paramlocale: The locale :typelocale: str :paramlocale_dir: The locale dir :typelocale_dir: str \"\"\" logger.info(f\"Switch to another locale: {locale_dir}\/{locale}\") self.i18n_loader.locale = locale self.i18n_loader.directory = locale_dir self.i18n_loader.translations = self.i18n_loader.load_locale( self.i18n_loader.locale, self.i18n_loader.directory ) self.l10n_loader.locale = locale self.l10n_loader.directory = directory self.i18n_loader.locale_settings = self.l10n_loader.load_locale( self.l10n_loader.locale, self.l10n_loader.directory ) <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0445\u0435\u043d\u0434\u0435\u0440 \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435 \u043e\u0431\u0440\u0430\u0431\u044b\u0432\u0430\u0442\u044c, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435, \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u043e\u0448\u0438\u0431\u043e\u043a.<\/p>\n<pre><code class=\"python\">def _handle_request(self, request: Request) -&gt; Response: \"\"\" Handle response from request  :paramrequest:  The request :typerequest:  Request  :returns:Response callable object :rtype:Response \"\"\" logger.debug(f\"Handle request: {request.path}\") response = self._get_response(request)  handler, kwargs = self._find_handler(request)  if handler is not None: if inspect.isclass(handler): handler = getattr(handler(), request.method.lower(), None) if handler is None: raise MethodNotAllow(f\"Method not allowed: {request.method}\")  result = handler(request, response, **kwargs)  if isinstance(result, Response): response = result  if response.use_i18n: response.body = self.i18n_loader.get_string( response.body, **response.i18n_kwargs ) else: response.body = self.i18n_loader.get_string(result)  if not response.use_i18n: response.body = result else: raise URLNotFound(f'URL \"{request.path}\" not found.')  return response <\/code><\/pre>\n<p>\u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u0435\u0442\u043e\u0434 <code>__call__<\/code>. \u041e\u043d \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u0430\u0448 \u043a\u043b\u0430\u0441\u0441 callable, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u043c.<\/p>\n<pre><code class=\"python\">def __call__(self, environ: dict, start_response: method) -&gt; Iterable: \"\"\" Makes the application object callable  :paramenviron: The environ :typeenviron: dict :paramstart_response: The start response :typestart_response: method  :returns:response body :rtype:Iterable \"\"\" request = self._get_request(environ) self._apply_middleware_to_request(request) response = self._get_response(request)  try: response = self._handle_request(request) self._apply_middleware_to_response(response) except URLNotFound as err: logger.error( \"URLNotFound error has been raised: set default response (404)\" ) self._apply_middleware_to_response(response) self._default_response(response, error=err) except MethodNotAllow as err: logger.error( \"MethodNotAllow error has been raised: set default response (405)\" ) self._apply_middleware_to_response(response) self._default_response(response, error=err)  self.history.append(HistoryEntry(request=request, response=response)) return response(environ, start_response) <\/code><\/pre>\n<p>\u0418 \u0434\u0430, \u043e\u0448\u0438\u0431\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0438 \u0431\u0443\u0434\u0443\u0442 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u0430\u0439\u0442\u0430 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 URLNotFound \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 404 \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435. \u042d\u0442\u043e \u0434\u0430\u0441\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0430\u043a\u0436\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u0432 \u043a\u043e\u0434\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0432\u0435\u0431-\u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n<p>\u0418 \u0432 \u044d\u0442\u043e\u043c \u0436\u0435 \u043c\u0435\u0442\u043e\u0434\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430.<\/p>\n<h2>\u276f \u041f\u0440\u0438\u043c\u0435\u0440\u044b<\/h2>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u044f \u043d\u0430\u043f\u0438\u0448\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432.<\/p>\n<h3>\u276f \u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0435\u0431\u0430\u043f\u043f<\/h3>\n<p>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u0438 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043f\u0443\u0442\u044f\u043c\u0438.<\/p>\n<pre><code class=\"python\">import os from pyechonext.utils.exceptions import MethodNotAllow from pyechonext.app import ApplicationType, EchoNext from pyechonext.views import View from pyechonext.urls import URL, IndexView from pyechonext.config import SettingsLoader, SettingsConfigType from pyechonext.template_engine.jinja import render_template from pyechonext.middleware import middlewares from pyechonext.docsgen import ProjDocumentation   class UsersView(View): def get(self, request, response, **kwargs): return render_template( request, \"index.html\", user_name=\"User\", session_id=request.session_id, friends=[\"Bob\", \"Anna\", \"John\"], )  def post(self, request, response, **kwargs): raise MethodNotAllow(f\"Request {request.path}: method not allow\")   url_patterns = [URL(url=\"\/\", view=IndexView), URL(url=\"\/users\", view=UsersView)] config_loader = SettingsLoader(SettingsConfigType.PYMODULE, 'example_module.py') settings = config_loader.get_settings() echonext = EchoNext( __name__, settings, middlewares, urls=url_patterns, application_type=ApplicationType.HTML, ) apidoc = ProjDocumentation(echonext)   @echonext.route_page(\"\/book\") @apidoc.documentate_route('\/book', str, {}, ['GET', 'POST']) class BooksResource(View): \"\"\" This class describes a books resource. \"\"\"  def get(self, request, response, **kwargs): \"\"\" get queries  :param      request:   The request :type       request:   Request :param      response:  The response :type       response:  Response :param      kwargs:    The keywords arguments :type       kwargs:    dictionary  :returns:   result :rtype:     str \"\"\" return f\"GET Params: {request.GET}\"  def post(self, request, response, **kwargs): \"\"\" post queries  :param      request:   The request :type       request:   Request :param      response:  The response :type       response:  Response :param      kwargs:    The keywords arguments :type       kwargs:    dictionary  :returns:   result :rtype:     str \"\"\" return f\"POST Params: {request.POST}\"   apidoc.generate_documentation() <\/code><\/pre>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0444\u0430\u0439\u043b templates\/index.html \u0438 \u0444\u0430\u0439\u043b example_module.py.<\/p>\n<p>example_module.py \u2014 \u044d\u0442\u043e \u0444\u0430\u0439\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a:<\/p>\n<pre><code class=\"python\">import os  BASE_DIR = os.path.dirname(os.path.abspath(__file__)) TEMPLATES_DIR = 'templates' SECRET_KEY = 'secret-key' LOCALE = 'DEFAULT' LOCALE_DIR = None VERSION = 0.1.0 DESCRIPTION = 'Example echonext webapp' <\/code><\/pre>\n<h3>\u276f \u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438 docs-api ui<\/h3>\n<pre><code class=\"python\">import os from pyechonext.utils.exceptions import MethodNotAllow from pyechonext.app import ApplicationType, EchoNext from pyechonext.views import View from pyechonext.urls import URL, IndexView from pyechonext.config import SettingsLoader, SettingsConfigType from pyechonext.response import Response from pyechonext.template_engine.jinja import render_template from pyechonext.middleware import middlewares from pyechonext.docsgen import ProjDocumentation from pyechonext.apidoc_ui import APIDocumentation, APIDocUI   class UsersView(View): def get(self, request, response, **kwargs): return render_template( request, \"index.html\", user_name=\"User\", session_id=request.session_id, friends=[\"Bob\", \"Anna\", \"John\"], )  def post(self, request, response, **kwargs): raise MethodNotAllow(f\"Request {request.path}: method not allow\")   url_patterns = [URL(url=\"\/\", view=IndexView), URL(url=\"\/users\", view=UsersView)] config_loader = SettingsLoader(SettingsConfigType.PYMODULE, 'el_config.py') settings = config_loader.get_settings() echonext = EchoNext( __name__, settings, middlewares, urls=url_patterns, application_type=ApplicationType.HTML, ) apidoc = APIDocumentation(echonext) projdoc = ProjDocumentation(echonext)   @echonext.route_page('\/api-docs') def api_docs(request, response): ui = APIDocUI(apidoc.generate_spec()) return ui.generate_html_page()   @echonext.route_page(\"\/book\") @projdoc.documentate_route('\/book', str, {}, ['GET', 'POST']) class BooksResource(View): \"\"\" This class describes a books resource. \"\"\"  def get(self, request, response, **kwargs): \"\"\" get queries  :param      request:   The request :type       request:   Request :param      response:  The response :type       response:  Response :param      kwargs:    The keywords arguments :type       kwargs:    dictionary  :returns:   result :rtype:     str \"\"\" return echonext.l10n_loader.format_currency(1305.50)  def post(self, request, response, **kwargs): \"\"\" post queries  :param      request:   The request :type       request:   Request :param      response:  The response :type       response:  Response :param      kwargs:    The keywords arguments :type       kwargs:    dictionary  :returns:   result :rtype:     str \"\"\" return echonext.i18n_loader.get_string('title %{name}', name='Localization Site')   projdoc.generate_documentation() <\/code><\/pre>\n<h3>\u276f \u041f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0411\u0414<\/h3>\n<p>\u042f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e ORM \u2014 <a href=\"https:\/\/github.com\/alexeev-prog\/SQLSymphony\">\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>. \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e: <code>pip3 install sqlsymphony_orm<\/code>.<\/p>\n<pre><code class=\"python\">import os from pyechonext.app import ApplicationType, EchoNext from pyechonext.config import Settings from sqlsymphony_orm.datatypes.fields import IntegerField, RealField, TextField from sqlsymphony_orm.models.session_models import SessionModel from sqlsymphony_orm.models.session_models import SQLiteSession from pyechonext.middleware import middlewares   settings = Settings( BASE_DIR=os.path.dirname(os.path.abspath(__file__)), TEMPLATES_DIR=\"templates\", SECRET_KEY=\"secret\" ) echonext = EchoNext( __name__, settings, middlewares, application_type=ApplicationType.HTML ) session = SQLiteSession(\"echonext.db\")   class User(SessionModel): __tablename__ = \"Users\"  id = IntegerField(primary_key=True) name = TextField(null=False) cash = RealField(null=False, default=0.0)  def __repr__(self): return f\"&lt;User {self.pk}&gt;\"   @echonext.route_page(\"\/\") def home(request, response): user = User(name=\"John\", cash=100.0) session.add(user) session.commit() return \"Hello from the HOME page\"   @echonext.route_page(\"\/users\") def about(request, response): users = session.get_all_by_model(User)  return f\"Users: {[f'{user.name}: {user.cash}$' for user in users]}\" <\/code><\/pre>\n<hr\/>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u043f\u043e\u0447\u0442\u0438 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 Python. \u041f\u043e\u043a\u0430 \u0435\u043c\u0443 \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0412\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u044b;<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f celery;<\/p>\n<\/li>\n<li>\n<p>\u041a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435;<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b.<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0430\u0441\u044c \u0441\u0442\u0430\u0442\u044c\u044f, \u044f \u043c\u043e\u0433\u0443 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c, \u0433\u0434\u0435 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430.<\/p>\n<h2>\u276f \u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u042d\u0442\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u043c\u043e\u0438\u0445 \u0441\u0430\u043c\u044b\u0445 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0438 \u043f\u0440\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432. \u042d\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u043b\u043e\u0436\u043d\u043e, \u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e. \u042f \u043b\u0443\u0447\u0448\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0441\u044f \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0438\u043b\u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u0440\u0430\u0434 \u0431\u0443\u0434\u0443 \u0432\u044b\u0441\u043b\u0443\u0448\u0430\u0442\u044c.<\/p>\n<p>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e <a href=\"https:\/\/github.com\/alexeev-prog\/pyEchoNext\">\u0441\u0441\u044b\u043b\u043a\u0435<\/a>.<\/p>\n<p>\u0411\u0443\u0434\u0443 \u0440\u0430\u0434, \u0435\u0441\u043b\u0438 \u0432\u044b \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u0435\u0441\u044c \u043a \u043c\u043e\u0435\u043c\u0443 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u043c\u0443 <a href=\"https:\/\/t.me\/hex_warehouse\">\u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u0431\u043b\u043e\u0433\u0443<\/a>. \u0410\u043d\u043e\u043d\u0441\u044b \u0441\u0442\u0430\u0442\u0435\u0439, \u043d\u043e\u0432\u043e\u0441\u0442\u0438 \u0438\u0437 \u043c\u0438\u0440\u0430 IT \u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0434\u043b\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0441\u043c\u0435\u0436\u043d\u044b\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439. \u041d\u0435 \u0431\u0435\u0439\u0442\u0435 \ud83d\ude42<\/p>\n<blockquote>\n<p><a href=\"https:\/\/t.me\/timewebru\"><strong>\u041d\u043e\u0432\u043e\u0441\u0442\u0438, \u043e\u0431\u0437\u043e\u0440\u044b \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 \u0438 \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u044b \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b Timeweb.Cloud &#8212; \u0432 \u043d\u0430\u0448\u0435\u043c Telegram-\u043a\u0430\u043d\u0430\u043b\u0435<\/strong><\/a> <strong>\u21a9<\/strong><\/p>\n<\/blockquote>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/u9\/vg\/io\/u9vgio3hxj12h5u7j3un0wx_zpk.png\" data-src=\"https:\/\/habrastorage.org\/webt\/u9\/vg\/io\/u9vgio3hxj12h5u7j3un0wx_zpk.png\"\/><\/figure>\n<blockquote>\n<p><a href=\"https:\/\/timeweb.cloud\/?i=106909\"><strong>\u041f\u0435\u0440\u0435\u0439\u0442\u0438<\/strong><\/a> <strong>\u21a9<\/strong><\/p>\n<\/blockquote>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><\/p>\n<div class=\"tm-article-poll-container\"><!--[--><\/p>\n<div class=\"tm-article-poll tm-article-poll_variant-bordered\">\n<div class=\"tm-notice tm-notice_positive tm-article-poll__notice\"><!----><\/p>\n<div class=\"tm-notice__inner\"><!----><\/p>\n<div class=\"tm-notice__content\" data-test-id=\"notice-content\"><!--[--><span>\u0422\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043e\u043f\u0440\u043e\u0441\u0435. <a rel=\"nofollow\" href=\"\/kek\/v1\/auth\/habrahabr\/?back=\/ru\/companies\/timeweb\/articles\/858664\/&#038;hl=ru\">\u0412\u043e\u0439\u0434\u0438\u0442\u0435<\/a>, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430.<\/span><!--]--><\/div>\n<\/div>\n<\/div>\n<p><!--[--><\/p>\n<div class=\"tm-article-poll__header\">\u0425\u043e\u0442\u0438\u0442\u0435 \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c?<\/div>\n<div class=\"tm-article-poll__answers\"><!--[--><\/p>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent tm-article-poll__answer-percent_winning\">83.33% <\/span><span class=\"tm-article-poll__answer-label\">\u0414\u0430<\/span><span class=\"tm-article-poll__answer-votes\">15<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress tm-article-poll__answer-progress_winning\" style=\"width: 83.33%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">16.67% <\/span><span class=\"tm-article-poll__answer-label\">\u041d\u0435\u0442<\/span><span class=\"tm-article-poll__answer-votes\">3<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 16.67%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">0% <\/span><span class=\"tm-article-poll__answer-label\">\u0414\u0430, \u043d\u043e \u0441 \u0434\u0440\u0443\u0433\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u043e\u043c (\u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0443 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445)<\/span><span class=\"tm-article-poll__answer-votes\">0<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 0%\"><\/div>\n<\/div>\n<\/div>\n<p><!--]--><\/div>\n<div class=\"tm-article-poll__stats\"> \u041f\u0440\u043e\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043b\u0438 18 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.   \u0412\u043e\u0437\u0434\u0435\u0440\u0436\u0430\u043b\u0438\u0441\u044c 3 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. <\/div>\n<p><!--]--><\/div>\n<p><!--]--><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/858664\/\"> https:\/\/habr.com\/ru\/articles\/858664\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a, \u0445\u0430\u0431\u0440! \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0432\u043e\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 Python \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c gunicorn.<\/p>\n<p>\u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0433\u043a\u0438\u043c, \u0438\u043c\u0435\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b. \u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (views), \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044e, Middleware, i18n \u0438 l10n, Request\/Response, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 html-\u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u043c \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0438\u0437\u0443\u0447\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 WSGI \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0418 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043b\u0435\u0433\u0447\u0435 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432: flask, django.<\/p>\n<p>\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u0432\u0430\u0441 \u043c\u043e\u0433\u0443\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0447\u0442\u043e \u043c\u044b \u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0435\u043c \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434. \u0410 \u044f \u0432 \u043e\u0442\u0432\u0435\u0442 \u0441\u043a\u0430\u0436\u0443 \u2014 \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043b\u0438 \u0432\u044b \u043f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441, \u0431\u0435\u0437 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a, \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u043f\u0430\u043c\u044f\u0442\u0438, \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434 \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a?<\/p>\n<hr\/>\n<p>\u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0432\u0430\u0436\u043d\u044b\u043c\u0438 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u043e\u0440\u043a\u043e\u0432 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f:<\/p>\n<ul>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438 (routes): <\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0441\u0442\u044b\u0435: <code>\/index<\/code><\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435: <code>\/article\/{article_id}<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (views).<\/p>\n<\/li>\n<li>\n<p>Middleware<\/p>\n<\/li>\n<li>\n<p>Request\/Response<\/p>\n<\/li>\n<li>\n<p>i18n\/l10n<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435: \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u044b\u043c, \u043b\u0435\u0433\u043a\u0438\u043c \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 gunicorn). \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 Python \u0435\u0441\u0442\u044c \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e WSGI.<\/p>\n<p>\u041d\u0430\u0448 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f pyEchoNext. <a href=\"https:\/\/github.com\/alexeev-prog\/pyEchoNext\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.<\/a><\/p>\n<h2>\u276f \u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 Python<\/h2>\n<pre><code>            \u0417\u0410\u041f\u0420\u041e\u0421 CLIENT &lt;--------------&gt; [HTTP (80) \u0438\u043b\u0438 HTTPS (443)] \u0421\u0435\u0440\u0432\u0435\u0440              \u041e\u0422\u0412\u0415\u0422             &gt; \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439         &gt; \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f python-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f  &lt;-- \u0417\u043e\u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u043a\u0430 (\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b gunicorn \u0441 \u043d\u0438\u043c)         &gt; Gunicorn         &gt; \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0421\u0415\u0420\u0412\u0415\u0420 -&gt; NGINX         &gt; \u041c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 <\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 python \u043c\u044b \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>\u041c\u043d\u043e\u0433\u0438\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438 (ex. django) \u043d\u0435 \u0443\u043c\u0435\u044e\u0442 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c\u0438, \u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0434\u0432\u0435\u0440\u0436\u0435\u043d\u044b DDoS-\u0430\u0442\u0430\u043a\u0435 (Distributed Denial of Service, \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u043a\u0430\u0437 \u0432 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0438).<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0442 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043c\u0435\u0436\u0434\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0440\u0435\u0448\u0430\u0435\u0442 NGINX, \u043d\u043e \u043e\u043d \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0438 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441 Python-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043d\u0443\u0436\u0434\u0430 \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 WSGI-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 (Web Server Gateway Interface) \u0438 \u043f\u0440\u043e\u043a\u0441\u0438-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 (\u0442\u0430\u043a\u043e\u0433\u043e \u043a\u0430\u043a NGINX).<\/p>\n<h2>\u276f WSGI<\/h2>\n<p>\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f Python \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0445\u0432\u0430\u0441\u0442\u0430\u0442\u044c\u0441\u044f \u0448\u0438\u0440\u043e\u043a\u0438\u043c \u0441\u043f\u0435\u043a\u0442\u0440\u043e\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a Zope, Quixote, Webware, SkunkWeb, PSO \u0438 Twisted Web \u2014 \u0432\u043e\u0442 \u043b\u0438\u0448\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445. \u0422\u0430\u043a\u043e\u0435 \u0448\u0438\u0440\u043e\u043a\u043e\u0435 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u0434\u043b\u044f \u043d\u043e\u0432\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 Python, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0438\u0445 \u0432\u044b\u0431\u043e\u0440 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442 \u0438\u0445 \u0432\u044b\u0431\u043e\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432, \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442.<\/p>\n<p>\u041d\u0430\u043f\u0440\u043e\u0442\u0438\u0432, \u0445\u043e\u0442\u044f Java \u0438\u043c\u0435\u0435\u0442 \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, API \u00abservlet\u00bb Java \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043b\u044e\u0431\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 Java, \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 API \u0441\u0435\u0440\u0432\u043b\u0435\u0442\u043e\u0432.<\/p>\n<p>\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c \u0438 \u0448\u0438\u0440\u043e\u043a\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0430\u043a\u043e\u0433\u043e API \u0432 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445 \u0434\u043b\u044f Python \u2014 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u043e\u0433\u043e, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043b\u0438 \u044d\u0442\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u044b \u043d\u0430 Python (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Medusa), \u0432\u0441\u0442\u0440\u043e\u0435\u043d \u043b\u0438 Python (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, mod_python) \u0438\u043b\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 Python \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0448\u043b\u044e\u0437\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, CGI, FastCGI \u0438 \u0442. \u0434.) \u2014 \u043e\u0442\u0434\u0435\u043b\u0438\u0442 \u0432\u044b\u0431\u043e\u0440 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0443\u044e \u0438\u043c \u043f\u0430\u0440\u0443, \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043b\u044f \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0438\u0445 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u044d\u0442\u043e\u0442 PEP \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0438 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043c\u0435\u0436\u0434\u0443 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c\u0438 \u0438 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438 \u0438\u043b\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438: \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0448\u043b\u044e\u0437\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 Python (WSGI).<\/p>\n<p>\u041d\u043e \u0441\u0430\u043c\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 WSGI \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u0442 \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0434\u043b\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 Python. \u0410\u0432\u0442\u043e\u0440\u044b \u0438 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c WSGI, \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0438\u043c\u0435\u043b\u043e \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u044d\u0444\u0444\u0435\u043a\u0442.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0438 \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438\u043b\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 WSGI, \u0430\u0432\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 WSGI, \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u043e\u0437\u043d\u0430\u0433\u0440\u0430\u0436\u0434\u0435\u043d\u0438\u044f.\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, WSGI \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0441\u0442 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0432\u0435\u0441\u0442\u0438\u0446\u0438\u0438 \u0430\u0432\u0442\u043e\u0440\u0430 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043c\u043e\u0433\u043b\u0438 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043d\u0438\u0437\u043a\u0438\u043c\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u0430\u043a \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0442\u0430\u043a \u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0441\u0442\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 WSGI \u0438, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0435\u043c \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u2014 \u044d\u0442\u043e \u043d\u0435 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. WSGI \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u00ab\u0431\u0435\u0437 \u0438\u0437\u043b\u0438\u0448\u0435\u0441\u0442\u0432\u00bb \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0442\u0430\u043a\u0438\u0435 \u043d\u0430\u0432\u043e\u0440\u043e\u0442\u044b, \u043a\u0430\u043a \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043e\u0442\u0432\u0435\u0442\u0430 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 cookie, \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043c\u0435\u0448\u0430\u044e\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c \u0440\u0435\u0448\u0430\u0442\u044c \u044d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041e\u043f\u044f\u0442\u044c \u0436\u0435, \u0446\u0435\u043b\u044c WSGI \u2014 \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043b\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432, \u0430 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u0430 \u0446\u0435\u043b\u044c \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 WSGI \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e, \u0447\u0442\u043e \u0435\u0449\u0435 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u0432 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445 Python. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u043e\u0432\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0435 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u044d\u0442\u043e\u0439 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439, \u0438 \u043d\u0438\u0447\u0442\u043e \u0432 WSGI \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u0435\u0440\u0441\u0438\u0438 Python \u0432\u044b\u0448\u0435 2.2.2. (\u043e\u0434\u043d\u0430\u043a\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u0447\u0442\u043e\u0431\u044b \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 Python \u0432\u043a\u043b\u044e\u0447\u0430\u043b\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439).<\/p>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0438 \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432, \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043b\u0435\u0433\u043a\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u043e\u0441\u0442\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u044b \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u00ab\u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f\u00bb \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 WSGI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043a\u0430\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0432\u043e\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0445\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0435 \u041f\u041e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u043c, \u0430 WSGI \u0448\u0438\u0440\u043e\u043a\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u0445, \u044d\u0442\u043e \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 Python: \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e \u0438\u0437 \u0441\u043b\u0430\u0431\u043e\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0433\u043e \u041f\u041e WSGI. \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u044b \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0434\u0430\u0436\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0441\u043b\u0443\u0436\u0431 \u0441\u0432\u043e\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0438\u0441\u044c \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u0445\u043e\u0436\u0438\u043c\u0438 \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0441 WSGI, \u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u043d\u0430 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438. \u042d\u0442\u043e \u0442\u043e\u0433\u0434\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0431\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u00ab\u043b\u0443\u0447\u0448\u0438\u0435 \u0432 \u0441\u0432\u043e\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0435\u00bb \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0431\u0440\u0430\u0442\u044c \u043d\u0430 \u0441\u0435\u0431\u044f \u0432\u0441\u0435 \u043f\u043b\u044e\u0441\u044b \u0438 \u043c\u0438\u043d\u0443\u0441\u044b \u043e\u0434\u043d\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430.<\/p>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u044d\u0442\u043e\u0442 \u0434\u0435\u043d\u044c, \u043d\u0435\u0441\u043e\u043c\u043d\u0435\u043d\u043d\u043e, \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u043b\u0435\u043a. \u0412 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f, \u044d\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0439 \u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0440\u043e\u0447\u043d\u043e\u0439 \u0446\u0435\u043b\u044c\u044e \u0434\u043b\u044f WSGI, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0441 \u043b\u044e\u0431\u044b\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c.<\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f WSGI \u043d\u0435 \u043f\u0440\u0435\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u043b\u044f \u00ab\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f\u00bb \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u043c \u0448\u043b\u044e\u0437\u043e\u043c. \u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u044d\u0442\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438\u043b\u0438 \u0448\u043b\u044e\u0437\u0430. \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0432\u043d\u0435\u0434\u0440\u0438\u0442 WSGI \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043e\u043f\u044b\u0442\u0430 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c\u0438 \u043a \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044e, \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u043c\u044b\u0441\u043b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d PEP, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0439<\/p>\n<h2>\u276f \u0426\u0435\u043b\u0438 pyEchoNext<\/h2>\n<p>pyEchoNext \u2014 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u043e\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0438\u043b\u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. Django \u0434\u043b\u044f \u043d\u0430\u0441 \u0431\u044b\u043b \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438 \u043d\u0435\u043f\u043e\u0432\u043e\u0440\u043e\u0442\u043b\u0438\u0432\u044b\u0439, flask \u0438\u043b\u0438 fastapi \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u0432\u0437\u044f\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0444\u0438\u0447\u0438 \u0438\u0437 django \u0438 flask\/fastapi, \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u0445 \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0432 \u0441\u0438\u043c\u0431\u0438\u043e\u0437\u0435. \u0422\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u0442\u0430\u043a \u0438 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441. \u0418 \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0432 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0443\u0441\u0438\u043b\u0438\u0439.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u0448\u0438\u043c\u0438 \u0446\u0435\u043b\u044f\u043c\u0438 \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c, \u0434\u0440\u0443\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a.<\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435, \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0442\u0430\u043a\u0430\u044f:<\/p>\n<ol>\n<li>\n<p>\u0426\u0435\u043b\u044c: \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u043d\u043e\u0433\u043e\u0433\u0440\u0430\u043d\u043d\u044b\u0439 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0430 python.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0434\u0430\u0447\u0438:<\/p>\n<\/li>\n<\/ol>\n<ul>\n<li>\n<p>\u041d\u0430\u0439\u0442\u0438 \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u0438 \u043f\u043b\u043e\u0445\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b Flask, FastAPI<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0439\u0442\u0438 \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u0438 \u043f\u043b\u043e\u0445\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b Django<\/p>\n<\/li>\n<li>\n<p>\u0421\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0431\u043e\u0440 \u043b\u0443\u0447\u0448\u0438\u0445 \u0444\u0438\u0447<\/p>\n<\/li>\n<li>\n<p>\u0421\u0438\u043c\u0431\u0438\u043e\u0437 \u0444\u0438\u0447 \u0432 \u043e\u0434\u043d\u043e \u0446\u0435\u043b\u043e\u0435<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043e\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e SOLID \u0438 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0430\u043c \u041e\u041e\u041f, \u043b\u0435\u0433\u043a\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u044b\u043c, \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u044b\u043c \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u044b\u0441\u0442\u0440\u044b\u043c \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c, \u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0431\u043e\u0434\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443<\/p>\n<\/li>\n<\/ul>\n<ol start=\"3\">\n<li>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432, \u0434\u0430\u044e\u0449\u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u0430\u043a \u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0442\u0430\u043a \u0438 \u0431\u044b\u0441\u0442\u0440\u044b\u0439 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441.<\/p>\n<\/li>\n<li>\n<p>\u0410\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c: \u0432\u0435\u0431-\u0441\u0444\u0435\u0440\u0430 \u0432 \u0434\u0430\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430, \u0443\u043c\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0432\u0435\u0431-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438, \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f\u043c\u0438, \u0437\u043d\u0430\u0442\u044c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0441\u0430\u0439\u0442\u043e\u0432 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0441\u0435\u043c.<\/p>\n<\/li>\n<\/ol>\n<h2>\u276f \u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 gunicorn<\/h2>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 <code>gunicorn<\/code> \u0438 <code>pysocks<\/code> \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0444\u0430\u0439\u043b app.py:<\/p>\n<pre><code class=\"python\">from socks import method   def app(environ: dict, start_response: method): response_body = b'Hello, Habr!' status = \"200 OK\" start_response(status, headers=[]) return iter([response_body]) <\/code><\/pre>\n<p>\u0418 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 gunicorn:<\/p>\n<pre><code class=\"bash\">gunicorn app:app # gunicorn &lt;\u0444\u0430\u0439\u043b&gt;:&lt;callable-\u043a\u043b\u0430\u0441\u0441 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430&gt; <\/code><\/pre>\n<p>\u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0432\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 &#8212; environ \u0438 start_response. \u0412 environ \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0432\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0432\u0435\u0431-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a user-agent, \u043f\u0443\u0442\u044c, \u043c\u0435\u0442\u043e\u0434, GET \u0438 POST \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438 \u0434\u0440\u0443\u0433\u0438\u0435. \u0412\u0442\u043e\u0440\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u2014 start_response, \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0439 \u043e\u0442\u0432\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0441\u044b\u043b\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0433\u0430\u0435\u043c\u044b\u0439 \u043e\u0442\u0432\u0435\u0442.<\/p>\n<p>\u041d\u043e \u0431\u043e\u043b\u0435\u0435 \u0445\u043e\u0440\u043e\u0448\u043e\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c callable-\u043a\u043b\u0430\u0441\u0441:<\/p>\n<pre><code class=\"python\">class App: def __call__(self, environ: dict, start_response: method): response_body = b'Hello, Habr!' status = \"200 OK\" start_response(status, headers=[]) return iter([response_body])   app = App() <\/code><\/pre>\n<p>\u041c\u0430\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 <code>__call__<\/code> \u0434\u0435\u043b\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u043c\u0438.<\/p>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"bash\">gunicorn app:app # gunicorn &lt;\u0444\u0430\u0439\u043b&gt;:&lt;callable-\u043a\u043b\u0430\u0441\u0441 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430&gt; <\/code><\/pre>\n<p>\u041d\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442, \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u044f \u0435\u0433\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0447\u043d\u0435\u043c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 poetry.<\/p>\n<h2>\u276f \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>Poetry \u2014 \u044d\u0442\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u0441\u0431\u043e\u0440\u043a\u043e\u0439 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0432 Python. \u0410 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 Poetry \u043e\u0447\u0435\u043d\u044c \u043b\u0435\u0433\u043a\u043e \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043d\u0430 PyPi!<\/p>\n<p>\u0412 Poetry \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u043e\u043b\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-443184","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/443184","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=443184"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/443184\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=443184"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=443184"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=443184"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}