Merge pull request #76 from markbeep/uv-nix-docker

Use uv and update to python 3.12
This commit is contained in:
Mark
2025-03-21 18:50:26 +01:00
committed by GitHub
12 changed files with 1280 additions and 138 deletions

View File

@@ -25,14 +25,13 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
cache: "pip"
- run: |
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "0.6.9"
- run: uv sync --all-extras --dev
- run: echo "$PWD/.venv/bin" >> $GITHUB_PATH

View File

@@ -8,12 +8,12 @@ COPY package-lock.json package-lock.json
RUN npm install
# Setup python
FROM python:3.11-alpine AS linux-amd64
FROM python:3.12-alpine AS linux-amd64
WORKDIR /app
RUN apk add --no-cache curl gcompat build-base
RUN curl https://github.com/tailwindlabs/tailwindcss/releases/download/v4.0.6/tailwindcss-linux-x64-musl -L -o /bin/tailwindcss
FROM python:3.11-alpine AS linux-arm64
FROM python:3.12-alpine AS linux-arm64
WORKDIR /app
RUN apk add --no-cache curl gcompat build-base
RUN curl https://github.com/tailwindlabs/tailwindcss/releases/download/v4.0.6/tailwindcss-linux-arm64-musl -L -o /bin/tailwindcss
@@ -21,11 +21,11 @@ RUN curl https://github.com/tailwindlabs/tailwindcss/releases/download/v4.0.6/ta
FROM ${TARGETOS}-${TARGETARCH}${TARGETVARIANT}
RUN chmod +x /bin/tailwindcss
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY --from=0 /app/node_modules/ node_modules/
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
COPY uv.lock pyproject.toml /app
RUN uv sync --frozen --no-cache
COPY alembic/ alembic/
COPY alembic.ini alembic.ini
@@ -40,5 +40,5 @@ ENV ABR_APP__PORT=8000
ARG VERSION
ENV ABR_APP__VERSION=$VERSION
CMD alembic upgrade heads && fastapi run --port $ABR_APP__PORT
CMD /app/.venv/bin/alembic upgrade heads && /app/.venv/bin/fastapi run --port $ABR_APP__PORT

View File

