add tests

This commit is contained in:
Dmitry Afanasyev 2022-08-14 01:01:01 +03:00
parent bf2e7c626f
commit faae3f7846
9 changed files with 728 additions and 15 deletions

75
.github/workflows/poetry-test.yml vendored Normal file
View File

@ -0,0 +1,75 @@
name: test
on:
push:
branches-ignore:
- test
tags-ignore:
- "*"
pull_request:
branches:
- 'release/**'
jobs:
build:
runs-on: ubuntu-latest
steps:
#----------------------------------------------
# check-out repo and set-up python
#----------------------------------------------
- name: Check out repository
uses: actions/checkout@v2
- name: Set up python
id: setup-python
uses: actions/setup-python@v2
with:
python-version: '3.10'
#----------------------------------------------
# ----- install & configure poetry -----
#----------------------------------------------
- name: Install poetry
env: # Keep in sync with `POETRY_VERSION` in `Dockerfile`
POETRY_VERSION: "1.1.13"
run: |
curl -sSL "https://install.python-poetry.org" | python -
# Adding `poetry` to `$PATH`:
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Set up cache
uses: actions/cache@v3
with:
path: .venv
key: venv-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
#----------------------------------------------
# load cached venv if cache exists
#----------------------------------------------
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v2
with:
path: .venv
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
#----------------------------------------------
# install dependencies if cache does not exist
#----------------------------------------------
- name: Install dependencies
run: |
poetry config virtualenvs.in-project true
poetry install
poetry run pip install -U pip
#----------------------------------------------
# run test suite
#----------------------------------------------
- name: Run tests
run: |
source .venv/bin/activate
poetry run pytest -vv --exitfirst
- name: Coverage report
run: |
poetry run coverage run -m pytest
poetry run coverage report
- name: Extended checks
run: |
poetry run poetry check
poetry run pip check
poetry run safety check --full-report

View File

