fixed inefficient file loading
This commit is contained in:
		
							
								
								
									
										12
									
								
								examples/01_hello_world/config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								examples/01_hello_world/config.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| { | ||||
|     "root_folder": "01_hello_world", | ||||
|     "title": "01_hello_world", | ||||
|     "packages": [], | ||||
|     "paths": [], | ||||
|     "pyscript_css_url": "https://pyscript.net/alpha/pyscript.css", | ||||
|     "pyscript_js_url": "https://pyscript.net/alpha/pyscript.min.js", | ||||
|     "pyscript_py_url": "https://pyscript.net/alpha/pyscript.py", | ||||
|     "bootstrap_css_url": "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css", | ||||
|     "bootstrap_js_url": "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js", | ||||
|     "pyscript_bootstrap_templates_wheel_url": "../dist/pyscript_bootstrap_templates-0.1.0-py3-none-any.whl" | ||||
| } | ||||
							
								
								
									
										29
									
								
								examples/01_hello_world/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								examples/01_hello_world/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
|  | ||||
| <!DOCTYPE html> | ||||
| <html lang="en" style="width: 100%;height: 100%"> | ||||
|     <head id="head"> | ||||
|         <meta charset="UTF-8"> | ||||
|         <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|  | ||||
|         <link rel="stylesheet" href="./resources/pyscript.css" /> | ||||
|         <script defer src="./resources/pyscript.js"></script> | ||||
|  | ||||
|         <!-- Bootstrap CSS --> | ||||
|         <link href="./resources/bootstrap.css" rel="stylesheet"> | ||||
|  | ||||
|         <title>01_hello_world</title> | ||||
|  | ||||
|         <py-env> | ||||
|             - ./resources/pyscript_bootstrap_templates-0.1.0-py3-none-any.whl | ||||
|             - paths: | ||||
|  | ||||
|         </py-env> | ||||
|     </head> | ||||
|     <body style="width: 100%; height: 100%"> | ||||
|         <div id="pyscript_app" style="height: 100%; min-height: 100%"></div> | ||||
|         <py-script src="./main.py"></py-script> | ||||
|  | ||||
|         <script src="./resources/bootstrap.js"></script> | ||||
|     </body> | ||||
| </html> | ||||
|      | ||||
							
								
								
									
										15
									
								
								examples/01_hello_world/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								examples/01_hello_world/main.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
|  | ||||
| from pyscript_bootstrap_templates import bootstrap_templates | ||||
| from pyscript_bootstrap_templates import bootstrap_HTML as bHTML | ||||
| from pyscript_bootstrap_templates import HTML as HTML | ||||
|  | ||||
| app = bootstrap_templates.PyScriptBootstrapDashboard( | ||||
|     parent_element="pyscript_app", brand_name="hello_world") | ||||
| div = bHTML.BootstrapContainer("This is a sidebar", parent=app.sidebar) | ||||
| div.font_size = 4 | ||||
|  | ||||
| btn = bHTML.ButtonPrimary("Click me", parent=app.sidebar) | ||||
| btn.w = 100 | ||||
| btn.onclick = lambda _: bHTML.AlertSuccess( | ||||
|     "You clicked me!", parent=app.main_area) | ||||
|      | ||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										15
									
								
								examples/02_image_filter/config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								examples/02_image_filter/config.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| { | ||||
|     "root_folder": "02_image_filter", | ||||
|     "title": "02_image_filter", | ||||
|     "packages": [ | ||||
|         "numpy", | ||||
|         "scikit-image" | ||||
|     ], | ||||
|     "paths": null, | ||||
|     "pyscript_css_url": "https://pyscript.net/alpha/pyscript.css", | ||||
|     "pyscript_js_url": "https://pyscript.net/alpha/pyscript.min.js", | ||||
|     "pyscript_py_url": "https://pyscript.net/alpha/pyscript.py", | ||||
|     "bootstrap_css_url": "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css", | ||||
|     "bootstrap_js_url": "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js", | ||||
|     "pyscript_bootstrap_templates_wheel_url": "../dist/pyscript_bootstrap_templates-0.1.0-py3-none-any.whl" | ||||
| } | ||||
| @ -11,12 +11,12 @@ | ||||
|         <!-- Bootstrap CSS --> | ||||
|         <link href="./resources/bootstrap.css" rel="stylesheet"> | ||||
| 
 | ||||
|         <title>sobel_filter</title> | ||||
|         <title>02_image_filter</title> | ||||
| 
 | ||||