@@ -1,6 +1,6 @@
![GitHub Release](https://img.shields.io/github/v/release/markbeep/AudioBookRequest)
[![Discord](https://dcbadge.limes.pink/api/server/https://discord.gg/SsFRXWMg7s)](https://discord.gg/SsFRXWMg7s)
![GitHub Release](https://img.shields.io/github/v/release/markbeep/AudioBookRequest?style=for-the-badge)
![Python Version](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fmarkbeep%2FAudioBookRequest%2Fmain%2Fpyproject.toml&style=for-the-badge&logo=python)
![Discord](https://img.shields.io/discord/1350874252282171522?style=for-the-badge&logo=discord&link=https%3A%2F%2Fdiscord.gg%2FSsFRXWMg7s)
![Header](/media/AudioBookRequestIcon.png)
@@ -163,17 +163,13 @@ Suggestions are always welcome. Do note though that a big goal is to keep this p
## Local Development
Virtual environments help isolate any installed packages to this directory. Project was made with `Python 3.11`. Any python version above 3.9 _should_ work, but if there are any problems use `>= 3.11`.
Virtual environments help isolate any installed packages to this directory. Project was made with `Python 3.12` and uses new generics introduced in 3.12. Older python versions might not work or could have incorrect typing.
For improved dependency management, `uv` is used instead of `pip`.
```sh
python -m venv .venv
source .venv/bin/activate # sh/bash
source .venv/bin/activate.fish # fish
.venv\Scripts\activate.bat # cmd
.venv\Scripts\Activate.ps1 # powershell
pip install -r requirements.txt
# This creates the venv as well as installs all dependencies
uv sync
```
For local development, environment variables can be added to `.env.local` and they'll be used wherever required.
@@ -183,7 +179,7 @@ For local development, environment variables can be added to `.env.local` and th
[Alembic](https://alembic.sqlalchemy.org/en/latest/) is used to create database migrations. Run the following before starting up the application for the first time. It will initialize the directory if non-existant, create the database file as well as execute any required migrations.
```sh
alembic upgrade heads
uv run alembic upgrade heads
```
_In case of any model changes, remember to create migrations using `alembic revision --autogenerate -m "<message>"`._
@@ -195,7 +191,7 @@ Running the application is best done in multiple terminals:
1. Start FastAPI dev mode:
```sh
fastapi dev
uv run fastapi dev
```
Website can be visited at http://localhost:8000.
@@ -204,7 +200,7 @@ Website can be visited at http://localhost:8000.
```sh
npm i
tailwindcss -i styles/globals.css -o static/globals.css --watch
uv run tailwindcss -i styles/globals.css -o static/globals.css --watch
# Alternatively npx can be used to run tailwindcss
npx @tailwindcss/cli@4 -i styles/globals.css -o static/globals.css --watch
```

View File

@@ -1,7 +1,7 @@
import asyncio
import time
from datetime import datetime
from typing import Any, Generic, Literal, Optional, TypeVar
from typing import Any, Literal, Optional
from urllib.parse import urlencode
import pydantic
@@ -62,10 +62,7 @@ class CacheQuery(pydantic.BaseModel, frozen=True):
audible_region: audible_region_type
T = TypeVar("T")
class CacheResult(pydantic.BaseModel, Generic[T], frozen=True):
class CacheResult[T](pydantic.BaseModel, frozen=True):
value: T
timestamp: float

View File

@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod
from typing import Any, Generic, TypeVar
from typing import Any
from aiohttp import ClientSession
from pydantic import BaseModel
@@ -14,10 +14,7 @@ class SessionContainer(BaseModel, arbitrary_types_allowed=True):
client_session: ClientSession
T = TypeVar("T", bound=Configurations)
class AbstractIndexer(ABC, Generic[T]):
class AbstractIndexer[T: Configurations](ABC):
name: str
@abstractmethod

View File

@@ -1,5 +1,5 @@
import logging
from typing import Any, Generic, Optional, TypeVar
from typing import Any, Optional
from pydantic import BaseModel
from sqlmodel import Session
@@ -9,10 +9,7 @@ from app.util.cache import StringConfigCache
logger = logging.getLogger(__name__)
T = TypeVar("T", str, int, bool, float, None)
class IndexerConfiguration(BaseModel, Generic[T]):
class IndexerConfiguration[T: (str, int, bool, float, None)](BaseModel):
display_name: str
description: Optional[str] = None
default: Optional[T] = None

View File

@@ -1,16 +1,13 @@
import time
from abc import ABC
from typing import Generic, Optional, TypeVar, overload
from typing import Optional, overload
from sqlmodel import Session, select
from app.internal.models import Config
T = TypeVar("T")
# TODO: determine if we want to use the DB as well or not
class SimpleCache(Generic[T]):
class SimpleCache[T]:
_cache: dict[tuple[str, ...], tuple[int, T]] = {}
def get(self, source_ttl: int, *query: str) -> Optional[T]:
@@ -29,10 +26,7 @@ class SimpleCache(Generic[T]):
self._cache = {}
L = TypeVar("L", bound=str)
class StringConfigCache(Generic[L], ABC):
class StringConfigCache[L: str](ABC):
_cache: dict[L, str] = {}
@overload

10
flake.lock generated
View File

@@ -2,12 +2,12 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1731676054,
"narHash": "sha256-OZiZ3m8SCMfh3B6bfGC/Bm4x3qc1m2SVEAlkV6iY7Yg=",
"rev": "5e4fbfb6b3de1aa2872b76d49fafc942626e2add",
"revCount": 708622,
"lastModified": 1742422364,
"narHash": "sha256-mNqIplmEohk5jRkqYqG19GA8MbQ/D4gQSK0Mu4LvfRQ=",
"rev": "a84ebe20c6bc2ecbcfb000a50776219f48d134cc",
"revCount": 770807,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.708622%2Brev-5e4fbfb6b3de1aa2872b76d49fafc942626e2add/0193363c-ab27-7bbd-af1d-3e6093ed5e2d/source.tar.gz"
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.770807%2Brev-a84ebe20c6bc2ecbcfb000a50776219f48d134cc/0195b626-8c1d-7fb9-9282-563af3d37ab9/source.tar.gz"
},
"original": {
"type": "tarball",

View File

@@ -3,7 +3,8 @@
inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1.*.tar.gz";
outputs = { self, nixpkgs }:
outputs = { self, nixpkgs, ... }:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
@@ -11,12 +12,12 @@
});
in
{
devShells = forEachSupportedSystem ({ pkgs }: {
default = pkgs.mkShell {
venvDir = ".venv";
packages = with pkgs; [ python311 nodejs_23 sqlite nodePackages.browser-sync ] ++
(with pkgs.python311Packages; [
pip
packages = with pkgs; [ python312 nodejs_23 sqlite nodePackages.browser-sync uv ] ++
(with pkgs.python312Packages; [
venvShellHook
]);
};

View File

@@ -1,11 +1,41 @@
[project]
name = "audiobookrequest"
requires-python = ">= 3.11"
dynamic = ["version"]
name = "AudioBookRequest"
version = "1.3.0"
requires-python = ">= 3.12"
readme = "README.md"
dependencies = [
"aiohttp==3.11.13",
"alembic==1.15.1",
"argon2-cffi==23.1.0",
"argon2-cffi-bindings==21.2.0",
"fastapi==0.115.11",
"fastapi-cli==0.0.7",
"itsdangerous==2.2.0",
"jinja2==3.1.6",
"jinja2-fragments==1.8.0",
"pydantic==2.10.6",
"pydantic-settings==2.8.1",
"pydantic-core==2.27.2",
"pyjwt==2.10.1",
"pytailwindcss==0.2.0",
"sqlmodel==0.0.23",
"terminaltables==3.1.10",
"torrent-parser==0.4.1",
"typer==0.15.2",
"urllib3==2.3.0",
"rapidfuzz>=3.12.2",
"python-multipart>=0.0.20",
]
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.sdist]
include = ["app/*.py", "alembic/"]
[tool.uv]
package = false
[tool.pyright]
include = ["**/*.py"]
@@ -15,3 +45,6 @@ ignore = []
typeCheckingMode = "strict"
reportUnknownParameterType = true
reportMissingParameterType = true
[dependency-groups]
dev = ["black>=25.1.0", "pyright>=1.1.397"]

View File

@@ -1,71 +0,0 @@
aiohappyeyeballs==2.5.0
aiohttp==3.11.13
aiosignal==1.3.2
alembic==1.15.1
annotated-types==0.7.0
anyio==4.8.0
argon2-cffi==23.1.0
argon2-cffi-bindings==21.2.0
attrs==25.1.0
black==25.1.0
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
click==8.1.8
colorclass==2.2.2
dnspython==2.7.0
docopt==0.6.2
email_validator==2.2.0
fastapi==0.115.11
fastapi-cli==0.0.7
frozenlist==1.5.0
greenlet==3.1.1
h11==0.14.0
httpcore==1.0.7
httptools==0.6.4
httpx==0.28.1
idna==3.10
itsdangerous==2.2.0
Jinja2==3.1.6
jinja2_fragments==1.8.0
Mako==1.3.9
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mdurl==0.1.2
multidict==6.1.0
mypy-extensions==1.0.0
nodeenv==1.9.1
packaging==24.2
pathspec==0.12.1
pip-upgrader==1.4.15
platformdirs==4.3.6
propcache==0.3.0
pycparser==2.22
pydantic==2.10.6
pydantic-settings==2.8.1
pydantic_core==2.27.2
Pygments==2.19.1
PyJWT==2.10.1
pyright==1.1.396
pytailwindcss==0.2.0
python-dotenv==1.0.1
python-multipart==0.0.20
PyYAML==6.0.2
RapidFuzz==3.12.2
rich==13.9.4
rich-toolkit==0.13.2
shellingham==1.5.4
sniffio==1.3.1
SQLAlchemy==2.0.38
sqlmodel==0.0.23
starlette==0.46.0
terminaltables==3.1.10
torrent-parser==0.4.1
typer==0.15.2
typing_extensions==4.12.2
urllib3==2.3.0
uvicorn==0.34.0
uvloop==0.21.0
watchfiles==1.0.4
websockets==15.0.1
yarl==1.18.3

1199
uv.lock generated Normal file

File diff suppressed because it is too large Load Diff