commit 9623258bf601faf5a6266ef549620d798366e6b5 Author: ModZero Date: Thu Jan 23 02:58:00 2025 +0000 Initial commit diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100755 index 0000000..fbb8855 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,52 @@ +{ + "name": "Kredens Dev Container", + "build": { + "dockerfile": "../dockerfiles/devcontainer.dockerfile", + "context": ".." + }, + "features": { + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { + "installDockerComposeSwitch": false + }, + "ghcr.io/devcontainers/features/node:1": { + "nodeGypDependencies": true, + "installYarnUsingApt": true, + "version": "lts", + "pnpmVersion": "latest", + "nvmVersion": "latest" + }, + "ghcr.io/va-h/devcontainers-features/uv:1": { + "shellautocompletion": true, + "version": "latest" + } + }, + "onCreateCommand": "${containerWorkspaceFolder}/.devcontainer/onCreate.sh", + "postAttachCommand": "${containerWorkspaceFolder}/.devcontainer/postAttach.sh", + "remoteEnv": { + "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}", + "WORKSPACE_FOLDER": "${containerWorkspaceFolder}", + "UV_LINK_MODE": "copy" + }, + "mounts": [ + { + "type": "volume", + "source": "${devcontainerId}-venv", + "target": "${containerWorkspaceFolder}/.venv" + }, + { + "type": "volume", + "source": "${devcontainerId}-node-modules", + "target": "${containerWorkspaceFolder}/node_modules" + } + ], + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "ms-python.debugpy", + "ms-azuretools.vscode-docker" + ] + } + } +} diff --git a/.devcontainer/onCreate.sh b/.devcontainer/onCreate.sh new file mode 100755 index 0000000..ba35f3b --- /dev/null +++ b/.devcontainer/onCreate.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +sudo apt update -y +sudo apt upgrade -y + +git config --global --add safe.directory ${WORKSPACE_FOLDER} +sudo chown $(id -u):$(id -g) -fR \ + ${WORKSPACE_FOLDER}/.venv \ + ${WORKSPACE_FOLDER}/node_modules + +cd ${WORKSPACE_FOLDER} + +uv python install +uv venv --allow-existing diff --git a/.devcontainer/postAttach.sh b/.devcontainer/postAttach.sh new file mode 100755 index 0000000..961d7b3 --- /dev/null +++ b/.devcontainer/postAttach.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +sudo apt update -y +sudo apt upgrade -y + +cd ${WORKSPACE_FOLDER} + +uv sync --frozen diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b6eaf5f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.git +node_modules +.venv +__pycache__ \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1116386 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.venv +.env +node_modules +__pycache__ diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/README.md b/README.md new file mode 100644 index 0000000..5c750af --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Kredens + +Where I keep my spoons. + +## Development + +Create a .env file: +```sh +DATABASE_PASSWORD=TOTALMESSREPLACE +DATABASE_URL=postgres://postgres:${DATABASE_PASSWORD}@host.docker.internal/kredens +``` + +Then, to start the thing: + +```sh +% docker compose up -d +``` + +The entire thing comes with a dev container that should mostly work. diff --git a/configs/apt/sources.list.d/caddy-stable.list b/configs/apt/sources.list.d/caddy-stable.list new file mode 100755 index 0000000..d9503cb --- /dev/null +++ b/configs/apt/sources.list.d/caddy-stable.list @@ -0,0 +1,9 @@ +# Source: Caddy +# Site: https://github.com/caddyserver/caddy +# Repository: Caddy / stable +# Description: Fast, multi-platform web server with automatic HTTPS + + +deb [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main + +deb-src [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main diff --git a/configs/caddy/Caddyfile b/configs/caddy/Caddyfile new file mode 100644 index 0000000..eb60406 --- /dev/null +++ b/configs/caddy/Caddyfile @@ -0,0 +1,21 @@ +{ + admin 0.0.0.0:2019 +} + +localhost { + redir /mailpit /mailpit/ + handle_path /mailpit/* { + rewrite * /mailpit{path} + reverse_proxy mailpit:8025 + } + + handle { + reverse_proxy backend:8000 { + header_up Host {host} + } + } + + tls internal { + on_demand + } +} diff --git a/configs/keys/caddy.key b/configs/keys/caddy.key new file mode 100755 index 0000000..444c642 --- /dev/null +++ b/configs/keys/caddy.key @@ -0,0 +1,64 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +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 +A5zVwuXbvH6GHaZJVHUrII6w8rjimo5r +=e4lF +-----END PGP PUBLIC KEY BLOCK----- diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7fec22d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,74 @@ +services: + backend: + image: modzero.xyz/kredens/backend + build: + dockerfile: dockerfiles/backend.dockerfile + context: . + pull_policy: build + develop: + watch: + - path: ${LOCAL_WORKSPACE_FOLDER:-.}/kredens + action: sync + target: /app/kredens + - path: ${LOCAL_WORKSPACE_FOLDER:-.}/pyproject.toml + action: rebuild + - path: ${LOCAL_WORKSPACE_FOLDER:-.}/manage.py + action: rebuild + - path: ${LOCAL_WORKSPACE_FOLDER:-.}/uv.lock + action: rebuild + environment: + - DATABASE_URL=postgres://postgres:${DATABASE_PASSWORD:?Database password required}@database/kredens + depends_on: + - database + database: + image: postgres:17 + restart: unless-stopped + shm_size: 128mb + environment: + - POSTGRES_PASSWORD=${DATABASE_PASSWORD:?Database password required} + - POSTGRES_DB=kredens + healthcheck: + test: ["CMD-SHELL", "su -c 'pg_isready -d kredens -h localhost' postgres"] + interval: 30s + timeout: 60s + retries: 5 + start_period: 80s + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + webproxy: + image: caddy + restart: unless-stopped + cap_add: + - NET_ADMIN + volumes: + - ${LOCAL_WORKSPACE_FOLDER:-.}/configs/caddy/:/etc/caddy/ + - caddy_data:/data + - caddy_config:/config + ports: + - "80:80" + - "443:443" + - "443:443/udp" + - "2019:2019" + mailpit: + image: axllent/mailpit + restart: unless-stopped + volumes: + - mailpit_data:/data + environment: + MP_MAX_MESSAGES: 5000 + MP_DATABASE: /data/mailpit.db + MP_SMTP_AUTH_ACCEPT_ANY: 1 + MP_SMTP_AUTH_ALLOW_INSECURE: 1 + MP_WEBROOT: mailpit + +volumes: + caddy_data: + caddy_config: + postgres_data: + mailpit_data: + +networks: + default: + enable_ipv6: true \ No newline at end of file diff --git a/dockerfiles/backend.dockerfile b/dockerfiles/backend.dockerfile new file mode 100644 index 0000000..5193dca --- /dev/null +++ b/dockerfiles/backend.dockerfile @@ -0,0 +1,21 @@ +FROM python:3.12-slim-bookworm + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ +WORKDIR /app + +RUN --mount=type=cache,target=/root/.cache/uv \ + --mount=type=bind,source=uv.lock,target=uv.lock \ + --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + uv sync --frozen --no-install-project + +COPY ./kredens/ /app/kredens +COPY \ + manage.py \ + pyproject.toml \ + uv.lock \ + /app/ +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --frozen + +ENTRYPOINT [ "uv", "run", "python", "./manage.py" ] +CMD [ "runserver", "0.0.0.0:8000"] diff --git a/dockerfiles/devcontainer.dockerfile b/dockerfiles/devcontainer.dockerfile new file mode 100755 index 0000000..d507a6e --- /dev/null +++ b/dockerfiles/devcontainer.dockerfile @@ -0,0 +1,26 @@ +FROM mcr.microsoft.com/devcontainers/base:bookworm + +# Install things I need for Caddy and such + +RUN \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + rm -f \ + /etc/apt/apt.conf.d/docker-clean \ + /etc/apt/apt.conf.d/docker-no-languages \ + && apt-get update -y && apt-get upgrade -y \ + && apt-get install -y --no-install-recommends \ + debian-keyring \ + debian-archive-keyring \ + apt-transport-https \ + gnupg + +RUN --mount=type=bind,target=/tmp/caddy.key,source=./configs/keys/caddy.key \ + gpg -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg --dearmor /tmp/caddy.key +COPY ./configs/apt/sources.list.d/caddy-stable.list /etc/apt/sources.list +RUN \ + --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update -y \ + && apt-get install -y --no-install-recommends \ + caddy \ No newline at end of file diff --git a/kredens/__init__.py b/kredens/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kredens/asgi.py b/kredens/asgi.py new file mode 100644 index 0000000..379e2d5 --- /dev/null +++ b/kredens/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for kredens project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'kredens.settings') + +application = get_asgi_application() diff --git a/kredens/settings.py b/kredens/settings.py new file mode 100644 index 0000000..188a2f8 --- /dev/null +++ b/kredens/settings.py @@ -0,0 +1,125 @@ +""" +Django settings for kredens project. + +Generated by 'django-admin startproject' using Django 5.1.5. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +from pathlib import Path + +import dj_database_url + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-n+yg%(i+kmm6yf=ab5)f1qv)-kzn$*!v&f6(5rtczz52!rer$&" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "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.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", +] + +ROOT_URLCONF = "kredens.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "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 = "kredens.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DATABASES = { + "default": dj_database_url.config( + conn_max_age=600, + conn_health_checks=True, + ), +} + + +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/5.1/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = "static/" + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/kredens/urls.py b/kredens/urls.py new file mode 100644 index 0000000..1f12cca --- /dev/null +++ b/kredens/urls.py @@ -0,0 +1,22 @@ +""" +URL configuration for kredens project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] diff --git a/kredens/wsgi.py b/kredens/wsgi.py new file mode 100644 index 0000000..5ddf168 --- /dev/null +++ b/kredens/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for kredens project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'kredens.settings') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..848ce22 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'kredens.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8b6afe4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,11 @@ +[project] +name = "kredens" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "dj-database-url", + "django", + "psycopg[binary]>=3.2.4", +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..38b006a --- /dev/null +++ b/uv.lock @@ -0,0 +1,117 @@ +version = 1 +requires-python = ">=3.13" + +[[package]] +name = "asgiref" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/38/b3395cc9ad1b56d2ddac9970bc8f4141312dbaec28bc7c218b0dfafd0f42/asgiref-3.8.1.tar.gz", hash = "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590", size = 35186 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/e3/893e8757be2612e6c266d9bb58ad2e3651524b5b40cf56761e985a28b13e/asgiref-3.8.1-py3-none-any.whl", hash = "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", size = 23828 }, +] + +[[package]] +name = "dj-database-url" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/9f/fc9905758256af4f68a55da94ab78a13e7775074edfdcaddd757d4921686/dj_database_url-2.3.0.tar.gz", hash = "sha256:ae52e8e634186b57e5a45e445da5dc407a819c2ceed8a53d1fac004cc5288787", size = 10980 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/91/641a4e5c8903ed59f6cbcce571003bba9c5d2f731759c31db0ba83bb0bdb/dj_database_url-2.3.0-py3-none-any.whl", hash = "sha256:bb0d414ba0ac5cd62773ec7f86f8cc378a9dbb00a80884c2fc08cc570452521e", size = 7793 }, +] + +[[package]] +name = "django" +version = "5.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/17/834e3e08d590dcc27d4cc3c5cd4e2fb757b7a92bab9de8ee402455732952/Django-5.1.5.tar.gz", hash = "sha256:19bbca786df50b9eca23cee79d495facf55c8f5c54c529d9bf1fe7b5ea086af3", size = 10700031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/e6/e92c8c788b83d109f34d933c5e817095d85722719cb4483472abc135f44e/Django-5.1.5-py3-none-any.whl", hash = "sha256:c46eb936111fffe6ec4bc9930035524a8be98ec2f74d8a0ff351226a3e52f459", size = 8276957 }, +] + +[[package]] +name = "kredens" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "dj-database-url" }, + { name = "django" }, + { name = "psycopg", extra = ["binary"] }, +] + +[package.metadata] +requires-dist = [ + { name = "dj-database-url" }, + { name = "django" }, + { name = "psycopg", extras = ["binary"], specifier = ">=3.2.4" }, +] + +[[package]] +name = "psycopg" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/f2/954b1467b3e2ca5945b83b5e320268be1f4df486c3e8ffc90f4e4b707979/psycopg-3.2.4.tar.gz", hash = "sha256:f26f1346d6bf1ef5f5ef1714dd405c67fb365cfd1c6cea07de1792747b167b92", size = 156109 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/49/15114d5f7ee68983f4e1a24d47e75334568960352a07c6f0e796e912685d/psycopg-3.2.4-py3-none-any.whl", hash = "sha256:43665368ccd48180744cab26b74332f46b63b7e06e8ce0775547a3533883d381", size = 198716 }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/e2/f56675aada063762f08559b6969e47e1313f269fc1682c16457c13da8186/psycopg_binary-3.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:81ab801c0d35830c876bf0d1edc8e7dd2f73aa2b04fe24eb812159c0b054d149", size = 3846854 }, + { url = "https://files.pythonhosted.org/packages/7b/8b/8c4a66b2b3db494367df0299535b7d2df78f303334228c517b8d00c411d5/psycopg_binary-3.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c09e02ce1124eb6638b3381df050a8cf88aedfad4522f939945cda49050a990c", size = 3932292 }, + { url = "https://files.pythonhosted.org/packages/84/e8/618d45f77cebce73d75497c95685a0902aea3783386d9335ce486c69e13a/psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a249cdc6a5c2b5088a8677acba66b291e5237524739ab3d27498e1ef189312f5", size = 4493785 }, + { url = "https://files.pythonhosted.org/packages/c4/87/fc30318e6b97e723e017e7dc88d0f721bbfb749de1a6e414e52d4ac54c9a/psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2960ba8a5c0ad75e184f6d8bf76bdf023708999efe75fe4e13445136c1cd206", size = 4304874 }, + { url = "https://files.pythonhosted.org/packages/91/30/1d127e651c21cd77befaf361c7c3b9001bfff51ac38027e8fce598ba0701/psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dae2e50b0d3425c167eebbedc3553f7c811dbc0dbfc737b6877f68a03be7daf", size = 4541296 }, + { url = "https://files.pythonhosted.org/packages/0d/5e/22c824cb38745c1c744cec85d227190727c564afb75960ce0057ca15fd84/psycopg_binary-3.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03bf7ee7e0002c2cce43ecb923ec510358056eb2e44a96afaeb0424518f35206", size = 4255756 }, + { url = "https://files.pythonhosted.org/packages/b3/83/ae8783dec3f7e39df8a4056e4d383926ffec531970c0b415d48d9fd4a2c2/psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5f5c85eeb63b1a8a6b026eef57f5da36ff215ce9a6a3bb8e20a409670d6cfbda", size = 3845918 }, + { url = "https://files.pythonhosted.org/packages/be/f7/fb7bffb0c4c45a5a82fe324e4f7b176075a4c5372e546a038858dd13c7ab/psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8c7b95899d4d6d23c5cc46cb3419e8e6ca68d867509432ee1487042564a1ea55", size = 3315429 }, + { url = "https://files.pythonhosted.org/packages/81/a3/29f4993a239d6a3fb18ef8681d9990c007f5f73bdd2e21f65f07ac55ad6f/psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fa4acea9ca20a567c3872a5afab2084751530bb57b8fb6b52820d5c54e7c8c3b", size = 3399388 }, + { url = "https://files.pythonhosted.org/packages/25/5b/925171cbfa2e3d1ccb7f4c005d0d5db609ba796c1d08a23c42825b09c554/psycopg_binary-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c487f35a1905bb15da927c1fc05f70f3d29f0e21fb4ba21d360a0da9c755f20", size = 3436702 }, + { url = "https://files.pythonhosted.org/packages/b6/47/25b2b85b8fcabf99bfa92b4b0d587894c01576bf0b2bf137c243d1eb1070/psycopg_binary-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:80297c3a9f7b5a6afdb0d8f220661ccd796e5c9128c44b32c41267f7daefd37f", size = 2779196 }, +] + +[[package]] +name = "sqlparse" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/40/edede8dd6977b0d3da179a342c198ed100dd2aba4be081861ee5911e4da4/sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", size = 84999 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[package]] +name = "tzdata" +version = "2025.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/0f/fa4723f22942480be4ca9527bbde8d43f6c3f2fe8412f00e7f5f6746bc8b/tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", size = 194950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/dd/84f10e23edd882c6f968c21c2434fe67bd4a528967067515feca9e611e5e/tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639", size = 346762 }, +]