# coding=utf-8 import multiprocessing.managers import threading import server.user_session from db.models import Problem from . import problems __all__ = ['PythonSession'] class PythonSession(object): """Abstracts a Python session. Only public methods are available to the outside world due to the use of multiprocessing managers. Therefore prefix any private methods with an underscore (_). No properties are accessible; use getters and setters instead. Values are passed by value instead of by reference (deep copy!). """ def __init__(self): self._access_lock = threading.Lock() self._interpreter = None # Proxy for calling the Python runner. We use a separate connection for # each session so the runner can be restarted without affecting the # server. _m = multiprocessing.managers.BaseManager(address=('localhost', 3031), authkey=b'c0d3q3y-python') _m.register('Python') _m.connect() self._python = _m.Python() def run(self, code=None, inputs=None, timeout=1.0): with self._access_lock: return self._python.run(code, inputs, timeout) def create(self): with self._access_lock: if self._interpreter is None: self._interpreter = self._python.create() def pull(self): with self._access_lock: if self._interpreter is None: return 'Python is not running' return self._python.pull(self._interpreter) def push(self, stdin): with self._access_lock: if self._interpreter is not None: self._python.push(self._interpreter, stdin) def destroy(self): with self._access_lock: if self._interpreter is not None: self._python.destroy(self._interpreter) self._interpreter = None def __del__(self): # no locking needed if GC is removing us, as there cannot be any concurrent access by definition if hasattr(self, '_interpreter') and self._interpreter is not None: self._python.destroy(self._interpreter) self._interpreter = None def hint(self, sid, problem_id, program): session = server.user_session.get_session_by_id(sid) language, problem_group, problem = Problem.get_identifier(problem_id) problem_module = problems.load_problem(language, problem_group, problem, 'common') # Try problem-specific hints. if hasattr(problem_module, 'hint'): hints = problem_module.hint(session, program) if hints: return hints # Finally return a generic "try thinking a bit" message. return [{'id': 'no_hint'}] def test(self, sid, problem_id, program): session = server.user_session.get_session_by_id(sid) language, problem_group, problem = Problem.get_identifier(problem_id) problem_module = problems.load_problem(language, problem_group, problem, 'common') try: n_correct, n_all = problem_module.test(session, program) return [{'id': 'test_results', 'args': {'passed': n_correct, 'total': n_all}}] except AttributeError as ex: return [{'id': 'test_results', 'args': {'passed': 0, 'total': 0}}]