Commits

Don Spaulding  committed 43893a4

Rework to use Werkzeug/Jinja2

  • Participants
  • Parent commits 1677aee
  • Branches mulligan

Comments (0)

Files changed (16)

 ====
 Silk
 ====
-Silk is like the condom of the Python web world.  Everyone expects you to
-invent your own framework, so you might as well do it safely by using Silk.  
-Silk is intended to provide a minimal set of tools that you can use to map HTTP
-requests and responses to the kind of code that fits your brain.
+Everyone expects you to invent your own framework, you might as well do it 
+safely by using Silk. Silk is intended to provide a minimal set of tools 
+that you can use to map HTTP requests and responses to the kind of code 
+that fits your brain.
 
 Also, silk is smooth.
 
 
+Status
+======
+Silk is pre-pre-Alpha.  The code here might work, but it's
+mainly a playground for me to experiment with WSGI concepts. Maybe
+it will grow up some day, but for now, Caveat Emptor.
+
+
 Philosophy
 ==========
 Writing a web app is centered around the idea of accepting a request, and

File examples/todone/__init__.py

Empty file added.

File examples/todone/hello.py

+import silk
+
+@silk.controller
+def hello(request, name='World'):
+    return "Hello, %s!"%name

File examples/todone/website.py

+from silk import Website
+
+import hello#, todos, admin
+
+site = Website(
+    hello = hello,
+    #todos = todos,
+    #admin = admin
+)
+
+
+if __name__ == '__main__':
+    site.run()
 
 setup(
     name='Silk',
-    version='0.1.1',
+    version='0.2.1',
     author='Don Spaulding',
     author_email='donspauldingii@gmail.com',
     packages=['silk', 'silk.apps', 'silk.middleware'],
     url='http://pypi.python.org/pypi/Silk/',
     license='LICENSE.txt',
-    description='A WebOb based mini-framework.',
+    description='A smooth web framework.',
     long_description=open('README.txt').read(),
-    install_requires=['webob', 'tempita', 'spawning'],
+    install_requires=['werkzeug', 'jinja2', 'gunicorn'],
 )

File silk/__init__.py

-from silk.apps.base import WebApp as Application
-from webob import Request, Response
+from werkzeug import Request, Response
+
+from silk.sites import Website
+from silk.controllers import controller

File silk/apps/__init__.py

Empty file removed.

File silk/apps/base.py

-import re
-import sys
-import logging
-from collections import namedtuple
-
-from webob import Request, Response
-
-from silk.default_config import CONFIG
-
-logger = logging.getLogger("silk.apps")
-
-def compile_pattern(pattern):
-    expanders = {
-        'word': '\w+',
-        'words': '[\w\s]+',
-        'int': '\d+',
-        'float': '\d+(\.\d+)?',
-        'date': '\d{4}-\d{2}-\d{2}',
-        'datetime': '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?',
-        'decimal': '\d+(\.\d+)?'
-        'anything': '.*?'
-    }
-
-class Handler(object):
-    def __init__(self, pattern, handler_func, expand_pattern=True):
-        self.pattern = pattern
-        self.handler_func = handler_func
-        if expand_pattern:
-            self.regex, self.expanded = compile_pattern(pattern)
-        else:
-            self.regex, self.expanded = re.compile(pattern), pattern
-
-class ImmediateResponse(Exception):
-    def __init__(self, response):
-        self.response = response
-
-class WebApp(object):
-    def __init__(self, handlers=None, middlewares=None, **config):
-        self.middlewares = middlewares or {}
-        for middleware_category in ('request', 'config', 'handler', 'response', 'exception'):
-            self.middlewares.setdefault(middleware_category, ())
-
-        logger.debug("Handlers loaded:\n\n%s"%self.handlers)
-        conf = CONFIG.copy()
-        conf.update(config)
-        self.config = conf
-
-    def __call__(self, environ, start_response):
-        try:
-            try:
-                request = Request(environ)
-                logger.debug("Received request:\n\n%s"%request)
-                request = self.run_middlewares('request', [request])
-                config = self.config.copy()
-                request, config = self.run_middlewares('config', [request, config])
-                logger.debug("Beginning Request routing for path: %s"%request.path)
-                for regex, pattern, expanded, handler in self.handlers:
-                    match = regex.match(request.path)
-                    if match:
-                        logger.info("%s matches handler url of %s"%(request.path, pattern))
-                        request, config, handler = self.run_middlewares('handler', [request,config,handler])
-                        response = handler(request, config, **match.groupdict())
-                        request, config, handler, response = self.run_middlewares('response', [request, config, handler, response])
-                        start_response(response.status, response.headerlist)
-                        return response.app_iter
-                    raise ImmediateResponse(Response(status=404, body="<h1>404 Not Found</h1>"))
-            except Exception, e:
-                if isinstance(e, ImmediateResponse):
-                    raise
-                import traceback
-                error_text = traceback.format_exc()
-                logger.error("Encountered exception:\n\n%s"% error_text)
-                self.run_middlewares('exception', [locals()])
-                self.notify_admins()
-                if not self.config.get('DEBUG', False):
-                    error_text = '<h1>500 Internal Server Error</h1>'
-                raise ImmediateResponse(Response(status=500, body=error_text))
-        except ImmediateResponse, resp:
-            start_response(resp.response.status, resp.response.headerlist)
-            return resp.response.app_iter
-
-    def run_middlewares(self, category, args):
-        middlewares = self.middlewares[category]
-        logger.debug("Running %s middlewares:\t%s"%(category, str(middlewares)))
-        for middleware in self.middlewares[category]:
-            ret = middleware(*args)
-            if isinstance(ret, Response):
-                logger.info("Middleware %s returned Response."%middleware)
-                raise ImmediateResponse(ret)
-            if ret is not None:
-                args = ret
-        return args if len(args) > 1 else args[0]
-
-    def notify_admins(self):
-        print "NOTIFY ADMINS"
-    
-    def serve(self, host='127.0.0.1', port=8080):
-        from wsgiref.simple_server import make_server
-        server = make_server(host, port, self)
-        server.serve_forever()

