{"id":302754,"date":"2020-04-29T15:01:18","date_gmt":"2020-04-29T15:01:18","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=302754"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=302754","title":{"rendered":"\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0431\u044d\u043a\u0435\u043d\u0434-\u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043d\u0430 Python"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/499534\/\">\u041f\u0440\u0438\u0432\u0435\u0442, \u043c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0412\u0430\u0441\u0438\u043d, \u044f \u0431\u044d\u043a\u0435\u043d\u0434-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0415\u0434\u0430\u0434\u0438\u043b\u0435. \u0418\u0434\u0435\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043d\u0430\u0447\u0430\u043b\u0430\u0441\u044c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u0445\u043e\u0442\u0435\u043b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 (<a href=\"https:\/\/yadi.sk\/i\/dA9umaGbQdMNLw\">\u042f.\u0414\u0438\u0441\u043a<\/a>) \u0432 \u0428\u043a\u043e\u043b\u0443 \u0431\u044d\u043a\u0435\u043d\u0434-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u042f\u043d\u0434\u0435\u043a\u0441\u0430. \u042f \u043d\u0430\u0447\u0430\u043b \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u0438 \u0432\u044b\u0431\u043e\u0440\u0430 \u0442\u0435\u0445 \u0438\u043b\u0438 \u0438\u043d\u044b\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439, \u043c\u0435\u0442\u043e\u0434\u0438\u043a\u0443 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\u2026 \u041f\u043e\u043b\u0443\u0447\u0430\u043b\u0441\u044f \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u0440\u0430\u0437\u0431\u043e\u0440, \u0430 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u0433\u0430\u0439\u0434 \u043f\u043e \u0442\u043e\u043c\u0443, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u0431\u044d\u043a\u0435\u043d\u0434\u044b \u043d\u0430 Python. \u041e\u0442 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u0434\u0435\u0438 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443, \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0434\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0438 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438. \u0412 \u0438\u0442\u043e\u0433\u0435 \u044f \u043e\u0447\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0441\u043e\u0442\u043d\u0435 \u0442\u044b\u0441\u044f\u0447 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432. \u0420\u043e\u0432\u043d\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432\u0441\u0451 \u0432 \u043c\u0435\u043b\u044c\u0447\u0430\u0439\u0448\u0438\u0445 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u0445. \u0418\u0442\u0430\u043a, \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 100 \u043a\u0438\u043b\u043e\u0431\u0430\u0439\u0442: \u043a\u0430\u043a \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0431\u044d\u043a\u0435\u043d\u0434 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044f \u0434\u0435\u043f\u043b\u043e\u0435\u043c.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ks\/_x\/t3\/ks_xt39dvtjt1ychs8mt3blwyg0.png\"><\/p>\n<p>  <b>TL;DR:<\/b> \u0412\u043e\u0442 <a href=\"https:\/\/github.com\/alvassin\/backendschool2019\">\u0440\u0435\u043f\u043a\u0430 \u043d\u0430 GitHub \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c<\/a>, \u0430 \u043a\u0442\u043e \u043b\u044e\u0431\u0438\u0442 (\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435) \u043b\u043e\u043d\u0433\u0440\u0438\u0434\u044b \u2014 \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<br \/>  <a name=\"habracut\"><\/a><br \/>  \u041c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0438 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c REST API-\u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0430 Python, \u0443\u043f\u0430\u043a\u0443\u0435\u043c \u0435\u0433\u043e \u0432 \u043b\u0435\u0433\u043a\u0438\u0439 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Ansible.<br \/>  <cut><\/cut>  <\/p>\n<blockquote><p>\u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c REST API-\u0441\u0435\u0440\u0432\u0438\u0441 \u043c\u043e\u0436\u043d\u043e \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0430\u0437\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432. \u041e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u0435\u0440\u043d\u043e\u0435, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u044f \u0432\u044b\u0431\u0438\u0440\u0430\u043b \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0441\u0432\u043e\u0435\u0433\u043e \u043b\u0438\u0447\u043d\u043e\u0433\u043e \u043e\u043f\u044b\u0442\u0430 \u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0435\u043d\u0438\u0439.<\/p><\/blockquote>\n<p>  <\/p>\n<ul>\n<li><a href=\"#task\">\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c?<\/a><\/li>\n<li><a href=\"#tools\">\u041a\u0430\u043a\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0432\u044b\u0431\u0440\u0430\u0442\u044c?<\/a><\/li>\n<li> <a href=\"#development\">\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/a><br \/> \n<ul>\n<li><a href=\"#setuppy\">\u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0441 setup.py?<\/a><\/li>\n<li><a href=\"#requirements\">\u041a\u0430\u043a \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439?<\/a><\/li>\n<li> <a href=\"#db\">\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/a><br \/> \n<ul>\n<li><a href=\"#dbstructure\">\u041f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0441\u0445\u0435\u043c\u0443<\/a><\/li>\n<li><a href=\"#do_sqlalchemy\">\u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u0445\u0435\u043c\u0443 \u0432 SQLAlchemy<\/a><\/li>\n<li><a href=\"#db_alembic\">\u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c Alembic<\/a><\/li>\n<li><a href=\"#db_alembic_migrations\">\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438<\/a><\/li>\n<\/ul>\n<\/li>\n<li> <a href=\"#application\">\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/a>\n<ul>\n<li><a href=\"#serialization\">\u0421\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445<\/a><\/li>\n<li><a href=\"#handlers\">\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438<\/a>\n<ul>\n<li><a href=\"#imports_handler\">POST \/imports<\/a><\/li>\n<li><a href=\"#citizens_handler\">GET \/imports\/$import_id\/citizens<\/a><\/li>\n<li><a href=\"#update_citizen_handler\">PATCH \/imports\/$import_id\/citizens\/$citizen_id<\/a><\/li>\n<li><a href=\"#citizen_birthdays_handler\">GET \/imports\/$import_id\/citizens\/birthdays<\/a><\/li>\n<li><a href=\"#town_age_stat_handler\">GET \/imports\/$import_id\/towns\/stat\/percentile\/age<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#testing\">\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a>\n<ul>\n<li><a href=\"#testing_handlers\">\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438<\/a>\n<ul>\n<li><a href=\"#test_citizens_handler\">GET \/imports\/$import_id\/citizens<\/a><\/li>\n<li><a href=\"#test_imports_handler\">POST \/imports<\/a><\/li>\n<li><a href=\"#test_update_citizen_handler\">PATCH \/imports\/$import_id\/citizens\/$citizen_id<\/a><\/li>\n<li><a href=\"#test_citizen_birthdays_handler\">GET \/imports\/$import_id\/citizens\/birthdays<\/a><\/li>\n<li><a href=\"#test_town_age_stat_handler\">GET \/imports\/$import_id\/towns\/stat\/percentile\/age<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#test_migrations\">\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u0438<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#build\">\u0421\u0431\u043e\u0440\u043a\u0430<\/a><\/li>\n<li><a href=\"#ci\">CI<\/a><\/li>\n<li><a href=\"#deployment\">\u0414\u0435\u043f\u043b\u043e\u0439<\/a><\/li>\n<li><a href=\"#load_testing\">\u041d\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a><\/li>\n<li><a href=\"#whatelse\">\u0427\u0442\u043e \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c?<\/a><\/li>\n<li><a href=\"#final\">\u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/a><\/li>\n<\/ul>\n<p>  <a name=\"task\"><\/a><\/p>\n<h1>\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c?<\/h1>\n<p>  \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d \u043f\u043e\u0434\u0430\u0440\u043a\u043e\u0432 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0430\u043a\u0446\u0438\u044e \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0435\u0433\u0438\u043e\u043d\u0430\u0445. \u0427\u0442\u043e\u0431\u044b \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f \u043f\u0440\u043e\u0434\u0430\u0436 \u0431\u044b\u043b\u0430 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0430\u043d\u0430\u043b\u0438\u0437 \u0440\u044b\u043d\u043a\u0430. \u0423 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u0435\u0441\u0442\u044c \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a, \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u044e\u0449\u0438\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u043f\u043e\u0447\u0442\u0443) \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0436\u0438\u0442\u0435\u043b\u044f\u0445.<\/p>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c REST API-\u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0430 Python, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0432\u044b\u044f\u0432\u043b\u044f\u0442\u044c \u0441\u043f\u0440\u043e\u0441 \u043d\u0430 \u043f\u043e\u0434\u0430\u0440\u043a\u0438 \u0443 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u044b\u0445 \u0433\u0440\u0443\u043f\u043f \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0433\u043e\u0440\u043e\u0434\u0430\u0445 \u043f\u043e \u043c\u0435\u0441\u044f\u0446\u0430\u043c.<\/p>\n<p>  \u0412 \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438:<\/p>\n<ul>\n<li> <code>POST \/imports<\/code><br \/>  \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u043e\u0432\u0443\u044e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438;   <\/li>\n<li> <code>GET \/imports\/$import_id\/citizens<\/code><br \/>  \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438;   <\/li>\n<li> <code>PATCH \/imports\/$import_id\/citizens\/$citizen_id<\/code><br \/>  \u0418\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0436\u0438\u0442\u0435\u043b\u0435 (\u0438 \u0435\u0433\u043e \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u0445) \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435;   <\/li>\n<li> <code>GET \/imports\/$import_id\/citizens\/birthdays<\/code><br \/>  \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 \u0447\u0438\u0441\u043b\u043e \u043f\u043e\u0434\u0430\u0440\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0435\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 \u0436\u0438\u0442\u0435\u043b\u044c \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0432\u043e\u0438\u043c \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c (\u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430), \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043f\u043e \u043c\u0435\u0441\u044f\u0446\u0430\u043c;   <\/li>\n<li> <code>GET \/imports\/$import_id\/towns\/stat\/percentile\/age<\/code><br \/>  \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 50-\u0439, 75-\u0439 \u0438 99-\u0439 \u043f\u0435\u0440\u0446\u0435\u043d\u0442\u0438\u043b\u0438 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u043e\u0432 (\u043f\u043e\u043b\u043d\u044b\u0445 \u043b\u0435\u0442) \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u043f\u043e \u0433\u043e\u0440\u043e\u0434\u0430\u043c \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u0432\u044b\u0431\u043e\u0440\u043a\u0435.   <\/li>\n<\/ul>\n<p>  <a name=\"tools\"><\/a><\/p>\n<h1>\u041a\u0430\u043a\u0438\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0432\u044b\u0431\u0440\u0430\u0442\u044c?<\/h1>\n<p>  \u0418\u0442\u0430\u043a, \u043f\u0438\u0448\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0430 Python, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438, \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438 \u0421\u0423\u0411\u0414.<\/p>\n<p>  \u0412 <a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#4\">4 \u043b\u0435\u043a\u0446\u0438\u0438<\/a> \u0432\u0438\u0434\u0435\u043e\u043a\u0443\u0440\u0441\u0430 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0421\u0423\u0411\u0414 \u0438 \u0438\u0445 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u0445. \u0414\u043b\u044f \u043c\u043e\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0421\u0423\u0411\u0414 <a href=\"https:\/\/www.postgresql.org\">PostgreSQL<\/a>, \u0437\u0430\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u0432\u0448\u0443\u044e \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 c \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u0439 <a href=\"https:\/\/postgrespro.ru\/docs\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435<\/a>, \u0441\u0438\u043b\u044c\u043d\u044b\u043c \u0440\u0443\u0441\u0441\u043a\u0438\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e\u043c (\u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435) \u0438 \u0434\u0430\u0436\u0435 <a href=\"https:\/\/postgrespro.ru\/education\/courses\">\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c\u0438 \u043a\u0443\u0440\u0441\u0430\u043c\u0438<\/a>. \u0420\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u0430 \u0438 \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u0430 \u043c\u043d\u043e\u0433\u0438\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c. \u0425\u043e\u0442\u044f \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 NoSQL \u0421\u0423\u0411\u0414, \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e PostgreSQL.<\/p>\n<p>  \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u2014 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0441\u0435\u0442\u0438 \u043c\u0435\u0436\u0434\u0443 \u0411\u0414 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c\u0438 \u2014 \u043d\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440, \u043d\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u043e\u0434\u0438\u043d \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0412 <a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#10\">10 \u043b\u0435\u043a\u0446\u0438\u0438<\/a> \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u041e\u0421 (\u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0432\u043e Flask\/Django pre-fork-\u043c\u043e\u0434\u0435\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u0442 \u043f\u0430\u043c\u044f\u0442\u044c, \u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u0438\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438). \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 <a href=\"https:\/\/docs.aiohttp.org\/en\/stable\/\">aiohttp<\/a>.<\/p>\n<p>  <a href=\"https:\/\/habrastorage.org\/webt\/or\/rj\/pn\/orrjpnx6upvsipcqbsql7f36vzc.png\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/or\/rj\/pn\/orrjpnx6upvsipcqbsql7f36vzc.png\"><\/a><\/p>\n<p>  \u0412 <a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#5\">5 \u043b\u0435\u043a\u0446\u0438\u0438<\/a> \u0432\u0438\u0434\u0435\u043e\u043a\u0443\u0440\u0441\u0430 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e <a href=\"https:\/\/www.sqlalchemy.org\">SQLAlchemy<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0447\u0430\u0441\u0442\u0438, \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043f\u043e\u043b\u0435\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, PATCH-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0436\u0438\u0442\u0435\u043b\u044f \u0441 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438) \u0438 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435. \u0421 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u044d\u0442\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0432\u0441\u0435\u0445 \u0441\u043f\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0434\u0440\u0430\u0439\u0432\u0435\u0440 <a href=\"https:\/\/github.com\/MagicStack\/asyncpg\">asyncpg<\/a>, \u0430 \u043f\u043e\u0434\u0440\u0443\u0436\u0438\u0442\u044c \u0438\u0445 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 <a href=\"https:\/\/asyncpgsa.readthedocs.io\/en\/latest\/\">asyncpgsa<\/a>.<\/p>\n<p>  \u041c\u043e\u0439 \u043b\u044e\u0431\u0438\u043c\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 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0411\u0414 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u043c\u0438 \u2014 <a href=\"https:\/\/alembic.sqlalchemy.org\">Alembic<\/a>. \u041a\u0441\u0442\u0430\u0442\u0438, \u044f \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043e \u043d\u0435\u043c \u043d\u0430 <a href=\"https:\/\/www.youtube.com\/watch?v=qrlTDNaUQ-Q&amp;feature=youtu.be&amp;t=5651\">Moscow Python<\/a>.<\/p>\n<p>  \u041b\u043e\u0433\u0438\u043a\u0443 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0445\u0435\u043c\u0430\u043c\u0438 <a href=\"https:\/\/marshmallow.readthedocs.io\/en\/stable\/\">Marshmallow<\/a> (\u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043d\u0430 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0441\u0432\u044f\u0437\u0438). \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u0434\u0443\u043b\u044f <a href=\"https:\/\/github.com\/maximdanilchenko\/aiohttp-apispec\">aiohttp-spec<\/a> \u044f \u0441\u0432\u044f\u0437\u0430\u043b aiohttp-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0438 \u0441\u0445\u0435\u043c\u044b \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0431\u043e\u043d\u0443\u0441\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <a href=\"https:\/\/swagger.io\">Swagger<\/a> \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0435\u0435 \u0432 <a href=\"https:\/\/swagger.io\/tools\/swagger-ui\/\">\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435<\/a>.<\/p>\n<p>  \u0414\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u044f \u0432\u044b\u0431\u0440\u0430\u043b <code>pytest<\/code>, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u043d\u0435\u043c \u2014 \u0432 <a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#3\">3 \u043b\u0435\u043a\u0446\u0438\u0438<\/a>.<\/p>\n<p>  \u0414\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0438 \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043e\u0442\u043b\u0430\u0434\u0447\u0438\u043a PyCharm (<a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#9\">\u043b\u0435\u043a\u0446\u0438\u044f 9<\/a>).<\/p>\n<p>  \u0412 <a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#7\">7 \u043b\u0435\u043a\u0446\u0438\u0438<\/a> \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u0430\u043a \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 \u0441 <a href=\"http:\/\/docker.com\">Docker<\/a> (\u0438 \u0434\u0430\u0436\u0435 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u041e\u0421) \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u043b\u0435\u0433\u043a\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\/\u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\/\u0443\u0434\u0430\u043b\u044f\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.<\/p>\n<p>  \u0414\u043b\u044f \u0434\u0435\u043f\u043b\u043e\u044f \u044f \u0432\u044b\u0431\u0440\u0430\u043b <a href=\"https:\/\/www.ansible.com\">Ansible<\/a>. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e ssh \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u043e\u0444\u0442\u0430.<\/p>\n<p>  <a name=\"development\"><\/a><\/p>\n<h1>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430<\/h1>\n<p>  \u042f \u0440\u0435\u0448\u0438\u043b \u0434\u0430\u0442\u044c Python-\u043c\u043e\u0434\u0443\u043b\u044e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 <code>analyzer<\/code> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/dv\/eo\/ht\/dveoht-k8-pe_nac7ylyhue_zy8.png\" width=\"550\"><\/p>\n<p>  \u0412 \u0444\u0430\u0439\u043b\u0435 <code>analyzer\/__init__.py<\/code> \u044f \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043b \u043e\u0431\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u043e\u0434\u0443\u043b\u0435: \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 (<a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0257\/#what-is-a-docstring\">docstring<\/a>), \u0432\u0435\u0440\u0441\u0438\u044e, \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u044e, \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0415\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 help<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">$ python &gt;&gt;&gt; import analyzer &gt;&gt;&gt; help(analyzer)  Help on package analyzer:  NAME     analyzer  DESCRIPTION     \u0421\u0435\u0440\u0432\u0438\u0441 \u0441 REST API, \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0440\u044b\u043d\u043e\u043a \u0434\u043b\u044f \u043f\u0440\u043e\u043c\u043e\u0430\u043a\u0446\u0438\u0439.  PACKAGE CONTENTS     api (package)     db (package)     utils (package)  DATA     __all__ = ('__author__', '__email__', '__license__', '__maintainer__',...     __email__ = 'alvassin@yandex.ru'     __license__ = 'MIT'     __maintainer__ = 'Alexander Vasin'  VERSION     0.0.1  AUTHOR     Alexander Vasin  FILE     \/Users\/alvassin\/Work\/backendschool2019\/analyzer\/__init__.py<\/code><\/pre>\n<\/div><\/div>\n<p>  \u041c\u043e\u0434\u0443\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u0434\u0432\u0435 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0442\u043e\u0447\u043a\u0438 \u2014 REST API-\u0441\u0435\u0440\u0432\u0438\u0441 (<code>analyzer\/api\/__main__.py<\/code>) \u0438 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0411\u0414 (<code>analyzer\/db\/__main__.py<\/code>). \u0424\u0430\u0439\u043b\u044b \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f <code>__main__.py<\/code> \u043d\u0435\u0441\u043f\u0440\u043e\u0441\u0442\u0430 \u2014 \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0442\u0430\u043a\u043e\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043f\u043e \u043d\u0435\u043c\u0443 \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0444\u0430\u0439\u043b \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u043e\u0439. <\/p>\n<p>  \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0434\u0445\u043e\u0434\u0443 \u043a \u0432\u0445\u043e\u0434\u043d\u044b\u043c \u0442\u043e\u0447\u043a\u0430\u043c <a href=\"https:\/\/docs.python.org\/3\/library\/__main__.html#module-__main__\"><code>\u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b python -m<\/code><\/a>:<\/p>\n<pre><code class=\"bash\"># REST API $ python -m analyzer.api --help  # \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0411\u0414 $ python -m analyzer.db --help<\/code><\/pre>\n<p>  <a name=\"setuppy\"><\/a><\/p>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0441 setup.py?<\/h2>\n<p>  \u0417\u0430\u0431\u0435\u0433\u0430\u044f \u0432\u043f\u0435\u0440\u0435\u0434, \u043f\u043e\u0434\u0443\u043c\u0430\u0435\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435: \u043e\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u043d\u043e \u0432 zip- (\u0430 \u0442\u0430\u043a\u0436\u0435 wheel\/egg-) \u0430\u0440\u0445\u0438\u0432, rpm-\u043f\u0430\u043a\u0435\u0442, pkg-\u0444\u0430\u0439\u043b \u0434\u043b\u044f macOS \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440, \u0432 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443, MacBook \u0438\u043b\u0438 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440.<\/p>\n<p>  \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0446\u0435\u043b\u044c \u0444\u0430\u0439\u043b\u0430 <a href=\"https:\/\/docs.python.org\/3\/distutils\/setupscript.html\"><code>setup.py<\/code><\/a> \u2014 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f <code><a href=\"https:\/\/docs.python.org\/3\/library\/distutils.html\">distutils<\/a>\/<a href=\"https:\/\/setuptools.readthedocs.io\/en\/latest\/\">setuptools<\/a><\/code>. <\/p>\n<p>  \u0412 \u0444\u0430\u0439\u043b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0431\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u043e\u0434\u0443\u043b\u0435 (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435, \u0432\u0435\u0440\u0441\u0438\u044e, \u0430\u0432\u0442\u043e\u0440\u0430 \u0438 \u0442. \u0434.), \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0432 \u043d\u0435\u043c \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043c\u043e\u0434\u0443\u043b\u0438, \u00ab\u044d\u043a\u0441\u0442\u0440\u0430\u00bb-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f), \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b) \u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440\u0443.<\/p>\n<p>  \u041f\u043b\u0430\u0433\u0438\u043d\u044b setuptools \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0438\u0437 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442. \u0415\u0441\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043f\u043b\u0430\u0433\u0438\u043d\u044b: zip, egg, rpm, macOS pkg. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043b\u0430\u0433\u0438\u043d\u044b \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 PyPI: <a href=\"https:\/\/pypi.org\/project\/wheel\">wheel<\/a>, <a href=\"https:\/\/pypi.org\/project\/xar\">xar<\/a>, <a href=\"https:\/\/pypi.org\/project\/pex\">pex<\/a>. <\/p>\n<p>  \u0412 \u0441\u0443\u0445\u043e\u043c \u043e\u0441\u0442\u0430\u0442\u043a\u0435, \u043e\u043f\u0438\u0441\u0430\u0432 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u043e\u0432\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c \u0441 <code>setup.py<\/code>.<\/p>\n<p>  \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>setup()<\/code> \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u043e\u043c:<\/p>\n<pre><code class=\"python\">setup(..., install_requires=[&quot;aiohttp&quot;, &quot;SQLAlchemy&quot;])<\/code><\/pre>\n<p>  \u041d\u043e \u044f \u043e\u043f\u0438\u0441\u0430\u043b \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u0430\u0445 <code>requirements.txt<\/code> \u0438 <code>requirements.dev.txt<\/code>, \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 <code>setup.py<\/code>. \u041c\u043d\u0435 \u044d\u0442\u043e \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0438\u043c, \u043f\u043b\u044e\u0441 \u0442\u0443\u0442 \u0435\u0441\u0442\u044c \u0441\u0435\u043a\u0440\u0435\u0442: \u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c Docker-\u043e\u0431\u0440\u0430\u0437 \u0431\u044b\u0441\u0442\u0440\u0435\u0435. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u0442\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u0434\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0441\u0431\u043e\u0440\u043a\u0435 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043f\u043e\u043f\u0430\u0434\u0430\u0442\u044c \u0432 \u043a\u0435\u0448.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b <code>setup.py<\/code> \u0441\u043c\u043e\u0433 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437 \u0444\u0430\u0439\u043b\u043e\u0432 <code>requirements.txt<\/code> \u0438 <code>requirements.dev.txt<\/code>, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f:<\/p>\n<pre><code class=\"python\">def load_requirements(fname: str) -&gt; list:     requirements = []     with open(fname, 'r') as fp:         for req in parse_requirements(fp.read()):             extras = '[{}]'.format(','.join(req.extras)) if req.extras else ''             requirements.append(                 '{}{}{}'.format(req.name, extras, req.specifier)             )     return requirements<\/code><\/pre>\n<p>  \u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e <code>setuptools<\/code> \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 source distribution \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0431\u043e\u0440\u043a\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u044b <code>.py<\/code>, <code>.c<\/code>, <code>.cpp<\/code> \u0438 <code>.h<\/code>. \u0427\u0442\u043e\u0431\u044b \u0444\u0430\u0439\u043b\u044b \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 <code>requirements.txt<\/code> \u0438 <code>requirements.dev.txt<\/code> \u043f\u043e\u043f\u0430\u043b\u0438 \u0432 \u043f\u0430\u043a\u0435\u0442, \u0438\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432 \u0444\u0430\u0439\u043b\u0435 <code>MANIFEST.in<\/code>.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">setup.py \u0446\u0435\u043b\u0438\u043a\u043e\u043c<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os from importlib.machinery import SourceFileLoader  from pkg_resources import parse_requirements from setuptools import find_packages, setup  module_name = 'analyzer'  # \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043c\u043e\u0434\u0443\u043b\u044c \u0435\u0449\u0435 \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d (\u0438\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0434\u0440\u0443\u0433\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 # \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c __init__.py \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e machinery. module = SourceFileLoader(     module_name, os.path.join(module_name, '__init__.py') ).load_module()  def load_requirements(fname: str) -&gt; list:     requirements = []     with open(fname, 'r') as fp:         for req in parse_requirements(fp.read()):             extras = '[{}]'.format(','.join(req.extras)) if req.extras else ''             requirements.append(                 '{}{}{}'.format(req.name, extras, req.specifier)             )     return requirements  setup(     name=module_name,     version=module.__version__,     author=module.__author__,     author_email=module.__email__,     license=module.__license__,     description=module.__doc__,     long_description=open('README.rst').read(),     url='https:\/\/github.com\/alvassin\/backendschool2019',     platforms='all',     classifiers=[         'Intended Audience :: Developers',         'Natural Language :: Russian',         'Operating System :: MacOS',         'Operating System :: POSIX',         'Programming Language :: Python',         'Programming Language :: Python :: 3',         'Programming Language :: Python :: 3.8',         'Programming Language :: Python :: Implementation :: CPython'     ],     python_requires='&gt;=3.8',     packages=find_packages(exclude=['tests']),     install_requires=load_requirements('requirements.txt'),     extras_require={'dev': load_requirements('requirements.dev.txt')},     entry_points={         'console_scripts': [             # f-strings \u0432 setup.py \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0438\u0437-\u0437\u0430 \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439             # \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438.             # \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043f\u0430\u043a\u0435\u0442 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 Python 3.8, \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438             # source distribution \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u043e\u043b\u0435\u0435             # \u0440\u0430\u043d\u043d\u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 Python. \u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u043b\u0438\u0448\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u044d\u0442\u043e\u0439             # \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438.             '{0}-api = {0}.api.__main__:main'.format(module_name),             '{0}-db = {0}.db.__main__:main'.format(module_name)         ]     },     include_package_data=True )<\/code><\/pre>\n<\/div><\/div>\n<p>  \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439. (\u0412 editable-\u0440\u0435\u0436\u0438\u043c\u0435 Python \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 \u043c\u043e\u0434\u0443\u043b\u044c \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0432 \u043f\u0430\u043f\u043a\u0443 <code>site-packages<\/code>, \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0441\u0441\u044b\u043b\u043a\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043b\u044e\u0431\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0432\u043d\u043e\u0441\u0438\u043c\u044b\u0435 \u0432 \u0444\u0430\u0439\u043b\u044b \u043c\u043e\u0434\u0443\u043b\u044f, \u0431\u0443\u0434\u0443\u0442 \u0432\u0438\u0434\u043d\u044b \u0441\u0440\u0430\u0437\u0443.)<\/p>\n<pre><code class=\"python\"># \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c \u0441 \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 \u0438 extra-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 &quot;dev&quot; pip install -e '.[dev]'  # \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 pip install -e .<\/code><\/pre>\n<p>  <a name=\"requirements\"><\/a><\/p>\n<h2>\u041a\u0430\u043a \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439?<\/h2>\n<p>  \u0417\u0434\u043e\u0440\u043e\u0432\u043e, \u043a\u043e\u0433\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0441\u0432\u043e\u0438\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438 \u2014 \u0432 \u0442\u0430\u043a\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u044f\u0445 \u0430\u043a\u0442\u0438\u0432\u043d\u0435\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0438, \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u0432\u044f\u0437\u044c. \u041d\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u0445 \u043d\u0435 \u0438\u043c\u0435\u044e\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c \u0432 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u043e\u0431 \u044d\u0442\u043e\u043c \u0437\u0430\u0440\u0430\u043d\u0435\u0435.<\/p>\n<p>  \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>aiohttp==3.6.2<\/code>. \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0441 \u0442\u0435\u043c\u0438 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043e\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043e. \u041d\u043e \u0443 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0435\u0441\u0442\u044c \u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a \u2014 \u0435\u0441\u043b\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u044f\u0442 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u044b\u0439 \u0431\u0430\u0433 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u043c \u043c\u043e\u0434\u0443\u043b\u0435, \u043d\u0435 \u0432\u043b\u0438\u044f\u044e\u0449\u0438\u0439 \u043d\u0430 \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u044c, \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u043e\u043f\u0430\u0434\u0435\u0442.<\/p>\n<p>  \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e <a href=\"https:\/\/semver.org\">Semantic Versioning<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u044e \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>MAJOR.MINOR.PATCH<\/code>:<\/p>\n<ul>\n<li><code>MAJOR<\/code> \u2014 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439;<\/li>\n<li><code>MINOR<\/code> \u2014 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438;<\/li>\n<li><code>PATCH<\/code> \u2014 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0439 \u0431\u0430\u0433\u043e\u0432 \u0441 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u043e\u0439 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438.<\/li>\n<\/ul>\n<p>  \u0415\u0441\u043b\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0434\u0445\u043e\u0434\u0443 (\u043e \u0447\u0435\u043c \u0430\u0432\u0442\u043e\u0440\u044b \u043e\u0431\u044b\u0447\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0430\u044e\u0442 \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 README \u0438\u043b\u0438 CHANGELOG), \u0442\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <code>MAJOR<\/code>, <code>MINOR<\/code> \u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f PATCH-\u0432\u0435\u0440\u0441\u0438\u0438: <code>&gt;= MAJOR.MINOR.PATCH, == MAJOR.MINOR.*<\/code>. <\/p>\n<p>  \u0422\u0430\u043a\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0440\/#compatible-release\">~=<\/a>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>aiohttp~=3.6.2<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 PIP \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u043b\u044f <code>aiohttp<\/code> \u0432\u0435\u0440\u0441\u0438\u044e 3.6.3, \u043d\u043e \u043d\u0435 3.7. <\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0432\u0435\u0440\u0441\u0438\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u044d\u0442\u043e \u0434\u0430\u0441\u0442 \u0435\u0449\u0435 \u043e\u0434\u043d\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u2014 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u0432\u0435\u0440\u0441\u0438\u0439 \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438. <\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u043e\u0434\u0443\u043b\u044c-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c, \u0442\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u0435 \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u043d\u0435 \u043e\u0434\u043d\u0443 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e, \u0430 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b. \u0422\u043e\u0433\u0434\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f\u043c \u0432\u0430\u0448\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043b\u0435\u0433\u0447\u0435 \u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c (\u0432\u0434\u0440\u0443\u0433 \u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u044d\u0442\u043e\u0442 \u0436\u0435 \u043c\u043e\u0434\u0443\u043b\u044c-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c, \u043d\u043e \u0443\u0436\u0435 \u0434\u0440\u0443\u0433\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438).<\/p>\n<p>  Semantic Versioning \u2014 \u043b\u0438\u0448\u044c \u0441\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0430\u0432\u0442\u043e\u0440\u0430\u043c\u0438 \u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u0435\u0439. \u041e\u043d\u043e \u043d\u0435 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u0430\u0432\u0442\u043e\u0440\u044b \u043f\u0438\u0448\u0443\u0442 \u043a\u043e\u0434 \u0431\u0435\u0437 \u0431\u0430\u0433\u043e\u0432 \u0438 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443 \u0432 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u0432\u043e\u0435\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f. <\/p>\n<p>  <a name=\"db\"><\/a><\/p>\n<h2>\u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<p>  <a name=\"dbstructure\"><\/a><\/p>\n<h3>\u041f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0441\u0445\u0435\u043c\u0443<\/h3>\n<p>  \u0412 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 POST \/imports \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0436\u0438\u0442\u0435\u043b\u044f\u0445:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"json\">{   &quot;citizens&quot;: [     {       &quot;citizen_id&quot;: 1,       &quot;town&quot;: &quot;\u041c\u043e\u0441\u043a\u0432\u0430&quot;,       &quot;street&quot;: &quot;\u041b\u044c\u0432\u0430 \u0422\u043e\u043b\u0441\u0442\u043e\u0433\u043e&quot;,       &quot;building&quot;: &quot;16\u043a7\u0441\u0442\u04405&quot;,       &quot;apartment&quot;: 7,       &quot;name&quot;: &quot;\u0418\u0432\u0430\u043d\u043e\u0432 \u0418\u0432\u0430\u043d \u0418\u0432\u0430\u043d\u043e\u0432\u0438\u0447&quot;,       &quot;birth_date&quot;: &quot;26.12.1986&quot;,       &quot;gender&quot;: &quot;male&quot;,       &quot;relatives&quot;: [2]     },     {       &quot;citizen_id&quot;: 2,       &quot;town&quot;: &quot;\u041c\u043e\u0441\u043a\u0432\u0430&quot;,       &quot;street&quot;: &quot;\u041b\u044c\u0432\u0430 \u0422\u043e\u043b\u0441\u0442\u043e\u0433\u043e&quot;,       &quot;building&quot;: &quot;16\u043a7\u0441\u0442\u04405&quot;,       &quot;apartment&quot;: 7,       &quot;name&quot;: &quot;\u0418\u0432\u0430\u043d\u043e\u0432 \u0421\u0435\u0440\u0433\u0435\u0439 \u0418\u0432\u0430\u043d\u043e\u0432\u0438\u0447&quot;,       &quot;birth_date&quot;: &quot;01.04.1997&quot;,       &quot;gender&quot;: &quot;male&quot;,       &quot;relatives&quot;: [1]     },     {       &quot;citizen_id&quot;: 3,       &quot;town&quot;: &quot;\u041a\u0435\u0440\u0447\u044c&quot;,       &quot;street&quot;: &quot;\u0418\u043e\u0441\u0438\u0444\u0430 \u0411\u0440\u043e\u0434\u0441\u043a\u043e\u0433\u043e&quot;,       &quot;building&quot;: &quot;2&quot;,       &quot;apartment&quot;: 11,       &quot;name&quot;: &quot;\u0420\u043e\u043c\u0430\u043d\u043e\u0432\u0430 \u041c\u0430\u0440\u0438\u044f \u041b\u0435\u043e\u043d\u0438\u0434\u043e\u0432\u043d\u0430&quot;,       &quot;birth_date&quot;: &quot;23.11.1986&quot;,       &quot;gender&quot;: &quot;female&quot;,       &quot;relatives&quot;: []     },     ...   ] }<\/code><\/pre>\n<\/div><\/div>\n<p>  \u041f\u0435\u0440\u0432\u043e\u0439 \u043c\u044b\u0441\u043b\u044c\u044e \u0431\u044b\u043b\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0436\u0438\u0442\u0435\u043b\u0435 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 <code>citizens<\/code>, \u0433\u0434\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0441\u0432\u044f\u0437\u0438 \u0431\u044b\u043b\u0438 \u0431\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043f\u043e\u043b\u0435\u043c <code>relatives<\/code> \u0432 <b>\u0432\u0438\u0434\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0446\u0435\u043b\u044b\u0445 \u0447\u0438\u0441\u0435\u043b<\/b>.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041d\u043e \u0443 \u044d\u0442\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0435\u0441\u0442\u044c \u0440\u044f\u0434 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<ol>\n<li> \u0412 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 <code>GET \/imports\/$import_id\/citizens\/birthdays<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043c\u0435\u0441\u044f\u0446\u0435\u0432, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0434\u043d\u0438 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043b\u0438\u044f\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>citizens<\/code> \u0441 \u0441\u0430\u043c\u043e\u0439 \u0441\u043e\u0431\u043e\u0439. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432 <code>relatives<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u0446\u0438\u0438 <code>UNNEST<\/code>.\n<p>  \u0422\u0430\u043a\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e, \u0438 <b>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435 \u0443\u043b\u043e\u0436\u0438\u0442\u0441\u044f \u0432 10-\u0441\u0435\u043a\u0443\u043d\u0434\u043d\u044b\u0439 \u0442\u0430\u0439\u043c\u0430\u0443\u0442<\/b>:  <\/p>\n<pre><code class=\"sql\">SELECT      relations.citizen_id,      relations.relative_id,      date_part('month', relatives.birth_date) as relative_birth_month FROM ( \tSELECT         citizens.import_id,          citizens.citizen_id,         UNNEST(citizens.relatives) as relative_id \tFROM citizens     WHERE import_id = 1 ) as relations INNER JOIN citizens as relatives ON     relations.import_id = relatives.import_id AND     relations.relative_id = relatives.citizen_id <\/code><\/pre>\n<p>   <\/li>\n<li> \u0412 \u0442\u0430\u043a\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 <b>\u0446\u0435\u043b\u043e\u0441\u0442\u043d\u043e\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043f\u043e\u043b\u0435 <code>relatives<\/code> \u043d\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f PostgreSQL<\/b>, \u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c: \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a <code>relatives<\/code> \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u044e\u0431\u043e\u0435 \u0446\u0435\u043b\u043e\u0435 \u0447\u0438\u0441\u043b\u043e, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f. \u041e\u0448\u0438\u0431\u043a\u0430 \u0432 \u043a\u043e\u0434\u0435 \u0438\u043b\u0438 \u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u0438\u0439 \u0444\u0430\u043a\u0442\u043e\u0440 (\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0432 \u0411\u0414 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c) \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u043d\u043e \u0438\u043b\u0438 \u043f\u043e\u0437\u0434\u043d\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0443\u0442 \u043a \u043d\u0435\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u043d\u043e\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445.<\/li>\n<\/ol>\n<\/div><\/div>\n<p>  \u0414\u0430\u043b\u0435\u0435, \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u0432\u0441\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0434\u0430\u043d\u043d\u044b\u0435 \u043a <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A2%D1%80%D0%B5%D1%82%D1%8C%D1%8F_%D0%BD%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0\">\u0442\u0440\u0435\u0442\u044c\u0435\u0439 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435<\/a>, \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/di\/pf\/px\/dipfpxxw142kafiect0yhrtt4uo.png\"><\/p>\n<ol>\n<li> \u0422\u0430\u0431\u043b\u0438\u0446\u0430 <b>imports<\/b> \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430 <code>import_id<\/code>. \u041e\u043d \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u043c\u0443 \u043a\u043b\u044e\u0447\u0443 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 <code>citizens<\/code>.   <\/li>\n<li> \u0412 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 <b>citizens<\/b> \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f <b>\u0441\u043a\u0430\u043b\u044f\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435<\/b> \u043e \u0436\u0438\u0442\u0435\u043b\u0435 (\u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u044f\u0445).\n<p>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0430 (<code>import_id<\/code>, <code>citizen_id<\/code>), \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0436\u0438\u0442\u0435\u043b\u0435\u0439 <code>citizen_id<\/code> \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 <code>import_id<\/code>. <\/p>\n<p>  \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u043a\u043b\u044e\u0447 <code>citizens.import_id -&gt; imports.import_id<\/code> \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u043f\u043e\u043b\u0435 <code>citizens.import_id<\/code> \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438.   <\/li>\n<li> \u0422\u0430\u0431\u043b\u0438\u0446\u0430 <b>relations<\/b> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e <b>\u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u044f\u0445<\/b>.\n<p>  <b>\u041e\u0434\u043d\u0430 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0441\u0432\u044f\u0437\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0434\u0432\u0443\u043c\u044f \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438<\/b> (\u043e\u0442 \u0436\u0438\u0442\u0435\u043b\u044f \u043a \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0443 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e): \u044d\u0442\u0430 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043f\u0440\u0438 \u0441\u043b\u0438\u044f\u043d\u0438\u0438 \u0442\u0430\u0431\u043b\u0438\u0446 <code>citizens<\/code> \u0438 <code>relations<\/code> \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e.<br \/>  \u041f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 (<code>import_id<\/code>, <code>citizen_id<\/code>, <code>relative_id<\/code>) \u0438 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 <code>import_id<\/code> \u0443 \u0436\u0438\u0442\u0435\u043b\u044f <code>citizen_id<\/code> \u0431\u0443\u0434\u0443\u0442 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0438 c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 <code>relative_id<\/code>. <\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u0432\u0430 \u0441\u043e\u0441\u0442\u0430\u0432\u043d\u044b\u0445 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043a\u043b\u044e\u0447\u0430: <code>(relations.import_id, relations.citizen_id) -&gt; (citizens.import_id, citizens.citizen_id)<\/code> \u0438 <code>(relations.import_id, relations.relative_id) -&gt; (citizens.import_id, citizens.citizen_id)<\/code>, \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0435, \u0447\u0442\u043e \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u0431\u0443\u0434\u0443\u0442 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0436\u0438\u0442\u0435\u043b\u044c <code>citizen_id<\/code> \u0438 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a <code>relative_id<\/code> \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438.<\/li>\n<\/ol>\n<p>  \u0422\u0430\u043a\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 <b>\u0446\u0435\u043b\u043e\u0441\u0442\u043d\u043e\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c\u0438 PostgreSQL<\/b>, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 <b>\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0441 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438<\/b> \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e <b>\u043f\u043e\u0434\u0432\u0435\u0440\u0436\u0435\u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e \u0433\u043e\u043d\u043a\u0438<\/b> \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0436\u0438\u0442\u0435\u043b\u044f\u0445 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 PATCH).<\/p>\n<p>  <a name=\"do_sqlalchemy\"><\/a><\/p>\n<h3>\u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u0445\u0435\u043c\u0443 \u0432 SQLAlchemy<\/h3>\n<p>  \u0412 <a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#5\">\u043b\u0435\u043a\u0446\u0438\u0438 5<\/a> \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b, \u0447\u0442\u043e \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SQLAlchemy \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0445\u0435\u043c\u0443 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432: \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>sqlalchemy.Table<\/code> \u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043a \u0440\u0435\u0435\u0441\u0442\u0440\u0443 <code>sqlalchemy.MetaData<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u0440\u0430\u043d\u0438\u0442 \u0432\u0441\u044e \u043c\u0435\u0442\u0430\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a \u0441\u043b\u043e\u0432\u0443, \u0440\u0435\u0435\u0441\u0442\u0440 <code>MetaData<\/code> \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u0443\u044e \u0432 Python \u043c\u0435\u0442\u0430\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043d\u043e \u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 SQLAlchemy.<\/p>\n<p>  \u042d\u0442\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 Alembic \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438.<\/p>\n<p>  \u041a\u0441\u0442\u0430\u0442\u0438, \u0443 \u043a\u0430\u0436\u0434\u043e\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0432\u043e\u044f \u0441\u0445\u0435\u043c\u0430 \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f constraints \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e. \u0427\u0442\u043e\u0431\u044b \u0432\u044b \u043d\u0435 \u0442\u0440\u0430\u0442\u0438\u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 constraints \u0438\u043b\u0438 \u043d\u0430 \u0432\u043e\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f\/\u043f\u043e\u0438\u0441\u043a\u0438 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043d\u0430\u0437\u0432\u0430\u043d constraint, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0435\u0441\u044c \u0443\u0434\u0430\u043b\u0438\u0442\u044c, SQLAlchemy \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/docs.sqlalchemy.org\/en\/13\/core\/constraints.html#configuring-constraint-naming-conventions\">naming conventions<\/a>. \u0418\u0445 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 <code>MetaData<\/code>.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0440\u0435\u0435\u0441\u0442\u0440 MetaData \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432 \u043d\u0435\u0433\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># analyzer\/db\/schema.py from sqlalchemy import MetaData  convention = {     'all_column_names': lambda constraint, table: '_'.join([         column.name for column in constraint.columns.values()     ]),      # \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u0432     'ix': 'ix__%(table_name)s__%(all_column_names)s',      # \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u0432     'uq': 'uq__%(table_name)s__%(all_column_names)s',      # \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 CHECK-constraint-\u043e\u0432     'ck': 'ck__%(table_name)s__%(constraint_name)s',      # \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043a\u043b\u044e\u0447\u0435\u0439     'fk': 'fk__%(table_name)s__%(all_column_names)s__%(referred_table_name)s',      # \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439     'pk': 'pk__%(table_name)s' } metadata = MetaData(naming_convention=convention)<\/code><\/pre>\n<\/div><\/div>\n<p>  \u0415\u0441\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f, Alembic \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u043c\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u0438 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435 constraints \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043d\u0438\u043c\u0438. \u0412 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c c\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0440\u0435\u0435\u0441\u0442\u0440 <code>MetaData<\/code> \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u0445\u0435\u043c\u0443 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 SQLAlchemy<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># analyzer\/db\/schema.py from enum import Enum, unique  from sqlalchemy import (     Column, Date, Enum as PgEnum, ForeignKey, ForeignKeyConstraint, Integer,     String, Table )   @unique class Gender(Enum):     female = 'female'     male = 'male'   imports_table = Table(     'imports',     metadata,     Column('import_id', Integer, primary_key=True) )  citizens_table = Table(     'citizens',     metadata,     Column('import_id', Integer, ForeignKey('imports.import_id'),            primary_key=True),     Column('citizen_id', Integer, primary_key=True),     Column('town', String, nullable=False, index=True),     Column('street', String, nullable=False),     Column('building', String, nullable=False),     Column('apartment', Integer, nullable=False),     Column('name', String, nullable=False),     Column('birth_date', Date, nullable=False),     Column('gender', PgEnum(Gender, name='gender'), nullable=False), )  relations_table = Table(     'relations',     metadata,     Column('import_id', Integer, primary_key=True),     Column('citizen_id', Integer, primary_key=True),     Column('relative_id', Integer, primary_key=True),     ForeignKeyConstraint(         ('import_id', 'citizen_id'),         ('citizens.import_id', 'citizens.citizen_id')     ),     ForeignKeyConstraint(         ('import_id', 'relative_id'),         ('citizens.import_id', 'citizens.citizen_id')     ), ) <\/code><\/pre>\n<\/div><\/div>\n<p>  <a name=\"db_alembic\"><\/a><\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c Alembic<\/h3>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u0441\u0445\u0435\u043c\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u043f\u0438\u0441\u0430\u043d\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Alembic, \u043e\u0431 \u044d\u0442\u043e\u043c \u0442\u043e\u0436\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 <a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#5\">\u043b\u0435\u043a\u0446\u0438\u0438 5<\/a>.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>alembic<\/code>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438:<\/p>\n<ol>\n<li>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c: <code>pip install alembic<\/code><\/li>\n<li> \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c Alembic: <code>cd analyzer &amp;&amp; alembic init db\/alembic<\/code>.\n<p>  \u042d\u0442\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>analyzer\/alembic.ini<\/code> \u0438 \u043f\u0430\u043f\u043a\u0443 <code>analyzer\/db\/alembic<\/code> \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:   <\/p>\n<ul>\n<li> <code>env.py<\/code> \u2014 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 Alembic. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 Alembic \u0440\u0435\u0435\u0441\u0442\u0440 <code>sqlalchemy.MetaData<\/code> \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0411\u0414 \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u043f\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0443 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439.   <\/li>\n<li><code>script.py.mako<\/code> \u2014 \u0448\u0430\u0431\u043b\u043e\u043d, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438.<\/li>\n<li><code>versions<\/code> \u2014 \u043f\u0430\u043f\u043a\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 Alembic \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043a\u0430\u0442\u044c (\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c) \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438.<\/li>\n<\/ul>\n<\/li>\n<li> \u0423\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0444\u0430\u0439\u043b\u0435 alembic.ini:\n<pre><code class=\"plaintext\">; analyzer\/alembic.ini [alembic]  sqlalchemy.url = postgresql:\/\/user:hackme@localhost\/analyzer<\/code><\/pre>\n<\/li>\n<li> \u0423\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 (\u0440\u0435\u0435\u0441\u0442\u0440 <code>sqlalchemy.MetaData<\/code>), \u0447\u0442\u043e\u0431\u044b Alembic \u043c\u043e\u0433 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438:\n<pre><code class=\"python\"># analyzer\/db\/alembic\/env.py from analyzer.db import schema target_metadata = schema.metadata<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>  Alembic \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u0438 \u0438\u043c \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u043d\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u0430\u043a\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0438\u043c\u0435\u0435\u0442 \u0440\u044f\u0434 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432:<\/p>\n<ol>\n<li>\u0423\u0442\u0438\u043b\u0438\u0442\u0430 <code>alembic<\/code> \u0438\u0449\u0435\u0442 <code>alembic.ini<\/code> \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438. \u041f\u0443\u0442\u044c \u043a <code>alembic.ini<\/code> \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438, \u043d\u043e \u044d\u0442\u043e \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e: \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0438\u0437 \u043b\u044e\u0431\u043e\u0439 \u043f\u0430\u043f\u043a\u0438 \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432.<\/li>\n<li>\u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Alembic \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u043d\u044f\u0442\u044c \u0444\u0430\u0439\u043b <code>alembic.ini<\/code>. \u0413\u043e\u0440\u0430\u0437\u0434\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0431\u044b\u043b\u043e \u0431\u044b \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0411\u0414 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\/\u0438\u043b\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>--pg-url<\/code>.<\/li>\n<li>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0443\u0442\u0438\u043b\u0438\u0442\u044b <code>alembic<\/code> \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043a\u043e\u0440\u0440\u0435\u043b\u0438\u0440\u0443\u0435\u0442 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0432\u043b\u0430\u0434\u0435\u0442\u044c Python \u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0442\u044c \u043e\u0431 Alembic). \u041a\u043e\u043d\u0435\u0447\u043d\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0435, \u0435\u0441\u043b\u0438 \u0431\u044b \u0432\u0441\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438\u043c\u0435\u043b\u0438 \u043e\u0431\u0449\u0438\u0439 \u043f\u0440\u0435\u0444\u0438\u043a\u0441, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>analyzer-*<\/code>.<\/li>\n<\/ol>\n<p>  \u042d\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0440\u0435\u0448\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043e\u0431\u0435\u0440\u0442\u043a\u0438 <code>analyzer\/db\/__main__.py:<\/code><\/p>\n<ul>\n<li> \u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 Alembic \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c <code><a href=\"https:\/\/docs.python.org\/3\/library\/argparse.html\">argparse<\/a><\/code>. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 <code>--pg-url<\/code> \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f <code>ANALYZER_PG_URL<\/code>.\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os from alembic.config import CommandLine, Config from analyzer.utils.pg import DEFAULT_PG_URL   def main():     alembic = CommandLine()     alembic.parser.add_argument(         '--pg-url', default=os.getenv('ANALYZER_PG_URL', DEFAULT_PG_URL),         help='Database URL [env var: ANALYZER_PG_URL]'     )     options = alembic.parser.parse_args()      # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Alembic     config = Config(file_=options.config, ini_section=options.name,                     cmd_opts=options)      # \u041c\u0435\u043d\u044f\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 sqlalchemy.url \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0430 Alembic     config.set_main_option('sqlalchemy.url', options.pg_url)      # \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 alembic     exit(alembic.run_cmd(config, options))   if __name__ == '__main__':     main()<\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li>\u041f\u0443\u0442\u044c \u0434\u043e \u0444\u0430\u0439\u043b\u0430 <code>alembic.ini<\/code> \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430, \u0430 \u043d\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0440\u0430\u0431\u043e\u0447\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os from alembic.config import CommandLine, Config from pathlib import Path   PROJECT_PATH = Path(__file__).parent.parent.resolve()   def main():     alembic = CommandLine()     options = alembic.parser.parse_args()      # \u0415\u0441\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u043d \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c (alembic.ini), \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e     # \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0434\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f     if not os.path.isabs(options.config):         options.config = os.path.join(PROJECT_PATH, options.config)      # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Alembic     config = Config(file_=options.config, ini_section=options.name,                     cmd_opts=options)      # \u041f\u043e\u0434\u043c\u0435\u043d\u044f\u0435\u043c \u043f\u0443\u0442\u044c \u0434\u043e \u043f\u0430\u043f\u043a\u0438 \u0441 alembic \u043d\u0430 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0439 (\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b alembic     # \u043c\u043e\u0433 \u043d\u0430\u0439\u0442\u0438 env.py, \u0448\u0430\u0431\u043b\u043e\u043d \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u0438 \u0441\u0430\u043c\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438)     alembic_location = config.get_main_option('script_location')     if not os.path.isabs(alembic_location):         config.set_main_option('script_location',                                os.path.join(PROJECT_PATH, alembic_location))      # \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 alembic     exit(alembic.run_cmd(config, options))   if __name__ == '__main__':     main()<\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p>  \u041a\u043e\u0433\u0434\u0430 <a href=\"https:\/\/github.com\/alvassin\/backendschool2019\/blob\/master\/analyzer\/db\/__main__.py\">\u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0411\u0414<\/a> \u0433\u043e\u0442\u043e\u0432\u0430, \u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 <code>setup.py<\/code> \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0441 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>analyzer-db<\/code>:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 setup.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from setuptools import setup  setup(..., entry_points={     'console_scripts': [         'analyzer-db = analyzer.db.__main__:main'     ] }) <\/code><\/pre>\n<\/div><\/div>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043c\u043e\u0434\u0443\u043b\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0444\u0430\u0439\u043b <code>env\/bin\/analyzer-db<\/code> \u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 <code>analyzer-db<\/code> \u0441\u0442\u0430\u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0439:<\/p>\n<pre><code class=\"bash\">$ pip install -e '.[dev]'<\/code><\/pre>\n<p>  <a name=\"db_alembic_migrations\"><\/a><\/p>\n<h3>\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0432\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0435 (\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043e\u043f\u0438\u0441\u0430\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 SQLAlchemy) \u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 (\u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0443\u0441\u0442\u0430\u044f).<\/p>\n<p>  \u042f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u043f\u0440\u043e\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u043d\u044f\u0442\u044c Postgres \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Docker \u0438 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <code>make postgres<\/code>, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0443\u044e \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441 PostgreSQL \u043d\u0430 5432 \u043f\u043e\u0440\u0442\u0443:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u043c PostgreSQL \u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">$ make postgres ... $ analyzer-db revision --message=&quot;Initial&quot; --autogenerate INFO  [alembic.runtime.migration] Context impl PostgresqlImpl. INFO  [alembic.runtime.migration] Will assume transactional DDL. INFO  [alembic.autogenerate.compare] Detected added table 'imports' INFO  [alembic.autogenerate.compare] Detected added table 'citizens' INFO  [alembic.autogenerate.compare] Detected added index 'ix__citizens__town' on '['town']' INFO  [alembic.autogenerate.compare] Detected added table 'relations'   Generating \/Users\/alvassin\/Work\/backendschool2019\/analyzer\/db\/alembic\/versions\/d5f704ed4610_initial.py ...  done<\/code><\/pre>\n<\/div><\/div>\n<p>  Alembic \u0432 \u0446\u0435\u043b\u043e\u043c \u0445\u043e\u0440\u043e\u0448\u043e \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u0440\u0443\u0442\u0438\u043d\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u043e\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439, \u043d\u043e \u044f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ul>\n<li>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0445 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445, \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 <code>gender<\/code>), \u043d\u043e \u043a\u043e\u0434 \u0434\u043b\u044f \u0438\u0445 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0432 <code>downgrade<\/code> \u043d\u0435 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c, \u043e\u0442\u043a\u0430\u0442\u0438\u0442\u044c \u0438 \u043f\u043e\u0442\u043e\u043c \u0435\u0449\u0435 \u0440\u0430\u0437 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e, \u044d\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443, \u0442\u0430\u043a \u043a\u0430\u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 gender \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 downgrade<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from alembic import op from sqlalchemy import Column, Enum  GenderType = Enum('female', 'male', name='gender')   def upgrade():     ...     # \u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 GenderType \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438     op.create_table('citizens', ...,                     Column('gender', GenderType, nullable=False))     ...   def downgrade():     op.drop_table('citizens')      # \u041f\u043e\u0441\u043b\u0435 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c     GenderType.drop(op.get_bind())<\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li>\u0412 \u043c\u0435\u0442\u043e\u0434\u0435 <code>downgrade<\/code> \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438\u043d\u043e\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0443\u0431\u0440\u0430\u0442\u044c (\u0435\u0441\u043b\u0438 \u043c\u044b \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0446\u0435\u043b\u0438\u043a\u043e\u043c, \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0435\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e):\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def downgrade(): op.drop_table('relations')  # \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u043c\u044b \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 citizens, \u0438\u043d\u0434\u0435\u043a\u0441 \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u0435\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 # \u044d\u0442\u0443 \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c op.drop_index(op.f('ix__citizens__town'), table_name='citizens') op.drop_table('citizens') op.drop_table('imports')<\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<\/ul>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u0438 \u0433\u043e\u0442\u043e\u0432\u0430, \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u0435\u0435:<\/p>\n<pre><code class=\"bash\">$ analyzer-db upgrade head INFO  [alembic.runtime.migration] Context impl PostgresqlImpl. INFO  [alembic.runtime.migration] Will assume transactional DDL. INFO  [alembic.runtime.migration] Running upgrade  -&gt; d5f704ed4610, Initial<\/code><\/pre>\n<p>  <a name=\"application\"><\/a><\/p>\n<h2>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h2>\n<p>  \u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 aiohttp.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0415\u0441\u043b\u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c aiohttp quickstart, \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import logging  from aiohttp import web   def main():     # \u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435     logging.basicConfig(level=logging.DEBUG)      # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435     app = web.Application()      # \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438     app.router.add_route(...)      # \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435     web.run_app(app) <\/code><\/pre>\n<\/div><\/div>\n<p>  \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0440\u044f\u0434 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u0438\u043c\u0435\u0435\u0442 \u0440\u044f\u0434 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432:<\/p>\n<ul>\n<li> <strong>\u041a\u0430\u043a \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435?<\/strong> \u041a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0445\u043e\u0441\u0442 \u0438 \u043f\u043e\u0440\u0442 \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.\n<p>  \u041c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0440\u0435\u0448\u0430\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u0434\u0443\u043b\u044f <a href=\"https:\/\/pypi.org\/project\/ConfigArgParse\/\"><code>ConfigArgParse<\/code><\/a>: \u043e\u043d \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 <a href=\"https:\/\/docs.python.org\/3\/library\/argparse.html\"><code>argparse<\/code><\/a> \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438, \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f (\u043d\u0435\u0437\u0430\u043c\u0435\u043d\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432) \u0438 \u0434\u0430\u0436\u0435 \u0444\u0430\u0439\u043b\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (\u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0432\u043c\u0435\u0449\u0430\u0442\u044c \u044d\u0442\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u044b). C \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>ConfigArgParse<\/code> \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e ConfigArgParse<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from aiohttp import web from configargparse import ArgumentParser, ArgumentDefaultsHelpFormatter  from analyzer.utils.argparse import positive_int  parser = ArgumentParser(     # \u041f\u0430\u0440\u0441\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043a\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c ANALYZER_,     # \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 ANALYZER_API_ADDRESS \u0438 ANALYZER_API_PORT     auto_env_var_prefix='ANALYZER_',      # \u041f\u043e\u043a\u0430\u0436\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e     formatter_class=ArgumentDefaultsHelpFormatter )  parser.add_argument('--api-address', default='0.0.0.0',                     help='IPv4\/IPv6 address API server would listen on')  # \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0446\u0435\u043b\u044b\u0435 \u0447\u0438\u0441\u043b\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0443\u043b\u044f parser.add_argument('--api-port', type=positive_int, default=8081,                     help='TCP port API server would listen on')   def main():     # \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043a\u0430\u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438     # \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438, \u0442\u0430\u043a \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f     args = parser.parse_args()      # \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c \u043f\u043e\u0440\u0442\u0443 \u0438 \u0430\u0434\u0440\u0435\u0441\u0435     app = web.Application()     web.run_app(app, host=args.api_address, port=args.api_port)   if __name__ == '__main__':     main()<\/code><\/pre>\n<\/div><\/div>\n<p>  \u041a\u0441\u0442\u0430\u0442\u0438, <code>ConfigArgParse<\/code>, \u043a\u0430\u043a \u0438 <code>argparse<\/code>, \u0443\u043c\u0435\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0443 \u043f\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0432\u0441\u0435\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 (\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0437\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0441 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c <code>-h<\/code> \u0438\u043b\u0438 <code>--help<\/code>). \u042d\u0442\u043e \u043d\u0435\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0436\u0438\u0437\u043d\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0432\u0430\u0448\u0435\u0433\u043e \u041f\u041e:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"bash\">$ python __main__.py --help usage: __main__.py [-h] [--api-address API_ADDRESS] [--api-port API_PORT]  If an arg is specified in more than one place, then commandline values override environment variables which override defaults.  optional arguments:   -h, --help            show this help message and exit   --api-address API_ADDRESS                         IPv4\/IPv6 address API server would listen on [env var: ANALYZER_API_ADDRESS] (default: 0.0.0.0)   --api-port API_PORT   TCP port API server would listen on [env var: ANALYZER_API_PORT] (default: 8081)<\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li> \u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u044b \u0438 \u0434\u0430\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u2014 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u00ab\u0443\u0442\u0435\u0447\u044c\u00bb \u0441 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435. \u0417\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u0438 \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0431\u0443\u0434\u0443\u0442 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 <strong>\u043e\u0447\u0438\u0441\u0442\u043a\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0445\u043e\u0440\u043e\u0448\u0438\u043c \u0442\u043e\u043d\u043e\u043c<\/strong>.\n<p>  \u041c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <code>os.environ.clear()<\/code>, \u043d\u043e Python \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043d\u043e\u0433\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u0434\u0440\u0443\u0433 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u043e\u0442\u043b\u0430\u0434\u043a\u0438 <code>asyncio<\/code>?), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0430\u0437\u0443\u043c\u043d\u0435\u0435 \u043e\u0447\u0438\u0449\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0432 <code>ConfigArgParser<\/code>.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os from typing import Callable from configargparse import ArgumentParser from yarl import URL  from analyzer.api.app import create_app from analyzer.utils.pg import DEFAULT_PG_URL  ENV_VAR_PREFIX = 'ANALYZER_'  parser = ArgumentParser(auto_env_var_prefix=ENV_VAR_PREFIX) parser.add_argument('--pg-url', type=URL, default=URL(DEFAULT_PG_URL),                    help='URL to use to connect to the database')   def clear_environ(rule: Callable):     &quot;&quot;&quot;     \u041e\u0447\u0438\u0449\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f, \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u0430\u044f     \u0444\u0443\u043d\u043a\u0446\u0438\u044f rule     &quot;&quot;&quot;     # \u041a\u043b\u044e\u0447\u0438 \u0438\u0437 os.environ \u043a\u043e\u043f\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 \u043d\u043e\u0432\u044b\u0439 tuple, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043c\u0435\u043d\u044f\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442     # os.environ \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438     for name in filter(rule, tuple(os.environ)):         os.environ.pop(name)   def main():     # \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b     args = parser.parse_args()      # \u041e\u0447\u0438\u0449\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0443 ANALYZER_     clear_environ(lambda i: i.startswith(ENV_VAR_PREFIX))      # \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435     app = create_app(args)     ...   if __name__ == '__main__':     main()<\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li> <strong>\u0417\u0430\u043f\u0438\u0441\u044c \u043b\u043e\u0433\u043e\u0432 \u0432 stderr\/\u0444\u0430\u0439\u043b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 \u0446\u0438\u043a\u043b \u0441\u043e\u0431\u044b\u0442\u0438\u0439.<\/strong>\n<p>  \u0412 <a href=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/498856\/#9\">\u043b\u0435\u043a\u0446\u0438\u0438 9<\/a> \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <code>logging.basicConfig()<\/code> \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 <a href=\"https:\/\/github.com\/python\/cpython\/blob\/950c6795aa0ffa85e103a13e7a04e08cb34c66ad\/Lib\/logging\/__init__.py#L1907\"><code>\u0437\u0430\u043f\u0438\u0441\u044c \u043b\u043e\u0433\u043e\u0432 \u0432 stderr<\/code><\/a>.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435 \u043c\u0435\u0448\u0430\u043b\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u043b\u043e\u0433\u043e\u0432 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"https:\/\/github.com\/aiokitchen\/aiomisc#buffered-log-handler\">\u0433\u043e\u0442\u043e\u0432\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c<\/a> \u0438\u0437 \u043c\u043e\u0434\u0443\u043b\u044f aiomisc.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e aiomisc<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import logging  from aiomisc.log import basic_config  basic_config(logging.DEBUG, buffered=True)     <\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li> <strong>\u041a\u0430\u043a \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0441\u0442\u0430\u043d\u0435\u0442 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e<\/strong> \u0434\u043b\u044f \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0442\u0440\u0430\u0444\u0438\u043a\u0430? \u041c\u043e\u0436\u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0430\u043b\u043b\u043e\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043a\u0435\u0442, \u0437\u0430\u0442\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Fork\"><code>fork<\/code><\/a> \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u043e\u0432\u044b\u0445 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432, \u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043e\u043a\u0435\u0442\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430\u043c\u0438 \u044f\u0434\u0440\u0430 (\u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u043e\u0434 Windows \u044d\u0442\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442).\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os from sys import argv  import forklib from aiohttp.web import Application, run_app from aiomisc import bind_socket from setproctitle import setproctitle   def main():     sock = bind_socket(address='0.0.0.0', port=8081, proto_name='http')     setproctitle(f'[Master] {os.path.basename(argv[0])}')      def worker():         setproctitle(f'[Worker] {os.path.basename(argv[0])}')         app = Application()         run_app(app, sock=sock)      forklib.fork(os.cpu_count(), worker, auto_restart=True)   if __name__ == '__main__':     main() <\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li> \u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e <strong>\u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0438\u043b\u0438 \u0430\u043b\u043b\u043e\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b<\/strong>? \u0415\u0441\u043b\u0438 \u043d\u0435\u0442, \u043f\u043e \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0432\u0441\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 \u0441\u043e\u043a\u0435\u0442 \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432) \u043c\u043e\u0436\u043d\u043e \u0430\u043b\u043b\u043e\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u0435, \u0430 \u0437\u0430\u0442\u0435\u043c \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 <code>nobody<\/code>. \u041e\u043d \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043f\u0440\u0438\u0432\u0438\u043b\u043b\u0435\u0433\u0438\u0439 \u2014 \u044d\u0442\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u043e \u0443\u0441\u043b\u043e\u0436\u043d\u0438\u0442 \u0436\u0438\u0437\u043d\u044c \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u0430\u043c.\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os import pwd  from aiohttp.web import run_app from aiomisc import bind_socket  from analyzer.api.app import create_app   def main():     # \u0410\u043b\u043b\u043e\u0446\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u043a\u0435\u0442     sock = bind_socket(address='0.0.0.0', port=8085, proto_name='http')      user = pwd.getpwnam('nobody')     os.setgid(user.pw_gid)     os.setuid(user.pw_uid)      app = create_app(...)     run_app(app, sock=sock)   if __name__ == '__main__':     main()<\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li>\u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432 \u044f \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0443\u0435\u043c\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>create_app<\/code>, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043b\u0435\u0433\u043a\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/li>\n<\/ul>\n<p>  <a name=\"serialization\"><\/a><\/p>\n<h2>\u0421\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445<\/h2>\n<p>  \u0412\u0441\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0435 \u043e\u0442\u0432\u0435\u0442\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0442\u043e\u0436\u0435 \u0431\u044b\u043b\u043e \u0431\u044b \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0432 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u044f \u043d\u0435 \u043f\u0440\u043e\u0448\u043b\u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e).<\/p>\n<p>  \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f <code>aiohttp<\/code> \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/docs.aiohttp.org\/en\/stable\/web_quickstart.html#json-response\"><code>json_response<\/code><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442, \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0435\u0433\u043e \u0432 JSON \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 <code>aiohttp.web.Response<\/code> \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c <code>Content-Type: application\/json<\/code> \u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432\u043d\u0443\u0442\u0440\u0438.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u0430\u043a \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e json_response<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from aiohttp.web import Application, View, run_app from aiohttp.web_response import json_response   class SomeView(View):     async def get(self):         return json_response({'hello': 'world'})   app = Application() app.router.add_route('*', '\/hello', SomeView) run_app(app) <\/code><\/pre>\n<\/div><\/div>\n<p>  \u041d\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431: aiohttp \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442\u0432\u0435\u0442\u0430 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 <code>aiohttp.PAYLOAD_REGISTRY<\/code>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 <code>aiohttp.JsonPayload<\/code> \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0442\u0438\u043f\u0430 <a href=\"https:\/\/docs.python.org\/3\/library\/collections.abc.html#collections.abc.Mapping\">Mapping<\/a>. <\/p>\n<p>  \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 <code>Response<\/code> \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0442\u0432\u0435\u0442\u0430 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0435 <code>body<\/code>. aiohttp \u043d\u0430\u0439\u0434\u0435\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0442\u0438\u043f\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043e\u0442\u0432\u0435\u0442. <\/p>\n<p>  \u041f\u043e\u043c\u0438\u043c\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0435\u0449\u0435 \u0438 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0438\u0439 \u2014 \u043e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f (\u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 <code>GET \/imports\/$import_id\/citizens<\/code>). <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u0430\u043a \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e aiohttp.PAYLOAD_REGISTRY<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from types import MappingProxyType from typing import Mapping  from aiohttp import PAYLOAD_REGISTRY, JsonPayload from aiohttp.web import run_app, Application, Response, View  PAYLOAD_REGISTRY.register(JsonPayload, (Mapping, MappingProxyType))   class SomeView(View):     async def get(self):         return Response(body={'hello': 'world'})   app = Application() app.router.add_route('*', '\/hello', SomeView) run_app(app) <\/code><\/pre>\n<\/div><\/div>\n<p>  \u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 <code>json_response<\/code>, \u043a\u0430\u043a \u0438 <code>aiohttp.JsonPayload<\/code>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 <a href=\"https:\/\/docs.python.org\/3\/library\/json.html#json.dumps\"><code>json.dumps<\/code><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <code>datetime.date<\/code> \u0438\u043b\u0438 <code>asyncpg.Record<\/code> (<code>asyncpg<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0411\u0414 \u0432 \u0432\u0438\u0434\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430). \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u043e\u0434\u043d\u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435: \u0432 \u043e\u0434\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0411\u0414 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435 \u0442\u0438\u043f\u0430 <code>datetime.date<\/code>.<\/p>\n<p>  \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 Python \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443: \u043c\u0435\u0442\u043e\u0434 <code>json.dumps<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 <code>default<\/code> \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442. \u041e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043d\u0435\u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a \u0442\u0438\u043f\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043c\u0435\u0435\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c json.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u0430\u043a \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c JsonPayload \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import json from datetime import date from functools import partial, singledispatch from typing import Any  from aiohttp.payload import JsonPayload as BaseJsonPayload from aiohttp.typedefs import JSONEncoder  @singledispatch def convert(value):     raise NotImplementedError(f'Unserializable value: {value!r}')   @convert.register(Record) def convert_asyncpg_record(value: Record):     &quot;&quot;&quot;     \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0435     asyncpg     &quot;&quot;&quot;     return dict(value)   @convert.register(date) def convert_date(value: date):     &quot;&quot;&quot;     \u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u0431\u044a\u0435\u043a\u0442 date \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043e\u0434\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 \u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e     \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0434\u0430\u0442\u0443 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u0442\u044b \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u0435\u043d     \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0444\u043e\u0440\u043c\u0430\u0442 \u0414\u0414.\u041c\u041c.\u0413\u0413\u0413\u0413     &quot;&quot;&quot;     return value.strftime('%d.%m.%Y')        dumps = partial(json.dumps, default=convert)   class JsonPayload(BaseJsonPayload):     def __init__(self,                  value: Any,                  encoding: str = 'utf-8',                  content_type: str = 'application\/json',                  dumps: JSONEncoder = dumps,                  *args: Any,                  **kwargs: Any) -&gt; None:         super().__init__(value, encoding, content_type, dumps, *args, **kwargs)<\/code><\/pre>\n<\/div><\/div>\n<p>  <a name=\"handlers\"><\/a><\/p>\n<h2>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438<\/h2>\n<p>  aiohttp \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438. \u041a\u043b\u0430\u0441\u0441\u044b \u0431\u043e\u043b\u0435\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u044b: \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043a\u043e\u0434, \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0439\u0441\u044f \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443, \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435, \u0430 \u0432\u043e \u0432\u0442\u043e\u0440\u044b\u0445, \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u0438\u0437\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0442 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445).<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from aiohttp.web_urldispatcher import View from asyncpgsa import PG   class BaseView(View):     URL_PATH: str      @property     def pg(self) -&gt; PG:         return self.request.app['pg'] <\/code><\/pre>\n<\/div><\/div>\n<p>  \u0422\u0430\u043a \u043a\u0430\u043a \u043e\u0434\u0438\u043d \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0444\u0430\u0439\u043b \u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u043e, \u044f \u0440\u0435\u0448\u0438\u043b \u0440\u0430\u0437\u043d\u0435\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043f\u043e \u0444\u0430\u0439\u043b\u0430\u043c. \u041c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u043f\u043e\u043e\u0449\u0440\u044f\u044e\u0442 \u0441\u043b\u0430\u0431\u0443\u044e \u0441\u0432\u044f\u0437\u043d\u043e\u0441\u0442\u044c, \u0430 \u0435\u0441\u043b\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u0442\u044c \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u044b\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u0445\u044d\u043d\u0434\u043b\u0435\u0440\u043e\u0432 \u2014 \u0437\u043d\u0430\u0447\u0438\u0442, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0442\u0430\u043a \u0441 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>  <a name=\"imports_handler\"><\/a><\/p>\n<h3>POST \/imports<\/h3>\n<p>  \u041d\u0430 \u0432\u0445\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 json \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e \u0436\u0438\u0442\u0435\u043b\u044f\u0445. <b>\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/b> \u0432 aiohttp \u0440\u0435\u0433\u0443\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u0435\u0439 <code>client_max_size<\/code> \u0438 <a href=\"http:\/\/docs.aiohttp.org\/en\/stable\/web_reference.html#aiohttp.web.Application\">\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0440\u0430\u0432\u0435\u043d 2 \u041c\u0411<\/a>. \u041f\u0440\u0438 \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0438\u0438 \u043b\u0438\u043c\u0438\u0442\u0430 aiohttp \u0432\u0435\u0440\u043d\u0435\u0442 HTTP-\u043e\u0442\u0432\u0435\u0442 \u0441\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u043c 413: Request Entity Too Large Error. <\/p>\n<p>  \u0412 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 json c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u0438\u043d\u043d\u044b\u043c\u0438 \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u043c\u0438 \u0438 \u0446\u0438\u0444\u0440\u0430\u043c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0441\u0438\u0442\u044c ~63 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043d\u0430 \u0440\u0430\u0437\u043c\u0435\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c.<\/p>\n<p>  \u0414\u0430\u043b\u0435\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <strong>\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435<\/strong>. \u0415\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435, \u043d\u0443\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c HTTP-\u043e\u0442\u0432\u0435\u0442 <code>400: Bad Request<\/code>. <\/p>\n<p>  \u041c\u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0434\u0432\u0435 \u0441\u0445\u0435\u043c\u044b <code>Marhsmallow<\/code>. \u041f\u0435\u0440\u0432\u0430\u044f, <code>CitizenSchema<\/code>, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u0434\u043d\u0435\u043c \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 <code>datetime.date<\/code>:<\/p>\n<ul>\n<li>\u0422\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445, \u0444\u043e\u0440\u043c\u0430\u0442 \u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0432\u0441\u0435\u0445 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439;<\/li>\n<li>\u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0435\u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0445 \u043f\u043e\u043b\u0435\u0439;<\/li>\n<li>\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>DD.MM.YYYY<\/code> \u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e;<\/li>\n<li>\u0421\u043f\u0438\u0441\u043e\u043a \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0432 \u044d\u0442\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0436\u0438\u0442\u0435\u043b\u0435\u0439.<\/li>\n<\/ul>\n<p>  \u0412\u0442\u043e\u0440\u0430\u044f \u0441\u0445\u0435\u043c\u0430, <code>ImportSchema<\/code>, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0432 \u0446\u0435\u043b\u043e\u043c:<\/p>\n<ul>\n<li><code>citizen_id<\/code> \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u0435\u043d;<\/li>\n<li>\u0420\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0441\u0432\u044f\u0437\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0434\u0432\u0443\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c\u0438 (\u0435\u0441\u043b\u0438 \u0443 \u0436\u0438\u0442\u0435\u043b\u044f #1 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432 \u0443\u043a\u0430\u0437\u0430\u043d \u0436\u0438\u0442\u0435\u043b\u044c #2, \u0442\u043e \u0438 \u0443 \u0436\u0438\u0442\u0435\u043b\u044f #2 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a #1).<\/li>\n<\/ul>\n<p>  <strong>\u0415\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435, \u0438\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0411\u0414<\/strong> \u0441 \u043d\u043e\u0432\u044b\u043c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c <code>import_id<\/code>. <br \/>  \u0414\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u0427\u0442\u043e\u0431\u044b \u0432 \u0411\u0414 \u043d\u0435 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438 \u0438\u043b\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u043e\u0442\u0432\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e, aiohttp <a href=\"http:\/\/docs.aiohttp.org\/en\/stable\/web_advanced.html?highlight=shield#web-handler-cancellation\">\u0431\u0440\u043e\u0441\u0438\u0442 \u0438\u0441\u043a\u043e\u043b\u044e\u0447\u0435\u043d\u0438\u0435 CancelledError<\/a>), <strong>\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e<\/strong>.<\/p>\n<p>  <strong>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0447\u0430\u0441\u0442\u044f\u043c\u0438<\/strong>, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u043e\u0434\u043d\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a PostgreSQL \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435 \u0431\u043e\u043b\u0435\u0435 32 767 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432. \u0412 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 <code>citizens<\/code> 9 \u043f\u043e\u043b\u0435\u0439. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0437\u0430 1 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u044d\u0442\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e 32 767 \/ 9 = 3640 \u0441\u0442\u0440\u043e\u043a, \u0430 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0434\u043e 10 000 \u0436\u0438\u0442\u0435\u043b\u0435\u0439.<\/p>\n<p>  <a name=\"citizens_handler\"><\/a><\/p>\n<h3>GET \/imports\/$import_id\/citizens<\/h3>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0432\u0441\u0435\u0445 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0434\u043b\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c <code>import_id<\/code>. \u0415\u0441\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u0430\u044f <b>\u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442<\/b>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c HTTP-\u043e\u0442\u0432\u0435\u0442 404: Not Found. \u042d\u0442\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u0431\u0449\u0438\u043c \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0432\u044b\u043d\u0435\u0441 \u043a\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430\u043c\u0438<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from aiohttp.web_exceptions import HTTPNotFound from sqlalchemy import select, exists  from analyzer.db.schema import imports_table   class BaseImportView(BaseView):     @property     def import_id(self):         return int(self.request.match_info.get('import_id'))      async def check_import_exists(self):         query = select([             exists().where(imports_table.c.import_id == self.import_id)         ])         if not await self.pg.fetchval(query):             raise HTTPNotFound() <\/code><\/pre>\n<\/div><\/div>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c <code>LEFT JOIN<\/code> \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>citizens<\/code> \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 <code>relations<\/code>, \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u0443\u044f \u043f\u043e\u043b\u0435 <code>relations.relative_id<\/code> \u0441 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u043f\u043e <code>import_id<\/code> \u0438 <code>citizen_id<\/code>. <\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0443 \u0436\u0438\u0442\u0435\u043b\u044f \u043d\u0435\u0442 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u0442\u043e <code>LEFT JOIN<\/code> \u0432\u0435\u0440\u043d\u0435\u0442 \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0432 \u043f\u043e\u043b\u0435 <code>relations.relative_id<\/code> \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>NULL<\/code> \u0438 \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0430\u0433\u0440\u0435\u0433\u0430\u0446\u0438\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a <code>[NULL]<\/code>.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u044d\u0442\u043e \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 <a href=\"https:\/\/postgrespro.ru\/docs\/postgrespro\/12\/functions-array\">array_remove<\/a>.<\/p>\n<p>  \u0411\u0414 \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u0442\u0443 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>YYYY-MM-DD<\/code>, \u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0444\u043e\u0440\u043c\u0430\u0442 <code>DD.MM.YYYY<\/code>. <\/p>\n<p>  \u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u0442\u0443 \u043c\u043e\u0436\u043d\u043e \u043b\u0438\u0431\u043e SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c, \u043b\u0438\u0431\u043e \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Python \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u0430 \u0441 <code>json.dumps<\/code> (asyncpg \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f <code>birth_date<\/code> \u043a\u0430\u043a \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <code>datetime.date<\/code>). <\/p>\n<p>  \u042f \u0432\u044b\u0431\u0440\u0430\u043b \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Python, \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u044f, \u0447\u0442\u043e <code>birth_date<\/code> \u2014 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 <code>datetime.date<\/code> \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0441 \u0435\u0434\u0438\u043d\u044b\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u043c (\u0441\u043c. \u0440\u0430\u0437\u0434\u0435\u043b <a href=\"#serialization\">\u00ab\u0421\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445\u00bb<\/a>).<\/p>\n<p>  \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u0432\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0436\u0438\u0442\u0435\u043b\u0435\u0439), <b>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e<\/b>. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e PostgreSQL \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 <code>READ COMMITTED<\/code> \u0438 \u0434\u0430\u0436\u0435 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u0438\u0434\u043d\u044b \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433\u0438\u0445, \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 (\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0441\u0442\u0440\u043e\u043a, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445).<\/p>\n<p>  \u0421\u0430\u043c\u0430\u044f \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c ~63 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u0430 \u2014 \u044d\u0442\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043c\u043d\u043e\u0433\u043e, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u044f, \u0447\u0442\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0439\u0442\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 <b>\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0411\u0414 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/postgrespro.ru\/docs\/postgrespro\/10\/plpgsql-cursors\">\u043a\u0443\u0440\u0441\u043e\u0440\u0430<\/a> \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u043f\u043e \u0447\u0430\u0441\u0442\u044f\u043c<\/b>. <\/p>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0432\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430: <\/p>\n<ol>\n<li> \u041e\u0431\u044a\u0435\u043a\u0442 <code>SelectQuery<\/code> \u0442\u0438\u043f\u0430 <code>AsyncIterable<\/code>, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0431\u0430\u0437\u0435, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043a\u0443\u0440\u0441\u043e\u0440, \u043f\u0440\u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0411\u0414. \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c.\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434 SelectQuery<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from collections import AsyncIterable from asyncpgsa.transactionmanager import ConnectionTransactionContextManager from sqlalchemy.sql import Select   class SelectQuery(AsyncIterable):     &quot;&quot;&quot;     \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 PostgreSQL \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435     \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f, \u043f\u043e \u0447\u0430\u0441\u0442\u044f\u043c, \u0431\u0435\u0437 \u0431\u0443\u0444\u0444\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0445 \u0434\u0430\u043d\u043d\u044b\u0445     &quot;&quot;&quot;     PREFETCH = 500      __slots__ = (         'query', 'transaction_ctx', 'prefetch', 'timeout'     )      def __init__(self, query: Select,                  transaction_ctx: ConnectionTransactionContextManager,                  prefetch: int = None,                  timeout: float = None):         self.query = query         self.transaction_ctx = transaction_ctx         self.prefetch = prefetch or self.PREFETCH         self.timeout = timeout      async def __aiter__(self):         async with self.transaction_ctx as conn:             cursor = conn.cursor(self.query, prefetch=self.prefetch,                                  timeout=self.timeout)             async for row in cursor:                 yield row <\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<li> \u0421\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 <code>AsyncGenJSONListPayload<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043c\u0435\u0435\u0442 \u0438\u0442\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u043c, \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0432 JSON \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u043f\u043e \u0447\u0430\u0441\u0442\u044f\u043c. \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 <code>aiohttp.PAYLOAD_REGISTRY<\/code> \u043a\u0430\u043a \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 <code>AsyncIterable<\/code>.\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434 AsyncGenJSONListPayload<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import json from functools import partial  from aiohttp import Payload   # \u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u0443\u043c\u0435\u044e\u0449\u0430\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432 JSON \u043e\u0431\u044a\u0435\u043a\u0442\u044b asyncpg.Record \u0438 datetime.date dumps = partial(json.dumps, default=convert, ensure_ascii=False)   class AsyncGenJSONListPayload(Payload):     &quot;&quot;&quot;     \u0418\u0442\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c AsyncIterable, \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445     \u0432 JSON \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0443     &quot;&quot;&quot;     def __init__(self, value, encoding: str = 'utf-8',                  content_type: str = 'application\/json',                  root_object: str = 'data',                  *args, **kwargs):         self.root_object = root_object         super().__init__(value, content_type=content_type, encoding=encoding,                          *args, **kwargs)      async def write(self, writer):         # \u041d\u0430\u0447\u0430\u043b\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430         await writer.write(             ('{&quot;%s&quot;:[' % self.root_object).encode(self._encoding)         )          first = True         async for row in self._value:             # \u041f\u0435\u0440\u0435\u0434 \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u0447\u043a\u043e\u0439 \u0437\u0430\u043f\u044f\u0442\u0430\u044f \u043d\u0435 \u043d\u0443\u0436\u043d\u0430\u0430             if not first:                 await writer.write(b',')             else:                 first = False              await writer.write(dumps(row).encode(self._encoding))          # \u041a\u043e\u043d\u0435\u0446 \u043e\u0431\u044a\u0435\u043a\u0442\u0430         await writer.write(b']}')<\/code><\/pre>\n<\/div><\/div>\n<\/li>\n<\/ol>\n<p>  \u0414\u0430\u043b\u0435\u0435, \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 <code>SelectQuery<\/code>, \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0435\u043c\u0443 SQL \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0435\u0433\u043e \u0432 <code>Response body<\/code>:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># analyzer\/api\/handlers\/citizens.py from aiohttp.web_response import Response from aiohttp_apispec import docs, response_schema  from analyzer.api.schema import CitizensResponseSchema from analyzer.db.schema import citizens_table as citizens_t from analyzer.utils.pg import SelectQuery  from .query import CITIZENS_QUERY from .base import BaseImportView   class CitizensView(BaseImportView):     URL_PATH = r'\/imports\/{import_id:\\d+}\/citizens'      @docs(summary='\u041e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438')     @response_schema(CitizensResponseSchema())     async def get(self):         await self.check_import_exists()          query = CITIZENS_QUERY.where(             citizens_t.c.import_id == self.import_id         )         body = SelectQuery(query, self.pg.transaction())         return Response(body=body) <\/code><\/pre>\n<\/div><\/div>\n<p>  <code>aiohttp<\/code> \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 <code>aiohttp.PAYLOAD_REGISTRY<\/code> \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 <code>AsyncGenJSONListPayload<\/code> \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0442\u0438\u043f\u0430 <code>AsyncIterable<\/code>. \u0417\u0430\u0442\u0435\u043c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u0431\u0443\u0434\u0435\u0442 \u0438\u0442\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0443 <code>SelectQuery<\/code> \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0443. \u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 <code>SelectQuery<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043a \u0411\u0414, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043a\u0443\u0440\u0441\u043e\u0440, \u043f\u0440\u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0411\u0414 \u043a\u0443\u0440\u0441\u043e\u0440\u043e\u043c \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u0445 \u043f\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u043e.<\/p>\n<p>  \u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c \u043f\u0430\u043c\u044f\u0442\u044c \u043d\u0430 \u0432\u0435\u0441\u044c \u043e\u0431\u044a\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435, \u043d\u043e \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c: \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 HTTP-\u0441\u0442\u0430\u0442\u0443\u0441, \u0435\u0441\u043b\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 (\u0432\u0435\u0434\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0443\u0436\u0435 \u0431\u044b\u043b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d HTTP-\u0441\u0442\u0430\u0442\u0443\u0441, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438, \u0438 \u043f\u0438\u0448\u0443\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435). <\/p>\n<p>  \u041f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0435 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0438\u0447\u0435\u0433\u043e, \u043a\u0440\u043e\u043c\u0435 \u043a\u0430\u043a \u0440\u0430\u0437\u043e\u0440\u0432\u0430\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435. \u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043d\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a\u0430\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430. <\/p>\n<p>  \u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u043f\u043e\u0445\u043e\u0436\u0430\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0411\u0414, \u043d\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u043c\u043e\u0440\u0433\u043d\u0435\u0442 \u0441\u0435\u0442\u044c \u2014 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0437\u0430\u0441\u0442\u0440\u0430\u0445\u043e\u0432\u0430\u043d.<\/p>\n<p>  <a name=\"update_citizen_handler\"><\/a><\/p>\n<h3>PATCH \/imports\/$import_id\/citizens\/$citizen_id<\/h3>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u0445\u043e\u0434 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 <code>import_id<\/code>, \u0436\u0438\u0442\u0435\u043b\u044f <code>citizen_id<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 json \u0441 \u043d\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e \u0436\u0438\u0442\u0435\u043b\u0435. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a <b>\u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u0438\u043b\u0438 \u0436\u0438\u0442\u0435\u043b\u044e<\/b> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c HTTP-\u043e\u0442\u0432\u0435\u0442 <code>404: Not Found<\/code>.<\/p>\n<p>  \u041f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f <strong>\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c<\/strong>. \u0415\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u2014 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c HTTP-\u043e\u0442\u0432\u0435\u0442 <code>400: Bad Request<\/code>. \u042f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b Marshmallow-\u0441\u0445\u0435\u043c\u0443 <code>PatchCitizenSchema<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442:<\/p>\n<ul>\n<li>\u0422\u0438\u043f \u0438 \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439.<\/li>\n<li>\u0414\u0430\u0442\u0443 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f. \u041e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <code>DD.MM.YYYY<\/code> \u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e.<\/li>\n<li>\u0421\u043f\u0438\u0441\u043e\u043a \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f. \u041e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0436\u0438\u0442\u0435\u043b\u0435\u0439<\/li>\n<\/ul>\n<p>  \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u0432 \u043f\u043e\u043b\u0435 <code>relatives<\/code>, \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c: \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 <code>relations<\/code> \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f PostgreSQL \u0432\u0435\u0440\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 <code>ForeignKeyViolationError<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c HTTP-\u0441\u0442\u0430\u0442\u0443\u0441 <code>400: Bad Request<\/code>.<\/p>\n<p>  \u041a\u0430\u043a\u043e\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u0440\u0438\u0441\u043b\u0430\u043b <b>\u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f \u0438\u043b\u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438<\/b>? \u0421\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0435\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0436\u0438\u0442\u0435\u043b\u044f (\u0435\u0441\u043b\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u043d\u0435\u0442 \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c <code>404: Not Found<\/code>) \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u2014\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u0441\u043b\u0430\u043b \u043a\u043b\u0438\u0435\u043d\u0442 (\u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u2014 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c <code>400: Bad Request<\/code>). \u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0447\u0430\u0441\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u0434\u0435\u0448\u0435\u0432\u043b\u0435 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435, \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0431\u0430\u0437\u0435. <\/p>\n<p>  \u041e\u0431\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u044b, \u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0434\u0435\u0448\u0435\u0432\u044b\u0439 \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u043e\u0448\u0438\u0431\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0438 \u043d\u0430 \u0447\u0442\u043e \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442 (\u043a\u043b\u0438\u0435\u043d\u0442 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043f\u043e\u0442\u043e\u043c \u0442\u0430\u043a \u0436\u0435 \u0443\u0437\u043d\u0430\u0435\u0442, \u0447\u0442\u043e \u0436\u0438\u0442\u0435\u043b\u044c \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442). <\/p>\n<p>  \u0415\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <strong>\u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0436\u0438\u0442\u0435\u043b\u0435 \u0432 \u0411\u0414<\/strong>. \u0412 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0440\u0430\u0437\u043d\u044b\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c. \u0415\u0441\u043b\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 \u0438\u043b\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 <b>\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438<\/b>.<\/p>\n<p>  \u041c\u0435\u0442\u043e\u0434 <code>PATCH<\/code> <b>\u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043b\u0438\u0448\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043b\u044f<\/b> \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f. <\/p>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043d\u0435 \u043f\u0430\u0434\u0430\u043b \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043a \u0434\u0430\u043d\u043d\u044b\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043b \u043a\u043b\u0438\u0435\u043d\u0442, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c, \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u0443\u043a\u0430\u0437\u0430\u043b \u043f\u043e\u043b\u0435 <code>relatives<\/code>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432. \u0415\u0441\u043b\u0438 \u043e\u043d \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f \u2014 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>relatives<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c, \u0430 \u043a\u0430\u043a\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 PostgreSQL \u0434\u043b\u044f \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <a href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/9.6\/transaction-iso#xact-read-committed\"><code>\u0443\u0440\u043e\u0432\u0435\u043d\u044c READ COMMITTED<\/code><\/a>. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u0438\u0434\u043d\u044b \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 (\u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445) \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0434\u0440\u0443\u0433\u0438\u0445 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0445 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0439. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a <b>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e \u0433\u043e\u043d\u043a\u0438 \u043c\u0435\u0436\u0434\u0443 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u043c\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438<\/b>.<\/p>\n<p>  \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438 <code>#1<\/code>, <code>#2<\/code>, <code>#3<\/code>, \u0431\u0435\u0437 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u0435\u0439. \u0421\u0435\u0440\u0432\u0438\u0441 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0432\u0430 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0436\u0438\u0442\u0435\u043b\u044f #1: <code><nobr>{&quot;relatives&quot;: [2]}<\/nobr><\/code> \u0438 <code><nobr>{&quot;relatives&quot;: [3]}<\/nobr><\/code>. aiohttp \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0434\u0432\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0436\u0438\u0442\u0435\u043b\u044f \u0438\u0437 PostgreSQL. <\/p>\n<p>  \u041a\u0430\u0436\u0434\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442 \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438 \u0438 \u043f\u0440\u0438\u043c\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0441\u0432\u044f\u0437\u044c \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u043c. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0443 \u0436\u0438\u0442\u0435\u043b\u044f #1 \u043f\u043e\u043b\u0435 relatives \u0440\u0430\u0432\u043d\u043e <code>[2,3]<\/code>.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/go\/bk\/mz\/gobkmzuhzr47rfzgvtygkxb1stm.png\"><\/p>\n<p>  \u0422\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u043c. \u0415\u0441\u0442\u044c \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e \u0440\u0435\u0448\u0438\u0442\u044c \u0438\u0441\u0445\u043e\u0434 \u0433\u043e\u043d\u043a\u0438: \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441, \u0430 \u0434\u043b\u044f \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c HTTP-\u043e\u0442\u0432\u0435\u0442 <br \/>  <code>409: Conflict<\/code> (\u0447\u0442\u043e\u0431\u044b \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u043b \u0437\u0430\u043f\u0440\u043e\u0441), \u043b\u0438\u0431\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u043e\u0447\u0435\u0440\u0435\u0434\u0438 (\u0432\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0432\u043e\u0433\u043e).<\/p>\n<p>  \u041f\u0435\u0440\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c, \u0432\u043a\u043b\u044e\u0447\u0438\u0432 \u0440\u0435\u0436\u0438\u043c \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u0438 <a href=\"https:\/\/postgrespro.ru\/docs\/postgresql\/9.6\/transaction-iso#xact-serializable\"><code>SERIALIZABLE<\/code><\/a>. \u0415\u0441\u043b\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a\u0442\u043e-\u0442\u043e \u0443\u0436\u0435 \u0443\u0441\u043f\u0435\u043b \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0438 \u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0442\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u0431\u0443\u0434\u0435\u0442 \u0431\u0440\u043e\u0448\u0435\u043d\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 HTTP-\u0441\u0442\u0430\u0442\u0443\u0441. <\/p>\n<p>  \u041c\u0438\u043d\u0443\u0441 \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u2014 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a \u0432 PostgreSQL, <code>SERIALIZABLE<\/code> \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043c\u0435\u043d\u044f\u044e\u0442 \u0437\u0430\u043f\u0438\u0441\u0438 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043e\u043a.<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u043c <a href=\"https:\/\/postgrespro.ru\/docs\/postgrespro\/10\/explicit-locking#ADVISORY-LOCKS\">\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a<\/a>. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u043f\u043e <code>import_id<\/code>, \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043e\u043a \u0441\u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e. <\/p>\n<p>  \u0414\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432: \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>pg_try_advisory_xact_lock<\/code> \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u0438 <br \/>  \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 boolean \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e (\u0435\u0441\u043b\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u2014 \u043c\u043e\u0436\u043d\u043e \u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435), \u0430 <code>pg_advisory_xact_lock<\/code> \u043e\u0436\u0438\u0434\u0430\u0435\u0442, \u043f\u043e\u043a\u0430 <br \/>  \u0440\u0435\u0441\u0443\u0440\u0441 \u043d\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0434\u043b\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438 (\u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0430 \u044d\u0442\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435).<\/p>\n<p>  \u0412 \u0438\u0442\u043e\u0433\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d <b>\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u0436\u0438\u0442\u0435\u043b\u0435<\/b>. \u041c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c\u0441\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0435\u0433\u043e \u0436\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u0440\u0430\u0437 \u043c\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0442\u0432\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0443, \u0437\u043d\u0430\u0447\u0438\u0442, \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043d\u0435 \u0431\u044b\u043b\u043e \u0438 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b). \u0418\u043b\u0438 \u2014 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0441\u043b\u043e\u0432\u043e\u043c RETURNING \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445, \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0445 \u0411\u0414, \u0438 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u0438\u0437 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432. \u041d\u043e \u043e\u0431\u0430 \u044d\u0442\u0438\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u0438 \u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0438 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0443\u0447\u0430\u0439 \u0441 \u0433\u043e\u043d\u043a\u043e\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. <\/p>\n<p>  \u041a \u0441\u0435\u0440\u0432\u0438\u0441\u0443 \u043d\u0435 \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u044f\u043b\u0438\u0441\u044c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0436\u0438\u0442\u0435\u043b\u0435 \u0437\u0430\u043d\u043e\u0432\u043e \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0447\u0435\u0441\u0442\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438\u0437 \u0411\u0414. <\/p>\n<p>  <a name=\"citizen_birthdays_handler\"><\/a><\/p>\n<h3>GET \/imports\/$import_id\/citizens\/birthdays<\/h3>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 \u0447\u0438\u0441\u043b\u043e \u043f\u043e\u0434\u0430\u0440\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0435\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 \u0436\u0438\u0442\u0435\u043b\u044c \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0432\u043e\u0438\u043c \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c (\u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430). \u0427\u0438\u0441\u043b\u043e \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u043f\u043e \u043c\u0435\u0441\u044f\u0446\u0430\u043c \u0434\u043b\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c <code>import_id<\/code>. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a <b>\u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435<\/b> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c HTTP-\u043e\u0442\u0432\u0435\u0442 <code>404: Not Found<\/code>.<\/p>\n<p>  \u0415\u0441\u0442\u044c \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438: <\/p>\n<ol>\n<li>\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0441 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438 \u0438\u0437 \u0431\u0430\u0437\u044b, \u0430 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Python \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u043c\u0435\u0441\u044f\u0446\u0430\u043c \u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043a\u0438 \u0434\u043b\u044f \u0442\u0435\u0445 \u043c\u0435\u0441\u044f\u0446\u0435\u0432, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0411\u0414.<\/li>\n<li>C\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c json-\u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u0431\u0430\u0437\u0443 \u0438 \u0434\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u043b\u044f \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438.<\/li>\n<\/ol>\n<p>  \u042f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435 \u2014 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u043c. \u0427\u0438\u0441\u043b\u043e \u0434\u043d\u0435\u0439 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u0439 \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u043c \u043c\u0435\u0441\u044f\u0446\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u0441\u0434\u0435\u043b\u0430\u0432 <code>JOIN<\/code> \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0441 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0441\u0432\u044f\u0437\u044f\u043c\u0438 (<code>relations.citizen_id<\/code> \u2014 \u0436\u0438\u0442\u0435\u043b\u044c, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0434\u043d\u0438 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432) \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 <code>citizens<\/code> (\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u0442\u0443 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043c\u0435\u0441\u044f\u0446).<\/p>\n<p>  \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432\u0435\u0434\u0443\u0449\u0438\u0445 \u043d\u0443\u043b\u0435\u0439. \u041c\u0435\u0441\u044f\u0446, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0439 \u0438\u0437 \u043f\u043e\u043b\u044f <code>birth_date<\/code> c \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>date_part<\/code>, \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432\u0435\u0434\u0443\u0449\u0438\u0439 \u043d\u043e\u043b\u044c. \u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0440\u0430\u0442\u044c \u0435\u0433\u043e, \u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b <code>cast<\/code> \u043a <code>integer<\/code> \u0432 SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0435.<\/p>\n<p>  \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u0432\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0434\u043d\u044f\u0445 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0438 \u043f\u043e\u0434\u0430\u0440\u043a\u0430\u0445), <b>\u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f<\/b>. <\/p>\n<p>  \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e PostgreSQL \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0440\u0435\u0436\u0438\u043c READ COMMITTED, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432\u0438\u0434\u043d\u044b \u0432\u0441\u0435 \u043d\u043e\u0432\u044b\u0435 (\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438) \u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 (\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0435 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438) \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u043e\u0441\u043b\u0435 \u0438\u0445 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f.<\/p>\n<p>  \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u043e\u0432\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u2014 \u043e\u043d\u0430 \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043f\u043e\u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435. \u0415\u0441\u043b\u0438 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0436\u0438\u0442\u0435\u043b\u044f \u2014 \u0442\u043e \u043b\u0438\u0431\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0435\u0449\u0435 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u0438\u0434\u043d\u044b (\u0435\u0441\u043b\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f, \u043c\u0435\u043d\u044f\u044e\u0449\u0430\u044f \u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0430\u0441\u044c), \u043b\u0438\u0431\u043e \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0438 \u0441\u0442\u0430\u043d\u0443\u0442 \u0432\u0438\u0434\u043d\u044b \u0441\u0440\u0430\u0437\u0443 \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f. \u0426\u0435\u043b\u043e\u0441\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0445 \u0438\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435 \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u0441\u044f.<\/p>\n<p>  <a name=\"town_age_stat_handler\"><\/a><\/p>\n<h3>GET \/imports\/$import_id\/towns\/stat\/percentile\/age<\/h3>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 50-\u0439, 75-\u0439 \u0438 99-\u0439 \u043f\u0435\u0440\u0446\u0435\u043d\u0442\u0438\u043b\u0438 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u043e\u0432 (\u043f\u043e\u043b\u043d\u044b\u0445 \u043b\u0435\u0442) \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u043f\u043e \u0433\u043e\u0440\u043e\u0434\u0430\u043c \u0432 \u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c import_id. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a <b>\u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435<\/b> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c HTTP-\u043e\u0442\u0432\u0435\u0442 <code>404: Not Found<\/code>.<\/p>\n<p>  \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u0432\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0436\u0438\u0442\u0435\u043b\u0435\u0439), <b>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044e \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e<\/b>.<\/p>\n<p>  \u0415\u0441\u0442\u044c \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438: <\/p>\n<ol>\n<li>\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0411\u0414 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430 \u0436\u0438\u0442\u0435\u043b\u0435\u0439, \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0433\u043e\u0440\u043e\u0434\u0430\u043c, \u0430 \u0437\u0430\u0442\u0435\u043c \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Python \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043f\u0435\u0440\u0446\u0435\u043d\u0442\u0438\u043b\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e numpy (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u0437\u0430\u0434\u0430\u043d\u0438\u0438 \u0443\u043a\u0430\u0437\u0430\u043d \u043a\u0430\u043a \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u0439) \u0438 \u043e\u043a\u0440\u0443\u0433\u043b\u0438\u0442\u044c \u0434\u043e \u0434\u0432\u0443\u0445 \u0437\u043d\u0430\u043a\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u044f\u0442\u043e\u0439.<\/li>\n<li>\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 PostgreSQL: \u0444\u0443\u043d\u043a\u0446\u0438\u044f percentile_cont \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 \u043f\u0435\u0440\u0446\u0435\u043d\u0442\u0438\u043b\u044c \u0441 \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u0435\u0439, \u0437\u0430\u0442\u0435\u043c \u043e\u043a\u0440\u0443\u0433\u043b\u044f\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043e \u0434\u0432\u0443\u0445 \u0437\u043d\u0430\u043a\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u044f\u0442\u043e\u0439 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0433\u043e SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0430 numpy \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/li>\n<\/ol>\n<p>  \u0412\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438 PostgreSQL, \u043d\u043e \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0439 \u043f\u043e\u0434\u0432\u043e\u0434\u043d\u044b\u0439 \u043a\u0430\u043c\u0435\u043d\u044c: \u0432 PostgreSQL \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435, (<code>SELECT ROUND(2.5)<\/code> \u0432\u0435\u0440\u043d\u0435\u0442 3), \u0430 \u0432 Python \u2014 \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0441\u043a\u043e\u0435, \u043a \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u043c\u0443 \u0446\u0435\u043b\u043e\u043c\u0443 (<code>round(2.5)<\/code> \u0432\u0435\u0440\u043d\u0435\u0442 2).<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0439 \u0438 \u0432 PostgreSQL, \u0438 \u0432 Python (\u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u0435\u043c \u0432 Python \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u043e\u0449\u0435). \u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0438 \u043f\u0435\u0440\u0446\u0435\u043d\u0442\u0438\u043b\u0435\u0439 numpy \u0438 PostgreSQL \u043c\u043e\u0433\u0443\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0447\u0438\u0441\u043b\u0430, \u043d\u043e \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u0430 \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u043d\u0430.<\/p>\n<p>  <a name=\"testing\"><\/a><\/p>\n<h1>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h1>\n<p>  \u0427\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438? \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0442 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0432 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u043b\u0438\u0437\u043a\u043e\u043c \u043a \u0431\u043e\u0435\u0432\u043e\u043c\u0443. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0447\u0442\u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a. \u0412-\u0442\u0440\u0435\u0442\u044c\u0438\u0445, \u0435\u0441\u0442\u044c \u0440\u044f\u0434 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u043e\u0436\u0435 \u0431\u044b\u043b\u043e \u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u043a\u0440\u044b\u0442\u044c \u0442\u0435\u0441\u0442\u0430\u043c\u0438.<\/p>\n<p>  \u042f \u0440\u0435\u0448\u0438\u043b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"https:\/\/docs.pytest.org\/en\/latest\/\">\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c pytest<\/a> \u0438\u0437-\u0437\u0430 \u0435\u0433\u043e \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u0438 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438. \u041e\u043d \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u043c\u043e\u0449\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u2014 <a href=\"https:\/\/docs.pytest.org\/en\/latest\/fixture.html\">\u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b<\/a>, \u0442\u043e \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u043e\u043c <code>pytest.mark.fixture<\/code>, \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u0432 \u0442\u0435\u0441\u0442\u0435. \u0415\u0441\u043b\u0438 pytest \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442 \u0432 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u043e\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u044d\u0442\u0443 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0441\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430. \u0410 \u0435\u0441\u043b\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u043c, \u0442\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0442\u0435\u0441\u0442\u0430 \u043f\u0440\u0438\u043c\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0435 <code>yield<\/code>, \u0438 \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u0432\u0442\u043e\u0440\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u043e\u0436\u0435\u0442 \u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u0438\u043b\u0438 \u0437\u0430\u043a\u0440\u044b\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f.<\/p>\n<p>  \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 PostgreSQL. \u0427\u0442\u043e\u0431\u044b \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u2014 \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0435\u0435.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os import uuid  import pytest from sqlalchemy import create_engine from sqlalchemy_utils import create_database, drop_database from yarl import URL  from analyzer.utils.pg import DEFAULT_PG_URL  PG_URL = os.getenv('CI_ANALYZER_PG_URL', DEFAULT_PG_URL)   @pytest.fixture def postgres():     tmp_name = '.'.join([uuid.uuid4().hex, 'pytest'])     tmp_url = str(URL(PG_URL).with_path(tmp_name))     create_database(tmp_url)      try:         # \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 postgres \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u0442\u0435\u0441\u0442\u0435         yield tmp_url     finally:         drop_database(tmp_url)   def test_db(postgres):     &quot;&quot;&quot;     \u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0435\u0441\u0442\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0435\u0433\u043e PostgreSQL     &quot;&quot;&quot;     engine = create_engine(postgres)     assert engine.execute('SELECT 1').scalar() == 1     engine.dispose()<\/code><\/pre>\n<\/div><\/div>\n<p>  C \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 \u0437\u0434\u043e\u0440\u043e\u0432\u043e \u0441\u043f\u0440\u0430\u0432\u0438\u043b\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u044c <a href=\"https:\/\/sqlalchemy-utils.readthedocs.io\/en\/latest\/\">sqlalchemy_utils<\/a>, \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, PostgreSQL \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 <code>CREATE DATABASE<\/code> \u0432 \u0431\u043b\u043e\u043a\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438. \u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0411\u0414 <code>sqlalchemy_utils<\/code> \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442 <code>psycopg2<\/code> (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044b\u0447\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438) \u0432 \u0440\u0435\u0436\u0438\u043c autocommit.<\/p>\n<p>  \u0414\u0440\u0443\u0433\u0430\u044f \u0432\u0430\u0436\u043d\u0430\u044f \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c: \u0435\u0441\u043b\u0438 \u043a PostgreSQL \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u043a\u043b\u0438\u0435\u043d\u0442 \u2014 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u043b\u044c\u0437\u044f \u0443\u0434\u0430\u043b\u0438\u0442\u044c, \u0430 <code>sqlalchemy_utils<\/code> \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432\u0441\u0435\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043f\u0435\u0440\u0435\u0434 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435\u043c \u0431\u0430\u0437\u044b. \u0411\u0414 \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0443\u0434\u0430\u043b\u0435\u043d\u0430, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0437\u0430\u0432\u0438\u0441\u043d\u0435\u0442 \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0442\u0435\u0441\u0442, \u0438\u043c\u0435\u044e\u0449\u0438\u0439 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u043d\u0435\u0439. <\/p>\n<p>  PostgreSQL \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u043c \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u0445: \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0447\u0438\u0441\u0442\u0430\u044f \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432 \u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0442\u0440\u0435\u0431\u0443\u044e\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0431\u044b\u043b\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u044b. \u0418\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434 Alembic, \u0434\u043b\u044f \u0438\u0445 \u0432\u044b\u0437\u043e\u0432\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Alembic.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Alembic<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from types import SimpleNamespace  import pytest  from analyzer.utils.pg import make_alembic_config   @pytest.fixture() def alembic_config(postgres):     cmd_options = SimpleNamespace(config='alembic.ini', name='alembic',                                   pg_url=postgres, raiseerr=False, x=None)     return make_alembic_config(cmd_options)<\/code><\/pre>\n<\/div><\/div>\n<p>  \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0443 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b <code>alembic_config<\/code> \u0435\u0441\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>postgres<\/code> \u2014 <code>pytest<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u0430 \u043e\u0442 \u0444\u0438\u043a\u0441\u0442\u0443\u0440, \u043d\u043e \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043c\u0435\u0436\u0434\u0443 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430\u043c\u0438. <\/p>\n<p>  \u042d\u0442\u043e\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0433\u0438\u0431\u043a\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0442\u043a\u0438\u0439 \u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u0434.<\/p>\n<p>  <a name=\"testing_handlers\"><\/a><\/p>\n<h3>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438<\/h3>\n<p>  \u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438 \u0438 \u0442\u0438\u043f\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 upgrade Alembic. \u0414\u043b\u044f \u0435\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 Alembic, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0443\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 <code>alembic_config<\/code>. \u0411\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u043c\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u0432\u043f\u043e\u043b\u043d\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u0438 \u0435\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b:<\/p>\n<pre><code class=\"python\">from alembic.command import upgrade  @pytest.fixture async def migrated_postgres(alembic_config, postgres):     upgrade(alembic_config, 'head')     # \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c DSN \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u044b\u043b\u0430 \u0441\u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0430      return postgres<\/code><\/pre>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u043e, \u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0427\u0442\u043e\u0431\u044b \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441, \u043c\u043e\u0436\u043d\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 <a href=\"https:\/\/github.com\/alvassin\/alembic-quickstart\/blob\/master\/tests\/api\/conftest.py#L10\">\u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u043c\u0438<\/a> \u0438 \u0437\u0430\u0442\u0435\u043c <a href=\"https:\/\/github.com\/alvassin\/alembic-quickstart\/blob\/master\/tests\/api\/conftest.py#L24\">\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430<\/a>.<\/p>\n<p>  \u041f\u043e\u043c\u0438\u043c\u043e \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043a\u043b\u0438\u0435\u043d\u0442, \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u044d\u0442\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c. \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043b\u0435\u0433\u043a\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u044f \u0432\u044b\u043d\u0435\u0441 \u0435\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>create_app<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430: \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u0440\u0442 \u0434\u043b\u044f REST API \u0438 \u0434\u0440\u0443\u0433\u0438\u0435.<\/p>\n<p>  \u0410\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b. \u0414\u043b\u044f \u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u043f\u043e\u0440\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0430\u0434\u0440\u0435\u0441 \u0434\u043e \u0441\u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  \u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u0442\u0430 \u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 <code>aiomisc_unused_port<\/code> \u0438\u0437 \u043f\u0430\u043a\u0435\u0442\u0430 aiomisc. <\/p>\n<p>  \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>aiohttp_unused_port<\/code> \u0442\u043e\u0436\u0435 \u0432\u043f\u043e\u043b\u043d\u0435 \u0431\u044b \u043f\u043e\u0434\u043e\u0448\u043b\u0430, \u043d\u043e \u043e\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u044b\u0445 \u043f\u043e\u0440\u0442\u043e\u0432, \u0432 \u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u043a <code>aiomisc_unused_port<\/code> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443 \u043d\u043e\u043c\u0435\u0440 \u043f\u043e\u0440\u0442\u0430. \u0414\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u043f\u043e\u0440\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u044e\u044e \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u043a\u043e\u0434\u0430 \u0441 \u0432\u044b\u0437\u043e\u0432\u043e\u043c <code>aiohttp_unused_port<\/code>.<\/p>\n<pre><code class=\"python\">@pytest.fixture def arguments(aiomisc_unused_port, migrated_postgres):     return parser.parse_args(         [             '--log-level=debug',             '--api-address=127.0.0.1',             f'--api-port={aiomisc_unused_port}',             f'--pg-url={migrated_postgres}'         ]     )<\/code><\/pre>\n<p>  \u0412\u0441\u0435 \u0442\u0435\u0441\u0442\u044b \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u044e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a REST API, \u0440\u0430\u0431\u043e\u0442\u0430 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c <code>aiohttp<\/code> \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u043e\u0434\u043d\u0443 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0430\u0431\u0440\u0438\u043a\u0438 <code>aiohttp_client<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 <code>aiohttp.test_utils.TestClient<\/code>.<\/p>\n<pre><code class=\"python\">from analyzer.api.app import create_app  @pytest.fixture async def api_client(aiohttp_client, arguments):     app = create_app(arguments)     client = await aiohttp_client(app, server_kwargs={         'port': arguments.api_port     })      try:         yield client     finally:         await client.close() <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u0435\u0441\u043b\u0438 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0442\u0435\u0441\u0442\u0430 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443 <code>api_client<\/code>, \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ol>\n<li>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>postgres<\/code> \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f <code>migrated_postgres<\/code>).<\/li>\n<li>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>alembic_config<\/code> \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Alembic, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u043a \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f <code>migrated_postgres<\/code>).<\/li>\n<li>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>migrated_postgres<\/code> \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 (\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f <code>arguments<\/code>).<\/li>\n<li>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>aiomisc_unused_port<\/code> \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u0439 \u043f\u043e\u0440\u0442 (\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f <code>arguments<\/code>).<\/li>\n<li>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>arguments<\/code> \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 (\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f <code>api_client<\/code>).<\/li>\n<li>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>api_client<\/code> \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0432\u0435\u0440\u043d\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/li>\n<li>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u0442\u0435\u0441\u0442.<\/li>\n<li>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>api_client<\/code> \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0438 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/li>\n<li>\u0424\u0438\u043a\u0441\u0442\u0443\u0440\u0430 <code>postgres<\/code> \u0443\u0434\u0430\u043b\u0438\u0442 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/li>\n<\/ol>\n<p>  \u0424\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430, \u043d\u043e \u043f\u043e\u043c\u0438\u043c\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0435\u0441\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u043d\u043e \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u043c\u043d\u043e\u0433\u043e \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u2014 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e.<\/p>\n<p>  \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0441\u0434\u0435\u043b\u0430\u0432 \u0437\u0430\u043f\u0440\u043e\u0441, \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 HTTP-\u0441\u0442\u0430\u0442\u0443\u0441. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0435\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u0443\u0441 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c, \u0442\u043e \u043f\u0435\u0440\u0435\u0434 \u0440\u0430\u0431\u043e\u0442\u043e\u0439 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d\u0438 \u0438\u043c\u0435\u044e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442. \u0417\u0434\u0435\u0441\u044c \u043b\u0435\u0433\u043a\u043e \u043e\u0448\u0438\u0431\u0438\u0442\u044c\u0441\u044f \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u043b\u0430\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0438 <strong>\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u043d\u043e \u043d\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0438\u0437-\u0437\u0430 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u043e\u0442\u0432\u0435\u0442\u0430<\/strong> (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0437\u0430\u0431\u044b\u0442\u044c \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u043a\u043b\u044e\u0447\u043e\u043c <code>data<\/code>). \u0412\u0441\u0435 \u044d\u0442\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435.<\/p>\n<p>  \u0412 \u043c\u043e\u0434\u0443\u043b\u0435 <code>analyzer.testing<\/code> \u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 HTTP, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0444\u043e\u0440\u043c\u0430\u0442 \u043e\u0442\u0432\u0435\u0442\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Marshmallow. <\/p>\n<p>  <a name=\"test_citizens_handler\"><\/a><\/p>\n<h4>GET \/imports\/$import_id\/citizens<\/h4>\n<p>  \u042f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u0447\u0430\u0442\u044c \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0435\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u0435\u0439, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0440\u0430\u0431\u043e\u0442\u044b \u0434\u0440\u0443\u0433\u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>  \u042f \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u043d\u043e \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043a\u043e\u0434, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0431\u0430\u0437\u0443 \u0438\u0437 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 <code>POST \/imports<\/code>, \u0445\u043e\u0442\u044f \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0435\u0433\u043e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e. \u041a\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0430 \u0435\u0441\u043b\u0438 \u0432 \u043a\u043e\u0434\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u043c \u0432 \u0431\u0430\u0437\u0443, \u0431\u0443\u0434\u0435\u0442 \u043a\u0430\u043a\u0430\u044f-\u043b\u0438\u0431\u043e \u043e\u0448\u0438\u0431\u043a\u0430, \u0435\u0441\u0442\u044c \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u044c, \u0447\u0442\u043e \u0442\u0435\u0441\u0442 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u043a \u0437\u0430\u0434\u0443\u043c\u0430\u043d\u043e \u0438 \u043d\u0435\u044f\u0432\u043d\u043e \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0431\u043e\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<ul>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d \u0441\u043f\u0438\u0441\u043e\u043a \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432.<\/li>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u043e\u0434\u043d\u0438\u043c \u0436\u0438\u0442\u0435\u043b\u0435\u043c \u0431\u0435\u0437 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043f\u043e\u043b\u0435 <code>relatives<\/code> \u2014 \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a (\u0438\u0437-\u0437\u0430 <code>LEFT JOIN<\/code> \u0432 SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0432\u0435\u043d <code>[None]<\/code>).<\/li>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u0436\u0438\u0442\u0435\u043b\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0430\u043c \u0441\u0435\u0431\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a.<\/li>\n<li>\u041f\u0443\u0441\u0442\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0441\u0442\u0443\u044e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0438 \u043d\u0435 \u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439.<\/li>\n<\/ul>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0442\u0435\u0441\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435, \u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0435\u0449\u0435 \u043e\u0434\u043d\u0438\u043c \u043e\u0447\u0435\u043d\u044c \u043c\u043e\u0449\u043d\u044b\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u043c pytest \u2014 <a href=\"https:\/\/docs.pytest.org\/en\/latest\/parametrize.html\">\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439<\/a>. \u042d\u0442\u043e\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0442\u0435\u0441\u0442 \u0432 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 <code>pytest.mark.parametrize<\/code> \u0438 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043d\u0435\u043c, \u043a\u0430\u043a\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f-\u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u0441\u0442<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import pytest  from analyzer.utils.testing import generate_citizen  datasets = [     # \u0416\u0438\u0442\u0435\u043b\u044c \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438     [         generate_citizen(citizen_id=1, relatives=[2, 3]),         generate_citizen(citizen_id=2, relatives=[1]),         generate_citizen(citizen_id=3, relatives=[1])     ],      # \u0416\u0438\u0442\u0435\u043b\u044c \u0431\u0435\u0437 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432     [         generate_citizen(relatives=[])     ],      # \u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u0436\u0438\u0442\u0435\u043b\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0430\u043c \u0441\u0435\u0431\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a     [         generate_citizen(citizen_id=1, name='\u0414\u0436\u0435\u0439\u043d', gender='male',                          birth_date='17.02.2020', relatives=[1])     ],      # \u041f\u0443\u0441\u0442\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430     [], ]   @pytest.mark.parametrize('dataset', datasets) async def test_get_citizens(api_client, dataset):     &quot;&quot;&quot;     \u042d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d 4 \u0440\u0430\u0437\u0430, \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430     &quot;&quot;&quot;<\/code><\/pre>\n<\/div><\/div>\n<p>  \u0418\u0442\u0430\u043a, \u0442\u0435\u0441\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445, \u0437\u0430\u0442\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0436\u0438\u0442\u0435\u043b\u044f\u0445 \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0442 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u0443\u044e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0439. \u041d\u043e \u043a\u0430\u043a \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0436\u0438\u0442\u0435\u043b\u0435\u0439? <\/p>\n<p>  \u041a\u0430\u0436\u0434\u044b\u0439 \u0436\u0438\u0442\u0435\u043b\u044c \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0438 \u043f\u043e\u043b\u044f <code>relatives<\/code> \u2014 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432. \u0421\u043f\u0438\u0441\u043e\u043a \u0432 Python \u2014 \u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0435\u043d\u043d\u044b\u0439 \u0442\u0438\u043f, \u0438 \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043d\u043e \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0441 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 <code>relatives<\/code> \u043a \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0443 \u043f\u0435\u0440\u0435\u0434 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435\u043c, \u0442\u043e \u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u044c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e, \u043a\u043e\u0433\u0434\u0430 \u0443 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u0437 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0432 \u043f\u043e\u043b\u0435 <code>relatives<\/code> \u0435\u0441\u0442\u044c \u0434\u0443\u0431\u043b\u0438. \u0415\u0441\u043b\u0438 \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u044d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043e\u0431\u043e\u0439\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u044c \u0434\u0443\u0431\u043b\u0438.<\/p>\n<p>  \u041f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438 \u0434\u0432\u0443\u0445 \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0441 \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u0445\u043e\u0436\u0435\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439: \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438, \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0432 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u043d\u0435 \u0432\u0430\u0436\u0435\u043d, \u043d\u043e \u0432\u0430\u0436\u043d\u043e \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432 \u043e\u0434\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u0431\u0443\u0434\u0435\u0442 \u0434\u0432\u0430 \u0436\u0438\u0442\u0435\u043b\u044f \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438, \u0430 \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u043d\u0435\u0442. \u0422\u0430\u043a \u0447\u0442\u043e \u043f\u043e\u043c\u0438\u043c\u043e \u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0441 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438 relatives \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0442\u044c \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435. <\/p>\n<p>  \u0422\u0430\u043a \u043a\u0430\u043a \u0437\u0430\u0434\u0430\u0447\u0430 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u0435\u0449\u0435 \u043d\u0435 \u0440\u0430\u0437, \u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u0434\u0432\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438: \u043e\u0434\u043d\u0443 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0434\u0432\u0443\u0445 \u0436\u0438\u0442\u0435\u043b\u0435\u0439, \u0430 \u0432\u0442\u043e\u0440\u0443\u044e \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0434\u0432\u0443\u0445 \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0441 \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0436\u0438\u0442\u0435\u043b\u0435\u0439<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from typing import Iterable, Mapping  def normalize_citizen(citizen):     &quot;&quot;&quot;     \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0436\u0438\u0442\u0435\u043b\u044f \u0441 \u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0435\u043d\u043d\u044b\u043c \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432     &quot;&quot;&quot;     return {**citizen, 'relatives': sorted(citizen['relatives'])}   def compare_citizens(left: Mapping, right: Mapping) -&gt; bool:     &quot;&quot;&quot;     \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u0434\u0432\u0443\u0445 \u0436\u0438\u0442\u0435\u043b\u0435\u0439     &quot;&quot;&quot;     return normalize_citizen(left) == normalize_citizen(right)   def compare_citizen_groups(left: Iterable, right: Iterable) -&gt; bool:     &quot;&quot;&quot;     \u0423\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043a\u0438 \u0441 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f, \u0441\u043f\u0438\u0441\u043a\u0438 \u0441 \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438     \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u0438\u0445     &quot;&quot;&quot;     left = [normalize_citizen(citizen) for citizen in left]     left.sort(key=lambda citizen: citizen['citizen_id'])      right = [normalize_citizen(citizen) for citizen in right]     right.sort(key=lambda citizen: citizen['citizen_id'])     return left == right <\/code><\/pre>\n<\/div><\/div>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043e\u043a, \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0435\u0440\u0435\u0434 \u043a\u0430\u0436\u0434\u044b\u043c \u0442\u0435\u0441\u0442\u043e\u043c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u043e\u0434\u043d\u0438\u043c \u0436\u0438\u0442\u0435\u043b\u0435\u043c.<\/p>\n<p>  <a name=\"test_imports_handler\"><\/a><\/p>\n<h4>POST \/imports<\/h4>\n<p>  \u042f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0431\u043e\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430:<\/p>\n<ul>\n<li> <b>\u041a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u0411\u0414.<\/b>\n<ul>\n<li> \u0416\u0438\u0442\u0435\u043b\u044c \u0431\u0435\u0437 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432 (\u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439).\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0434\u0432\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u0415\u0441\u043b\u0438 \u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f, \u043a\u043e\u0433\u0434\u0430 \u0443 \u0436\u0438\u0442\u0435\u043b\u044f \u043d\u0435\u0442 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432, \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u043f\u0443\u0441\u0442\u043e\u0439 insert \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u0435\u0439, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u043e\u0448\u0438\u0431\u043a\u0435.<\/li>\n<li>\u0416\u0438\u0442\u0435\u043b\u044c \u0441 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438 (\u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0439, \u043e\u0431\u044b\u0447\u043d\u044b\u0439).\n<p>  \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043e \u0436\u0438\u0442\u0435\u043b\u0435 \u0438 \u0435\u0433\u043e \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u044f\u0445.   <\/li>\n<li> \u0416\u0438\u0442\u0435\u043b\u044c \u0441\u0430\u043c \u0441\u0435\u0431\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a.\n<p>  \u041f\u0440\u043e \u044d\u0442\u043e\u0442 \u0441\u043b\u0443\u0447\u0430\u0439 \u0431\u044b\u043b\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0448\u0443\u0442\u043a\u0443 \u0440\u0435\u0448\u0438\u043b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438 \u0435\u0433\u043e. \ud83d\ude42   <\/li>\n<li> \u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430\n<p>  \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e aiohttp \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u043e\u0431\u044a\u0435\u043c\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0447\u0442\u043e \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 PostgreSQL \u043d\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 32 767 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 (\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432).   <\/li>\n<li> \u041f\u0443\u0441\u0442\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 \u0438 \u043d\u0435 \u043f\u0430\u0434\u0430\u0442\u044c, \u043f\u044b\u0442\u0430\u044f\u0441\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0443\u0441\u0442\u043e\u0439 insert \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438.   <\/li>\n<\/ul>\n<p>   <\/li>\n<li> <b>\u0414\u0430\u043d\u043d\u044b\u0435 \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438, \u043e\u0436\u0438\u0434\u0430\u0435\u043c HTTP-\u043e\u0442\u0432\u0435\u0442 400: Bad Request.<\/b>\n<ul>\n<li>\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u0430\u044f (\u0431\u0443\u0434\u0443\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f).<\/li>\n<li>citizen_id \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u0435\u043d.<\/li>\n<li>\u0420\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0441\u0432\u044f\u0437\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u0430 \u043d\u0435\u0432\u0435\u0440\u043d\u043e (\u0435\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f \u043a \u0434\u0440\u0443\u0433\u043e\u043c\u0443, \u043d\u043e \u043d\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439).<\/li>\n<li>\u0423 \u0436\u0438\u0442\u0435\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0432 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a.<\/li>\n<li>\u0420\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0441\u0432\u044f\u0437\u0438 \u043d\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  \u0415\u0441\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u044b\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0432 \u0411\u0414 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0438\u0445 \u0441 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u0443\u0436\u0435 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c <code>GET \/imports\/$import_id\/citizens<\/code>, \u0430 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 <code>compare_citizen_groups<\/code>.<\/p>\n<p>  <a name=\"test_update_citizen_handler\"><\/a><\/p>\n<h4>PATCH \/imports\/$import_id\/citizens\/$citizen_id<\/h4>\n<p>  \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u043e \u043c\u043d\u043e\u0433\u043e\u043c \u043f\u043e\u0445\u043e\u0436\u0430 \u043d\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u0443\u044e \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 <code>POST \/imports<\/code> \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f\u043c\u0438: \u0435\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0436\u0438\u0442\u0435\u043b\u044c \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c <a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/HTTP\/Methods\/PATCH\">\u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0436\u0435\u043b\u0430\u0435\u0442<\/a>. <\/p>\n<p>  \u042f \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0431\u043e\u0440\u044b \u0441 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u0435\u0440\u043d\u0435\u0442 HTTP-\u043e\u0442\u0432\u0435\u0442 <code>400: Bad request<\/code>:<\/p>\n<ul>\n<li>\u041f\u043e\u043b\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e, \u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u0442\u0438\u043f \u0438\/\u0438\u043b\u0438 \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u043d\u043d\u044b\u0445<\/li>\n<li>\u0423\u043a\u0430\u0437\u0430\u043d\u0430 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u0430\u044f \u0434\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f (\u0431\u0443\u0434\u0443\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f).<\/li>\n<li>\u041f\u043e\u043b\u0435 <code>relatives<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0435\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0432 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430.<\/li>\n<\/ul>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0436\u0438\u0442\u0435\u043b\u0435 \u0438 \u0435\u0433\u043e \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u0445. <\/p>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u0442\u0440\u0435\u043c\u044f \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438, \u0434\u0432\u0430 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u2014 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0438, \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u043d\u043e\u0432\u044b\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0432\u0441\u0435\u0445 \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0438 \u043d\u043e\u0432\u044b\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430 \u0432 \u043f\u043e\u043b\u0435 <code>relatives<\/code>.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0435\u0442 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043e\u043a \u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u0441\u0442\u043e\u043c (\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0439 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438), \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u0442\u0440\u0435\u043c\u044f \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u044e\u0442 \u0442\u0430\u043a\u0438\u0435 \u0436\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b.<\/p>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439, \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0433\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430 \u0438 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0432\u044f\u0437\u044c \u0441\u043e \u0441\u0442\u0430\u0440\u044b\u043c, \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u043c. \u0412\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0441\u0432\u044f\u0437\u0435\u0439 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0434\u0432\u0443\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c\u0438. \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430\u0445 \u0431\u044b\u0442\u044c \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e.<\/p>\n<p>  \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0430\u043a\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0434\u0432\u0435\u0440\u0436\u0435\u043d \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e \u0433\u043e\u043d\u043a\u0438 (\u044d\u0442\u043e \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u043b\u043e\u0441\u044c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430\u00bb), \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b <a href=\"https:\/\/github.com\/alvassin\/backendschool2019\/blob\/master\/tests\/api\/test_update_race_condition.py\">\u0434\u0432\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0442\u0435\u0441\u0442\u0430<\/a>. \u041e\u0434\u0438\u043d \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0433\u043e\u043d\u043a\u0438 (\u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0438 \u0443\u0431\u0438\u0440\u0430\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0443), \u0432\u0442\u043e\u0440\u043e\u0439 \u0434\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0433\u043e\u043d\u043a\u0438 \u043d\u0435 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f.<\/p>\n<p>  <a name=\"test_citizen_birthdays_handler\"><\/a><\/p>\n<h4>GET \/imports\/$import_id\/citizens\/birthdays<\/h4>\n<p>  \u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0431\u043e\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<ul>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0443 \u0436\u0438\u0442\u0435\u043b\u044f \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u044f\u0446\u0435 \u0438 \u0434\u0432\u0430 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c.<\/li>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u043e\u0434\u043d\u0438\u043c \u0436\u0438\u0442\u0435\u043b\u0435\u043c \u0431\u0435\u0437 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u0432. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u043f\u0440\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430\u0445.<\/li>\n<li>\u041f\u0443\u0441\u0442\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435 \u0443\u043f\u0430\u0434\u0435\u0442 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u0438 \u0432\u0435\u0440\u043d\u0435\u0442 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 12 \u043c\u0435\u0441\u044f\u0446\u0430\u043c\u0438.<\/li>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u0436\u0438\u0442\u0435\u043b\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0430\u043c \u0441\u0435\u0431\u0435 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0436\u0438\u0442\u0435\u043b\u044c \u043a\u0443\u043f\u0438\u0442 \u0441\u0435\u0431\u0435 \u043f\u043e\u0434\u0430\u0440\u043e\u043a \u0432 \u043c\u0435\u0441\u044f\u0446 \u0441\u0432\u043e\u0435\u0433\u043e \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f.<\/li>\n<\/ul>\n<p>  \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u0432\u0441\u0435 \u043c\u0435\u0441\u044f\u0446\u044b, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0432 \u044d\u0442\u0438 \u043c\u0435\u0441\u044f\u0446\u044b \u043d\u0435\u0442 \u0434\u043d\u0435\u0439 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u0439. \u0427\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u043b\u0430 \u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0434\u043b\u044f \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043c\u0435\u0441\u044f\u0446\u0435\u0432.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0435\u0442 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043e\u043a, \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u0434\u0432\u0443\u043c\u044f \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0430\u043c\u0438. \u0415\u0441\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e \u043e\u0448\u0438\u0431\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0438\u0445 \u043f\u0440\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430\u0445, \u0442\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u043c\u0438 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0443\u043f\u0430\u0434\u0435\u0442 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439.<\/p>\n<p>  <a name=\"test_town_age_stat_handler\"><\/a><\/p>\n<h4>GET \/imports\/$import_id\/towns\/stat\/percentile\/age<\/h4>\n<p>  \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0435\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438: \u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0434\u0430\u0442\u044b. \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u0438\u0441\u044c \u0441 \u0442\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0434\u0430\u0442\u0443, \u0434\u0430\u0442\u044b \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043b\u0435\u0433\u043a\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043b\u044e\u0431\u044b\u0435, \u0434\u0430\u0436\u0435 \u043a\u0440\u0430\u0435\u0432\u044b\u0435 \u0441\u043b\u0443\u0447\u0430\u0438.<\/p>\n<p>  \u041a\u0430\u043a \u043b\u0443\u0447\u0448\u0435 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u0442\u0443? \u0412 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f PostgreSQL-\u0444\u0443\u043d\u043a\u0446\u0438\u044f <a href=\"https:\/\/postgrespro.ru\/docs\/postgrespro\/9.5\/functions-datetime\"><code>AGE<\/code><\/a>, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0449\u0430\u044f \u043f\u0435\u0440\u0432\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u0434\u0430\u0442\u0443, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0432\u043e\u0437\u0440\u0430\u0441\u0442, \u0430 \u0432\u0442\u043e\u0440\u044b\u043c \u2014 \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0434\u0430\u0442\u0443 (\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043e\u0439 <code>TownAgeStatView.CURRENT_DATE<\/code>).<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u043e\u0434\u043c\u0435\u043d\u044f\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0434\u0430\u0442\u0443 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0442\u0435\u0441\u0442\u0430<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from unittest.mock import patch  import pytz  CURRENT_DATE = datetime(2020, 2, 17, tzinfo=pytz.utc)   @patch('analyzer.api.handlers.TownAgeStatView.CURRENT_DATE', new=CURRENT_DATE) async def test_get_ages(...):     ...<\/code><\/pre>\n<\/div><\/div>\n<p>  \u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0431\u043e\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 (\u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043e\u0434\u0438\u043d \u0433\u043e\u0440\u043e\u0434, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043f\u043e \u0433\u043e\u0440\u043e\u0434\u0430\u043c):<\/p>\n<ul>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0437\u0430\u0432\u0442\u0440\u0430 \u0434\u0435\u043d\u044c \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f (\u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u2014 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442 \u0438 364 \u0434\u043d\u044f). \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0432 \u0440\u0430\u0441\u0447\u0435\u0442\u0430\u0445 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u043d\u044b\u0445 \u043b\u0435\u0442.<\/li>\n<li>\u0412\u044b\u0433\u0440\u0443\u0437\u043a\u0430 \u0441 \u0436\u0438\u0442\u0435\u043b\u0435\u043c, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0434\u0435\u043d\u044c \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f (\u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u2014 \u0440\u043e\u0432\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442). \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043a\u0440\u0430\u0435\u0432\u043e\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 \u2014 \u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u0436\u0438\u0442\u0435\u043b\u044f, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0434\u0435\u043d\u044c \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f, \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u043d\u044b\u0439 \u043d\u0430 1 \u0433\u043e\u0434.<\/li>\n<li>\u041f\u0443\u0441\u0442\u0430\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430 \u043d\u0435\u0439 \u043f\u0430\u0434\u0430\u0442\u044c.<\/li>\n<\/ul>\n<p>  \u042d\u0442\u0430\u043b\u043e\u043d \u0434\u043b\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u043f\u0435\u0440\u0446\u0435\u043d\u0442\u0438\u043b\u0435\u0439 \u2014 <code>numpy<\/code> \u0441 \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u0435\u0439, \u0438 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044f \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043b \u0438\u043c\u0435\u043d\u043d\u043e \u0438\u043c.<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u043a\u0440\u0443\u0433\u043b\u044f\u0442\u044c \u0434\u0440\u043e\u0431\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0446\u0435\u043d\u0442\u0438\u043b\u0435\u0439 \u0434\u043e \u0434\u0432\u0443\u0445 \u0437\u043d\u0430\u043a\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u044f\u0442\u043e\u0439. \u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0434\u043b\u044f \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u044f PostgreSQL, \u0430 \u0434\u043b\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u044d\u0442\u0430\u043b\u043e\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 Python, \u0442\u043e \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e <strong>\u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u0435 \u0432 Python 3 \u0438 PostgreSQL \u043c\u043e\u0436\u0435\u0442 \u0434\u0430\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b<\/strong>.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\"># Python 3 round(2.5) &gt; 2  -- PostgreSQL SELECT ROUND(2.5) &gt; 3 <\/code><\/pre>\n<\/div><\/div>\n<p>  \u0414\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e Python \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0431\u0430\u043d\u043a\u043e\u0432\u0441\u043a\u043e\u0435 \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u0435 <a href=\"https:\/\/docs.python.org\/3\/library\/functions.html#round\">\u0434\u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0433\u043e \u0447\u0435\u0442\u043d\u043e\u0433\u043e<\/a>, \u0430 PostgreSQL \u2014 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 (half-up). \u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u044b \u0438 \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0432 PostgreSQL, \u0431\u044b\u043b\u043e \u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0442\u0430\u043a\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u0435.<\/p>\n<p>  \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u043e\u043f\u0438\u0441\u0430\u043b \u043d\u0430\u0431\u043e\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0434\u0430\u0442\u0430\u043c\u0438 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435, \u043d\u043e \u0447\u0438\u0442\u0430\u0442\u044c \u0442\u0435\u0441\u0442 \u0432 \u0442\u0430\u043a\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0431\u044b\u043b\u043e \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e: \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0442\u044c \u0432 \u0443\u043c\u0435 \u0432\u043e\u0437\u0440\u0430\u0441\u0442 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u0442 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438 \u0432 \u043a\u043e\u0434\u0435, \u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u0439\u0442\u0438 \u0447\u0443\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435 \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>age2date<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u0442\u0443 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0432 \u0432\u0438\u0434\u0435 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430: \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043b\u0435\u0442 \u0438 \u0434\u043d\u0435\u0439.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u043e\u0442 \u0442\u0430\u043a<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import pytz  from analyzer.utils.testing import generate_citizen   CURRENT_DATE = datetime(2020, 2, 17, tzinfo=pytz.utc)  def age2date(years: int, days: int = 0, base_date=CURRENT_DATE) -&gt; str:     birth_date = copy(base_date).replace(year=base_date.year - years)     birth_date -= timedelta(days=days)     return birth_date.strftime(BIRTH_DATE_FORMAT)  # \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0442 \u044d\u0442\u043e\u043c\u0443 \u0436\u0438\u0442\u0435\u043b\u044e? \u041f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e, \u043d\u043e \u0435\u0441\u043b\u0438 \u0438\u0445 \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e? generate_citizen(birth_date='17.02.2009')  # \u0416\u0438\u0442\u0435\u043b\u044e \u0440\u043e\u0432\u043d\u043e 11 \u043b\u0435\u0442 \u0438 \u0443 \u043d\u0435\u0433\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0434\u0435\u043d\u044c \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f generate_citizen(birth_date=age2date(years=11)) <\/code><\/pre>\n<\/div><\/div>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0435\u0442 \u0436\u0438\u0442\u0435\u043b\u0435\u0439 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u044b\u0433\u0440\u0443\u0437\u043e\u043a, \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u043e\u0434\u043d\u0438\u043c \u0436\u0438\u0442\u0435\u043b\u0435\u043c \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0433\u043e\u0440\u043e\u0434\u0430: \u0435\u0441\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e \u043e\u0448\u0438\u0431\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0435\u0433\u043e, \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u0445 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043b\u0438\u0448\u043d\u0438\u0439 \u0433\u043e\u0440\u043e\u0434 \u0438 \u0442\u0435\u0441\u0442 \u0441\u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f.<\/p>\n<blockquote><p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u0444\u0430\u043a\u0442: \u043a\u043e\u0433\u0434\u0430 \u044f \u043f\u0438\u0441\u0430\u043b \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442 29 \u0444\u0435\u0432\u0440\u0430\u043b\u044f 2020 \u0433\u043e\u0434\u0430, \u0443 \u043c\u0435\u043d\u044f \u0432\u043d\u0435\u0437\u0430\u043f\u043d\u043e \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 \u0441 \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438 <a href=\"https:\/\/github.com\/joke2k\/faker\/issues\/1123\">\u0438\u0437-\u0437\u0430 \u0431\u0430\u0433\u0430 \u0432 Faker<\/a> (2020-\u0439 \u2014 \u0432\u0438\u0441\u043e\u043a\u043e\u0441\u043d\u044b\u0439 \u0433\u043e\u0434, \u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0433\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b\u0431\u0438\u0440\u0430\u043b Faker, \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u044b\u043b\u0438 \u0432\u0438\u0441\u043e\u043a\u043e\u0441\u043d\u044b\u043c\u0438 \u0438 \u0432 \u043d\u0438\u0445 \u043d\u0435 \u0431\u044b\u043b\u043e 29 \u0444\u0435\u0432\u0440\u0430\u043b\u044f). \u041d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0439\u0442\u0435 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u0442\u044b \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0440\u0430\u0435\u0432\u044b\u0435 \u0441\u043b\u0443\u0447\u0430\u0438!<\/p><\/blockquote>\n<p>  <a name=\"test_migrations\"><\/a><\/p>\n<h3>\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p>  \u041a\u043e\u0434 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u043c \u0438 \u043d\u0430\u0438\u043c\u0435\u043d\u0435\u0435 \u043f\u043e\u0434\u0432\u0435\u0440\u0436\u0435\u043d\u043d\u044b\u043c \u043e\u0448\u0438\u0431\u043a\u0430\u043c, \u0437\u0430\u0447\u0435\u043c \u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c? \u042d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0437\u0430\u0431\u043b\u0443\u0436\u0434\u0435\u043d\u0438\u0435: \u0441\u0430\u043c\u044b\u0435 \u043a\u043e\u0432\u0430\u0440\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u043e\u044f\u0432\u0438\u0442\u044c \u0441\u0435\u0431\u044f \u0432 \u0441\u0430\u043c\u044b\u0439 \u043d\u0435\u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u0414\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u0440\u0442\u044f\u0442 \u0434\u0430\u043d\u043d\u044b\u0435, \u0442\u043e \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u0430\u0442\u044c \u043f\u0440\u0438\u0447\u0438\u043d\u043e\u0439 \u043b\u0438\u0448\u043d\u0435\u0433\u043e \u0434\u0430\u0443\u043d\u0442\u0430\u0439\u043c\u0430.<\/p>\n<p>  \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 <i>initial<\/i> \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435. \u041e\u0442 \u043a\u0430\u043a\u0438\u0445 \u0442\u0438\u043f\u043e\u0432\u044b\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0449\u0438\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f\u0445?<\/p>\n<ul>\n<li> \u041c\u0435\u0442\u043e\u0434 <code>downgrade<\/code> \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0438\u043b\u0438 \u043d\u0435 \u0443\u0434\u0430\u043b\u0435\u043d\u044b \u0432\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 (\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u044f \u043f\u0440\u043e \u043d\u0438\u0445 \u0443\u0436\u0435 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b).\n<p>  \u042d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u0432\u0430 \u0440\u0430\u0437\u0430 (\u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c-\u043e\u0442\u043a\u0430\u0442\u0438\u0442\u044c-\u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c): \u043f\u0440\u0438 \u043e\u0442\u043a\u0430\u0442\u0435 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u044b \u0432\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0435\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0439\u0434\u0435\u0442 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u2014 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.   <\/li>\n<li>C\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0438.<\/li>\n<li>\u041e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0441\u0432\u044f\u0437\u044f\u0445 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439 (\u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0430).<\/li>\n<\/ul>\n<p>  \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u044d\u0442\u0438\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442 <a href=\"https:\/\/github.com\/alvassin\/backendschool2019\/blob\/master\/tests\/migrations\/test_stairway.py\">stairway-\u0442\u0435\u0441\u0442<\/a>. \u0415\u0433\u043e \u0438\u0434\u0435\u044f \u2014 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043f\u043e \u043e\u0434\u043d\u043e\u0439, \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044f \u043c\u0435\u0442\u043e\u0434\u044b <code>upgrade<\/code>, <code>downgrade<\/code>, <code>upgrade<\/code> \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438. \u0422\u0430\u043a\u043e\u0439 \u0442\u0435\u0441\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442, \u043e\u043d \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0443\u0436\u0438\u0442\u044c \u0432\u0435\u0440\u043e\u0439 \u0438 \u043f\u0440\u0430\u0432\u0434\u043e\u0439.<\/p>\n<p>  \u0410 \u0432\u043e\u0442 \u0435\u0441\u043b\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f, \u043f\u043e\u043c\u0438\u043c\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0438\u0437\u043c\u0435\u043d\u044f\u043b\u0430 \u0431\u044b \u0434\u0430\u043d\u043d\u044b\u0435, \u0442\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0431\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0435\u0441\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0438\u0439, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>upgrade<\/code> \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u043a \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e \u0432 <code>downgrade<\/code>. \u041d\u0430 \u0432\u0441\u044f\u043a\u0438\u0439 \u0441\u043b\u0443\u0447\u0430\u0439: <a href=\"https:\/\/github.com\/alvassin\/alembic-quickstart\">\u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0439<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043b \u0434\u043b\u044f <a href=\"https:\/\/bit.ly\/2UhmyyD\">\u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043f\u0440\u043e Alembic<\/a> \u043d\u0430 Moscow Python.<\/p>\n<p>  <a name=\"build\"><\/a><\/p>\n<h1>\u0421\u0431\u043e\u0440\u043a\u0430<\/h1>\n<p>  \u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u0441\u044f \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0441\u0431\u043e\u0440\u043a\u0438, \u2014 Docker-\u043e\u0431\u0440\u0430\u0437. \u0414\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <b>\u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437<\/b> c Python. \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 <a href=\"https:\/\/hub.docker.com\/_\/python\"><code>python:latest<\/code><\/a> \u0432\u0435\u0441\u0438\u0442 ~1 \u0413\u0411 \u0438, \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e, \u043e\u0431\u0440\u0430\u0437 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u043c. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 <a href=\"https:\/\/github.com\/jfloff\/alpine-python#why\">\u043e\u0431\u0440\u0430\u0437\u044b \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u041e\u0421 Alpine<\/a>, \u0440\u0430\u0437\u043c\u0435\u0440 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044c\u0448\u0435. \u041d\u043e \u0441 \u0440\u0430\u0441\u0442\u0443\u0449\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0440\u0430\u0437\u043c\u0435\u0440 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 \u0432\u044b\u0440\u0430\u0441\u0442\u0435\u0442, \u0438 \u0432 \u0438\u0442\u043e\u0433\u0435 \u0434\u0430\u0436\u0435 \u043e\u0431\u0440\u0430\u0437, \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 Alpine, \u0431\u0443\u0434\u0435\u0442 \u043d\u0435 \u0442\u0430\u043a\u0438\u043c \u0443\u0436 \u0438 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c. \u042f \u0432\u044b\u0431\u0440\u0430\u043b \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 <a href=\"https:\/\/github.com\/snakepacker\/python\">snakepacker\/python<\/a> \u2014 \u043e\u043d \u0432\u0435\u0441\u0438\u0442 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435 Alpine-\u043e\u0431\u0440\u0430\u0437\u043e\u0432, \u043d\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 Ubuntu, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a.<\/p>\n<p>  \u0415\u0449\u0435 \u043e\u0434\u0438\u043d \u0441\u043f\u043e\u0441\u043e\u0431 <b>\u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u043e\u0431\u0440\u0430\u0437\u0430 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c<\/b> \u2014 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440, \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438 \u0444\u0430\u0439\u043b\u044b \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <\/p>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"https:\/\/docs.docker.com\/develop\/develop-images\/multistage-build\/#use-multi-stage-builds\">\u043c\u043d\u043e\u0433\u043e\u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u043e\u0439 \u0441\u0431\u043e\u0440\u043a\u043e\u0439<\/a> Docker:<\/p>\n<ol>\n<li> \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u00ab\u0442\u044f\u0436\u0435\u043b\u043e\u0433\u043e\u00bb \u043e\u0431\u0440\u0430\u0437\u0430 <code>snakepacker\/python:all<\/code> (~1 \u0413\u0411, \u0432 \u0441\u0436\u0430\u0442\u043e\u043c \u0432\u0438\u0434\u0435 ~500 \u041c\u0411) \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432 \u043d\u0435\u0433\u043e \u0432\u0441\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u043c\u043e\u0434\u0443\u043b\u044c \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c. \u042d\u0442\u043e\u0442 \u043e\u0431\u0440\u0430\u0437 \u043d\u0443\u0436\u0435\u043d \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438, \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440, \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0438 \u0444\u0430\u0439\u043b\u044b \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c\u0438.\n<pre><code class=\"python\">FROM snakepacker\/python:all as builder  # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 RUN python3.8 -m venv \/usr\/share\/python3\/app  # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c source distribution \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e COPY dist\/ \/mnt\/dist\/ RUN \/usr\/share\/python3\/app\/bin\/pip install \/mnt\/dist\/*<\/code><\/pre>\n<\/li>\n<li> \u0413\u043e\u0442\u043e\u0432\u043e\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0432 \u00ab\u043b\u0435\u0433\u043a\u0438\u0439\u00bb \u043e\u0431\u0440\u0430\u0437 <code>snakepacker\/python:3.8<\/code> (~100 \u041c\u0411, \u0432 \u0441\u0436\u0430\u0442\u043e\u043c \u0432\u0438\u0434\u0435 ~50 \u041c\u0411), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 Python.\n<p>  \u0412\u0430\u0436\u043d\u043e: \u0432 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0435 \u043f\u0443\u0442\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0442\u043e\u043c\u0443 \u0436\u0435 \u0430\u0434\u0440\u0435\u0441\u0443, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u043d\u043e \u0431\u044b\u043b\u043e \u0441\u043e\u0431\u0440\u0430\u043d\u043e \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435-\u0441\u0431\u043e\u0440\u0449\u0438\u043a\u0435. <\/p>\n<pre><code class=\"python\">FROM snakepacker\/python:3.8 as api  # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 builder COPY --from=builder \/usr\/share\/python3\/app \/usr\/share\/python3\/app  # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438 # \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f RUN ln -snf \/usr\/share\/python3\/app\/bin\/analyzer-* \/usr\/local\/bin\/  # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0443\u044e \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e CMD [&quot;analyzer-api&quot;]<\/code><\/pre>\n<\/li>\n<\/ol>\n<p>  \u0427\u0442\u043e\u0431\u044b <b>\u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0441\u0431\u043e\u0440\u043a\u0443 \u043e\u0431\u0440\u0430\u0437\u0430<\/b>, \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u043e \u0435\u0433\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u0422\u043e\u0433\u0434\u0430 Docker \u0437\u0430\u043a\u0435\u0448\u0438\u0440\u0443\u0435\u0442 \u0438\u0445 \u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u043d\u043e\u0432\u043e, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u0438\u0441\u044c.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Dockerfile \u0446\u0435\u043b\u0438\u043a\u043e\u043c<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">############### \u041e\u0431\u0440\u0430\u0437 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f ################ # \u041e\u0441\u043d\u043e\u0432\u0430 \u2014 \u00ab\u0442\u044f\u0436\u0435\u043b\u044b\u0439\u00bb (~1 \u0413\u0411, \u0432 \u0441\u0436\u0430\u0442\u043e\u043c \u0432\u0438\u0434\u0435 ~500 \u0413\u0411) \u043e\u0431\u0440\u0430\u0437 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 # \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 FROM snakepacker\/python:all as builder  # \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c pip RUN python3.8 -m venv \/usr\/share\/python3\/app RUN \/usr\/share\/python3\/app\/bin\/pip install -U pip  # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u041f\u0440\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0431\u043e\u0440\u043a\u0435 # Docker \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442 \u044d\u0442\u043e\u0442 \u0448\u0430\u0433, \u0435\u0441\u043b\u0438 requirements.txt \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f COPY requirements.txt \/mnt\/ RUN \/usr\/share\/python3\/app\/bin\/pip install -Ur \/mnt\/requirements.txt  # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c source distribution \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e COPY dist\/ \/mnt\/dist\/ RUN \/usr\/share\/python3\/app\/bin\/pip install \/mnt\/dist\/* \\     &amp;&amp; \/usr\/share\/python3\/app\/bin\/pip check  ########################### \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 ############################ # \u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0431\u0435\u0440\u0435\u043c \u00ab\u043b\u0435\u0433\u043a\u0438\u0439\u00bb (~100 \u041c\u0411, \u0432 \u0441\u0436\u0430\u0442\u043e\u043c \u0432\u0438\u0434\u0435 ~50 \u041c\u0411) \u043e\u0431\u0440\u0430\u0437 \u0441 Python FROM snakepacker\/python:3.8 as api  # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0432 \u043d\u0435\u0433\u043e \u0433\u043e\u0442\u043e\u0432\u043e\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 builder COPY --from=builder \/usr\/share\/python3\/app \/usr\/share\/python3\/app  # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438 # \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f RUN ln -snf \/usr\/share\/python3\/app\/bin\/analyzer-* \/usr\/local\/bin\/  # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0443\u044e \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e CMD [&quot;analyzer-api&quot;]<\/code><\/pre>\n<\/div><\/div>\n<p>  \u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0441\u0431\u043e\u0440\u043a\u0438 \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <code>make upload<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 Docker-\u043e\u0431\u0440\u0430\u0437 \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0435\u0433\u043e \u043d\u0430 hub.docker.com.<\/p>\n<p>  <a name=\"ci\"><\/a><\/p>\n<h1>CI<\/h1>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043a\u043e\u0434 \u043f\u043e\u043a\u0440\u044b\u0442 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u043c\u044b \u0443\u043c\u0435\u0435\u043c \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c Docker-\u043e\u0431\u0440\u0430\u0437, \u0441\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b. \u041f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0432 \u0433\u043e\u043b\u043e\u0432\u0443: \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0443\u043b-\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u043e\u0432, \u0430 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 master-\u0432\u0435\u0442\u043a\u0443 \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 Docker-\u043e\u0431\u0440\u0430\u0437 \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0435\u0433\u043e \u043d\u0430 <a href=\"https:\/\/hub.docker.com\">Docker Hub<\/a> (\u0438\u043b\u0438 <a href=\"https:\/\/github.com\/features\/packages\">GitHub Packages<\/a>, \u0435\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0435\u0441\u044c \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0437 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e).<\/p>\n<p>  \u042f \u0440\u0435\u0448\u0438\u043b \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/features\/actions\">GitHub Actions<\/a>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c YAML-\u0444\u0430\u0439\u043b \u0432 \u043f\u0430\u043f\u043a\u0435 <code>.github\/workflows<\/code> \u0438 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043d\u0435\u043c workflow (c \u0434\u0432\u0443\u043c\u044f \u0437\u0430\u0434\u0430\u0447\u0430\u043c\u0438: <code>test<\/code> \u0438 <code>publish<\/code>), \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u043d\u0430\u0437\u0432\u0430\u043b <code>CI<\/code>.<\/p>\n<p>  \u0417\u0430\u0434\u0430\u0447\u0430 <code>test<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 workflow <code>CI<\/code>, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/help.github.com\/en\/actions\/reference\/workflow-syntax-for-github-actions#jobsjob_idservices\">services<\/a> \u043f\u043e\u0434\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441 PostgreSQL, \u043e\u0436\u0438\u0434\u0430\u0435\u0442, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0441\u0442\u0430\u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d, \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 <code>pytest<\/code> \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 <code>snakepacker\/python:all<\/code>.<\/p>\n<p>  \u0417\u0430\u0434\u0430\u0447\u0430 <code>publish<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f, \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u044b\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0432 \u0432\u0435\u0442\u043a\u0443 <code>master<\/code> \u0438 \u0435\u0441\u043b\u0438 \u0437\u0430\u0434\u0430\u0447\u0430 <code>test<\/code> \u0431\u044b\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e. \u041e\u043d\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 source distribution \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u043c <code>snakepacker\/python:all<\/code>, \u0437\u0430\u0442\u0435\u043c \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 Docker-\u043e\u0431\u0440\u0430\u0437 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/docker\/build-push-action\"><code>docker\/build-push-action@v1<\/code><\/a>.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u043e\u043b\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 workflow<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"plaintext\">name: CI  # Workflow \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439  # \u0438\u043b\u0438 \u043d\u043e\u0432\u043e\u043c \u043f\u0443\u043b-\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0435 \u0432 master on:   push:     branches: [ master ]   pull_request:     branches: [ master ]  jobs:   # \u0422\u0435\u0441\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 workflow   test:     runs-on: ubuntu-latest      services:       postgres:         image: docker:\/\/postgres         ports:           - 5432:5432         env:           POSTGRES_USER: user           POSTGRES_PASSWORD: hackme           POSTGRES_DB: analyzer      steps:       - uses: actions\/checkout@v2       - name: test         uses: docker:\/\/snakepacker\/python:all         env:           CI_ANALYZER_PG_URL: postgresql:\/\/user:hackme@postgres\/analyzer         with:           args: \/bin\/bash -c &quot;pip install -U '.[dev]' &amp;&amp; pylama &amp;&amp; wait-for-port postgres:5432 &amp;&amp; pytest -vv --cov=analyzer --cov-report=term-missing tests&quot;    # \u0421\u0431\u043e\u0440\u043a\u0430 \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 Docker-\u043e\u0431\u0440\u0430\u0437\u0430 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c   publish:     # \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043f\u0430\u043b\u0438 \u0432 \u0432\u0435\u0442\u043a\u0443 master     if: github.event_name == 'push' &amp;&amp; github.ref == 'refs\/heads\/master'     # \u0422\u0440\u0435\u0431\u0443\u0435\u0442, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0434\u0430\u0447\u0430 test \u0431\u044b\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e     needs: test     runs-on: ubuntu-latest     steps:       - uses: actions\/checkout@v2       - name: sdist         uses: docker:\/\/snakepacker\/python:all         with:           args: make sdist        - name: build-push         uses: docker\/build-push-action@v1         with:           username: ${{ secrets.REGISTRY_LOGIN }}           password: ${{ secrets.REGISTRY_TOKEN }}           repository: alvassin\/backendschool2019           target: api           tags: 0.0.1, latest <\/code><\/pre>\n<\/div><\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 master \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 Actions \u043d\u0430 GitHub \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432, \u0441\u0431\u043e\u0440\u043a\u0443 \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443 Docker-\u043e\u0431\u0440\u0430\u0437\u0430:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/r5\/qx\/pm\/r5qxpmy7mlttqniibfvxadvzitw.png\"><\/p>\n<p>  \u0410 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0443\u043b-\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430 \u0432 master-\u0432\u0435\u0442\u043a\u0443 \u0432 \u043d\u0435\u043c \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0447\u0438 <code>test<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/pz\/d9\/nk\/pzd9nkmxq7a75fnlcw2tx37i308.png\"><\/p>\n<p>  <a name=\"deployment\"><\/a><\/p>\n<h1>\u0414\u0435\u043f\u043b\u043e\u0439<\/h1>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u043d\u0443\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Docker, Docker Compose, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438 PostgreSQL \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p>  \u042d\u0442\u0438 \u0448\u0430\u0433\u0438 \u043c\u043e\u0436\u043d\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c\u0438 Ansible. \u041e\u043d\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043d\u0430 Python, \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432 (\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u044f\u043c\u043e \u043f\u043e ssh), \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 jinja-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 YAML-\u0444\u0430\u0439\u043b\u0430\u0445. \u0414\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u0445, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043a \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e. \u0412\u0441\u044f \u044d\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u0430 \u043b\u043e\u0436\u0438\u0442\u0441\u044f \u043d\u0430 \u043f\u043b\u0435\u0447\u0438 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 Ansible.<\/p>\n<p>  Ansible \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 <b>\u0440\u043e\u043b\u0438<\/b> \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u041d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0434\u0432\u0435 \u0440\u043e\u043b\u0438: <code>docker<\/code> (\u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 Docker) \u0438 <code>analyzer<\/code> (\u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435).<\/p>\n<p>  <b>\u0420\u043e\u043b\u044c <code>docker<\/code><\/b> \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 Docker, \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u044b <code>docker-ce<\/code> \u0438 <code>docker-compose<\/code>.<\/p>\n<p>  \u041e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043b\u0430\u0434\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u044b REST API \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. Ubuntu \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0441\u0438\u043b\u0430\u043c\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/Systemd\"><code>systemd<\/code><\/a>. \u041e\u043d\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u044e\u043d\u0438\u0442\u0430\u043c\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u043c\u0438 \u0441\u043e\u0431\u043e\u0439 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b (\u0434\u0435\u043c\u043e\u043d\u044b, \u0441\u043e\u043a\u0435\u0442\u044b, \u0442\u043e\u0447\u043a\u0438 \u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0434\u0440\u0443\u0433\u0438\u0435). \u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044e\u043d\u0438\u0442 \u0432 systemd, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0435\u0433\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 .service \u0438 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0432 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0430\u043f\u043e\u043a, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432 <code>\/etc\/systemd\/system<\/code>. \u0417\u0430\u0442\u0435\u043c \u044e\u043d\u0438\u0442 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0430\u0432\u0442\u043e\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443.<\/p>\n<p>  \u041f\u0430\u043a\u0435\u0442 <code>docker-ce<\/code> \u043f\u0440\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0444\u0430\u0439\u043b \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 \u044e\u043d\u0438\u0442\u0430 \u2014 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u0414\u043b\u044f Docker Compose <a href=\"https:\/\/gist.github.com\/mosquito\/b23e1c1e5723a7fd9e6568e5cf91180f\"><code>\u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 docker-compose@.service<\/code><\/a> \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d \u0441\u0438\u043b\u0430\u043c\u0438 Ansible. \u0421\u0438\u043c\u0432\u043e\u043b <code>@<\/code> \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 systemd, \u0447\u0442\u043e \u044e\u043d\u0438\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043c. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441 <code>docker-compose<\/code> \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u2014 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432\u043c\u0435\u0441\u0442\u043e <code>%i<\/code> \u0432 \u0444\u0430\u0439\u043b\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u044e\u043d\u0438\u0442\u0430:<\/p>\n<pre><code class=\"plaintext\">[Unit] Description=%i service with docker compose Requires=docker.service After=docker.service  [Service] Type=oneshot RemainAfterExit=true WorkingDirectory=\/etc\/docker\/compose\/%i ExecStart=\/usr\/local\/bin\/docker-compose up -d --remove-orphans ExecStop=\/usr\/local\/bin\/docker-compose down  [Install] WantedBy=multi-user.target<\/code><\/pre>\n<p>  <b>\u0420\u043e\u043b\u044c <code>analyzer<\/code><\/b> \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0444\u0430\u0439\u043b <code>docker-compose.yml<\/code> \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>\/etc\/docker\/compose\/analyzer<\/code>, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043a\u0430\u043a \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0432 <code>systemd<\/code> \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438. \u041a\u043e\u0433\u0434\u0430 \u0440\u043e\u043b\u0438 \u0433\u043e\u0442\u043e\u0432\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c playbook.<\/p>\n<pre><code class=\"plaintext\">---  - name: Gathering facts   hosts: all   become: yes   gather_facts: yes  - name: Install docker   hosts: docker   become: yes   gather_facts: no   roles:     - docker  - name: Install analyzer   hosts: api   become: yes   gather_facts: no   roles:     - analyzer<\/code><\/pre>\n<p>  \u0421\u043f\u0438\u0441\u043e\u043a \u0445\u043e\u0441\u0442\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432 \u0440\u043e\u043b\u044f\u0445, \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432 inventory-\u0444\u0430\u0439\u043b\u0435 <code>hosts.ini<\/code>.<\/p>\n<pre><code class=\"plaintext\">[api] 130.193.51.154  [docker:children] api  [api:vars] analyzer_image = alvassin\/backendschool2019 analyzer_pg_user = user analyzer_pg_password = hackme analyzer_pg_dbname = analyzer<\/code><\/pre>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0432\u0441\u0435 \u0444\u0430\u0439\u043b\u044b Ansible \u0431\u0443\u0434\u0443\u0442 \u0433\u043e\u0442\u043e\u0432\u044b, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0435\u0433\u043e:<\/p>\n<pre><code class=\"plaintext\">$ ansible-playbook -i hosts.ini deploy.yml<\/code><\/pre>\n<p>  <a name=\"load_testing\"><\/a><\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041f\u0440\u043e \u043d\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/b>                         <\/p>\n<div class=\"spoiler_text\">\u0418\u0442\u0430\u043a, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u043e \u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u043e \u0438 \u0433\u043e\u0442\u043e\u0432\u043e \u043a \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438. \u0414\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0442\u044b \u043a\u0430\u0440\u0442\u0438\u043d\u044b \u043d\u0430 \u043c\u0438\u043d\u0443\u0442\u043a\u0443 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u0432\u043e\u0434\u043e\u043c \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043a\u043e\u0433\u0434\u0430-\u0442\u043e \u0431\u044b\u043b\u043e \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0435 <a href=\"https:\/\/yadi.sk\/i\/dA9umaGbQdMNLw\">\u0437\u0430\u0434\u0430\u043d\u0438\u0435<\/a>. \u0412 \u043d\u0435\u043c \u0431\u044b\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f: \u043d\u0430 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0435 \u0441 \u0434\u0435\u0441\u044f\u0442\u044c\u044e \u0442\u044b\u0441\u044f\u0447\u0430\u043c\u0438 \u0436\u0438\u0442\u0435\u043b\u0435\u0439, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0442\u044b\u0441\u044f\u0447\u0430 \u2014 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u0438 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430, \u043a\u0430\u0436\u0434\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043c\u0435\u043d\u0435\u0435 \u0447\u0435\u043c \u0437\u0430 10 \u0441\u0435\u043a\u0443\u043d\u0434. \u0411\u0435\u0437\u0443\u0441\u043b\u043e\u0432\u043d\u043e, \u0442\u0430\u043a\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0435 (\u0430, \u0441\u043a\u0430\u0436\u0435\u043c, \u043d\u0435 \u043d\u0430 CI-\u0441\u0435\u0440\u0432\u0435\u0440\u0435): \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.<\/p>\n<p>  \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043c\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0443 \u0441 \u0436\u0438\u0442\u0435\u043b\u044f\u043c\u0438, \u0432\u044b\u0437\u0432\u0430\u043b\u0438 \u0434\u0440\u0443\u0433 \u0437\u0430 \u0434\u0440\u0443\u0433\u043e\u043c \u0432\u0441\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438, \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043c\u0435\u043d\u0435\u0435 \u0447\u0435\u043c \u0437\u0430 10 \u0441\u0435\u043a\u0443\u043d\u0434. \u0414\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0438 \u044d\u0442\u043e\u0433\u043e? \u041c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c, \u0447\u0442\u043e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u0433\u0440\u0430\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441. \u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0433\u0440\u0443\u0437\u043e\u043a \u0441\u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0443\u0442 \u0443\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>  \u0425\u043e\u0442\u044c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u043a\u0438\u0439 RPS, \u0435\u0433\u043e \u043d\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u044e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c: \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0436\u0438\u0442\u0435\u043b\u0435\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043c\u0435\u0442\u044c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0438 <code>import_id<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c <code>POST \/imports<\/code> \u0438 \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043b\u044e\u0431\u044b\u043c \u0446\u0435\u043b\u044b\u043c \u0447\u0438\u0441\u043b\u043e\u043c. \u042d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044e. <\/p>\n<p>  \u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f, \u0447\u0442\u043e \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 Python 3, \u044f \u0440\u0435\u0448\u0438\u043b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c <a href=\"https:\/\/locust.io\">Locust<\/a>. <\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>locustfile.py<\/code> \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 <code>locust<\/code>. \u0417\u0430\u0442\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0430\u0445 \u0432 \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u0438\u043b\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438.<\/p>\n<p>  \u0413\u0440\u0430\u0444\u0438\u043a\u0438 Locust \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043e\u0431\u0449\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e. \u041c\u043d\u0435 \u0431\u044b\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0443\u0437\u043d\u0430\u0442\u044c, \u043d\u0430 \u043a\u0430\u043a\u043e\u043c \u0440\u0430\u0443\u043d\u0434\u0435 \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0435 \u0443\u043b\u043e\u0436\u0438\u0442\u0441\u044f \u0432 \u0442\u0430\u0439\u043c\u0430\u0443\u0442. \u042f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0441 \u043d\u043e\u043c\u0435\u0440\u043e\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u0439 <br \/>  \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 <code>self.round<\/code> \u0438 \u043b\u043e\u0433\u0438\u0432\u0430\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">\u041e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0432 \u0444\u0430\u0439\u043b\u0435 locustfile.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\"># locustfile.py import logging from http import HTTPStatus  from locust import HttpLocust, constant, task, TaskSet from locust.exception import RescheduleTask  from analyzer.api.handlers import (     CitizenBirthdaysView, CitizensView, CitizenView, TownAgeStatView ) from analyzer.utils.testing import generate_citizen, generate_citizens, url_for   class AnalyzerTaskSet(TaskSet):     def __init__(self, *args, **kwargs):         super().__init__(*args, **kwargs)         self.round = 0      def make_dataset(self):         citizens = [             # \u041f\u0435\u0440\u0432\u043e\u0433\u043e \u0436\u0438\u0442\u0435\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0438\u043a\u043e\u043c. \u0412 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a             # PATCH-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u0441\u043f\u0438\u0441\u043e\u043a relatives \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0440\u0443\u0433\u043e\u0433\u043e             # \u0436\u0438\u0442\u0435\u043b\u044f, \u0447\u0442\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043b-\u0432\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432             # (\u043a\u0430\u043a \u043d\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0440\u043e\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438, \u0442\u0430\u043a \u0438 \u043d\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435             # \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439).             generate_citizen(citizen_id=1, relatives=[2]),             generate_citizen(citizen_id=2, relatives=[1]),             *generate_citizens(citizens_num=9998, relations_num=1000,                                start_citizen_id=3)         ]         return {citizen['citizen_id']: citizen for citizen in citizens}      def request(self, method, path, expected_status, **kwargs):         with self.client.request(                 method, path, catch_response=True, **kwargs         ) as resp:             if resp.status_code != expected_status:                 resp.failure(f'expected status {expected_status}, '                              f'got {resp.status_code}')             logging.info(                 'round %r: %s %s, http status %d (expected %d), took %rs',                 self.round, method, path, resp.status_code, expected_status,                 resp.elapsed.total_seconds()             )             return resp      def create_import(self, dataset):         resp = self.request('POST', '\/imports', HTTPStatus.CREATED,                             json={'citizens': list(dataset.values())})         if resp.status_code != HTTPStatus.CREATED:             raise RescheduleTask         return resp.json()['data']['import_id']      def get_citizens(self, import_id):         url = url_for(CitizensView.URL_PATH, import_id=import_id)         self.request('GET', url, HTTPStatus.OK,                      name='\/imports\/{import_id}\/citizens')      def update_citizen(self, import_id):         url = url_for(CitizenView.URL_PATH, import_id=import_id, citizen_id=1)         self.request('PATCH', url, HTTPStatus.OK,                      name='\/imports\/{import_id}\/citizens\/{citizen_id}',                      json={'relatives': [i for i in range(3, 10)]})      def get_birthdays(self, import_id):         url = url_for(CitizenBirthdaysView.URL_PATH, import_id=import_id)         self.request('GET', url, HTTPStatus.OK,                      name='\/imports\/{import_id}\/citizens\/birthdays')      def get_town_stats(self, import_id):         url = url_for(TownAgeStatView.URL_PATH, import_id=import_id)         self.request('GET', url, HTTPStatus.OK,                      name='\/imports\/{import_id}\/towns\/stat\/percentile\/age')      @task     def workflow(self):         self.round += 1         dataset = self.make_dataset()          import_id = self.create_import(dataset)         self.get_citizens(import_id)         self.update_citizen(import_id)         self.get_birthdays(import_id)         self.get_town_stats(import_id)   class WebsiteUser(HttpLocust):     task_set = AnalyzerTaskSet     wait_time = constant(1)<\/code><\/pre>\n<\/div><\/div>\n<p>  \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0432 100 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439 c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430\u043c\u0438, \u044f \u0443\u0431\u0435\u0434\u0438\u043b\u0441\u044f, \u0447\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u0441\u0435\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0443\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/qx\/ri\/b3\/qxrib3jily9gzmexxhupu35tipa.png\"><\/p>\n<p>  \u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0435 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u0434\u0435\u0433\u0440\u0430\u0434\u0438\u0440\u0443\u0435\u0442 \u0441 \u0440\u043e\u0441\u0442\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 (\u0436\u0435\u043b\u0442\u044b\u0439 \u2014 95 \u043f\u0435\u0440\u0446\u0435\u043d\u0442\u0438\u043b\u044c, \u0437\u0435\u043b\u0435\u043d\u044b\u0439 \u2014 \u043c\u0435\u0434\u0438\u0430\u043d\u0430). \u0414\u0430\u0436\u0435 \u0441\u043e \u0441\u0442\u0430 \u0432\u044b\u0433\u0440\u0443\u0437\u043a\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/dn\/px\/fn\/dnpxfn5ly7vttziqnnfpvvdsl9g.png\"><\/p>\n<p>  \u041d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0430\u0445 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432\u0438\u0434\u0435\u043d \u0432\u0441\u043f\u043b\u0435\u0441\u043a \u2014 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Ansible \u0438 \u0434\u0430\u043b\u0435\u0435 \u0440\u043e\u0432\u043d\u043e\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0441 ~20.15 \u0434\u043e ~20.30 \u043f\u043e\u0434 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439 \u043e\u0442 Locust.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/om\/1e\/ok\/om1eoknqvzqmyez-plpgykhz8io.png\"><\/div>\n<\/p><\/div>\n<p>  <a name=\"whatelse\"><\/a><\/p>\n<h1>\u0427\u0442\u043e \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c?<\/h1>\n<p>  \u041f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u043e, \u0447\u0442\u043e \u043e\u043a\u043e\u043b\u043e \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0438 \u0432\u0441\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0443\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e JSON: \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c\u044b\u0445 \u0438\u0437 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043c\u043d\u043e\u0433\u043e. \u042d\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u043c\u043e\u0436\u043d\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <a href=\"https:\/\/github.com\/ijl\/orjson\">orjson<\/a>, \u043d\u043e \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u2014 <code>orjson<\/code> \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f drop-in-\u0437\u0430\u043c\u0435\u043d\u043e\u0439 \u0434\u043b\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f <code>json<\/code> <\/p>\n<p>  \u041e\u0431\u044b\u0447\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043f\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0438 \u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u0441 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439. \u0414\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0433\u0440\u0443\u043f\u043f\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0443\u0436\u0435\u043d \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439, \u00ab\u0436\u0438\u0432\u0430\u00bb \u043b\u0438 \u043a\u043e\u043f\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0420\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c <code>\/health<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0441\u043b\u0438 <code>SELECT 1<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043c\u0435\u043d\u044c\u0448\u0435 \u0447\u0435\u043c \u0437\u0430 \u0441\u0435\u043a\u0443\u043d\u0434\u0443, \u0442\u043e \u0441\u0435\u0440\u0432\u0438\u0441 \u0436\u0438\u0432. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u2014 \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u043d\u0430 \u043d\u0435\u0433\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435.<\/p>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0447\u0435\u043d\u044c \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0441\u0435\u0442\u044c\u044e, <a href=\"https:\/\/github.com\/MagicStack\/uvloop\">uvloop<\/a> \u043c\u043e\u0436\u0435\u0442 \u0437\u0434\u043e\u0440\u043e\u0432\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>  \u041d\u0435\u043c\u0430\u043b\u043e\u0432\u0430\u0436\u043d\u044b\u043c \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438 \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0434\u0430. \u041e\u0434\u0438\u043d \u043c\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u0433\u0430, \u042e\u0440\u0438\u0439 \u0428\u0438\u043a\u0430\u043d\u043e\u0432, \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0438\u0439 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043c\u043e\u0434\u0443\u043b\u044c <a href=\"https:\/\/github.com\/dizballanze\/gray\">gray<\/a> \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438 \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043b\u0435\u0433\u043a\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 <code>pre-commit<\/code> Git-\u0445\u0443\u043a, \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043e\u0434\u043d\u0438\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. Gray \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u044b (<a href=\"https:\/\/timothycrosley.github.io\/isort\/\">isort<\/a>), \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f python \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043d\u043e\u0432\u044b\u043c\u0438 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 \u044f\u0437\u044b\u043a\u0430 (<a href=\"https:\/\/github.com\/asottile\/pyupgrade\">pyupgrade<\/a>), \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u044f\u0442\u044b\u0435 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0438\u043c\u043f\u043e\u0440\u0442\u043e\u0432, \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0438 \u0442. \u0434. (<a href=\"https:\/\/github.com\/asottile\/add-trailing-comma\">add-trailing-comma<\/a>), \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a\u0430\u0432\u044b\u0447\u043a\u0438 \u043a \u0435\u0434\u0438\u043d\u043e\u043c\u0443 \u0432\u0438\u0434\u0443 (<a href=\"https:\/\/github.com\/myint\/unify\">unify<\/a>).<\/p>\n<p>  <a name=\"final\"><\/a><\/p>\n<h1>* * *<\/h1>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u0443 \u043c\u0435\u043d\u044f \u0432\u0441\u0435: \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438, \u043f\u043e\u043a\u0440\u044b\u043b\u0438 \u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0441\u043e\u0431\u0440\u0430\u043b\u0438 \u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u0432\u0435\u043b\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043e\u0447\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<h1>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u043d\u043e\u0441\u0442\u0438<\/h1>\n<p>  \u042f \u0445\u043e\u0442\u0435\u043b \u0431\u044b \u0432\u044b\u0440\u0430\u0437\u0438\u0442\u044c \u043e\u0433\u0440\u043e\u043c\u043d\u0443\u044e \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u043d\u043e\u0441\u0442\u044c \u0440\u0435\u0431\u044f\u0442\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0448\u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0438\u043d\u044f\u0442\u044c \u0443\u0447\u0430\u0441\u0442\u0438\u0435 \u0432 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u043f\u043e\u0440\u0435\u0432\u044c\u044e\u0432\u0438\u0442\u044c \u043a\u043e\u0434, \u0432\u043d\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0438 \u0438\u0434\u0435\u0438 \u0438 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f: \u041c\u0430\u0440\u0438\u0438 \u0417\u0435\u043b\u0435\u043d\u043e\u0432\u043e\u0439 <a href=\"https:\/\/habr.com\/ru\/users\/zelma\/\" class=\"user_link\">zelma<\/a>, \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0443 \u0421\u043e\u043b\u043e\u043c\u0430\u0442\u0438\u043d\u0443 <a href=\"https:\/\/habr.com\/ru\/users\/leenr\/\" class=\"user_link\">leenr<\/a>, \u0410\u043d\u0430\u0441\u0442\u0430\u0441\u0438\u0438 \u0421\u0435\u043c\u0451\u043d\u043e\u0432\u043e\u0439 <a href=\"https:\/\/habr.com\/ru\/users\/morkov\/\" class=\"user_link\">morkov<\/a>, \u042e\u0440\u0438\u044e \u0428\u0438\u043a\u0430\u043d\u043e\u0432\u0443 <a href=\"https:\/\/habr.com\/ru\/users\/dizballanze\/\" class=\"user_link\">dizballanze<\/a>, \u041c\u0438\u0445\u0430\u0438\u043b\u0443 \u0428\u0443\u0448\u043f\u0430\u043d\u043e\u0432\u0443 <a href=\"https:\/\/habr.com\/ru\/users\/mishush\/\" class=\"user_link\">mishush<\/a>, \u041f\u0430\u0432\u043b\u0443 \u041c\u043e\u0441\u0435\u0438\u043d\u0443 <a href=\"https:\/\/habr.com\/ru\/users\/pavkazzz\/\" class=\"user_link\">pavkazzz<\/a> \u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0414\u043c\u0438\u0442\u0440\u0438\u044e \u041e\u0440\u043b\u043e\u0432\u0443 <a href=\"https:\/\/habr.com\/ru\/users\/orlovdl\/\" class=\"user_link\">orlovdl<\/a>.<\/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\/company\/yandex\/blog\/499534\/\"> https:\/\/habr.com\/ru\/company\/yandex\/blog\/499534\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/company\/yandex\/blog\/499534\/\">\u041f\u0440\u0438\u0432\u0435\u0442, \u043c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0412\u0430\u0441\u0438\u043d, \u044f \u0431\u044d\u043a\u0435\u043d\u0434-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0415\u0434\u0430\u0434\u0438\u043b\u0435. \u0418\u0434\u0435\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043d\u0430\u0447\u0430\u043b\u0430\u0441\u044c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u0445\u043e\u0442\u0435\u043b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 (<a href=\"https:\/\/yadi.sk\/i\/dA9umaGbQdMNLw\">\u042f.\u0414\u0438\u0441\u043a<\/a>) \u0432 \u0428\u043a\u043e\u043b\u0443 \u0431\u044d\u043a\u0435\u043d\u0434-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u042f\u043d\u0434\u0435\u043a\u0441\u0430. \u042f \u043d\u0430\u0447\u0430\u043b \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u0438 \u0432\u044b\u0431\u043e\u0440\u0430 \u0442\u0435\u0445 \u0438\u043b\u0438 \u0438\u043d\u044b\u0445 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0439, \u043c\u0435\u0442\u043e\u0434\u0438\u043a\u0443 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\u2026 \u041f\u043e\u043b\u0443\u0447\u0430\u043b\u0441\u044f \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u0440\u0430\u0437\u0431\u043e\u0440, \u0430 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u0433\u0430\u0439\u0434 \u043f\u043e \u0442\u043e\u043c\u0443, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u0431\u044d\u043a\u0435\u043d\u0434\u044b \u043d\u0430 Python. \u041e\u0442 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u0434\u0435\u0438 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443, \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0434\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0438 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438. \u0412 \u0438\u0442\u043e\u0433\u0435 \u044f \u043e\u0447\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0441\u043e\u0442\u043d\u0435 \u0442\u044b\u0441\u044f\u0447 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432. \u0420\u043e\u0432\u043d\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432\u0441\u0451 \u0432 \u043c\u0435\u043b\u044c\u0447\u0430\u0439\u0448\u0438\u0445 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u0445. \u0418\u0442\u0430\u043a, \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 100 \u043a\u0438\u043b\u043e\u0431\u0430\u0439\u0442: \u043a\u0430\u043a \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0431\u044d\u043a\u0435\u043d\u0434 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u043e\u0442 \u0432\u044b\u0431\u043e\u0440\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044f \u0434\u0435\u043f\u043b\u043e\u0435\u043c.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ks\/_x\/t3\/ks_xt39dvtjt1ychs8mt3blwyg0.png\"><\/p>\n<p>  <b>TL;DR:<\/b> \u0412\u043e\u0442 <a href=\"https:\/\/github.com\/alvassin\/backendschool2019\">\u0440\u0435\u043f\u043a\u0430 \u043d\u0430 GitHub \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c<\/a>, \u0430 \u043a\u0442\u043e \u043b\u044e\u0431\u0438\u0442 (\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435) \u043b\u043e\u043d\u0433\u0440\u0438\u0434\u044b \u2014 \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.  <\/p>\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-302754","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/302754","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=302754"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/302754\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=302754"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=302754"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=302754"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}