class HTMLDiff(difflib.HtmlDiff):
    FROM_DESC = 'Correct Output'
    TO_DESC = 'Your Output'
    TD_DIFF_HEADER = '<td class="diff_header"{0}>{1}</td>\
    <td style="white-space:nowrap{2}">{3}</td>'
    SHOW_HIDE_INSTRUMENTATION = "<p>" + \
        """\t<a href="javascript:void(0)" onclick="showAll(""" + \
        """'difflib_chg_{0}_top');">Show All</a>\n""" + \
        """\t<a href="javascript:void(0)" onclick="hideAll(""" + \
        """'difflib_chg_{0}_top');">Hide All</a>\n""" + \
        "</p>"
    FAILING_BLOCK = '\n'.join(['<div class="well well-small" id="{}">',
                               '  <h4>{}: {}</h4>', '  {}', '</div>'])
    NEXT_ID_CHANGE = ' id="difflib_chg_{0}_{1}"'
    NEXT_HREF = '<a href="#difflib_chg_{0}_{1}">n</a>'
    NEXT_HREF_TOP = '<a href="#difflib_chg_{0}_top">t</a>'
    NEXT_ID_SAME = ' id="difflib_same_{0}{1}_{2}"'
    SHOW_HIDE_ROWS = \
        '<a href="javascript:void(0)" onclick="showHideRows(this);">h</a>'
    NO_DIFFERENCES = '<td></td><td>&nbsp;No Differences Found&nbsp;</td>'
    EMPTY_FILE = '<td></td><td>&nbsp;Empty File&nbsp;</td>'
    MAX_SAME_LINES_BEFORE_SHOW_HIDE = 5  # must be >= 4

    def __init__(self, points_possible=0, num_reveal_limit=MAX_NUM_REVEALS):
        super(HTMLDiff, self).__init__(wrapcolumn=LINE_WRAP)
        self._legend = _legend
        self._table_template = _table_template
        self._file_template = _file_template
        self._last_collapsed = False
        self._mapping = {}  # maps a renderable to html
        self._num_reveal_limit = num_reveal_limit
        self._points_possible = points_possible
        self._show_legend = False

    def add_renderable(self, renderable):
        value = renderable.custom_output
        if renderable.show_diff_table():
            self._show_legend = True
            self._last_collapsed = False
            table = self.make_table(renderable)
            if self._last_collapsed:
                show_hide = self.SHOW_HIDE_INSTRUMENTATION.format(
                    self._prefix[1])
                table = '{0}{1}{0}'.format(show_hide, table)
            value += table
        name = renderable.name
        issue = renderable.get_issue()
        if issue:
            name += '  -- {}'.format(issue)
        self._mapping[renderable] = None if not (value or issue) else \
            self.FAILING_BLOCK.format(renderable.id, renderable.group, name,
                                      value)

    def make_table(self, renderable):
        """Makes unique anchor prefixes so that multiple tables may exist
        on the same page without conflict."""
        self._make_prefix()
        diffs = renderable.diff._diff

        # set up iterator to wrap lines that exceed desired width
        if self._wrapcolumn:
            diffs = self._line_wrapper(diffs, renderable.diff.hide_expected)

        # collect up from/to lines and flags into lists (also format the lines)
        fromlist, tolist, flaglist = self._collect_lines(diffs)

        # process change flags, generating middle column of next anchors/links
        fromlist, tolist, flaglist, next_href, next_id = self._convert_flags(
            fromlist, tolist, flaglist, False, 5)

        s = []
        fmt = '            <tr><td class="diff_next"%s>%s</td>%s' + \
              '<td class="diff_next">%s</td>%s</tr>\n'
        for i in range(len(flaglist)):
            if flaglist[i] is None:
                # mdiff yields None on separator lines skip the bogus ones
                # generated for the first line
                if i > 0:
                    s.append('        </tbody>        \n        <tbody>\n')
            else:
                s.append(fmt % (next_id[i], next_href[i], fromlist[i],
                                next_href[i], tolist[i]))
        header_row = '<thead><tr>%s%s%s%s</tr></thead>' % (
            '<th class="diff_next"><br /></th>',
            '<th colspan="2" class="diff_header">%s</th>' % self.FROM_DESC,
            '<th class="diff_next"><br /></th>',
            '<th colspan="2" class="diff_header">%s</th>' % self.TO_DESC)

        table = self._table_template % dict(
            data_rows=''.join(s),
            header_row=header_row,
            prefix=self._prefix[1])

        return table.replace('\0+', '<span class="diff_add">'). \
            replace('\0-', '<span class="diff_sub">'). \
            replace('\0^', '<span class="diff_chg">'). \
            replace('\1', '</span>'). \
            replace('\t', '&nbsp;')

    def _format_line(self, side, flag, linenum, text):
        """Returns HTML markup of "from" / "to" text lines

        side -- 0 or 1 indicating "from" or "to" text
        flag -- indicates if difference on line
        linenum -- line number (used for line number column)
        text -- line text to be marked up
        """
        try:
            linenum = '%d' % linenum
            id = ' id="%s%s"' % (self._prefix[side], linenum)
        except TypeError:
            # handle blank lines where linenum is '>' or ''
            id = ''
        # replace those things that would get confused with HTML symbols
        text = text.replace("&", "&amp;"). \
            replace(">", "&gt;"). \
            replace("<", "&lt;")

        # make space non-breakable so they don't get compressed or line wrapped
        text = text.replace(' ', '&nbsp;').rstrip()

        color = ''
        if '\0^' in text or '\0+' in text or '\0-' in text:
            color = ';background-color:{0}'
            if side == 0:
                color = color.format('#ffe6e6')
            else:
                color = color.format('#e3ffe3')
        return self.TD_DIFF_HEADER.format(id, linenum, color, text)

    def _make_test_summary(self):
        """Return html tables for failed and passed tests."""
        template = ('<div class="pull-left well well-small">'
                    '<h3 style="color:{2}">{0} Tests</h3>'
                    '<table border="1">\n  <tr><th>Test Group</th>'
                    '<th>Test Name</th><th>Value</th></tr>{1}</table></div>')
        failed = passed = ''
        for diff, html in sorted(self._mapping.items()):
            if html:
                failed += diff.html_header_row()
            else:
                passed += diff.html_header_row()

        output = ''
        if passed:
            output += template.format('Passed', passed, 'green')
        if failed:
            output += template.format('Failed', failed, 'red')
        if self._show_legend:
            output += ('<div class="pull-left well well-small">{}</div>'
                       .format(self._legend))
        return '<div class="row-fluid">{}</div>'.format(output)

    def make_whole_file(self):
        tables = [x[1] for x in sorted(self._mapping.items()) if x[1]]
        return self._file_template % {'summary': self._make_test_summary(),
                                      'table': '\n'.join(tables)}

    def _line_wrapper(self, diffs, hide_expected):
        diffs = limit_revealed_lines_to(diffs, self._num_reveal_limit,
                                        hide_expected)
        return super(HTMLDiff, self)._line_wrapper(diffs)

    def _make_prefix(self):
        sameprefix = "same{0}_".format(HTMLDiff._default_prefix)
        super(HTMLDiff, self)._make_prefix()
        self._prefix.append(sameprefix)

    def _convert_flags(self, fromlist, tolist, flaglist, context, numlines):
        """Handles making inline links in the document."""

        # all anchor names will be generated using the unique "to" prefix
        toprefix = self._prefix[1]
        sameprefix = self._prefix[2]

        # process change flags, generating middle column of next anchors/links
        next_id = [''] * len(flaglist)
        next_href = [''] * len(flaglist)
        (change_positions, same_positions) = \
            change_same_starting_points(flaglist)
        change_positions_set = set(change_positions)

        for numChange, changePos in enumerate(change_positions[: -1]):
            next_id[changePos] = self.NEXT_ID_CHANGE.format(
                toprefix, numChange)
            next_href[changePos] = self.NEXT_HREF.format(
                toprefix, numChange + 1)

        for same_block, same_start_pos in enumerate(same_positions):
            same_pos = same_start_pos
            while same_pos < len(flaglist) and \
                    same_pos not in change_positions_set:
                next_id[same_pos] = self.NEXT_ID_SAME.format(
                    sameprefix, same_block,
                    same_pos - same_start_pos + 1)
                same_pos += 1
            num_same_lines = same_pos - same_start_pos
            if num_same_lines > self.MAX_SAME_LINES_BEFORE_SHOW_HIDE:
                next_href[same_start_pos + 2] = self.SHOW_HIDE_ROWS
                self._last_collapsed = True

        # check for cases where there is no content to avoid exceptions
        if not flaglist:
            flaglist = [False]
            next_id = ['']
            next_href = ['']
            if context:
                fromlist = [self.NO_DIFFERENCES]
                tolist = fromlist
            else:
                fromlist = tolist = [self.EMPTY_FILE]

        # redo the last link to link to the top
        if change_positions:
            pos = change_positions[-1]
            next_id[pos] = self.NEXT_ID_CHANGE.format(
                toprefix, len(change_positions) - 1)
            next_href[pos] = self.NEXT_HREF_TOP.format(toprefix)

        return fromlist, tolist, flaglist, next_href, next_id class GroupWithException(SubmitException):

    """Indicates there are too many users to join a group.""" class InvalidId(SubmitException):

    """Indicates that the id to fetch doesn't exist.""" class SubmitException(Exception):

    """Superclass for all Submit exceptions.""" class AccessibleDBThing(DBThing):

    """An extension of DBThing that also checks for accessibility.

    Usage of this validator assumes the Thing class has a `can_acess` method
    that takes as a sole argument a User object.

    """

    def run(self, value, errors, request):
        """Return thing, but abort validation if request.user cannot edit."""
        thing = super(AccessibleDBThing, self).run(value, errors, request)
        if errors:
            return None
        if not thing.can_access(request.user):
            message = 'Insufficient permissions for {0}'.format(self.param)
            raise HTTPForbidden(message)
        return thing class DBThing(Validator):

    """A validator that converts a primary key into the database object."""

    def __init__(self, param, cls, fetch_by=None, validator=None,
                 **kwargs):
        super(DBThing, self).__init__(param, **kwargs)
        self.cls = cls
        self.fetch_by = fetch_by
        self.id_validator = validator if validator else TextNumber(param,
                                                                   min_value=0)

    def run(self, value, errors, request):
        """Return the object if valid and available, otherwise None."""
        value = self.id_validator(value, errors, request)
        if errors:
            return None
        if self.fetch_by:
            thing = self.cls.fetch_by(**{self.fetch_by: value})
        else:
            thing = self.cls.fetch_by_id(value)
        if not thing and self.source == SOURCE_MATCHDICT:
            # If part of the URL we should have a not-found error
            raise HTTPNotFound()
        elif not thing:
            self.add_error(errors, 'Invalid {0}'
                           .format(self.cls.__name__))
        return thing class DummyTemplateAttr(object):
    def __init__(self, default=None):
        self.default = default

    def __getattr__(self, attr):
        return self.default class EditableDBThing(DBThing):

    """An extension of DBThing that also checks for edit access.

    Usage of this validator assumes the Thing class has a `can_edit` method
    that takes as a sole argument a User object.

    """

    def run(self, value, errors, request):
        """Return thing, but abort validation if request.user cannot edit."""
        thing = super(EditableDBThing, self).run(value, errors, request)
        if errors:
            return None
        if not thing.can_edit(request.user):
            message = 'Insufficient permissions for {0}'.format(self.param)
            raise HTTPForbidden(message)
        return thing class TestableStatus(object):
    def __init__(self, testable, testable_result, verification_errors):
        self.issue = None
        self.errors = {x: y for (x, y) in verification_errors.items()
                       if testable.requires_file(x)}
        self.show_make_output = False
        self.testable = testable
        self.testable_result = testable_result

        if testable_result:
            if testable_result.status == 'make_failed':
                self.issue = 'Build failed'
                self.show_make_output = True
            elif testable_result.status == 'nonexistent_executable':
                self.issue = ('The expected executable was not created during '
                              'the build process')
        else:
            self.issue = ('One or more of the required files did not pass '
                          'verification (see below)')

    def __cmp__(self, other):
        return cmp(self.testable, other.testable) class TextDate(Validator):

    """A validator that converts a string into a tz-enabled datetime object."""

    def run(self, value, errors, _):
        if not isinstance(value, unicode):
            self.add_error(errors, 'must be a unicode string')
            return value
        try:
            return dateutil.parser.parse(value)
        except ValueError:
            self.add_error(errors, 'is not a valid datetime format')
            return value class ViewableDBThing(DBThing):

    """An extension of DBThing that also checks for view access.

    Usage of this validator assumes the Thing class has a `can_view` method
    that takes as a sole argument a User object.

    """

    def run(self, value, errors, request):
        """Return thing, but abort validation if request.user cannot view."""
        thing = super(ViewableDBThing, self).run(value, errors, request)
        if errors:
            return None
        if not thing.can_view(request.user):
            message = 'Insufficient permissions for {0}'.format(self.param)
            raise HTTPForbidden(message)
        return thing class UmailAddress(EmailAddress):

    """A validator to verify that a umail address is correct."""

    def run(self, value, errors, request, *args):
        retval = super(UmailAddress, self).run(value.lower(), errors, request,
                                               *args)
        if errors:
            return retval
        if not retval.endswith('@umail.ucsb.edu'):
            self.add_error(errors, 'must end with @umail.ucsb.edu')
            return retval
        # Fetch name
        try:
            name = fetch_name_by_umail(retval, request)
        except Exception as exc:
            self.add_error(errors, exc.message)
            return retval
        if not name:
            self.add_error(errors, 'does not appear to be a valid umail email')
            return retval
        return (retval, name) def add_user(request, name, username, verification, redir_location=None):
    if username != verification:
        raise HTTPBadRequest('email and verification do not match')

    # Set the password to blank
    new_user = User(name=name, username=username, password='', is_admin=False)
    Session.add(new_user)
    try:
        Session.flush()
    except IntegrityError:
        raise HTTPConflict('User \'{0}\' already exists'.format(username))

    password_reset = PasswordReset.generate(new_user)
    Session.add(password_reset)
    try:
        Session.flush()
    except IntegrityError:
        raise HTTPConflict('Error creating password reset.')
    site_name = request.registry.settings['site_name']
    reset_url = request.route_url('password_reset_item',
                                  token=password_reset.get_token())
    body = ('Please visit the following link to complete your account '
            'creation:\n\n{0}'.format(reset_url))
    send_email(request, recipients=username, body=body,
               subject='{0} password reset email'.format(site_name))
    request.session.flash('Account creation initiated. Instructions for '
                          'completion have been emailed to {0}.'
                          .format(username), 'successes')
    redir_location = redir_location or request.route_path(
        'session', _query={'username': username})
    return http_created(request, redir_location=redir_location) def clone(item, exclude=None, update=None):
    """Return a clone of the SQLA object.

    :param item: The SQLA object to copy the attributes from.
    :param exclude: If provided, should be an iterable that contains the names
        attributes to exclude from the copy. The attributes `created_at` and
        `id` are always excluded.
    :param update: If provided, should be a mapping of attribute name, to the
        value that should be set.

    """
    # Prepare attribute exclusion set
    if not exclude:
        exclude = set()
    if not isinstance(exclude, set):
        exclude = set(exclude)
    exclude.update(('created_at', 'id'))
    # Build a mapping of attributes to values
    attrs = {x: getattr(item, x) for x in item.__mapper__.columns.keys()
             if x not in exclude}
    if update:  # Update the mapping if necessary
        attrs.update(update)
    # Build and return the SQLA object
    return item.__class__(**attrs) def fetch_request_ids(item_ids, cls, attr_name, verification_list=None):
    """Return a list of cls instances for all the ids provided in item_ids.

    :param item_ids: The list of ids to fetch objects for
    :param cls: The class to fetch the ids from
    :param attr_name: The name of the attribute for exception purposes
    :param verification_list: If provided, a list of acceptable instances

    Raise InvalidId exception using attr_name if any do not
        exist, or are not present in the verification_list.

    """
    if not item_ids:
        return []
    items = []
    for item_id in item_ids:
        item = cls.fetch_by_id(item_id)
        if not item or (verification_list is not None and
                        item not in verification_list):
            raise InvalidId(attr_name)
        items.append(item)
    return items def file_verifier_verification(function):
    def wrapped(request, min_size, max_size, min_lines, max_lines,
                *args, **kwargs):
        msgs = []
        if max_size is not None and max_size < min_size:
            msgs.append('min_size cannot be > max_size')
        if max_lines is not None and max_lines < min_lines:
            msgs.append('min_lines cannot be > max_lines')
        if min_size < min_lines:
            msgs.append('min_lines cannot be > min_size')
        if max_size is not None and max_lines is not None \
                and max_size < max_lines:
            msgs.append('max_lines cannot be > max_size')
        if msgs:
            raise HTTPBadRequest(msgs)
        return function(request, *args, min_size=min_size, max_size=max_size,
                        min_lines=min_lines, max_lines=max_lines, **kwargs)
    return wrapped def prepare_renderable(request, test_case_result, is_admin):
    """Return a completed Renderable."""
    test_case = test_case_result.test_case
    file_directory = request.registry.settings['file_directory']
    sha1 = test_case_result.diff.sha1 if test_case_result.diff else None
    kwargs = {'number': test_case.id, 'group': test_case.testable.name,
              'name': test_case.name, 'points': test_case.points,
              'status': test_case_result.status,
              'extra': test_case_result.extra}

    if test_case.output_type == 'image':
        url = request.route_path('file_item', filename='_', _query={'raw': 1},
                                 sha1sum=sha1) if sha1 else None
        return ImageOutput(url=url, **kwargs)
    elif test_case.output_type == 'text':
        content = None
        if sha1:
            with open(File.file_path(file_directory, sha1)) as fp:
                content = fp.read()
        return TextOutput(content=content, **kwargs)
    elif not test_case_result.diff:  # Outputs match
        return DiffWithMetadata(diff=None, **kwargs)

    try:
        with open(File.file_path(file_directory, sha1)) as fp:
            diff = pickle.load(fp)
    except (AttributeError, EOFError):
        content = 'submit system mismatch -- requeue submission'
        content += traceback.format_exc(1)
        return TextOutput(content=content, **kwargs)
    except Exception:
        content = 'unexected error -- requeue submission\n'
        content += traceback.format_exc(1)
        return TextOutput(content=content, **kwargs)

    diff.hide_expected = not is_admin and test_case.hide_expected
    return DiffWithMetadata(diff=diff, **kwargs) def prev_next_submission(submission):
    """Return adjacent sumbission objects for the given submission."""
    return (Submission.earlier_submission_for_group(submission),
            Submission.later_submission_for_group(submission)) def prev_next_group(project, group):
    """Return adjacent group objects or None for the given project and group.

    The previous and next group objects are relative to sort order of the
    project's groups with respect to the passed in group.

    """
    # TODO: Profile and optimize this query if necessary
    groups = sorted(x for x in project.groups if x.submissions)
    try:
        index = groups.index(group)
    except ValueError:
        return None, None
    prev_group = groups[index - 1] if index > 0 else None
    next_group = groups[index + 1] if index + 1 < len(groups) else None
    return prev_group, next_group def project_file_create(request, file_, filename, project, cls):
    # Check for BuildFile and FileVerifier conflict
    if cls == BuildFile and FileVerifier.fetch_by(project_id=project.id,
                                                  filename=filename,
                                                  optional=False):
        msg = 'A required expected file already exists with that name.'
        raise HTTPBadRequest(msg)
    cls_file = cls(file=file_, filename=filename, project=project)
    Session.add(cls_file)
    try:
        Session.flush()
    except IntegrityError:
        raise HTTPConflict('That filename already exists for the project')
    redir_location = request.route_path('project_edit', project_id=project.id)
    request.session.flash('Added {0} {1}.'.format(cls.__name__, filename),
                          'successes')
    return http_created(request, redir_location=redir_location) def project_file_delete(request, project_file):
    redir_location = request.route_path('project_edit',
                                        project_id=project_file.project.id)
    request.session.flash('Deleted {0} {1}.'
                          .format(project_file.__class__.__name__,
                                  project_file.filename),
                          'successes')
    # Delete the file
    Session.delete(project_file)
    return http_ok(request, redir_location=redir_location) def send_email(request, recipients, subject, body):
    # If in development mode send email to exception email
    if asbool(request.registry.settings.get('development_mode', False)):
        recipients = [request.registry.settings['exc_mail_to']]

    if isinstance(recipients, basestring):
        recipients = [recipients]
    message = Message(subject=subject, recipients=recipients, body=body)
    return get_mailer(request).send(message) def test_case_verification(function):
    def wrapped(request, expected, output_filename, output_source, output_type,
                *args, **kwargs):
        msgs = []
        if output_filename and output_source != 'file':
            msgs.append('output_filename can only be set when the source '
                        'is a named file')
        elif not output_filename and output_source == 'file':
            msgs.append('output_filename must be set when the source is a '
                        'named file')
        if expected and output_type != 'diff':
            msgs.append('expected_id can only be set when the type is diff')
        elif not expected and output_type == 'diff':
            msgs.append('expected_id must be set when the type is diff')
        if msgs:
            raise HTTPBadRequest(msgs)
        return function(request, *args, expected=expected,
                        output_filename=output_filename,
                        output_source=output_source, output_type=output_type,
                        **kwargs)
    return wrapped def zip_response(request, filename, files):
    """Return a Response object that is a zipfile with name filename.

    :param request: The request object.
    :param filename: The filename the browser should save the file as.
    :param files: A list of mappings between filenames (path/.../file) to file
        objects.

    """
    tmp_file = NamedTemporaryFile()
    try:
        with ZipFile(tmp_file, 'w') as zip_file:
            for zip_path, actual_path in files:
                zip_file.write(actual_path, zip_path)
        tmp_file.flush()  # Just in case
        response = FileResponse(tmp_file.name, request=request,
                                content_type=str('application/zip'))
        response.headers['Content-disposition'] = ('attachment; filename="{0}"'
                                                   .format(filename))
        return response
    finally:
        tmp_file.close() def zip_response_adv(request, filename, files):
    """Return a Response object that is a zipfile with name filename.

    :param request: The request object.
    :param filename: The filename the browser should save the file as.
    :param files: A list of tupples mapping 
        (type, name in zip, filepath or content) 
        i.e.
        ('file', name in zip, './myfile.txt')
        ('text', name in zip, 'a.out foo bar baz the quick fox jumps over the lazy dog')
        only supported types are 'file' and 'text'
    """
    tmp_file = NamedTemporaryFile()
    try:
        with ZipFile(tmp_file, 'w') as zip_file:
            for type, zip_path, actual in files:
                if type == "file":
                    zip_file.write(actual, zip_path)
                else:
                    zip_file.writestr(zip_path, actual)
        tmp_file.flush()  # Just in case
        response = FileResponse(tmp_file.name, request=request,
                                content_type=str('application/zip'))
        response.headers['Content-disposition'] = ('attachment; filename="{0}"'
                                                   .format(filename))
        return response
    finally:
        tmp_file.close()  class BuildFile(BasicBase, Base):
