feat: Enhance Python environment setup with system Python option and improve dependency installation
refactor: Clean up imports in currencies and users routes fix: Update theme settings saving logic and clean up test imports
This commit is contained in:
@@ -5,30 +5,48 @@ inputs:
|
|||||||
python-version:
|
python-version:
|
||||||
description: Python version to install.
|
description: Python version to install.
|
||||||
required: false
|
required: false
|
||||||
default: "3.10"
|
default: '3.10'
|
||||||
|
use-system-python:
|
||||||
|
description: Skip setup-python and rely on the system Python already available in the environment.
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
install-playwright:
|
install-playwright:
|
||||||
description: Install Playwright browsers when true.
|
description: Install Playwright browsers when true.
|
||||||
required: false
|
required: false
|
||||||
default: "false"
|
default: 'false'
|
||||||
install-requirements:
|
install-requirements:
|
||||||
description: Space-delimited list of requirement files to install.
|
description: Space-delimited list of requirement files to install.
|
||||||
required: false
|
required: false
|
||||||
default: "requirements.txt requirements-test.txt"
|
default: 'requirements.txt requirements-test.txt'
|
||||||
run-db-setup:
|
run-db-setup:
|
||||||
description: Run database wait and setup scripts when true.
|
description: Run database wait and setup scripts when true.
|
||||||
required: false
|
required: false
|
||||||
default: "true"
|
default: 'true'
|
||||||
db-dry-run:
|
db-dry-run:
|
||||||
description: Execute setup script dry run before live run when true.
|
description: Execute setup script dry run before live run when true.
|
||||||
required: false
|
required: false
|
||||||
default: "true"
|
default: 'true'
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
|
if: ${{ inputs.use-system-python != 'true' }}
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: ${{ inputs.python-version }}
|
python-version: ${{ inputs.python-version }}
|
||||||
|
|
||||||
|
- name: Verify system Python
|
||||||
|
if: ${{ inputs.use-system-python == 'true' }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if ! command -v python >/dev/null 2>&1; then
|
||||||
|
echo "Python executable not found on PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
python --version
|
||||||
|
python -m pip --version >/dev/null 2>&1 || python -m ensurepip --upgrade
|
||||||
|
python -m pip --version
|
||||||
- name: Configure apt proxy
|
- name: Configure apt proxy
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
@@ -59,7 +77,7 @@ runs:
|
|||||||
if [ -n "${requirements}" ]; then
|
if [ -n "${requirements}" ]; then
|
||||||
for requirement in ${requirements}; do
|
for requirement in ${requirements}; do
|
||||||
if [ -f "${requirement}" ]; then
|
if [ -f "${requirement}" ]; then
|
||||||
pip install -r "${requirement}"
|
python -m pip install -r "${requirement}"
|
||||||
else
|
else
|
||||||
echo "Requirement file ${requirement} not found" >&2
|
echo "Requirement file ${requirement} not found" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ jobs:
|
|||||||
uses: ./.gitea/actions/setup-python-env
|
uses: ./.gitea/actions/setup-python-env
|
||||||
with:
|
with:
|
||||||
install-playwright: ${{ matrix.target != 'e2e' }}
|
install-playwright: ${{ matrix.target != 'e2e' }}
|
||||||
|
use-system-python: 'true'
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from typing import Dict, List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class ThemeSettings(BaseModel):
|
|||||||
@router.post("/theme")
|
@router.post("/theme")
|
||||||
async def update_theme(theme_data: ThemeSettings, db: Session = Depends(get_db)):
|
async def update_theme(theme_data: ThemeSettings, db: Session = Depends(get_db)):
|
||||||
data_dict = theme_data.model_dump()
|
data_dict = theme_data.model_dump()
|
||||||
saved = save_theme_settings(db, data_dict)
|
save_theme_settings(db, data_dict)
|
||||||
return {"message": "Theme updated", "theme": data_dict}
|
return {"message": "Theme updated", "theme": data_dict}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,15 @@ from sqlalchemy.orm import Session
|
|||||||
|
|
||||||
from config.database import get_db
|
from config.database import get_db
|
||||||
from models.user import User
|
from models.user import User
|
||||||
from services.security import get_password_hash, verify_password, create_access_token, SECRET_KEY, ALGORITHM, get_current_user, oauth2_scheme
|
from services.security import create_access_token, get_current_user
|
||||||
from jose import jwt, JWTError
|
from schemas.user import (
|
||||||
from schemas.user import UserCreate, UserInDB, UserLogin, UserUpdate, PasswordResetRequest, PasswordReset, Token
|
PasswordReset,
|
||||||
|
PasswordResetRequest,
|
||||||
|
UserCreate,
|
||||||
|
UserInDB,
|
||||||
|
UserLogin,
|
||||||
|
UserUpdate,
|
||||||
|
)
|
||||||
|
|
||||||
router = APIRouter(prefix="/users", tags=["users"])
|
router = APIRouter(prefix="/users", tags=["users"])
|
||||||
|
|
||||||
@@ -62,7 +68,7 @@ async def update_user_me(user_update: UserUpdate, current_user: User = Depends(g
|
|||||||
if existing_user:
|
if existing_user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST, detail="Username already taken")
|
status_code=status.HTTP_400_BAD_REQUEST, detail="Username already taken")
|
||||||
current_user.username = user_update.username
|
setattr(current_user, "username", user_update.username)
|
||||||
|
|
||||||
if user_update.email and user_update.email != current_user.email:
|
if user_update.email and user_update.email != current_user.email:
|
||||||
existing_user = db.query(User).filter(
|
existing_user = db.query(User).filter(
|
||||||
@@ -70,7 +76,7 @@ async def update_user_me(user_update: UserUpdate, current_user: User = Depends(g
|
|||||||
if existing_user:
|
if existing_user:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered")
|
status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered")
|
||||||
current_user.email = user_update.email
|
setattr(current_user, "email", user_update.email)
|
||||||
|
|
||||||
if user_update.password:
|
if user_update.password:
|
||||||
current_user.set_password(user_update.password)
|
current_user.set_password(user_update.password)
|
||||||
|
|||||||
@@ -43,15 +43,14 @@ def backfill(
|
|||||||
engine = create_engine(db_url)
|
engine = create_engine(db_url)
|
||||||
with engine.begin() as conn:
|
with engine.begin() as conn:
|
||||||
# Ensure currency table exists
|
# Ensure currency table exists
|
||||||
res = (
|
if db_url.startswith("sqlite:"):
|
||||||
conn.execute(
|
conn.execute(
|
||||||
text(
|
text(
|
||||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='currency';"
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='currency';"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if db_url.startswith("sqlite:")
|
else:
|
||||||
else conn.execute(text("SELECT to_regclass('public.currency');"))
|
conn.execute(text("SELECT to_regclass('public.currency');"))
|
||||||
)
|
|
||||||
# Note: we don't strictly depend on the above - we assume migration was already applied
|
# Note: we don't strictly depend on the above - we assume migration was already applied
|
||||||
|
|
||||||
# Helper: find or create currency by code
|
# Helper: find or create currency by code
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os
|
from typing import Optional
|
||||||
from typing import Iterable, Optional
|
|
||||||
|
|
||||||
import psycopg2
|
import psycopg2
|
||||||
from psycopg2 import errors
|
from psycopg2 import errors
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
import pytest
|
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from fastapi.testclient import TestClient
|
|
||||||
|
|
||||||
from main import app
|
|
||||||
from models.theme_setting import ThemeSetting
|
|
||||||
from services.settings import save_theme_settings, get_theme_settings
|
from services.settings import save_theme_settings, get_theme_settings
|
||||||
|
|
||||||
|
|
||||||
client = TestClient(app)
|
|
||||||
|
|
||||||
|
|
||||||
def test_save_theme_settings(db_session: Session):
|
def test_save_theme_settings(db_session: Session):
|
||||||
theme_data = {
|
theme_data = {
|
||||||
"theme_name": "dark",
|
"theme_name": "dark",
|
||||||
|
|||||||
Reference in New Issue
Block a user