Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
trampgeek committed Aug 2, 2021
1 parent ccbb3f7 commit 515c72d
Show file tree
Hide file tree
Showing 18 changed files with 5,606 additions and 0 deletions.

Large diffs are not rendered by default.

632 changes: 632 additions & 0 deletions programming_contest_problem/template.py

Large diffs are not rendered by default.

Large diffs are not rendered by default.

403 changes: 403 additions & 0 deletions python3_html_gapfiller/template.py

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions python3_stage1/__author_solution.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div class="coderunner-test-results good">
<a class="btn btn-link coderunner-solution-link" style="background-color:#CFC">Show author's solution</a>
</div>
<div class="coderunner-authors-solution collapse" expanded="false" style="margin-bottom:8px">
<pre class="code-highlight">%s</pre>
</div>
<script>
window.coderunner_solution_link_clicked = window.coderunner_solution_link_clicked || function(src) {
var question = src.target.closest('div.specificfeedback');
var solution_div = question.getElementsByClassName('coderunner-authors-solution')[0];
var solution_link = question.getElementsByClassName('coderunner-solution-link')[0];
var code = question.getElementsByClassName('code-highlight')[0];

if (!code.classList.contains('has-highlight')) {
var highlight = window.ace.require("ace/ext/static_highlight");
highlight(code, {
mode: "ace/mode/python",
showGutter: false
}, function(highlighted) {
code.getElementsByClassName('ace_static_highlight')[0].style['font-size'] = "14px";
});
code.classList.add('has-highlight');
}

if (!$(solution_div).hasClass('collapsing')) {
if ($(solution_div).attr("expanded") === "true") {
solution_link.innerHTML = "Show author's solution";
$(solution_div).collapse('hide');
$(solution_div).attr("expanded", "false");
} else {
solution_link.innerHTML = "Hide author's solution";
$(solution_div).collapse('show');
$(solution_div).attr("expanded", "true");
}
}
}
var coderunner_all_links = document.getElementsByClassName('coderunner-solution-link');

for (var i = 0; i < coderunner_all_links.length; i++) {
var el = coderunner_all_links[i];
if (!el.classList.contains('has-click-handler')) {
el.addEventListener('click', window.coderunner_solution_link_clicked);
el.classList.add('has-click-handler');
}
}
</script>

47 changes: 47 additions & 0 deletions python3_stage1/__author_solution_scrambled.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div class="coderunner-test-results bad">
<a class="btn btn-link coderunner-scrambled-solution-link" style="background-color:#FCC">Show scrambled author's solution</a>
</div>
<div class="coderunner-scrambled-authors-solution collapse" expanded="false" style="margin-bottom:8px">
<pre class="code-highlight">%s</pre>
</div>
<script>
window.coderunner_solution_link_clicked = window.coderunner_solution_link_clicked || function(src) {
var question = src.target.closest('div.specificfeedback');
var solution_div = question.getElementsByClassName('coderunner-scrambled-authors-solution')[0];
var solution_link = question.getElementsByClassName('coderunner-scrambled-solution-link')[0];
var code = question.getElementsByClassName('code-highlight')[0];

if (!code.classList.contains('has-highlight')) {
var highlight = window.ace.require("ace/ext/static_highlight");
highlight(code, {
mode: "ace/mode/python",
showGutter: false
}, function(highlighted) {
code.getElementsByClassName('ace_static_highlight')[0].style['font-size'] = "14px";
});
code.classList.add('has-highlight');
}

if (!$(solution_div).hasClass('collapsing')) {
if ($(solution_div).attr("expanded") === "true") {
solution_link.innerHTML = "Show scrambled author's solution";
$(solution_div).collapse('hide');
$(solution_div).attr("expanded", "false");
} else {
solution_link.innerHTML = "Hide scrambled author's solution";
$(solution_div).collapse('show');
$(solution_div).attr("expanded", "true");
}
}
}
var coderunner_all_links = document.getElementsByClassName('coderunner-scrambled-solution-link');

for (var i = 0; i < coderunner_all_links.length; i++) {
var el = coderunner_all_links[i];
if (!el.classList.contains('has-click-handler')) {
el.addEventListener('click', window.coderunner_solution_link_clicked);
el.classList.add('has-click-handler');
}
}
</script>

