summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md84
-rw-r--r--yaksh/models.py4
-rw-r--r--yaksh/scripts/cli.py114
-rw-r--r--yaksh/scripts/project_detail.py2
4 files changed, 115 insertions, 89 deletions
diff --git a/README.md b/README.md
index 70f1a85..caae485 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ Yaksh
[![Build Status](https://travis-ci.org/FOSSEE/online_test.svg?branch=master)](https://travis-ci.org/FOSSEE/online_test)
[![Documentation Status](https://readthedocs.org/projects/yaksh/badge/?version=latest)](http://yaksh.readthedocs.io/en/latest/?badge=latest)
-To get a hang of the Yaksh interface please refer to the user documentation at [Yaksh Docs] (http://yaksh.readthedocs.io)
+To get an overview of the Yaksh interface please refer to the user documentation at [Yaksh Docs] (http://yaksh.readthedocs.io)
This is a Quickstart guide to help users setup a trial instance. If you wish to deploy Yaksh in a production environment here is a [Production Deployment Guide] (https://github.com/FOSSEE/online_test/blob/master/README_production.md)
@@ -12,14 +12,14 @@ This is a Quickstart guide to help users setup a trial instance. If you wish to
#### Introduction
This project provides an "exam" app that lets users take an online
-programming quiz.
+programming quiz.
#### Features
* Define fairly complicated programming problems and have users
- solve the problem.
- * Immediate verification of code solution.
- * Supports pretty much arbitrary coding questions in Python, C, C++ and
+ solve the problem.
+ * Immediate verification of code solution.
+ * Supports pretty much arbitrary coding questions in Python, C, C++ and
simple Bash and uses "test cases" to test the implementations of the students.
* Supports simple multiple choice questions and File uploads.
* Since it runs on your Python, you could technically test any Python based library.
@@ -29,41 +29,62 @@ programming quiz.
Quick Start
===========
-#### Pre-Requisite
+#### Pre-Requisites
-1. Ensure [pip](https://pip.pypa.io/en/latest/installing.html) is installed
+1. Ensure you have Python available.
+1. Ensure [pip](https://pip.pypa.io/en/latest/installing.html) is installed.
#### Installation
-1. Install the yaksh
+1. Install yaksh
- For latest stable release
-
+
$ pip install yaksh
- For the development version
$ pip install git+https://github.com/FOSSEE/online_test.git
-1. In the terminal run
-
- yaksh create_demo [-p PATH] [project_name]
- - ```project_name``` is the desired name of the django project.
- - In case a ```project_name``` is not specified, the project is initialised with the name ```yaksh_demo```
- - PATH is an optional flag to specify where the django project will be installed
- - If PATH is not provided, the project is created in the current directory
+#### Short instructions
+
+To see a quick demo after installing yaksh do the following:
+
+ $ yaksh create_demo yaksh_demo
+ $ yaksh run yaksh_demo
+
+On another terminal start up the code server that executes the user code safely:
+
+ $ sudo yaksh run_code_server
+
+Now point your browser to ```http://localhost:8000/exam```.
+
+#### More detailed instructions
+
+1. On the terminal run:
+
+ $ yaksh create_demo [project_path]
+
+ - `project_path` is the desired directory of the django project the
+ basename of which is also the Django project name. This can be a
+ relative directory.
+
+ - In case a `project_path` is not specified, the project is created
+ in a `yaksh_demo` subdirectory of the current directory.
1. The script does the following;
- 1. Creates a new django project called `project_name`
- 1. Creates a new demo database
- 1. Creates two users, test moderator and test examinee
- 1. Loads demo questions
- 1. Loads demo quiz
+ 1. Creates a new django project with name as the basename of the specified
+ `project_path`
+ 1. Creates a new demo database.
+ 1. Creates two users, teacher and student.
+ 1. Loads demo questions.
+ 1. Loads demo quiz.
-1. Run:
+1. To run the server, run:
- $ yaksh run_demo
+ $ yaksh run relpath/or/abspath/to/demo
-1. In a new terminal run:
+1. In a new terminal run the following command which executes user submitted
+ code safely:
$ sudo yaksh run_code_server
@@ -77,19 +98,20 @@ Quick Start
1. User can also login to the Default Django admin using;
- Admin - Username: admin | Password: admin
+
History
=======
At FOSSEE, Nishanth had implemented a nice django based app to
test for multiple-choice questions. Prabhu Ramachandran was inspired by a
programming contest that he saw at PyCon APAC 2011. Chris Boesch, who
-administered the contest, used a nice web application
-[Singpath](http://singpath.com) that he had built on top of GAE that
+administered the contest, used a nice web application
+[Singpath](http://singpath.com) that he had built on top of GAE that
basically checked your Python code, live. This made it fun and interesting.
-Prabhu wanted an implementation that was not tied to GAE and hence wrote
-the initial cut of what is now 'Yaksh'. The idea being that
-anyone can use this to test students programming skills and not have to worry
+Prabhu wanted an implementation that was not tied to GAE and hence wrote
+the initial cut of what is now 'Yaksh'. The idea being that
+anyone can use this to test students programming skills and not have to worry
about grading their answers manually and instead do so on their machines.
The application has since been refactored and maintained by FOSSEE Developers.
@@ -110,7 +132,7 @@ information is at the bottom of this file.
Authors
=======
- [FOSSEE Developers] (https://github.com/FOSSEE/online_test/graphs/contributors)
+ [FOSSEE Developers] (https://github.com/FOSSEE/online_test/graphs/contributors)
-Copyright (c) 2011 FOSSEE (fossee.in)
+Copyright (c) 2011-2017 FOSSEE (fossee.in)
diff --git a/yaksh/models.py b/yaksh/models.py
index f5c1129..49ba32a 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -957,10 +957,10 @@ class AnswerPaper(models.Model):
comments = models.TextField()
# Total marks earned by the student in this paper.
- marks_obtained = models.FloatField(null=True, default=None)
+ marks_obtained = models.FloatField(null=True, default=0.0)
# Marks percent scored by the user
- percent = models.FloatField(null=True, default=None)
+ percent = models.FloatField(null=True, default=0.0)
# Result of the quiz, True if student passes the exam.
passed = models.NullBooleanField()
diff --git a/yaksh/scripts/cli.py b/yaksh/scripts/cli.py
index 1489af7..4a58e48 100644
--- a/yaksh/scripts/cli.py
+++ b/yaksh/scripts/cli.py
@@ -6,13 +6,10 @@ import contextlib
import os
from os import path
import argparse
-from importlib import import_module
from django.conf import settings
from django.core import management
from django.template import Template, Context
-from .project_detail import NAME, PATH
-
CUR_DIR = os.getcwd()
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
PARENT_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, os.pardir))
@@ -21,61 +18,68 @@ TEMPLATE_DIR = path.join(PARENT_DIR, 'demo_templates')
settings.configure()
django.setup()
+
def main():
- #Parse command-line to obtain the arguments and/or options
+ # Parse command-line to obtain the arguments and/or options
# create top-level parser object
parser = argparse.ArgumentParser(prog="yaksh")
subparser = parser.add_subparsers(dest="subcommand")
# create parser for the "create_demo" subcommand
- create_demo_parser = subparser.add_parser("create_demo",
- help="Create a new demo Django project")
- create_demo_parser.add_argument("project_name", type=str,
- default="yaksh_demo",
- nargs="?",
- help="name of demo Django project")
- create_demo_parser.add_argument("-p", "--path", type=str,
- help="path of demo Django project")
-
+ create_demo_parser = subparser.add_parser(
+ "create_demo",
+ help="Create a new demo Django project"
+ )
+ create_demo_parser.add_argument(
+ "path", type=str,
+ default=path.join(CUR_DIR, "yaksh_demo"),
+ nargs="?",
+ help="Path to the demo Django project (defaults to 'yaksh_demo')"
+ )
+
# create parser for the "run_demo" subcommand
- run_demo_parser = subparser.add_parser("run_demo",
- help="Initialise django server and run the demo project")
+ run_parser = subparser.add_parser(
+ "run",
+ help="Initialise django server and run the demo project"
+ )
+ run_parser.add_argument(
+ "path", type=str, nargs=1,
+ help="full path to the demo yaksh project"
+ )
# create parser for the "run_code_server" subcommand
- code_server_parser = subparser.add_parser("run_code_server",
- help="Initialise yaksh code server")
- code_server_parser.add_argument("-P", "--ports", type=int, nargs='+',
- help="code server ports")
+ code_server_parser = subparser.add_parser(
+ "run_code_server",
+ help="Initialise yaksh code server"
+ )
+ code_server_parser.add_argument("-P", "--ports", type=int, nargs='+',
+ help="code server ports")
args = parser.parse_args()
if args.subcommand == "create_demo":
- if args.path:
- create_demo(args.project_name, args.path)
- else:
- create_demo(args.project_name)
-
- elif args.subcommand == "run_demo":
- try:
- run_demo(NAME, PATH)
- except Exception as e:
- if not NAME or not PATH:
- print("Error: Unable to find Project Name or Path variables\n")
- else:
- print("Error: {0}\n".format(e))
- subparser.print_help()
-
+ pth = path.abspath(args.path)
+ name = path.basename(pth)
+ create_demo(name, pth)
+ elif args.subcommand == "run":
+ pth = path.abspath(args.path[0])
+ name = path.basename(pth)
+ run_demo(name, pth)
elif args.subcommand == "run_code_server":
if args.ports:
run_server(args.ports)
else:
run_server()
+
def create_demo(project_name='yaksh_demo', project_dir=CUR_DIR):
+ if not path.exists(project_dir):
+ os.makedirs(project_dir)
try:
management.call_command('startproject', project_name, project_dir)
- print("Demo Django project '{0}' created at '{1}'".format(project_name,
- project_dir))
+ print("Demo Django project '{0}' created at '{1}'".format(
+ project_name, project_dir)
+ )
except Exception as e:
print("Error: {0}\nExiting yaksh Installer".format(e))
@@ -87,50 +91,50 @@ def create_demo(project_name='yaksh_demo', project_dir=CUR_DIR):
project_path = path.join(top_dir, project_name)
fixture_dir = path.join(PARENT_DIR, 'fixtures')
fixture_path = path.join(fixture_dir, 'demo_fixtures.json')
- # Store project details
- _set_project_details(project_name, top_dir)
with _chdir(project_path):
root_urlconf = "{0}.{1}".format(project_name, 'demo_urls')
settings_template_path = path.join(TEMPLATE_DIR, 'demo_settings.py')
settings_target_path = path.join(project_path, 'demo_settings.py')
settings_context = Context({'project_name': project_name,
- 'root_urlconf': root_urlconf,
- 'fixture_dir': fixture_dir})
+ 'root_urlconf': root_urlconf,
+ 'fixture_dir': fixture_dir})
urls_template_path = path.join(TEMPLATE_DIR, 'demo_urls.py')
urls_target_path = path.join(project_path, 'demo_urls.py')
command = ("python ../manage.py migrate --run-syncdb "
- "--noinput --settings={0}.demo_settings").format(project_name)
+ "--noinput --settings={0}.demo_settings").format(
+ project_name)
loaddata_command = ("python ../manage.py loaddata "
- "--settings={0}.demo_settings {1}").format(project_name, fixture_path)
+ "--settings={0}.demo_settings {1}").format(
+ project_name, fixture_path)
# Create demo_settings file
- _render_demo_files(settings_template_path, settings_target_path, settings_context)
- # Create demo_urls file
+ _render_demo_files(
+ settings_template_path, settings_target_path, settings_context
+ )
+ # Create demo_urls file
_render_demo_files(urls_template_path, urls_target_path)
# Run syncdb
- subprocess.call("{0}; {1}".format(command, loaddata_command), shell=True)
+ subprocess.call(
+ "{0}; {1}".format(command, loaddata_command), shell=True
+ )
+
def run_demo(project_name, top_dir):
with _chdir(top_dir):
- project_path = path.join(top_dir, 'manage.py')
command = ("python manage.py runserver "
- "--settings={0}.demo_settings").format(project_name)
+ "--settings={0}.demo_settings").format(project_name)
subprocess.call(command, shell=True)
-def run_server():
+
+def run_server(args=None):
try:
from yaksh import code_server
- code_server.main()
+ code_server.main(args)
except Exception as e:
print("Error: {0}\nExiting yaksh code server".format(e))
-def _set_project_details(project_name, top_dir):
- file_path = path.join(SCRIPT_DIR, 'project_detail.py')
- detail = "NAME ='{0}'\nPATH ='{1}'".format(project_name, top_dir)
- with open(file_path, 'w') as data_store:
- data_store.write(detail)
def _render_demo_files(template_path, output_path, context=None):
with open(template_path, 'r') as template_file:
@@ -142,6 +146,7 @@ def _render_demo_files(template_path, output_path, context=None):
with open(output_path, 'w') as new_file:
new_file.write(content)
+
@contextlib.contextmanager
def _chdir(path):
starting_directory = os.getcwd()
@@ -151,5 +156,6 @@ def _chdir(path):
finally:
os.chdir(starting_directory)
+
if __name__ == '__main__':
main()
diff --git a/yaksh/scripts/project_detail.py b/yaksh/scripts/project_detail.py
deleted file mode 100644
index 583e9f4..0000000
--- a/yaksh/scripts/project_detail.py
+++ /dev/null
@@ -1,2 +0,0 @@
-NAME = None
-PATH = None