Problem uploading

Problem sources

Let us consider the most typical use case. A contest admin decides to upload a new problem or modify an existing one. Depending on the OIOIOI installation there could be many sources of the problem. Such a source should inherit from the ProblemSource.

class oioioi.problems.problem_sources.ProblemSource[source]
view(request, contest, existing_problem=None)[source]

Renders the view where the user can upload the file or point out where to get the problem from.

If the request method is GET, it should return rendered HTML, which will be injected in an appropriate div element. TemplateResponse is fine, too.

If the request method is POST, it should start the unpacking process. If no errors occur, it should return HttpResponseRedirect (e.g. to a view with problem packages queued for processing).

Parameters:
  • request – Django request

  • contest – Contest where the problem is going to be attached (or is already attached); may be None.

  • existing_problem – Problem to update (if problem update was requested)

is_available(request)[source]

Returns True if the source is available for the given request.

The complete list of available problem sources can be specified in the deployment/settings.py file under the PROBLEM_SOURCES name. The listed problem sources will be displayed as tabs of the problem upload view, provided that their is_available() method returns True.

Developers are expected to implement their custom problem sources by inheriting from the above-mentioned class, such code should be preferably placed in a problem_sources module in a given app.

Package sources

The most basic problem source is a PackageSource. It may be used when all the data necessary for creating a problem may be uploaded in a single file.

class oioioi.problems.problem_sources.PackageSource[source]
make_form(request, contest, existing_problem=None)[source]

Creates a form, which can be later filled in by the user with information necessary for obtaining the problem package.

If the request method is POST, then the form should be filled with its data.

create_package_instance(user, contest, path, existing_problem=None, original_filename=None)[source]

Creates a ProblemPackage instance from a given package file.

choose_backend(path, original_filename=None)[source]

Returns the dotted name of a ProblemPackageBackend suitable for processing a given package.

This function is called when an unpacking environment is created, i.e. from create_env().

create_env(user, contest, path, package, form, round_id=None, visibility='FR', existing_problem=None, original_filename=None)[source]

Creates an environment which will be later passed to unpackmgr_job().

Since every instance of PackageSource is associated with a file of some kind, the file, together with some additional data, is represented as a separate model, namely the ProblemPackage. Such a design is quite natural when combined with the unpacking manager pipeline, which is described below.

Unpacking manager

When a user uploads a problem via the PackageSource, an unpacking environment is created and passed to a new Celery task, that is to unpackmgr_job().

oioioi.problems.unpackmgr.unpackmgr_job(env)[source]

Creates (or modifies) a Problem instance using a package file represented by a ProblemPackage.

Used env keys:

package_id: id of the ProblemPackage instance to process

backend_name: problem package backend (dotted name) to be used for unpacking

post_upload_handlers: a list of handler functions to be called after the new problem is created

Before the handlers are called, the following env keys are produced:

job_id: the Celery task id

problem_id: id of the ProblemPackage instance, which was created or modified

