From 7cbe7b7c50c6debc19a5ee773800baf940ee9552 Mon Sep 17 00:00:00 2001 From: Dmitry Afanasyev <71835315+Balshgit@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:38:56 +0300 Subject: [PATCH] add more tests (#79) * add more tests * add more tests & update poetry.lock --- bot_microservice/main.py | 2 +- .../tests/integration/bot/test_bot_api.py | 118 ++++++++++ .../tests/integration/bot/test_bot_updates.py | 208 +++++++++++++++++- .../tests/integration/factories/user.py | 10 +- bot_microservice/tests/integration/utils.py | 4 +- poetry.lock | 58 ++--- pyproject.toml | 6 +- 7 files changed, 368 insertions(+), 38 deletions(-) diff --git a/bot_microservice/main.py b/bot_microservice/main.py index 5dd19fc..fd9f18a 100644 --- a/bot_microservice/main.py +++ b/bot_microservice/main.py @@ -22,7 +22,7 @@ class Application: self.app = FastAPI( title="Chat gpt bot", description="Bot for proxy to chat gpt in telegram", - version="0.0.3", + version="1.1.12", docs_url=build_uri([settings.api_prefix, "docs"]), redoc_url=build_uri([settings.api_prefix, "redocs"]), openapi_url=build_uri([settings.api_prefix, "openapi.json"]), diff --git a/bot_microservice/tests/integration/bot/test_bot_api.py b/bot_microservice/tests/integration/bot/test_bot_api.py index 4516f99..b6fee26 100644 --- a/bot_microservice/tests/integration/bot/test_bot_api.py +++ b/bot_microservice/tests/integration/bot/test_bot_api.py @@ -75,6 +75,38 @@ async def test_change_chatgpt_model_priority( assert upd_model2.priority == priority +@pytest.mark.parametrize( + "bot_api_key_header", + [ + pytest.param({"BOT-API-KEY": ""}, id="empty key in header"), + pytest.param({"BOT-API-KEY": "Hello World"}, id="incorrect token"), + pytest.param({"Hello-World": "lasdkj3-wer-weqwe_34"}, id="correct token but wrong api key"), + pytest.param({}, id="no api key header"), + ], +) +async def test_cant_change_chatgpt_model_priority_with_wrong_api_key( + dbsession: Session, + rest_client: AsyncClient, + faker: Faker, + test_settings: AppSettings, + bot_api_key_header: dict[str, str], +) -> None: + ChatGptModelFactory(priority=0) + model2 = ChatGptModelFactory(priority=1) + priority = faker.random_int(min=2, max=7) + user = UserFactory(username=test_settings.SUPERUSER) + AccessTokenFactory(user_id=user.id, token="lasdkj3-wer-weqwe_34") # noqa: S106 + response = await rest_client.put( + url=f"/api/chatgpt/models/{model2.id}/priority", + json={"priority": priority}, + headers=bot_api_key_header, + ) + assert response.status_code == 403 + + changed_model = dbsession.query(ChatGptModels).filter_by(id=model2.id).one() + assert changed_model.priority == model2.priority + + async def test_reset_chatgpt_models_priority( dbsession: Session, rest_client: AsyncClient, @@ -101,6 +133,37 @@ async def test_reset_chatgpt_models_priority( assert model.priority == 0 +@pytest.mark.parametrize( + "bot_api_key_header", + [ + pytest.param({"BOT-API-KEY": ""}, id="empty key in header"), + pytest.param({"BOT-API-KEY": "Hello World"}, id="incorrect token"), + ], +) +async def test_cant_reset_chatgpt_models_priority_with_wrong_api_key( + dbsession: Session, rest_client: AsyncClient, test_settings: AppSettings, bot_api_key_header: dict[str, str] +) -> None: + chat_gpt_models = ChatGptModelFactory.create_batch(size=2) + model_with_highest_priority = ChatGptModelFactory(priority=42) + + priorities = sorted([model.priority for model in chat_gpt_models] + [model_with_highest_priority.priority]) + + user = UserFactory(username=test_settings.SUPERUSER) + AccessTokenFactory(user_id=user.id) + + response = await rest_client.put( + url="/api/chatgpt/models/priority/reset", + headers=bot_api_key_header, + ) + assert response.status_code == 403 + + models = dbsession.query(ChatGptModels).all() + + changed_priorities = sorted([model.priority for model in models]) + + assert changed_priorities == priorities + + async def test_create_new_chatgpt_model( dbsession: Session, rest_client: AsyncClient, @@ -142,6 +205,37 @@ async def test_create_new_chatgpt_model( } +async def test_cant_create_new_chatgpt_model_with_wrong_api_key( + dbsession: Session, + rest_client: AsyncClient, + faker: Faker, + test_settings: AppSettings, +) -> None: + ChatGptModelFactory.create_batch(size=2) + ChatGptModelFactory(priority=42) + + user = UserFactory(username=test_settings.SUPERUSER) + AccessTokenFactory(user_id=user.id) + + model_name = "new-gpt-model" + model_priority = faker.random_int(min=1, max=5) + + models = dbsession.query(ChatGptModels).all() + assert len(models) == 3 + + response = await rest_client.post( + url="/api/chatgpt/models", + json={ + "model": model_name, + "priority": model_priority, + }, + ) + assert response.status_code == 403 + + models = dbsession.query(ChatGptModels).all() + assert len(models) == 3 + + async def test_add_existing_chatgpt_model( dbsession: Session, rest_client: AsyncClient, @@ -197,3 +291,27 @@ async def test_delete_chatgpt_model( assert len(models) == 2 assert model not in models + + +async def test_cant_delete_chatgpt_model_with_wrong_api_key( + dbsession: Session, + rest_client: AsyncClient, + test_settings: AppSettings, +) -> None: + ChatGptModelFactory.create_batch(size=2) + model = ChatGptModelFactory(priority=42) + + user = UserFactory(username=test_settings.SUPERUSER) + access_token = AccessTokenFactory(user_id=user.id) + + models = dbsession.query(ChatGptModels).all() + assert len(models) == 3 + + response = await rest_client.delete( + url=f"/api/chatgpt/models/{model.id}", + headers={"ROOT-ACCESS": access_token.token}, + ) + assert response.status_code == 403 + + models = dbsession.query(ChatGptModels).all() + assert len(models) == 3 diff --git a/bot_microservice/tests/integration/bot/test_bot_updates.py b/bot_microservice/tests/integration/bot/test_bot_updates.py index 3db8a06..0a2f746 100644 --- a/bot_microservice/tests/integration/bot/test_bot_updates.py +++ b/bot_microservice/tests/integration/bot/test_bot_updates.py @@ -11,6 +11,7 @@ from sqlalchemy.orm import Session from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update from constants import BotStagesEnum +from core.auth.models.users import User, UserQuestionCount from core.bot.app import BotApplication, BotQueue from main import Application from settings.config import AppSettings @@ -22,6 +23,7 @@ from tests.integration.factories.bot import ( CallBackFactory, ChatGptModelFactory, ) +from tests.integration.factories.user import UserFactory, UserQuestionCountFactory from tests.integration.utils import mocked_ask_question_api pytestmark = [ @@ -113,6 +115,33 @@ async def test_help_command( ) +async def test_help_command_user_is_banned( + main_application: Application, + test_settings: AppSettings, +) -> None: + message = BotMessageFactory.create_instance(text="/help") + user = message["from"] + UserFactory( + id=user["id"], + first_name=user["first_name"], + last_name=user["last_name"], + username=user["username"], + is_active=False, + ban_reason="test reason", + ) + with mock.patch.object( + telegram._bot.Bot, "send_message", return_value=lambda *args, **kwargs: (args, kwargs) + ) as mocked_send_message: + bot_update = BotUpdateFactory(message=message) + + await main_application.bot_app.application.process_update( + update=Update.de_json(data=bot_update, bot=main_application.bot_app.bot) + ) + assert mocked_send_message.call_args.kwargs["text"] == ( + "You have banned for reason: *test reason*.\nPlease contact the /developer" + ) + + async def test_start_entry( main_application: Application, test_settings: AppSettings, @@ -232,6 +261,35 @@ async def test_website_callback_action( assert mocked_reply_text.call_args.args == ("Веб версия: http://localhost/chat/",) +async def test_website_callback_action_user_is_banned( + main_application: Application, + test_settings: AppSettings, +) -> None: + message = BotMessageFactory.create_instance(text="Список основных команд:") + user = message["from"] + UserFactory( + id=user["id"], + first_name=user["first_name"], + last_name=user["last_name"], + username=user["username"], + is_active=False, + ban_reason="test reason", + ) + with mock.patch.object(telegram._message.Message, "reply_text") as mocked_reply_text: + bot_update = BotCallBackQueryFactory( + message=message, + callback_query=CallBackFactory(data=BotStagesEnum.website), + ) + + await main_application.bot_app.application.process_update( + update=Update.de_json(data=bot_update, bot=main_application.bot_app.bot) + ) + + assert mocked_reply_text.call_args.kwargs["text"] == ( + "You have banned for reason: *test reason*.\nPlease contact the /developer" + ) + + async def test_bug_report_action( main_application: Application, test_settings: AppSettings, @@ -261,6 +319,35 @@ async def test_bug_report_action( ) +async def test_bug_report_action_user_is_banned( + main_application: Application, + test_settings: AppSettings, +) -> None: + message = BotMessageFactory.create_instance(text="/bug_report") + user = message["from"] + UserFactory( + id=user["id"], + first_name=user["first_name"], + last_name=user["last_name"], + username=user["username"], + is_active=False, + ban_reason="test reason", + ) + with ( + mock.patch.object(telegram._message.Message, "reply_text") as mocked_reply_text, + mock.patch.object(telegram._bot.Bot, "send_message", return_value=lambda *args, **kwargs: (args, kwargs)), + ): + bot_update = BotUpdateFactory(message=message) + + await main_application.bot_app.application.process_update( + update=Update.de_json(data=bot_update, bot=main_application.bot_app.bot) + ) + + assert mocked_reply_text.call_args.kwargs["text"] == ( + "You have banned for reason: *test reason*.\nPlease contact the /developer" + ) + + async def test_get_developer_action( main_application: Application, test_settings: AppSettings, @@ -278,19 +365,28 @@ async def test_get_developer_action( assert mocked_reply_text.call_args.args == ("Автор бота: *Дмитрий Афанасьев*\n\nTg nickname: *Balshtg*",) -async def test_ask_question_action( +async def test_ask_question_action_bot_user_not_exists( dbsession: Session, main_application: Application, test_settings: AppSettings, ) -> None: ChatGptModelFactory.create_batch(size=3) + users = dbsession.query(User).all() + users_question_count = dbsession.query(UserQuestionCount).all() + + assert len(users) == 0 + assert len(users_question_count) == 0 + + message = BotMessageFactory.create_instance(text="Привет!") + user = message["from"] + with mock.patch.object( telegram._bot.Bot, "send_message", return_value=lambda *args, **kwargs: (args, kwargs) ) as mocked_send_message, mocked_ask_question_api( host=test_settings.GPT_BASE_HOST, return_value=Response(status_code=httpx.codes.OK, text="Привет! Как я могу помочь вам сегодня?"), ): - bot_update = BotUpdateFactory(message=BotMessageFactory.create_instance(text="Привет!")) + bot_update = BotUpdateFactory(message=message) bot_update["message"].pop("entities") await main_application.bot_app.application.process_update( @@ -313,6 +409,114 @@ async def test_ask_question_action( include=["text", "chat_id"], ) + created_user = dbsession.query(User).filter_by(id=user["id"]).one() + assert created_user.username == user["username"] + + created_user_question_count = dbsession.query(UserQuestionCount).filter_by(user_id=user["id"]).one() + assert created_user_question_count.question_count == 1 + + +async def test_ask_question_action_bot_user_already_exists( + dbsession: Session, + main_application: Application, + test_settings: AppSettings, +) -> None: + ChatGptModelFactory.create_batch(size=3) + message = BotMessageFactory.create_instance(text="Привет!") + user = message["from"] + existing_user = UserFactory( + id=user["id"], first_name=user["first_name"], last_name=user["last_name"], username=user["username"] + ) + existing_user_question_count = UserQuestionCountFactory(user_id=existing_user.id).question_count + + users = dbsession.query(User).all() + assert len(users) == 1 + + with mock.patch.object( + telegram._bot.Bot, "send_message", return_value=lambda *args, **kwargs: (args, kwargs) + ) as mocked_send_message, mocked_ask_question_api( + host=test_settings.GPT_BASE_HOST, + return_value=Response(status_code=httpx.codes.OK, text="Привет! Как я могу помочь вам сегодня?"), + ): + bot_update = BotUpdateFactory(message=message) + bot_update["message"].pop("entities") + + await main_application.bot_app.application.process_update( + update=Update.de_json(data=bot_update, bot=main_application.bot_app.bot) + ) + assert_that(mocked_send_message.call_args_list[0].kwargs).is_equal_to( + { + "text": ( + "Ответ в среднем занимает 10-15 секунд.\n- Список команд: /help\n- Сообщить об ошибке: /bug_report" + ), + "chat_id": bot_update["message"]["chat"]["id"], + }, + include=["text", "chat_id"], + ) + assert_that(mocked_send_message.call_args_list[1].kwargs).is_equal_to( + { + "text": "Привет! Как я могу помочь вам сегодня?", + "chat_id": bot_update["message"]["chat"]["id"], + }, + include=["text", "chat_id"], + ) + + users = dbsession.query(User).all() + assert len(users) == 1 + + updated_user_question_count = dbsession.query(UserQuestionCount).filter_by(user_id=user["id"]).one() + assert updated_user_question_count.question_count == existing_user_question_count + 1 + + +async def test_ask_question_action_user_is_banned( + dbsession: Session, + main_application: Application, + test_settings: AppSettings, +) -> None: + ChatGptModelFactory.create_batch(size=3) + + users_question_count = dbsession.query(UserQuestionCount).all() + assert len(users_question_count) == 0 + + message = BotMessageFactory.create_instance(text="Привет!") + user = message["from"] + UserFactory( + id=user["id"], + first_name=user["first_name"], + last_name=user["last_name"], + username=user["username"], + is_active=False, + ban_reason="test reason", + ) + + with mock.patch.object( + telegram._bot.Bot, "send_message", return_value=lambda *args, **kwargs: (args, kwargs) + ) as mocked_send_message, mocked_ask_question_api( + host=test_settings.GPT_BASE_HOST, + return_value=Response(status_code=httpx.codes.OK, text="Привет! Как я могу помочь вам сегодня?"), + assert_all_called=False, + ): + bot_update = BotUpdateFactory(message=message) + bot_update["message"].pop("entities") + + await main_application.bot_app.application.process_update( + update=Update.de_json(data=bot_update, bot=main_application.bot_app.bot) + ) + assert_that(mocked_send_message.call_args_list[0].kwargs).is_equal_to( + { + "text": ("You have banned for reason: *test reason*.\nPlease contact the /developer"), + "chat_id": bot_update["message"]["chat"]["id"], + }, + include=["text", "chat_id"], + ) + + created_user = dbsession.query(User).filter_by(id=user["id"]).one() + assert created_user.username == user["username"] + assert created_user.is_active is False + + created_user_question_count = dbsession.query(UserQuestionCount).filter_by(user_id=user["id"]).scalar() + assert created_user_question_count is None + async def test_ask_question_action_not_success( dbsession: Session, diff --git a/bot_microservice/tests/integration/factories/user.py b/bot_microservice/tests/integration/factories/user.py index 3b122c7..5a117cf 100644 --- a/bot_microservice/tests/integration/factories/user.py +++ b/bot_microservice/tests/integration/factories/user.py @@ -2,7 +2,7 @@ import uuid import factory -from core.auth.models.users import AccessToken, User +from core.auth.models.users import AccessToken, User, UserQuestionCount from tests.integration.factories.utils import BaseModelFactory @@ -29,3 +29,11 @@ class AccessTokenFactory(BaseModelFactory): class Meta: model = AccessToken + + +class UserQuestionCountFactory(BaseModelFactory): + user_id = factory.Sequence(lambda n: n + 1) + question_count = factory.Faker("random_int") + + class Meta: + model = UserQuestionCount diff --git a/bot_microservice/tests/integration/utils.py b/bot_microservice/tests/integration/utils.py index d89668e..241d8d2 100644 --- a/bot_microservice/tests/integration/utils.py +++ b/bot_microservice/tests/integration/utils.py @@ -9,11 +9,11 @@ from settings.config import settings @contextmanager def mocked_ask_question_api( - host: str, return_value: Response | None = None, side_effect: Any | None = None + host: str, return_value: Response | None = None, side_effect: Any | None = None, assert_all_called: bool = True ) -> Iterator[respx.MockRouter]: with respx.mock( assert_all_mocked=True, - assert_all_called=True, + assert_all_called=assert_all_called, base_url=host, ) as respx_mock: ask_question_route = respx_mock.post(url=settings.chatgpt_backend_url, name="ask_question") diff --git a/poetry.lock b/poetry.lock index 671f684..39b4bbc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -607,25 +607,25 @@ toml = ["tomli"] [[package]] name = "cyclonedx-python-lib" -version = "5.2.0" +version = "6.3.0" description = "Python library for CycloneDX" optional = false python-versions = ">=3.8,<4.0" files = [ - {file = "cyclonedx_python_lib-5.2.0-py3-none-any.whl", hash = "sha256:1b43065205cdc53490c825fcfbda73142b758aa40ca169c968e342e88d06734f"}, - {file = "cyclonedx_python_lib-5.2.0.tar.gz", hash = "sha256:b9ebf2c0520721d2f8ee16aadc2bbb9d4e015862c84ab1691a49b177f3014d99"}, + {file = "cyclonedx_python_lib-6.3.0-py3-none-any.whl", hash = "sha256:0e73c1036c2f7fc67adc28aef807e6b44340ea70202aab197fb06b20ea165de8"}, + {file = "cyclonedx_python_lib-6.3.0.tar.gz", hash = "sha256:82f2489de3c0cadad5af1ad7fa6b6a185f985746370245d38769699c734533c6"}, ] [package.dependencies] license-expression = ">=30,<31" packageurl-python = ">=0.11" -py-serializable = ">=0.15,<0.16" +py-serializable = ">=0.16,<0.18" sortedcontainers = ">=2.4.0,<3.0.0" [package.extras] json-validation = ["jsonschema[format] (>=4.18,<5.0)"] -validation = ["jsonschema[format] (>=4.18,<5.0)", "lxml (>=4,<5)"] -xml-validation = ["lxml (>=4,<5)"] +validation = ["jsonschema[format] (>=4.18,<5.0)", "lxml (>=4,<6)"] +xml-validation = ["lxml (>=4,<6)"] [[package]] name = "decorator" @@ -761,19 +761,19 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "flake8" -version = "6.1.0" +version = "7.0.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" files = [ - {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, - {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, + {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, + {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, ] [package.dependencies] mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.11.0,<2.12.0" -pyflakes = ">=3.1.0,<3.2.0" +pyflakes = ">=3.2.0,<3.3.0" [[package]] name = "flake8-aaa" @@ -956,17 +956,17 @@ flake8 = ">3.0.0" [[package]] name = "flake8-noqa" -version = "1.3.2" +version = "1.4.0" description = "Flake8 noqa comment validation" optional = false python-versions = ">=3.7" files = [ - {file = "flake8-noqa-1.3.2.tar.gz", hash = "sha256:b12ddf7b02dedabaca0f807cb436ea7992cc0106cb6fa41e997ad45a0a3bf754"}, - {file = "flake8_noqa-1.3.2-py3-none-any.whl", hash = "sha256:a2c139c4cc223f268fb262cd32a46fa72f509225d038058baa87c0ff8ac4d348"}, + {file = "flake8-noqa-1.4.0.tar.gz", hash = "sha256:771765ab27d1efd157528379acd15131147f9ae578a72d17fb432ca197881243"}, + {file = "flake8_noqa-1.4.0-py3-none-any.whl", hash = "sha256:4465e16a19be433980f6f563d05540e2e54797eb11facb9feb50fed60624dc45"}, ] [package.dependencies] -flake8 = ">=3.8.0,<7.0" +flake8 = ">=3.8.0,<8.0" typing-extensions = ">=3.7.4.2" [package.extras] @@ -1410,13 +1410,13 @@ files = [ [[package]] name = "ipython" -version = "8.19.0" +version = "8.20.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.19.0-py3-none-any.whl", hash = "sha256:2f55d59370f59d0d2b2212109fe0e6035cfea436b1c0e6150ad2244746272ec5"}, - {file = "ipython-8.19.0.tar.gz", hash = "sha256:ac4da4ecf0042fb4e0ce57c60430c2db3c719fa8bdf92f8631d6bd8a5785d1f0"}, + {file = "ipython-8.20.0-py3-none-any.whl", hash = "sha256:bc9716aad6f29f36c449e30821c9dd0c1c1a7b59ddcc26931685b87b4c569619"}, + {file = "ipython-8.20.0.tar.gz", hash = "sha256:2f21bd3fc1d51550c89ee3944ae04bbc7bc79e129ea0937da6e6c68bfdbf117a"}, ] [package.dependencies] @@ -2089,18 +2089,18 @@ pip = "*" [[package]] name = "pip-audit" -version = "2.6.2" +version = "2.6.3" description = "A tool for scanning Python environments for known vulnerabilities" optional = false python-versions = ">=3.8" files = [ - {file = "pip_audit-2.6.2-py3-none-any.whl", hash = "sha256:ac3a4b6e977ef2c574aa8d19a5d71d12201bdb65bba2d67d9df49f53f0be5e7d"}, - {file = "pip_audit-2.6.2.tar.gz", hash = "sha256:0bbd023a199a104b29f949f063a872d41113b5a9048285666820fa35a76a7794"}, + {file = "pip_audit-2.6.3-py3-none-any.whl", hash = "sha256:216983210db4a15393f9e80e4d24a805f5767e4c8e0c31fc70c336acc629613b"}, + {file = "pip_audit-2.6.3.tar.gz", hash = "sha256:bd796066f69684b2f4fc2c2b6d222589e23190db0bbde069cea5c2b0be2cc57d"}, ] [package.dependencies] CacheControl = {version = ">=0.13.0", extras = ["filecache"]} -cyclonedx-python-lib = ">=4,<6" +cyclonedx-python-lib = ">=5,<7" html5lib = ">=1.1" packaging = ">=23.0.0" pip-api = ">=0.0.28" @@ -2112,7 +2112,7 @@ toml = ">=0.10" [package.extras] dev = ["build", "bump (>=1.3.2)", "pip-audit[doc,lint,test]"] doc = ["pdoc"] -lint = ["interrogate", "mypy", "ruff (<0.1.9)", "types-html5lib", "types-requests", "types-toml"] +lint = ["interrogate", "mypy", "ruff (<0.1.12)", "types-html5lib", "types-requests", "types-toml"] test = ["coverage[toml] (>=7.0,!=7.3.3,<8.0)", "pretend", "pytest", "pytest-cov"] [[package]] @@ -2216,13 +2216,13 @@ tests = ["pytest"] [[package]] name = "py-serializable" -version = "0.15.0" +version = "0.17.1" description = "Library for serializing and deserializing Python Objects to and from JSON and XML." optional = false python-versions = ">=3.7,<4.0" files = [ - {file = "py-serializable-0.15.0.tar.gz", hash = "sha256:8fc41457d8ee5f5c5a12f41fd87bf1a4f2ecf9da39fee92059b728e78f320771"}, - {file = "py_serializable-0.15.0-py3-none-any.whl", hash = "sha256:d3f1201b33420c481aa83f7860c7bf2c2f036ba3ea82b6e15a96696457c36cd2"}, + {file = "py-serializable-0.17.1.tar.gz", hash = "sha256:875bb9c01df77f563dfcd1e75bb4244b5596083d3aad4ccd3fb63e1f5a9d3e5f"}, + {file = "py_serializable-0.17.1-py3-none-any.whl", hash = "sha256:389c2254d912bec3a44acdac667c947d73c59325050d5ae66386e1ed7108a45a"}, ] [package.dependencies] @@ -2407,13 +2407,13 @@ resolved_reference = "996cec42e9621701edb83354232b2c0ca0121560" [[package]] name = "pyflakes" -version = "3.1.0" +version = "3.2.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" files = [ - {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, - {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, ] [[package]] @@ -3732,4 +3732,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "3a78cb3473202950a11ebbe28e5662f6a1a57508a0e2703761c3c448744b0bed" +content-hash = "79650f1ee926621124c6b8cc3e3ddbf6c438ae15dee98f9bc9e1fddef07a8a70" diff --git a/pyproject.toml b/pyproject.toml index 33503ff..3370304 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,11 @@ [tool.poetry] name = "chat_gpt_bot" -version = "1.4.1" +version = "1.5.0" description = "Bot to integrated with Chat gpt" authors = ["Dmitry Afanasyev "] [build-system] -requires = ["poetry-core>=1.7.0"] +requires = ["poetry-core>=1.7.1"] build-backend = "poetry.core.masonry.api" [tool.poetry.dependencies] @@ -84,7 +84,7 @@ autoflake = "^2.2" flake8-aaa = "^0.17.0" flake8-variables-names = "^0.0.6" flake8-deprecated = "^2.2.1" -flake8-noqa = "^1.3.2" +flake8-noqa = "^1.4" flake8-annotations-complexity = "^0.0.8" flake8-useless-assert = "^0.4.4" flake8-newspaper-style = "^0.4.3"