77 changes: 77 additions & 0 deletions python3_stage1/__languagetask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""The generic LanguageTask, subclasses of which manage compiling and executing
code in a particular language.
"""
from datetime import datetime

WATCHDOG_FREEBOARD = 1

class CompileError(Exception):
def __init__(self, error_message):
Exception.__init__(self, error_message)


class RunError(Exception):
def __init__(self, error_message=''):
Exception.__init__(self, error_message)

class LanguageTask:
def __init__(self, params, code=None):
"""Initialise the object, recording the parameters that will control compilation and
running plus the code if supplied. Code may be alternatively be supplied later by
calls to set_code.
self.params is the dictionary of template & global parameters - language specific.
"""
self.params = params
self.code = code
self.executable_built = False
self.compile_error_message = None
self.error_message_offset = 0
self.stderr = ''
self.stdout = ''
self.start_time = datetime.now()
self.timed_out = False
if 'totaltimeout' not in params:
self.params['totaltimeout'] = 30 # Secs

def seconds_remaining(self):
"""The number of seconds of execution time remaining before the watchdog timer goes off.
The watchdog timer goes off 1 second before runguard kills the job (as determined by the 'timeout' parameter).
"""
t_elapsed = (datetime.now() - self.start_time).total_seconds()
return self.params['totaltimeout'] - t_elapsed - WATCHDOG_FREEBOARD

def set_code(self, code, error_message_offset=0):
"""Set the code to be used for subsequent compiling and running. The optional error_message_offset
is a number to be subtracted from any error messages generated by compile and run_code calls.
Exactly how (or even 'if') it is used is language dependent.
"""
self.code = code
self.error_message_offset = error_message_offset

def compile(self, make_executable=False):
"""Compile the currently set code, either to an object file or
to an executable file depending on the given make_executable parameter.
Adjust any error message by subtracting error_message_offset.
Raise CompileError if the code does not
compile, with the compilation error message within the exception
and also recorded in self.compile_error_message.
No return value.
"""
raise NotImplementedError("compile not implemented by concrete class")

def discard_executable(self):
"""Called if something breaks in the executable and it will need rebuilding
(with different source, presumably)
"""
self.executable_built = False

def run_code(self, standard_input=None, bash_command=None):
"""Run the code in the executable program that a call to compile is assumed
to have created, using the given standard input.
If a bash_command is supplied it used as given.
Otherwise the command to be executed is the compiled executable.
Returns a tuple of the output from the
run and a stderr (or a derivative thereof) string. Those two values
are also recorded in self.stdout and self.stderr respectively.
"""
raise NotImplementedError("run_code not implemented by concrete class")
204 changes: 204 additions & 0 deletions python3_stage1/__plottools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
"""Define support functions for testing of matplotlib questions.
The main function is print_plot_info, which displays suitably formatted
data about the current matplotlib plot.
This module works only if imported *after* a call to matplotlibg.use("Agg") has
been done.
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors as colors
from scipy import interpolate

MAX_LABEL_LENGTH = 60 # Use multiline display if the tick label string length exceeds this

def my_interpolate(data, xs):
"""Return the spline interpolated list of (x, y) values at abscissa xs, given
a list of (x, y) pairs
"""
def linear(x, x0, y0, x1, y1):
return y0 + (x - x0)/(x1 - x0) * (y1 - y0)

if len(data[:,0]) == 2:
x0, y0 = data[0][0], data[0][1]
x1, y1 = data[-1][0], data[-1][1]
return [(x, linear(x, x0, y0, x1, y1)) for x in xs]
else: # cubic
tck = interpolate.splrep(data[:,0], data[:,1], s=0) # Cubic spline interpolator
return zip(xs, interpolate.splev(xs, tck)) # Evaluate at required x values


def fmt_float_pair(p):
"""A formatted point or other pair of floating-point numbers"""
return f"({p[0]:.2f}, {p[1]:.2f})"


def tick_fmt(tick):
"""Format a tick label, which may be either a string or a float. If it's
a float, try to format it as an int, otherwise format it to 2 decimal
places.
"""
if isinstance(tick, str):
return tick
elif float(int(tick)) == tick:
return str(int(tick))
else:
return f"{tick:.2f}"


def normalise_colour(colour):
"""Given a matplotlib colour, convert to a standarised format"""
rgb = colors.to_rgb(colour)
return f"RGB({rgb[0]:0.2f}, {rgb[1]:0.2f}, {rgb[2]:0.2f})"


def print_lines(subplot, x_samples, show_colour, has_legend):
"""Print all lines in the plot showing y values interplolated at the given x sample points,
if not None. Otherwise print just the first 5 and last 5 points. Also
show line colours if show_colour is True.
"""
lines = subplot.get_lines()
if len(lines) == 0:
print("No plotted lines found")
return
multilines = len(lines) > 1
if multilines:
print(f"{len(lines)} separate plots found")
for i, line in enumerate(lines, 1):
if multilines:
print(f"Line {i}:")
if show_colour:
print("Color:", normalise_colour(line.get_color()))
print("Marker:", line.get_marker())
print("Line style:", line.get_linestyle())
label = line.get_label()
if has_legend and label:
print("Label:", label)
data = line.get_xydata()
if x_samples is not None:
print(f"First point: {fmt_float_pair(data[0])}")
print(f"Last point: {fmt_float_pair(data[-1])}")
print(f"Interpolating line at selected x values:")
interpolated = my_interpolate(data, x_samples)
for p in interpolated:
print(fmt_float_pair(p))
else:
print(f"Num points: {len(data)}")
n = min(len(data), 5)
points = '\n '.join(fmt_float_pair(p) for p in data[:n])
print(f"First {n} points:\n {points}")
last_n = min(len(data) - n, 5)
if last_n:
points = '\n '.join(fmt_float_pair(p) for p in data[-last_n:])
print(f"Last {last_n} points:\n {points}")
if multilines:
print()


