Código fonte de client.superpython.core

#! /usr/bin/env python
# -*- coding: UTF8 -*-
# Este arquivo é parte do programa SuperPython
# Copyright 2013-2015 Carlo Oliveira <carlo@nce.ufrj.br>,
# `Labase <http://labase.selfip.org/>`__; `GPL <http://is.gd/3Udt>`__.
#
# SuperPython é um software livre; você pode redistribuí-lo e/ou
# modificá-lo dentro dos termos da Licença Pública Geral GNU como
# publicada pela Fundação do Software Livre (FSF); na versão 2 da
# Licença.
#
# Este programa é distribuído na esperança de que possa ser útil,
# mas SEM NENHUMA GARANTIA; sem uma garantia implícita de ADEQUAÇÃO
# a qualquer MERCADO ou APLICAÇÃO EM PARTICULAR. Veja a
# Licença Pública Geral GNU para maiores detalhes.
#
# Você deve ter recebido uma cópia da Licença Pública Geral GNU
# junto com este programa, se não, veja em <http://www.gnu.org/licenses/>

"""
############################################################
SuperPython - Pacote Cliente
############################################################

Adiciona um editor Ace, dois botões e dois consoles do programa.

"""
import traceback
import sys
import json
import collections
# from . import __version__
__version__ = "1.1.2"
LOAD_MODULE_ = "/main/load?module="

LOGOUT = "/main/logout?proj="

SAVE = "/main/save"
Dims = collections.namedtuple('Dims', 'x y w h')
GUI = None


