From 2909a5375629f1ac1985e4346b586d4f60893955 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 30 Apr 2013 02:49:34 -0300 Subject: [PATCH] First commit --- .gitignore | 8 ++ .project | 18 ++++ .pydevproject | 7 ++ CHANGES.txt | 0 LICENSE.txt | 0 MANIFEST.in | 0 README.txt | 43 +++++++++ orun/__init__.py | 0 orun/app.py | 14 +++ orun/examples/cp.py | 26 ++++++ orun/extjs/__init__.py | 5 ++ orun/extjs/app.html | 14 +++ orun/extjs/base.py | 56 ++++++++++++ orun/extjs/cp.py | 23 +++++ orun/js.py | 187 +++++++++++++++++++++++++++++++++++++++ orun/servers/__init__.py | 0 orun/servers/cp.py | 27 ++++++ orun/session.py | 7 ++ setup.py | 13 +++ 19 files changed, 448 insertions(+) create mode 100644 .gitignore create mode 100644 .project create mode 100644 .pydevproject create mode 100644 CHANGES.txt create mode 100644 LICENSE.txt create mode 100644 MANIFEST.in create mode 100644 README.txt create mode 100644 orun/__init__.py create mode 100644 orun/app.py create mode 100644 orun/examples/cp.py create mode 100644 orun/extjs/__init__.py create mode 100644 orun/extjs/app.html create mode 100644 orun/extjs/base.py create mode 100644 orun/extjs/cp.py create mode 100644 orun/js.py create mode 100644 orun/servers/__init__.py create mode 100644 orun/servers/cp.py create mode 100644 orun/session.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6eaad0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.class +*.pyc +*.pyo +.svn +__pycache__ +_svn +/.project +/.pydevproject diff --git a/.project b/.project new file mode 100644 index 0000000..81dcad3 --- /dev/null +++ b/.project @@ -0,0 +1,18 @@ + + + orun + + + + + + org.python.pydev.PyDevBuilder + + + + + + com.aptana.projects.webnature + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 0000000..a9cca03 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,7 @@ + + + + +Default +python 2.7 + diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e69de29 diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..e69de29 diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..1f377a7 --- /dev/null +++ b/README.txt @@ -0,0 +1,43 @@ +==== +Orun +==== + +Orun (Object RUNtime) is a small/lightweight library that provides a fast +and full way to build Python RIA, the client communicates with the server +through ajax. Typical usage often looks like this:: + + #!/usr/bin/env python + # Cherrypy + ExtJS example + + from orun.extjs import * + from orun.extjs import cp + + def ok_click(id, *args, **kwargs): + cli << Ext.getCmp(id).setText('Clicked') + cli << js.client.alert('Server side message') + + def button_click(id, *args, **kwargs): + js.write(""" + Ext.getCmp("%s").setText('Clicked'); + alert('Server side callback message'); + """ % id) + + class MyApplication(cp.ExtApplication): + def main(self, *args, **kwargs): + wnd = Ext.create('widget.window', {'title': 'My Window', 'width': 300, 'height': 250, + 'items': [{'xtype': 'button', 'text': 'Click Here', 'handler': button_click}], + 'buttons': [ + {'text': 'OK', 'handler': ok_click}, + {'text': 'Close', 'handler': js.function('this.up("window").close();')}]}) + wnd.show() + wnd.setHeight(200) + + app = MyApplication('Orun (ExtJS Application)') + app.run() + +The example above, runs cherrypy application on 8080 http port, and exposes +extjs method. + +Installation +------------ + diff --git a/orun/__init__.py b/orun/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/orun/app.py b/orun/app.py new file mode 100644 index 0000000..d82238a --- /dev/null +++ b/orun/app.py @@ -0,0 +1,14 @@ + +from orun import js + +class Application(object): + AJAX_URL = '/ajax_callback' + + def __init__(self, title=''): + self.title = title + + def main(self): + pass + + def run(self): + js.AJAX_URL = self.AJAX_URL diff --git a/orun/examples/cp.py b/orun/examples/cp.py new file mode 100644 index 0000000..f60932f --- /dev/null +++ b/orun/examples/cp.py @@ -0,0 +1,26 @@ + +from orun.extjs import * +from orun.extjs import cp + +def ok_click(id, *args, **kwargs): + cli << Ext.getCmp(id).setText('Clicked') + cli << js.client.alert('Server side message') + +def button_click(id, *args, **kwargs): + js.write(""" + Ext.getCmp("%s").setText('Clicked'); + alert('Server side callback message'); + """ % id) + +class MyApplication(cp.ExtApplication): + def main(self, *args, **kwargs): + wnd = Ext.create('widget.window', {'title': 'My Window', 'width': 300, 'height': 250, + 'items': [{'xtype': 'button', 'text': 'Click Here', 'handler': button_click}], + 'buttons': [ + {'text': 'OK', 'handler': ok_click}, + {'text': 'Close', 'handler': js.function('this.up("window").close();')}]}) + wnd.show() + wnd.setHeight(200) + +app = MyApplication('Orun (ExtJS Application)') +app.run() diff --git a/orun/extjs/__init__.py b/orun/extjs/__init__.py new file mode 100644 index 0000000..f44d217 --- /dev/null +++ b/orun/extjs/__init__.py @@ -0,0 +1,5 @@ + +from orun import js +from orun.js import client +from . import base as Ext +from .base import * diff --git a/orun/extjs/app.html b/orun/extjs/app.html new file mode 100644 index 0000000..a6dd548 --- /dev/null +++ b/orun/extjs/app.html @@ -0,0 +1,14 @@ + + + + %s + + + + + + \ No newline at end of file diff --git a/orun/extjs/base.py b/orun/extjs/base.py new file mode 100644 index 0000000..5eeefa0 --- /dev/null +++ b/orun/extjs/base.py @@ -0,0 +1,56 @@ + +import json +from . import js + +__all__ = ['create', 'createByAlias', 'Component'] + +def js_ajax(fn): + i = id(fn) + js.live_methods[i] = fn + return js.client.Ext.Ajax.request({'url': js.AJAX_URL, 'method': 'GET', 'params': {'fn': i, 'id': js.client.this.id}, 'success': js.function('eval(arguments[0].responseText);')}) + +js.js_ajax = js_ajax + +def _create(meth, name, args): + #args['pyLive'] = True : TODO + obj = Component(**args) + js.write('var %s = Ext.create("%s", %s);' % (obj._id, name, str(obj))) + return obj + +def create(name, args={}): + return _create('create', name, args) + +def createByAlias(alias, args={}): + return _create('createByAlias', alias, args) + +def get(id): + return js.JsNode('Ext.get("%s")' % id) + +def getCmp(id): + return js.JsNode('Ext.getCmp("%s")' % id) + +class Component(js.JsObject): + def __init__(self, *args, **kwargs): + super(Component, self).__init__(*args, **kwargs) + + def _update(self, config): + def get_obj(value): + if isinstance(value, dict): + return Component(**v) + elif isinstance(value, (list, tuple)): + return [get_obj(v) for v in value] + else: + return value + cfg = {} + for k, v in config.items(): + cfg[k] = get_obj(v) + super(Component, self).update(cfg) + + def down(self, item): + pass + + def up(self, item): + pass + + def __str__(self): + return json.dumps(self._js, default=js._encoder) diff --git a/orun/extjs/cp.py b/orun/extjs/cp.py new file mode 100644 index 0000000..f42f92f --- /dev/null +++ b/orun/extjs/cp.py @@ -0,0 +1,23 @@ + +import os +from orun.extjs import * +from orun.servers import cp + +class ExtApplication(cp.Application): + def index(self, *args, **kwargs): + f = open(os.path.join(os.path.dirname(__file__), 'app.html')).read() + self.main() + return f % (self.title, str(js.js_manager)) + index.exposed = True + + def ajax_callback(self, *args, **kwargs): + fn = kwargs.pop('fn') + if fn: + fn = js.live_methods[int(fn)] + fn(*args, **kwargs) + return str(js.js_manager) + ajax_callback.exposed = True + +if __name__ == '__main__': + app = ExtApplication('Orun (ExtJS Application)') + app.run() diff --git a/orun/js.py b/orun/js.py new file mode 100644 index 0000000..2248d54 --- /dev/null +++ b/orun/js.py @@ -0,0 +1,187 @@ + +import types +import json + +AJAX_URL = '/ajax_callback' +js_manager = None +js_ajax = None + +live_methods = {} + +def _encoder(o): + if isinstance(o, JsObject): + return o._js + elif isinstance(o, JsNode): + return block(str(o)) + elif isinstance(o, types.FunctionType) and js_ajax: + return function(js_ajax(o)) + +def encode(o): + if isinstance(o, JsNode): + return str(o) + elif isinstance(o, (list, tuple)): + return '[%s]' % ','.join([encode(i) for i in o]) + else: + return json.dumps(o, default=_encoder) + +# trick json serialize javascript block +class JsBlock(int): + def __new__(cls, *args, **kwargs): + obj = super(JsBlock, cls).__new__(cls, 0) + obj.code = args[0] + return obj + + def __str__(cls): + return cls.code + +class JsFunction(JsBlock): + def __str__(cls): + return 'function () { %s }' % cls.code + +block = JsBlock +func = function = JsFunction + +def write(code): + if js_manager: + js_manager.write(str(code)) + + def __lshift__(self, value): + print('test') + +class JsManager(object): + def __init__(self): + self.output = [] + + def write(self, data): + self.output.append(data) + + def __str__(self): + s = '\n'.join(output) + output = self.output[:] + return s + +class JsNode(object): + def __init__(self, name='', parent=None): + if parent and parent.name: + self.name = parent.name + '.' + name + else: + self.name = name + + def __getattr__(self, attr): + return JsNode(attr, self) + + def __setattr__(self, attr, value): + if attr == 'name': + super(JsNode, self).__setattr__(attr, value) + else: + value = encode(value) + if self is client.var: + s = 'var %s = %s' % (attr, value) + else: + name = self.name + '.' if self.name else '' + s = '%s%s = %s' % (name, attr, value) + write(s) + + def __add__(self, other): + return JsNode('%s + %s' % (encode(self), encode(other))) + + def __sub__(self, other): + return JsNode('%s - %s' % (encode(self), encode(other))) + + def __mul__(self, other): + return JsNode('%s * %s' % (encode(self), encode(other))) + + def __truediv__(self, other): + return JsNode('%s / %s' % (encode(self), encode(other))) + + def __call__(self, *args, **kwargs): + l = [] + d = [] + for arg in args: + l.append(encode(arg)) + for k, v in kwargs.items(): + d.append('%s=%s' % (k, encode(v))) + _args = [] + if l: + _args.extend(l) + if d: + _args.extend(d) + s = '%s(%s)' % (self.name, ','.join(_args)) + self.name = s + return self + + def __str__(self): + return self.name + +class JsClient(JsNode): + def __init__(self, name='', parent=None): + if parent and parent.name: + self.name = parent.name + '.' + name + else: + self.name = name + self.__dict__['var'] = JsNode('var') + + def __lshift__(self, other): + write(other) + +class JsObjectNode(JsNode): + def __call__(self, *args, **kwargs): + super(JsObjectNode, self).__call__(*args, **kwargs) + write(str(self)) + +class JsObject(object): + def __init__(self, *args, **kwargs): + self._loading = True + self._id = 'js_%s' % id(self) + self._create() + self._js = kwargs + self._loading = False + + def _create(self): + pass + + def _update(self, config): + self._js.update(config) + + def __getattr__(self, attr): + if not self.__dict__.get('_loading', True): + if attr in self._js: + return self._js.get(attr) + else: + return JsObjectNode(attr, JsNode(self._id)) + + def __setattr__(self, attr, value): + if '_js' in self.__dict__ and not attr in self.__dict__: + self[attr] = value + else: + super(JsObject, self).__setattr__(attr, value) + + def __setitem__(self, attr, value): + if not self._loading: + write('%s.%s = %s' % (self._id, attr, json.dumps(value))) + self._js[attr] = value + +def load(filename, klass=JsObject): + return klass(**json.load(open(filename))) + +cli = client = JsClient() + +def call(self, *args): + print('call') + +if __name__ == '__main__': + class MyManager(JsManager): + def write(self, code): + print(code) + js_manager = MyManager() + write(client.console.log('test')) + n = JsNode('console') + write(n.print(n.log({'id': 'item id'}))) + client.var.x = 1 + client.x.y = client.window.open('http://www.google.com') + client << client.x.y()([client.x]) + client << client.Ext.create('window', {'left': 10}) + client << client.x + + # test block + print(json.dumps({'click': call}, default=_encoder)) diff --git a/orun/servers/__init__.py b/orun/servers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/orun/servers/cp.py b/orun/servers/cp.py new file mode 100644 index 0000000..17fc7d6 --- /dev/null +++ b/orun/servers/cp.py @@ -0,0 +1,27 @@ + +import cherrypy +from orun import js +from orun import app + +class Application(app.Application): + def index(self): + return 'Orun application server is running' + index.exposed = True + + def run(self, port=8080, config=None): + super(Application, self).run() + cherrypy.quickstart(self, '/', config) + +class JsManager(object): + def write(self, data): + cherrypy.response.body.append(data) + + def __str__(self): + return ';\n'.join(cherrypy.response.body) + ';' + +# Auto start cherrypy javascript manager +js.js_manager = JsManager() + +if __name__ == '__main__': + app = Application() + app.run() diff --git a/orun/session.py b/orun/session.py new file mode 100644 index 0000000..1426344 --- /dev/null +++ b/orun/session.py @@ -0,0 +1,7 @@ + +class Session(dict): + def add_object(self, obj): + self['js_' + id(obj)] = obj + +def create_session(): + return Session() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..27e7c55 --- /dev/null +++ b/setup.py @@ -0,0 +1,13 @@ +from distutils.core import setup + +setup( + name='Orun', + version='0.1.0', + author='Alexandre L. Dias', + author_email='alexandre@katrid.com', + packages=['orun', 'orun.test'], + url='http://pypi.python.org/pypi/Orun/', + license='LICENSE.txt', + description='Orun (Object RUNtime) Python JavaScript RIA framework.', + long_description=open('README.txt').read(), +) \ No newline at end of file