Migrate from poetry/black to uv/ruff (#1673)

* Migrate from poetry/black to uv/ruff

* fixes

* path change

* path pt 2

* ah

* mkst tweaks (#1674)

* mkst tweaks

* tweaks++

* doh

* tweak harder

---------

Co-authored-by: Mark Street <22226349+mkst@users.noreply.github.com>
This commit is contained in:
Ethan Roseman
2025-09-22 19:23:55 +09:00
committed by GitHub
parent 66b10b2057
commit 50a2b836b9
38 changed files with 1752 additions and 2227 deletions

View File

@@ -19,13 +19,13 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
python-version: "3.12"
- name: Install Poetry
run: pip install poetry==2.2.0
- name: Install uv
run: pip install uv
- name: Update m2c & asm-differ
run: cd backend && poetry update m2c asm-differ
run: cd backend && uv pip install --upgrade m2c asm-differ
- name: Check for changes
run: |
@@ -37,8 +37,8 @@ jobs:
- name: Commit changes
uses: peter-evans/create-pull-request@v6
with:
commit-message: "🤖 (chore): bump m2c & asm-differ to latest"
title: "🤖 (chore): bump m2c & asm-differ to latest"
commit-message: "🤖 (chore): bump m2c / asm-differ to latest"
title: "🤖 (chore): bump m2c / asm-differ to latest"
branch: "update-m2c-asm-differ"
delete-branch: true
committer: "GitHub Actions <actions@github.com>"

View File

@@ -18,10 +18,12 @@ jobs:
run: |-
sudo sysctl -w kernel.apparmor_restrict_unprivileged_unconfined=0
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
mkdir -p sandbox && chmod 777 sandbox
mkdir -p local_files && chmod 777 local_files
mkdir -p compilers && chmod 777 compilers
mkdir -p libraries && chmod 777 libraries
# NOTE: CI does not run as 'ubuntu' user
export USER_1000=$(getent passwd 1000 | cut -d: -f1)
for dir in backend/.venv sandbox local_files compilers libraries; do
mkdir -p "$dir"
sudo chown "${USER_1000}:${USER_1000}" "$dir"
done
docker run \
-v $(pwd):/decomp.me \
-v $(pwd)/local_files:/local_files \
@@ -42,14 +44,13 @@ jobs:
-e USE_SANDBOX_JAIL=on \
-e SANDBOX_DISABLE_PROC=true \
-e TIMEOUT_SCALE_FACTOR=10 \
-e POETRY_VIRTUALENVS_PATH=/backend/virtualenvs \
decompme_backend \
-c 'cd /decomp.me/backend && \
poetry install --no-root && \
poetry run compilers/download.py --compilers-dir ${COMPILER_BASE_PATH} && \
poetry run libraries/download.py --libraries-dir ${LIBRARY_BASE_PATH} && \
uv sync && \
uv run compilers/download.py --compilers-dir ${COMPILER_BASE_PATH} && \
uv run libraries/download.py --libraries-dir ${LIBRARY_BASE_PATH} && \
for r in wine/*.reg; do regedit $r; done && \
poetry run python manage.py test'
uv run python manage.py test'
backend_test_docker_prod:
name: backend tests (docker prod container)
@@ -98,7 +99,7 @@ jobs:
decompme_backend \
-c '\
for r in wine/*.reg; do regedit $r; done && \
poetry run python manage.py test'
uv run python manage.py test'
docker_compose_test:
name: test docker compose
@@ -191,24 +192,34 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install poetry
run: pipx install poetry
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Setup Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: poetry
cache-dependency-path: backend/poetry.lock
- run: |-
cd backend
poetry install --no-root
poetry run mypy
uv sync
uv run mypy
black:
name: black
ruff:
name: ruff
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: psf/black@stable
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
src: "./backend"
version: "latest"
- name: Setup Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: |-
cd backend
uv sync
uv run ruff check .
uv run ruff format --check .

1
.gitignore vendored
View File

@@ -24,3 +24,4 @@ docker.prod.env
.vercel
send_update.py
update.sh
.venv/

22
.vscode/settings.json vendored
View File

@@ -1,44 +1,40 @@
{
"files.trimTrailingWhitespace": true,
// eslint
"eslint.workingDirectories": [
"frontend"
],
"eslint.workingDirectories": ["frontend"],
"eslint.format.enable": true,
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
// stylelint
"[css]": {
"editor.defaultFormatter": "stylelint.vscode-stylelint",
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
"[scss]": {
"editor.defaultFormatter": "stylelint.vscode-stylelint",
"editor.formatOnSave": true,
"editor.formatOnSave": true
},
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.defaultFormatter": "charliermarsh.ruff"
},
"typescript.tsdk": "frontend/node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"mypy-type-checker.args": [
"--config-file=backend/mypy.ini"
],
"mypy-type-checker.args": ["--config-file=backend/mypy.ini"],
"json.format.enable": false,
"json.format.keepLines": true
}

View File

@@ -2,6 +2,7 @@
virtualenvs/
__pycache__/
.mypy_cache/
.venv/
# avoid cache-busting when testing Docker
Dockerfile*

View File

@@ -4,41 +4,33 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
python-is-python3 \
python3 \
python3-pip \
python3.12-dev \
python3.12-venv \
software-properties-common \
ca-certificates \
curl \
git \
python-is-python3 \
python3 \
python3-pip \
python3.12-dev \
python3.12-venv \
software-properties-common \
&& rm -rf /var/lib/apt/lists/*
RUN curl -sSL https://install.python-poetry.org/ | \
POETRY_VERSION=2.2.0 \
POETRY_HOME=/etc/poetry \
python3.12 -
ENV POETRY_VIRTUALENVS_PATH=/virtualenvs
ENV PATH="${PATH}:/etc/poetry/bin"
RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="/usr/bin/" sh
FROM base AS nsjail
RUN apt-get -y update && apt-get install -y \
autoconf \
bison \
flex \
g++ \
gcc \
git \
libnl-route-3-dev \
libprotobuf-dev \
libtool \
make \
pkg-config \
protobuf-compiler
autoconf \
bison \
flex \
g++ \
gcc \
libnl-route-3-dev \
libprotobuf-dev \
libtool \
make \
pkg-config \
protobuf-compiler
RUN git clone "https://github.com/google/nsjail" --recursive --branch 3.4 /nsjail \
&& cd /nsjail \
@@ -52,31 +44,31 @@ RUN dpkg --add-architecture i386 \
&& add-apt-repository -y ppa:stsp-0/dj64 \
&& apt-get update \
&& apt-get install -y -o APT::Immediate-Configure=false --no-install-recommends \
binutils-aarch64-linux-gnu \
binutils-arm-none-eabi \
binutils-djgpp \
binutils-mingw-w64-i686 \
binutils-mips-linux-gnu \
binutils-powerpc-linux-gnu \
binutils-sh-elf \
cpp \
dj64 \
dos2unix \
dosemu2 \
gcc-mips-linux-gnu \
iptables \
libarchive-tools \
libc6-dev-i386 \
libdevmapper1.02.1 \
libgpgme11 \
libnl-route-3-200 \
libprotobuf-dev \
libtinfo6 \
netcat-traditional \
unzip \
wget \
wine \
wine32:i386 \
binutils-aarch64-linux-gnu \
binutils-arm-none-eabi \
binutils-djgpp \
binutils-mingw-w64-i686 \
binutils-mips-linux-gnu \
binutils-powerpc-linux-gnu \
binutils-sh-elf \
cpp \
dj64 \
dos2unix \
dosemu2 \
gcc-mips-linux-gnu \
iptables \
libarchive-tools \
libc6-dev-i386 \
libdevmapper1.02.1 \
libgpgme11 \
libnl-route-3-200 \
libprotobuf-dev \
libtinfo6 \
netcat-traditional \
unzip \
wget \
wine \
wine32:i386 \
&& rm -rf /var/lib/apt/lists/*
RUN wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.3-2ubuntu0.1_amd64.deb \
@@ -124,7 +116,6 @@ RUN wineboot --init
WORKDIR /backend
ENV POETRY_VIRTUALENVS_PATH=/backend/virtualenvs
ARG ENABLE_DREAMCAST_SUPPORT
ARG ENABLE_GBA_SUPPORT

View File

@@ -4,92 +4,74 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
python-is-python3 \
python3 \
python3-pip \
python3.12-dev \
python3.12-venv \
software-properties-common \
ca-certificates \
curl \
git \
python-is-python3 \
python3 \
python3-pip \
python3.12-dev \
python3.12-venv \
software-properties-common \
&& rm -rf /var/lib/apt/lists/*
RUN curl -sSL https://install.python-poetry.org/ | \
POETRY_VERSION=2.2.0 \
POETRY_HOME=/etc/poetry \
python3.12 -
ENV POETRY_VIRTUALENVS_PATH=/virtualenvs
ENV PATH="${PATH}:/etc/poetry/bin"
RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR="/usr/bin/" sh
FROM base AS nsjail
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
autoconf \
bison \
flex \
g++ \
gcc \
git \
libnl-route-3-dev \
libprotobuf-dev \
libtool \
make \
pkg-config \
protobuf-compiler \
autoconf \
bison \
flex \
g++ \
gcc \
libnl-route-3-dev \
libprotobuf-dev \
libtool \
make \
pkg-config \
protobuf-compiler \
&& rm -rf /var/lib/apt/lists/*
RUN git clone "https://github.com/google/nsjail" \
--recursive --branch 3.4 /nsjail \
--recursive --branch 3.4 /nsjail \
&& cd /nsjail \
&& make
FROM base AS poetry
COPY pyproject.toml poetry.lock /backend/
WORKDIR /backend
# NOTE: adding "--no-dev" results in "ModuleNotFoundError: No module named 'django_stubs_ext'" error
RUN poetry install
FROM base AS dependencies
FROM base AS developer
RUN dpkg --add-architecture i386 \
&& add-apt-repository -y ppa:dosemu2/ppa \
&& add-apt-repository -y ppa:stsp-0/dj64 \
&& apt-get update \
&& apt-get install -y -o APT::Immediate-Configure=false --no-install-recommends \
binutils-aarch64-linux-gnu \
binutils-arm-none-eabi \
binutils-djgpp \
binutils-mingw-w64-i686 \
binutils-mips-linux-gnu \
binutils-powerpc-linux-gnu \
binutils-sh-elf \
cpp \
dj64 \
dos2unix \
dosemu2 \
gcc-mips-linux-gnu \
iptables \
libarchive-tools \
libc6-dev-i386 \
libdevmapper1.02.1 \
libgpgme11 \
libnl-route-3-200 \
libprotobuf-dev \
libtinfo6 \
netcat-traditional \
unzip \
wget \
wine \
wine32:i386 \
binutils-aarch64-linux-gnu \
binutils-arm-none-eabi \
binutils-djgpp \
binutils-mingw-w64-i686 \
binutils-mips-linux-gnu \
binutils-powerpc-linux-gnu \
binutils-sh-elf \
cpp \
dj64 \
dos2unix \
dosemu2 \
gcc-mips-linux-gnu \
iptables \
libarchive-tools \
libc6-dev-i386 \
libdevmapper1.02.1 \
libgpgme11 \
libnl-route-3-200 \
libprotobuf-dev \
libtinfo6 \
netcat-traditional \
unzip \
wget \
wine \
wine32:i386 \
&& rm -rf /var/lib/apt/lists/*
RUN wget http://security.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.3-2ubuntu0.1_amd64.deb \
@@ -123,13 +105,11 @@ RUN mkdir -p /etc/fonts
ENV WINEPREFIX=/tmp/wine
# Ensure /sandbox, wine, and virtualenv dirs have correct ownership
# Ensure /sandbox and wine dirs have correct ownership
RUN mkdir -p /sandbox \
&& chown -R ubuntu:ubuntu /sandbox \
&& mkdir -p "${WINEPREFIX}" \
&& chown ubuntu:ubuntu "${WINEPREFIX}" \
&& mkdir /virtualenvs \
&& chown -R ubuntu:ubuntu /virtualenvs
&& chown ubuntu:ubuntu "${WINEPREFIX}"
# Switch to non-root user
USER ubuntu
@@ -137,15 +117,27 @@ USER ubuntu
# Initialize wine files to /home/ubuntu/.wine
RUN wineboot --init
COPY wine /wine
WORKDIR /backend
FROM dependencies AS deployment
FROM base AS uv-install
WORKDIR /backend
COPY --from=poetry /virtualenvs /virtualenvs
COPY pyproject.toml poetry.lock /backend/
RUN chown -R ubuntu:ubuntu /backend
COPY pyproject.toml uv.lock /backend/
USER ubuntu
# Install dependencies to /backend/.venv
RUN uv sync --locked
FROM developer AS deployment
COPY --from=uv-install /backend/.venv /backend/.venv
COPY pyproject.toml uv.lock /backend/
COPY manage.py /backend
COPY housekeeping.py /backend

View File

@@ -229,7 +229,7 @@ class CompilerWrapper:
# Shlex issue?
logging.debug("Compilation failed: %s", e)
raise CompilationError(str(e))
except subprocess.TimeoutExpired as e:
except subprocess.TimeoutExpired:
raise CompilationError("Compilation failed: timeout expired")
if not object_path.exists():
@@ -298,7 +298,7 @@ class CompilerWrapper:
)
except subprocess.CalledProcessError as e:
raise AssemblyError.from_process_error(e)
except subprocess.TimeoutExpired as e:
except subprocess.TimeoutExpired:
raise AssemblyError("Timeout expired")
# Assembly failed

View File

@@ -1,7 +1,7 @@
from functools import wraps
import logging
from typing import Callable, Any, Optional, TypeVar, ParamSpec
from typing import Callable, Optional, TypeVar, ParamSpec
from rest_framework.response import Response
logger = logging.getLogger(__file__)
@@ -21,12 +21,10 @@ def globally_cacheable(
def decorator(view_func: Callable[P, R]) -> Callable[P, R]:
@wraps(view_func)
def _wrapped_view(*args: P.args, **kwargs: P.kwargs) -> R:
# First argument is typically request
request: Any = args[0] if args else None
response: R = view_func(*args, **kwargs)
# Build Cache-Control header
directives = [f"public", f"max-age={max_age}"]
directives = ["public", f"max-age={max_age}"]
if stale_while_revalidate is not None:
directives.append(f"stale-while-revalidate={stale_while_revalidate}")

View File

@@ -113,7 +113,7 @@ class DiffWrapper:
},
timeout=settings.OBJDUMP_TIMEOUT_SECONDS,
)
except subprocess.TimeoutExpired as e:
except subprocess.TimeoutExpired:
raise NmError("Timeout expired")
except subprocess.CalledProcessError as e:
raise NmError.from_process_error(e)
@@ -198,7 +198,7 @@ class DiffWrapper:
},
timeout=settings.OBJDUMP_TIMEOUT_SECONDS,
)
except subprocess.TimeoutExpired as e:
except subprocess.TimeoutExpired:
raise ObjdumpError("Timeout expired")
except subprocess.CalledProcessError as e:
raise ObjdumpError.from_process_error(e)
@@ -287,7 +287,7 @@ class DiffWrapper:
mydump = DiffWrapper.get_dump(
compiled_elf, platform, diff_label, config, objdump_flags
)
except Exception as e:
except Exception:
mydump = ""
try:

View File

@@ -1,5 +1,5 @@
import logging
from typing import Callable, Optional, TYPE_CHECKING, Union
from typing import Callable, TYPE_CHECKING, Union
from django.contrib import auth
from django.contrib.auth.models import User
@@ -13,7 +13,7 @@ from .models.profile import Profile
logger = logging.getLogger(__name__)
if TYPE_CHECKING:
from .models.github import GitHubUser
pass
class AnonymousUser(auth.models.AnonymousUser):

View File

@@ -11,7 +11,7 @@ from ..models.scratch import gen_scratch_id
class Migration(migrations.Migration):
initial = True
dependencies: List[Tuple[str, str]] = []
dependencies: List[Tuple[str, str]] = [] # type: ignore
operations = [
migrations.CreateModel(

View File

@@ -13,7 +13,7 @@ def populate_preset_fk(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> N
if scratch.preset is not None:
try:
preset = Preset.objects.get(name=scratch.preset)
except:
except Exception:
continue
scratch.preset_fk = preset
scratch.save(update_fields=["preset_fk"])

View File

@@ -3,7 +3,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("coreapp", "0058_rename_gcc272sn_to_gcc272sn0004"),
]

View File

@@ -75,7 +75,6 @@ def set_family_field(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> Non
class Migration(migrations.Migration):
dependencies = [
("coreapp", "0059_scratch_family_alter_scratch_parent"),
]

View File

@@ -5,7 +5,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("coreapp", "0061_remove_githubuser_access_token"),
]

View File

@@ -78,7 +78,6 @@ class GitHubUser(models.Model):
)
try:
scope_str = str(response_json["scope"])
access_token = str(response_json["access_token"])
except KeyError:
raise MalformedGitHubApiResponseException()

View File

@@ -1,6 +1,6 @@
import json
import logging
from typing import Any, List, Sequence
from typing import Any, Sequence
from django.db import models
from django.contrib import admin

View File

@@ -1,20 +1,16 @@
from typing import TYPE_CHECKING, Any, Dict, List, Optional
from django.contrib.auth.models import User
from django.core.exceptions import ImproperlyConfigured
from html_json_forms.serializers import JSONFormSerializer
from rest_framework import serializers
from rest_framework.exceptions import APIException
from rest_framework.fields import SerializerMethodField
from rest_framework.relations import HyperlinkedRelatedField, SlugRelatedField
from rest_framework.reverse import reverse
from rest_framework.relations import SlugRelatedField
from coreapp import platforms
from . import compilers
from .flags import LanguageFlagSet
from .libraries import Library
from .middleware import Request
from .models.github import GitHubUser
from .models.preset import Preset
from .models.profile import Profile
@@ -123,14 +119,14 @@ class PresetSerializer(serializers.ModelSerializer[Preset]):
def validate_platform(self, platform: str) -> str:
try:
platforms.from_id(platform)
except:
except Exception:
raise serializers.ValidationError(f"Unknown platform: {platform}")
return platform
def validate_compiler(self, compiler: str) -> str:
try:
compilers.from_id(compiler)
except:
except Exception:
raise serializers.ValidationError(f"Unknown compiler: {compiler}")
return compiler
@@ -167,14 +163,14 @@ class ScratchCreateSerializer(serializers.Serializer[None]):
def validate_platform(self, platform: str) -> str:
try:
platforms.from_id(platform)
except:
except Exception:
raise serializers.ValidationError(f"Unknown platform: {platform}")
return platform
def validate_compiler(self, compiler: str) -> str:
try:
compilers.from_id(compiler)
except:
except Exception:
raise serializers.ValidationError(f"Unknown compiler: {compiler}")
return compiler

View File

@@ -17,7 +17,6 @@ def requiresCompiler(*compilers: Compiler) -> Callable[..., Any]:
class BaseTestCase(APITestCase):
def setUp(self) -> None:
super().setUp()
self.client.credentials(HTTP_USER_AGENT="Firefrogz 1.0")

View File

@@ -227,7 +227,15 @@ nop
len(result.elf_object), 0, "The compilation result should be non-null"
)
@parameterized.expand(input=[(c,) for c in compilers.available_compilers() if not isinstance(c, DummyCompiler)], name_func=all_compilers_name_func, skip_on_empty=True) # type: ignore
@parameterized.expand(
input=[
(c,)
for c in compilers.available_compilers()
if not isinstance(c, DummyCompiler)
],
name_func=all_compilers_name_func,
skip_on_empty=True,
) # type: ignore
def test_all_compilers(self, compiler: Compiler) -> None:
"""
Ensure that we can run a simple compilation/diff for all available compilers

View File

@@ -1,6 +1,5 @@
from typing import Any, Dict
from django.test import Client
from coreapp.compilers import GCC281PM
from coreapp.models.preset import Preset

View File

@@ -1,5 +1,4 @@
import tempfile
from unittest.mock import Mock, patch
from coreapp.models.github import GitHubUser
from coreapp.models.profile import Profile

View File

@@ -407,7 +407,7 @@ class ScratchDetailTests(BaseTestCase):
# fork the fork
response = self.client.post(reverse("scratch-fork", args=[fork.slug]))
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
fork2: Scratch = Scratch.objects.get(slug=response.json()["slug"])
Scratch.objects.get(slug=response.json()["slug"])
# verify the family holds all three
response = self.client.get(reverse("scratch-family", args=[root.slug]))
@@ -420,7 +420,6 @@ class ScratchDetailTests(BaseTestCase):
# fork the root
response = self.client.post(reverse("scratch-fork", args=[root.slug]))
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
fork = response.json()
# verify the family holds both, in creation order
response = self.client.get(reverse("scratch-family", args=[root.slug]))
@@ -477,7 +476,7 @@ class ScratchDetailTests(BaseTestCase):
}
scratch1 = self.create_scratch(scratch1_dict)
scratch2 = self.create_scratch(scratch2_dict)
self.create_scratch(scratch2_dict)
response = self.client.get(reverse("scratch-family", args=[scratch1.slug]))
self.assertEqual(len(response.json()), 1)

View File

@@ -34,7 +34,6 @@ class SingleCompilerDetail(APIView):
platform: Optional[str] = "",
compiler: Optional[str] = "",
) -> Response:
filtered = [
c for c in compilers.available_compilers() if c.platform.id == platform
]

View File

@@ -21,12 +21,12 @@ class LibraryDetail(APIView):
def libraries_json(platform: str = "") -> list[dict[str, object]]:
return [
{
"name": l.name,
"supported_versions": l.supported_versions,
"platform": l.platform,
"name": lib.name,
"supported_versions": lib.supported_versions,
"platform": lib.platform,
}
for l in libraries.available_libraries()
if platform == "" or l.platform == platform
for lib in libraries.available_libraries()
if platform == "" or lib.platform == platform
]
@condition(last_modified_func=lambda request: boot_time)

View File

@@ -60,7 +60,6 @@ class PresetFilterSet(django_filters.FilterSet):
globally_cacheable(max_age=300, stale_while_revalidate=30), name="dispatch"
)
class PresetViewSet(ModelViewSet): # type: ignore
permission_classes = [IsAdminUser | IsOwnerOrReadOnly]
queryset = Preset.objects.all().annotate(num_scratches=Count("scratch__preset__id"))
pagination_class = PresetPagination

View File

@@ -194,8 +194,6 @@ def create_scratch(data: Dict[str, Any], allow_project: bool = False) -> Scratch
platform: Optional[Platform] = data.get("platform")
compiler = compilers.from_id(data["compiler"])
project = data.get("project")
rom_address = data.get("rom_address")
if not platform:
platform = compiler.platform

View File

@@ -6,12 +6,11 @@ DB_PORT=${DATABASE_PORT:-5432}
BE_HOST=${BACKEND_HOST:-0.0.0.0}
BE_PORT=${BACKEND_PORT:-8000}
POETRY_VIRTUALENVS_PATH=/backend/virtualenvs
poetry install
uv sync
poetry run /backend/compilers/download.py
poetry run /backend/libraries/download.py
uv run /backend/compilers/download.py
uv run /backend/libraries/download.py
if command -v regedit &> /dev/null; then
for reg in /backend/wine/*.reg; do
@@ -27,6 +26,6 @@ until nc -z ${DB_HOST} ${DB_PORT} > /dev/null; do
sleep 1
done
poetry run /backend/manage.py migrate
uv run /backend/manage.py migrate
poetry run /backend/manage.py runserver ${BE_HOST}:${BE_PORT}
uv run /backend/manage.py runserver ${BE_HOST}:${BE_PORT}

View File

@@ -14,12 +14,12 @@ until nc -z ${DB_HOST} ${DB_PORT} > /dev/null; do
done
if [ -z "$CI" ]; then
poetry run /backend/housekeeping.py
uv run /backend/housekeeping.py
else
echo "Skipping housekeeping: running in CI environment"
fi
poetry run /backend/manage.py migrate
uv run /backend/manage.py migrate
if command -v regedit &> /dev/null; then
for reg in /backend/wine/*.reg; do
@@ -30,4 +30,4 @@ else
echo "regedit command not found. Skipping registry import."
fi
poetry run gunicorn -w ${WORKERS} decompme.wsgi --bind ${BE_HOST}:${BE_PORT}
uv run gunicorn -w ${WORKERS} decompme.wsgi --bind ${BE_HOST}:${BE_PORT}

View File

@@ -179,11 +179,11 @@ def main():
if args.verbose:
logger.setLevel("DEBUG")
if args.libraries_dir == None:
if args.libraries_dir is None:
args.libraries_dir = Path(os.path.dirname(os.path.realpath(__file__)))
libraries_yaml = (
Path(os.path.dirname(os.path.realpath(__file__))) / f"libraries.yaml"
Path(os.path.dirname(os.path.realpath(__file__))) / "libraries.yaml"
)
libraries_config = yaml.safe_load(libraries_yaml.open())

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys

1947
backend/poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,50 +1,56 @@
[tool.poetry]
[project]
name = "backend"
version = "0.1.0"
description = ""
authors = ["Decomp.me team"]
license = "MIT"
package-mode = false
authors = [
{name = "Decomp.me team"}
]
license = {text = "MIT"}
requires-python = ">=3.10"
dependencies = [
"django-cors-headers>=4.6.0",
"django-environ>=0.11.2",
"django-filter>=24.3",
"djangorestframework>=3.15.2",
"psycopg2-binary>=2.9.10",
"jwt>=1.3.1",
"PyGithub>=2.5.0",
"drf-extensions>=0.7.1",
"tzdata==2024.2",
"Pillow==11.0",
"html-json-forms>=1.1.1",
"django-resized>=1.0.3",
"django-cleanup>=9.0.0",
"m2c @ git+https://github.com/matt-kempster/m2c.git",
"asm-differ @ git+https://github.com/simonlindholm/asm-differ.git",
"sentry-sdk>=2.19.0",
"django-session-timeout>=0.1.0",
"django>=5.1.3",
"requests>=2.32.3",
"setuptools>=75.6.0",
"debugpy>=1.8.13",
"gunicorn>=23.0.0",
]
[tool.poetry.dependencies]
python = "^3.10"
django-cors-headers = "^4.6.0"
django-environ = "^0.11.2"
django-filter = "^24.3"
djangorestframework = "^3.15.2"
psycopg2-binary = "^2.9.10"
jwt = "^1.3.1"
PyGithub = "^2.5.0"
drf-extensions = "^0.7.1"
tzdata = "2024.2"
Pillow = "11.0"
html-json-forms = "^1.1.1"
django-resized = "^1.0.3"
django-cleanup = "^9.0.0"
m2c = {git="https://github.com/matt-kempster/m2c.git"}
asm-differ = {git="https://github.com/simonlindholm/asm-differ.git"}
sentry-sdk = "^2.19.0"
django-session-timeout = "^0.1.0"
django = "^5.1.3"
requests = "^2.32.3"
setuptools = "^75.6.0"
debugpy = "^1.8.13"
gunicorn = "^23.0.0"
[tool.poetry.group.dev.dependencies]
black = "^24.10.0"
usort = "^1.0.8.post1"
django-stubs-ext = "^5.1.1"
django-stubs = "^5.1.1"
djangorestframework-stubs = "^3.15.1"
types-requests = "^2.32.0.20241016"
parameterized = "^0.9.0"
mypy = "^1.13.0"
responses = "0.25.3"
[dependency-groups]
dev = [
"ruff>=0.8.0",
"usort>=1.0.8",
"django-stubs-ext>=5.1.1",
"django-stubs>=5.1.1",
"djangorestframework-stubs>=3.15.1",
"types-requests>=2.32.0.20241016",
"parameterized>=0.9.0",
"mypy>=1.13.0",
"responses==0.25.3",
]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.black]
extend-exclude = '^/(local_files)/'
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["coreapp", "decompme"]

1482
backend/uv.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@ Dependencies:
- Python >=3.10
- Node.js >=14
- [Yarn](https://yarnpkg.com/getting-started/install)
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
---
Create a file to hold environment variables:
@@ -38,29 +38,30 @@ touch .env.local
cd backend
```
* Install Python dependencies with [poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
* Install Python dependencies with [uv](https://docs.astral.sh/uv/getting-started/installation/)
```shell
poetry install
uv sync
```
- Install compilers
```shell
poetry run python compilers/download.py
uv run python compilers/download.py
```
- Install libraries
```shell
poetry run python libraries/download.py
uv run python libraries/download.py
```
- Set up the database
```shell
poetry run python manage.py migrate
uv run python manage.py migrate
```
- Start the API server
```shell
poetry run python manage.py runserver
uv run python manage.py runserver
```
---
@@ -98,8 +99,8 @@ yarn dev
If you modify any database models (`models.py`), you'll need to run the following to update the database:
```shell
poetry run python manage.py makemigrations
poetry run python manage.py migrate
uv run python manage.py makemigrations
uv run python manage.py migrate
```
### Running tests
@@ -107,7 +108,7 @@ poetry run python manage.py migrate
To ensure everything is working properly, you can run the unit tests in the backend folder.
```shell
poetry run python manage.py test
uv run python manage.py test
```
### Frontend styling
@@ -131,6 +132,7 @@ yarn lint --fix
- Check backend
```shell
cd backend
poetry run mypy
poetry run black .
uv run mypy
uv run ruff check .
uv run ruff format .
```

View File

@@ -15,7 +15,7 @@
After signing in with GitHub, you can make yourself an admin with the following:
```
$ poetry run python3 manage.py shell
$ uv run python3 manage.py shell
>>> from django.contrib.auth.models import User
>>> user = User.objects.get(username="your_username")
>>> user.is_staff = True

View File

@@ -1,8 +1,8 @@
### Configuring vscode for development
Poetry creates a virtualenv where packages for the site are installed. You can set your python interpreter path in vscode to use this virtualenv's interpreter, which will allow a much nicer backend development experience.
uv creates a virtual environment where packages for the site are installed. You can set your python interpreter path in vscode to use this virtual environment's interpreter, which will allow a much nicer backend development experience.
1. Inside the `backend/` directory, run `poetry debug info` and copy the "Path:" property under the "Virtualenv" category.
1. Inside the `backend/` directory, run `uv run which python` and copy the output path.
<img width="580" alt="image" src="https://user-images.githubusercontent.com/2985314/190146150-4ac8ecdd-dcfa-4e8e-a8b2-4913044aa088.png">