diff --git a/runestone/activecode/activecode.py b/runestone/activecode/activecode.py index 3ba7d22cf..e5432ac2c 100644 --- a/runestone/activecode/activecode.py +++ b/runestone/activecode/activecode.py @@ -71,7 +71,7 @@ def setup(app): %(hidecode)s %(include)s %(timelimit)s %(coach)s %(codelens)s %(enabledownload)s %(chatcodes)s %(optional)s data-audio='%(ctext)s' %(sourcefile)s %(datafile)s %(stdin)s %(tie)s %(dburl)s %(nopair)s %(cargs)s %(largs)s %(rargs)s %(iargs)s %(gradebutton)s %(caption)s %(hidehistory)s %(wasmuri)s - %(showlastsql)s style="visibility: hidden;"> + %(showlastsql)s %(python3_interpreter)s style="visibility: hidden;"> %(initialcode)s @@ -162,6 +162,7 @@ class ActiveCode(RunestoneIdDirective): :nopair: -- disable pair programming features :dburl: url to load database for sql mode :showlastsql: -- Only show the last sql result in output + :python3_interpreter: brython (uses brython as interpreter of python3) If this is a homework problem instead of an example in the text then the assignment text should go here. The assignment text ends with @@ -217,6 +218,7 @@ class ActiveCode(RunestoneIdDirective): "nopair": directives.flag, "dburl": directives.unchanged, "showlastsql": directives.flag, + "python3_interpreter": directives.unchanged } ) @@ -266,6 +268,11 @@ def run(self): self.options["ctext"] = newcomplete self.options["no_of_buttons"] = no_of_buttons + if ("python3_interpreter" in self.options) and (self.options["language"]=="python3") : + self.options["python3_interpreter"] = "data-python3_interpreter='%s'" % self.options["python3_interpreter"] + else: + self.options["python3_interpreter"] = "" + if "caption" not in self.options: self.options["caption"] = "" else: diff --git a/runestone/activecode/js/acfactory.js b/runestone/activecode/js/acfactory.js index b064754d8..0911fe7e2 100644 --- a/runestone/activecode/js/acfactory.js +++ b/runestone/activecode/js/acfactory.js @@ -2,6 +2,7 @@ import { ActiveCode } from "./activecode.js"; import JSActiveCode from "./activecode_js.js"; import HTMLActiveCode from "./activecode_html.js"; import SQLActiveCode from "./activecode_sql.js"; +import BrythonActiveCode from "./activecode_brython.js"; import LiveCode from "./livecode.js"; import { TimedActiveCode, @@ -9,6 +10,7 @@ import { TimedJSActiveCode, TimedHTMLActiveCode, TimedSQLActiveCode, + TimedBrythonActiveCode, } from "./timed_activecode"; import "../../common/js/jquery.highlight.js"; @@ -30,7 +32,12 @@ export default class ACFactory { if (lang === undefined) { lang = $(opts.orig).find("[data-lang]").data("lang"); } + var text_area = $(opts.orig).find("textarea")[0] + var python3_interpreter = $(text_area).attr("data-python3_interpreter"); if (opts.timed == true) { + if(python3_interpreter==="brython"){ + return new TimedBrythonActiveCode(opts); + } if (lang === "python") { return new TimedActiveCode(opts); } else if ( @@ -50,7 +57,10 @@ export default class ACFactory { return new TimedActiveCode(opts); } } else { - if (lang === "javascript") { + if ((lang ==="python3") && (python3_interpreter === "brython")){ + return new BrythonActiveCode(opts); + } + else if (lang === "javascript") { return new JSActiveCode(opts); } else if (lang === "htmlmixed") { return new HTMLActiveCode(opts); diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index bf60c122b..db2a7584d 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -60,6 +60,7 @@ export class ActiveCode extends RunestoneBase { this.question = $(opts.orig).find(`#${this.divid}_question`)[0]; this.tie = $(orig).data("tie"); this.dburl = $(orig).data("dburl"); + this.python3_interpreter = $(orig).data("python3_interpreter"); this.runButton = null; this.enabledownload = $(orig).data("enabledownload"); this.downloadButton = null; diff --git a/runestone/activecode/js/activecode_brython.js b/runestone/activecode/js/activecode_brython.js new file mode 100644 index 000000000..833bf445d --- /dev/null +++ b/runestone/activecode/js/activecode_brython.js @@ -0,0 +1,130 @@ +import { ActiveCode } from "./activecode.js"; + +export default class BrythonActiveCode extends ActiveCode { + constructor(opts) { + super(opts); + opts.alignVertical = true; + this.python3_interpreter = $(orig).data("python3_interpreter"); + $(this.runButton).text("Render"); + this.editor.setValue(this.code); + } + + async runProg() { + var prog = await this.buildProg(true); + let saveCode = "True"; + this.saveCode = await this.manage_scrubber(saveCode); + $(this.output).text(""); + if (!this.alignVertical) { + $(this.codeDiv).switchClass("col-md-12", "col-md-6", { + duration: 500, + queue: false, + }); + } + $(this.outDiv).show({ duration: 700, queue: false }); + prog = ` + + + + + + + + + +
+                
+            
+ + + + + `; + this.output.srcdoc = prog; + } + + createOutput() { + this.alignVertical = true; + var outDiv = document.createElement("div"); + $(outDiv).addClass("ac_output"); + if (this.alignVertical) { + $(outDiv).addClass("col-md-12"); + } else { + $(outDiv).addClass("col-md-5"); + } + this.outDiv = outDiv; + this.output = document.createElement("iframe"); + $(this.output).css("background-color", "white"); + $(this.output).css("position", "relative"); + $(this.output).css("height", "400px"); + $(this.output).css("width", "100%"); + outDiv.appendChild(this.output); + this.outerDiv.appendChild(outDiv); + var clearDiv = document.createElement("div"); + $(clearDiv).css("clear", "both"); // needed to make parent div resize properly + this.outerDiv.appendChild(clearDiv); + } + enableSaveLoad() { + $(this.runButton).text($.i18n("msg_activecode_render")); + } +} \ No newline at end of file diff --git a/runestone/activecode/js/timed_activecode.js b/runestone/activecode/js/timed_activecode.js index c0c5c65ce..540f57c12 100644 --- a/runestone/activecode/js/timed_activecode.js +++ b/runestone/activecode/js/timed_activecode.js @@ -8,6 +8,7 @@ import { ActiveCode } from "./activecode"; import JSActiveCode from "./activecode_js"; import HTMLActiveCode from "./activecode_html"; import SQLActiveCode from "./activecode_sql"; +import BrythonActiveCode from "./activecode_brython.js"; var TimedActiveCodeMixin = { timedInit: async function (opts) { @@ -145,3 +146,11 @@ export class TimedSQLActiveCode extends SQLActiveCode { } } Object.assign(TimedSQLActiveCode.prototype, TimedActiveCodeMixin); + +export class TimedBrythonActiveCode extends BrythonActiveCode { + constructor(opts) { + super(opts); + this.timedInit(opts); + } +} +Object.assign(TimedBrythonActiveCode.prototype, TimedActiveCodeMixin); diff --git a/runestone/activecode/test/_sources/index.rst b/runestone/activecode/test/_sources/index.rst index a92f802c6..012b907f1 100644 --- a/runestone/activecode/test/_sources/index.rst +++ b/runestone/activecode/test/_sources/index.rst @@ -2825,3 +2825,18 @@ Support for SQL in the browser ? Yes! } } // end of World class + +Trying Brython as Python 3 interpreter +-------------------------------------- +.. activecode:: test_activecode_python3 + :language: python3 + :python3_interpreter: brython + + print("You can see this print inside the iframe console") + from browser import document, alert, html + + def hello(ev): + alert("Hello! I'm using Brython :D") + + document <= html.BUTTON("My button", id="button_alert") + document["button_alert"].bind("click", hello) \ No newline at end of file