mirror of
https://github.com/markbeep/AudioBookRequest.git
synced 2026-01-07 06:00:04 -06:00
Merge pull request #76 from markbeep/uv-nix-docker
Use uv and update to python 3.12
This commit is contained in:
13
.github/workflows/build.yaml
vendored
13
.github/workflows/build.yaml
vendored
@@ -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
|
||||
|
||||
|
||||
14
Dockerfile
14
Dockerfile
@@ -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
|
||||
|
||||
|
||||
26
README.md
26
README.md
@@ -1,6 +1,6 @@
|
||||

|
||||
|
||||
[](https://discord.gg/SsFRXWMg7s)
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
10
flake.lock
generated
@@ -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",
|
||||
|
||||
@@ -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
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user