|         <py-env> | ||||
|             - ./resources/pyscript_bootstrap_templates-0.1.0-py3-none-any.whl | ||||
|             - numpy | ||||
|             - scikit-image | ||||
|             - ./resources/pyscript_bootstrap_templates-0.1.0-py3-none-any.whl | ||||
| 
 | ||||
|         </py-env> | ||||
|     </head> | ||||
| @ -1,5 +1,3 @@ | ||||
| 
 | ||||
| 
 | ||||
| from pyscript_bootstrap_templates import bootstrap_templates | ||||
| from pyscript_bootstrap_templates import bootstrap_HTML as bHTML | ||||
| from pyscript_bootstrap_templates import bootstrap_inputs as bInputs | ||||
| @ -20,15 +18,10 @@ def sobel_image(img): | ||||
|     return ((255 * img_sobel) / img_sobel.max()).astype(np.uint8) | ||||
| 
 | ||||
| 
 | ||||
| app = bootstrap_templates.PyScriptBootstrapDashboard(parent_element="pyscript_app", brand_name="Sobel Filter Example") | ||||
| 
 | ||||
| HTML.H3("upload an image:", parent=app.sidebar) | ||||
| HTML.H3("filtered image:", parent=app.main_area) | ||||
| 
 | ||||
| 
 | ||||
| app = bootstrap_templates.PyScriptBootstrapDashboard(parent_element="pyscript_app", brand_name="Image Filter Example") | ||||
| 
 | ||||
| image_input = bInputs.InputFile(label_text="choose image file", parent=app.sidebar) | ||||
| image_input._input.set_attribute("accept", "image/*") # TODO: write wrapper for this | ||||
| image_input.set_attribute("accept", "image/*") | ||||
| 
 | ||||
| def on_image_change(f, *args): | ||||
|     print("image changed") | ||||
| @ -42,5 +35,4 @@ def on_image_change(f, *args): | ||||
|     output.rounded_size = 10 | ||||
|     output.shadow = bHTML.Shadow.LARGE | ||||
| 
 | ||||
| image_input.onchange = on_image_change | ||||
| 
 | ||||
| image_input.onchange = on_image_change | ||||
							
								
								
									
										7
									
								
								examples/02_image_filter/resources/bootstrap.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								examples/02_image_filter/resources/bootstrap.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								examples/02_image_filter/resources/bootstrap.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								examples/02_image_filter/resources/bootstrap.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										14
									
								
								examples/02_image_filter/resources/pyscript.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								examples/02_image_filter/resources/pyscript.css
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								examples/02_image_filter/resources/pyscript.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								examples/02_image_filter/resources/pyscript.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										424
									
								
								examples/02_image_filter/resources/pyscript.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								examples/02_image_filter/resources/pyscript.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,424 @@ | ||||
