Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit 03493e2

Browse files
authored
Merge pull request #1392 from ascholerChemeketa/python-check
Python check
2 parents 1d29eda + b4efe96 commit 03493e2

File tree

9 files changed

+89
-77
lines changed

9 files changed

+89
-77
lines changed

runestone/activecode/activecode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def setup(app):
8787
TEMPLATE_START = """
8888
<div class="%(divclass)s %(optclass)s">
8989
<div data-component="activecode" id=%(divid)s data-question_label="%(question_label)s">
90-
<div id=%(divid)s_question class="ac_question col-md-12">
90+
<div id=%(divid)s_question class="ac_question">
9191
"""
9292

9393
TEMPLATE_END = """

runestone/activecode/css/activecode.css

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,24 @@
5757
clear: both;
5858
}
5959

60-
.ac_section .clearfix {
61-
position: initial;
62-
}
63-
6460
.unittest-results {
6561
margin-left: 20px;
6662
}
6763

6864
.ac_output {
6965
margin-top: 10px;
66+
margin-bottom: -10px;
7067
display: none;
7168
background-color: inherit;
7269
}
7370
.ac_output pre {
7471
background-color: lightgray;
7572
}
7673

74+
.python_check_results pre {
75+
background-color: #f5f5f5;
76+
}
77+
7778
.ac_caption {
7879
text-align: center;
7980
font-weight: bold;
@@ -102,10 +103,6 @@
102103
border: 2px solid black;
103104
}
104105

105-
.ac_section > .col-md-12 {
106-
max-width: 100% !important;
107-
}
108-
109106
.full_width ol {
110107
max-width: 100% !important;
111108
}
@@ -150,3 +147,15 @@
150147
margin-bottom: 10px;
151148
min-height: 0px !important;
152149
}
150+
151+
.codelens {
152+
margin-bottom: 20px;
153+
}
154+
155+
.codecoach {
156+
margin-top: 20px;
157+
}
158+
159+
.ac_section .alert h3:first-child {
160+
margin-top: 0px;
161+
}

runestone/activecode/js/acfactory.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,6 @@ export default class ACFactory {
8686
sid: sid,
8787
graderactive: true,
8888
};
89-
if (language === "htmlmixed") {
90-
addopts["vertical"] = true;
91-
}
9289
newac = ACFactory.createActiveCode(thepre, language, addopts);
9390
var savediv = newac.divid;
9491
newac.divid = savediv;

runestone/activecode/js/activecode.js

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ export class ActiveCode extends RunestoneBase {
6363
this.containerDiv = opts.orig;
6464
this.useRunestoneServices = opts.useRunestoneServices;
6565
this.python3 = true;
66-
this.alignVertical = opts.vertical;
6766
this.origElem = orig;
6867
this.origText = this.origElem.textContent;
6968
this.divid = opts.orig.id;
@@ -159,7 +158,7 @@ export class ActiveCode extends RunestoneBase {
159158
var linkdiv = document.createElement("div");
160159
linkdiv.id = this.divid.replace(/_/g, "-").toLowerCase(); // :ref: changes _ to - so add this as a target
161160
var codeDiv = document.createElement("div");
162-
$(codeDiv).addClass("ac_code_div col-md-12");
161+
$(codeDiv).addClass("ac_code_div");
163162
this.codeDiv = codeDiv;
164163
this.outerDiv.lang = this.language;
165164
$(this.origElem).replaceWith(this.outerDiv);
@@ -286,7 +285,6 @@ export class ActiveCode extends RunestoneBase {
286285
var ctrlDiv = document.createElement("div");
287286
var butt;
288287
$(ctrlDiv).addClass("ac_actions");
289-
$(ctrlDiv).addClass("col-md-12");
290288
// Run
291289
butt = document.createElement("button");
292290
$(butt).text($.i18n("msg_activecode_run_code"));
@@ -703,7 +701,7 @@ export class ActiveCode extends RunestoneBase {
703701
// to hold turtle graphics output. We use a div in case the turtle changes from
704702
// using a canvas to using some other element like svg in the future.
705703
var outDiv = document.createElement("div");
706-
$(outDiv).addClass("ac_output col-md-12");
704+
$(outDiv).addClass("ac_output");
707705
this.outDiv = outDiv;
708706
this.output = document.createElement("pre");
709707
this.output.id = this.divid + "_stdout";
@@ -723,26 +721,28 @@ export class ActiveCode extends RunestoneBase {
723721
$(this.graphics).addClass("visible-ac-canvas");
724722
}.bind(this)
725723
);
726-
var clearDiv = document.createElement("div");
727-
$(clearDiv).css("clear", "both"); // needed to make parent div resize properly
728-
this.outerDiv.appendChild(clearDiv);
724+
725+
//Anything that wants to add output to coachdiv can do so after the h3
726+
// all those elements will be cleared with each run and coach display will be
727+
// reset to none. Any component that adds content after a run should set display
728+
// to block to ensure visibility
729+
var coachDiv = document.createElement("div");
730+
coachDiv.classList.add("alert", "alert-warning", "codecoach");
731+
$(coachDiv).css("display", "none");
732+
let coachHead = coachDiv.appendChild(document.createElement("h3"));
733+
coachHead.textContent = "Code Coach";
734+
this.outerDiv.appendChild(coachDiv);
735+
this.codecoach = coachDiv;
736+
729737
outDiv.appendChild(this.output);
730738
outDiv.appendChild(this.graphics);
731739
this.outerDiv.appendChild(outDiv);
732740
var lensDiv = document.createElement("div");
741+
lensDiv.classList.add("codelens");
733742
lensDiv.id = `${this.divid}_codelens`;
734-
$(lensDiv).addClass("col-md-12");
735743
$(lensDiv).css("display", "none");
736744
this.codelens = lensDiv;
737745
this.outerDiv.appendChild(lensDiv);
738-
var coachDiv = document.createElement("div");
739-
$(coachDiv).addClass("col-md-12");
740-
$(coachDiv).css("display", "none");
741-
this.codecoach = coachDiv;
742-
this.outerDiv.appendChild(coachDiv);
743-
clearDiv = document.createElement("div");
744-
$(clearDiv).css("clear", "both"); // needed to make parent div resize properly
745-
this.outerDiv.appendChild(clearDiv);
746746
}
747747

748748
disableSaveLoad() {
@@ -911,38 +911,6 @@ export class ActiveCode extends RunestoneBase {
911911
div_id: this.divid,
912912
});
913913
}
914-
// <iframe id="%(divid)s_codelens" width="800" height="500" style="display:block"src="#">
915-
// </iframe>
916-
showCodeCoach() {
917-
var myIframe;
918-
var srcURL;
919-
var cl;
920-
var div_id = this.divid;
921-
if (this.codecoach === null) {
922-
this.codecoach = document.createElement("div");
923-
this.codecoach.style.display = "block";
924-
}
925-
cl = this.codecoach.firstChild;
926-
if (cl) {
927-
this.codecoach.removeChild(cl);
928-
}
929-
srcURL = eBookConfig.app + "/admin/diffviewer?divid=" + div_id;
930-
myIframe = document.createElement("iframe");
931-
myIframe.setAttribute("id", div_id + "_coach");
932-
myIframe.setAttribute("width", "100%");
933-
myIframe.setAttribute("height", "500px");
934-
myIframe.setAttribute("style", "display:block");
935-
myIframe.style.background = "#fff";
936-
myIframe.style.width = "100%";
937-
myIframe.src = srcURL;
938-
this.codecoach.appendChild(myIframe);
939-
$(this.codecoach).show();
940-
this.logBookEvent({
941-
event: "coach",
942-
act: "view",
943-
div_id: this.divid,
944-
});
945-
}
946914

947915
toggleEditorVisibility() {}
948916

@@ -1303,6 +1271,51 @@ Yet another is that there is an internal error. The internal error message is:
13031271
}
13041272
}
13051273

1274+
async checkPythonSyntax() {
1275+
let code = this.editor.getValue();
1276+
fetch('/ns/coach/python_check', {
1277+
method: 'POST',
1278+
body: code
1279+
})
1280+
.then((response) => {
1281+
return response.json();
1282+
})
1283+
.then((data) => {
1284+
if(data.trim() !== '') {
1285+
//clean up returned text
1286+
let errorLines = data.split("\n");
1287+
let codeLines = code.split("\n");
1288+
let message = "";
1289+
for(let line of errorLines) {
1290+
if(line.indexOf(".py:") != -1) {
1291+
//old pyflakes returns "file:line:col error"
1292+
//new pyflakes returns "file:line:col: error"
1293+
//handle either
1294+
const cleaner = /[^.]*.py:(\d+):(\d+):? (.*)/i;
1295+
let lineParts = line.match(cleaner)
1296+
message += "Line " + lineParts[1] + ": " + lineParts[3] + "\n";
1297+
message += codeLines[lineParts[1] - 1] + "\n";
1298+
message += " ".repeat(lineParts[2] - 1) + "^\n";
1299+
} else {
1300+
message += line + "\n";
1301+
}
1302+
}
1303+
message = message.slice(0,-1); //remove trailing newline
1304+
1305+
//Render
1306+
let checkDiv = document.createElement("div");
1307+
checkDiv.classList.add("python_check_results");
1308+
let checkPre = checkDiv.appendChild(document.createElement("pre"));
1309+
checkPre.textContent = message;
1310+
this.codecoach.append(checkDiv);
1311+
$(this.codecoach).css("display", "block");
1312+
}
1313+
})
1314+
.catch(err => {
1315+
console.log("Error with ajax python check:", err);
1316+
});
1317+
}
1318+
13061319
/* runProg has several async elements to it.
13071320
* 1. Skulpt runs the python program asynchronously
13081321
* 2. The history is restored asynchronously
@@ -1328,6 +1341,10 @@ Yet another is that there is an internal error. The internal error message is:
13281341
var prog = await this.buildProg(true);
13291342
this.saveCode = "True";
13301343
$(this.output).text("");
1344+
1345+
//clear anything after header in codecoach
1346+
$(this.codecoach).children().slice(1).remove();
1347+
13311348
while ($(`#${this.divid}_errinfo`).length > 0) {
13321349
$(`#${this.divid}_errinfo`).remove();
13331350
}
@@ -1369,6 +1386,9 @@ Yet another is that there is an internal error. The internal error message is:
13691386
queue: false,
13701387
});
13711388
}
1389+
if (this.language == "python" || this.language == "python3") {
1390+
this.checkPythonSyntax();
1391+
}
13721392
try {
13731393
await Sk.misceval.asyncToPromise(function () {
13741394
return Sk.importMainWithBody("<stdin>", false, prog, true);

runestone/activecode/js/activecode_html.js

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { ActiveCode } from "./activecode.js";
33
export default class HTMLActiveCode extends ActiveCode {
44
constructor(opts) {
55
super(opts);
6-
opts.alignVertical = true;
76
this.code = $("<textarea />").html(this.origElem.innerHTML).text();
87
$(this.runButton).text("Render");
98
this.editor.setValue(this.code);
@@ -14,12 +13,6 @@ export default class HTMLActiveCode extends ActiveCode {
1413
let saveCode = "True";
1514
this.saveCode = await this.manage_scrubber(saveCode);
1615
$(this.output).text("");
17-
if (!this.alignVertical) {
18-
$(this.codeDiv).switchClass("col-md-12", "col-md-6", {
19-
duration: 500,
20-
queue: false,
21-
});
22-
}
2316
$(this.outDiv).show({ duration: 700, queue: false });
2417
prog =
2518
"<script type=text/javascript>window.onerror = function(msg,url,line) {alert(msg+' on line: '+line);};</script>" +
@@ -28,14 +21,8 @@ export default class HTMLActiveCode extends ActiveCode {
2821
}
2922

3023
createOutput() {
31-
this.alignVertical = true;
3224
var outDiv = document.createElement("div");
3325
$(outDiv).addClass("ac_output");
34-
if (this.alignVertical) {
35-
$(outDiv).addClass("col-md-12");
36-
} else {
37-
$(outDiv).addClass("col-md-5");
38-
}
3926
this.outDiv = outDiv;
4027
this.output = document.createElement("iframe");
4128
$(this.output).css("background-color", "white");

runestone/common/js/presenter_mode.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function codelensListener(duration) {
138138
function configureCodelens() {
139139
let acCodeTitle = document.createElement("h4");
140140
acCodeTitle.textContent = "Active Code Window";
141-
let acCode = $(".ac_code_div").removeClass("col-md-12");
141+
let acCode = $(".ac_code_div");
142142
$(".ac_code_div").addClass("col-md-6");
143143
acCode.prepend(acCodeTitle);
144144

runestone/hparsons/hparsons.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def setup(app):
3939
TEMPLATE_START = """
4040
<div class="runestone">
4141
<div data-component="hparsons" id=%(divid)s data-question_label="%(question_label)s" class="alert alert-warning hparsons_section">
42-
<div class="hp_question col-md-12">
42+
<div class="hp_question">
4343
"""
4444

4545
TEMPLATE_END = """

runestone/hparsons/js/SQLFeedback.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default class SQLFeedback extends HParsonsFeedback {
99

1010
createOutput() {
1111
var outDiv = document.createElement("div");
12-
$(outDiv).addClass("hp_output col-md-12");
12+
$(outDiv).addClass("hp_output");
1313
this.outDiv = outDiv;
1414
this.output = document.createElement("pre");
1515
this.output.id = this.hparsons.divid + "_stdout";

runestone/hparsons/js/hparsons.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ export default class HParsons extends RunestoneBase {
125125
createControls() {
126126
var ctrlDiv = document.createElement("div");
127127
$(ctrlDiv).addClass("hp_actions");
128-
$(ctrlDiv).addClass("col-md-12");
129128

130129
// Run Button
131130
this.runButton = document.createElement("button");

0 commit comments

Comments
 (0)