@ -44,7 +44,7 @@ def configure_firefox_driver(private_window: bool = False) -> WebDriver:
return firefox_driver return firefox_driver
def parse_site(driver: WebDriver, url: str, message: str) -> str: async def parse_site(driver: WebDriver, url: str, message: str) -> str:
driver.get(url) driver.get(url)
time.sleep(4) time.sleep(4)
elements = driver.find_elements( elements = driver.find_elements(

0
app/tests/__init__.py Normal file
View File

63
app/tests/conftest.py Normal file
View File

@ -0,0 +1,63 @@
import asyncio
from typing import Any
import aresponses
import pytest
from aiogram import Bot
BOT_ID = 123456789
TOKEN = f'{BOT_ID}:AABBCCDDEEFFaabbccddeeff-1234567890'
class FakeTelegram(aresponses.ResponsesMockServer):
def __init__(
self, message_data: dict[str, Any], bot: Bot = None, **kwargs: Any
) -> None:
super().__init__(**kwargs)
self._body, self._headers = self.parse_data(message_data)
if isinstance(bot, Bot):
Bot.set_current(bot)
async def __aenter__(self) -> None:
await super().__aenter__()
_response = self.Response(
text=self._body, headers=self._headers, status=200, reason='OK'
)
self.add(self.ANY, response=_response)
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
if hasattr(self, 'monkeypatch'):
self.monkeypatch.undo()
await super().__aexit__(exc_type, exc_val, exc_tb)
@staticmethod
def parse_data(message_data: dict[str, Any]) -> tuple[str, dict[str, str]]:
from aiogram.utils import json
from aiogram.utils.payload import _normalize
_body = '{"ok":true,"result":' + json.dumps(_normalize(message_data)) + '}'
_headers = {
'Server': 'nginx/1.12.2',
'Date': 'Tue, 03 Apr 2018 16:59:54 GMT',
'Content-Type': 'application/json',
'Content-Length': str(len(_body)),
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Expose-Headers': 'Content-Length,Content-Type,Date,Server,Connection',
'Strict-Transport-Security': 'max-age=31536000; includeSubdomains',
}
return _body, _headers
@pytest.fixture(name='bot')
async def bot_fixture() -> Bot:
"""Bot fixture."""
bot = Bot(TOKEN)
yield bot
session = await bot.get_session()
if session and not session.closed:
await session.close()
await asyncio.sleep(0.2)

535
app/tests/dataset.py Normal file
View File

@ -0,0 +1,535 @@
""""
Dict data set for Telegram message types
"""
USER = {
"id": 12345678,
"is_bot": False,
"first_name": "FirstName",
"last_name": "LastName",
"username": "username",
"language_code": "ru",
}
CHAT = {
"id": 12345678,
"first_name": "FirstName",
"last_name": "LastName",
"username": "username",
"type": "private",
}
CHAT_PHOTO = {
"small_file_id": "small_file_id",
"small_file_unique_id": "small_file_unique_id",
"big_file_id": "big_file_id",
"big_file_unique_id": "big_file_unique_id",
}
PHOTO = {
"file_id": "AgADBAADFak0G88YZAf8OAug7bHyS9x2ZxkABHVfpJywcloRAAGAAQABAg",
"file_size": 1101,
"width": 90,
"height": 51,
}
AUDIO = {
"duration": 236,
"mime_type": "audio/mpeg3",
"title": "The Best Song",
"performer": "The Best Singer",
"file_id": "CQADAgADbQEAAsnrIUpNoRRNsH7_hAI",
"file_size": 9507774,
}
BOT_COMMAND = {
"command": "start",
"description": "Start bot",
}
CHAT_MEMBER = {
"user": USER,
"status": "administrator",
"can_be_edited": False,
"can_manage_chat": True,
"can_change_info": True,
"can_delete_messages": True,
"can_invite_users": True,
"can_restrict_members": True,
"can_pin_messages": True,
"can_promote_members": False,
"can_manage_voice_chats": True,
"is_anonymous": False,
}
CHAT_MEMBER_OWNER = {
"user": USER,
"status": "creator",
"is_anonymous": False,
}
CONTACT = {
"phone_number": "88005553535",
"first_name": "John",
"last_name": "Smith",
}
DICE = {"value": 6}
DOCUMENT = {
"file_name": "test.docx",
"mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"file_id": "BQADAgADpgADy_JxS66XQTBRHFleAg",
"file_size": 21331,
}
ANIMATION = {
"file_name": "a9b0e0ca537aa344338f80978f0896b7.gif.mp4",
"mime_type": "video/mp4",
"thumb": PHOTO,
"file_id": "CgADBAAD4DUAAoceZAe2WiE9y0crrAI",
"file_size": 65837,
}
ENTITY_BOLD = {
"offset": 5,
"length": 2,
"type": "bold",
}
ENTITY_ITALIC = {
"offset": 8,
"length": 1,
"type": "italic",
}
ENTITY_LINK = {
"offset": 10,
"length": 6,
"type": "text_link",
"url": "http://google.com/",
}
ENTITY_CODE = {
"offset": 17,
"length": 7,
"type": "code",
}
ENTITY_PRE = {
"offset": 30,
"length": 4,
"type": "pre",
}
ENTITY_MENTION = {
"offset": 47,
"length": 9,
"type": "mention",
}
GAME = {
"title": "Karate Kido",
"description": "No trees were harmed in the making of this game :)",
"photo": [PHOTO, PHOTO, PHOTO],
"animation": ANIMATION,
}
INVOICE = {
"title": "Working Time Machine",
"description": "Want to visit your great-great-great-grandparents? "
"Make a fortune at the races? "
"Shake hands with Hammurabi and take a stroll in the Hanging Gardens? "
"Order our Working Time Machine today!",
"start_parameter": "time-machine-example",
"currency": "USD",
"total_amount": 6250,
}
LOCATION = {
"latitude": 50.693416,
"longitude": 30.624605,
}
VENUE = {
"location": LOCATION,
"title": "Venue Name",
"address": "Venue Address",
"foursquare_id": "4e6f2cec483bad563d150f98",
}
SHIPPING_ADDRESS = {
"country_code": "US",
"state": "State",
"city": "DefaultCity",
"street_line1": "Central",
"street_line2": "Middle",
"post_code": "424242",
}
STICKER = {
"width": 512,
"height": 512,
"emoji": "🛠",
"set_name": "StickerSet",
"thumb": {
"file_id": "AAbbCCddEEffGGhh1234567890",
"file_size": 1234,
"width": 128,
"height": 128,
},
"file_id": "AAbbCCddEEffGGhh1234567890",
"file_size": 12345,
}
SUCCESSFUL_PAYMENT = {
"currency": "USD",
"total_amount": 6250,
"invoice_payload": "HAPPY FRIDAYS COUPON",
"telegram_payment_charge_id": "_",
"provider_payment_charge_id": "12345678901234_test",
}
VIDEO = {
"duration": 52,
"width": 853,
"height": 480,
"mime_type": "video/quicktime",
"thumb": PHOTO,
"file_id": "BAADAgpAADdawy_JxS72kRvV3cortAg",
"file_size": 10099782,
}
VIDEO_NOTE = {
"duration": 4,
"length": 240,
"thumb": PHOTO,
"file_id": "AbCdEfGhIjKlMnOpQrStUvWxYz",
"file_size": 186562,
}
VOICE = {
"duration": 1,
"mime_type": "audio/ogg",
"file_id": "AwADawAgADADy_JxS2gopIVIIxlhAg",
"file_size": 4321,
}
CALLBACK_QUERY = {} # type: ignore
CHANNEL_POST = {} # type: ignore
CHOSEN_INLINE_RESULT = {} # type: ignore
EDITED_CHANNEL_POST = {} # type: ignore
EDITED_MESSAGE = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508825372,
"edit_date": 1508825379,
"text": "hi there (edited)",
}
FORWARDED_MESSAGE = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1522828529,
"forward_from_chat": CHAT,
"forward_from_message_id": 123,
"forward_date": 1522749037,
"text": "Forwarded text with entities from public channel ",
"entities": [
ENTITY_BOLD,
ENTITY_CODE,
ENTITY_ITALIC,
ENTITY_LINK,
ENTITY_LINK,
ENTITY_MENTION,
ENTITY_PRE,
],
}
INLINE_QUERY = {} # type: ignore
MESSAGE = {
"message_id": 11223,
"from": USER,
"chat": CHAT,
"date": 1508709711,
"text": "Hi, world!",
}
MESSAGE_WITH_AUDIO = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508739776,
"audio": AUDIO,
"caption": "This is my favourite song",
}
MESSAGE_WITH_AUTHOR_SIGNATURE = {} # type: ignore
MESSAGE_WITH_CHANNEL_CHAT_CREATED = {} # type: ignore
MESSAGE_WITH_CONTACT = {
"message_id": 56006,
"from": USER,
"chat": CHAT,
"date": 1522850298,
"contact": CONTACT,
}
MESSAGE_WITH_DELETE_CHAT_PHOTO = {} # type: ignore
MESSAGE_WITH_DICE = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508768012,
"dice": DICE,
}
MESSAGE_WITH_DOCUMENT = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508768012,
"document": DOCUMENT,
"caption": "Read my document",
}
MESSAGE_WITH_EDIT_DATE = {} # type: ignore
MESSAGE_WITH_ENTITIES = {} # type: ignore
MESSAGE_WITH_GAME = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508824810,
"game": GAME,
}
MESSAGE_WITH_GROUP_CHAT_CREATED = {} # type: ignore
MESSAGE_WITH_INVOICE = {
"message_id": 9772,
"from": USER,
"chat": CHAT,
"date": 1508761719,
"invoice": INVOICE,
}
MESSAGE_WITH_LEFT_CHAT_MEMBER = {} # type: ignore
MESSAGE_WITH_LOCATION = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508755473,
"location": LOCATION,
}
MESSAGE_WITH_MIGRATE_TO_CHAT_ID = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1526943253,
"migrate_to_chat_id": -1234567890987,
}
MESSAGE_WITH_MIGRATE_FROM_CHAT_ID = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1526943253,
"migrate_from_chat_id": -123456789,
}
MESSAGE_WITH_NEW_CHAT_MEMBERS = {} # type: ignore
MESSAGE_WITH_NEW_CHAT_PHOTO = {} # type: ignore
MESSAGE_WITH_NEW_CHAT_TITLE = {} # type: ignore
MESSAGE_WITH_PHOTO = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508825154,
"photo": [PHOTO, PHOTO, PHOTO, PHOTO],
"caption": "photo description",
}
MESSAGE_WITH_MEDIA_GROUP = {
"message_id": 55966,
"from": USER,
"chat": CHAT,
"date": 1522843665,
"media_group_id": "12182749320567362",
"photo": [PHOTO, PHOTO, PHOTO, PHOTO],
}
MESSAGE_WITH_PINNED_MESSAGE = {} # type: ignore
MESSAGE_WITH_REPLY_TO_MESSAGE = {} # type: ignore
MESSAGE_WITH_STICKER = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508771450,
"sticker": STICKER,
}
MESSAGE_WITH_SUCCESSFUL_PAYMENT = {
"message_id": 9768,
"from": USER,
"chat": CHAT,
"date": 1508761169,
"successful_payment": SUCCESSFUL_PAYMENT,
}
MESSAGE_WITH_SUPERGROUP_CHAT_CREATED = {} # type: ignore
MESSAGE_WITH_VENUE = {
"message_id": 56004,
"from": USER,
"chat": CHAT,
"date": 1522849819,
"location": LOCATION,
"venue": VENUE,
}
MESSAGE_WITH_VIDEO = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508756494,
"video": VIDEO,
"caption": "description",
}
MESSAGE_WITH_VIDEO_NOTE = {
"message_id": 55934,
"from": USER,
"chat": CHAT,
"date": 1522835890,
"video_note": VIDEO_NOTE,
}
MESSAGE_WITH_VOICE = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508768403,
"voice": VOICE,
}
CHANNEL = {
"type": "channel",
"username": "best_channel_ever",
"id": -1001065170817,
}
MESSAGE_FROM_CHANNEL = {
"message_id": 123432,
"from": None,
"chat": CHANNEL,
"date": 1508768405,
"text": "Hi, world!",
}
PRE_CHECKOUT_QUERY = {
"id": "262181558630368727",
"from": USER,
"currency": "USD",
"total_amount": 6250,
"invoice_payload": "HAPPY FRIDAYS COUPON",
}
REPLY_MESSAGE = {
"message_id": 12345,
"from": USER,
"chat": CHAT,
"date": 1508751866,
"reply_to_message": MESSAGE,
"text": "Reply to quoted message",
}
SHIPPING_QUERY = {
"id": "262181558684397422",
"from": USER,
"invoice_payload": "HAPPY FRIDAYS COUPON",
"shipping_address": SHIPPING_ADDRESS,
}
USER_PROFILE_PHOTOS = {
"total_count": 1,
"photos": [
[PHOTO, PHOTO, PHOTO],
],
}
FILE = {
"file_id": "XXXYYYZZZ",
"file_size": 5254,
"file_path": "voice/file_8",
}
INVITE_LINK = 'https://t.me/joinchat/AbCdEfjKILDADwdd123'
UPDATE = {
"update_id": 123456789,
"message": MESSAGE,
}
WEBHOOK_INFO = {
"url": "",
"has_custom_certificate": False,
"pending_update_count": 0,
}
REPLY_KEYBOARD_MARKUP = {
"keyboard": [[{"text": "something here"}]],
"resize_keyboard": True,
}
CHAT_PERMISSIONS = {
"can_send_messages": True,
"can_send_media_messages": True,
"can_send_polls": True,
"can_send_other_messages": True,
"can_add_web_page_previews": True,
"can_change_info": True,
"can_invite_users": True,
"can_pin_messages": True,
}
CHAT_LOCATION = {
"location": LOCATION,
"address": "address",
}
FULL_CHAT = {
**CHAT,
"photo": CHAT_PHOTO,
"bio": "bio",
"has_private_forwards": False,
"description": "description",
"invite_link": "invite_link",
"pinned_message": MESSAGE,
"permissions": CHAT_PERMISSIONS,
"slow_mode_delay": 10,
"message_auto_delete_time": 60,
"has_protected_content": True,
"sticker_set_name": "sticker_set_name",
"can_set_sticker_set": True,
"linked_chat_id": -1234567890,
"location": CHAT_LOCATION,
}