class Class(BasicBase, Base):
class ExecutionFile(BasicBase, Base):
class File(BasicBase, Base):
class FileVerifier(BasicBase, Base):
class Group(BasicBase, Base):
class GroupRequest(BasicBase, Base):
class VerificationResults(object):
class PasswordReset(Base):
class Project(BasicBase, Base):
class Submission(BasicBase, Base):
class SubmissionToFile(Base):
class TestCase(BasicBase, Base):
class TestCaseResult(Base):
class Testable(BasicBase, Base):
class TestableResult(BasicBase, Base):
class User(UserMixin, BasicBase, Base):
class UserToGroup(Base):
    def __cmp__(self, other):
    def can_edit(self, user):
    def edit_json(self, jsonify=True):
    def __repr__(self):
    def __str__(self):
    def __cmp__(self, other):
    def can_edit(self, user):
    def can_view(self, user):
    def is_admin(self, user):
    def __cmp__(self, other):
    def can_edit(self, user):
    def edit_json(self, jsonify=True):
    def fetch_or_create(data, base_path, sha1sum=None):
    def file_path(base_path, sha1sum):
    def __init__(self, base_path, data, sha1):
    def can_view(self, user):
    def __cmp__(self, other):
    def can_edit(self, user):
    def edit_json(self, jsonify=True):
    def verify(self, base_path, file_):
    def has_consent(self):
    def users(self):
    def users_str(self):
    def __lt__(self, other):
    def can_view(self, user):
    def can_access(self, user):
    def can_edit(self, user):
    def errors(self):
    def extra_filenames(self):
    def warnings(self):
    def __init__(self):
    def __str__(self):
    def missing_testables(self):
    def set_errors_for_filename(self, errors, filename):
    def set_extra_filenames(self, filenames):
    def set_warnings_for_filename(self, warnings, filename):
    def fetch_by(cls, **kwargs):
    def generate(cls, user):
    def get_token(self):
    def delay(self):
    def is_ready(self):
    def student_submissions(self):
    def __cmp__(self, other):
    def build_files_json(self):
    def can_access(self, user):
    def can_edit(self, user):
    def can_view(self, user):
    def execution_files_json(self):
    def file_verifiers_json(self):
    def points_possible(self, include_hidden=False):
    def process_submissions(self):
    def recent_submissions(self):
    def submit_string(self):
    def testables_json(self):
    def verify_submission(self, base_path, submission, update):
    def is_late(self):
    def earlier_submission_for_group(submission):
    def later_submission_for_group(submission):
    def merge_dict(d1, d2, on_collision):
    def most_recent_submission(project, group):
    def __cmp__(self, other):
    def can_edit(self, user):
    def can_view(self, user):
    def file_mapping(self):
    def get_delay(self, update):
    def points(self, include_hidden=False):
    def testables_pending(self, prune=False):
    def testables_succeeded(self):
    def time_score(self, request, group=False, admin=False):
    def verify(self, base_path, update=False):
    def __cmp__(self, other):
    def __cmp__(self, other):
    def can_edit(self, user):
    def edit_json(self, jsonify=False):
    def serialize(self):
    def fetch_by_ids(cls, submission_id, test_case_id):
    def update(self, data):
    def __cmp__(self, other):
    def can_edit(self, user):
    def edit_json(self, jsonify=True):
        def ids(item):
    def points(self):
    def requires_file(self, filename):
    def update_points(self):
    def fetch_or_create(make_results, status, **kwargs):
    def get_value(cls, value):
    def login(username, password, development_mode=False):
    def __cmp__(self, other):
    def __repr__(self):
    def __str__(self):
    def can_join_group(self, project):
    def can_view(self, user):
    def classes_can_admin(self):
    def group_with(self, to_user, project, bypass_limit=False):
    def fetch_group_assoc(self, project):
    def make_submission(self, project):
    def user_count(self):
    def __eq__(self, other):
