Permalink
Browse files

initial commit

  • Loading branch information...
alexcepoi committed Feb 7, 2012
0 parents commit 60ca9504098178031911b12f95e9f942444038f0
@@ -0,0 +1,12 @@
+# temp files
+**pyc
+**pyo
+
+# swap files
+**swp
+**~
+
+# build directory (setup.py)
+build/
+dist/
+**pyscale.egg-info/
@@ -0,0 +1,2 @@
+include README.rst
+graft pyscale/files
@@ -0,0 +1,91 @@
+General purpose Python framework for writing highly scalable applications.
+
+About
+---------------------------------------------------
+A typical application consists of several modules. Each module has its own
+process, stores a pidfile in 'tmp/pids', and has a logfile in 'logs'.
+
+A RPC protocol is implemented on top of zeromq in order to allow for
+inter-module communication. Modules have an auto-adjustable number of workers
+in order to cope with a high number of requests. These rpc requests will block
+until that module becomes available.
+Read more about zeromq at http://zguide.zeromq.org/
+
+Each module consists of several gevent greenlets. A basic module will already
+contain a few greenlets that handle incoming rpc requests. You can spawn
+additional greenlets for your own needs.
+Read more about gevent at http://www.gevent.org/
+
+
+Tasks
+---------------------------------------------------
+You can manage and debug your modules using built-in tasks. Type 'cake' at a
+bash prompt when inside your project to see available tasks and what they do.
+You can also define your own taks.
+
+Commands
+---------------------------------------------------
+To create a new project:
+
+::
+
+ $ pyscale new <name>
+
+To generate a new module:
+
+::
+
+ $ pyscale generate <name>
+
+To start, stop, debug, view logs and more check out available cake tasks:
+
+::
+
+ $ cake
+ $ cake start
+ $ cake stop
+ $ cake status
+ $ cake log
+ $ cake console
+
+Usage
+---------------------------------------------------
+To execute an rpc request on another module:
+
+::
+
+ self.sock('modname').method(*args, **kwargs)
+
+You can also use properties, and chain requests:
+
+::
+
+ self.sock('modname').prop.method()
+
+You can also issue requests on all available modules:
+
+::
+
+ self.multisock('*').method()
+
+
+To spawn another gevent greenlet in a current module:
+
+::
+
+ self.jobs.spawn(func)
+
+To debug your application use logs and the console.
+
+Requirements
+---------------------------------------------------
+System Dependencies:
+ * zeromq
+ * atd
+
+Python Dependencies:
+ * pyzmq
+ * gevent
+ * gevent_zeromq
+ * cake
+ * nose
@@ -0,0 +1,21 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+import sys
+
+from cake.color import puts, fore
+from pyscale.lib import PyscaleError
+from pyscale.tools.generators import new, generate
+
+
+# main
+if __name__ == '__main__':
+ command, arg = sys.argv[1:]
+
+ try:
+ if command in ['new', 'n']:
+ new(arg)
+ elif command in ['generate', 'g']:
+ generate(arg)
+ except PyscaleError as ex:
+ puts(fore.red(ex))
No changes.
@@ -0,0 +1,16 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+import logging
+
+from lib.module import Module
+
+
+# Module
+class {{module}}(Module):
+ pass
+
+
+# main
+if __name__ == '__main__':
+ {{module}}().run()
@@ -0,0 +1,4 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+from pyscale.tools.tasks import *
No changes.
No changes.
@@ -0,0 +1,18 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+import os
+import os.path as osp
+import logging
+
+class Configuration(object):
+ def __init__(self, env='development'):
+ self.env = os.environ.get('APP_ENV') or env
+ self.root = osp.abspath('.')
+
+ @property
+ def log_level(self):
+ if self.env == 'production':
+ return logging.WARNING
+ else:
+ return logging.DEBUG
No changes.
@@ -0,0 +1,18 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+from pyscale.lib.module import BaseModule
+
+
+class Module(BaseModule):
+ """ Module Class (daemon) """
+
+ # notifications
+ def notice(self, msg):
+ pass
+
+ def alert(self, msg):
+ pass
+
+ def error(self, msg):
+ pass
No changes.
No changes.
No changes.
@@ -0,0 +1,25 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+import sys
+
+from pyscale.tools.console import main
+from pyscale.tools.console import api as _api
+from pyscale.tools.console import reinit as _reinit
+
+
+self = sys.modules[__name__]
+self.sockets = []
+
+
+def api(modules=None):
+ if modules == None:
+ modules = self.all
+
+ _api(modules)
+
+def reinit(info=True):
+ _reinit(self, info)
+
+
+main(self)
@@ -0,0 +1,5 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+from pyscale.tools.logger import main
+main()
@@ -0,0 +1,5 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+from .decorators import *
+from .errors import *
@@ -0,0 +1,7 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+def api(method):
+ """ Basic decorator for module API methods """
+ method.api = True
+ return method
@@ -0,0 +1,40 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+
+class PyscaleError(Exception):
+ def __init__(self, msg):
+ self.msg = msg
+
+ def __str__(self):
+ return self.msg
+
+
+class ReqError(Exception):
+ def __init__(self, msg):
+ self.msg = msg
+
+ def __getattr__(self, key):
+ return self
+
+ def __setattr__(self, key, name):
+ if key == 'msg':
+ return super(ReqError, self).__setattr__(key, name)
+ return self
+
+ def __delattr__(self, key):
+ if key == 'msg':
+ return super(ReqError, self).__delattr__(key, name)
+ return self
+
+ def __call__(self, *args, **kwargs):
+ return self
+
+ def __str__(self):
+ return '(error: %s)' % self.msg
+
+ def __repr__(self):
+ return str(self)
+
+ def __nonzero__(self):
+ return False
@@ -0,0 +1,74 @@
+#! /usr/bin/env python2.6
+# -*- coding: utf-8 -*-
+
+import sys
+import logging
+import logging.handlers
+import traceback
+
+
+class MyFormatter(logging.Formatter):
+ def format(self, record):
+ record.fname = "[%s:%s]" % (record.filename, record.lineno)
+ return logging.Formatter.format(self, record)
+
+
+EXCEPTION_PREFIX = ' => '
+
+def log_exception(msg=None):
+ """ Custom exception log helper """
+ if msg is None:
+ msg = traceback.format_exc()
+
+ lines = msg.split('\n')
+ lines = [ '%s%s' % (EXCEPTION_PREFIX, line) for line in lines if line]
+ msg = '\n' + '\n'.join(lines) + '\n'
+
+ logging.log(75, '\n%s' % msg)
+
+def log_status(msg):
+ """ Always log regardless of level """
+ logging.log(100, msg)
+
+
+def config_logger(stream=sys.stdout, level=logging.DEBUG):
+ logger = logging.getLogger()
+ logger.setLevel(level)
+
+
+ # handler
+ if stream in [sys.stdout, sys.stderr]:
+ handler = logging.StreamHandler(stream)
+ else:
+ handler = logging.handlers.RotatingFileHandler(stream, maxBytes=409600, backupCount=3)
+ logger.addHandler(handler)
+
+ # formatter
+ formatter = MyFormatter(
+ fmt = '%(asctime)s %(levelname)-8s %(fname)-20s %(message)s',
+ datefmt = '%b %d %Y %H:%M:%S',
+ )
+ handler.setFormatter(formatter)
+
+ # custom levels
+ logging.addLevelName(75, 'EXCEPT')
+ logging.exception = log_exception
+
+ logging.addLevelName(100, 'STATUS')
+ logging.status = log_status
+
+
+# test
+if __name__ == '__main__':
+ config_logger()
+
+ logging.warning('test')
+ logging.info('test')
+ logging.debug('test')
+ logging.error('test')
+
+ try: err_var
+ except Exception as ex:
+ logging.exception()
+
+ logging.status('test')
Oops, something went wrong.

0 comments on commit 60ca950

Please sign in to comment.