Add display impl, rm outputManage, print and console.log default to browser console (#749)

* Add display impl, remove outputManage, print and console.log defaults to terminal

* Fixing tests

* Lint

* Erase unecessary code, add cuter CSS formating for errors, fix problems around REPL output

* Add fix to repl2 and lint

* lint

* Allow for list of display, fix elif to else

* Add better global option

* test work

* xfails

* (antocuni, mariana): let's try to start again with TDD methodology: write the minimum test and code for a simple display()

* (antocuni, mariana): this test works out of the box

* WIP: this test is broken, mariana is going to fix it

* add a failing test

* Add ability to deal with targets

* Add append arg and append tests

* Add multiple values to display

* Small adjustments to tests. I noticed I wasn;t running all at some point

* add display test

* Add console tests

* Add async tests

* Fix repl tests

* Fixing merging issues

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Address antocuni's review

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Fixing more tests

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* linting

* Improve repl tests

* Change my test so codespell is hapy with it

* Test: change test_runtime_config to use json instead of toml to see if stops failing on CI

* kill this file: it is a merge artifact since it was renamed into test_py_config.py on the main branch

* Change test execution order and add async tests to async test file

Co-authored-by: Antonio Cuni <anto.cuni@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Mariana Meireles
2022-10-17 16:28:40 +02:00
committed by GitHub
parent beb3aa1574
commit 1587273868
18 changed files with 459 additions and 180 deletions

View File

@@ -111,45 +111,19 @@ export class BaseEvalElement extends HTMLElement {
this.preEvaluate();
let source: string;
let output: string;
try {
source = this.source ? await this.getSourceFromFile(this.source)
: this.getSourceFromElement();
this._register_esm(runtime);
<string>await runtime.run(
`output_manager.change(out="${this.outputElement.id}", err="${this.errorElement.id}", append=${this.appendOutput ? 'True' : 'False'})`,
);
output = <string>await runtime.run(source);
if (output !== undefined) {
if (Element === undefined) {
Element = <Element>runtime.globals.get('Element');
}
const out = Element(this.outputElement.id);
out.write.callKwargs(output, { append: this.appendOutput });
this.outputElement.hidden = false;
this.outputElement.style.display = 'block';
try {
<string>await runtime.run(`set_current_display_target(target_id="${this.id}")`);
<string>await runtime.run(source);
} finally {
<string>await runtime.run(`set_current_display_target(target_id=None)`);
}
await runtime.run(`output_manager.revert()`);
// check if this REPL contains errors, delete them and remove error classes
const errorElements = document.querySelectorAll(`div[id^='${this.errorElement.id}'][error]`);
if (errorElements.length > 0) {
errorElements.forEach( errorElement =>
{
errorElement.classList.add('hidden');
if (this.hasAttribute('std-err')) {
this.errorElement.hidden = true;
this.errorElement.style.removeProperty('display');
}
}
)
}
removeClasses(this.errorElement, ['bg-red-200', 'p-2']);
removeClasses(this.errorElement, ['py-error']);
this.postEvaluate();
} catch (err) {
logger.error(err);
@@ -159,7 +133,7 @@ export class BaseEvalElement extends HTMLElement {
}
const out = Element(this.errorElement.id);
addClasses(this.errorElement, ['bg-red-200', 'p-2']);
addClasses(this.errorElement, ['py-error']);
out.write.callKwargs(err.toString(), { append: this.appendOutput });
if (this.errorElement.children.length === 0){
this.errorElement.setAttribute('error', '');

View File

@@ -89,34 +89,6 @@ export function make_PyWidget(runtime: Runtime) {
createWidget(runtime, this.name, this.code, this.klass);
}
initOutErr(): void {
if (this.hasAttribute('output')) {
this.errorElement = this.outputElement = document.getElementById(this.getAttribute('output'));
// in this case, the default output-mode is append, if hasn't been specified
if (!this.hasAttribute('output-mode')) {
this.setAttribute('output-mode', 'append');
}
} else {
if (this.hasAttribute('std-out')) {
this.outputElement = document.getElementById(this.getAttribute('std-out'));
} else {
// In this case neither output or std-out have been provided so we need
// to create a new output div to output to
this.outputElement = document.createElement('div');
this.outputElement.classList.add('output');
this.outputElement.hidden = true;
this.outputElement.id = this.id + '-' + this.getAttribute('exec-id');
}
if (this.hasAttribute('std-err')) {
this.errorElement = document.getElementById(this.getAttribute('std-err'));
} else {
this.errorElement = this.outputElement;
}
}
}
async getSourceFromFile(s: string): Promise<string> {
const response = await fetch(s);
return await response.text();

View File

@@ -1,7 +1,6 @@
import asyncio
import base64
import io
import sys
import time
from textwrap import dedent
@@ -124,6 +123,33 @@ class PyScript:
)
def set_current_display_target(target_id):
get_current_display_target._id = target_id
def get_current_display_target():
return get_current_display_target._id
get_current_display_target._id = None
def display(*values, target=None, append=True):
default_target = get_current_display_target()
if default_target is None and target is None:
raise Exception(
"Implicit target not allowed here. Please use display(..., target=...)"
)
if target is not None:
for v in values:
Element(target).write(v, append=append)
else:
for v in values:
Element(default_target).write(v, append=append)
class Element:
def __init__(self, element_id, element=None):
self._id = element_id
@@ -365,59 +391,4 @@ class PyListTemplate:
pass
class OutputCtxManager:
def __init__(self, out=None, output_to_console=True, append=True):
self._out = out
self._prev = out
self.output_to_console = output_to_console
self._append = append
def change(self, out=None, output_to_console=True, append=True):
self._prev = self._out
self._out = out
self.output_to_console = output_to_console
self._append = append
def revert(self):
self._out = self._prev
def write(self, value):
if self._out:
Element(self._out).write(value, self._append)
if self.output_to_console:
console.info(value)
class OutputManager:
def __init__(self, out=None, err=None, output_to_console=True, append=True):
sys.stdout = self._out_manager = OutputCtxManager(
out=out, output_to_console=output_to_console, append=append
)
sys.stderr = self._err_manager = OutputCtxManager(
out=err, output_to_console=output_to_console, append=append
)
self.output_to_console = output_to_console
self._append = append
def change(self, out=None, err=None, output_to_console=True, append=True):
self._out_manager.change(
out=out, output_to_console=output_to_console, append=append
)
sys.stdout = self._out_manager
self._err_manager.change(
out=err, output_to_console=output_to_console, append=append
)
sys.stderr = self._err_manager
self.output_to_console = output_to_console
self._append = append
def revert(self):
self._out_manager.revert()
self._err_manager.revert()
sys.stdout = self._out_manager
sys.stderr = self._err_manager
pyscript = PyScript()
output_manager = OutputManager()

View File

@@ -89,6 +89,7 @@ html {
opacity: 1;
}
color: #0f172a;
.py-pop-up {
text-align: center;
width: 600px;
@@ -107,7 +108,16 @@ html {
right: 5%;
}
.py-box {
/* Pop-up second layer end */
.py-error{
background-color: rgb(254 226 226);
border: solid;
border-color: #fca5a5;
color: #ff0000;
}
.py-box{
display: flex;
flex-direction: row;
justify-content: flex-start;