The above-mentioned post-upload handlers are functions, which accept an environment (a dictionary) as their only argument and return the modified environment. Before the handlers are called, the following new env keys are produced: job_id: the Celery task id problem_id`: id of the ProblemPackage instance, which was created or modified

Normally, when you add a new Problem, you want to attach it to a specific Round of a given Contest. That is why the default implementation of PackageSource specifies one post-upload handler, namely create_problem_instance().

Problem package backends

The PackageSource class defines how problem data should be uploaded by a user, which keys should be present in the unpacking environment and what should be done after the new Problem is created. However, it is not involved in the actual unpacking and processing of the uploaded file. It only chooses an appropriate ProblemPackageBackend (choose_backend()) and delegates this responsibility to it.

oioioi.problems.package

This module contains a problem package backend interface. You should create a package.py file in your new app and implement your package backend (inheriting from ProblemPackageBackend) whenever you introduce a new problem package format.

exception oioioi.problems.package.ProblemPackageError[source]

A generic exception to be used by or subclassed by backends.

exception oioioi.problems.package.PackageProcessingError(func_name, func_doc)[source]
class oioioi.problems.package.ProblemPackageBackend(*args, **kwargs)[source]

A class which manages problem packages.

The main functionality is extracting archives with problem statements, data, model solutions etc. and building Problem instances.

identify(path, original_filename=None)[source]

Checks if the backend is suitable for processing the specified problem package.

Parameters:
  • path – a path to the processed problem package

  • original_filename – the name of the package specified by the

uploading user.

Returns True if the backend can handle the specified problem package file.

get_short_name(path, original_filename=None)[source]

Returns the problem’s short name.

Parameters:
  • path – a path to the processed problem package

  • original_filename – the name of the package specified by the

uploading user.

unpack(env)[source]

Processes a package, creating a new Problem or updating an existing one.

This function will be called either from unpackmgr_job() (Celery task) or from simple_unpack() (e.g. when a problem is added from a command line).

Used env keys:

package_id: an id of the ProblemPackage instance with the package file to unpack.

Produced env keys:

problem_id: an id of the Problem instance representing the created or modified problem.

simple_unpack(filename, existing_problem=None)[source]

This function may be used for unpacking outside unpackmgr.

Parameters:
  • filename – a path to the problem package file

  • existing_problem –

    an instance of Problem to be changed.

    If None, a new Problem is created.

Returns a Problem instance.

pack(problem)[source]

Creates a package from problem, returns a django.http.HttpResponse instance.

Should raise NotImplementedError if creating packages is not supported.

mixins = []

A list of mixins to be automatically mixed in to all instances of the particular class and its subclasses.

exception oioioi.problems.package.NoBackend[source]
oioioi.problems.package.backend_for_package(filename, original_filename=None)[source]

Finds a backend suitable for unpacking the given package and returns its dotted name.

Parameters:
  • filename – a path to the processed problem package

  • original_filename – the name of the package specified by the

uploading user.

oioioi.sinolpack.package

Provides ProblemPackageBackend implementation to deal with Sinol packages - standardized archives with problem data. Sinolpack is OIOIOI standard problem package format. The detailed archive content description can be found here: https://sio2project.mimuw.edu.pl/display/DOC/Preparing+Task+Packages.

class oioioi.sinolpack.package.TaskType(*values)[source]
class oioioi.sinolpack.package.SinolPackageCreator(problem)[source]

Responsible for packing SinolPackages.

pack()[source]
Returns:

Archive from original package if such file exists,

otherwise new archive with test, statements and model solutions.

class oioioi.sinolpack.package.SinolPackageBackend(*args, **kwargs)[source]

Backend that use SinolPackage to unpack and SinolPackageCreator to pack sinol packages.

identify(path, original_filename=None)[source]

Checks if the backend is suitable for processing the specified problem package.

Parameters:
  • path – a path to the processed problem package

  • original_filename – the name of the package specified by the

uploading user.

Returns True if the backend can handle the specified problem package file.

get_short_name(path, original_filename=None)[source]

Returns the problem’s short name.

Parameters:
  • path – a path to the processed problem package

  • original_filename – the name of the package specified by the

uploading user.

unpack(env)[source]

Processes a package, creating a new Problem or updating an existing one.

This function will be called either from unpackmgr_job() (Celery task) or from simple_unpack() (e.g. when a problem is added from a command line).

Used env keys:

package_id: an id of the ProblemPackage instance with the package file to unpack.

Produced env keys:

problem_id: an id of the Problem instance representing the created or modified problem.

pack(problem)[source]

Creates a package from problem, returns a django.http.HttpResponse instance.

Should raise NotImplementedError if creating packages is not supported.

mixins = []

A list of mixins to be automatically mixed in to all instances of the particular class and its subclasses.

config.yml reference

Sinol packages may include a config.yml file in the package root to configure problem settings. Below are the supported keys:

title

The problem’s full name/title.

title_xx (where xx is a language code, e.g. title_en, title_pl)

Language-specific problem title.

sinol_task_id

Task identifier used for validation against the package short name.

time_limit

Global time limit in milliseconds (default: 10000).

time_limits

Dictionary mapping test group names to per-group time limits in milliseconds. Example:

time_limits:
  1: 5000
  2: 10000
memory_limit

Global memory limit in KiB (default: 66000).

memory_limits

Dictionary mapping test group names to per-group memory limits in KiB.

scores

Dictionary mapping test group names to their maximum scores. Example:

scores:
  1: 20
  2: 30
  3: 50
subtask_dependencies

Dictionary defining dependencies between test groups (subtasks). When a group depends on prerequisites, its score is calculated as if it also contained the prerequisite groups’ tests (with scores normalized to the dependent group’s scale). The score can only be lowered, never raised. A warning icon is shown in the report when a dependency lowers the score.

Circular dependencies are not allowed and will be rejected during package upload. Example:

subtask_dependencies:
  2: [1]
  3: [1, 2]

In this example, group 2 depends on group 1, and group 3 depends on both groups 1 and 2.

override_limits

Dictionary mapping programming languages to per-language time/memory limit overrides. Example:

override_limits:
  py:
    time_limit: 20000
    memory_limit: 132000
library

Name of a library file needed during compilation.

extra_compilation_files

List of extra files needed during compilation.

extra_execution_files

Dictionary mapping language codes to lists of files needed during execution.

no_outgen

Boolean flag to disable automatic test output generation.