Skip to content

Commit

Permalink
Django integration (#4)
Browse files Browse the repository at this point in the history
* Add django integration

* Remove debug

* Add tests

* Reformat

* Bugfixes, refactor

* Fix tests

* Fix workflows

* Formatter and test setup

* Chmod manage.py

* Python 3.10

* Fix workflows

* Remove arch

---------

Co-authored-by: Tomasz Kwiatkowski <[email protected]>
  • Loading branch information
MasloMaslane and geoff128 authored Dec 2, 2024
1 parent b093aa4 commit f8b49f5
Show file tree
Hide file tree
Showing 33 changed files with 543 additions and 54 deletions.
28 changes: 0 additions & 28 deletions .github/workflows/arch.yml

This file was deleted.

23 changes: 23 additions & 0 deletions .github/workflows/check_migrations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: migrations
run-name: Check if all migrations are created
on:
push:
branches: 'main'
pull_request:
jobs:
pytest:
runs-on: ubuntu-latest
name: migrations-ubuntu
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.12
- name: Install dependencies
run: |
pip3 install .[django]
- name: Check migrations
run: |
python3 tests/test_django/manage.py makemigrations --dry-run --check
6 changes: 3 additions & 3 deletions .github/workflows/formatter.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: Python Formatter (isort & black)

on:
push:
branches: 'main'
pull_request:
branches: [main]

jobs:
formatting:
runs-on: ubuntu-latest
Expand All @@ -12,7 +12,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.9'
python-version: '3.10'
- name: Install isort and black
run: |
python -m pip install --upgrade pip
Expand Down
14 changes: 11 additions & 3 deletions .github/workflows/macOS.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: macos-latest
strategy:
matrix:
python-version: ["3.9", "3.13"]
python-version: ["3.10", "3.13"]
name: pytest-macos-python-${{ matrix.python-version }}
steps:
- name: Checkout
Expand All @@ -30,10 +30,18 @@ jobs:
run: |
python3 -m venv .venv
source .venv/bin/activate
pip install .[tests]
- name: Run pytest
pip install -e .[tests]
- name: Run pytest without Django
env:
PYTEST_ADDOPTS: "--color=yes"
run: |
source .venv/bin/activate
pytest -v -n auto
- name: Run pytest with Django
env:
PYTEST_ADDOPTS: "--color=yes"
run: |
source .venv/bin/activate
pip install -e .[tests,django_tests,django]
./tests/test_django/manage.py migrate
pytest -v -n auto
15 changes: 11 additions & 4 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ on:
pull_request:
jobs:
pytest:
runs-on: ubuntu:latest
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.13"]
python-version: ["3.10", "3.13"]
name: pytest-ubuntu-python-${{ matrix.python-version }}
steps:
- name: Checkout
Expand All @@ -20,9 +20,16 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip3 install .[tests]
- name: Run pytest
pip3 install -e .[tests]
- name: Run pytest without Django
env:
PYTEST_ADDOPTS: "--color=yes"
run: |
python3 -m pytest -v -n auto
- name: Run pytest with Django
env:
PYTEST_ADDOPTS: "--color=yes"
run: |
pip3 install -e .[tests,django_tests,django]
./tests/test_django/manage.py migrate
python3 -m pytest -v -n auto
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ build
.vscode
.idea
__pycache__
tests/test_django/db.sqlite3

# pytest-cov
.coverage*
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ include_trailing_comma = true

[tool.black]
line_length = 120
exclude = "migrations/"
5 changes: 5 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[pytest]
DJANGO_SETTINGS_MODULE = test_django.settings
pythonpath = ./tests/test_django
markers =
no_django: marks tests that should be run without Django
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ tests =
pytest
pytest-cov
pytest-xdist
django_tests =
pytest-django
django =
django

[tool:pytest]
testpaths =
Expand Down
17 changes: 17 additions & 0 deletions src/sio3pack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
__version__ = "0.0.1"

from sio3pack.files import LocalFile
from sio3pack.packages.exceptions import ImproperlyConfigured, PackageAlreadyExists
from sio3pack.packages.package import Package


Expand All @@ -14,3 +15,19 @@ def from_file(file: str | LocalFile, django_settings=None) -> Package:
if isinstance(file, str):
file = LocalFile(file)
return Package.from_file(file, django_settings=django_settings)


def from_db(problem_id: int) -> Package:
"""
Initialize a package object from the database.
If sio3pack isn't installed with Django support, it should raise an ImproperlyConfigured exception.
If there is no package with the given problem_id, it should raise an UnknownPackageType exception.
:param problem_id: The problem id.
:return: The package object.
"""
try:
import django

return Package.from_db(problem_id)
except ImportError:
raise ImproperlyConfigured("sio3pack is not installed with Django support.")
Empty file added src/sio3pack/django/__init__.py
Empty file.
Empty file.
17 changes: 17 additions & 0 deletions src/sio3pack/django/sinolpack/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from sio3pack.django.sinolpack.models import SinolpackPackage
from sio3pack.packages.exceptions import PackageAlreadyExists
from sio3pack.packages.package.django.handler import DjangoHandler


class SinolpackDjangoHandler(DjangoHandler):
def save_to_db(self):
"""
Save the package to the database.
"""
if SinolpackPackage.objects.filter(problem_id=self.problem_id).exists():
raise PackageAlreadyExists(self.problem_id)

SinolpackPackage.objects.create(
problem_id=self.problem_id,
short_name=self.package.short_name,
)
21 changes: 21 additions & 0 deletions src/sio3pack/django/sinolpack/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 5.1.3 on 2024-12-01 17:22

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = []

operations = [
migrations.CreateModel(
name="SinolpackPackage",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("problem_id", models.IntegerField()),
("short_name", models.CharField(max_length=100)),
],
),
]
Empty file.
10 changes: 10 additions & 0 deletions src/sio3pack/django/sinolpack/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from django.db import models