def configure_sql(engine):
def create_schema(alembic_config_ini=None):
def populate_database():
import codecs
import numpy
import os
import transaction
import itertools
import re 
import yaml
import sys
import submit
from base64 import b64decode
from hashlib import sha1
from pyramid_addons.helpers import (http_created, http_gone, http_ok)
from pyramid_addons.validation import (EmailAddress, Enum, List, Or, String,
                                       RegexString, TextNumber,
                                       WhiteSpaceString, validate, SOURCE_GET,
                                       SOURCE_MATCHDICT as MATCHDICT)
from pyramid.httpexceptions import (HTTPBadRequest, HTTPConflict, HTTPError,
                                    HTTPFound, HTTPNotFound, HTTPOk,
                                    HTTPRedirection, HTTPSeeOther)
from pyramid.response import FileResponse, Response
from pyramid.security import forget, remember
from pyramid.settings import asbool
from pyramid.view import (forbidden_view_config, notfound_view_config,
                          view_config)
from sqlalchemy.exc import IntegrityError
from zipfile import ZipFile
from .diff_render import HTMLDiff
from .exceptions import GroupWithException, InvalidId, SubmitException
from .helpers import (
    AccessibleDBThing, DBThing as AnyDBThing, DummyTemplateAttr,
    EditableDBThing, TestableStatus, TextDate, ViewableDBThing, UmailAddress,
    add_user, clone, fetch_request_ids, file_verifier_verification,
    prepare_renderable, prev_next_submission, prev_next_group,
    project_file_create, project_file_delete, send_email,
    test_case_verification, zip_response,zip_response_adv)