View File

@ -0,0 +1,17 @@
import pytest
from aiogram import Bot, types
from app.tests.conftest import FakeTelegram
from app.tests.dataset import USER
pytestmark = [
pytest.mark.asyncio,
]
async def test_parse_site(bot: Bot) -> None:
user = types.User(**USER)
async with FakeTelegram(message_data=USER):
result = await bot.me
assert result == user

40
poetry.lock generated
View File

@ -1,6 +1,6 @@
[[package]] [[package]]
name = "aiogram" name = "aiogram"
version = "2.21" version = "2.22"
description = "Is a pretty simple and fully asynchronous framework for Telegram Bot API" description = "Is a pretty simple and fully asynchronous framework for Telegram Bot API"
category = "main" category = "main"
optional = false optional = false
@ -12,8 +12,8 @@ Babel = ">=2.9.1,<2.10.0"
certifi = ">=2021.10.8" certifi = ">=2021.10.8"
[package.extras] [package.extras]
fast = ["uvloop (>=0.16.0,<0.17.0)", "ujson (>=1.35)"]
proxy = ["aiohttp-socks (>=0.5.3,<0.6.0)"] proxy = ["aiohttp-socks (>=0.5.3,<0.6.0)"]
fast = ["ujson (>=1.35)", "uvloop (>=0.16.0,<0.17.0)"]
[[package]] [[package]]
name = "aiohttp" name = "aiohttp"
@ -97,6 +97,18 @@ tornado = ["tornado (>=4.3)"]
twisted = ["twisted"] twisted = ["twisted"]
zookeeper = ["kazoo"] zookeeper = ["kazoo"]
[[package]]
name = "aresponses"
version = "2.1.6"
description = "Asyncio response mocking. Similar to the responses library used for 'requests'"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
aiohttp = ">=3.1.0,<4.0.0"
pytest-asyncio = "*"
[[package]] [[package]]
name = "astor" name = "astor"
version = "0.8.1" version = "0.8.1"
@ -375,7 +387,7 @@ python-versions = "*"
[[package]] [[package]]
name = "executing" name = "executing"
version = "0.9.1" version = "0.10.0"
description = "Get the currently executing AST node of a frame, and other information" description = "Get the currently executing AST node of a frame, and other information"
category = "dev" category = "dev"
optional = false optional = false
@ -1389,7 +1401,7 @@ typing-extensions = ">=3.7.4"
[[package]] [[package]]
name = "stack-data" name = "stack-data"
version = "0.3.0" version = "0.4.0"
description = "Extract data from python stack frames and tracebacks for informative displays" description = "Extract data from python stack frames and tracebacks for informative displays"
category = "dev" category = "dev"
optional = false optional = false
@ -1401,7 +1413,7 @@ executing = "*"
pure-eval = "*" pure-eval = "*"
[package.extras] [package.extras]
tests = ["pytest", "typeguard", "pygments", "littleutils", "cython"] tests = ["cython", "littleutils", "pygments", "typeguard", "pytest"]
[[package]] [[package]]
name = "stevedore" name = "stevedore"
@ -1645,12 +1657,12 @@ multidict = ">=4.0"
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "5f54515db5c6ab1feb3c7fd62f3981ce3f217c2082e7da3b1554267dc341c338" content-hash = "429b7926e38d696263b3886755fbb33c3ac01faae3d2f124f7d5d38f6b20361e"
[metadata.files] [metadata.files]
aiogram = [ aiogram = [
{file = "aiogram-2.21-py3-none-any.whl", hash = "sha256:33ee61db550f6fc455e2d74d8911af31108e3c398eda03c2f91b0a7cb32a97d9"}, {file = "aiogram-2.22-py3-none-any.whl", hash = "sha256:af5eda881f72d9ad378d93e7c084c11daf6d20834a1799eb7a656b516420b734"},
{file = "aiogram-2.21.tar.gz", hash = "sha256:390ac56a629cd0d151d544e3b87d539ee49f734ccc7a1a7e375c33f436e556e0"}, {file = "aiogram-2.22.tar.gz", hash = "sha256:92bef502b2f14b58fef2b534bc90319e0789fcfbd63e8d91c719236f1f33a3f7"},
] ]
aiohttp = [ aiohttp = [
{file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"}, {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"},
@ -1742,6 +1754,10 @@ apscheduler = [
{file = "APScheduler-3.9.1-py2.py3-none-any.whl", hash = "sha256:ddc25a0ddd899de44d7f451f4375fb971887e65af51e41e5dcf681f59b8b2c9a"}, {file = "APScheduler-3.9.1-py2.py3-none-any.whl", hash = "sha256:ddc25a0ddd899de44d7f451f4375fb971887e65af51e41e5dcf681f59b8b2c9a"},
{file = "APScheduler-3.9.1.tar.gz", hash = "sha256:65e6574b6395498d371d045f2a8a7e4f7d50c6ad21ef7313d15b1c7cf20df1e3"}, {file = "APScheduler-3.9.1.tar.gz", hash = "sha256:65e6574b6395498d371d045f2a8a7e4f7d50c6ad21ef7313d15b1c7cf20df1e3"},
] ]
aresponses = [
{file = "aresponses-2.1.6-py3-none-any.whl", hash = "sha256:06525f6911063f0f8d370cbc96bd273e6cddc89c7b5163ddf91e0c8abf148a32"},
{file = "aresponses-2.1.6.tar.gz", hash = "sha256:231dfa0756e39ca9f1e82212038f98e773d1ed9c0993caf2667e25ba535697ca"},
]
astor = [ astor = [
{file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"}, {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"},
{file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"}, {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"},
@ -1978,8 +1994,8 @@ eradicate = [
{file = "eradicate-2.1.0.tar.gz", hash = "sha256:aac7384ab25b1bf21c4c012de9b4bf8398945a14c98c911545b2ea50ab558014"}, {file = "eradicate-2.1.0.tar.gz", hash = "sha256:aac7384ab25b1bf21c4c012de9b4bf8398945a14c98c911545b2ea50ab558014"},
] ]
executing = [ executing = [
{file = "executing-0.9.1-py2.py3-none-any.whl", hash = "sha256:4ce4d6082d99361c0231fc31ac1a0f56979363cc6819de0b1410784f99e49105"}, {file = "executing-0.10.0-py2.py3-none-any.whl", hash = "sha256:9c745f80cda11eb22b62cbecf21156491a794eb56ab06f9d286a44e62822b24e"},
{file = "executing-0.9.1.tar.gz", hash = "sha256:ea278e2cf90cbbacd24f1080dd1f0ac25b71b2e21f50ab439b7ba45dd3195587"}, {file = "executing-0.10.0.tar.gz", hash = "sha256:d1cd87c2e371e9966261410c5b3769d6df2f9e4a79a83eebd2662dd3388f9833"},
] ]
filelock = [ filelock = [
{file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"},
@ -2566,8 +2582,8 @@ sqlalchemy2-stubs = [
{file = "sqlalchemy2_stubs-0.0.2a25-py3-none-any.whl", hash = "sha256:9104894cee3159906079c4a31c2a66fbedfc72a381c51dfd1d8ebae8ffd7f2ca"}, {file = "sqlalchemy2_stubs-0.0.2a25-py3-none-any.whl", hash = "sha256:9104894cee3159906079c4a31c2a66fbedfc72a381c51dfd1d8ebae8ffd7f2ca"},
] ]
stack-data = [ stack-data = [
{file = "stack_data-0.3.0-py3-none-any.whl", hash = "sha256:aa1d52d14d09c7a9a12bb740e6bdfffe0f5e8f4f9218d85e7c73a8c37f7ae38d"}, {file = "stack_data-0.4.0-py3-none-any.whl", hash = "sha256:b94fed36d725cfabc6d09ed5886913e35eed9009766a1af1d5941b9da3a94aaa"},
{file = "stack_data-0.3.0.tar.gz", hash = "sha256:77bec1402dcd0987e9022326473fdbcc767304892a533ed8c29888dacb7dddbc"}, {file = "stack_data-0.4.0.tar.gz", hash = "sha256:a90ae7e260f7d15aefeceb46f0a028d4ccb9eb8856475c53e341945342d41ea7"},
] ]
stevedore = [ stevedore = [
{file = "stevedore-4.0.0-py3-none-any.whl", hash = "sha256:87e4d27fe96d0d7e4fc24f0cbe3463baae4ec51e81d95fbe60d2474636e0c7d8"}, {file = "stevedore-4.0.0-py3-none-any.whl", hash = "sha256:87e4d27fe96d0d7e4fc24f0cbe3463baae4ec51e81d95fbe60d2474636e0c7d8"},

View File

@ -24,6 +24,7 @@ tomlkit = "^0.7.2"
bandit = "1.7.4" bandit = "1.7.4"
requests = "^2.26.0" requests = "^2.26.0"
SQLAlchemy = {version = "^1.4", extras = ["mypy"]} SQLAlchemy = {version = "^1.4", extras = ["mypy"]}
aresponses = "^2.1"
pyupgrade = "^2.24.0" pyupgrade = "^2.24.0"
isort = "^5.9.3" isort = "^5.9.3"
@ -33,7 +34,7 @@ mypy = "^0.961"
types-PyMySQL = "^1.0.11" types-PyMySQL = "^1.0.11"
types-python-dateutil = "^2.8.4" types-python-dateutil = "^2.8.4"
pytest = "^6.0" pytest = "^6.2.4"
pytest-asyncio = "^0.15.1" pytest-asyncio = "^0.15.1"
pytest-deadfixtures = "^2.2.1" pytest-deadfixtures = "^2.2.1"
pytest-testmon = "^1.1.2" pytest-testmon = "^1.1.2"
@ -68,6 +69,7 @@ multi_line_output = 3
src_paths = ["LenokWinServer",] src_paths = ["LenokWinServer",]
[tool.mypy] [tool.mypy]
python_version = "3.10"
strict = true strict = true
ignore_missing_imports = true ignore_missing_imports = true
allow_subclassing_any = true allow_subclassing_any = true
@ -79,6 +81,7 @@ allow_untyped_decorators = true
warn_return_any = false warn_return_any = false
plugins = ["sqlalchemy.ext.mypy.plugin"] plugins = ["sqlalchemy.ext.mypy.plugin"]
[tool.coverage.run] [tool.coverage.run]
relative_files = true relative_files = true
@ -87,3 +90,6 @@ filterwarnings = [
"error", "error",
"ignore::DeprecationWarning", "ignore::DeprecationWarning",
] ]
[tool.black]
skip-string-normalization = true

View File

@ -23,12 +23,13 @@ ignore =
per-file-ignores = per-file-ignores =
; too complex queries ; too complex queries
*/repositories.py: ECE001 */repositories.py: ECE001
tests/*: TAE001, S101, S311 ./app/tests/*: TAE001, S101, S311
tests/*/factories/*: S5720 tests/*/factories/*: S5720
[mypy] [mypy]
# Mypy configuration: # Mypy configuration:
# https://mypy.readthedocs.io/en/latest/config_file.html # https://mypy.readthedocs.io/en/latest/config_file.html
python_version = 3.10
allow_redefinition = False allow_redefinition = False
check_untyped_defs = True check_untyped_defs = True
disallow_untyped_decorators = False disallow_untyped_decorators = False