Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:

- run:
name: "Tests: Run unit/integration tests (excluding e2e)"
command: docker compose exec django py.test src/ -m "not e2e"
command: docker compose exec django py.test src/

# We give the name of the test files manually because we need test_auth.py to be run before the others for state.json file to be created
# CI="true" to skip some tests that fail in the CI for now
Expand Down
6 changes: 4 additions & 2 deletions compute_worker/compute_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ def rewrite_bundle_url_if_needed(url):
# -----------------------------------------------------------------------------
@shared_task(name="compute_worker_run")
def run_wrapper(run_args):
# We need to convert the UUID given by celery into a byte like object otherwise things will break
run_args.update(secret=str(run_args["secret"]))
logger.info(f"Received run arguments: \n {colorize_run_args(json.dumps(run_args))}")
run = Run(run_args)

Expand Down Expand Up @@ -1183,20 +1185,20 @@ def start(self):

logger.info("Running scoring program, and then ingestion program")
loop = asyncio.new_event_loop()

gathered_tasks = asyncio.gather(
self._run_program_directory(program_dir, kind="program"),
self._run_program_directory(ingestion_program_dir, kind="ingestion"),
self.watch_detailed_results(),
loop=loop,
return_exceptions=True,
)

task_results = [] # will store results/exceptions from gather
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(self.execution_time_limit)
try:
# run tasks
# keep what gather returned so we can detect async errors later
loop = asyncio.get_event_loop()
task_results = loop.run_until_complete(gathered_tasks) or []
except ExecutionTimeLimitExceeded:
error_message = f"Execution Time Limit exceeded. Limit was {self.execution_time_limit} seconds"
Expand Down
17 changes: 9 additions & 8 deletions compute_worker/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@
authors = [
{name = "codalab"},
]
requires-python = "==3.9.20"
requires-python = "==3.13.11"
dependencies = [
"celery==5.2.2",
"celery==5.6.2",
"requests>=2.32.4,<3",
"watchdog==2.1.1",
"argh==0.26.2",
"websockets==9.1",
"aiofiles==0.4.0",
"pyyaml==6.0.1",
"watchdog==6.0.0",
"argh==0.31.3",
"websockets==16.0.0",
"aiofiles==25.1.0",
"pyyaml==6.0.3",
"loguru>=0.7.3,<0.8",
"docker>=7.1.0,<8",
"rich>=14.2.0,<15",
"setuptools>=82.0.0",
]

name = "compute-worker"
version = "0.1.0"
description = ""
description = ""
220 changes: 126 additions & 94 deletions compute_worker/uv.lock

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ services:
# Web Services
#----------------------------------------------------------------------------------------------------
caddy:
image: caddy:2.10.0
image: caddy:2.11.1
env_file: .env
environment:
- ACME_AGREE=true
Expand All @@ -22,9 +22,11 @@ services:
- django

django:
container_name: django
build:
context: .
dockerfile: packaging/container/Containerfile
image: django_site-worker
# NOTE: We use watchmedo to reload gunicorn nicely, Uvicorn + Gunicorn reloads don't work well
command: ["python manage.py migrate --no-input && python manage.py collectstatic --no-input && cd /app/src && watchmedo auto-restart -p '*.py' --recursive -- python3 ./gunicorn_run.py"]
environment:
Expand Down Expand Up @@ -95,6 +97,7 @@ services:
# Local development helper, rebuilds RiotJS/Stylus on change
#----------------------------------------------------------------------------------------------------
builder:
container_name: builder
build:
context: .
dockerfile: packaging/container/Containerfile.builder
Expand All @@ -115,6 +118,7 @@ services:
#----------------------------------------------------------------------------------------------------
db:
image: postgres:18-alpine
container_name: db
env_file: .env
environment:
- PGDATA=/var/lib/postgresql/18/docker
Expand All @@ -136,6 +140,7 @@ services:
# Rabbitmq & Flower monitoring tool
#----------------------------------------------------------------------------------------------------
rabbit:
container_name: rabbit
build:
context: .
dockerfile: packaging/container/Containerfile.rabbitmq
Expand All @@ -161,6 +166,7 @@ services:
max-file: "5"