from .models import (BuildFile, Class, ExecutionFile, File, FileVerifier,
                     Group, GroupRequest, PasswordReset, Project, Session,
                     Submission, SubmissionToFile, TestCase, Testable, User,
                     UserToGroup)
        raise HTTPBadRequest(msg)

    try:
        # Verify the ids actually exist and are associated with the project
        build_files = fetch_request_ids(build_file_ids, BuildFile,
                                        'build_file_id',
                                        project.build_files)
        execution_files = fetch_request_ids(execution_file_ids, ExecutionFile,
                                            'execution_file_id')
        file_verifiers = fetch_request_ids(file_verifier_ids, FileVerifier,
                                           'file_verifier_id',
                                           project.file_verifiers)
    except InvalidId as exc:
        raise HTTPBadRequest('Invalid {0}'.format(exc.message))

    testable = Testable(name=name, is_hidden=bool(is_hidden),
                        make_target=make_target,
                        executable=executable, project=project,
                        build_files=build_files,
                        execution_files=execution_files,
                        file_verifiers=file_verifiers)
    redir_location = request.route_path('project_edit', project_id=project.id)
    Session.add(testable)
    try:
        Session.flush()
    except IntegrityError:
        raise HTTPConflict('That name already exists for the project')
    return http_created(request, redir_location=redir_location,
                        testable_id=testable.id)