[documentos]class Ace: """ Inclui uma janela com um editor Acejs. :param browser: Brythom module browser :param edit: Referência ao módulo editor Ace :param project: Projeto que o usuário está desenvolvendo :param code: Texto do código a ser adicionado no editor """ def __init__(self, browser, edit, project, code): """Constroi os objetos iniciais. """ def _ace_editor_resize(_=0): _height = self.gui.doc.documentElement.clientHeight self._ace_editor.style.height = '%spx' % int(_height*0.98) # * 0.90) self._ace_editor.style.marginBottom = '2px' # _width = self.gui.doc.documentElement.clientWidth self._container.style.width = '98\%' # %spx' % int(_swidth) self._container.style.maxWidth = '1000px' # %spx' % int(_swidth) self._ace_editor.style.width = '98\%' # %spx' % int(_swidth) self._ace_editor.style.maxWidth = '1000px' # %spx' % int(_swidth) self.gui = browser self._ace_editor = browser.doc["edit"] self._container = browser.doc["main"] self._editors = {} self.edit, self.project = edit, project # self.unescape = browser.unescape self.gui.window.addEventListener('resize', _ace_editor_resize, True) _ace_editor_resize() self._code = code self.add_editor(self._code[:])
[documentos] def annotate(self, row=1, message="indefinido"): self._editors[self.project].session.clearAnnotations() if not row: return None return self._editors[self.project].session.setAnnotations( [dict(row=row, column=0, text=message, type="error")])
[documentos] def get_content(self): return self._editors[self.project].getValue()
[documentos] def set_content(self, code): return self._editors[self.project].setValue(code)
[documentos] def test_dirty(self, _, code_saved=False): """ Confere e testa o estado de edição para detectar modificações. :returns Se o código foi modificado desde a última vez que foi salvo. """ src = self.get_content() dirty = (src != self._code) if code_saved: self._code = src[:] return dirty and src
[documentos] def add_editor(self, code=None): # add ace editor to filename pre tag _editor = self.edit.edit(self.project) _session = _editor.getSession() _session.setMode("ace/mode/python") _editor.setValue(code) # _session.on('change', self.test_dirty) _editor.setTheme("ace/theme/cobalt") # _session.setMode("ace/mode/python") # _session.setUseWrapMode(true) # _session.setTabSize(4) _editor.setOptions({ 'enableLiveAutocompletion': True, 'enableSnippets': True, 'highlightActiveLine': False, 'displayIndentGuides': True, 'highlightSelectedWord': True }) _editor.focus() # return self._editors[self.project] = _editor # set resize self._ace_editor.bind('resize', lambda x: self._editors[self.project].resize(True))
[documentos]class Console: """Classe que define o console de resposta da execução :param browser: Referência ao módulo navegador do Brython :param ace: Referência ao módulo editor Ace """ def __init__(self, browser, ace): """Constroi os objetos iniciais. """ self.jq_canvas = self.jq_console = self.jq_msg = None self.jq_canvas_data = self.jq_console_data = None self._pyconsole = browser.doc["pyconsole"] self._pycanvas = browser.doc["pydiv"] self._pymessage = browser.doc["pymessage"] self.ace = ace self.jq = browser.jq # browser.doc["run"].onclick = self.run self._owrite = sys.stdout.write self._ewrite = sys.stderr.write sys.stdout.write = self.write sys.stderr.write = self.write self._pycanvas.html = '<img id="emmenu"' \ ' src="https://dl.dropboxusercontent.com/u/1751704/img/site_em_construcao_.jpg"' \ ' alt="menu" title="menu" width="400px"/>'
[documentos] def write(self, data): self._pyconsole.value += '%s' % data
[documentos] def display_saved(self, message="SAVED"): self.jq_msg = self.jq['message'].dialog( dict(position=dict(my="left bottom", at="left bottom", of="#edit"), width=350, height=40, dialogClass="no-titlebar"), show=dict(effect="fade", duration=800), hide=dict(effect="fade", duration=1800), buttons=[]) self._pymessage.style.display = "block" self._pymessage.value = message self.jq['message'].dialog("close")
[documentos] def display_canvas(self, display="block"): def console_resize(*_): self.jq_console_data = Dims( int(self.jq_console.offset().left), int(self.jq_console.offset().top), self.jq_console.outerWidth(), self.jq_console.outerHeight()) self.jq_canvas_data = Dims( int(self.jq_canvas.offset().left), int(self.jq_canvas.offset().top), self.jq_canvas.outerWidth(), self.jq_canvas.outerHeight()) self._pyconsole.style.display = display if self.jq_canvas_data: cs = self.jq_canvas_data self.jq_canvas = self.jq['pydiv'].dialog( dict(position=[cs.x, cs.y], width=cs.w, height=cs.h), show=dict(effect="fade", duration=800), resizeStop=console_resize, dragStop=console_resize) else: self.jq_canvas = self.jq['pydiv'].dialog( dict(position=dict(my="right top", at="left bottom", of="#control"), width="60%", height=400), show=dict(effect="fade", duration=800), resizeStop=console_resize, dragStop=console_resize) if self.jq_console_data: cs = self.jq_console_data self.jq_console = self.jq['console'].dialog( dict(position=[cs.x, cs.y], title="console", width=cs.w, height=cs.h), show=dict(effect="fade", duration=800), resizeStop=console_resize, dragStop=console_resize) else: self.jq_console = self.jq['console'].dialog( dict(position=dict(my="right bottom", at="right bottom", of="#edit"), title="console", width="60%", height=200), show=dict(effect="fade", duration=800), resizeStop=console_resize, dragStop=console_resize)
[documentos] def beforerun(self): self._pyconsole.value = '' src = self.ace.get_content() # .getCurrentText() self.display_canvas("block") self.ace.annotate(0) return src
[documentos] def onexec_error(self): # self._pycanvas.style.display = "none" self.jq_canvas.dialog("close") traceback.print_exc() self.ace.annotate(0) error = self._pyconsole.value lines = error.split(' line ') if len(lines) > 1: try: line = int(lines[-1].split("\n")[0]) error = error.split("\n")[-2] print(error) self.ace.annotate(line, error) except Exception as _: pass
""" def _code(self, _=0): self._run_or_code = self.run self._pycanvas.style.display = "none" def runcode(self, _=0): # print("self._run_or_code") self._run_or_code() """
AUTOSAVE = 600000
[documentos]class SuperPython: """Classe que define o ambiente de desenvolvimento :param browser: Referência ao módulo navegador do Brython """ def __init__(self, browser, edit, project, projeto): """Constroi os objetos iniciais. """ self.edit, self.project, self.projeto = edit, project, projeto self.gui = browser browser.window.addEventListener("beforeunload", self.logout_on_exit) self.ajax = browser.ajax self.ace = self.name = self._console = None browser.doc["menu"].onclick = self.save self._timer = self.gui.timer.set_timeout(lambda _=0: self.save(autosaved=True), AUTOSAVE) self.beforerun = self.onexec_error = None def _update_timer(self): self.gui.timer.clear_timeout(self._timer) self._timer = self.gui.timer.set_timeout(lambda _=0: self.save(autosaved=True), AUTOSAVE)
[documentos] def logout_on_exit(self, ev): ev.returnValue = "SAIR?" try: self.save() data = {"person": self.project} req = self.ajax.ajax() req.open('POST', LOGOUT + self.projeto) # , async=False) req.set_header('content-type', 'application/x-www-form-urlencoded') req.send(data) print(LOGOUT + self.projeto, data) except Exception as _: print("logout request error") return "SAIR?"
[documentos] def main(self, name="", code="# main"): self.name = name self.ace = Ace(self.gui, self.edit, self.project, code) self.load(msg="New Empty Module") self._console = Console(self.gui, self.ace) self.beforerun = self._console.beforerun self.onexec_error = self._console.onexec_error return self
[documentos] def save(self, _=0, autosaved=False): def on_complete(request): if request.text and (request.status == 200 or request.status == 0): msg = "AUTOSAVED: " if autosaved else "SAVED: " msg += request.text self._console.display_saved(msg) self.ace.test_dirty(None, code_saved=True) else: error = str(request.text) if len(request.text) > 2 else "WEB FAILURE" self._console.display_saved("NOT SAVED: " + error) src = self.ace.test_dirty(False) # print(SAVE, src) self._update_timer() if src is False: if not autosaved: self._console.display_saved("ALREADY SAVED") return 1 try: jsrc = json.dumps({"person": self.project, "name": self.name, "text": src}) # print(SAVE, jsrc) req = self.ajax.ajax() req.bind('complete', on_complete) req.set_timeout('20000', lambda _=0: self._console.display_saved("NOT SAVED: TIMEOUT")) req.open('POST', SAVE, async=False) req.set_header('content-type', 'application/json') # x-www-form-urlencoded') req.send(jsrc) state = 1 except Exception as error: state = 0 self._console.display_saved("NOT SAVED: ERROR -- %s" % error) return state
[documentos] def load(self, _=0, msg=None): def on_complete(request): if request.text and (request.status == 200 or request.status == 0): code = request.text self.ace.test_dirty(None, code_saved=True) self.ace.set_content(code) else: error = str(request.text) if len(request.text) > 2 else "WEB FAILURE" error = msg or "NOT LOADED: " + error self._console.display_saved(error) try: filename = self.name req = self.ajax.ajax() req.bind('complete', on_complete) req.set_timeout('20000', lambda: self._console.display_saved("NOT LOADED: TIMEOUT")) req.open('GET', LOAD_MODULE_ + filename, async=False) req.set_header('content-type', 'application/x-www-form-urlencoded') req.send() state = 1 except Exception as _: state = 0 return state
[documentos]def main(browse, canvas, edit, projeto): """ Cria uma instância da classe Super Python. :param browse: Módulo browser do Brython. :param canvas: Div *pydiv* onde se desenha gráficos. :param edit: :param projeto: Nome do projet0. :return: instância da classe Super Python. """ print('SuperPython '+__version__) superpython = SuperPython(browse, canvas, edit, projeto) return superpython