class SinolpackPackage(models.Model):
"""
A package for the sinolpack package type.
"""

problem_id = models.IntegerField()
short_name = models.CharField(max_length=100)
21 changes: 18 additions & 3 deletions src/sio3pack/packages/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
class UnknownPackageType(Exception):
def __init__(self, path: str) -> None:
self.path = path
super().__init__(f"Unknown package type for file {path}.")
def __init__(self, arg: str | int) -> None:
if isinstance(arg, str):
self.path = arg
super().__init__(f"Unknown package type for file {arg}.")
else:
self.problem_id = arg
super().__init__(f"Unknown package type for problem with id={arg}.")


class ImproperlyConfigured(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)


class PackageAlreadyExists(Exception):
def __init__(self, problem_id: int) -> None:
self.problem_id = problem_id
super().__init__(f"A package already exists for problem with id={problem_id}.")
Empty file.
14 changes: 14 additions & 0 deletions src/sio3pack/packages/package/django/handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from typing import Type

from sio3pack.packages.exceptions import ImproperlyConfigured


class DjangoHandler:
def __init__(self, package: Type["Package"], problem_id: int):
self.package = package
self.problem_id = problem_id


class NoDjangoHandler:
def __call__(self, *args, **kwargs):
raise ImproperlyConfigured("sio3pack is not installed with Django support.")
71 changes: 68 additions & 3 deletions src/sio3pack/packages/package/model.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import importlib
from typing import Any

from sio3pack import LocalFile
from sio3pack.files import File
from sio3pack.graph import Graph, GraphOperation
from sio3pack.packages.exceptions import UnknownPackageType
from sio3pack.packages.package.django.handler import NoDjangoHandler
from sio3pack.test import Test
from sio3pack.utils.archive import Archive
from sio3pack.utils.classinit import RegisteredSubclassesBase
Expand All @@ -19,11 +21,23 @@ class Package(RegisteredSubclassesBase):
def __init__(self):
super().__init__()

@classmethod
def identify(cls, file: LocalFile):
"""
Identify if the package is of this type.
"""
raise NotImplementedError()

@classmethod
def from_file(cls, file: LocalFile, django_settings=None):
"""
Create a package from a file.
"""
for subclass in cls.subclasses:
if subclass.identify(file):
return subclass(file, django_settings)
package = subclass()
package._from_file(file, django_settings)
return package
raise UnknownPackageType(file.path)

def _from_file(self, file: LocalFile):
Expand All @@ -34,6 +48,50 @@ def _from_file(self, file: LocalFile):
else:
self.is_archive = False

@classmethod
def identify_db(cls, problem_id: int):
"""
Identify if the package is of this type. Should check if there
is a package of this type in the database with the given problem_id.
"""
raise NotImplementedError()

@classmethod
def from_db(cls, problem_id: int):
"""
Create a package from the database. If sio3pack isn't installed with Django
support, it should raise an ImproperlyConfigured exception. If there is no
package with the given problem_id, it should raise an UnknownPackageType
exception.
"""
for subclass in cls.subclasses:
if subclass.identify_db(problem_id):
package = subclass()
package._from_db(problem_id)
return package
raise UnknownPackageType(problem_id)

def _from_db(self, problem_id: int):
"""
Internal method to setup the package from the database. If sio3pack
isn't installed with Django support, it should raise an ImproperlyConfigured
exception.
"""
self.problem_id = problem_id

def _setup_django_handler(self, problem_id: int):
try:
import django

self.django_enabled = True
module_path, class_name = self.django_handler.rsplit(".", 1)
module = importlib.import_module(module_path)
handler = getattr(module, class_name)
self.django = handler(package=self, problem_id=problem_id)
except ImportError:
self.django_enabled = False
self.django = NoDjangoHandler()

def get_task_id(self) -> str:
pass

Expand Down Expand Up @@ -61,8 +119,15 @@ def get_test(self, test_id: str) -> Test:
def get_unpack_graph(self) -> GraphOperation | None:
pass

def get_run_graph(self, file: File, tests: list[Test] | None = None) -> Graph:
def get_run_graph(self, file: File, tests: list[Test] | None = None) -> GraphOperation | None:
pass

def get_save_outs_graph(self, tests: list[Test] | None = None) -> GraphOperation | None:
pass

def get_save_outs_graph(self, tests: list[Test] | None = None) -> Graph:
def save_to_db(self, problem_id: int):
"""
Save the package to the database. If sio3pack isn't installed with Django
support, it should raise an ImproperlyConfigured exception.
"""
pass
Loading

0 comments on commit f8b49f5

Please sign in to comment.