# CodeQ: an online programming tutor. # Copyright (C) 2015 UL FRI # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU Affero General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more # details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import sys import importlib.machinery import threading import os.path import logging _path_prefix = os.environ.get('CODEQ_PROBLEMS') or '/var/local/codeq-problems' _module_loading_lock = threading.RLock() # TODO: make a more fine-grained locking import machinery def load_module(fullname): # return importlib.import_module(fullname) with _module_loading_lock: mod = sys.modules.get(fullname, None) if mod is None: parts = fullname.split('.') d = os.path.join(_path_prefix, *parts[:-1]) ff = importlib.machinery.FileFinder(d, (importlib.machinery.SourceFileLoader, ['.py'])) spec = ff.find_spec(fullname) if spec is None: logging.error('ERROR: there is no problem module {0}'.format(fullname)) return None mod = type(sys)(fullname) mod.__loader__ = spec.loader mod.__package__ = spec.parent mod.__spec__ = spec if spec.has_location: mod.__file__ = spec.origin mod.__cached__ = spec.cached sys.modules[fullname] = mod try: spec.loader.exec_module(mod) except: try: del sys.modules[fullname] except KeyError: pass raise return mod def load_language(language, tail_module): return load_module('{0}.{1}'.format(language, tail_module)) def load_group(language, problem_group, tail_module): return load_module('{0}.problems.{1}.{2}'.format(language, problem_group, tail_module)) def load_problem(language, problem_group, problem, tail_module): return load_module('{0}.problems.{1}.{2}.{3}'.format(language, problem_group, problem, tail_module)) def load_facts(language, fact_module): return load_module('{0}.facts.{1}'.format(language, fact_module)) def load_file(language, group, problem, name): path = os.path.join(_path_prefix, language, 'problems', group, problem, name) try: with open(path, 'r') as f: return f.read() except: return None def load_problems(language, tuples, tail_module): modules = [] for problem_group, problem in tuples: mod = '{0}.problems.{1}.{2}.{3}'.format(language, problem_group, problem, tail_module) modules.append(load_module(mod)) return modules def get_facts(language, problem_module): try: facts = problem_module.facts except AttributeError as e: return '' if facts is None: return '' module = load_facts(language, facts) if module: try: return module.facts except AttributeError as e: return '' return '' def solutions_for_problems(language, tuples): if not tuples: return '' modules = load_problems(language, tuples, 'common') solutions = [] for module in modules: try: solutions.append(module.solution) except AttributeError as me: pass return '\n'.join(solutions)