File silk/apps/files.py

-import os
-import mimetypes
-
-from silk import Application, Response
-
-class StaticFiles(Application):
-    def __init__(self, root_dir, show_dir_listings=True, default_documents=None, **config):
-        super(StaticFiles, self).__init__({'(?P<path>.*)': self.serve_files}, **config)
-        self.config['STATIC_FILES_ROOT_DIR'] = root_dir
-        self.config['STATIC_FILES_SHOW_DIR_LISTINGS'] = show_dir_listings
-        self.config['STATIC_FILES_DEFAULT_DOCUMENTS'] = default_documents or ['index.html']
-    
-    def serve_files(self, request, config, path):
-        real = os.path.realpath(path)
-        print(real)
-        root = config['STATIC_FILES_ROOT_DIR']
-        if os.path.commonprefix([real,root]) == root:
-            print("found")
-            typ, encoding = mimetypes.guess_type(real)
-            typ = typ or 'application/octet-stream'
-            encoding = encoding or ''
-            return Response(content_type=typ, content_encoding=encoding, body=open(real))
-        return Response(status=404, body='<h1>404 Not Found</h1>')
-
-if __name__ == "__main__":
-    import logging
-    logging.basicConfig()
-    logging.getLogger('silk.apps').setLevel(logging.DEBUG)
-    StaticFiles(os.getcwd()).serve()

File silk/controllers.py

+from silk.options import BaseOptions
+
+def controller(*args, **kwargs):
+    if args: # called as a decorator without any special options.
+        func = args[0]
+        func.silk_options = BaseOptions()
+        func.silk_options.is_view = True
+        return func
+    else:
+        def inner(func):
+            func.silk_options = BaseOptions()
+            for option, value in kwargs.items():
+                setattr(func.silk_options, option, value)
+            func.silk_options.is_view = True
+            return func
+        return inner
+    

File silk/default_config.py

-CONFIG = {
-    'DEBUG': False,
-}

File silk/middleware/__init__.py

Empty file removed.

File silk/options.py

+class BaseOptions(object):
+    pass

File silk/routers.py

+from utils import deepattr
+
+class Router(object):
+    def match(self, request):
+        """
+        Called when are attempting to resolve an HTTP request to a python callable.
+        """
+        raise NotImplementedError
+
+
+class ModuleRouter(object):
+    def __init__(self):
+        self.routes = {}
+        
+    def add_route(self, url_prefix, mod):
+        for var_name in dir(mod):
+            print "Examining: "+var_name
+            if deepattr(mod, var_name+'.silk_options.is_view', False):
+                print "Appears to be a view"
+                self.routes[url_prefix+var_name+'/'] =  getattr(mod, var_name)
+    
+    def match(self, request):
+        print "Attempting to match: "+request.path
+        pieces = [p for p in request.path.split('/') if p]
+        print "Pieces: %s"%pieces
+        print "Routes: %s"%self.routes.keys()
+        if len(pieces) > 2:
+            prefix = "/%s/%s/"%pieces[0:2]
+            if prefix in self.routes:
+                return self.routes[prefix], pieces[2:], None
+            return self.handle_404, [request], {}

File silk/sites.py

+from werkzeug import Request, Response, run_simple
+from jinja2 import Template
+
+from silk.routers import ModuleRouter
+
+class Website(object):
+    def __init__(self, *args, **app_map):
+        self.router = ModuleRouter()
+        for prefix, module in app_map.items():
+            self.router.add_route('/%s/'%prefix, module)
+    
+    def run(self):
+        return run_simple('localhost', 5000, self)
+        
+    def __call__(self, environ, start_response):
+        request = Request(environ)
+        kallable, args, kwargs = self.router.match(request)
+        rv = kallable(*args, **kwargs)
+        if isinstance(rv, basestring):
+            return Response(rv, mimetype='text/html')
+        if isinstance(rv, tuple):
+            return Response(kallable.jinja_env.get_template(rv[0]).render(rv[1]), mimetype='text/html')
+        return rv

File silk/utils.py

+def deepattr(obj, dotted_name, default='$entInel_value_for_d33Padder'):
+    for attr in dotted_name.split('.'):
+        try:
+            obj = getattr(obj, attr)
+        except AttributeError:
+            if default != '$entInel_value_for_d33Padder':
+                return default
+            else:
+                raise