flower:
container_name: flower
image: mher/flower
env_file: .env
environment:
Expand All @@ -179,6 +185,7 @@ services:
# Redis
#----------------------------------------------------------------------------------------------------
redis:
container_name: redis
image: redis
ports:
- 6379:6379
Expand All @@ -195,9 +202,8 @@ services:
# This auto-reloads
command: ["watchmedo auto-restart -p '*.py' --recursive -- celery -A celery_config worker -B -Q site-worker -l info -n site-worker@%n --concurrency=2"]
working_dir: /app/src
build:
context: .
dockerfile: packaging/container/Containerfile
container_name: site_worker
image: django_site-worker
depends_on:
- rabbit
- db
Expand All @@ -219,6 +225,7 @@ services:
compute_worker:
command: ["celery -A compute_worker worker -l info -Q compute-worker -n compute-worker@%n"]
working_dir: /app
container_name: compute_worker
build:
context: .
dockerfile: packaging/container/Containerfile.compute_worker
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"name": "competitions-v2",
"version": "0.0.1",
"dependencies": {
"jquery": "^3.2.1",
"npm-watch": "^0.2.0",
"riot": "^3.6.3",
"stylus": "^0.54.5",
"uglify-js": "^3.0.28"
"jquery": "^4.0.0",
"npm-watch": "^0.13.0",
"riot": "^3.13.2",
"stylus": "^0.64.0",
"uglify-js": "^3.19.3"
},
"devDependencies": {},
"watch": {
Expand Down
84 changes: 42 additions & 42 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "codabench"
version = "0.1.0"
description = ""
authors = [{ name = "Codalab" }]
requires-python = ">=3.10,<3.11"
requires-python = "==3.13.11"
readme = "README.md"
classifiers = [
"Programming Language :: Python :: 3",
Expand All @@ -13,29 +13,26 @@ dependencies = [
"django>=4.2.0,<5",
"django-oauth-toolkit==1.6.3",
"django-cors-middleware==1.5.0",
"social-auth-core>=4.1.0,<5",
"social-auth-app-django>=5.0.0,<6",
"six==1.16.0",
"django-extensions>=3.2,<4",
"channels==4.2.0",
"social-auth-core==4.8.5",
"social-auth-app-django==5.4.3",
"django-extensions==4.1.0",
"channels==4.3.2",
"channels-redis==4.0.0",
"pillow==10.3.0",
"celery==4.4.7",
"gunicorn==22.0.0",
"urllib3>=1.25.4,<1.27",
"uvicorn>=0.22.0,<0.23",
"pyyaml==5.3.1",
"watchdog==2.1.1",
"argh==0.26.2",
"python-dateutil==2.7.3",
"bpython>=0.21.0,<0.22",
"websockets>=10.4.0,<11",
"aiofiles==0.4.0",
"oyaml==0.7",
"pillow==12.1.1",
"celery==5.6.2",
"gunicorn==23.0",
"urllib3==2.6.3",
"uvicorn==0.38",
"pyyaml==6.0.3",
"watchdog==6.0.0",
"argh==0.31.3",
"python-dateutil==2.9.0",
"bpython==0.26",
"websockets==16.0.0",
"aiofiles==25.1.0",
"oyaml==1.0",
"factory-boy==2.11.1",
"bleach>=5.0.0",
"django-debug-toolbar==3.2",
"django-querycount==0.7.0",
"bleach==6.3.0",
"blessings==1.7",
"django-su>=1.0.0,<2",
"django-ajax-selects==2.0.0",
Expand All @@ -45,29 +42,30 @@ dependencies = [
"django-storages[azure]>=1.14.6,<2",
"azure-storage-blob>=12,<13",
"azure-storage-common==2.1.0",
"boto3==1.26.76",
"whitenoise==5.2.0",
"djangorestframework>=3.13.0",
"boto3==1.42.50",
"whitenoise==6.11.0",
"djangorestframework==3.16.1",
"djangorestframework-csv==3.0.1",
"drf-extensions==0.4.0",
"markdown==2.6.11",
"pygments==2.2.0",
"drf-writable-nested==0.6.2",
"django-filter==2.4.0",
"flex==6.12.0",
"markdown==3.10.2",
"pygments==2.19.2",
"drf-writable-nested==0.7.2",
"flex==6.14.1",
"pyrabbit2==1.0.7",
"django-enforce-host==1.0.1",
"twisted==24.7.0",
"ipdb==0.13",
"jinja2==3.1.4",
"requests==2.32.2",
"drf-extra-fields>=3.5.0",
"botocore==1.29.76",
"s3transfer==0.6.0",
"django-enforce-host==1.1.0",
"twisted==25.5.0",
"ipdb==0.13.13",
"jinja2==3.1.6",
"requests==2.32.5",
"drf-extra-fields==3.7.0",
"botocore==1.42.50",
"s3transfer==0.16.0",
"drf-spectacular>=0.28.0,<0.29",
"coreapi>=2.3.3,<3",
"loguru>=0.7.3,<0.8",
"tzdata>=2025.3",
"setuptools==82.0.0",
"pytz>=2025.2",
"django-filter==25.1",
]

[tool.uv]
Expand All @@ -79,9 +77,11 @@ build-backend = "uv_build"

[dependency-groups]
dev = [
"flake8>=3.8.4",
"pytest==7.4.4",
"pytest-django==4.11.1",
"django-querycount==0.7.0",
"django-debug-toolbar==6.2.0",
"flake8==7.3.0",
"pytest==9.0.2",
"pytest-django==4.12.0",
]
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "settings.develop" # Just "settings" since pytest will be running from src/
Expand Down
7 changes: 0 additions & 7 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,3 @@ isort-show-traceback = True
# E501 -- line too long
# F405 -- name may be undefined, or defined from star imports
# E402 -- module level import not at top of file

[tool:pytest]
addopts = --ds=settings.test --reuse-db
python_paths = src/
testpaths =
src/apps
src/tests
3 changes: 1 addition & 2 deletions src/apps/api/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import binascii
import json

import six
from django.core.files.base import ContentFile
from drf_extra_fields.fields import Base64ImageField
from rest_framework.exceptions import ValidationError
Expand Down Expand Up @@ -36,7 +35,7 @@ def to_internal_value(self, named_json_data):
file_name = data["file_name"]
base64_data = data["data"]

if isinstance(base64_data, six.string_types):
if isinstance(base64_data, str):
# Strip base64 header.
if ';base64,' in base64_data:
header, base64_data = base64_data.split(';base64,')
Expand Down
40 changes: 1 addition & 39 deletions src/apps/api/views/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import os
import datetime
import coreapi
import pytz
import logging
logger = logging.getLogger(__name__)
Expand All @@ -26,42 +25,6 @@
delete_orphan_files_task = None


class SimpleFilterBackend(BaseFilterBackend):
def get_schema_fields(self, view):
fields = [
coreapi.Field(
name='start_date',
location='query',
required=True,
type='string',
description='Beginning of query interval (inclusive) (YYYY-MM-DD format string)'
),
coreapi.Field(
name='end_date',
location='query',
required=True,
type='string',
description='End of query interval (exclusive) (YYYY-MM-DD format string)'
),
coreapi.Field(
name='time_unit',
location='query',
required=True,
type='string',
description='Unit of time (choose 1 of month, week, or day)'
),
coreapi.Field(
name='format',
location='query',
required=False,
type='string',
description='If csv data is desired set format=csv, otherwise do not set.'
),
]

return fields


def merge_dicts(d1, d2):
d = {**d1, **d2}
return d
Expand Down Expand Up @@ -111,7 +74,7 @@ class AnalyticsView(APIView):
Return the total number of users joined, competitions created, published competitions created, and submissions made within a given time interval. Also returns the number of comps, users, and subs created within the time range for each time unit.
"""

filter_backends = (SimpleFilterBackend,)
filter_backends = (BaseFilterBackend,)
renderer_classes = (JSONRenderer, AnalyticsRenderer,)

def get(self, request):
Expand Down Expand Up @@ -399,7 +362,6 @@ def check_orphans_deletion_status(request):
if not request.user.is_superuser:
raise PermissionDenied(detail="Admin only")

global delete_orphan_files_task
state = None
if delete_orphan_files_task:
state = delete_orphan_files_task.state
Expand Down
2 changes: 1 addition & 1 deletion src/apps/api/views/competitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ class CompetitionParticipantViewSet(ModelViewSet):
queryset = CompetitionParticipant.objects.all()
serializer_class = CompetitionParticipantSerializer
filter_backends = (DjangoFilterBackend, SearchFilter)
filter_fields = ('user__username', 'user__email', 'status', 'competition', 'user__is_deleted')
filterset_fields = ('user__username', 'user__email', 'status', 'competition', 'user__is_deleted')
search_fields = ('user__username', 'user__email',)

def get_queryset(self):
Expand Down
Loading