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 proccess. If no errors occur, it should return HttpResponseRedirect (e.g. to a view with problem packages queued for processing).

Parameters:
  • request – Django request
  • contestContest where the problem is going to be attached (or is already attached); may be None.
  • existing_problemProblem 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(request, 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(request, contest, form, path, package, 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.

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.

class oioioi.problems.package.ProblemPackageBackend[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.

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.