From 4af076798a11df37f9f9260da28a52299672fd5a Mon Sep 17 00:00:00 2001 From: yumoqing Date: Mon, 7 Nov 2022 22:34:19 -0500 Subject: [PATCH] bugfix --- kivyblocks/blocks.py | 829 +----------------------------------- kivyblocks/dataloader.py | 192 +-------- kivyblocks/pyinterpreter.py | 107 +++++ kivyblocks/register.py | 2 + kivyblocks/script.py | 34 +- 5 files changed, 135 insertions(+), 1029 deletions(-) create mode 100644 kivyblocks/pyinterpreter.py diff --git a/kivyblocks/blocks.py b/kivyblocks/blocks.py index b61b866..da4d020 100755 --- a/kivyblocks/blocks.py +++ b/kivyblocks/blocks.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD import os import sys import codecs @@ -111,10 +110,7 @@ class Blocks(EventDispatcher): self.register_event_type('on_failed') self.env = GlobalEnv() config = getConfig() - if config.script_root: - self.script = Script(config.script_root) - else: - self.script = Script(config.workdir) + self.script = Script() def set(self, k:str, v): self.env[k] = v @@ -415,7 +411,7 @@ class Blocks(EventDispatcher): p.update(d) opts['options'] = p def doit(target:Widget, add_mode:str, o, w:Widget): - if isinstance(w, ModalView): + if isinstance(w, Modal): return if target and not w.parent: @@ -724,7 +720,7 @@ class Blocks(EventDispatcher): children = [i for i in from_widget.children] if hasattr(from_widget, 'get_subwidgets'): children = from_widget.get_subwidgets() - Logger.info('children=%s', str(children)) + # Logger.info('children=%s', str(children)) for c in children: ret = _find_widget(name, from_widget=c, dir=dir) if ret: @@ -819,822 +815,3 @@ class {{ classname }}({% for b in bases -%}{{b}}{% endfor %}) Factory.register('Blocks',Blocks) Factory.register('Video',Video) Factory.register('OrientationLayout', OrientationLayout) -======= -import os -import sys -import codecs -# import ujson as json -try: - import ujson as json -except: - import json -from traceback import print_exc - -from functools import partial - -from appPublic.dictExt import dictExtend -from appPublic.folderUtils import ProgramPath -from appPublic.dictObject import DictObject -from appPublic.Singleton import SingletonDecorator, GlobalEnv -from appPublic.datamapping import keyMapping -from appPublic.registerfunction import RegisterFunction - -from kivy.logger import Logger -from kivy.config import Config -from kivy.metrics import sp,dp,mm -from kivy.core.window import WindowBase, Window -from kivy.properties import BooleanProperty -from kivy.uix.widget import Widget -from kivy.clock import mainthread -from kivy.uix.modalview import ModalView -from kivy.app import App -from kivy.factory import Factory -from kivy.uix.video import Video -from .utils import * -from .newvideo import Video -from .orientationlayout import OrientationLayout -from .threadcall import HttpClient -from .register import * -from .script import Script, set_script_env - -class WidgetNotFoundById(Exception): - def __init__(self, id): - super().__init__() - self.idstr = id - - def __str__(self): - return "Widget not found by id:" + self.idstr + ':' - - def __expr__(self): - return str(self) - -class ClassMethodNotFound(Exception): - def __init__(self,k,m): - super().__init__() - self.kname = k - self.mname = m - - def __str__(self): - s = 'Method(%s) not found in class(%s)' % (self.mname, - str(self.kname.__classname__)) - return s - - def __expr__(self): - return self.__str__() - - -class NotExistsObject(Exception): - def __init__(self,name): - super().__init__() - self.name = name - - def __str__(self): - s = 'not exists widget(%s)' % self.name - return s - - def __expr__(self): - return self.__str__() - -class ArgumentError(Exception): - def __init__(self,argument,desc): - super().__init__() - self.argument = argument - self.desc = desc - - def __str__(self): - s = 'argument(%s) missed:%s' % (self.argument,self.desc) - return s - - def __expr__(self): - return self.__str__() - - -class NotRegistedWidget(Exception): - def __init__(self, name:str): - super().__init__() - self.widget_name = name - - def __str__(self): - s = 'not reigsted widget(%s)' % self.name - return s - - def __expr__(self): - return self.__str__() - -def registerWidget(name:str,widget): - globals()[name] = widget - - -class Blocks(EventDispatcher): - def __init__(self): - EventDispatcher.__init__(self) - self.action_id = 0 - self.register_event_type('on_built') - self.register_event_type('on_failed') - self.env = GlobalEnv() - config = getConfig() - self.script = Script() - - def set(self, k:str, v): - self.env[k] = v - - def register_widget(self, name:str, widget:Widget): - globals()[name] = widget - - def buildAction(self, widget:Widget, desc): - conform_desc = desc.get('conform') - blocks = Blocks() - if not conform_desc: - return partial(blocks.uniaction, widget, desc) - func =partial(blocks.conform_action,widget, desc) - return func - - def eval(self, s:str, l:dict): - g = {} - forbidens = [ - "os", - "sys", - "codecs", - "json", - ] - - for k,v in globals().copy().items(): - if k not in forbidens: - g[k] = v - - """ - g['__builtins__'] = globals()['__builtins__'] - g['__builtins__']['__import__'] = None - g['__builtins__']['__loader__'] = None - g['__builtins__']['open'] = None - """ - g.update(self.env) - return eval(s,g,l) - - def getUrlData(self, url:str, method:str='GET', - params:dict={}, files:dict={}, - callback=None, - errback=None,**kw): - - if url is None: - if errback: - errback(None,Exception('url is None')) - else: - return None - - if url.startswith('file://'): - return self.script.dispatch(url, **params) - elif url.startswith('http://') or url.startswith('https://'): - try: - hc = HttpClient() - resp=hc(url,method=method,params=params,files=files) - # print('Blocks.py :resp=',resp) - return resp - except Exception as e: - print_exc() - if errback: - return errback(None,e) - return None - else: - config = getConfig() - url = config.uihome + url - return self.getUrlData(url,method=method, - params=params, - files=files, - **kw) - - def strValueExpr(self,s:str,localnamespace:dict={}): - if not s.startswith('py::'): - return s - s = s[4:] - try: - v = self.eval(s,localnamespace) - return v - except Exception as e: - print('Exception .... ',e,'script=',s) - print_exc() - return s - - def arrayValueExpr(self,arr:list,localnamespace:dict={}) -> list: - d = [] - for v in arr: - if type(v) == type(''): - d.append(self.strValueExpr(v,localnamespace)) - continue - if type(v) == type([]): - d.append(self.arrayValueExpr(v,localnamespace)) - continue - if type(v) == type({}): - d.append(self.dictValueExpr(v,localnamespace)) - continue - if type(v) == type(DictObject): - d.append(self.dictValueExpr(v,localnamespace)) - continue - d.append(v) - return d - - def dictValueExpr(self,dic:dict,localnamespace:dict={}) -> dict: - d = {} - for k,v in dic.items(): - if type(v) == type(''): - d[k] = self.strValueExpr(v,localnamespace) - continue - if type(v) == type([]): - d[k] = self.arrayValueExpr(v,localnamespace) - continue - if type(v) == type({}): - d[k] = self.dictValueExpr(v,localnamespace) - continue - if type(v) == type(DictObject): - d[k] = self.dictValueExpr(v,localnamespace) - continue - d[k] = v - return d - def valueExpr(self,obj,localnamespace:dict={}): - if type(obj) == type(''): - return self.strValueExpr(obj,localnamespace) - if type(obj) == type([]): - return self.arrayValueExpr(obj,localnamespace) - if type(obj) == type({}): - return self.dictValueExpr(obj,localnamespace) - if isinstance(obj,DictObject): - return self.dictValueExpr(obj,localnamespace) - return obj - - def w_build(self,desc) -> Widget: - widgetClass = desc.get('widgettype',None) - if not widgetClass: - Logger.info("Block: w_build(), desc invalid", desc) - raise Exception(desc) - - widgetClass = desc['widgettype'] - opts = self.valueExpr(desc.get('options',{}).copy()) - widget = None - try: - klass = Factory.get(widgetClass) - widget = klass(**opts) - except Exception as e: - print('Error:',widgetClass,'contructon error') - print_exc() - raise NotExistsObject(widgetClass) - - if desc.get('id'): - id = desc.get('id') - if id.startswith('app.'): - app = App.get_running_app() - id = id[4:] - setattr(app, id, widget) - if id.startswith('root.'): - app = App.get_running_app() - id = id[5:] - setattr(app.root, id, widget) - - if '.' in id: - Logger.info('widget id(%s) can not contain "."', id) - else: - widget.widget_id = id - - widget.build_desc = desc - self.build_attributes(widget, desc) - self.build_rest(widget, desc) - self.buildBinds(widget, desc) - return widget - - def build_attributes(self, widget:Widget,desc,t=None): - excludes = ['widgettype','options','subwidgets','binds'] - for k,v in [(k,v) for k,v in desc.items() if k not in excludes]: - if isinstance(v,dict) and v.get('widgettype'): - b = Blocks() - v = self.valueExpr(v, localnamespace={'self':widget}) - w = b.widgetBuild(v) - if hasattr(widget,k): - aw = getattr(widget,k) - if isinstance(aw,Layout): - aw.add_widget(w) - continue - setattr(widget,k,w) - continue - setattr(widget,k,self.valueExpr(v,\ - localnamespace={'self':widget})) - - def build_rest(self, widget:Widget,desc,t=None): - self.subwidget_total = len(desc.get('subwidgets',[])) - self.subwidgets = [ None for i in range(self.subwidget_total)] - pos = 0 - for pos,sw in enumerate(desc.get('subwidgets',[])): - b = Blocks() - if isinstance(sw, str): - # w = Blocks.getWidgetById(sw, from_widget=widget) - w = Blocks.findWidget(sw, from_widget=widget) - if w: - widget.add_widget(w) - continue - - kw = self.valueExpr(sw.copy(), - localnamespace={'self':widget}) - w = b.widgetBuild(kw) - if w: - widget.add_widget(w) - - - def buildBinds(self, widget:Widget, desc:dict): - for b in desc.get('binds',[]): - kw = self.valueExpr(b.copy(), \ - localnamespace={'self':widget}) - self.buildBind(widget,kw) - - def buildBind(self, widget:Widget, desc:dict): - wid = desc.get('wid','self') - # w = Blocks.getWidgetById(desc.get('wid','self'),from_widget=widget) - w = Blocks.findWidget(desc.get('wid','self'),from_widget=widget) - if not w: - Logger.info('Block: id(%s) %s',desc.get('wid','self'), - 'not found via Blocks.getWidgetById()') - return - event = desc.get('event') - if event is None: - Logger.info('Block: binds desc miss event, desc=%s',str(desc)) - return - f = self.buildAction(widget,desc) - if f is None: - Logger.info('Block: get a null function,%s',str(desc)) - return - w.bind(**{event:f}) - - def multipleAction(self, widget:Widget, desc, *args): - desc1 = {k:v for k, v in desc.items() if k != 'actions'} - mydesc = desc1.copy() - for a in desc['actions']: - new_desc = mydesc.copy() - new_desc.update(a) - self.uniaction(widget,new_desc, *args) - - def conform_action(self, widget:Widget, desc, *args): - conform_desc = desc.get('conform') - blocks = Blocks() - if not conform_desc: - blocks.uniaction(widget, desc,*args, **kw) - return - w = blocks.widgetBuild({ - "widgettype":"Conform", - "options":conform_desc - }) - w.bind(on_conform=partial(blocks.uniaction, widget, desc)) - w.open() - - def uniaction(self, widget:Widget, desc, *args): - acttype = desc.get('actiontype') - if acttype=='blocks': - return self.blocksAction(widget,desc, *args) - if acttype=='urlwidget': - return self.urlwidgetAction(widget,desc, *args) - if acttype == 'registedfunction': - return self.registedfunctionAction(widget,desc, *args) - if acttype == 'script': - return self.scriptAction(widget, desc, *args) - if acttype == 'method': - return self.methodAction(widget, desc, *args) - if acttype == 'event': - return self.eventAction(widget, desc, *args) - if acttype == 'multiple': - return self.multipleAction(widget, desc, *args) - - alert("actiontype(%s) invalid" % acttype,title='error') - - def eventAction(self, widget:Widget, desc, *args): - target = self.get_target(widget, desc) - event = desc.get('dispatch_event') - if not event: - Logger.info('Block: eventAction():desc(%s) miss dispatch_event', - str(desc)) - return - params = desc.get('params',{}) - d = self.getActionData(widget,desc, *args) - if d: - params.update(d) - try: - target.dispatch(event, params) - except Exception as e: - Logger.info(f'Block: eventAction():dispatch {event} error') - print_exc() - return - - def get_target(self, widget:Widget, desc): - if not desc.get('target'): - return None - # return Blocks.getWidgetById(desc.get('target'),from_widget=widget) - return Blocks.findWidget(desc.get('target'),from_widget=widget) - - def blocksAction(self, widget:Widget, desc, *args): - target = self.get_target(widget, desc) - add_mode = desc.get('mode','replace') - opts = desc.get('options').copy() - d = self.getActionData(widget,desc, *args) - p = opts.get('options',{}).copy() - if d: - p.update(d) - opts['options'] = p - def doit(target:Widget, add_mode:str, o, w:Widget): - if isinstance(w, Modal): - return - - if target and not w.parent: - if add_mode == 'replace': - target.clear_widgets() - target.add_widget(w) - - def doerr(o,e): - Logger.info('Block: blocksAction(): desc=%s widgetBuild error' - ,str(desc)) - raise e - - b = Blocks() - b.bind(on_built=partial(doit,target,add_mode)) - b.bind(on_failed=doerr) - b.widgetBuild(opts) - - def urlwidgetAction(self, widget:Widget, desc, *args): - target = self.get_target(widget, desc) - add_mode = desc.get('mode','replace') - opts = desc.get('options', {}).copy() - p1 = opts.get('params',{}) - p = {} - if p1: - p.update(p1) - if len(args) >= 1 and isinstance(args[0],dict): - p.update(args[0]) - d = self.getActionData(widget, desc, *args) - if d: - p.update(d) - opts['params'] = p - d = { - 'widgettype' : 'urlwidget', - 'options': opts - } - - def doit(target:Widget, add_mode:str, o, w:Widget): - if isinstance(w, ModalView): - return - - if target and not w.parent: - if add_mode == 'replace': - target.clear_widgets() - target.add_widget(w) - - def doerr(o,e): - Logger.info('Block: urlwidgetAction(): desc=%s widgetBuild error' - ,str(desc)) - - b = Blocks() - b.bind(on_built=partial(doit,target,add_mode)) - b.bind(on_failed=doerr) - b.widgetBuild(d) - - def getActionData(self, widget:Widget, desc, *args): - data = {} - rtdesc = self.build_rtdesc(desc) - if rtdesc: - rt = self.get_rtdata(widget, rtdesc, *args) - if rt: - data.update(rt) - if desc.get('keymapping'): - data = keyMapping(data, desc.get('keymapping')) - Logger.info('getActionData():rtdesc=%s, data=%s', rtdesc, data) - return data - - def registedfunctionAction(self, widget:Widget, desc, *args): - target = self.get_target(widget, desc) - rf = RegisterFunction() - name = desc.get('rfname') - func = rf.get(name) - if func is None: - Logger.info('Block: desc=%s rfname(%s) not found', - str(desc), name) - raise Exception('rfname(%s) not found' % name) - - params = desc.get('params',{}).copy() - d = self.getActionData(widget,desc, *args) - if d: - params.update(d) - func(target, *args, **params) - - def scriptAction(self, widget:Widget, desc, *args): - script = desc.get('script') - if not script: - Logger.info('Block: scriptAction():desc(%s) target not found', - str(desc)) - return - target = self.get_target(widget, desc) - d = self.getActionData(widget,desc, *args) - ns = { - "self":target, - "args":args, - "kwargs":d - } - if d: - ns.update(d) - try: - self.eval(script, ns) - except Exception as e: - print_exc() - print(e) - - def build_rtdesc(self, desc): - rtdesc = desc.get('rtdata') - if not rtdesc: - if desc.get('datawidget'): - rtdesc = {} - rtdesc['target'] = desc['datawidget'] - if desc.get('datascript'): - rtdesc['script'] = desc.get('datacript') - else: - rtdesc['method'] = desc.get('datamethod', 'getValue') - rtdesc['kwargs'] = desc.get('datakwargs', {}) - return rtdesc - - def get_rtdata(self, widget:Widget, desc, *args): - """ - desc descript follow attributes - { - "target", a target name from widget - "method", a method name, default is 'getValue', - "script", script to handle the data - "kwargs":" a dict arguments, default is {} - } - """ - - if desc is None or desc == {}: - print('get_rtdata():desc is None') - return {} - kwargs = desc.get('kwargs', {}) - if not isinstance(kwargs, dict): - kwargs = {} - w = None - if len(args) > 0: - w = args[0] - target = desc.get('target') - if target: - # w = Blocks.getWidgetById(target, from_widget=widget) - w = Blocks.findWidget(target, from_widget=widget) - if w is None: - print('get_rtdata():w is None', desc) - return {} - script = desc.get('script') - if script: - ns = { - "self":w, - "args":args, - "kwargs":kwargs - } - d = self.eval(script, ns) - return d - - method = desc.get('method', 'getValue') - if not hasattr(w, method): - print('get_rtdata():method is None', desc, type(w)) - return {} - f = getattr(w, method) - try: - r = f(**kwargs) - if isinstance(r, dict): - return r - if isinstance(r, DictObject): - return r.to_dict() - print('get_rtdata():method return is not dict', desc, 'ret=', r, type(r)) - return {} - except: - print_exc() - return {} - - def methodAction(self, widget:Widget, desc, *args): - method = desc.get('method') - target = self.get_target(widget, desc) - if target is None: - Logger.info('Block: methodAction():desc(%s) target not found', - str(desc)) - return - if method is None: - Logger.info('Block: methodAction():desc(%s) method not found', - str(desc)) - return - if hasattr(target,method): - f = getattr(target, method) - kwargs = desc.get('options',{}).copy() - d = self.getActionData(widget,desc, *args) - if d: - kwargs.update(d) - f(*args, **kwargs) - else: - alert('%s method not found' % method) - - def widgetBuild(self, desc): - """ - desc format: - { - widgettype:, - id:widget id, - options:{} - subwidgets:[ - ] - binds:[ - ] - } - """ - def doit(desc): - if isinstance(desc,DictObject): - desc = desc.to_dict() - if not isinstance(desc,dict): - Logger.info('Block: desc(%s) must be a dict object(%s)', - desc,type(desc)) - return None - - # desc = self.valueExpr(desc) - try: - widget = self.w_build(desc) - self.dispatch('on_built',widget) - if hasattr(widget,'ready'): - widget.ready = True - return widget - except Exception as e: - print_exc() - self.dispatch('on_failed',e) - return None - - if isinstance(desc,DictObject): - desc = desc.to_dict() - if not isinstance(desc, dict): - print('widgetBuild1: desc must be a dict object', - desc,type(desc)) - self.dispatch('on_failed',Exception('miss url')) - return - - widgettype = desc.get('widgettype') - while widgettype == "urlwidget": - opts = desc.get('options',{}).copy() - extend = desc.get('extend') - addon = None - if desc.get('extend'): - addon = desc.get('extend').copy() - url = opts.get('url') - if url is None: - self.dispatch('on_failed',Exception('miss url')) - return - - if opts.get('url'): - del opts['url'] - rtdesc = self.build_rtdesc(opts) - if rtdesc: - rtdata = self.get_rtdata(None, rtdesc) - params = opts.get('params', {}) - params.update(rtdata) - opts['params'] = params - - desc = self.getUrlData(url,**opts) - if not (isinstance(desc, DictObject) or \ - isinstance(desc, dict)): - print('Block2: desc must be a dict object', - desc,type(desc)) - self.dispatch('on_failed',Exception('miss url')) - return - - if addon: - desc = dictExtend(desc,addon) - widgettype = desc.get('widgettype') - if widgettype is None: - print('Block3: desc must be a dict object not None') - return None - return doit(desc) - - @classmethod - def findWidget(self, id:str, from_widget:Widget=None) -> Widget: - """ - -:find up direct, find widget in ancestor - + or empty: find down direct, find widget in descendant - @:find widget by class - $ or empty:find widget by id - .:more than one step. - - """ - def find_widget_by_id(id, from_widget): - if id=='self': - return from_widget - if hasattr(from_widget,'widget_id'): - if from_widget.widget_id == id: - return from_widget - if hasattr(from_widget, id): - w = getattr(from_widget,id) - return w - return None - - def find_widget_by_class(klass, from_widget): - if from_widget.__class__.__name__ == klass: - return from_widget - for k, v in from_widget.__dict__.items(): - if isinstance(v, Widget): - if v.__class__.__name__ == klass: - return v - return None - - def _find_widget(name, from_widget, dir='down', - find_func=find_widget_by_id): - w = find_func(name, from_widget) - if w: - return w - if dir == 'down': - children = [i for i in from_widget.children] - if hasattr(from_widget, 'get_subwidgets'): - children = from_widget.get_subwidgets() - # Logger.info('children=%s', str(children)) - for c in children: - ret = _find_widget(name, from_widget=c, dir=dir) - if ret: - return ret - else: - if isinstance(from_widget, WindowBase): - return None - if from_widget.parent: - return _find_widget(name, - from_widget=from_widget.parent, - dir=dir) - return None - - def find_widget(step, from_widget): - dir = 'down' - if step[0:1] == '-': - dir = 'up' - step = step[1:] - find_func = find_widget_by_id - if step[0:1] == '@': - step = step[1:] - find_func = find_widget_by_class - return _find_widget(step, from_widget=from_widget, - dir=dir, find_func=find_func) - - steps = id.split('.') - w = from_widget - for i, s in enumerate(steps): - if i==0: - app = App.get_running_app() - fid = s - if fid == '/self' or fid == 'root': - w = app.root - if len(steps) == 1: - return from_widget - continue - if fid == 'Window': - w = Window - if len(steps) == 1: - return w - continue - if fid == 'app': - return app - - w = find_widget(s, w) - if not w: - return None - return w - - @classmethod - def getWidgetById(self, id:str, from_widget:Widget=None) -> Widget: - return Blocks.findWidget(id, from_widget=from_widget) - - def on_built(self,v=None): - return - - def on_failed(self,e=None): - return - - def buildKlass(self, desc): - """ - desc = { - "classname":"MyClass", - "base":["Box", "WidgetReady"], - "properties":[ - { - "name":"aaa", - "type":"str", - "default":1 - } - ] - "subwidgets":[ - ], - - """ - codes = """ -{% for b in bases %} -{{b}} = Factory.{{b}} -{% endfor %} - -class {{ classname }}({% for b in bases -%}{{b}}{% endfor %}) -{% for p in properties %} - {{p.name}} {{p.type}}({{p.default}}) -{% endfor %} - def __init__(self, **kw): - super({{classname}}, self).__init__(**kw) - -""" - -Factory.register('Blocks',Blocks) -Factory.register('Video',Video) -Factory.register('OrientationLayout', OrientationLayout) ->>>>>>> cab6a2818466e5d32880a6a01e7afe16ad192675 diff --git a/kivyblocks/dataloader.py b/kivyblocks/dataloader.py index 939c259..684e3da 100644 --- a/kivyblocks/dataloader.py +++ b/kivyblocks/dataloader.py @@ -1,5 +1,3 @@ -<<<<<<< HEAD - from kivy.event import EventDispatcher from kivy.app import App from kivy.factory import Factory @@ -9,8 +7,7 @@ from appPublic.registerfunction import RegisterFunction def getUrlData(url, method='GET', params={}): blocks = Factory.Blocks() - d = blocks.getUrlData(url, method=method, - params=params) + d = blocks.getUrlData(url, method=method, params=params) return d class DataGraber(EventDispatcher): @@ -141,7 +138,7 @@ class DataLoader(EventDispatcher): class UrlDataLoader(DataLoader): def load(self, *args, **kw): app = App.get_running_app() - url = app.realurl(self.data_user.url) + url = self.data_user.url method = self.data_user.method params = self.data_user.params.copy() params.update({ @@ -191,188 +188,3 @@ class RegisterFunctionDataLoader(DataLoader): except Exception as e: self.dispatch('on_error', e) - -======= - -from kivy.event import EventDispatcher -from kivy.app import App -from kivy.factory import Factory -from .threadcall import HttpClient -from .utils import absurl -from appPublic.registerfunction import RegisterFunction - -class DataGraber(EventDispatcher): - """ - Graber format - { - "widgettype":"DataGraber", - "options":{ - "dataurl":"first", - "datarfname":"second", - "target":"third", - "params": - "method": - "pagging":"default false" - } - } - if dataurl present, the DataGraber using this dataurl to get and - return data - else if datarfname present, it find a registered function named - by 'datarfname' to return data - else if datatarget present, it find the widget and uses target - method(default is 'getValue') to return data - else it return None - """ - def __init__(self, **kw): - super().__init__() - self.options = kw - self.register_event_type('on_success') - self.register_event_type('on_error') - - def load(self, *args, **kw): - ret = None - while True: - try: - dataurl = self.options.get('dataurl') - if dataurl: - ret = self.loadUrlData(*args, **kw) - break - - rfname = self.options.get('datarfname') - if rfname: - ret = self.loadRFData(*args, **kw) - break - target = self.options.get('datatarget') - if target: - ret = self.loadTargetData(*args, **kw) - break - except Exception as e: - self.dispatch('on_error', e) - return - if ret: - self.dispatch('on_success',ret) - else: - e = Exception('Not method to do load') - self.dispatch('on_error', e) - - def loadUrlData(self, *args, **kw): - dataurl = self.options.get('dataurl') - hc = HttpClient() - params = self.options.get('params',{}).copy() - params.update(kw) - method = self.options.get('method','GET') - d = hc(dataurl, params=params,method=method) - return d - - def loadRFData(self, *args, **kw): - rfname = self.options.get('datarfname') - rf = RegisterFunction() - f = rf.get(rfname) - if not f: - return None - params = self.options.get('params',{}).copy() - params.update(kw) - try: - d = f(**params) - return d - except Exception as e: - Logger.info('blocks : Exception:%s',e) - print_exc() - return None - - def loadTargetData(self, *args, **kw): - target = self.options.get('datatarget') - w = Factory.Blocks.getWidgetById(target) - if not w: - return None - params = self.options.get('params',{}).copy() - params.update(kw) - method = params.get('method', 'getValue') - if not has(w, method): - return None - try: - f = getattr(w, method) - d = f() - return d - except Exception as e: - Logger.info('blocks : Exception %s', e) - print_exc() - return None - - def on_success(self,d): - pass - - def on_error(self,e): - pass - -class DataLoader(EventDispatcher): - def __init__(self,data_user): - self.data_user = data_user - EventDispatcher.__init__(self) - self.register_event_type('on_success') - self.register_event_type('on_error') - - def on_success(self,d): - pass - - def on_error(self,e): - pass - - def load(self): - pass - -class HttpDataLoader(DataLoader): - def load(self, *args, **kw): - app = App.get_running_app() - url = self.data_user.url - method = self.data_user.method - params = self.data_user.params.copy() - params.update({ - "page":self.data_user.curpage, - "rows":self.data_user.page_rows - }) - hc = HttpClient() - try: - r = hc(url, method=method, params=params) - self.dispatch('on_success', r) - return r - except Exception as e: - self.dispatch('on_error', e) - - -class ListDataLoader(DataLoader): - def load(self, *args, **kw): - p = self.data_user.curpage - r = self.data_user.page_rows - try: - s = self.data_user.data[(p-1)*r:p*r] - d = { - "total":len(self.data_user.data), - "rows":s - } - self.dispatch('on_success', d) - return d - except Exception as e: - self.dispatch('on_error', e) - -class RegisterFunctionDataLoader(DataLoader): - def load(self, *args, **kw): - rf = RegisterFunction() - try: - rfname = self.data_user.rfname - func = rf.get(rfname) - if func is None: - raise Exception('%s is not a registerfunction' % rfname) - params = {k:v for k,v in self.user_data.params.items()} - params.update({ - "page":self.data_user.curpage, - "rows":self.data_user.page_rows - }) - s = func(**params) - self.dispatch('on_success', s) - return s - except Exception as e: - self.dispatch('on_error', e) - - ->>>>>>> cab6a2818466e5d32880a6a01e7afe16ad192675 diff --git a/kivyblocks/pyinterpreter.py b/kivyblocks/pyinterpreter.py new file mode 100644 index 0000000..02ac50e --- /dev/null +++ b/kivyblocks/pyinterpreter.py @@ -0,0 +1,107 @@ +from traceback import print_exc +from io import StringIO +from contextlib import redirect_stdout + +from kivy.app import App +from kivy.factory import Factory +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.textinput import TextInput + +from appPublic.Singleton import SingletonDecorator, GlobalEnv + +from .baseWidget import PressableText +from .tab import TabsPanel +from .utils import * +from kivy.utils import platform +import plyer +if platform == 'android': + import android + import jnius +elif platform == 'ios': + from pyobjus import autoclass, protocol, objc_str + from pyobjus.dylib_manager import load_framework, INCLUDE + +class PyInterpreter(TextInput): + def __init__(self, **kw): + kw['multiline'] = True + super().__init__(**kw) + self.env = {} + for n,f in Factory.classes.items(): + if f['cls']: + self.env[n] = f['cls'] + self.text = '>>>' + self.focus = True + self.scroll_line = -1 + # self.bind(on_key_up=self.check_enter_key) + + def find_line_start_idx(self): + lines = self.text.split('\n') + lines[-1] = '>>>' + txt = '\n'.join(lines) + idx = len(txt) + return idx + + def keyboard_on_key_down(self, o, keycode, text, modifiers): + _, key = keycode + print('key=', key, 'pos=', self.cursor_pos, self.cursor_index()) + script = None + if key == 'enter': + script = self.get_script() + if key == 'home': + stop_idx = self.find_line_start_idx() + self.cursor = self.get_cursor_from_index(stop_idx) + return + if key == 'left': + stop_idx = self.find_line_start_idx() + idx = self.cursor_index(cursor=self.cursor) + if idx <= stop_idx: + return + if key == 'up' or key == 'down': + self.scroll_script(key) + return + if key == 'backspace' and self.text[-3:] == '>>>': + return + ret = super().keyboard_on_key_down(o, keycode, text, modifiers) + if script: + self.exec_script(script) + elif key == 'enter': + self.text += '>>>' + return ret + + def scroll_script(self, key): + lines = self.text.split('\n') + slines = [l for l in lines if l.startswith('>>>') and l!='>>>'] + maxl = len(slines) - 1 + if self.scroll_line < 0: + self.scroll_line = maxl + if self.scroll_line == maxl and key == 'down': + return + if self.scroll_line == 0 and key == 'up': + return + if key == 'down': + self.scroll_line += 1 + else: + self.scroll_line -= 1 + lines[-1] = slines[self.scroll_line] + self.text = '\n'.join(lines) + + def get_script(self): + ts = self.text.split('\n') + s = ts[-1][3:] + print('script=',s) + return s + + def exec_script(self, script): + env = globals().copy() + f = StringIO() + with redirect_stdout(f): + try: + exec(script, env, self.env) + except Exception as e: + print('Exception:', e) + print_exc() + f.seek(0) + s = f.getvalue() + self.text = self.text + s + '\n>>>' + print('result=', s) + diff --git a/kivyblocks/register.py b/kivyblocks/register.py index f4a9f2f..a1fa35d 100644 --- a/kivyblocks/register.py +++ b/kivyblocks/register.py @@ -43,10 +43,12 @@ from .hierarchy import Hierarchy from .price import PriceView from .ffpyplayer_video import FFVideo from .upload import UploadFile +from .pyinterpreter import PyInterpreter r = Factory.register # if kivy.platform in ['win','linux', 'macosx']: # r('ScreenWithMic', ScreenWithMic) +r('PyInterpreter', PyInterpreter) r('UploadFile', UploadFile) r('FFVideo', FFVideo) r('AnchorBox', AnchorBox) diff --git a/kivyblocks/script.py b/kivyblocks/script.py index 619a114..e777b69 100644 --- a/kivyblocks/script.py +++ b/kivyblocks/script.py @@ -1,4 +1,5 @@ import os +import codecs import traceback try: import ujson as json @@ -34,26 +35,29 @@ class Script: self.register('.ui', TemplateHandler) def url2filepath(self, url): - if url.startswith('file://'): - url = url[7:] - return join(self.root, *url.split('/')) + if url.startswith('file:///'): + url = url[8:] + ret = join(self.root, *url.split('/')) + # print('url2filepath():root=', self.root, url, ret) + return ret def show_info(self, env): workdir = env['workdir'] sfile = env['filepath'] url = env['url'] - print(f'script:workdir={workdir}') - print(f'script:script_file={sfile}') - print(f'script:url={url}') + # print(f'script:workdir={workdir}') + # print(f'script:script_file={sfile}') + # print(f'script:url={url}') sdir = os.path.join(workdir, 'scripts') sf_exists = os.path.isdir(sdir) conf_f = os.path.join(workdir, 'conf', 'config.json') conf_exists = os.path.isfile(conf_f) - print(f'script:script exists {sf_exists}') - print(f'script:config.json exists {conf_exists}') + # print(f'script:script exists {sf_exists}') + # print(f'script:config.json exists {conf_exists}') def dispatch(self, url, **kw): filepath = self.url2filepath(url) + # print('dispatch():url=', url, 'filepath=', filepath) for suffix, handler in self.handlers.items(): if filepath.endswith(suffix): env = self.env.copy() @@ -62,10 +66,6 @@ class Script: env['root_path'] = self.root env['url'] = url env['filepath'] = filepath - # print(f"workdir={env['workdir']}--------") - # if platform == 'android': - # self.show_info(env) - h = handler(env) d = h.render() try: @@ -92,7 +92,15 @@ class BaseHandler: return '/'.join(tokens) p1 = self.env['url'].split('/')[:-1] - return '/'.join(p1+tokens) + ret = '/'.join(p1+tokens) + """ + print('entire_url(): org_url=', self.env['url'], + 'url=', url, + 'p1=', p1, + 'tokens=', tokens, + 'ret=', ret) + """ + return ret def __init__(self, env): self.env = env