diff --git a/.gitignore b/.gitignore index 9efb2e3..04b62fc 100644 --- a/.gitignore +++ b/.gitignore @@ -103,9 +103,6 @@ venv.bak/ # mypy .mypy_cache/ -# VS code -.vscode - .idea .envrc diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..eee7e9f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Django", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}\\manage.py", + "args": [ + "runserver", + "--no-color", + "--noreload" + ], + "django": true, + "justMyCode": true + }, + { + "name": "Python: shell", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}\\manage.py", + "args": [ + "shell" + ], + "django": true, + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e508ca2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "flake8.args": [ + "--max-line-length", "120", + "--extend-ignore", "E203" + ], + "[python]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "charliermarsh.ruff" + } +} \ No newline at end of file diff --git a/django_views_routing_homework/settings.py b/django_views_routing_homework/settings.py index dee3f58..6b4e4ce 100644 --- a/django_views_routing_homework/settings.py +++ b/django_views_routing_homework/settings.py @@ -1,7 +1,7 @@ from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent -SECRET_KEY = 'django-insecure-$$depm8wi$v*0y-)3#1&wlrwg$l%!pqa(x-t#z5gr^x=^vo#eo' +SECRET_KEY = "django-insecure-$$depm8wi$v*0y-)3#1&wlrwg$l%!pqa(x-t#z5gr^x=^vo#eo" DEBUG = True @@ -9,75 +9,75 @@ INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'django_views_routing_homework.urls' +ROOT_URLCONF = "django_views_routing_homework.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [str(BASE_DIR / 'templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [str(BASE_DIR / "templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'django_views_routing_homework.wsgi.application' +WSGI_APPLICATION = "django_views_routing_homework.wsgi.application" DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", } } AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True USE_TZ = True -STATIC_URL = 'static/' -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +STATIC_URL = "static/" +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/django_views_routing_homework/urls.py b/django_views_routing_homework/urls.py index 269591b..5fbce64 100644 --- a/django_views_routing_homework/urls.py +++ b/django_views_routing_homework/urls.py @@ -2,27 +2,52 @@ from django.urls import path from django_views_routing_homework.views.level_1.a_welcome_user import welcome_user_view -from django_views_routing_homework.views.level_1.c_baned_username import is_username_banned_view -from django_views_routing_homework.views.level_2.a_user_info_by_username import get_user_info_by_username_view +from django_views_routing_homework.views.level_1.b_bye_user import bye_user_view +from django_views_routing_homework.views.level_1.c_baned_username import ( + is_username_banned_view, +) +from django_views_routing_homework.views.level_2.a_user_info_by_username import ( + get_user_info_by_username_view, +) from django_views_routing_homework.views.level_2.c_product_type import get_products_view -from django_views_routing_homework.views.level_2.d_authorization import authorization_view, process_authorization_view -from django_views_routing_homework.views.level_3.b_validate_user_data import validate_user_data_view -from django_views_routing_homework.views.level_3.c_github_full_name import fetch_name_from_github_view -from django_views_routing_homework.views.level_3.d_file_generation import generate_file_with_text_view +from django_views_routing_homework.views.level_2.b_greet_user_language import ( + greet_user_in_different_languages_view, +) +from django_views_routing_homework.views.level_2.d_authorization import ( + authorization_view, + process_authorization_view, +) +from django_views_routing_homework.views.level_3.b_validate_user_data import ( + validate_user_data_view, +) +from django_views_routing_homework.views.level_3.c_github_full_name import ( + fetch_name_from_github_view, +) +from django_views_routing_homework.views.level_3.d_file_generation import ( + generate_file_with_text_view, +) from django_views_routing_homework.views.level_3.a_user_ip import show_user_ip_view +from django_views_routing_homework.views.level_1.d_user_info import get_user_info_view +from django_views_routing_homework.views.level_1.e_month_title import ( + get_month_title_view, +) + urlpatterns = [ - path('admin/', admin.site.urls), - path('welcome/', welcome_user_view), - path('banned//', is_username_banned_view), - path('user-info-by-username//', get_user_info_by_username_view), - path('products/', get_products_view), - path('authorization/', authorization_view), - path('process-authorization/', process_authorization_view), - path('me/ip/', show_user_ip_view), - path('user/validate/', validate_user_data_view), - path('user/github//full-name/', fetch_name_from_github_view), - path('text/generate/', generate_file_with_text_view), - # добавлять пути тут + path("admin/", admin.site.urls), + path("welcome/", welcome_user_view), + path("bye/", bye_user_view), + path("banned//", is_username_banned_view), + path("user-info-by-username//", get_user_info_by_username_view), + path("greet///", greet_user_in_different_languages_view), + path("products/", get_products_view), + path("authorization/", authorization_view), + path("process-authorization/", process_authorization_view), + path("me/ip/", show_user_ip_view), + path("user/validate/", validate_user_data_view), + path("user/github//full-name/", fetch_name_from_github_view), + path("text/generate/", generate_file_with_text_view), + path("user-info//", get_user_info_view), + path("month-title//", get_month_title_view), ] diff --git a/django_views_routing_homework/views/level_1/a_welcome_user.py b/django_views_routing_homework/views/level_1/a_welcome_user.py index c45ef16..ea9f0ed 100644 --- a/django_views_routing_homework/views/level_1/a_welcome_user.py +++ b/django_views_routing_homework/views/level_1/a_welcome_user.py @@ -10,5 +10,6 @@ def welcome_user_view(request): - welcome_message = 'Bye, user' + # welcome_message = 'Bye, user' + welcome_message = "hello, user" return HttpResponse(welcome_message) diff --git a/django_views_routing_homework/views/level_1/c_baned_username.py b/django_views_routing_homework/views/level_1/c_baned_username.py index 54bb122..752a569 100644 --- a/django_views_routing_homework/views/level_1/c_baned_username.py +++ b/django_views_routing_homework/views/level_1/c_baned_username.py @@ -10,9 +10,11 @@ 2. Результат проверяйте по ссылке http://127.0.0.1:8000/banned/тут интересующий юзернэйм/, например http://127.0.0.1:8000/banned/any_username/ """ -BANNED_USERNAMES = ['red_dev', 'green_bear', 'monster'] +BANNED_USERNAMES = ["red_dev", "green_bear", "monster"] def is_username_banned_view(request, username: str): - # код писать тут - return HttpResponse('User not banned') + if username in BANNED_USERNAMES: + return HttpResponse("User is banned") + else: + return HttpResponse("User is not banned") diff --git a/django_views_routing_homework/views/level_1/e_month_title.py b/django_views_routing_homework/views/level_1/e_month_title.py index 77b266c..43efed7 100644 --- a/django_views_routing_homework/views/level_1/e_month_title.py +++ b/django_views_routing_homework/views/level_1/e_month_title.py @@ -1,3 +1,4 @@ +import calendar from django.http import HttpResponse, HttpResponseNotFound @@ -13,10 +14,14 @@ """ -def get_month_title_by_number(month_number: int): - pass # код писать тут +def get_month_title_by_number(month_number: int) -> str: + if 1 <= month_number <= 12: + return calendar.month_name[month_number] + return "" def get_month_title_view(request, month_number: int): - # код писать тут - return HttpResponseNotFound('Месяца с таким номером не существует') + month_name = get_month_title_by_number(month_number) + if month_name: + return HttpResponse(month_name) + return HttpResponseNotFound("Месяца с таким номером не существует") diff --git a/django_views_routing_homework/views/level_2/c_product_type.py b/django_views_routing_homework/views/level_2/c_product_type.py index 5d87f69..7076f7b 100644 --- a/django_views_routing_homework/views/level_2/c_product_type.py +++ b/django_views_routing_homework/views/level_2/c_product_type.py @@ -13,31 +13,32 @@ 3. Файл urls.py трогать не нужно, праметры хранятся в объекте request. """ PRODUCTS = [ - {'type': 'electronics', 'title': 'Smartphone', 'price': 500}, - {'type': 'clothing', 'title': 'T-Shirt', 'price': 20}, - {'type': 'books', 'title': 'Python for Beginners', 'price': 25}, - {'type': 'electronics', 'title': 'Television', 'price': 300}, - {'type': 'clothing', 'title': 'Sneakers', 'price': 50}, - {'type': 'groceries', 'title': 'Milk', 'price': 2}, - {'type': 'toys', 'title': 'Lego Set', 'price': 40}, - {'type': 'books', 'title': 'Django for Dummies', 'price': 30}, - {'type': 'electronics', 'title': 'Laptop', 'price': 1000}, - {'type': 'clothing', 'title': 'Jeans', 'price': 40}, - {'type': 'groceries', 'title': 'Eggs', 'price': 3}, - {'type': 'toys', 'title': 'Action Figure', 'price': 15}, - {'type': 'home & garden', 'title': 'Lawn Mower', 'price': 250}, - {'type': 'electronics', 'title': 'Headphones', 'price': 100}, - {'type': 'clothing', 'title': 'Jacket', 'price': 60}, - {'type': 'home & garden', 'title': 'Chair', 'price': 80}, - {'type': 'books', 'title': 'JavaScript: The Good Parts', 'price': 35}, - {'type': 'groceries', 'title': 'Bread', 'price': 1}, - {'type': 'toys', 'title': 'Board Game', 'price': 25}, - {'type': 'home & garden', 'title': 'Table', 'price': 120} + {"type": "electronics", "title": "Smartphone", "price": 500}, + {"type": "clothing", "title": "T-Shirt", "price": 20}, + {"type": "books", "title": "Python for Beginners", "price": 25}, + {"type": "electronics", "title": "Television", "price": 300}, + {"type": "clothing", "title": "Sneakers", "price": 50}, + {"type": "groceries", "title": "Milk", "price": 2}, + {"type": "toys", "title": "Lego Set", "price": 40}, + {"type": "books", "title": "Django for Dummies", "price": 30}, + {"type": "electronics", "title": "Laptop", "price": 1000}, + {"type": "clothing", "title": "Jeans", "price": 40}, + {"type": "groceries", "title": "Eggs", "price": 3}, + {"type": "toys", "title": "Action Figure", "price": 15}, + {"type": "home & garden", "title": "Lawn Mower", "price": 250}, + {"type": "electronics", "title": "Headphones", "price": 100}, + {"type": "clothing", "title": "Jacket", "price": 60}, + {"type": "home & garden", "title": "Chair", "price": 80}, + {"type": "books", "title": "JavaScript: The Good Parts", "price": 35}, + {"type": "groceries", "title": "Bread", "price": 1}, + {"type": "toys", "title": "Board Game", "price": 25}, + {"type": "home & garden", "title": "Table", "price": 120}, ] def get_products_view(request): - products = [] - # код писать тут - + products = PRODUCTS + product_type = request.GET.get("type") + if product_type: + products = [product for product in PRODUCTS if product["type"] == product_type] return JsonResponse(data=products, safe=False) diff --git a/django_views_routing_homework/views/level_2/d_authorization.py b/django_views_routing_homework/views/level_2/d_authorization.py index 4873af5..89219c3 100644 --- a/django_views_routing_homework/views/level_2/d_authorization.py +++ b/django_views_routing_homework/views/level_2/d_authorization.py @@ -22,28 +22,35 @@ 5. На странице вы увидете сообщение об успехе или неудаче. """ USERNAME_TO_PASSWORD_MAPPER = { - 'john_doe': 'password123', - 'sarah_connor': 'terminator2', - 'admin': 'admin_pass', - 'coder2021': 'qwerty', - 'happy_user': '12345', - 'l33t_h4ck3r': 'leetpassword', - 'music_lover': 'beethoven', - 'sports_fan': 'goal2023', - 'travel_guru': 'wanderlust', + "john_doe": "password123", + "sarah_connor": "terminator2", + "admin": "admin_pass", + "coder2021": "qwerty", + "happy_user": "12345", + "l33t_h4ck3r": "leetpassword", + "music_lover": "beethoven", + "sports_fan": "goal2023", + "travel_guru": "wanderlust", } +def authorization(username: str, password: str) -> bool: + return USERNAME_TO_PASSWORD_MAPPER.get(username, "") == password + + @csrf_exempt def process_authorization_view(request): - if request.method == 'POST': + if request.method == "POST": data = json.loads(request.body) - # код писать тут + if authorization( + username=data.get("username", ""), password=data.get("password", "") + ): + return JsonResponse(data={}, status=200) + return JsonResponse(data={}, status=403) else: - return HttpResponseNotAllowed(permitted_methods=['POST']) + return HttpResponseNotAllowed(permitted_methods=["POST"]) # не обращайте внимания на эту вьюху, она нужна лишь для отрисовки страницы авторизации def authorization_view(request): - return render(request, 'authorization.html') - + return render(request, "authorization.html") diff --git a/django_views_routing_homework/views/level_3/a_user_ip.py b/django_views_routing_homework/views/level_3/a_user_ip.py index f1e0ac8..604aea2 100644 --- a/django_views_routing_homework/views/level_3/a_user_ip.py +++ b/django_views_routing_homework/views/level_3/a_user_ip.py @@ -9,4 +9,4 @@ def show_user_ip_view(request: HttpRequest) -> HttpResponse: - pass # код писать тут + return HttpResponse(request.META.get("REMOTE_ADDR")) diff --git a/django_views_routing_homework/views/level_3/b_validate_user_data.py b/django_views_routing_homework/views/level_3/b_validate_user_data.py index d58e56d..7b887cd 100644 --- a/django_views_routing_homework/views/level_3/b_validate_user_data.py +++ b/django_views_routing_homework/views/level_3/b_validate_user_data.py @@ -18,8 +18,64 @@ Когда будете писать код, не забывайте о читаемости, поддерживаемости и модульности. """ -from django.http import HttpResponse, HttpRequest +import re +import json +from django.http import HttpResponse, HttpRequest, HttpResponseBadRequest + + +def check_that_the_length_of_full_name_is_beetwen_5_and_256(full_name): + if isinstance(full_name, str): + return 5 <= len(full_name) <= 256 + return False + + +def check_that_email_similate_email(email): + if isinstance(email, str): + return ( + re.match("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", email) + is not None + ) + return False + + +def check_registered_from_contain_website_or_mobile_app(registered_from): + if isinstance(registered_from, str): + return True if registered_from.lower() in ["website", "mobile_app"] else False + return False + + +def check_age(age): + return isinstance(age, int) + + +def binary_to_dict(binary): + return json.loads(binary.decode("utf-8")) + + +def handle_incoming_data(data): + return ( + data.get("full_name"), + data.get("email", ""), + data.get("registered_from"), + data.get("age"), + ) def validate_user_data_view(request: HttpRequest) -> HttpResponse: - pass # код писать тут + try: + data = binary_to_dict(request.body) + except json.decoder.JSONDecodeError: + return HttpResponseBadRequest() + + full_name, email, registered_from, age = handle_incoming_data(data) + result = all( + [ + full_name + and check_that_the_length_of_full_name_is_beetwen_5_and_256(full_name), + email and check_that_email_similate_email(email), + registered_from + and check_registered_from_contain_website_or_mobile_app(registered_from), + check_age(age) if age else True, + ] + ) + return HttpResponse(json.dumps({"is_valid": result})) diff --git a/django_views_routing_homework/views/level_3/c_github_full_name.py b/django_views_routing_homework/views/level_3/c_github_full_name.py index 1a0bd38..383af21 100644 --- a/django_views_routing_homework/views/level_3/c_github_full_name.py +++ b/django_views_routing_homework/views/level_3/c_github_full_name.py @@ -9,8 +9,16 @@ - если пользователь на Гитхабе есть, но имя у него не указано, верните None вместо имени """ -from django.http import HttpResponse, HttpRequest +import json +import requests +from django.http import HttpResponse, HttpRequest, HttpResponseNotFound -def fetch_name_from_github_view(request: HttpRequest, github_username: str) -> HttpResponse: - pass # код писать тут +def fetch_name_from_github_view( + request: HttpRequest, github_username: str +) -> HttpResponse: + response = requests.get(f"https://api.github.com/users/{github_username}") + if not response.ok: + return HttpResponseNotFound() + name = json.loads(response.text).get("name") + return HttpResponse({"name": name}) diff --git a/django_views_routing_homework/views/level_3/d_file_generation.py b/django_views_routing_homework/views/level_3/d_file_generation.py index 60d8fce..ddc2b49 100644 --- a/django_views_routing_homework/views/level_3/d_file_generation.py +++ b/django_views_routing_homework/views/level_3/d_file_generation.py @@ -14,8 +14,27 @@ скачивать сгенерированный файл. """ -from django.http import HttpResponse, HttpRequest +import csv +import random +import string +from django.http import HttpResponse, HttpRequest, HttpResponseForbidden +from django.views.decorators.http import require_http_methods +def get_random_string(length): + return "".join([random.choice(string.ascii_letters) for _ in range(length)]) + + +@require_http_methods(["GET"]) def generate_file_with_text_view(request: HttpRequest) -> HttpResponse: - pass # код писать тут + length = int(request.GET.get("length", "0")) + if length < 1 or length > 128: + return HttpResponseForbidden() + random_string = get_random_string(length) + response = HttpResponse( + content_type="text/csv", + headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'}, + ) + writer = csv.writer(response) + writer.writerow([random_string]) + return response diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..cd027e3 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,228 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "asgiref" +version = "3.8.1" +description = "ASGI specs, helper code, and adapters" +optional = false +python-versions = ">=3.8" +files = [ + {file = "asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47"}, + {file = "asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"}, +] + +[package.extras] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] + +[[package]] +name = "certifi" +version = "2024.8.30" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "django" +version = "4.2.3" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Django-4.2.3-py3-none-any.whl", hash = "sha256:f7c7852a5ac5a3da5a8d5b35cc6168f31b605971441798dac845f17ca8028039"}, + {file = "Django-4.2.3.tar.gz", hash = "sha256:45a747e1c5b3d6df1b141b1481e193b033fd1fdbda3ff52677dc81afdaacbaed"}, +] + +[package.dependencies] +asgiref = ">=3.6.0,<4" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} + +[package.extras] +argon2 = ["argon2-cffi (>=19.1.0)"] +bcrypt = ["bcrypt"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "sqlparse" +version = "0.5.1" +description = "A non-validating SQL parser." +optional = false +python-versions = ">=3.8" +files = [ + {file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}, + {file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"}, +] + +[package.extras] +dev = ["build", "hatch"] +doc = ["sphinx"] + +[[package]] +name = "tzdata" +version = "2024.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.12" +content-hash = "2766816f5598788c00594682744504fae53f210c6464a1ef02f1a91c65f829b0" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d638f2f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "django-views-challenges" +version = "0.1.0" +description = "" +authors = ["denis sergeevich pekshev "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.12" +django = "4.2.3" +requests = "^2.32.3" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file