This commit is contained in:
yumoqing 2022-11-07 22:34:19 -05:00
parent 3cdbf6183a
commit 4af076798a
5 changed files with 135 additions and 1029 deletions

View File

@ -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:<registered widget>,
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

View File

@ -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

107
kivyblocks/pyinterpreter.py Normal file
View File

@ -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)

View File

@ -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)

View File

@ -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