@view_config(route_name='testable_item', request_method='POST',
             permission='authenticated', renderer='json')
@validate(name=String('name', min_length=1),
          is_hidden=TextNumber('is_hidden', min_value=0, max_value=1,
                               optional=True),
          make_target=String('make_target', min_length=1, optional=True),
          executable=String('executable', min_length=1),
          build_file_ids=List('build_file_ids', TextNumber('', min_value=0),
                              optional=True),
          execution_file_ids=List('execution_file_ids',
                                  TextNumber('', min_value=0), optional=True),
          file_verifier_ids=List('file_verifier_ids',
                                 TextNumber('', min_value=0), optional=True),
          testable=EditableDBThing('testable_id', Testable, source=MATCHDICT))
def testable_edit(request, name, is_hidden, make_target, executable,
                  build_file_ids, execution_file_ids, file_verifier_ids,
                  testable):
    if make_target and not testable.project.makefile:
        msg = 'make_target cannot be specified without a make file'
        raise HTTPBadRequest(msg)

    try:
        # Verify the ids actually exist and are associated with the project
        build_files = fetch_request_ids(build_file_ids, BuildFile,
                                        'build_file_id',
                                        testable.project.build_files)
        execution_files = fetch_request_ids(execution_file_ids, ExecutionFile,
                                            'execution_file_id')
        file_verifiers = fetch_request_ids(file_verifier_ids, FileVerifier,
                                           'file_verifier_id',
                                           testable.project.file_verifiers)
    except InvalidId as exc:
        raise HTTPBadRequest('Invalid {0}'.format(exc.message))

    Session.autoflush = False  # Don't flush while testing for changes
    if not testable.update(_ignore_order=True, is_hidden=bool(is_hidden),
                           name=name, make_target=make_target,
                           executable=executable,
                           build_files=build_files,
                           execution_files=execution_files,
                           file_verifiers=file_verifiers):
        return http_ok(request, message='Nothing to change')
    try:
        Session.flush()
    except IntegrityError:
        raise HTTPConflict('That name already exists for the project')
    request.session.flash('Updated Testable {0}.'.format(testable.name),
                          'successes')
    redir_location = request.route_path('project_edit',
                                        project_id=testable.project.id)
    return http_ok(request, redir_location=redir_location)