def in_range(labels, limits):
"""Return the list of axis labels, filtered to include only those within
the given limits (min, max). If any of the axis labels are non-numeric
the list is returned unchanged.
"""
try:
clipped_labels = []
for s in labels:
s_orig = s
if isinstance(s, str):
s = s.replace('−', '-')
if limits[0] <= float(s) <= limits[1]:
clipped_labels.append(s_orig)
return clipped_labels
except ValueError:
return labels


def print_bars(subplot, show_colour):
"""Print a list of all bars"""
print("Bars:")
bars = subplot.patches
if bars and show_colour:
print(f"First bar colour: {normalise_colour(bars[0].get_facecolor())}")
for i, bar in enumerate(subplot.patches):
print(f"Bar{i}: x = {int(bar.get_xy()[0] + bar.get_width() / 2)} height = {bar.get_height():.2f}")


def tick_label_text(labels):
"""Return a string suitable for displaying tick labels"""
label_text = ', '.join(labels)
if len(label_text) > MAX_LABEL_LENGTH:
label_text = '\n'.join(labels)
return label_text


def print_plot_info(data_type, x_samples=None,
show_xlim=False, show_ylim=False,
show_colour=False,
show_xticklabels=None, # Default is True for bar chars, False otherwise
show_yticklabels=False
):
"""Output key attributes of current plot, as defined by plt.gca().
data_type must be one of 'points', 'lines' or 'bars', to print the
appropriate type of data.
x_samples, meaningful only if data_type = 'lines', is a list of x values
at which the graph y values should be printed
"""
try:
axes = plt.gcf().get_axes()
texts = plt.gcf().texts
if len(axes) > 1:
print(f"Figure has {len(axes)} subplots")
if len(texts) != 0:
print(f"Suptitle: {texts[0].get_text()}\n")
for i, current_axes in enumerate(axes, 1):
if len(axes) > 1:
print(f"Subplot {i}\n---------")
subplot = current_axes.axes
has_legend = subplot.get_legend() is not None
print("Plot title: '{}'".format(current_axes.title.get_text()))
print("X-axis label: '{}'".format(subplot.get_xlabel()))
print("Y-axis label: '{}'".format(subplot.get_ylabel()))
xgridlines = subplot.get_xgridlines()
ygridlines = subplot.get_ygridlines()
gridx_on = len(xgridlines) > 0 and xgridlines[0].get_visible()
gridy_on = len(ygridlines) > 0 and ygridlines[0].get_visible()
print(f"(x, y) grid lines enabled: ({gridx_on}, {gridy_on})")
xlim = subplot.get_xlim()
ylim = subplot.get_ylim()
if show_xlim:
print(f"X-axis limits: {fmt_float_pair(xlim)}")
if show_ylim:
print(f"Y-axis limits: {fmt_float_pair(ylim)}")
if data_type == 'points':
print_lines(subplot, None, show_colour, has_legend)
elif data_type == 'lines':
print_lines(subplot, x_samples, show_colour, has_legend)
elif data_type == 'bars':
print_bars(subplot, show_colour)

if show_xticklabels or (show_xticklabels is None and data_type == 'bars'):
x_tick_labels = [label.get_text() for label in subplot.get_xticklabels()]
if all(label.strip() == '' for label in x_tick_labels):
x_tick_labels = [tick_fmt(pos) for pos in subplot.get_xticks()]
x_tick_labels = in_range(x_tick_labels, xlim)
print('\nX-axis tick labels:')
print(tick_label_text(x_tick_labels))

if show_yticklabels:
y_tick_labels = [label.get_text() for label in subplot.get_yticklabels()]
if all(label.strip() == '' for label in y_tick_labels):
y_tick_labels = [tick_fmt(pos) for pos in subplot.get_yticks()]
y_tick_labels = in_range(y_tick_labels, ylim)
print("\nY-axis tick labels:")
print(tick_label_text(y_tick_labels))

if has_legend:
print(f"Legend: True")

if len(axes) > 1:
print(40 * "=")
print()


except Exception as exception:
print("Failed to get plot info:", str(exception))
Loading

0 comments on commit 515c72d

Please sign in to comment.