| import asyncio | ||||
| import base64 | ||||
| import io | ||||
| import sys | ||||
| import time | ||||
| from textwrap import dedent | ||||
|  | ||||
| import micropip  # noqa: F401 | ||||
| from js import console, document | ||||
|  | ||||
| loop = asyncio.get_event_loop() | ||||
|  | ||||
| MIME_METHODS = { | ||||
|     "__repr__": "text/plain", | ||||
|     "_repr_html_": "text/html", | ||||
|     "_repr_markdown_": "text/markdown", | ||||
|     "_repr_svg_": "image/svg+xml", | ||||
|     "_repr_png_": "image/png", | ||||
|     "_repr_pdf_": "application/pdf", | ||||
|     "_repr_jpeg_": "image/jpeg", | ||||
|     "_repr_latex": "text/latex", | ||||
|     "_repr_json_": "application/json", | ||||
|     "_repr_javascript_": "application/javascript", | ||||
|     "savefig": "image/png", | ||||
| } | ||||
|  | ||||
|  | ||||
| def render_image(mime, value, meta): | ||||
|     data = f"data:{mime};charset=utf-8;base64,{value}" | ||||
|     attrs = " ".join(['{k}="{v}"' for k, v in meta.items()]) | ||||
|     return f'<img src="{data}" {attrs}</img>' | ||||
|  | ||||
|  | ||||
| def identity(value, meta): | ||||
|     return value | ||||
|  | ||||
|  | ||||
| MIME_RENDERERS = { | ||||
|     "text/plain": identity, | ||||
|     "text/html": identity, | ||||
|     "image/png": lambda value, meta: render_image("image/png", value, meta), | ||||
|     "image/jpeg": lambda value, meta: render_image("image/jpeg", value, meta), | ||||
|     "image/svg+xml": identity, | ||||
|     "application/json": identity, | ||||
|     "application/javascript": lambda value, meta: f"<script>{value}</script>", | ||||
| } | ||||
|  | ||||
|  | ||||
| def eval_formatter(obj, print_method): | ||||
|     """ | ||||
|     Evaluates a formatter method. | ||||
|     """ | ||||
|     if print_method == "__repr__": | ||||
|         return repr(obj) | ||||
|     elif hasattr(obj, print_method): | ||||
|         if print_method == "savefig": | ||||
|             buf = io.BytesIO() | ||||
|             obj.savefig(buf, format="png") | ||||
|             buf.seek(0) | ||||
|             return base64.b64encode(buf.read()).decode("utf-8") | ||||
|         return getattr(obj, print_method)() | ||||
|     elif print_method == "_repr_mimebundle_": | ||||
|         return {}, {} | ||||
|     return None | ||||
|  | ||||
|  | ||||
| def format_mime(obj): | ||||
|     """ | ||||
|     Formats object using _repr_x_ methods. | ||||
|     """ | ||||
|     if isinstance(obj, str): | ||||
|         return obj, "text/plain" | ||||
|  | ||||
|     mimebundle = eval_formatter(obj, "_repr_mimebundle_") | ||||
|     if isinstance(mimebundle, tuple): | ||||
|         format_dict, _ = mimebundle | ||||
|     else: | ||||
|         format_dict = mimebundle | ||||
|  | ||||
|     output, not_available = None, [] | ||||
|     for method, mime_type in reversed(MIME_METHODS.items()): | ||||
|         if mime_type in format_dict: | ||||
|             output = format_dict[mime_type] | ||||
|         else: | ||||
|             output = eval_formatter(obj, method) | ||||
|  | ||||
|         if output is None: | ||||
|             continue | ||||
|         elif mime_type not in MIME_RENDERERS: | ||||
|             not_available.append(mime_type) | ||||
|             continue | ||||
|         break | ||||
|     if output is None: | ||||
|         if not_available: | ||||
|             console.warning( | ||||
|                 f"Rendered object requested unavailable MIME renderers: {not_available}" | ||||
|             ) | ||||
|         output = repr(output) | ||||
|         mime_type = "text/plain" | ||||
|     elif isinstance(output, tuple): | ||||
|         output, meta = output | ||||
|     else: | ||||
|         meta = {} | ||||
|     return MIME_RENDERERS[mime_type](output, meta), mime_type | ||||
|  | ||||
|  | ||||
| class PyScript: | ||||
|     loop = loop | ||||
|  | ||||
|     @staticmethod | ||||
|     def write(element_id, value, append=False, exec_id=0): | ||||
|         """Writes value to the element with id "element_id""" | ||||
|         console.log(f"APPENDING: {append} ==> {element_id} --> {value}") | ||||
|         if append: | ||||
|             child = document.createElement("div") | ||||
|             element = document.querySelector(f"#{element_id}") | ||||
|             if not element: | ||||
|                 return | ||||
|             exec_id = exec_id or element.childElementCount + 1 | ||||
|             element_id = child.id = f"{element_id}-{exec_id}" | ||||
|             element.appendChild(child) | ||||
|  | ||||
|         element = document.getElementById(element_id) | ||||
|         html, mime_type = format_mime(value) | ||||
|         if mime_type in ("application/javascript", "text/html"): | ||||
|             script_element = document.createRange().createContextualFragment(html) | ||||
|             element.appendChild(script_element) | ||||
|         else: | ||||
|             element.innerHTML = html | ||||
|  | ||||
|     @staticmethod | ||||
|     def run_until_complete(f): | ||||
|         _ = loop.run_until_complete(f) | ||||
|  | ||||
|  | ||||
| class Element: | ||||
|     def __init__(self, element_id, element=None): | ||||
|         self._id = element_id | ||||
|         self._element = element | ||||
|  | ||||
|     @property | ||||
|     def id(self): | ||||
|         return self._id | ||||
|  | ||||
|     @property | ||||
|     def element(self): | ||||
|         """Return the dom element""" | ||||
|         if not self._element: | ||||
|             self._element = document.querySelector(f"#{self._id}") | ||||
|         return self._element | ||||
|  | ||||
|     @property | ||||
|     def value(self): | ||||
|         return self.element.value | ||||
|  | ||||
|     @property | ||||
|     def innerHtml(self): | ||||
|         return self.element.innerHtml | ||||
|  | ||||
|     def write(self, value, append=False): | ||||
|         console.log(f"Element.write: {value} --> {append}") | ||||
|         # TODO: it should be the opposite... pyscript.write should use the Element.write | ||||
|         #       so we can consolidate on how we write depending on the element type | ||||
|         pyscript.write(self._id, value, append=append) | ||||
|  | ||||
|     def clear(self): | ||||
|         if hasattr(self.element, "value"): | ||||
|             self.element.value = "" | ||||
|         else: | ||||
|             self.write("", append=False) | ||||
|  | ||||
|     def select(self, query, from_content=False): | ||||
|         el = self.element | ||||
|         if from_content: | ||||
|             el = el.content | ||||
|  | ||||
|         _el = el.querySelector(query) | ||||
|         if _el: | ||||
|             return Element(_el.id, _el) | ||||
|         else: | ||||
|             console.log(f"WARNING: can't find element matching query {query}") | ||||
|  | ||||
|     def clone(self, new_id=None, to=None): | ||||
|         if new_id is None: | ||||
|             new_id = self.element.id | ||||
|  | ||||
|         clone = self.element.cloneNode(True) | ||||
|         clone.id = new_id | ||||
|  | ||||
|         if to: | ||||
|             to.element.appendChild(clone) | ||||
|  | ||||
|         # Inject it into the DOM | ||||
|         self.element.after(clone) | ||||
|  | ||||
|         return Element(clone.id, clone) | ||||
|  | ||||
|     def remove_class(self, classname): | ||||
|         if isinstance(classname, list): | ||||
|             for cl in classname: | ||||
|                 self.remove_class(cl) | ||||
|         else: | ||||
|             self.element.classList.remove(classname) | ||||
|  | ||||
|     def add_class(self, classname): | ||||
|         self.element.classList.add(classname) | ||||
|  | ||||
|  | ||||
| def add_classes(element, class_list): | ||||
|     for klass in class_list.split(" "): | ||||
|         element.classList.add(klass) | ||||
|  | ||||
|  | ||||
| def create(what, id_=None, classes=""): | ||||
|     element = document.createElement(what) | ||||
|     if id_: | ||||
|         element.id = id_ | ||||
|     add_classes(element, classes) | ||||
|     return Element(id_, element) | ||||
|  | ||||
|  | ||||
| class PyWidgetTheme: | ||||
|     def __init__(self, main_style_classes): | ||||
|         self.main_style_classes = main_style_classes | ||||
|  | ||||
|     def theme_it(self, widget): | ||||
|         for klass in self.main_style_classes.split(" "): | ||||
|             widget.classList.add(klass) | ||||
|  | ||||
|  | ||||
| class PyItemTemplate(Element): | ||||
|     label_fields = None | ||||
|  | ||||
|     def __init__(self, data, labels=None, state_key=None, parent=None): | ||||
|         self.data = data | ||||
|  | ||||
|         self.register_parent(parent) | ||||
|  | ||||
|         if not labels: | ||||
|             labels = list(self.data.keys()) | ||||
|         self.labels = labels | ||||
|  | ||||
|         self.state_key = state_key | ||||
|  | ||||
|         super().__init__(self._id) | ||||
|  | ||||
|     def register_parent(self, parent): | ||||
|         self._parent = parent | ||||
|         if parent: | ||||
|             self._id = f"{self._parent._id}-c-{len(self._parent._children)}" | ||||
|             self.data["id"] = self._id | ||||
|         else: | ||||
|             self._id = None | ||||
|  | ||||
|     def create(self): | ||||
|         console.log("creating section") | ||||
|         new_child = create("section", self._id, "task bg-white my-1") | ||||
|         console.log("creating values") | ||||
|  | ||||
|         console.log("creating innerHtml") | ||||
|         new_child._element.innerHTML = dedent( | ||||
|             f""" | ||||
|             <label for="flex items-center p-2 "> | ||||
|               <input class="mr-2" type="checkbox" class="task-check"> | ||||
|               <p class="m-0 inline">{self.render_content()}</p> | ||||
|             </label> | ||||
|             """ | ||||
|         ) | ||||
|  | ||||
|         console.log("returning") | ||||
|         return new_child | ||||
|  | ||||
|     def on_click(self, evt): | ||||
|         pass | ||||
|  | ||||
|     def pre_append(self): | ||||
|         pass | ||||
|  | ||||
|     def post_append(self): | ||||
|         self.element.click = self.on_click | ||||
|         self.element.onclick = self.on_click | ||||
|  | ||||
|         self._post_append() | ||||
|  | ||||
|     def _post_append(self): | ||||
|         pass | ||||
|  | ||||
|     def strike(self, value, extra=None): | ||||
|         if value: | ||||
|             self.add_class("line-through") | ||||
|         else: | ||||
|             self.remove_class("line-through") | ||||
|  | ||||
|     def render_content(self): | ||||
|         return " - ".join([self.data[f] for f in self.labels]) | ||||
|  | ||||
|  | ||||
| class PyListTemplate: | ||||
|     theme = PyWidgetTheme("flex flex-col-reverse mt-8 mx-8") | ||||
|     item_class = PyItemTemplate | ||||
|  | ||||
|     def __init__(self, parent): | ||||
|         self.parent = parent | ||||
|         self._children = [] | ||||
|         self._id = self.parent.id | ||||
|  | ||||
|     @property | ||||
|     def children(self): | ||||
|         return self._children | ||||
|  | ||||
|     @property | ||||
|     def data(self): | ||||
|         return [c.data for c in self._children] | ||||
|  | ||||
|     def render_children(self): | ||||
|         binds = {} | ||||
|         for i, c in enumerate(self._children): | ||||
|             txt = c.element.innerHTML | ||||
|             rnd = str(time.time()).replace(".", "")[-5:] | ||||
|             new_id = f"{c.element.id}-{i}-{rnd}" | ||||
|             binds[new_id] = c.element.id | ||||
|             txt = txt.replace(">", f" id='{new_id}'>") | ||||
|             print(txt) | ||||
|  | ||||
|         def foo(evt): | ||||
|             console.log(evt) | ||||
|             evtEl = evt.srcElement | ||||
|             srcEl = Element(binds[evtEl.id]) | ||||
|             srcEl.element.onclick() | ||||
|             evtEl.classList = srcEl.element.classList | ||||
|  | ||||
|         for new_id in binds: | ||||
|             Element(new_id).element.onclick = foo | ||||
|  | ||||
|     def connect(self): | ||||
|         self.md = main_div = document.createElement("div") | ||||
|         main_div.id = self._id + "-list-tasks-container" | ||||
|  | ||||
|         if self.theme: | ||||
|             self.theme.theme_it(main_div) | ||||
|  | ||||
|         self.parent.appendChild(main_div) | ||||
|  | ||||
|     def add(self, *args, **kws): | ||||
|         if not isinstance(args[0], self.item_class): | ||||
|             child = self.item_class(*args, **kws) | ||||
|         else: | ||||
|             child = args[0] | ||||
|         child.register_parent(self) | ||||
|         return self._add(child) | ||||
|  | ||||
|     def _add(self, child_elem): | ||||
|         console.log("appending child", child_elem.element) | ||||
|         self.pre_child_append(child_elem) | ||||
|         child_elem.pre_append() | ||||
|         self._children.append(child_elem) | ||||
|         self.md.appendChild(child_elem.create().element) | ||||
|         child_elem.post_append() | ||||
|         self.child_appended(child_elem) | ||||
|         return child_elem | ||||
|  | ||||
|     def pre_child_append(self, child): | ||||
|         pass | ||||
|  | ||||
|     def child_appended(self, child): | ||||
|         """Overwrite me to define logic""" | ||||
|         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, err=None, output_to_console=True, append=True): | ||||
|         self._prev = self._out | ||||
|         self._out = out | ||||
|         self.output_to_console = output_to_console | ||||
|         self._append = append | ||||
|         console.log("----> changed out to", self._out, self._append) | ||||
|  | ||||
|     def revert(self): | ||||
|         console.log("----> reverted") | ||||
|         self._out = self._prev | ||||
|  | ||||
|     def write(self, txt): | ||||
|         console.log("writing to", self._out, txt, self._append) | ||||
|         if self._out: | ||||
|             pyscript.write(self._out, txt, append=self._append) | ||||
|         if self.output_to_console: | ||||
|             console.log(self._out, txt) | ||||
|  | ||||
|  | ||||
| class OutputManager: | ||||
|     def __init__(self, out=None, err=None, output_to_console=True, append=True): | ||||
|         sys.stdout = self._out_manager = OutputCtxManager( | ||||
|             out, output_to_console, append | ||||
|         ) | ||||
|         sys.stderr = self._err_manager = OutputCtxManager( | ||||
|             err, output_to_console, 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, output_to_console, append) | ||||
|         sys.stdout = self._out_manager | ||||
|         self._err_manager.change(err, output_to_console, 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 | ||||
|         console.log("----> reverted") | ||||
|  | ||||
|  | ||||
| pyscript = PyScript() | ||||
| output_manager = OutputManager() | ||||
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user