@view_config(route_name='testable_item', request_method='DELETE',
             permission='authenticated', renderer='json')
@validate(testable=EditableDBThing('testable_id', Testable, source=MATCHDICT))
def testable_delete(request, testable):
    redir_location = request.route_path('project_edit',
                                        project_id=testable.project.id)
    request.session.flash('Deleted Testable {0}.'.format(testable.name),
                          'successes')
    Session.delete(testable)
    return http_ok(request, redir_location=redir_location)


@view_config(route_name='user', request_method='PUT', renderer='json')
@validate(identity=UmailAddress('email', min_length=16, max_length=64),
          verification=String('verification'))
def user_create(request, identity, verification):
    username, name = identity
    return add_user(request, name, username, verification)


@view_config(route_name='user', request_method='ADMINPUT', renderer='json',
             permission='admin')
@validate(name=String('name', min_length=5),
          username=String('email', min_length=6, max_length=64),
          verification=String('verification'))
def user_create_special(request, name, username, verification):
    return add_user(request, name, username, verification,
                    request.route_path('user_new_special'))


@view_config(route_name='user_join', request_method='GET',
             permission='authenticated',
             renderer='templates/forms/class_join_list.pt')
def user_join(request):
    # get all the classes that the given user is not in, and let the
    # user optionally join them

    all_classes = frozenset(Class.query_by(is_locked=False).all())