TurboGears2-2.1.5/0000775000175000017500000000000011737460177014507 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/setup.cfg0000664000175000017500000000136311737460177016333 0ustar marvinmarvin00000000000000[aliases] release = egg_info -RDb "" sdist bdist_egg register upload tgdevelop = develop -i http://tg.gy/215/ tgtesting = easy_install -i http://tg.gy/215/ AddOns BytecodeAssembler Chameleon coverage DecoratorTools Extremes Genshi Jinja2 Kajiki kid nose PEAK_Rules repoze.tm2 repoze.what repoze.what.plugins.sql repoze.what_pylons repoze.what_quickstart repoze.who repoze.who_friendlyform repoze.who.plugins.sa repoze.who_testutil simplegeneric simplejson sprox SQLAlchemy SymbolType tgext.admin tgext.crud ToscaWidgets transaction TurboJson TurboKid tw.forms zope.interface zope.sqlalchemy WebFlash yolk basketweaver cover = nosetests --with-coverage [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [nosetests] exclude = who_testutil|kajiki TurboGears2-2.1.5/PKG-INFO0000664000175000017500000000255711737460177015615 0ustar marvinmarvin00000000000000Metadata-Version: 1.0 Name: TurboGears2 Version: 2.1.5 Summary: Next generation TurboGears built on Pylons Home-page: http://www.turbogears.org/ Author: Mark Ramm, Christopher Perkins, Jonathan LaCour, Rick Copland, Alberto Valverde, and the TurboGears community Author-email: mark.ramm@gmail.com, alberto@toscat.net, m.pedersen@icelus.org License: MIT Description: TurboGears brings together a best of breed python tools to create a flexible, full featured, and easy to use web framework. TurboGears 2 provides an integrated and well tested set of tools for everything you need to build dynamic, database driven applications. It provides a full range of tools for front end javascript develeopment, back database development and everything in between: * dynamic javascript powered widgets (ToscaWidgets) * automatic JSON generation from your controllers * powerful, designer friendly XHTML based templating (Genshi) * object or route based URL dispatching * powerful Object Relational Mappers (SQLAlchemy) The latest development version is available in the `TurboGears Git repository`_. .. _TurboGears Git repository: https://sourceforge.net/p/turbogears2/tg2/ Keywords: turbogears pylons Platform: UNKNOWN TurboGears2-2.1.5/tg/0000775000175000017500000000000011737460177015121 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tg/templates/0000775000175000017500000000000011737460177017117 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tg/templates/__init__.py0000664000175000017500000000000011675520537021214 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tg/__init__.py0000664000175000017500000000631011736737176017237 0ustar marvinmarvin00000000000000"""TurboGears 2 is a reinvention of TurboGears and a return to TurboGears' roots. TurboGears is a project that is built upon a foundation of library development best-of-breed component selection, and the re-use of already existing code. And it was always intended to be a small collection of tools, docs, and helpers that made developing with that best-of-breed stack easy. In retrospect, some of the code that was added to the main TurboGears project should have been released as independent projects that integrate with TurboGears. This would have allowed those pieces to grow independently of TurboGears, and would have allowed TurboGears to remain smaller and easier to develop and debug. TurboGears 0.5 release was just a few hundred lines of Python code, but it built on thousands of lines of code in other libraries. Those libraries had already been deployed, used, and tested, and were known to be "production ready." TurboGears2 returns to that philosophy. It is built on Pylons, but it brings a best-of-breed approach to Pylons. TurboGears 2 is commited to the following Python components and libraries, which are backwards compatable with TurboGears 1.1: * Models: SQLAlchemy * Template engines: Genshi * URL Dispatching: Object dispatch * Form Handling: ToscaWidgets The zen of TurboGears is:: Keep simple things simple and complex things possible Give good defaults everywhere and allow choices where they matter Do your best to do things the right way, But when there's no "one right way," don't pretend there is. Mark Ramm described the relationship between TurboGears and Pylons this way "TurboGears 2 is to Pylons as Ubuntu is to Debian." In other words we're focused on user experience, and creating a novice-friendly environment. We ship a smaller subset of components, and thus are better able to focus, test, and document things so that new users have the best possible experience. Meanwhile Pylons provides the power and flexibility of the underlying core. And like Ubuntu, we don't intend to hide that power and flexibility from advanced users, but we know that they want things set up to just work too. Sensible defaults encourage code re-use within TurboGears because they make it possible for a group of TurboGears components to share assumptions about how things will work. """ from pylons import app_globals, request, response, tmpl_context, session, cache, translator from tg.wsgiapp import TGApp from tg.controllers import TGController, redirect, url, lurl, abort from tg.configuration import config from tg.release import version from tg.decorators import (validate, expose, override_template, use_custom_format, require, allow_only) from tg.flash import flash, get_flash, get_status from tg.jsonify import encode as json_encode from tg.controllers.util import use_wsgi_app from tg.controllers.dispatcher import dispatched_controller __version__ = version __all__ = ['__version__', 'allow_only', 'app_globals', 'expose', 'override_template', 'request', 'require', 'response', 'session', 'TGApp', 'TGController', 'tmpl_context', 'use_wsgi_app', 'validate', 'i18n','json_encode', 'cache', 'url', 'lurl', 'dispatched_controller', 'use_custom_format'] TurboGears2-2.1.5/tg/jsonify.py0000664000175000017500000000505011733765036017152 0ustar marvinmarvin00000000000000"""JSON encoding functions.""" import datetime import decimal from simplejson import JSONEncoder from webob.multidict import MultiDict class NotExistingImport: pass try: import sqlalchemy from sqlalchemy.engine.base import ResultProxy, RowProxy except ImportError: ResultProxy=NotExistingImport RowProxy=NotExistingImport try: from bson import ObjectId except ImportError: ObjectId=NotExistingImport def is_saobject(obj): return hasattr(obj, '_sa_class_manager') class JsonEncodeError(Exception): """JSON Encode error""" class GenericJSON(JSONEncoder): """JSON Encoder class""" def default(self, obj): if hasattr(obj, '__json__') and callable(obj.__json__): return obj.__json__() elif isinstance(obj, (datetime.date, datetime.datetime)): return str(obj) elif isinstance(obj, decimal.Decimal): return float(obj) elif is_saobject(obj): props = {} for key in obj.__dict__: if not key.startswith('_sa_'): props[key] = getattr(obj, key) return props elif isinstance(obj, ResultProxy): return dict(rows=list(obj), count=obj.rowcount) elif isinstance(obj, RowProxy): return dict(rows=dict(obj), count=1) elif isinstance(obj, ObjectId): return str(obj) elif isinstance(obj, MultiDict): return obj.mixed() else: return JSONEncoder.default(self, obj) try: from simplegeneric import generic _default = GenericJSON() @generic def jsonify(obj): return _default.default(obj) class GenericFunctionJSON(GenericJSON): """Generic Function JSON Encoder class.""" def default(self, obj): return jsonify(obj) _instance = GenericFunctionJSON() except ImportError: def jsonify(obj): raise ImportError('simplegeneric is not installed') _instance = GenericJSON() # General encoding functions def encode(obj): """Return a JSON string representation of a Python object.""" if isinstance(obj, basestring): return _instance.encode(obj) try: value = obj['test'] except TypeError: if not hasattr(obj, '__json__') and not is_saobject(obj): raise JsonEncodeError('Your Encoded object must be dict-like.') except: pass return _instance.encode(obj) def encode_iter(obj): """Encode object, yielding each string representation as available.""" return _instance.iterencode(obj) TurboGears2-2.1.5/tg/release.py0000664000175000017500000000244511737457417017123 0ustar marvinmarvin00000000000000"""TurboGears project related information""" version = "2.1.5" description = "Next generation TurboGears built on Pylons" long_description=""" TurboGears brings together a best of breed python tools to create a flexible, full featured, and easy to use web framework. TurboGears 2 provides an integrated and well tested set of tools for everything you need to build dynamic, database driven applications. It provides a full range of tools for front end javascript develeopment, back database development and everything in between: * dynamic javascript powered widgets (ToscaWidgets) * automatic JSON generation from your controllers * powerful, designer friendly XHTML based templating (Genshi) * object or route based URL dispatching * powerful Object Relational Mappers (SQLAlchemy) The latest development version is available in the `TurboGears Git repository`_. .. _TurboGears Git repository: https://sourceforge.net/p/turbogears2/tg2/ """ url="http://www.turbogears.org/" author= "Mark Ramm, Christopher Perkins, Jonathan LaCour, Rick Copland, Alberto Valverde, and the TurboGears community" email = "mark.ramm@gmail.com, alberto@toscat.net, m.pedersen@icelus.org" copyright = """Copyright 2005-2011 Kevin Dangoor, Alberto Valverde, Mark Ramm, Christopher Perkins and contributors""" license = "MIT" TurboGears2-2.1.5/tg/dottednames/0000775000175000017500000000000011737460177017430 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tg/dottednames/__init__.py0000664000175000017500000000000011675520537021525 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tg/dottednames/chameleon_genshi_lookup.py0000664000175000017500000000164611733764570024672 0ustar marvinmarvin00000000000000"""Chameleon.Genshi template loader that supports dotted names.""" from chameleon.genshi.loader import TemplateLoader from tg import config class ChameleonGenshiTemplateLoader(TemplateLoader): """Chameleon.Genshi template loader supporting dotted filenames. Supports zipped applications and dotted filenames as well as path names. """ template_extension = '.html' def get_dotted_filename(self, filename): if not filename.endswith(self.template_extension): finder = config['pylons.app_globals'].dotted_filename_finder filename = finder.get_dotted_filename( template_name=filename, template_extension=self.template_extension) return filename def load(self, filename, format='xml'): """Actual loader function.""" return TemplateLoader.load( self, self.get_dotted_filename(filename), format) TurboGears2-2.1.5/tg/dottednames/mako_lookup.py0000664000175000017500000001404511675520537022324 0ustar marvinmarvin00000000000000"""Reimplementation of the Mako template loader that supports dotted names.""" import os import stat try: import threading except ImportError: import dummy_threading as threading from mako.template import Template from paste.deploy.converters import asbool import tg class DottedTemplateLookup(object): """Mako template lookup emulation that supports zipped applications and dotted filenames. This is an emulation of the Mako template lookup that will handle get_template and support dotted names in Python path notation to support zipped eggs. This is necessary because Mako asserts that your project will always be installed in a zip-unsafe manner with all files somewhere on the hard drive. This is not the case when you want your application to be deployed in a single zip file (zip-safe). If you want to deploy in a zip file _and_ use the dotted template name notation then this class is necessary because it emulates files on the filesystem for the underlying Mako engine while they are in fact in your zip file. """ def __init__(self, input_encoding, output_encoding, imports, default_filters, module_directory=None): self.input_encoding = input_encoding self.output_encoding = output_encoding self.imports = imports self.default_filters = default_filters # implement a cache for the loaded templates self.template_cache = dict() # implement a cache for the filename lookups self.template_filenames_cache = dict() self.module_directory = module_directory self.auto_reload = asbool(tg.config.get('templating.mako.reloadfromdisk', 'false')) # a mutex to ensure thread safeness during template loading self._mutex = threading.Lock() def adjust_uri(self, uri, relativeto): """Adjust the given uri relative to a filename. This method is used by mako for filesystem based reasons. In dotted lookup land we don't adjust uri so we just return the value we are given without any change. """ if uri.startswith('local:'): uri = tg.config['pylons.package'] + '.' + uri[6:] if '.' in uri: # We are in the DottedTemplateLookup system so dots in # names should be treated as a Python path. Since this # method is called by template inheritance we must # support dotted names also in the inheritance. result = tg.config['pylons.app_globals'].\ dotted_filename_finder.get_dotted_filename(template_name=uri, template_extension='.mak') if not uri in self.template_filenames_cache: # feed our filename cache if needed. self.template_filenames_cache[uri] = result else: # no dot detected, just return plain name result = uri return result def __check(self, template): """private method used to verify if a template has changed since the last time it has been put in cache... This method being based on the mtime of a real file this should never be called on a zipped deployed application. This method is a ~copy/paste of the original caching system from the Mako lookup loader. """ if template.filename is None: return template if not os.path.exists(template.filename): # remove from cache. self.template_cache.pop(template.filename, None) raise exceptions.TemplateLookupException( "Cant locate template '%s'" % template.filename) elif template.module._modified_time < os.stat( template.filename)[stat.ST_MTIME]: # cache is too old, remove old template # from cache and reload. self.template_cache.pop(template.filename, None) return self.__load(template.filename) else: # cache is correct, use it. return template def __load(self, filename): """real loader function. copy paste from the mako template loader. """ # make sure the template loading from filesystem is only done # one thread at a time to avoid bad clashes... self._mutex.acquire() try: try: # try returning from cache one more time in case # concurrent thread already loaded return self.template_cache[filename] except KeyError: # not in cache yet... we can continue normally pass try: self.template_cache[filename] = Template( filename=filename, module_directory=self.module_directory, input_encoding=self.input_encoding, output_encoding=self.output_encoding, default_filters=self.default_filters, imports=self.imports, lookup=self) return self.template_cache[filename] except: self.template_cache.pop(filename, None) raise finally: # _always_ release the lock once done to avoid # "thread lock" effect self._mutex.release() def get_template(self, template_name): """this is the emulated method that must return a template instance based on a given template name """ if not self.template_cache.has_key(template_name): # the template string is not yet loaded into the cache. # Do so now self.__load(template_name) if self.auto_reload: # AUTO RELOADING will be activated only if user has # explicitly asked for it in the configuration # return the template, but first make sure it's not outdated # and if outdated, refresh the cache. return self.__check(self.template_cache[template_name]) else: return self.template_cache[template_name] TurboGears2-2.1.5/tg/dottednames/genshi_lookup.py0000664000175000017500000000173311733764570022654 0ustar marvinmarvin00000000000000"""Genshi template loader that supports dotted names.""" from genshi.template import TemplateLoader from tg import config class GenshiTemplateLoader(TemplateLoader): """Genshi template loader supporting dotted filenames. Supports zipped applications and dotted filenames as well as path names. """ template_extension = '.html' def get_dotted_filename(self, filename): if not filename.endswith(self.template_extension): finder = config['pylons.app_globals'].dotted_filename_finder filename = finder.get_dotted_filename( template_name=filename, template_extension=self.template_extension) return filename def load(self, filename, relative_to=None, cls=None, encoding=None): """Actual loader function.""" return TemplateLoader.load( self, self.get_dotted_filename(filename), relative_to=relative_to, cls=cls, encoding=encoding) TurboGears2-2.1.5/tg/dottednames/jinja_lookup.py0000664000175000017500000000243011733765570022466 0ustar marvinmarvin00000000000000"""Genshi template loader that supports dotted names.""" from os.path import exists, getmtime from jinja2.exceptions import TemplateNotFound from jinja2.loaders import FileSystemLoader from tg import config class JinjaTemplateLoader(FileSystemLoader): """Jinja template loader supporting dotted filenames. Based on Genshi Loader """ template_extension = '.html' def get_source(self, environment, template): # Check if dottedname if not template.endswith(self.template_extension): # Get the actual filename from dotted finder finder = config['pylons.app_globals'].dotted_filename_finder template = finder.get_dotted_filename( template_name=template, template_extension=self.template_extension) else: return FileSystemLoader.get_source(self, environment, template) # Check if the template exists if not exists(template): raise TemplateNotFound(template) # Get modification time mtime = getmtime(template) # Read the source fd = file(template) try: source = fd.read().decode('utf-8') finally: fd.close() return source, template, lambda: mtime == getmtime(template) TurboGears2-2.1.5/tg/amfify.py0000664000175000017500000000112011675520537016736 0ustar marvinmarvin00000000000000try: from pyamf.remoting.gateway.wsgi import WSGIGateway except: print 'You must easy_install pyamf for to use amf renderer' raise from pylons import request def render_amf(template_name, template_vars, **kwargs): assert 0 # somehow we need to dummy out the services here, but im not sure how # yet def dummy(*args, **kw): return template_vars services = { 'something.method': dummy, } # setup our server app = WSGIGateway(services) def start_request(*args, **kw):pass r = app(request.environ, start_request) return rTurboGears2-2.1.5/tg/flash.py0000664000175000017500000000237011733764765016600 0ustar marvinmarvin00000000000000""" Flash messaging system for sending info to the user in a non-obtrusive way """ from webflash import Flash from pylons import response, request from logging import getLogger log = getLogger(__name__) class TGFlash(Flash): def __call__(self, message, status=None, **extra_payload): # Force the message to be unicode so lazystrings, etc... are coerced result = super(TGFlash, self).__call__( unicode(message), status, **extra_payload ) if len(response.headers['Set-Cookie']) > 4096: raise ValueError, 'Flash value is too long (cookie would be >4k)' return result @property def message(self): return self.pop_payload().get('message') @property def status(self): return self.pop_payload().get('status') or self.default_status flash = TGFlash( get_response=lambda: response, get_request=lambda: request ) #TODO: Deprecate these? def get_flash(): """Get the message previously set by calling flash(). Additionally removes the old flash message. """ return flash.message def get_status(): """Get the status of the last flash message. Additionally removes the old flash message status. """ return flash.status TurboGears2-2.1.5/tg/error.py0000664000175000017500000000766111675520537016634 0ustar marvinmarvin00000000000000import pylons from paste.deploy.converters import asbool from pylons.error import template_error_formatters from weberror.evalexception import EvalException from weberror.errormiddleware import ErrorMiddleware media_path = pylons.middleware.media_path report_libs = pylons.middleware.report_libs if 'tg.devtools' not in report_libs: report_libs.extend(['tg.devtools']) header_html = pylons.middleware.head_html footer_html = """\

TurboGears Online Assistance

 

Looking for help?

Here are a few tips for troubleshooting if the above traceback isn't helping out.

  1. Search the mail list
  2. Post the traceback, and ask for help on IRC
  3. Post a message to the mail list, referring to the posted traceback

Note: Clicking this button will post your traceback to the PylonsHQ website. The traceback includes the module names, Python version, and lines of code that you can see above. All tracebacks are posted anonymously unless you're logged into the PylonsHQ website in this browser.

The following mail lists will be searched:
Python
Pylons
TurboGears
SQLAlchemy
Genshi
ToscaWidgets
Mako
SQLAlchemy

for:

Pylons version %s
""" def ErrorHandler(app, global_conf, **errorware): """ErrorHandler Toggle If debug is enabled, this function will return the app wrapped in the WebError ``EvalException`` middleware which displays interactive debugging sessions when a traceback occurs. Otherwise, the app will be wrapped in the WebError ``ErrorMiddleware``, and the ``errorware`` dict will be passed into it. The ``ErrorMiddleware`` handles sending an email to the address listed in the .ini file, under ``email_to``. """ if asbool(global_conf.get('debug')): footer = footer_html % (pylons.configuration.config.get('traceback_host', 'pylonshq.com'), pylons.__version__) py_media = dict(pylons=media_path) app = EvalException(app, global_conf, templating_formatters=template_error_formatters, media_paths=py_media, head_html=header_html, footer_html=footer, libraries=report_libs) else: app = ErrorMiddleware(app, global_conf, **errorware) return app TurboGears2-2.1.5/tg/configuration.py0000664000175000017500000011512511736737176020354 0ustar marvinmarvin00000000000000"""Configuration Helpers for TurboGears 2""" import atexit import os import logging import warnings from copy import copy import mimetypes from UserDict import DictMixin from pylons.i18n import ugettext from pylons.configuration import config as pylons_config from beaker.middleware import SessionMiddleware, CacheMiddleware from paste.cascade import Cascade from paste.registry import RegistryManager from paste.urlparser import StaticURLParser from paste.deploy.converters import asbool, asint import tg from tg import TGApp from tg.util import Bunch, get_partial_dict, DottedFileNameFinder from routes import Mapper from routes.middleware import RoutesMiddleware from webob import Request log = logging.getLogger(__name__) class TGConfigError(Exception):pass class PylonsConfigWrapper(DictMixin): """Wrapper for the Pylons configuration. Simple wrapper for the Pylons config object that provides attribute style access to the Pylons config dictionary. When used in TG, items with keys like "pylons.response_options" will be available via config.pylons.response_options as well as config['pylons.response_options']. This class works by proxying all attribute and dictionary access to the underlying Pylons config object, which is an application local proxy that allows for multiple Pylons/TG2 applicatoins to live in the same process simultaneously, but to always get the right config data for the application that's requesting them. Sites, with seeking to maximize needs may prefer to use the Pylons config stacked object proxy directly, using just dictionary style access, particularly whenever config is checked on a per-request basis. """ def __init__(self, dict_to_wrap): """Initialize the object by passing in pylons config to be wrapped""" self.__dict__['config_proxy'] = dict_to_wrap def __getitem__(self, key): return self.config_proxy.current_conf()[key] def __setitem__(self, key, value): self.config_proxy.current_conf()[key] = value def __getattr__(self, key): """Our custom attribute getter. Tries to get the attribute off the wrapped object first, if that does not work, tries dictionary lookup, and finally tries to grab all keys that start with the attribute and return sub-dictionaries that can be looked up. """ try: return self.config_proxy.__getattribute__(key) except AttributeError: try: return self.config_proxy.current_conf()[key] except KeyError: return get_partial_dict(key, self.config_proxy.current_conf()) def __setattr__(self, key, value): self.config_proxy.current_conf()[key] = value def __delattr__(self, name): try: del self.config_proxy.current_conf()[name] except KeyError: raise AttributeError(name) def keys(self): return self.config_proxy.keys() #Create a config object that has attribute style lookup built in. config = PylonsConfigWrapper(pylons_config) class AppConfig(Bunch): """Class to store application configuration. This class should have configuration/setup information that is *necessary* for proper application function. Deployment specific configuration information should go in the config files (e.g. development.ini or deployment.ini). AppConfig instances have a number of methods that are meant to be overridden by users who wish to have finer grained control over the setup of the WSGI environment in which their application is run. This is the place to configure custom routes, transaction handling, error handling, etc. """ def __init__(self): """Creates some configuration defaults""" # Create a few bunches we know we'll use self.paths = Bunch() self.render_functions = Bunch() # And also very often... self.sa_auth = Bunch() self.sa_auth.translations = Bunch() #Set individual defaults self.auto_reload_templates = True self.auth_backend = None self.default_renderer = 'genshi' self.stand_alone = True # this is to activate the legacy renderers # legacy renderers are buffet interface plugins self.use_legacy_renderer = False self.use_ming = False self.use_sqlalchemy = False self.use_toscawidgets = True self.use_transaction_manager = True self.use_toscawidgets2 = False # Registry for functions to be called on startup/teardown self.call_on_startup = [] self.call_on_shutdown = [] self.controller_wrappers = [] self.hooks = dict(before_validate=[], before_call=[], before_render=[], after_render=[], before_render_call=[], after_render_call=[], before_config=[], after_config=[]) # The codes TG should display an error page for. All other HTTP errors are # sent to the client or left for some middleware above us to handle self.handle_status_codes = [403, 404] #override this variable to customize how the tw2 middleware is set up self.custom_tw2_config = {} def get_root_module(self): root_module_path = self.paths['root'] base_controller_path = self.paths['controllers'] controller_path = base_controller_path[len(root_module_path)+1:] root_controller_module = '.'.join([self.package.__name__] + controller_path.split(os.sep) + ['root']) return root_controller_module def register_hook(self, hook_name, func): if hook_name == 'startup': self.call_on_startup.append(func) elif hook_name == 'shutdown': self.call_on_shutdown.append(func) elif hook_name == 'controller_wrapper': self.controller_wrappers.append(func) else: self.hooks.setdefault(hook_name, []).append(func) def setup_startup_and_shutdown(self): for cmd in self.call_on_startup: if callable(cmd): try: cmd() except Exception, error: log.debug("Error registering %s at startup: %s" % (cmd, error )) else: log.debug("Unable to register %s for startup" % cmd ) for cmd in self.call_on_shutdown: if callable(cmd): atexit.register(cmd) else: log.debug("Unable to register %s for shutdown" % cmd ) def setup_paths(self): root = os.path.dirname(os.path.abspath(self.package.__file__)) # The default paths: paths = Bunch(root=root, controllers=os.path.join(root, 'controllers'), static_files=os.path.join(root, 'public'), templates=[os.path.join(root, 'templates')]) # If the user defined custom paths, then use them instead of the # default ones: paths.update(self.paths) self.paths = paths def init_config(self, global_conf, app_conf): """Initialize the config object. tg.config is a proxy for pylons.configuration.config that allows attribute style access, so it's automatically setup when we create the pylons config. Besides basic initialization, this method copies all the values in base_config into the ``pylons.configuration.config`` and ``tg.config`` objects. """ pylons_config.init_app(global_conf, app_conf, package=self.package.__name__, paths=self.paths) self.auto_reload_templates = asbool(config.get('auto_reload_templates', True)) pylons_config['application_root_module'] = self.get_root_module() config.update(self) # set up the response options to None. This allows # you to set the proper content type within a controller method # if you choose. pylons_config['pylons.response_options']['headers']['Content-Type'] = None #see http://trac.turbogears.org/ticket/2247 if asbool(config['debug']): config['pylons.strict_tmpl_context'] = True else: config['pylons.strict_tmpl_context'] = False self.after_init_config() def after_init_config(self): """ Override this method to set up configuration variables at the application level. This method will be called after your configuration object has been initialized on startup. Here is how you would use it to override the default setting of pylons.strict_tmpl_context :: from tg.configuration import AppConfig from pylons import config class MyAppConfig(AppConfig): def after_init_config(self): config['pylons.strict_tmpl_context'] = False base_config = MyAppConfig() """ def setup_routes(self): """Setup the default TG2 routes Override this and setup your own routes maps if you want to use custom routes. It is recommended that you keep the existing application routing in tact, and just add new connections to the mapper above the routes_placeholder connection. Lets say you want to add a pylons controller SamplesController, inside the controllers/samples.py file of your application. You would augment the app_cfg.py in the following way:: from routes import Mapper from tg.configuration import AppConfig class MyAppConfig(AppConfig): def setup_routes(self): map = Mapper(directory=config['pylons.paths']['controllers'], always_scan=config['debug']) # Add a Samples route map.connect('/samples/', controller='samples', action=index) # Setup a default route for the root of object dispatch map.connect('*url', controller='root', action='routes_placeholder') config['routes.map'] = map base_config = MyAppConfig() """ map = Mapper(directory=config['pylons.paths']['controllers'], always_scan=config['debug']) # Setup a default route for the root of object dispatch map.connect('*url', controller='root', action='routes_placeholder') config['routes.map'] = map def setup_helpers_and_globals(self): """Add helpers and globals objects to the config. Override this method to customize the way that ``app_globals`` and ``helpers`` are setup. """ config['pylons.app_globals'] = self.package.lib.app_globals.Globals() g = config['pylons.app_globals'] g.dotted_filename_finder = DottedFileNameFinder() def setup_sa_auth_backend(self): """This method adds sa_auth information to the config.""" if 'beaker.session.secret' not in config: raise TGConfigError("You must provide a value for 'beaker.session.secret' If this is a project quickstarted with TG 2.0.2 or earlier \ double check that you have base_config['beaker.session.secret'] = 'mysecretsecret' in your app_cfg.py file.") defaults = { 'form_plugin': None, 'cookie_secret': config['beaker.session.secret'] } # The developer must have defined a 'sa_auth' section, because # values such as the User, Group or Permission classes must be # explicitly defined. config['sa_auth'] = defaults config['sa_auth'].update(self.sa_auth) def setup_mako_renderer(self, use_dotted_templatenames=None): """Setup a renderer and loader for mako templates. Override this to customize the way that the mako template renderer is setup. In particular if you want to setup a different set of search paths, different encodings, or additonal imports, all you need to do is update the ``TemplateLookup`` constructor. You can also use your own render_mako function instead of the one provided by tg.render. """ from tg.render import render_mako if not use_dotted_templatenames: use_dotted_templatenames = asbool(config.get('use_dotted_templatenames', 'true')) # If no dotted names support was required we will just setup # a file system based template lookup mechanism. compiled_dir = tg.config.get('templating.mako.compiled_templates_dir', None) if not compiled_dir: # Try each given templates path (when are they > 1 ?) for writability.. for template_path in self.paths['templates']: if os.access(template_path, os.W_OK): compiled_dir = template_path break # first match is as good as any # Last recourse: project-dir/data/templates (pylons' default directory) if not compiled_dir: try: root = os.path.dirname(os.path.abspath(self.package.__file__)) except AttributeError: # Thrown during unit tests when self.package.__file__ doesn't exist root = None if root: pylons_default_path = os.path.join(root, '../data/templates') if os.access(pylons_default_path, os.W_OK): compiled_dir = pylons_default_path if not compiled_dir: if use_dotted_templatenames: # Gracefully digress to in-memory template caching pass else: raise IOError("None of your templates directory, %s, are " "writable for compiled templates. Please set the " "templating.mako.compiled_templates_dir variable in your " ".ini file" % str(self.paths['templates'])) if use_dotted_templatenames: # Support dotted names by injecting a slightly different template # lookup system that will return templates from dotted template notation. from tg.dottednames.mako_lookup import DottedTemplateLookup config['pylons.app_globals'].mako_lookup = DottedTemplateLookup( input_encoding='utf-8', output_encoding='utf-8', imports=['from webhelpers.html import escape'], module_directory=compiled_dir, default_filters=['escape']) else: from mako.lookup import TemplateLookup config['pylons.app_globals'].mako_lookup = TemplateLookup( directories=self.paths['templates'], module_directory=compiled_dir, input_encoding='utf-8', output_encoding='utf-8', imports=['from webhelpers.html import escape'], default_filters=['escape'], filesystem_checks=self.auto_reload_templates) self.render_functions.mako = render_mako def setup_chameleon_genshi_renderer(self): """Setup a renderer and loader for the chameleon.genshi engine.""" from tg.render import RenderChameleonGenshi if config.get('use_dotted_templatenames', True): from tg.dottednames.chameleon_genshi_lookup \ import ChameleonGenshiTemplateLoader as TemplateLoader else: from chameleon.genshi.loader import TemplateLoader loader = TemplateLoader(search_path=self.paths.templates, auto_reload=self.auto_reload_templates) self.render_functions.chameleon_genshi = RenderChameleonGenshi(loader) def setup_genshi_renderer(self): """Setup a renderer and loader for Genshi templates. Override this to customize the way that the internationalization filter, template loader """ from tg.render import RenderGenshi from genshi.filters import Translator def template_loaded(template): """Plug-in our i18n function to Genshi, once the template is loaded. This function will be called by the Genshi TemplateLoader after loading the template. """ translator = Translator(ugettext) template.filters.insert(0, translator) if hasattr(template, 'add_directives'): template.add_directives(Translator.NAMESPACE, translator) if config.get('use_dotted_templatenames', True): from tg.dottednames.genshi_lookup \ import GenshiTemplateLoader as TemplateLoader else: from genshi.template import TemplateLoader loader = TemplateLoader(search_path=self.paths.templates, max_cache_size=asint(self.get('genshi.max_cache_size', 30)), auto_reload=self.auto_reload_templates, callback=template_loaded) self.render_functions.genshi = RenderGenshi(loader) def setup_kajiki_renderer(self): """Setup a renderer and loader for the fastpt engine.""" from kajiki.loader import PackageLoader from tg.render import render_kajiki loader = PackageLoader() config['pylons.app_globals'].kajiki_loader = loader self.render_functions.kajiki = render_kajiki def setup_jinja_renderer(self): """Setup a renderer and loader for Jinja2 templates.""" from jinja2 import ChoiceLoader, Environment from jinja2.filters import FILTERS from tg.render import render_jinja if config.get('use_dotted_templatenames', True): from tg.dottednames.jinja_lookup import JinjaTemplateLoader as TemplateLoader else: from jinja2 import FileSystemLoader as TemplateLoader if not 'jinja_extensions' in self : self.jinja_extensions = [] if not 'jinja_filters' in self: self.jinja_filters = {} loader = ChoiceLoader( [TemplateLoader(path) for path in self.paths['templates']]) config['pylons.app_globals'].jinja2_env = Environment(loader=loader, auto_reload=self.auto_reload_templates, extensions=self.jinja_extensions) # Try to load custom filters module under app_package.lib.templatetools try: filter_package = self.package.__name__ + ".lib.templatetools" autoload_lib = __import__(filter_package, {}, {}, ['jinja_filters']) autoload_filters = autoload_lib.jinja_filters.__dict__ except (ImportError, AttributeError): autoload_filters = {} # Add jinja filters filters = dict(FILTERS, **autoload_filters) filters.update(self.jinja_filters) config['pylons.app_globals'].jinja2_env.filters = filters # Jinja's unable to request c's attributes without strict_c warnings.simplefilter("ignore") config['pylons.strict_c'] = True warnings.resetwarnings() config['pylons.strict_tmpl_context'] = True self.render_functions.jinja = render_jinja def setup_amf_renderer(self): from tg.amfify import render_amf self.render_functions.amf = render_amf def setup_json_renderer(self): from tg.render import render_json self.render_functions.json = render_json def setup_default_renderer(self): """Setup template defaults in the buffed plugin. This is only used when use_legacy_renderer is set to True and it will not get deprecated in the next major TurboGears release. """ #T his is specific to buffet, will not be needed later config['buffet.template_engines'].pop() template_location = '%s.templates' % self.package.__name__ template_location = '%s.templates' % self.package.__name__ from genshi.filters import Translator def template_loaded(template): template.filters.insert(0, Translator(ugettext)) # Set some default options for genshi options = { 'genshi.loader_callback': template_loaded, 'genshi.default_format': 'xhtml', } # Override those options from config config['buffet.template_options'].update(options) config.add_template_engine(self.default_renderer, template_location, {}) def setup_mimetypes(self): lookup = {'.json':'application/json'} lookup.update(config.get('mimetype_lookup', {})) for key, value in lookup.iteritems(): mimetypes.add_type(value, key) def setup_persistence(self): """Override this method to define how your application configures it's persistence model. the default is to setup sqlalchemy from the cofiguration file, but you might choose to set up a persistence system other than sqlalchemy, or add an additional persistence layer. Here is how you would go about setting up a ming (mongo) persistence layer:: class MingAppConfig(AppConfig): def setup_persistence(self): self.ming_ds = DataStore(config['mongo.url']) session = Session.by_name('main') session.bind = self.ming_ds """ if self.use_sqlalchemy: self.setup_sqlalchemy() elif self.use_ming: self.setup_ming() def setup_ming(self): """Setup MongoDB database engine using Ming""" from ming.datastore import DataStore datastore = DataStore(config['ming.url'], database=config['ming.db']) config['pylons.app_globals'].ming_datastore = datastore self.package.model.init_model(datastore) def setup_sqlalchemy(self): """Setup SQLAlchemy database engine. The most common reason for modifying this method is to add multiple database support. To do this you might modify your app_cfg.py file in the following manner:: from tg.configuration import AppConfig, config from pylons import config as pylons_config from myapp.model import init_model # add this before base_config = class MultiDBAppConfig(AppConfig): def setup_sqlalchemy(self): '''Setup SQLAlchemy database engine(s)''' from sqlalchemy import engine_from_config engine1 = engine_from_config(pylons_config, 'sqlalchemy.first.') engine2 = engine_from_config(pylons_config, 'sqlalchemy.second.') # engine1 should be assigned to sa_engine as well as your first engine's name config['pylons.app_globals'].sa_engine = engine1 config['pylons.app_globals'].sa_engine_first = engine1 config['pylons.app_globals'].sa_engine_second = engine2 # Pass the engines to init_model, to be able to introspect tables init_model(engine1, engine2) #base_config = AppConfig() base_config = MultiDBAppConfig() This will pull the config settings from your .ini files to create the necessary engines for use within your application. Make sure you have a look at :ref:`multidatabase` for more information. """ from sqlalchemy import engine_from_config engine = engine_from_config(pylons_config, 'sqlalchemy.') config['pylons.app_globals'].sa_engine = engine # Pass the engine to initmodel, to be able to introspect tables self.package.model.init_model(engine) def setup_auth(self): """ Override this method to define how you would like the auth to be set up for your app. For the standard TurboGears App, this will set up the auth with SQLAlchemy. """ if self.auth_backend in ("ming", "sqlalchemy"): self.setup_sa_auth_backend() def make_load_environment(self): """Return a load_environment function. The returned load_environment function can be called to configure the TurboGears runtime environment for this particular application. You can do this dynamically with multiple nested TG applications if necessary. """ def load_environment(global_conf, app_conf): """Configure the Pylons environment via ``pylons.configuration.config``.""" global_conf=Bunch(global_conf) app_conf=Bunch(app_conf) self.setup_paths() self.init_config(global_conf, app_conf) #Registers functions to be called at startup and shutdown #from self.call_on_startup and shutdown respectively. self.setup_startup_and_shutdown() self.setup_routes() self.setup_helpers_and_globals() self.setup_mimetypes() self.setup_auth() if not 'json' in self.renderers: self.renderers.append('json') for renderer in self.renderers: setup = getattr(self, 'setup_%s_renderer'%renderer, None) if setup: setup() else: raise Exception('This configuration object does not support the %s renderer'%renderer) if self.use_legacy_renderer: self.setup_default_renderer() self.setup_persistence() return load_environment def add_error_middleware(self, global_conf, app): """Add middleware which handles errors and exceptions.""" from pylons.middleware import report_libs, StatusCodeRedirect from tg.error import ErrorHandler app = ErrorHandler(app, global_conf, **config['pylons.errorware']) # Display error documents for self.handle_status_codes status codes (and # 500 when debug is disabled) if asbool(config['debug']): app = StatusCodeRedirect(app, self.handle_status_codes) else: app = StatusCodeRedirect(app, self.handle_status_codes + [500]) return app def add_auth_middleware(self, app, skip_authentication): """ Configure authentication and authorization. :param app: The TG2 application. :param skip_authentication: Should authentication be skipped if explicitly requested? (used by repoze.who-testutil) :type skip_authentication: bool """ from repoze.what.plugins.pylonshq import booleanize_predicates # Predicates booleanized: booleanize_predicates() # Configuring auth logging: if 'log_stream' not in self.sa_auth: self.sa_auth['log_stream'] = logging.getLogger('auth') # Removing keywords not used by repoze.who: auth_args = copy(self.sa_auth) if 'sa_auth' in config: auth_args.update(config.sa_auth) if 'password_encryption_method' in auth_args: del auth_args['password_encryption_method'] if not skip_authentication: if not 'cookie_secret' in auth_args.keys(): msg = "base_config.sa_auth.cookie_secret is required "\ "you must define it in app_cfg.py or set "\ "sa_auth.cookie_secret in development.ini" raise TGConfigError(msg) if self.auth_backend == "sqlalchemy": from repoze.what.plugins.quickstart import setup_sql_auth app = setup_sql_auth(app, skip_authentication=skip_authentication, **auth_args) elif self.auth_backend == "ming": from tgming import setup_ming_auth app = setup_ming_auth(app, skip_authentication=skip_authentication, **auth_args) return app def add_core_middleware(self, app): """Add support for routes dispatch, sessions, and caching. This is where you would want to override if you wanted to provide your own routing, session, or caching middleware. Your app_cfg.py might look something like this:: from tg.configuration import AppConfig from routes.middleware import RoutesMiddleware from beaker.middleware import CacheMiddleware from mysessionier.middleware import SessionMiddleware class MyAppConfig(AppConfig): def add_core_middleware(self, app): app = RoutesMiddleware(app, config['routes.map']) app = SessionMiddleware(app, config) app = CacheMiddleware(app, config) return app base_config = MyAppConfig() """ app = RoutesMiddleware(app, config['routes.map']) app = SessionMiddleware(app, config) app = CacheMiddleware(app, config) return app def add_tosca_middleware(self, app): """Configure the ToscaWidgets middleware. If you would like to override the way the TW middleware works, you might do something like:: from tg.configuration import AppConfig from tw.api import make_middleware as tw_middleware class MyAppConfig(AppConfig): def add_tosca2_middleware(self, app): app = tw_middleware(app, { 'toscawidgets.framework.default_view': self.default_renderer, 'toscawidgets.framework.translator': ugettext, 'toscawidgets.middleware.inject_resources': False, }) return app base_config = MyAppConfig() The above example would disable resource injection. There is more information about the settings you can change in the ToscaWidgets `middleware. ` """ from tw.api import make_middleware as tw_middleware twconfig = {'toscawidgets.framework.default_view': self.default_renderer, 'toscawidgets.framework.translator': ugettext, 'toscawidgets.middleware.inject_resources': True, } for k,v in config.iteritems(): if k.startswith('toscawidgets.framework.') or k.startswith('toscawidgets.middleware.'): twconfig[k] = v if 'toscawidgets.framework.resource_variant' in config: import tw.api tw.api.resources.registry.ACTIVE_VARIANT = config['toscawidgets.framework.resource_variant'] #remove it from the middleware madness del twconfig['toscawidgets.framework.resource_variant'] app = tw_middleware(app, twconfig) return app def add_tosca2_middleware(self, app): """Configure the ToscaWidgets2 middleware. If you would like to override the way the TW2 middleware works, you might do change your app_cfg.py to add something like:: from tg.configuration import AppConfig from tw2.core.middleware import TwMiddleware class MyAppConfig(AppConfig): def add_tosca2_middleware(self, app): app = TwMiddleware(app, default_engine=self.default_renderer, translator=ugettext, auto_reload_templates = False ) return app base_config = MyAppConfig() The above example would always set the template auto reloading off. (This is normally an option that is set within your application's ini file.) """ from tw2.core.middleware import Config, TwMiddleware default_tw2_config = dict( default_engine=self.default_renderer, translator=ugettext, auto_reload_templates=asbool(self.get('templating.mako.reloadfromdisk', 'false')) ) default_tw2_config.update(self.custom_tw2_config) app = TwMiddleware(app, **default_tw2_config) return app def add_static_file_middleware(self, app): static_app = StaticURLParser(config['pylons.paths']['static_files']) app = Cascade([static_app, app]) return app def commit_veto(self, environ, status, headers): """Veto a commit. This hook is called by repoze.tm in case we want to veto a commit for some reason. Return True to force a rollback. By default we veto if the response's status code is an error code. Override this method, or monkey patch the instancemethod, to fine tune this behaviour. """ return not 200 <= int(status.split(None, 1)[0]) < 400 def add_tm_middleware(self, app): """Set up the transaction managment middleware. To abort a transaction inside a TG2 app:: import transaction transaction.doom() By default http error responses also roll back transactions, but this behavior can be overridden by overriding base_config.commit_veto. """ from repoze.tm import make_tm return make_tm(app, self.commit_veto) def add_ming_middleware(self, app): """Set up the ming middleware for the unit of work""" import ming.orm.middleware return ming.orm.middleware.MingMiddleware(app) def add_dbsession_remover_middleware(self, app): """Set up middleware that cleans up the sqlalchemy session. The default behavior of TG 2 is to clean up the session on every request. Only override this method if you know what you are doing! """ def remover(environ, start_response): try: return app(environ, start_response) finally: log.debug("Removing DBSession from current thread") self.DBSession.remove() return remover def setup_tg_wsgi_app(self, load_environment): """Create a base TG app, with all the standard middleware. ``load_environment`` A required callable, which sets up the basic evironment needed for the application. ``setup_vars`` A dictionary with all special values necessary for setting up the base wsgi app. """ def make_base_app(global_conf, wrap_app=None, full_stack=True, **app_conf): """Create a tg WSGI application and return it. ``wrap_app`` a WSGI middleware component which takes the core turbogears application and wraps it -- inside all the WSGI-components provided by TG and Pylons. This allows you to work with the full environment that your TG application would get before anything happens in the application itself. ``global_conf`` The inherited configuration for this application. Normally from the [DEFAULT] section of the Paste ini file. ``full_stack`` Whether or not this application provides a full WSGI stack (by default, meaning it handles its own exceptions and errors). Disable full_stack when this application is "managed" by another WSGI middleware. ``app_conf`` The application's local configuration. Normally specified in the [app:] section of the Paste ini file (where defaults to main). """ # Configure the Pylons environment load_environment(global_conf, app_conf) app = TGApp() if wrap_app: app = wrap_app(app) for hook in self.hooks['before_config']: app = hook(app) avoid_sess_touch = config.get('beaker.session.tg_avoid_touch', 'false') config['beaker.session.tg_avoid_touch'] = asbool(avoid_sess_touch) app = self.add_core_middleware(app) if self.use_toscawidgets: app = self.add_tosca_middleware(app) if self.use_toscawidgets2: app = self.add_tosca2_middleware(app) if self.auth_backend: # Skipping authentication if explicitly requested. Used by # repoze.who-testutil: skip_authentication = app_conf.get('skip_authentication', False) app = self.add_auth_middleware(app, skip_authentication) if self.use_transaction_manager: app = self.add_tm_middleware(app) if self.use_sqlalchemy: if not hasattr(self, 'DBSession'): # If the user hasn't specified a scoped_session, assume # he/she uses the default DBSession in model self.DBSession = self.model.DBSession app = self.add_dbsession_remover_middleware(app) if self.use_ming: app = self.add_ming_middleware(app) if pylons_config.get('make_body_seekable'): app = maybe_make_body_seekable(app) if 'PYTHONOPTIMIZE' in os.environ: warnings.warn("Forcing full_stack=False due to PYTHONOPTIMIZE enabled. "+\ "Error Middleware will be disabled", RuntimeWarning, stacklevel=2) full_stack = False if asbool(full_stack): if (self.auth_backend is None and 401 not in self.handle_status_codes): # If there's no auth backend configured which traps 401 # responses we redirect those responses to a nicely # formatted error page self.handle_status_codes.append(401) # This should never be true for internal nested apps app = self.add_error_middleware(global_conf, app) # Establish the registry for this application app = RegistryManager(app) # Static files (if running in production, and Apache or another # web server is serving static files) #if the user has set the value in app_config, don't pull it from the ini if not hasattr(self, 'serve_static'): self.serve_static = asbool(config.get('serve_static', 'true')) if self.serve_static: app = self.add_static_file_middleware(app) for hook in self.hooks['after_config']: app = hook(app) return app return make_base_app def maybe_make_body_seekable(app): def wrapper(environ, start_response): log.debug("Making request body seekable") Request(environ).make_body_seekable() return app(environ, start_response) return wrapper TurboGears2-2.1.5/tg/paginate.py0000664000175000017500000000412111733764570017261 0ustar marvinmarvin00000000000000from webhelpers.paginate import Page as WhPage from webhelpers.html import HTML from tg import request from tg.controllers.util import url class Page(WhPage): def _pagerlink(self, pagenr, text): """ Create a URL that links to another page using url_for(). Parameters: pagenr Number of the page that the link points to text Text to be printed in the A-HREF tag """ # Let the url_for() from webhelpers create a new link and set # the variable called 'page_param'. Example: # You are in '/foo/bar' (controller='foo', action='bar') # and you want to add a parameter 'pagenr'. Then you # call the navigator method with page_param='pagenr' and # the url_for() call will create a link '/foo/bar?pagenr=...' # with the respective page number added. link_params = {} # Use the instance kwargs from Page.__init__ as URL parameters link_params.update(self.kwargs) # Add keyword arguments from pager() to the link as parameters link_params.update(self.pager_kwargs) link_params[self.page_param] = pagenr # Create the URL to load the page area part of a certain page (AJAX updates) partial_url = link_params.pop('partial', '') #url_for(**link_params) # Create the URL to load a certain page link_url = link_params.pop('link', request.path_info) link_url = HTML.literal(url(link_url, params=link_params)) if self.onclick: # create link with onclick action for AJAX try: # if '%s' is used in the 'onclick' parameter (backwards compatibility) onclick_action = self.onclick % (partial_url,) except TypeError: onclick_action = Template(self.onclick).safe_substitute({ "partial_url": partial_url, "page": pagenr }) return HTML.a(text, href=link_url, onclick=onclick_action, **self.link_attr) else: # return static link return HTML.a(text, href=link_url, **self.link_attr) TurboGears2-2.1.5/tg/controllers/0000775000175000017500000000000011737460177017467 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tg/controllers/__init__.py0000664000175000017500000000105011736737176021601 0ustar marvinmarvin00000000000000from dispatcher import ObjectDispatcher from decoratedcontroller import DecoratedController, CUSTOM_CONTENT_TYPE from wsgiappcontroller import WSGIAppController from tgcontroller import TGController from restcontroller import RestController from pylons.controllers.util import abort from util import redirect, url, lurl, pylons_formencode_gettext __all__ = ['abort', 'redirect', 'url', 'lurl', 'pylons_formencode_gettext', 'DecoratedController', 'CUSTOM_CONTENT_TYPE', 'RestController', 'TGController', 'WSGIAppController'] TurboGears2-2.1.5/tg/controllers/restcontroller.py0000664000175000017500000003771511736737176023144 0ustar marvinmarvin00000000000000"""This module contains the RestController implementation. Rest controller provides a RESTful dispatch mechanism, and combines controller decoration for TG-Controller behavior. """ import pylons from pylons.controllers.util import abort import inspect from dispatcher import ObjectDispatcher from decoratedcontroller import DecoratedController class RestDispatcher(ObjectDispatcher): """Defines a restful interface for a set of HTTP verbs. Please see RestController for a rundown of the controller methods used. """ def _setup_wsgiorg_routing_args(self, url_path, remainder, params): pylons.request.environ['wsgiorg.routing_args'] = (tuple(remainder), params) def _handle_put_or_post(self, method, state, remainder): current_controller = state.controller if remainder: current_path = remainder[0] if self._is_exposed(current_controller, current_path): state.add_method(getattr(current_controller, current_path), remainder[1:]) return state if self._is_controller(current_controller, current_path): current_controller = getattr(current_controller, current_path) return self._dispatch_controller(current_path, current_controller, state, remainder[1:]) method_name = method method = self._find_first_exposed(current_controller, [method,]) if method and self._method_matches_args(method, state, remainder): state.add_method(method, remainder) return state return self._dispatch_first_found_default_or_lookup(state, remainder) def _handle_delete(self, method, state, remainder): current_controller = state.controller method_name = method method = self._find_first_exposed(current_controller, ('post_delete', 'delete')) if method and self._method_matches_args(method, state, remainder): state.add_method(method, remainder) return state #you may not send a delete request to a non-delete function if remainder and self._is_exposed(current_controller, remainder[0]): abort(405) # there might be a sub-controller with a delete method, let's go see if remainder: sub_controller = getattr(current_controller, remainder[0], None) if sub_controller: remainder = remainder[1:] state.current_controller = sub_controller state.url_path = '/'.join(remainder) r = self._dispatch_controller(state.url_path, sub_controller, state, remainder) if r: return r return self._dispatch_first_found_default_or_lookup(state, remainder) def _check_for_sub_controllers(self, state, remainder): current_controller = state.controller method = None for find in ('get_one', 'get'): if hasattr(current_controller, find): method = find break if method is None: return args = self._get_argspec(getattr(current_controller, method)) fixed_args = args[0][1:] fixed_arg_length = len(fixed_args) var_args = args[1] if var_args: for i, item in enumerate(remainder): if hasattr(current_controller, item) and self._is_controller(current_controller, item): current_controller = getattr(current_controller, item) state.add_routing_args(item, remainder[:i], fixed_args, var_args) return self._dispatch_controller(item, current_controller, state, remainder[i+1:]) elif fixed_arg_length< len(remainder) and hasattr(current_controller, remainder[fixed_arg_length]): item = remainder[fixed_arg_length] if hasattr(current_controller, item): if self._is_controller(current_controller, item): state.add_routing_args(item, remainder, fixed_args, var_args) return self._dispatch_controller(item, getattr(current_controller, item), state, remainder[fixed_arg_length+1:]) def _handle_delete_edit_or_new(self, state, remainder): method_name = remainder[-1] if method_name not in ('new', 'edit', 'delete'): return if method_name == 'delete': method_name = 'get_delete' current_controller = state.controller if self._is_exposed(current_controller, method_name): method = getattr(current_controller, method_name) new_remainder = remainder[:-1] if method and self._method_matches_args(method, state, new_remainder): state.add_method(method, new_remainder) return state def _handle_custom_get(self, state, remainder): method_name = remainder[-1] current_controller = state.controller if (self._is_exposed(current_controller, method_name) or self._is_exposed(current_controller, 'get_%s' % method_name)): method = self._find_first_exposed(current_controller, ('get_%s' % method_name, method_name)) new_remainder = remainder[:-1] if method and self._method_matches_args(method, state, new_remainder): state.add_method(method, new_remainder) return state def _handle_custom_method(self, method, state, remainder): current_controller = state.controller method_name = method method = self._find_first_exposed(current_controller, ('post_%s' % method_name, method_name)) if method and self._method_matches_args(method, state, remainder): state.add_method(method, remainder) return state #you may not send a delete request to a non-delete function if remainder and self._is_exposed(current_controller, remainder[0]): abort(405) # there might be a sub-controller with a delete method, let's go see if remainder: sub_controller = getattr(current_controller, remainder[0], None) if sub_controller: remainder = remainder[1:] state.current_controller = sub_controller state.url_path = '/'.join(remainder) r = self._dispatch_controller(state.url_path, sub_controller, state, remainder) if r: return r return self._dispatch_first_found_default_or_lookup(state, remainder) def _handle_get(self, method, state, remainder): current_controller = state.controller if not remainder: method = self._find_first_exposed(current_controller, ('get_all', 'get')) if method: state.add_method(method, remainder) return state if self._is_exposed(current_controller, 'get_one'): method = current_controller.get_one if method and self._method_matches_args(method, state, remainder): state.add_method(method, remainder) return state return self._dispatch_first_found_default_or_lookup(state, remainder) #test for "delete", "edit" or "new" r = self._handle_delete_edit_or_new(state, remainder) if r: return r #test for custom REST-like attribute r = self._handle_custom_get(state, remainder) if r: return r current_path = remainder[0] if self._is_exposed(current_controller, current_path): state.add_method(getattr(current_controller, current_path), remainder[1:]) return state if self._is_controller(current_controller, current_path): current_controller = getattr(current_controller, current_path) return self._dispatch_controller(current_path, current_controller, state, remainder[1:]) if self._is_exposed(current_controller, 'get_one') or self._is_exposed(current_controller, 'get'): if self._is_exposed(current_controller, 'get_one'): method = current_controller.get_one else: method = current_controller.get if method and self._method_matches_args(method, state, remainder): state.add_method(method, remainder) return state return self._dispatch_first_found_default_or_lookup(state, remainder) _handler_lookup = { 'put':_handle_put_or_post, 'post':_handle_put_or_post, 'delete':_handle_delete, 'get':_handle_get, } def _dispatch(self, state, remainder): """returns: populated DispachState object """ if not hasattr(state, 'http_method'): method = pylons.request.method.lower() params = state.params #conventional hack for handling methods which are not supported by most browsers request_method = params.get('_method', None) if request_method: request_method = request_method.lower() #make certain that DELETE and PUT requests are not sent with GET if method == 'get' and request_method == 'put': abort(405) if method == 'get' and request_method == 'delete': abort(405) method = request_method state.http_method = method r = self._check_for_sub_controllers(state, remainder) if r: return r if state.http_method in self._handler_lookup.keys(): r = self._handler_lookup[state.http_method](self, state.http_method, state, remainder) else: r = self._handle_custom_method(state.http_method, state, remainder) #clear out the method hack if '_method' in pylons.request.POST: del pylons.request.POST['_method'] del state.params['_method'] if '_method' in pylons.request.GET: del pylons.request.GET['_method'] del state.params['_method'] return r class RestController(DecoratedController, RestDispatcher): """A Decorated Controller that dispatches in a RESTful Manner. This controller was designed to follow Representational State Transfer protocol, also known as REST. The goal of this controller method is to provide the developer a way to map RESTful URLS to controller methods directly, while still allowing Normal Object Dispatch to occur. Here is a brief rundown of the methods which are called on dispatch along with an example URL. +-----------------+--------------------------------------------------------------+--------------------------------------------+ | Method | Description | Example Method(s) / URL(s) | +=================+==============================================================+============================================+ | get_one | Display one record. | GET /movies/1 | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | get_all | Display all records in a resource. | GET /movies/ | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | get | A combo of get_one and get_all. | GET /movies/ | | | +--------------------------------------------+ | | | GET /movies/1 | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | new | Display a page to prompt the User for resource creation. | GET /movies/new | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | edit | Display a page to prompt the User for resource modification. | GET /movies/1/edit | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | post | Create a new record. | POST /movies/ | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | put | Update an existing record. | POST /movies/1?_method=PUT | | | +--------------------------------------------+ | | | PUT /movies/1 | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | post_delete | Delete an existing record. | POST /movies/1?_method=DELETE | | | +--------------------------------------------+ | | | DELETE /movies/1 | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | get_delete | Display a delete Confirmation page. | GET /movies/1/delete | +-----------------+--------------------------------------------------------------+--------------------------------------------+ | delete | A combination of post_delete and get_delete. | GET /movies/delete | | | +--------------------------------------------+ | | | DELETE /movies/1 | | | +--------------------------------------------+ | | | DELETE /movies/ | | | +--------------------------------------------+ | | | POST /movies/1/delete | | | +--------------------------------------------+ | | | POST /movies/delete | +-----------------+--------------------------------------------------------------+--------------------------------------------+ You may note the ?_method on some of the URLs. This is basically a hack because exiting browsers do not support the PUT and DELETE methods. Just note that if you decide to use a this resource with a web browser, you will likely have to add a _method as a hidden field in your forms for these items. Also note that RestController differs from TGController in that it offers no index, _default, or _lookup. It is intended primarily for resource management. :References: `Controller <../main/Controllers.html>`_ A basic overview on how to write controller methods. `CrudRestController <../main/Extensions/Crud/index.html>`_ A way to integrate ToscaWdiget Functionality with RESTful Dispatch. """ __all__ = ['RestController'] TurboGears2-2.1.5/tg/controllers/dispatcher.py0000664000175000017500000005007611736737176022204 0ustar marvinmarvin00000000000000""" This is the main dispatcher module. Dispatch works as follows: Start at the RootController, the root controller must have a _dispatch function, which defines how we move from object to object in the system. Continue following the dispatch mechanism for a given controller until you reach another controller with a _dispatch method defined. Use the new _dispatch method until anther controller with _dispatch defined or until the url has been traversed to entirety. This module also contains the standard ObjectDispatch class which provides the ordinary TurboGears mechanism. """ from inspect import getargspec, isclass, ismethod import mimetypes import sys from warnings import warn import pylons from pylons.controllers import WSGIController from tg.exceptions import HTTPNotFound from tg.i18n import setup_i18n from tg.decorators import cached_property HTTPNotFound = HTTPNotFound().exception def dispatched_controller(): state = pylons.request.controller_state for location, cont in reversed(state.controller_path): if cont.mount_point: return cont return None class DispatchState(object): """ This class keeps around all the pertainent info for the state of the dispatch as it traverses through the tree. This allows us to attach things like routing args and to keep track of the path the controller takes along the system. """ def __init__(self, url_path, params): self.url_path = url_path self.controller_path = [] self.routing_args = {} self.method = None self.remainder = None self.dispatcher = None self.params = params self._notfound_stack = [] #remove the ignore params from self.params remove_params = pylons.config.get('ignore_parameters', []) for param in remove_params: if param in self.params: del self.params[param] def add_controller(self, location, controller): """Add a controller object to the stack""" self.controller_path.append((location, controller)) def add_method(self, method, remainder): """Add the final method that will be called in the _call method""" self.method = method self.remainder = remainder def add_routing_args(self, current_path, remainder, fixed_args, var_args): """ Add the "intermediate" routing args for a given controller mounted at the current_path """ i = 0 for i, arg in enumerate(fixed_args): if i >= len(remainder): break self.routing_args[arg] = remainder[i] remainder = remainder[i:] if var_args and remainder: self.routing_args[current_path] = remainder @property def controller(self): """returns the current controller""" return self.controller_path[-1][1] class Dispatcher(WSGIController): """ Extend this class to define your own mechanism for dispatch. """ def _call(self, controller, params, remainder=None): """Override to define how your controller method should be called.""" response = controller(*remainder, **dict(params)) return response def _get_argspec(self, func): try: cached_argspecs = self.__class__._cached_argspecs except AttributeError: self.__class__._cached_argspecs = cached_argspecs = {} try: argspec = cached_argspecs[func.im_func] except KeyError: argspec = cached_argspecs[func.im_func] = getargspec(func) return argspec def _get_params_with_argspec(self, func, params, remainder): params = params.copy() argspec = self._get_argspec(func) argvars = argspec[0][1:] if argvars and enumerate(remainder): for i, var in enumerate(argvars): if i >= len(remainder): break params[var] = remainder[i] return params def _remove_argspec_params_from_params(self, func, params, remainder): """Remove parameters from the argument list that are not named parameters Returns: params, remainder""" # figure out which of the vars in the argspec are required argspec = self._get_argspec(func) argvars = argspec[0][1:] # if there are no required variables, or the remainder is none, we # have nothing to do if not argvars or not remainder: return params, remainder # this is a work around for a crappy api choice in getargspec argvals = argspec[3] if argvals is None: argvals = [] required_vars = argvars optional_vars = [] if argvals: required_vars = argvars[:-len(argvals)] optional_vars = argvars[-len(argvals):] # make a copy of the params so that we don't modify the existing one params=params.copy() # replace the existing required variables with the values that come in # from params these could be the parameters that come off of validation. remainder = list(remainder) for i, var in enumerate(required_vars): if i < len(remainder): remainder[i] = params[var] elif params.get(var): remainder.append(params[var]) if var in params: del params[var] #remove the optional positional variables (remainder) from the named parameters # until we run out of remainder, that is, avoid creating duplicate parameters for i,(original,var) in enumerate(zip(remainder[len(required_vars):],optional_vars)): if var in params: remainder[ len(required_vars)+i ] = params[var] del params[var] return params, tuple(remainder) def _dispatch(self, state, remainder): """override this to define how your controller should dispatch. returns: dispatcher, controller_path, remainder """ raise NotImplementedError def _get_dispatchable(self, url_path): """Return a tuple (controller, remainder, params). :Parameters: url url as string """ if not pylons.config.get('disable_request_extensions', False): pylons.request.response_type = None pylons.request.response_ext = None if url_path and '.' in url_path[-1]: last_remainder = url_path[-1] mime_type, encoding = mimetypes.guess_type(last_remainder) if mime_type: extension_spot = last_remainder.rfind('.') extension = last_remainder[extension_spot:] url_path[-1] = last_remainder[:extension_spot] pylons.request.response_type = mime_type pylons.request.response_ext = extension params = pylons.request.params.mixed() state = DispatchState(url_path, params) state.add_controller('/', self) state.dispatcher = self state = state.controller._dispatch(state, url_path) pylons.tmpl_context.controller_url = '/'.join( url_path[:-len(state.remainder)]) state.routing_args.update(params) if hasattr(state.dispatcher, '_setup_wsgiorg_routing_args'): state.dispatcher._setup_wsgiorg_routing_args( url_path, state.remainder, state.routing_args) #save the controller state for possible use within the controller methods pylons.request.controller_state = state return state.method, state.controller, state.remainder, params def _setup_wsgiorg_routing_args(self, url_path, remainder, params): """ This is expected to be overridden by any subclass that wants to set the routing_args (RestController). Do not delete. """ # this needs to get added back in after we understand why it breaks pagination: # pylons.request.environ['wsgiorg.routing_args'] = (tuple(remainder), params) def _setup_wsgi_script_name(self, url_path, remainder, params): pass def _perform_call(self, func, args): """Called from within Pylons and should not be overridden.""" if pylons.config.get('i18n_enabled', True): setup_i18n() script_name = pylons.request.environ.get('SCRIPT_NAME', '') url_path = pylons.request.path if url_path.startswith(script_name): url_path = url_path[len(script_name):] url_path = url_path.split('/')[1:] if url_path[-1] == '': url_path.pop() func, controller, remainder, params = self._get_dispatchable(url_path) if hasattr(controller, '__before__' ) and not hasattr(controller, '_before'): warn("Support for __before__ is going to removed" " in the next minor version, please use _before instead.") controller.__before__(*args, **args) if hasattr(controller, '_before'): controller._before(*args, **args) self._setup_wsgi_script_name(url_path, remainder, params) r = self._call(func, params, remainder=remainder) if hasattr(controller, '__after__'): warn("Support for __after__ is going to removed" " in the next minor version, please use _after instead.") controller.__after__(*args, **args) if hasattr(controller, '_after'): controller._after(*args, **args) return r def routes_placeholder(self, url='/', start_response=None, **kwargs): """Routes placeholder. This function does not do anything. It is a placeholder that allows Routes to accept this controller as a target for its routing. """ pass class ObjectDispatcher(Dispatcher): """ Object dispatch (also "object publishing") means that each portion of the URL becomes a lookup on an object. The next part of the URL applies to the next object, until you run out of URL. Processing starts on a "Root" object. Thus, /foo/bar/baz become URL portion "foo", "bar", and "baz". The dispatch looks for the "foo" attribute on the Root URL, which returns another object. The "bar" attribute is looked for on the new object, which returns another object. The "baz" attribute is similarly looked for on this object. Dispatch does not have to be directly on attribute lookup, objects can also have other methods to explain how to dispatch from them. The search ends when a decorated controller method is found. The rules work as follows: 1) If the current object under consideration is a decorated controller method, the search is ended. 2) If the current object under consideration has a "_default" method, keep a record of that method. If we fail in our search, and the most recent method recorded is a "_default" method, then the search is ended with that method returned. 3) If the current object under consideration has a "_lookup" method, keep a record of that method. If we fail in our search, and the most recent method recorded is a "_lookup" method, then execute the "_lookup" method, and start the search again on the return value of that method. 4) If the URL portion exists as an attribute on the object in question, start searching again on that attribute. 5) If we fail our search, try the most recent recorded methods as per 2 and 3. """ def _find_first_exposed(self, controller, methods): for method in methods: if self._is_exposed(controller, method): return getattr(controller, method) def _is_exposed(self, controller, name): """Override this function to define how a controller method is determined to be exposed. :Arguments: controller - controller with methods that may or may not be exposed. name - name of the method that is tested. :Returns: True or None """ if ismethod(getattr(controller, name, None)): return True def _method_matches_args(self, method, state, remainder): """ This method matches the params from the request along with the remainder to the method's function signiture. If the two jive, it returns true. It is very likely that this method would go into ObjectDispatch in the future. """ argspec = self._get_argspec(method) #skip self, argvars = argspec[0][1:] argvals = argspec[3] required_vars = argvars if argvals: required_vars = argvars[:-len(argvals)] else: argvals = [] #remove the appropriate remainder quotient if len(remainder)`_ A basic overview on how to write controller methods. """ __all__ = ['TGController'] TurboGears2-2.1.5/tg/controllers/util.py0000664000175000017500000001372511733765570021027 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- """Helper functions for controller operation. URL definition and browser redirection are defined here. """ import urllib from warnings import warn import pylons from tg.exceptions import HTTPFound def smart_str(s, encoding='utf-8', strings_only=False, errors='strict'): """ Returns a bytestring version of 's', encoded as specified in 'encoding'. If strings_only is True, don't convert (some) non-string-like objects. This function was borrowed from Django. """ if strings_only and (s is None or isinstance(s, int)): return s elif not isinstance(s, basestring): try: return str(s) except UnicodeEncodeError: if isinstance(s, Exception): # An Exception subclass containing non-ASCII data that doesn't # know how to print itself properly. We shouldn't raise a # further exception. return ' '.join([smart_str(arg, encoding, strings_only, errors) for arg in s]) return unicode(s).encode(encoding, errors) elif isinstance(s, unicode): r = s.encode(encoding, errors) return r elif s and encoding != 'utf-8': return s.decode('utf-8', errors).encode(encoding, errors) else: return s def generate_smart_str(params): for key, value in params.iteritems(): if value is None: continue if isinstance(value, (list, tuple)): for item in value: yield smart_str(key), smart_str(item) else: yield smart_str(key), smart_str(value) def urlencode(params): """ A version of Python's urllib.urlencode() function that can operate on unicode strings. The parameters are first case to UTF-8 encoded strings and then encoded as per normal. """ return urllib.urlencode([i for i in generate_smart_str(params)]) def url(base_url=None, params=None, **kwargs): """Generate an absolute URL that's specific to this application. The URL function takes a string (base_url) and, appends the SCRIPT_NAME and adds parameters for all of the parameters passed into the params dict. For backwards compatibility you can also pass in keyword parameters. """ # remove in 2.2 if base_url is None: base_url = '/' if params is None: params = {} # First we handle the possibility that the user passed in params if base_url and isinstance(base_url, basestring): # remove in 2.2 if kwargs.keys(): warn('Passing in keyword arguments as URL components to url()' ' is deprecated. Please pass arguments as a dictionary' ' to the params argument.', DeprecationWarning, stacklevel=2) params = params.copy() params.update(kwargs) elif hasattr(base_url, '__iter__'): base_url = '/'.join(base_url) if base_url.startswith('/'): base_url = pylons.request.environ['SCRIPT_NAME'] + base_url if params: return '?'.join((base_url, urlencode(params))) return base_url class LazyUrl(object): """ Wraps tg.url in an object that enforces evaluation of the url only when you try to display it as a string. """ def __init__(self, base_url, params=None): self.base_url = base_url self.params = params self._decoded = None @property def _id(self): if self._decoded == None: self._decoded = url(self.base_url, params=self.params) return self._decoded @property def id(self): return self._id def __repr__(self): return self._id def __html__(self): return str(self) def __str__(self): return str(self._id) def encode(self, *args, **kw): return self._id.encode(*args, **kw) def __add__(self, other): return self._id + other def __radd__(self, other): return other + self._id def startswith(self, *args, **kw): return self._id.startswith(*args, **kw) def format(self, other): return self._id.format(other) def lurl(base_url=None, params=None): """ Like tg.url but is lazily evaluated. This is useful when creating global variables as no request is in place. As without a request it wouldn't be possible to correctly calculate the url using the SCRIPT_NAME this demands the url resolution to when it is displayed for the first time. """ return LazyUrl(base_url, params) def redirect(*args, **kwargs): """Generate an HTTP redirect. The function raises an exception internally, which is handled by the framework. The URL may be either absolute (e.g. http://example.com or /myfile.html) or relative. Relative URLs are automatically converted to absolute URLs. Parameters may be specified, which are appended to the URL. This causes an external redirect via the browser; if the request is POST, the browser will issue GET for the second request. """ new_url = url(*args, **kwargs) found = HTTPFound(location=new_url).exception raise found def use_wsgi_app(wsgi_app): return wsgi_app(pylons.request.environ, pylons.request.start_response) # Idea stolen from Pylons def pylons_formencode_gettext(value): from pylons.i18n import ugettext as pylons_gettext from gettext import NullTranslations trans = pylons_gettext(value) # Translation failed, try formencode if trans == value: try: fetrans = pylons.tmpl_context.formencode_translation except AttributeError: # the translator was not set in the Pylons context # we are certainly in the test framework # let's make sure won't return something that is ok with the caller fetrans = NullTranslations() if not fetrans: fetrans = NullTranslations() trans = fetrans.ugettext(value) return trans __all__ = ['url', 'lurl', 'redirect', 'etag_cache'] TurboGears2-2.1.5/tg/exceptions.py0000664000175000017500000000020211675520537017644 0ustar marvinmarvin00000000000000"""http exceptions for TurboGears TurboGears http exceptions are inherited from paste httpexceptions """ from webob.exc import * TurboGears2-2.1.5/tg/i18n.py0000664000175000017500000000670111733765036016254 0ustar marvinmarvin00000000000000import logging from gettext import translation from babel import parse_locale import formencode import pylons import pylons.i18n from pylons.i18n import add_fallback, LanguageError, get_lang from pylons.i18n import ugettext, ungettext, lazy_ugettext, gettext_noop from pylons.configuration import config from pylons import session log = logging.getLogger(__name__) def sanitize_language_code(lang): """Sanitize the language code if the spelling is slightly wrong. For instance, 'pt-br' and 'pt_br' should be interpreted as 'pt_BR'. """ try: lang = '_'.join(filter(None, parse_locale(lang)[:2])) except ValueError: if '-' in lang: try: lang = '_'.join(filter(None, parse_locale(lang, sep='-')[:2])) except ValueError: pass return lang def setup_i18n(): """Set languages from the request header and the session. The session language(s) take priority over the request languages. Automatically called by tg controllers to setup i18n. Should only be manually called if you override controllers function. """ session_ = pylons.session._current_obj() if session_: session_existed = session_.accessed() # If session is available, we try to see if there are languages set languages = session_.get(config.get('lang_session_key', 'tg_lang')) if not session_existed and config.get('beaker.session.tg_avoid_touch'): session_.__dict__['_sess'] = None if languages: if isinstance(languages, basestring): languages = [languages] else: languages = [] else: languages = [] languages.extend(map(sanitize_language_code, pylons.request.accept_language.best_matches())) set_temporary_lang(languages) def set_temporary_lang(languages): """Set the current language(s) used for translations without touching the session language. languages should be a string or a list of strings. First lang will be used as main lang, others as fallbacks. """ # the logging to the screen was removed because # the printing to the screen for every problem causes serious slow down. try: pylons.i18n.set_lang(languages) except LanguageError: pass #log.warn("Language %s: not supported", languages) try: set_formencode_translation(languages) except LanguageError: pass #log.warn("Language %s: not supported by FormEncode", languages) def set_lang(languages, **kwargs): """Set the current language(s) used for translations in current call and session. languages should be a string or a list of strings. First lang will be used as main lang, others as fallbacks. """ set_temporary_lang(languages) if pylons.session: session[config.get('lang_session_key', 'tg_lang')] = languages session.save() _localdir = formencode.api.get_localedir() def set_formencode_translation(languages): """Set request specific translation of FormEncode.""" try: formencode_translation = translation( 'FormEncode',languages=languages, localedir=_localdir) except IOError, error: raise LanguageError('IOError: %s' % error) pylons.tmpl_context.formencode_translation = formencode_translation __all__ = [ "setup_i18n", "set_lang", "get_lang", "add_fallback", "set_temporary_lang", "ugettext", "lazy_ugettext", "ungettext" ] TurboGears2-2.1.5/tg/decorators.py0000664000175000017500000006154511736737176017660 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- """ Decorators use by the TurboGears controllers. Not all of these decorators are traditional wrappers. They are much simplified from the TurboGears 1 decorators, because all they do is register attributes on the functions they wrap, and then the DecoratedController provides the hooks needed to support these decorators. """ from warnings import warn from decorator import decorator from formencode import variabledecode from paste.util.mimeparse import best_match from pylons.configuration import config from pylons import request, response from pylons.controllers.util import abort from webob.exc import HTTPMethodNotAllowed from tg import tmpl_context from tg.paginate import Page from tg.util import partial try: from repoze.what.plugins.pylonshq import ActionProtector from repoze.what.plugins.pylonshq.protectors import _BaseProtectionDecorator except ImportError: class ActionProtector(object): pass class _BaseProtectionDecorator(object): pass from tg.configuration import Bunch from tg.flash import flash #from tg.controllers import redirect class Decoration(object): """ Simple class to support 'simple registration' type decorators """ def __init__(self, controller): self.controller = controller self.engines = {} self.engines_keys = [] self.custom_engines = {} self.render_custom_format = None self.validation = None self.error_handler = None self.hooks = dict(before_validate=[], before_call=[], before_render=[], after_render=[]) def get_decoration(cls, func): if not hasattr(func, 'decoration'): func.decoration = cls(func) return func.decoration get_decoration = classmethod(get_decoration) @property def exposed(self): return bool(self.engines) or bool(self.custom_engines) def run_hooks(self, hook, *l, **kw): for func in config.get('hooks', {}).get(hook, []): func(*l, **kw) for func in self.hooks[hook]: func(*l, **kw) def wrap_controller(self, controller): controller_callable = controller for wrapper in config.get('controller_wrappers', []): controller_callable = wrapper(self, controller_callable) return controller_callable def register_template_engine(self, content_type, engine, template, exclude_names, render_params): """Registers an engine on the controller. Multiple engines can be registered, but only one engine per content_type. If no content type is specified the engine is registered at */* which is the default, and will be used whenever no content type is specified. exclude_names keeps track of a list of keys which will be removed from the controller's dictionary before it is loaded into the template. This allows you to exclude some information from JSONification, and other 'automatic' engines which don't require a template. render_params registers extra parameters which will be sent to the rendering method. This allows you to influence things like the rendering method or the injected doctype. """ self.engines[content_type or '*/*'] = ( engine, template, exclude_names, render_params or {}) # this is a work-around to make text/html prominent in respect # to other common choices when they have the same weight for # paste.util.mimeparse.best_match. self.engines_keys = sorted(self.engines, reverse=True) def register_custom_template_engine(self, custom_format, content_type, engine, template, exclude_names, render_params): """Registers a custom engine on the controller. Multiple engines can be registered, but only one engine per custom_format. The engine is registered when @expose is used with the custom_format parameter and controllers render using this engine when the use_custom_format() function is called with the corresponding custom_format. exclude_names keeps track of a list of keys which will be removed from the controller's dictionary before it is loaded into the template. This allows you to exclude some information from JSONification, and other 'automatic' engines which don't require a template. render_params registers extra parameters which will be sent to the rendering method. This allows you to influence things like the rendering method or the injected doctype. """ self.custom_engines[custom_format or '"*/*"'] = ( content_type, engine, template, exclude_names, render_params or {}) def lookup_template_engine(self, request): """Return the template engine data. Provides a convenience method to get the proper engine, content_type, template, and exclude_names for a particular tg_format (which is pulled off of the request headers). """ if hasattr(request, 'response_type' ) and request.response_type in self.engines: accept_types = request.response_type else: accept_types = request.headers.get('accept', '*/*') try: render_custom_format = request._render_custom_format[ self.controller] except: render_custom_format = self.render_custom_format if render_custom_format: (content_type, engine, template, exclude_names, render_params ) = self.custom_engines[render_custom_format] else: if self.engines: content_type = best_match(self.engines_keys, accept_types) else: content_type = 'text/html' if content_type == 'CUSTOM/LEAVE': warn('@expose(CUSTOM_CONTENT_TYPE) is no longer needed' ' and should be replaced with @expose()') # check for overridden content type from the controller call controller_content_type = response.headers.get('Content-Type') if controller_content_type: # make sure we handle types like 'text/html; charset=utf-8' content_type = controller_content_type.split(';', 1)[0] # check for overridden templates try: (engine, template, exclude_names, render_params ) = request._override_mapping[ self.controller][content_type.split(';', 1)[0]] except (AttributeError, KeyError): (engine, template, exclude_names, render_params ) = self.engines.get(content_type, (None,) * 4) if 'charset' not in content_type and (content_type.startswith('text') or content_type in ('application/xhtml+xml', 'application/xml', 'application/json')): content_type = '%s; charset=utf-8' % content_type return content_type, engine, template, exclude_names, render_params def register_hook(self, hook_name, func): """Registers the specified function as a hook. We now have four core hooks that can be applied by adding decorators: before_validate, before_call, before_render, and after_render. register_hook attaches the function to the hook which get's called at the appropriate time in the request life cycle.) """ self.hooks[hook_name].append(func) class _hook_decorator(object): """Superclass for all the specific TG2 hook validators. Its `hook_name` must be overridden by a specific hook. """ hook_name = None def __init__(self, hook_func): self.hook_func = hook_func def __call__(self, func): deco = Decoration.get_decoration(func) deco.register_hook(self.hook_name, self.hook_func) return func class before_validate(_hook_decorator): """A list of callables to be run before validation is performed.""" hook_name = 'before_validate' class before_call(_hook_decorator): """A list of callables to be run before the controller method is called.""" hook_name = 'before_call' class before_render(_hook_decorator): """A list of callables to be run before the template is rendered.""" hook_name = 'before_render' class after_render(_hook_decorator): """A list of callables to be run after the template is rendered. Will be run before it is returned returned up the WSGI stack. """ hook_name = 'after_render' class expose(object): """Register attributes on the decorated function. :Parameters: template Assign a template, you could use the syntax 'genshi:template' to use different templates. The default template engine is genshi. content_type Assign content type. The default content type is 'text/html'. exclude_names Assign exclude names render_params Assign parameters that shall be passed to the rendering method. The expose decorator registers a number of attributes on the decorated function, but does not actually wrap the function the way TurboGears 1.0 style expose decorators did. This means that we don't have to play any kind of special tricks to maintain the signature of the exposed function. The exclude_names parameter is new, and it takes a list of keys that ought to be scrubbed from the dictionary before passing it on to the rendering engine. This is particularly useful for JSON. The render_parameters is also new. It takes a dictionary of arguments that ought to be sent to the rendering engine, like this:: render_params={'method': 'xml', 'doctype': None} Expose decorator can be stacked like this:: @expose('json', exclude_names='d') @expose('kid:blogtutorial.templates.test_form', content_type='text/html') @expose('kid:blogtutorial.templates.test_form_xml', content_type='text/xml', custom_format='special_xml') def my_exposed_method(self): return dict(a=1, b=2, d="username") The expose('json') syntax is a special case. json is a buffet rendering engine, but unlike others it does not require a template, and expose assumes that it matches content_type='application/json' If you want to declare a desired content_type in a url, you can use the mime-type style dotted notation:: "/mypage.json" ==> for json "/mypage.html" ==> for text/html "/mypage.xml" ==> for xml. If you're doing an http post, you can also declare the desired content type in the accept headers, with standard content type strings. By default expose assumes that the template is for html. All other content_types must be explicitly matched to a template and engine. The last expose decorator example uses the custom_format parameter which takes an arbitrary value (in this case 'special_xml'). You can then use the`use_custom_format` function within the method to decide which of the 'custom_format' registered expose decorators to use to render the template. """ def __init__(self, template='', content_type=None, exclude_names=None, custom_format=None, render_params=None): if exclude_names is None: exclude_names = [] if template in config.get('renderers', []): engine, template = template, '' elif ':' in template: engine, template = template.split(':', 1) elif template: # Use the default templating engine from the config if config.get('use_legacy_renderer'): engine = config['buffet.template_engines'][0]['engine'] else: engine = config.get('default_renderer') else: engine, template = None, None if content_type is None: if engine == 'json': content_type = 'application/json' else: content_type = 'text/html' if engine in ('json', 'amf') and 'tmpl_context' not in exclude_names: exclude_names.append('tmpl_context') self.engine = engine self.template = template self.content_type = content_type self.exclude_names = exclude_names self.custom_format = custom_format self.render_params = render_params def __call__(self, func): deco = Decoration.get_decoration(func) if self.custom_format: deco.register_custom_template_engine( self.custom_format, self.content_type, self.engine, self.template, self.exclude_names, self.render_params) else: deco.register_template_engine( self.content_type, self.engine, self.template, self.exclude_names, self.render_params) return func def use_custom_format(controller, custom_format): """Use use_custom_format in a controller in order to change the active @expose decorator when available.""" deco = Decoration.get_decoration(controller) # Check the custom_format passed is available for use if custom_format not in deco.custom_engines: raise ValueError("'%s' is not a valid custom_format" % custom_format) try: render_custom_format = request._render_custom_format except AttributeError: render_custom_format = request._render_custom_format = {} render_custom_format[controller.im_func] = custom_format def override_template(controller, template): """Override the template to be used. Use override_template in a controller in order to change the template that will be used to render the response dictionary dynamically. The template string passed in requires that you include the template engine name, even if you're using the default. So you have to pass in a template id string like:: "genshi:myproject.templates.index2" future versions may make the `genshi:` optional if you want to use the default engine. """ try: engines = controller.decoration.engines except: return for content_type, content_engine in engines.iteritems(): tmpl = template.split(':', 1) tmpl.extend(content_engine[2:]) try: override_mapping = request._override_mapping except AttributeError: override_mapping = request._override_mapping = {} override_mapping.setdefault(controller.im_func, {}).update({content_type: tmpl}) class validate(object): """Registers which validators ought to be applied. If you want to validate the contents of your form, you can use the ``@validate()`` decorator to register the validators that ought to be called. :Parameters: validators Pass in a dictionary of FormEncode validators. The keys should match the form field names. error_handler Pass in the controller method which shoudl be used to handle any form errors form Pass in a ToscaWidget based form with validators The first positional parameter can either be a dictonary of validators, a FormEncode schema validator, or a callable which acts like a FormEncode validator. """ def __init__(self, validators=None, error_handler=None, form=None): if form: self.validators = form if validators: self.validators = validators self.error_handler = error_handler def __call__(self, func): deco = Decoration.get_decoration(func) deco.validation = self return func class paginate(object): """Paginate a given collection. This decorator is mainly exposing the functionality of :func:`webhelpers.paginate`. :Usage: You use this decorator as follows:: class MyController(object): @expose() @paginate("collection") def sample(self, *args): collection = get_a_collection() return dict(collection=collection) To render the actual pager, use:: ${tmpl_context.paginators..pager()} It is possible to have several :func:`paginate`-decorators for one controller action to paginate several collections independently from each other. If this is desired, don't forget to set the :attr:`use_prefix`-parameter to :const:`True`. :Parameters: name the collection to be paginated. items_per_page the number of items to be rendered. Defaults to 10 max_items_per_page the maximum number of items allowed to be set via parameter. Defaults to 0 (does not allow to change that value). use_prefix if True, the parameters the paginate decorator renders and reacts to are prefixed with "_". This allows for multi-pagination. """ def __init__(self, name, use_prefix=False, items_per_page=10, max_items_per_page=0): self.name = name prefix = use_prefix and name + '_' or '' self.page_param = prefix + 'page' self.items_per_page_param = prefix + 'items_per_page' self.items_per_page = items_per_page self.max_items_per_page = max_items_per_page def __call__(self, func): decoration = Decoration.get_decoration(func) decoration.register_hook('before_validate', self.before_validate) decoration.register_hook('before_render', self.before_render) return func def before_validate(self, remainder, params): page_param = params.pop(self.page_param, None) if page_param: try: page = int(page_param) if page < 1: raise ValueError except ValueError: page = 1 else: page = 1 try: paginators_data = request.paginators except: paginators_data = request.paginators = {'_tg_paginators_params':{}} paginators_data['_tg_paginators_params'][self.page_param] = page_param paginators_data[self.name] = paginator = Bunch() paginator.paginate_page = page or 1 items_per_page = params.pop(self.items_per_page_param, None) if items_per_page: try: items_per_page = min( int(items_per_page), self.max_items_per_page) if items_per_page < 1: raise ValueError except ValueError: items_per_page = self.items_per_page else: items_per_page = self.items_per_page paginator.paginate_items_per_page = items_per_page paginator.paginate_params = params.copy() paginator.paginate_params.update(paginators_data['_tg_paginators_params']) if items_per_page != self.items_per_page: paginator.paginate_params[self.items_per_page_param] = items_per_page def before_render(self, remainder, params, output): if not isinstance(output, dict) or not self.name in output: return paginator = request.paginators[self.name] collection = output[self.name] page = Page(collection, paginator.paginate_page, paginator.paginate_items_per_page, controller='/') page.kwargs = paginator.paginate_params if self.page_param != 'name': page.pager = partial(page.pager, page_param=self.page_param) if not getattr(tmpl_context, 'paginators', None): tmpl_context.paginators = Bunch() tmpl_context.paginators[self.name] = output[self.name] = page @decorator def postpone_commits(func, *args, **kwargs): """Turns SQLAlchemy commits into flushes in the decorated method. This has the end-result of postponing the commit to the normal TG2 transaction boundary. """ #TODO: Test and document this. s = config.get('DBSession', None) assert hasattr(s, 'commit') old_commit = s.commit s.commit = s.flush retval = func(*args, **kwargs) s.commit = old_commit return retval @before_validate def https(remainder, params): """Ensure that the decorated method is always called with https.""" from tg.controllers import redirect if request.scheme.lower() == 'https': return if request.method.upper() == 'GET': redirect('https' + request.url[len(request.scheme):]) raise HTTPMethodNotAllowed(headers=dict(Allow='GET')).exception @before_validate def variable_decode(remainder, params): """Best-effort formencode.variabledecode on the params before validation. If any exceptions are raised due to invalid parameter names, they are silently ignored, hopefully to be caught by the actual validator. Note that this decorator will *add* parameters to the method, not remove. So for instance a method will move from {'foo-1':'1', 'foo-2':'2'} to {'foo-1':'1', 'foo-2':'2', 'foo':['1', '2']}. """ try: new_params = variabledecode.variable_decode(params) params.update(new_params) except: pass @before_validate def without_trailing_slash(remainder, params): """This decorator allows you to ensure that the URL does not end in "/". The decorator accomplish this by redirecting to the correct URL. :Usage: You use this decorator as follows:: class MyController(object): @without_trailing_slash @expose() def sample(self, *args): return "found sample" In the above example http://localhost:8080/sample/ redirects to http://localhost:8080/sample In addition, the URL http://localhost:8080/sample/1/ redirects to http://localhost:8080/sample/1 """ if request.method == 'GET' and request.path.endswith('/') and not(request.response_type) and len(request.params)==0: from tg.controllers import redirect redirect(request.url[:-1]) @before_validate def with_trailing_slash(remainder, params): """This decorator allows you to ensure that the URL ends in "/". The decorator accomplish this by redirecting to the correct URL. :Usage: You use this decorator as follows:: class MyController(object): @with_trailing_slash @expose() def sample(self, *args): return "found sample" In the above example http://localhost:8080/sample redirects to http://localhost:8080/sample/ In addition, the URL http://localhost:8080/sample/1 redirects to http://localhost:8080/sample/1/ """ if (request.method == 'GET' and not(request.path.endswith('/')) and not(request.response_type) and len(request.params)==0): from tg.controllers import redirect redirect(request.url+'/') #{ Authorization decorators class require(ActionProtector): """ TurboGears-specific repoze.what-pylons action protector. The default authorization denial handler of this protector will flash the message of the unmet predicate with ``warning`` or ``error`` as the flash status if the HTTP status code is 401 or 403, respectively. See :class:`allow_only` for controller-wide authorization. """ def default_denial_handler(self, reason): """Authorization denial handler for repoze.what-pylons protectors.""" if response.status_int == 401: status = 'warning' else: # Status is a 403 status = 'error' flash(reason, status=status) abort(response.status_int, reason) class allow_only(_BaseProtectionDecorator): """ TurboGears-specific repoze.what-pylons controller protector. The default authorization denial handler of this protector will flash the message of the unmet predicate with ``warning`` or ``error`` as the flash status if the HTTP status code is 401 or 403, respectively, since by default the ``__before__`` method of the controller is decorated with :class:`require`. If the controller class has the ``_failed_authorization`` *class method*, it will replace the default denial handler. """ protector = require def __call__(self, cls, *args, **kwargs): if hasattr(self.protector, 'predicate'): cls.allow_only = self.protector.predicate if hasattr(cls, '_failed_authorization'): self.denial_handler = cls._failed_authorization sup = super(allow_only, self) if hasattr(sup, '__call__'): return super(allow_only, self).__call__(cls, *args, **kwargs) class cached_property(object): """Cached property executing the getter only once.""" def __init__(self, func): self.__name__ = func.__name__ self.__module__ = func.__module__ self.__doc__ = func.__doc__ self.func = func def __get__(self, obj, type=None): if obj is None: return self try: value = obj.__dict__[self.__name__] except KeyError: value = obj.__dict__[self.__name__] = self.func(obj) return value #} TurboGears2-2.1.5/tg/commands/0000775000175000017500000000000011737460177016722 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tg/commands/info.py0000664000175000017500000000445111675520537020231 0ustar marvinmarvin00000000000000""" TurboGears related projects and their versions """ import pkg_resources from paste.script import command entrypoints = {"TurboGears2 Commands" : "turbogears2.command", "Template Engines" : "python.templating.engines", "TurboGears2 Templates": "turbogears2.template", "Widget Packages" : "toscawidgets.widgets", "Toolbox2 Gadgets" : "turbogears2.toolboxcommand", } """#elements that not clear yet "TurboGears2 Extensions" : "turbogears2.extensions", "Auth Providers" : "turbogears2.auth.provider", "Visit Managers" : "turbogears2.visit.manager", """ def retrieve_info(): packages=['%s' % i for i in pkg_resources.require("TurboGears2")] plugins = {} for name, pointname in entrypoints.items(): if name in "samples": pass else: plugins[name] = ["%s (%s)" % (entrypoint.name, str(entrypoint.dist)) for entrypoint in pkg_resources.iter_entry_points(pointname) ] return packages, plugins class InfoCommand(command.Command): """Show TurboGears 2 related projects and their versions""" max_args = 0 min_args = 0 summary = __doc__.splitlines()[0] usage = '\n' + __doc__ group_name = "TurboGears2" parser = command.Command.standard_parser(verbose=True) def command(self): print """TurboGears2 Complete Version Information""" print """========================================""" print "\nTurboGears2 requires:\n" li = [] packages, plugins = retrieve_info() for p in packages: li.append(p) # print dependent modules for p in list(set(li)): print ' *', p # print plugins for name, pluginlist in plugins.items(): print "\n", name, "\n" for plugin in pluginlist: print ' *', plugin # print widgets print "\nAvailable Widgets:\n" for entrypoint in pkg_resources.iter_entry_points('toscawidgets.widgets'): if entrypoint.name in "samples": pass else: tool = entrypoint.load() temp = dir(tool) print "\n * "+str(entrypoint.dist)+":" for t in temp: if not t.startswith('__'): print ' -', t TurboGears2-2.1.5/tg/commands/__init__.py0000664000175000017500000000230311675520537021027 0ustar marvinmarvin00000000000000""" TurboGears command line tools. TurboGears commands are the extensions based on 'paster' command. You could investigating all paster commands with following command:: $ paster --help All TurboGears commands are grouped in the 'TurboGears2' section. Or you could check out the TurboGears-related infomation with command:: $ paster tginfo To create a new project named helloworld, you could start with quickstart command:: $ paster quickstart helloworld Then, you could run the created project with these commands:: $ cd helloworld $ paster serve --reload development.ini The command loads our project server configuration file in development.ini and serves the TurboGears 2 application. The --reload option ensures that the server is automatically reloaded if you make any changes to Python files or the development.ini config file. This is very useful during development. To stop the server, you can press Ctrl+c or your platform's equivalent. If you visit http://127.0.0.1:8080/ when the server is running, you will see the welcome page (127.0.0.1 is a special IP address that references your own computer, but you can change the hostname by editing the development.ini file). """ TurboGears2-2.1.5/tg/util.py0000664000175000017500000001600211736737176016454 0ustar marvinmarvin00000000000000"""Utilities""" import os, sys import pkg_resources from pkg_resources import resource_filename import warnings from pylons.configuration import config class DottedFileLocatorError(Exception):pass def get_project_meta(name): for dirname in os.listdir("./"): if dirname.lower().endswith("egg-info"): fname = os.path.join(dirname, name) return fname def get_project_name(): """get project name if exist""" pkg_info = get_project_meta('PKG-INFO') if pkg_info: name = list(open(pkg_info))[1][6:-1] return name.strip() def get_package_name(): """Try to find out the package name of the current directory.""" package = config.get("modules") if package: return package if "--egg" in sys.argv: projectname = sys.argv[sys.argv.index("--egg")+1] egg = pkg_resources.get_distribution(projectname) top_level = egg._get_metadata("top_level.txt") else: fname = get_project_meta('top_level.txt') top_level = fname and open(fname) or [] for package in top_level: package = package.rstrip() if package and package != 'locales': return package def get_model(): """return model""" package_name = get_package_name() if not package_name: return None package = __import__(package_name, {}, {}, ["model"]) if hasattr(package, "model"): return package.model def get_partial_dict(prefix, dictionary): """Given a dictionary and a prefix, return a Bunch, with just items that start with prefix The returned dictionary will have 'prefix.' stripped so: get_partial_dict('prefix', {'prefix.xyz':1, 'prefix.zyx':2, 'xy':3}) would return: {'xyz':1,'zyx':2} """ match = prefix + "." n = len(match) new_dict = Bunch([(key[n:], dictionary[key]) for key in dictionary.iterkeys() if key.startswith(match)]) if new_dict: return new_dict else: raise AttributeError class Bunch(dict): """A dictionary that provides attribute-style access.""" def __getitem__(self, key): return dict.__getitem__(self, key) def __getattr__(self, name): try: return self[name] except KeyError: return get_partial_dict(name, self) __setattr__ = dict.__setitem__ def __delattr__(self, name): try: del self[name] except KeyError: raise AttributeError(name) def partial(*args, **create_time_kwds): func = args[0] create_time_args = args[1:] def curried_function(*call_time_args, **call_time_kwds): args = create_time_args + call_time_args kwds = create_time_kwds.copy() kwds.update(call_time_kwds) return func(*args, **kwds) return curried_function class DottedFileNameFinder(object): """this class implements a cache system above the get_dotted_filename function and is designed to be stuffed inside the app_globals. It exposes a method named get_dotted_filename with the exact same signature as the function of the same name in this module. The reason is that is uses this function itself and just adds caching mechanism on top. """ def __init__(self): self.__cache = dict() def get_dotted_filename(self, template_name, template_extension='.html'): """this helper function is designed to search a template or any other file by python module name. Given a string containing the file/template name passed to the @expose decorator we will return a resource useable as a filename even if the file is in fact inside a zipped egg. The actual implementation is a revamp of the Genshi buffet support plugin, but could be used with any kind a file inside a python package. @param template_name: the string representation of the template name as it has been given by the user on his @expose decorator. Basically this will be a string in the form of: "genshi:myapp.templates.somename" @type template_name: string @param template_extension: the extension we excpect the template to have, this MUST be the full extension as returned by the os.path.splitext function. This means it should contain the dot. ie: '.html' This argument is optional and the default value if nothing is provided will be '.html' @type template_extension: string """ if template_name.startswith('app:'): template_name = '.'.join((get_package_name(), template_name[4:])) try: return self.__cache[template_name] except KeyError: # the template name was not found in our cache divider = template_name.rfind('.') if divider >= 0: package = template_name[:divider] basename = template_name[divider + 1:] + template_extension try: result = resource_filename(package, basename) except ImportError, e: raise DottedFileLocatorError(e.message +". Perhaps you have forgotten an __init__.py in that folder.") else: result = template_name self.__cache[template_name] = result return result class odict(dict): def __init__(self, *args, **kw): self._ordering = [] dict.__init__(self, *args, **kw) def __setitem__(self, key, value): if key in self._ordering: self._ordering.remove(key) self._ordering.append(key) dict.__setitem__(self, key, value) def keys(self): return self._ordering def clear(self): self._ordering = [] dict.clear(self) def getitem(self, n): return self[self._ordering[n]] # def __slice__(self, a, b=-1, n=1): # return self.values()[a:b:n] def iteritems(self): for item in self._ordering: yield item, self[item] def items(self): return [i for i in self.iteritems()] def itervalues(self): for item in self._ordering: yield self[item] def values(self): return [i for i in self.itervalues()] def __delitem__(self, key): self._ordering.remove(key) dict.__delitem__(self, key) def pop(self): item = self._ordering[-1] del self[item] def __str__(self): return str(self.items()) def wrap(wrapper, wrapped): """Update a wrapper function to look like the wrapped function""" for attr in ('__module__', '__name__', '__doc__'): setattr(wrapper, attr, getattr(wrapped, attr)) for attr in ('__dict__',): getattr(wrapper, attr).update(getattr(wrapped, attr, {})) # Return the wrapper so this can be used as a decorator via partial() return wrapper def no_warn(f, *args, **kwargs): def _f(*args, **kwargs): warnings.simplefilter("ignore") f(*args, **kwargs) warnings.resetwarnings() return wrap(_f, f)TurboGears2-2.1.5/tg/render.py0000664000175000017500000004076511736737176016773 0ustar marvinmarvin00000000000000from urllib import quote_plus from paste.deploy.converters import asbool try: from repoze.what import predicates except ImportError: predicates = [] from webhelpers.html import literal import tg from tg.configuration import Bunch from webhelpers.html import literal class MissingRendererError(Exception): def __init__(self, template_engine): Exception.__init__(self, ("The renderer for '%(template_engine)s' templates is missing. " "Try adding the following line in you app_cfg.py:\n" "\"base_config.renderers.append('%(template_engine)s')\"") % dict( template_engine=template_engine)) self.template_engine = template_engine class DeprecatedFlashVariable(object): def __init__(self, callable, msg): self.callable = callable self.msg = msg def __unicode__(self): import warnings warnings.warn(self.msg, DeprecationWarning, 2) return unicode(self.callable()) def __nonzero__(self): import warnings warnings.warn(self.msg, DeprecationWarning, 2) return bool(self.callable()) def _get_tg_vars(): """Create a Bunch of variables that should be available in all templates. These variables are: WARNING: This function should not be called from outside of the render() code. Please consider this function as private. quote_plus the urllib quote_plus function url the turbogears.url function for creating flexible URLs identity the current visitor's identity information session the current beaker.session if the session_filter.on it set in the app.cfg configuration file. If it is not set then session will be None. locale the default locale inputs input values from a form errors validation errors request the WebOb Request Object config the app's config object auth_stack_enabled A boolean that determines if the auth stack is present in the environment predicates The :mod:`repoze.what.predicates` module. """ req = tg.request._current_obj() conf = tg.config._current_obj() tmpl_context = tg.tmpl_context._current_obj() app_globals = tg.app_globals._current_obj() translator = tg.translator._current_obj() response = tg.response._current_obj() try: h = conf['package'].lib.helpers except AttributeError, ImportError: h = Bunch() # TODO: Implement user_agent and other missing features. tg_vars = Bunch( config=tg.config, flash_obj=tg.flash, flash=DeprecatedFlashVariable( lambda: tg.flash.message, "flash is deprecated, please use flash_obj.message instead " "or use the new flash_obj.render() method" ), flash_status=DeprecatedFlashVariable( lambda: 'status_' + tg.flash.status, "flash_status is deprecated, please use flash_obj.status instead " "or use the new flash_obj.render() method" ), quote_plus=quote_plus, url=tg.url, # this will be None if no identity identity=req.environ.get('repoze.who.identity'), session=tg.session, locale=req.accept_language.best_matches(), errors=getattr(tmpl_context, "form_errors", {}), inputs=getattr(tmpl_context, "form_values", {}), request=req, auth_stack_enabled='repoze.who.plugins' in req.environ, predicates=predicates) root_vars = Bunch( c=tmpl_context, tmpl_context=tmpl_context, response=response, request=req, config=conf, app_globals=app_globals, g=app_globals, url=tg.url, helpers=h, h=h, tg=tg_vars, translator=translator, ungettext=tg.i18n.ungettext, _=tg.i18n.ugettext, N_=tg.i18n.gettext_noop) econf = conf['pylons.environ_config'] if 'beaker.session' in req.environ or \ ('session' in econf and econf['session'] in req.environ): root_vars['session'] = tg.session._current_obj() # Allow users to provide a callable that defines extra vars to be # added to the template namespace variable_provider = conf.get('variable_provider', None) if variable_provider: root_vars.update(variable_provider()) return root_vars # Monkey patch pylons_globals for cases when pylons.templating is used # instead of tg.render to programmatically render templates. import pylons pylons.templating.pylons_globals = _get_tg_vars # end monkeying around def render(template_vars, template_engine=None, template_name=None, **kwargs): config = tg.config._current_obj() render_function = None if template_engine is not None: # the engine was defined in the @expose() render_function = config['render_functions'].get(template_engine) if render_function is None: # engine was forced in @expose() but is not present in the # engine list, warn developer raise MissingRendererError(template_engine) if not template_vars: template_vars = {} caching_options = template_vars.get('tg_cache', {}) kwargs['cache_key'] = caching_options.get('key') kwargs['cache_expire'] = caching_options.get('expire') kwargs['cache_type'] = caching_options.get('type') for func in config.get('hooks', {}).get('before_render_call', []): func(template_engine, template_name, template_vars, kwargs) tg_vars = template_vars if template_engine not in ("json", 'amf'): # Get the extra vars, and merge in the vars from the controller tg_vars = _get_tg_vars() tg_vars.update(template_vars) if not render_function: # getting the default renderer, if no engine was defined in @expose() render_function = config[ 'render_functions'][config['default_renderer']] kwargs['result'] = render_function(template_name, tg_vars, **kwargs) for func in config.get('hooks', {}).get('after_render_call', []): func(template_engine, template_name, template_vars, kwargs) return kwargs['result'] def cached_template(template_name, render_func, ns_options=(), cache_key=None, cache_type=None, cache_expire=None, **kwargs): """Cache and render a template, took from Pylons Cache a template to the namespace ``template_name``, along with a specific key if provided. Basic Options ``template_name`` Name of the template, which is used as the template namespace. ``render_func`` Function used to generate the template should it no longer be valid or doesn't exist in the cache. ``ns_options`` Tuple of strings, that should correspond to keys likely to be in the ``kwargs`` that should be used to construct the namespace used for the cache. For example, if the template language supports the 'fragment' option, the namespace should include it so that the cached copy for a template is not the same as the fragment version of it. Caching options (uses Beaker caching middleware) ``cache_key`` Key to cache this copy of the template under. ``cache_type`` Valid options are ``dbm``, ``file``, ``memory``, ``database``, or ``memcached``. ``cache_expire`` Time in seconds to cache this template with this ``cache_key`` for. Or use 'never' to designate that the cache should never expire. The minimum key required to trigger caching is ``cache_expire='never'`` which will cache the template forever seconds with no key. """ # If one of them is not None then the user did set something if (cache_key is not None or cache_expire is not None or cache_type is not None): if not cache_type: cache_type = 'dbm' if not cache_key: cache_key = 'default' if cache_expire == 'never': cache_expire = None namespace = template_name for name in ns_options: namespace += str(kwargs.get(name)) cache = tg.cache.get_cache(namespace, type=cache_type) content = cache.get_value(cache_key, createfunc=render_func, expiretime=cache_expire) return content else: return render_func() class RenderChameleonGenshi(object): """Singleton that can be called as the Chameleon-Genshi render function.""" format_for_content_type = { 'text/plain': 'text', 'text/css': 'text', 'text/html': 'xml', 'text/xml': 'xml', 'application/xml': 'xml', 'application/xhtml+xml': 'xml', 'application/atom+xml': 'xml', 'application/rss+xml': 'xml', 'application/soap+xml': 'xml', 'image/svg+xml': 'xml'} def __init__(self, loader): self.load_template = loader.load def __call__(self, template_name, template_vars, **kwargs): """Render the template_vars with the Chameleon-Genshi template.""" config = tg.config._current_obj() # Gets template format from content type or from config options format = kwargs.get('format') if not format: format = self.format_for_content_type.get(tg.response.content_type) if not format: format = config.get('templating.chameleon.genshi.format') if not format: format = config.get('templating.genshi.method') if not format or format not in ('xml', 'text'): format = 'xml' def render_template(): template = self.load_template(template_name, format=format) return literal(template.render(**template_vars)) return cached_template(template_name, render_template, ns_options=('doctype', 'method'), **kwargs) class RenderGenshi(object): """Singleton that can be called as the Genshi render function.""" genshi_functions = {} # auxiliary Genshi functions loaded on demand default_doctype = default_method = None doctypes_for_methods = { 'html': 'html-transitional', 'xhtml': 'xhtml-transitional'} doctypes_for_content_type = { 'text/html': ('html', 'html-transitional', 'html-frameset', 'html5', 'xhtml', 'xhtml-strict', 'xhtml-transitional', 'xhtml-frameset'), 'application/xhtml+xml': ('xhtml', 'xhtml-strict', 'xhtml-transitional', 'xhtml-frameset', 'xhtml11'), 'image/svg+xml': ('svg', 'svg-full', 'svg-basic', 'svg-tiny')} methods_for_content_type = { 'text/plain': ('text',), 'text/css': ('text',), 'text/html': ('html', 'xhtml'), 'text/xml': ('xml', 'xhtml'), 'application/xml': ('xml', 'xhtml'), 'application/xhtml+xml': ('xhtml',), 'application/atom+xml': ('xml',), 'application/rss+xml': ('xml',), 'application/soap+xml': ('xml',), 'image/svg+xml': ('xml',)} def __init__(self, loader): if not self.genshi_functions: from genshi import HTML, XML self.genshi_functions.update(HTML=HTML, XML=XML) self.load_template = loader.load doctype = tg.config.get('templating.genshi.doctype') if doctype: if isinstance(doctype, str): self.default_doctype = doctype elif isinstance(doctype, dict): doctypes = self.doctypes_for_content_type.copy() doctypes.update(doctype) self.doctypes_for_content_type = doctypes method = tg.config.get('templating.genshi.method') if method: if isinstance(method, str): self.default_method = method elif isinstance(method, dict): methods = self.methods_for_content_type.copy() methods.update(method) self.methods_for_content_type = methods @staticmethod def method_for_doctype(doctype): method = 'xhtml' if doctype: if doctype.startswith('html'): method = 'html' elif doctype.startswith('xhtml'): method = 'xhtml' elif doctype.startswith('svg'): method = 'xml' else: method = 'xhtml' return method def __call__(self, template_name, template_vars, **kwargs): """Render the template_vars with the Genshi template. If you don't pass a doctype or pass 'auto' as the doctype, then the doctype will be automatically determined. If you pass a doctype of None, then no doctype will be injected. If you don't pass a method or pass 'auto' as the method, then the method will be automatically determined. """ response = tg.response._current_obj() template_vars.update(self.genshi_functions) # Gets document type from content type or from config options doctype = kwargs.get('doctype', 'auto') if doctype == 'auto': doctype = self.default_doctype if not doctype: method = kwargs.get('method') or self.default_method or 'xhtml' doctype = self.doctypes_for_methods.get(method) doctypes = self.doctypes_for_content_type.get(response.content_type) if doctypes and (not doctype or doctype not in doctypes): doctype = doctypes[0] kwargs['doctype'] = doctype # Gets rendering method from content type or from config options method = kwargs.get('method') if not method or method == 'auto': method = self.default_method if not method: method = self.method_for_doctype(doctype) methods = self.methods_for_content_type.get(response.content_type) if methods and (not method or method not in methods): method = methods[0] kwargs['method'] = method def render_template(): template = self.load_template(template_name) return literal(template.generate(**template_vars).render( doctype=doctype, method=method, encoding=None)) return cached_template(template_name, render_template, ns_options=('doctype', 'method'), **kwargs) def render_mako(template_name, globs, cache_key=None, cache_type=None, cache_expire=None): config = tg.config._current_obj() if asbool(config.get('use_dotted_templatenames', 'true')): template_name = globs[ 'app_globals'].dotted_filename_finder.get_dotted_filename( template_name, template_extension='.mak') # Create a render callable for the cache function def render_template(): # Grab a template reference template = globs['app_globals'].mako_lookup.get_template(template_name) return literal(template.render_unicode(**globs)) return cached_template(template_name, render_template, cache_key=cache_key, cache_type=cache_type, cache_expire=cache_expire) def render_json(template_name, template_vars, **kwargs): return tg.json_encode(template_vars) def render_kajiki(template_name, globs, cache_key=None, cache_type=None, cache_expire=None, method='xhtml'): """Render a template with Kajiki Accepts the cache options ``cache_key``, ``cache_type``, and ``cache_expire`` in addition to method which are passed to Kajiki's render function. """ # Create a render callable for the cache function def render_template(): # Grab a template reference template = globs['app_globals'].kajiki_loader.load(template_name) return literal(template(globs).render()) return cached_template(template_name, render_template, cache_key=cache_key, cache_type=cache_type, cache_expire=cache_expire, ns_options=('method'), method=method) def render_jinja(template_name, globs, cache_key=None, cache_type=None, cache_expire=None): """Render a template with Jinja2 Accepts the cache options ``cache_key``, ``cache_type``, and ``cache_expire``. """ # Create a render callable for the cache function def render_template(): # Grab a template reference template = globs['app_globals'].jinja2_env.get_template(template_name) return literal(template.render(**globs)) return cached_template(template_name, render_template, cache_key=cache_key, cache_type=cache_type, cache_expire=cache_expire) TurboGears2-2.1.5/tg/wsgiapp.py0000664000175000017500000000371511733765036017151 0ustar marvinmarvin00000000000000import os import sys from pylons.wsgiapp import PylonsApp, class_name_from_module_name from pylons.util import class_name_from_module_name import logging log = logging.getLogger(__name__) import warnings if sys.version_info[:2] == (2,4): warnings.warn('Python 2.4 support is deprecated, and will be removed in TurboGears 2.2', DeprecationWarning) class TGApp(PylonsApp): def find_controller(self, controller): """Locates a controller by attempting to import it then grab the SomeController instance from the imported module. Override this to change how the controller object is found once the URL has been resolved. """ # Check to see if we've cached the class instance for this name if controller in self.controller_classes: return self.controller_classes[controller] root_module_path = self.config['paths']['root'] base_controller_path = self.config['paths']['controllers'] #remove the part of the path we expect to be the root part (plus one '/') assert base_controller_path.startswith(root_module_path) controller_path = base_controller_path[len(root_module_path)+1:] #attach the package pylons_package = self.config['pylons.package'] full_module_name = '.'.join([pylons_package] + controller_path.split(os.sep) + controller.split('/')) # Hide the traceback here if the import fails (bad syntax and such) __traceback_hide__ = 'before_and_this' __import__(full_module_name) module_name = controller.split('/')[-1] class_name = class_name_from_module_name(module_name) + 'Controller' if self.log_debug: log.debug("Found controller, module: '%s', class: '%s'", full_module_name, class_name) mycontroller = getattr(sys.modules[full_module_name], class_name) self.controller_classes[controller] = mycontroller return mycontroller TurboGears2-2.1.5/tests/0000775000175000017500000000000011737460177015651 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_validation.py0000664000175000017500000002447011736737176021430 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- from nose.tools import raises import pylons from formencode import validators, Schema from simplejson import loads from tg.controllers import TGController from tg.decorators import expose, validate, before_render from tests.base import (TestWSGIController, data_dir, make_app, setup_session_dir, teardown_session_dir) from tw.forms import TableForm, TextField from tw.api import WidgetsList def setup(): setup_session_dir() def teardown(): teardown_session_dir() class MyForm(TableForm): class fields(WidgetsList): """This WidgetsList is just a container.""" title=TextField(validator = validators.NotEmpty()) year = TextField(size=4, validator=validators.Int()) # then, we create an instance of this form myform = MyForm("my_form", action='create') class Pwd(Schema): pwd1 = validators.String(not_empty=True) pwd2 = validators.String(not_empty=True) chained_validators = [validators.FieldsMatch('pwd1', 'pwd2')] class controller_based_validate(validate): def __init__(self, error_handler=None, *args, **kw): self.error_handler = error_handler self.needs_controller = True class Validators(object): def validate(self, controller, params, state): return params self.validators = Validators() class ColonValidator(validators.FancyValidator): def validate_python(self, value, state): raise validators.Invalid('ERROR: Description', value, state) class BasicTGController(TGController): @expose('json') @validate(validators={"some_int": validators.Int()}) def validated_int(self, some_int): assert isinstance(some_int, int) return dict(response=some_int) @expose('json') @validate(validators={"a": validators.Int()}) def validated_and_unvalidated(self, a, b): assert isinstance(a, int) assert isinstance(b, unicode) return dict(int=a, str=b) @expose() @controller_based_validate() def validate_controller_based_validator(self, *args, **kw): return 'ok' @expose('json') @validate(validators={"a": validators.Int(), "someemail": validators.Email}) def two_validators(self, a=None, someemail=None, *args): errors = pylons.tmpl_context.form_errors values = pylons.tmpl_context.form_values return dict(a=a, someemail=someemail, errors=str(errors), values=str(values)) @expose('json') @validate(validators={"a": validators.Int()}) def with_default_shadow(self, a, b=None ): """A default value should not cause the validated value to disappear""" assert isinstance( a, int ), type(a) return { 'int': a, } @expose('json') @validate(validators={"e": ColonValidator()}) def error_with_colon(self, e): errors = pylons.tmpl_context.form_errors return dict(errors=str(errors)) @expose('json') @validate(validators={ "a": validators.Int(),"b":validators.Int(),"c":validators.Int(),"d":validators.Int() }) def with_default_shadow_long(self, a, b=None,c=None,d=None ): """A default value should not cause the validated value to disappear""" assert isinstance( a, int ), type(a) assert isinstance( b, int ), type(b) assert isinstance( c, int ), type(c) assert isinstance( d, int ), type(d) return { 'int': [a,b,c,d], } @expose() def display_form(self, **kwargs): return str(myform.render(values=kwargs)) @expose('json') @validate(form=myform) def process_form(self, **kwargs): kwargs['errors'] = pylons.tmpl_context.form_errors return dict(kwargs) @expose('json') @validate(form=myform, error_handler=process_form) def send_to_error_handler(self, **kwargs): kwargs['errors'] = pylons.tmpl_context.form_errors return dict(kwargs) @expose() def set_lang(self, lang=None): pylons.session['tg_lang'] = lang pylons.session.save() return 'ok' @expose() @validate(validators=Pwd()) def password(self, pwd1, pwd2): if pylons.tmpl_context.form_errors: return "There was an error" else: return "Password ok!" @expose('json') @before_render(lambda rem,params,output:output.update({'GOT_ERROR':'HOOKED'})) def hooked_error_handler(self, *args, **kw): return dict(GOT_ERROR='MISSED HOOK') @expose() @validate({'v':validators.Int()}, error_handler=hooked_error_handler) def with_hooked_error_handler(self, *args, **kw): return dict(GOT_ERROR='NO ERROR') class TestTGController(TestWSGIController): def setUp(self): TestWSGIController.setUp(self) pylons.config.update({ 'pylons.paths': {'root': data_dir}, 'pylons.package': 'tests'}) self.app = make_app(BasicTGController) def test_basic_validation_and_jsonification(self): """Ensure you can pass in a dictionary of validators""" form_values = {"some_int": 22} resp = self.app.post('/validated_int', form_values) assert '{"response": 22}'in resp, resp def test_for_other_params_after_validation(self): """Ensure that both validated and unvalidated data make it through""" form_values = {'a': 1, 'b': "string"} resp = self.app.post('/validated_and_unvalidated', form_values) assert '"int": 1' in resp assert '"str": "string"' in resp, resp def test_validation_shadowed_by_defaults( self ): """Catch regression on positional argument validation with defaults""" resp = self.app.post('/with_default_shadow/1?b=string') assert '"int": 1' in resp, resp def test_optional_shadowed_by_defaults( self ): """Catch regression on optional arguments being reverted to un-validated""" resp = self.app.post('/with_default_shadow_long/1?b=2&c=3&d=4') assert '"int": [1, 2, 3, 4]' in resp, resp @raises(AssertionError) def test_validation_fails_with_no_error_handler(self): form_values = {'a':'asdf', 'b':"string"} resp = self.app.post('/validated_and_unvalidated', form_values) def test_two_validators_errors(self): """Ensure that multiple validators are applied correctly""" form_values = {'a': '1', 'someemail': "guido@google.com"} resp = self.app.post('/two_validators', form_values) content = loads(resp.body) assert content['a'] == 1 def test_validation_errors(self): """Ensure that dict validation produces a full set of errors""" form_values = {'a': '1', 'someemail': "guido~google.com"} resp = self.app.post('/two_validators', form_values) content = loads(resp.body) errors = content.get('errors', None) assert errors, 'There should have been at least one error' assert 'someemail' in errors, \ 'The email was invalid and should have been reported in the errors' def test_form_validation(self): """Check @validate's handing of ToscaWidget forms instances""" form_values = {'title': 'Razer', 'year': "2007"} resp = self.app.post('/process_form', form_values) values = loads(resp.body) assert values['year'] == 2007 def test_error_with_colon(self): resp = self.app.post('/error_with_colon', {'e':"fakeparam"}) assert 'Description' in resp.body, resp.body def test_form_render(self): """Test that myform renders properly""" resp = self.app.post('/display_form') assert 'id="my_form_title.label"' in resp, resp assert 'class="fieldlabel required"' in resp, resp assert "Title" in resp, resp def test_form_validation_error(self): """Test form validation with error message""" form_values = {'title': 'Razer', 'year': "t007"} resp = self.app.post('/process_form', form_values) values = loads(resp.body) assert "Please enter an integer value" in values['errors']['year'], \ 'Error message not found: %r' % values['errors'] def test_form_validation_redirect(self): """Test form validation error message with redirect""" form_values = {'title': 'Razer', 'year': "t007"} resp = self.app.post('/send_to_error_handler', form_values) values = loads(resp.body) assert "Please enter an integer value" in values['errors']['year'], \ 'Error message not found: %r' % values['errors'] def test_form_validation_translation(self): """Test translation of form validation error messages""" form_values = {'title': 'Razer', 'year': "t007"} # check with language set in request header resp = self.app.post('/process_form', form_values, headers={'Accept-Language': 'de,ru,it'}) values = loads(resp.body) assert u"Bitte eine ganze Zahl eingeben" in values['errors']['year'], \ 'No German error message: %r' % values['errors'] resp = self.app.post('/process_form', form_values, headers={'Accept-Language': 'ru,de,it'}) values = loads(resp.body) assert u"Введите числовое значение" in values['errors']['year'], \ 'No Russian error message: %r' % values['errors'] # check with language set in session self.app.post('/set_lang/de') resp = self.app.post('/process_form', form_values, headers={'Accept-Language': 'ru,it'}) values = loads(resp.body) assert u"Bitte eine ganze Zahl eingeben" in values['errors']['year'], \ 'No German error message: %r' % values['errors'] def test_form_validation_error(self): """Test schema validation""" form_values = {'pwd1': 'me', 'pwd2': 'you'} resp = self.app.post('/password', form_values) assert "There was an error" in resp, resp form_values = {'pwd1': 'you', 'pwd2': 'you'} resp = self.app.post('/password', form_values) assert "Password ok!" in resp, resp def test_controller_based_validator(self): """Test controller based validation""" resp = self.app.post('/validate_controller_based_validator') assert 'ok' in resp, resp def test_hook_after_validation_error(self): resp = self.app.post('/with_hooked_error_handler?v=a') assert 'HOOKED' in resp, respTurboGears2-2.1.5/tests/__init__.py0000664000175000017500000000000011675520537017746 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_util.py0000664000175000017500000000142311675520537020235 0ustar marvinmarvin00000000000000import tg from tg.util import * from nose.tools import eq_ import os path = None def setup(): global path path = os.curdir os.chdir(os.path.abspath(os.path.dirname(os.path.dirname(tg.__file__)))) def teardown(): global path os.chdir(path) def test_get_partial_dict(): eq_(get_partial_dict('prefix', {'prefix.xyz':1, 'prefix.zyx':2, 'xy':3}), {'xyz':1,'zyx':2}) # These tests aren't reliable if the package in question has # entry points. def test_get_package_name(): eq_(get_package_name(), 'tg') def test_get_project_name(): eq_(get_project_name(), 'TurboGears2') def test_get_project_meta(): eq_(get_project_meta('requires.txt'), os.path.join('TurboGears2.egg-info', 'requires.txt')) def test_get_model(): eq_(get_model(), None) TurboGears2-2.1.5/tests/test_render.py0000664000175000017500000000064411675520537020543 0ustar marvinmarvin00000000000000""" Testing for TG2 Configuration """ from nose.tools import eq_, raises import atexit from tg.render import render, MissingRendererError from tests.base import TestWSGIController, make_app, setup_session_dir, teardown_session_dir, create_request def setup(): setup_session_dir() def teardown(): teardown_session_dir() @raises(MissingRendererError) def test_render_missing_renderer(): render({}, 'gensh') TurboGears2-2.1.5/tests/test_generic_json.py0000664000175000017500000000447211675520537021734 0ustar marvinmarvin00000000000000from tg.jsonify import jsonify, encode from simplejson import loads from datetime import date class Person(object): def __init__(self, first_name, last_name): self.first_name = first_name self.last_name = last_name @property def name(self): return '%s %s' % (self.first_name, self.last_name) def __json__(self): return dict(first_name=self.first_name, last_name=self.last_name) def test_simple_rule(): # skip this test if simplegeneric is not installed try: import simplegeneric except ImportError: return # create a Person instance p = Person('Jonathan', 'LaCour') # encode the object using the existing "default" rules result = loads(encode(p)) assert result['first_name'] == 'Jonathan' assert result['last_name'] == 'LaCour' assert len(result) == 2 # register a generic JSON rule @jsonify.when_type(Person) def jsonify_person(obj): return dict( name=obj.name ) # encode the object using our new rule result = loads(encode(p)) assert result['name'] == 'Jonathan LaCour' assert len(result) == 1 def test_builtin_override(): # skip this test if simplegeneric is not installed try: import simplegeneric except ImportError: return # create a few date objects d1 = date(1979, 10, 12) d2 = date(2000, 1, 1) d3 = date(2012, 1, 1) # jsonify using the built in rules result1 = encode(dict(date=d1)) assert '"1979-10-12"' in result1 result2 = encode(dict(date=d2)) assert '"2000-01-01"' in result2 result3 = encode(dict(date=d3)) assert '"2012-01-01"' in result3 # create a custom rule @jsonify.when_type(date) def jsonify_date(obj): if obj.year == 1979 and obj.month == 10 and obj.day == 12: return "Jon's Birthday!" elif obj.year == 2000 and obj.month == 1 and obj.day == 1: return "Its Y2K! Panic!" return '%d/%d/%d' % (obj.month, obj.day, obj.year) # jsonify using the built in rules result1 = encode(dict(date=d1)) assert '"Jon\'s Birthday!"' in result1 result2 = encode(dict(date=d2)) assert '"Its Y2K! Panic!"' in result2 result3 = encode(dict(date=d3)) assert '"1/1/2012"' in result3 TurboGears2-2.1.5/tests/test_tg_controller_dispatch.py0000664000175000017500000005170711736737176024035 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- from wsgiref.simple_server import demo_app from wsgiref.validate import validator from formencode import validators from webob import Response, Request from pylons.controllers.xmlrpc import XMLRPCController import tg from tg import config, tmpl_context from tg.controllers import ( TGController, CUSTOM_CONTENT_TYPE, WSGIAppController) from tg.decorators import expose, validate from tg.util import no_warn from tests.base import ( TestWSGIController, make_app, setup_session_dir, teardown_session_dir) config['renderers'] = ['genshi', 'mako', 'json'] def setup(): setup_session_dir() def teardown(): teardown_session_dir() def wsgi_app(environ, start_response): req = Request(environ) if req.method == 'POST': resp = Response(req.POST['data']) else: resp = Response("Hello from %s/%s"%(req.script_name, req.path_info)) return resp(environ, start_response) class XMLRpcTestController(XMLRPCController): def textvalue(self): return 'hi from xmlrpc' textvalue.signature = [ ['string'] ] class BeforeController(TGController): def _before(self, *args, **kw): tmpl_context.var = '__my_before__' def _after(self, *args, **kw): global_craziness = '__my_after__' @expose() def index(self): assert tmpl_context.var return tmpl_context.var class NewBeforeController(TGController): def _before(self, *args, **kw): tmpl_context.var = '__my_before__' tmpl_context.args = args tmpl_context.params = kw def _after(self, *args, **kw): global_craziness = '__my_after__' @expose() def index(self): assert tmpl_context.var return tmpl_context.var @expose() def with_args(self, *args, **kw): assert tmpl_context.args assert tmpl_context.params return tmpl_context.var + tmpl_context.params['environ']['webob._parsed_query_vars'][0]['x'] class SubController(object): mounted_app = WSGIAppController(wsgi_app) before = BeforeController() newbefore = NewBeforeController() @expose('genshi') def unknown_template(self): return "sub unknown template" @expose() def foo(self,): return 'sub_foo' @expose() def index(self): return 'sub index' @expose() def _default(self, *args): return "received the following args (from the url): %s" % list(args) @expose() def redirect_me(self, target, **kw): tg.redirect(target, **kw) @expose() def redirect_sub(self): tg.redirect('index') @expose() def hello(self, name): return "Why hello, %s!" % name class SubController3(object): @expose() def get_all(self): return 'Sub 3' class SubController2(object): @expose() def index(self): tg.redirect('list') @expose() def list(self, **kw): return "hello list" class LookupHelper: def __init__(self, var): self.var = var @expose() def index(self): return self.var class LookupHelperWithArgs: @expose() def get_here(self, *args): return "%s"%args @expose() def post_with_mixed_args(self, arg1, arg2, **kw): return "%s%s" % (arg1, arg2) class LookupControllerWithArgs(TGController): @expose() def _lookup(self, *args): helper = LookupHelperWithArgs() return helper, args class LookupController(TGController): @expose() def _lookup(self, a, *args): return LookupHelper(a), args class LookupWithEmbeddedLookupController(TGController): @expose() def _lookup(self, *args): return LookupControllerWithArgs(), args class LookupHelperWithIndex: @expose() def index(self): return "helper index" @expose() def method(self): return "helper method" class LookupControllerWithIndexHelper(TGController): @expose() def _lookup(self, a, *args): return LookupHelperWithIndex(), args @expose() def index(self): return "second controller with index" class LookupWithEmbeddedLookupWithHelperWithIndex(TGController): @expose() def _lookup(self, a, *args): return LookupControllerWithIndexHelper(), args @expose() def index(self): return "first controller with index" class LookupControllerWithSubcontroller(TGController): class SubController(object): pass @expose() def _lookup(self, a, *args): return self.SubController(), args class RemoteErrorHandler(TGController): @expose() def errors_here(self, *args, **kw): return "remote error handler" class NotFoundController(TGController): pass class DefaultWithArgsController(TGController): @expose() def _default(self, a, b=None, **kw): return "default with args %s %s" % (a, b) class DeprecatedDefaultWithArgsController(TGController): @expose() def default(self, a, b=None, **kw): return "deprecated default with args %s %s" % (a, b) class DefaultWithArgsAndValidatorsController(TGController): @expose() def failure(self, *args, **kw): return "failure" @expose() @validate(dict(a=validators.Int(), b=validators.StringBool()), error_handler=failure) def _default(self, a, b=None, **kw): return "default with args and validators %s %s"%(a, b) class SubController4: default_with_args = DefaultWithArgsController() deprecated_default_with_args = DeprecatedDefaultWithArgsController() class SubController5: default_with_args = DefaultWithArgsAndValidatorsController() class HelperWithSpecificArgs(TGController): @expose() def index(self, **kw): return str(kw) @expose() def method(self, arg1, arg2, **kw): return str((arg1, arg2, kw)) class SelfCallingLookupController(TGController): @expose() def _lookup(self, a, *args): if a in ['a', 'b', 'c']: return SelfCallingLookupController(), args a = [a] a.extend(args) return HelperWithSpecificArgs(), a @expose() def index(self, *args, **kw): return str((args, kw)) class BasicTGController(TGController): mounted_app = WSGIAppController(wsgi_app) xml_rpc = WSGIAppController(XMLRpcTestController()) error_controller = RemoteErrorHandler() lookup = LookupController() lookup_with_args = LookupControllerWithArgs() lookup_with_sub = LookupControllerWithSubcontroller() self_calling = SelfCallingLookupController() @expose(content_type='application/rss+xml') def ticket2351(self, **kw): return 'test' @expose() def index(self, **kwargs): return 'hello world' @expose() def _default(self, *remainder): return "Main default page called for url /%s" % list(remainder) @expose() def feed(self, feed=None): return feed sub = SubController() sub2 = SubController2() sub4 = SubController4() sub5 = SubController5() embedded_lookup = LookupWithEmbeddedLookupController() embedded_lookup_with_index = LookupWithEmbeddedLookupWithHelperWithIndex() @expose() def test_args(self, name, one=None, two=2, three=3): return "name=%s, one=%s, two=%s, three=%s" % (name, one, two, three) @expose() def redirect_me(self, target, **kw): tg.redirect(target, kw) @expose() def hello(self, name, silly=None): return "Hello " + name @expose() def optional_and_req_args(self, name, one=None, two=2, three=3): return "name=%s, one=%s, two=%s, three=%s" % (name, one, two, three) @expose() def ticket2412(self, arg1): return arg1 @expose() def redirect_cookie(self, name): tg.response.set_cookie('name', name) tg.redirect('/hello_cookie') @expose() def hello_cookie(self): return "Hello " + tg.request.cookies['name'] @expose() def flash_redirect(self): tg.flash("Wow, flash!") tg.redirect("/flash_after_redirect") @expose() def flash_unicode(self): tg.flash(u"Привет, мир!") tg.redirect("/flash_after_redirect") @expose() def flash_after_redirect(self): return tg.get_flash() @expose() def flash_status(self): return tg.get_status() @expose() def flash_no_redirect(self): tg.flash("Wow, flash!") return tg.get_flash() @expose('json') @validate(validators=dict(some_int=validators.Int())) def validated_int(self, some_int): assert isinstance(some_int, int) return dict(response=some_int) @expose('json') @validate(validators=dict(a=validators.Int())) def validated_and_unvalidated(self, a, b): assert isinstance(a, int) assert isinstance(b, unicode) return dict(int=a,str=b) @expose() def error_handler(self, **kw): return 'validation error handler' @expose('json') @validate(validators=dict(a=validators.Int()), error_handler=error_handler) def validated_with_error_handler(self, a, b): assert isinstance(a, int) assert isinstance(b, unicode) return dict(int=a,str=b) @expose('json') @validate(validators=dict(a=validators.Int()), error_handler=error_controller.errors_here) def validated_with_remote_error_handler(self, a, b): assert isinstance(a, int) assert isinstance(b, unicode) return dict(int=a,str=b) @expose() @expose('json') def stacked_expose(self): return dict(got_json=True) @expose('json') def bad_json(self): return [(1, 'a'), 'b'] @expose() def custom_content_type_in_controller(self): tg.response.headers['content-type'] = 'image/png' return 'PNG' @expose('json', content_type='application/json') def custom_content_type_in_controller_charset(self): tg.response.headers['content-type'] = 'application/json; charset=utf-8' return dict(result='TXT') @expose(content_type=CUSTOM_CONTENT_TYPE) def custom_content_type_with_ugliness(self): tg.response.headers['content-type'] = 'image/png' return 'PNG' @expose(content_type='image/png') def custom_content_type_in_decorator(self): return 'PNG' @expose() def test_204(self, *args, **kw): from webob.exc import HTTPNoContent raise HTTPNoContent().exception @expose() def custom_content_type_replace_header(self): replace_header(tg.response.headerlist, 'Content-Type', 'text/xml') return "" @expose() def multi_value_kws(sekf, *args, **kw): assert kw['foo'] == ['1', '2'], kw class TestNotFoundController(TestWSGIController): def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) self.app = make_app(NotFoundController) def test_not_found(self): r = self.app.get('/something', status=404) assert '404 Not Found' in r, r def test_not_found_blank(self): r = self.app.get('/', status=404) assert '404 Not Found' in r, r def test_not_found_unicode(self): r = self.app.get('/права', status=404) assert '404 Not Found' in r, r class TestWSGIAppController(TestWSGIController): def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) class TestedWSGIAppController(WSGIAppController): def __init__(self): def test_app(environ, start_response): if environ.get('CONTENT_LENGTH', None) in (-1, '-1'): del environ['CONTENT_LENGTH'] return validator(demo_app)(environ, start_response) super(TestedWSGIAppController, self).__init__(test_app) self.app = make_app(TestedWSGIAppController) def test_valid_wsgi(self): try: r = self.app.get('/some_url') except Exception, e: raise AssertionError(str(e)) assert 'some_url' in r class TestTGController(TestWSGIController): def setUp(self, *args, **kargs): TestWSGIController.setUp(self, *args, **kargs) self.app = make_app(BasicTGController) def test_lookup(self): r = self.app.get('/lookup/EYE') msg = 'EYE' assert msg in r, r def test_lookup_with_sub(self): r = self.app.get('/lookup_with_sub/EYE') msg = 'EYE' assert msg in r, r def test_lookup_with_args(self): r = self.app.get('/lookup_with_args/get_here/got_here') msg = 'got_here' assert r.body==msg, r def test_post_with_mixed_args(self): r = self.app.post('/lookup_with_args/post_with_mixed_args/test', params={'arg2': 'time'}) msg = 'testtime' assert r.body==msg, r def test_validated_int(self): r = self.app.get('/validated_int/1') assert '{"response": 1}' in r, r def test_validated_with_error_handler(self): r = self.app.get('/validated_with_error_handler?a=asdf&b=123') msg = 'validation error handler' assert msg in r, r def test_validated_with_remote_error_handler(self): r = self.app.get('/validated_with_remote_error_handler?a=asdf&b=123') msg = 'remote error handler' assert msg in r, r def test_unknown_template(self): r = self.app.get('/sub/unknown_template/') msg = 'sub unknown template' assert msg in r, r def test_mounted_wsgi_app_at_root(self): r = self.app.get('/mounted_app/') assert 'Hello from /mounted_app' in r, r def test_mounted_wsgi_app_at_subcontroller(self): r = self.app.get('/sub/mounted_app/') assert 'Hello from /sub/mounted_app/' in r, r def test_request_for_wsgi_app_with_extension(self): r = self.app.get('/sub/mounted_app/some_document.pdf') assert 'Hello from /sub/mounted_app//some_document.pdf' in r, r def test_posting_to_mounted_app(self): r = self.app.post('/mounted_app/', params={'data':'Foooo'}) assert 'Foooo' in r, r def test_custom_content_type_replace_header(self): s = ''' textvalue ''' r = self.app.post('/xml_rpc/', s, [('Content-Type', 'text/xml')]) assert len(r.headers.getall('Content-Type')) == 1 def test_response_type(self): r = self.app.post('/stacked_expose.json') assert 'got_json' in r.body, r def test_multi_value_kw(self): r = self.app.get('/multi_value_kws?foo=1&foo=2') def test_before_controller(self): r = self.app.get('/sub/before') assert '__my_before__' in r, r def test_new_before_controller(self): r = self.app.get('/sub/newbefore') assert '__my_before__' in r, r def test_before_with_args(self): r = self.app.get('/sub/newbefore/with_args/1/2?x=5') assert '__my_before__5' in r, r @no_warn def test_unicode_default_dispatch(self): r =self.app.get('/sub/äö') assert "\\xc3\\xa4\\xc3\\xb6" in r, r def test_default_with_empty_second_arg(self): r =self.app.get('/sub4/default_with_args/a') assert "default with args a None" in r.body, r assert "deprecated" not in r.body import warnings warnings.filterwarnings('ignore', category=DeprecationWarning) r = self.app.get('/sub4/deprecated_default_with_args/a') warnings.resetwarnings() assert "deprecated default with args a None" in r.body, r def test_default_with_args_a_b(self): r =self.app.get('/sub4/default_with_args/a/b') assert "default with args a b" in r.body, r assert "deprecated" not in r.body import warnings warnings.filterwarnings('ignore', category=DeprecationWarning) r = self.app.get('/sub4/deprecated_default_with_args/a/b') warnings.resetwarnings() assert "deprecated default with args a b" in r.body, r def test_default_with_query_arg(self): r =self.app.get('/sub4/default_with_args?a=a') assert "default with args a None" in r.body, r assert "deprecated" not in r.body import warnings warnings.filterwarnings('ignore', category=DeprecationWarning) r = self.app.get('/sub4/deprecated_default_with_args?a=a') warnings.resetwarnings() assert "deprecated default with args a None" in r.body, r def test_default_with_validator_fail(self): r =self.app.get('/sub5/default_with_args?a=True') assert "failure" in r.body, r def test_default_with_validator_pass(self): r =self.app.get('/sub5/default_with_args?a=66') assert "default with args and validators 66 None" in r.body, r def test_default_with_validator_pass2(self): r =self.app.get('/sub5/default_with_args/66') assert "default with args and validators 66 None" in r.body, r def test_default_with_validator_fail2(self): r =self.app.get('/sub5/default_with_args/True/more') assert "failure" in r.body, r def test_custom_content_type_in_controller(self): resp = self.app.get('/custom_content_type_in_controller') assert 'PNG' in resp, resp assert resp.headers['Content-Type'] == 'image/png', resp def test_custom_content_type_in_controller_charset(self): resp = self.app.get('/custom_content_type_in_controller_charset') assert 'TXT' in resp, resp assert resp.headers['Content-Type'] == 'application/json; charset=utf-8', resp def test_custom_content_type_in_decorator(self): resp = self.app.get('/custom_content_type_in_decorator') assert 'PNG' in resp, resp assert resp.headers['Content-Type'] == 'image/png', resp def test_custom_content_type_with_ugliness(self): #in 2.2 this test can be removed for CUSTOM_CONTENT_TYPE will be removed resp = self.app.get('/custom_content_type_with_ugliness') assert 'PNG' in resp, resp assert resp.headers['Content-Type'] == 'image/png', resp def test_removed_spurious_content_type(self): r = self.app.get('/test_204') assert r.headers.get('Content-Type', 'MISSING') == 'MISSING' def test_optional_and_req_args(self): resp = self.app.get('/optional_and_req_args/test/one') assert "name=test, one=one, two=2, three=3" in resp, resp def test_optional_and_req_args_at_root(self): resp = self.app.get('/test_args/test/one') assert "name=test, one=one, two=2, three=3" in resp, resp def test_no_args(self): resp = self.app.get('/test_args/test/') assert "name=test, one=None, two=2, three=3" in resp, resp def test_one_extra_arg(self): resp = self.app.get('/test_args/test/1') assert "name=test, one=1, two=2, three=3" in resp, resp def test_two_extra_args(self): resp = self.app.get('/test_args/test/1/2') assert "name=test, one=1, two=2, three=3" in resp, resp def test_three_extra_args(self): resp = self.app.get('/test_args/test/1/2/3') assert "name=test, one=1, two=2, three=3" in resp, resp def test_extra_args_forces_default_lookup(self): resp = self.app.get('/test_args/test/1/2/3/4') assert resp.body == """Main default page called for url /['test_args', 'test', '1', '2', '3', '4']""", resp def test_not_enough_args(self): resp = self.app.get('/test_args/test/1') assert "name=test, one=1, two=2, three=3" in resp, resp def test_ticket_2412_with_ordered_arg(self): # this is failing resp = self.app.get('/ticket2412/Abip%C3%B3n') assert """Abipón""" in resp, resp def test_ticket_2412_with_named_arg(self): resp = self.app.get('/ticket2412?arg1=Abip%C3%B3n') assert """Abipón""" in resp, resp def test_ticket_2351_bad_content_type(self): resp = self.app.get('/ticket2351', headers={'Accept':'text/html'}) assert 'test' in resp, resp def test_embedded_lookup_with_index_first(self): resp = self.app.get('/embedded_lookup_with_index/') assert 'first controller with index' in resp, resp def test_embedded_lookup_with_index_second(self): resp = self.app.get('/embedded_lookup_with_index/a') assert 'second controller with index' in resp, resp def test_embedded_lookup_with_index_helper(self): resp = self.app.get('/embedded_lookup_with_index/a/b') assert 'helper index' in resp, resp def test_embedded_lookup_with_index_method(self): resp = self.app.get('/embedded_lookup_with_index/a/b/method') assert 'helper method' in resp, resp def test_self_calling_lookup_simple_index(self): resp = self.app.get('/self_calling') assert '((), {})' in resp, resp def test_self_calling_lookup_method(self): resp = self.app.get('/self_calling/a/method/a/b') assert "('a', 'b', {})" in resp, resp def test_self_calling_lookup_multiple_calls_method(self): resp = self.app.get('/self_calling/a/b/c/method/a/b') assert "('a', 'b', {})" in resp, resp TurboGears2-2.1.5/tests/test_jsonify.py0000664000175000017500000000265611675520537020752 0ustar marvinmarvin00000000000000from tg import jsonify from nose.tools import raises class Foo(object): def __init__(self, bar): self.bar = bar class Bar(object): def __init__(self, bar): self.bar = bar def __json__(self): return 'bar-%s' % self.bar class Baz(object): pass def test_string(): d = "string" encoded = jsonify.encode(d) assert encoded == '"string"' @raises(jsonify.JsonEncodeError) def test_list(): d = ['a', 1, 'b', 2] encoded = jsonify.encode(d) assert encoded == '["a", 1, "b", 2]' @raises(jsonify.JsonEncodeError) def test_list_iter(): d = range(3) encoded = jsonify.encode_iter(d) assert ''.join(jsonify.encode_iter(d)) == jsonify.encode(d) def test_dictionary(): d = {'a': 1, 'b': 2} encoded = jsonify.encode(d) assert encoded == '{"a": 1, "b": 2}' @raises(jsonify.JsonEncodeError) def test_nospecificjson(): b = Baz() try: encoded = jsonify.encode(b) except TypeError, e: pass assert "is not JSON serializable" in e.message def test_exlicitjson(): b = Bar("bq") encoded = jsonify.encode(b) assert encoded == '"bar-bq"' @raises(jsonify.JsonEncodeError) def test_exlicitjson_in_list(): b = Bar("bq") d = [b] encoded = jsonify.encode(d) assert encoded == '["bar-bq"]' def test_exlicitjson_in_dict(): b = Bar("bq") d = {"b": b} encoded = jsonify.encode(d) assert encoded == '{"b": "bar-bq"}' TurboGears2-2.1.5/tests/test_rest_controller_dispatch.py0000664000175000017500000005133011736737176024370 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- from webob import Response, Request from tg.controllers import TGController, RestController from tg.decorators import expose from tg.util import no_warn from tests.base import ( TestWSGIController, make_app, setup_session_dir, teardown_session_dir) def setup(): setup_session_dir() def teardown(): teardown_session_dir() def wsgi_app(environ, start_response): req = Request(environ) if req.method == 'POST': resp = Response(req.POST['data']) else: resp = Response("Hello from %s/%s"%(req.script_name, req.path_info)) return resp(environ, start_response) class LookupHelper: def __init__(self, var): self.var = var @expose() def index(self): return self.var class LookupController(TGController): @expose() def _lookup(self, a, *args): return LookupHelper(a), args class DeprecatedLookupController(TGController): @expose() def lookup(self, a, *args): return LookupHelper(a), args class LookupAlwaysHelper: """for testing _dispatch""" def __init__(self, var): self.var = var def _setup_wsgiorg_routing_args(self, url_path, remainder, params): pass @expose() def always(self, *args, **kwargs): return 'always go here' def _dispatch(self, state, remainder): state.add_method(self.always, remainder) return state class LookupAlwaysController(TGController): @expose() def _lookup(self, a, *args): return LookupAlwaysHelper(a), args class CustomDispatchingSubController(TGController): @expose() def always(self, *args, **kwargs): return 'always go here' def _dispatch(self, state, remainder): state.add_method(self.always, remainder) return state class OptionalArgumentRestController(RestController): @expose() def get_one(self, optional=None): return "SUBREST GET ONE" @expose() def put(self, optional=None): return "subrest put" @expose() def post(self, optional=None): return "subrest post" @expose() def edit(self, optional=None): return "subrest edit" @expose() def new(self, optional=None): return "subrest new" @expose() def get_delete(self, optional=None): return "subrest get delete" @expose() def post_delete(self, optional=None): return "subrest post delete" class RequiredArgumentRestController(RestController): @expose() def get_one(self, something): return "subrest get one" @expose() def put(self, something): return "subrest put" @expose() def post(self, something): return "subrest post" @expose() def edit(self, something): return "subrest edit" @expose() def new(self): return "subrest new" @expose() def get_delete(self, something): return "subrest get delete" @expose() def post_delete(self, something): return "subrest post delete" class VariableSubRestController(RestController): @expose() def get_one(self, *args): return "subrest get one" @expose() def put(self, *args): return "subrest put" @expose() def edit(self, *args): return "subrest edit" @expose() def new(self, *args): return "subrest new" @expose() def get_delete(self, *args): return "subrest get delete" @expose() def post_delete(self, *args): return "subrest post delete" class SubRestController(RestController): @expose() def get_all(self): return "subrest get all" @expose() def get_one(self, nr): return "subrest get one %s" % nr @expose() def new(self): return "subrest new" @expose() def edit(self, nr): return "subrest edit %s" % nr @expose() def post(self): return "subrest post" @expose() def put(self, nr): return "subrest put %s" % nr @expose() def fxn(self): return "subrest fxn" @expose() def get_delete(self, nr): return "subrest get delete %s" % nr @expose() def post_delete(self, nr): return "subrest post delete %s" % nr class VariableRestController(RestController): subrest = SubRestController() vsubrest = VariableSubRestController() @expose() def get_all(self): return "rest get all" @expose() def get_one(self, *args): return "rest get onE" @expose() def get_delete(self, *args): return "rest get delete" @expose() def post_delete(self, *args): return "rest post delete" class ExtraRestController(RestController): @expose() def get_all(self): return "rest get all" @expose() def get_one(self, nr): return "rest get one %s" % nr @expose() def get_delete(self, nr): return "rest get delete %s" % nr @expose() def post_delete(self, nr): return "rest post delete %s" % nr class sub(TGController): @expose() def index(self): return "rest sub index" subrest = SubRestController() optsubrest = OptionalArgumentRestController() reqsubrest = RequiredArgumentRestController() @expose() def post_archive(self): return 'got to post archive' @expose() def get_archive(self): return 'got to get archive' class BasicRestController(RestController): @expose() def get(self): return "rest get" @expose() def post(self): return "rest post" @expose() def put(self): return "rest put" @expose() def delete(self): return "rest delete" @expose() def new(self): return "rest new" @expose() def edit(self, *args, **kw): return "rest edit" @expose() def other(self): return "rest other" @expose() def archive(self): return 'got to archive' class EmptyRestController(RestController): pass class SubController(TGController): rest = BasicRestController() @expose() def sub_method(self, arg): return 'sub %s'%arg class BasicTGController(TGController): sub = SubController() custom_dispatch = CustomDispatchingSubController() lookup = LookupController() deprecated_lookup = LookupController() lookup_dispatch = LookupAlwaysController() rest = BasicRestController() rest2 = ExtraRestController() rest3 = VariableRestController() empty = EmptyRestController() @expose() def index(self, **kwargs): return 'hello world' @expose() def _default(self, *remainder): return "Main default page called for url /%s" % list(remainder) @expose() def hello(self, name, silly=None): return "Hello %s" % name class BasicTGControllerNoDefault(TGController): @expose() def index(self, **kwargs): return 'hello world' class TestTGControllerRoot(TestWSGIController): def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) self.app = make_app(BasicTGControllerNoDefault) def test_root_default_dispatch(self): self.app.get('/i/am/not/a/sub/controller', status=404) class TestTGController(TestWSGIController): def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) self.app = make_app(BasicTGController) def test_lookup(self): r = self.app.get('/lookup/eye') msg = 'eye' assert msg in r, r def test_deprecated_lookup(self): r = self.app.get('/deprecated_lookup/eye') msg = 'eye' assert msg in r, r def test_lookup_with_dispatch(self): r = self.app.get('/lookup_dispatch/eye') msg = 'always' assert msg in r, r def test_root_method_dispatch(self): resp = self.app.get('/hello/Bob') assert "Hello Bob" in resp, resp def test_root_index_dispatch(self): resp = self.app.get('/') assert "hello world" in resp, resp def test_no_sub_index_dispatch(self): resp = self.app.get('/sub/') assert "['sub']" in resp, resp def test_root_default_dispatch(self): resp = self.app.get('/i/am/not/a/sub/controller') assert "['i', 'am', 'not', 'a', 'sub', 'controller']" in resp, resp def test_default_dispatch_not_found_in_sub_controller(self): resp = self.app.get('/sub/no/default/found') assert "['sub', 'no', 'default', 'found']" in resp, resp def test_root_method_dispatch_with_trailing_slash(self): resp = self.app.get('/hello/Bob/') assert "Hello Bob" in resp, resp def test_sub_method_dispatch(self): resp = self.app.get('/sub/sub_method/army of darkness') assert "sub army" in resp, resp def test_custom_dispatch(self): resp = self.app.get('/custom_dispatch/army of darkness') assert "always" in resp, resp class TestRestController(TestWSGIController): def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) self.app = make_app(BasicTGController) def test_post(self): r = self.app.post('/rest/') assert 'rest post' in r, r def _test_non_resty(self): r = self.app.post('/rest/non_resty_thing') assert 'non_resty' in r, r def test_custom_action_simple_get(self): r = self.app.get('/rest/archive') assert 'got to archive' in r, r def test_custom_action_simple_post(self): r = self.app.post('/rest/archive') assert 'got to archive' in r, r def test_custom_action_simple_post_args(self): r = self.app.post('/rest?_method=archive') assert 'got to archive' in r, r def test_custom_action_get(self): r = self.app.get('/rest2/archive') assert 'got to get archive' in r, r def test_custom_action_post(self): r = self.app.post('/rest2?_method=archive') assert 'got to post archive' in r, r def test_get(self): r = self.app.get('/rest/') assert 'rest get' in r, r def test_put(self): r = self.app.put('/rest/') assert 'rest put' in r, r def test_put_post(self): r = self.app.post('/rest?_method=PUT') assert 'rest put' in r, r def test_put_post_params(self): r = self.app.post('/rest', params={'_method':'PUT'}) assert 'rest put' in r, r def test_put_get(self): self.app.get('/rest?_method=PUT', status=405) def test_get_delete_bad(self): self.app.get('/rest?_method=DELETE', status=405) def test_delete(self): r = self.app.delete('/rest/') assert 'rest delete' in r, r def test_post_delete(self): r = self.app.post('/rest/', params={'_method':'DELETE'}) assert 'rest delete' in r, r def test_get_all(self): r = self.app.get('/rest2/') assert 'rest get all' in r, r def test_get_one(self): r = self.app.get('/rest2/1') assert 'rest get one 1' in r, r def test_get_delete(self): r = self.app.get('/rest2/1/delete') assert 'rest get delete' in r, r def test_post_delete_params(self): r = self.app.post('/rest2/1', params={'_method':'DELETE'}) assert 'rest post delete' in r, r def test_post_delete_var(self): r = self.app.post('/rest3/a/b/c', params={'_method':'DELETE'}) assert 'rest post delete' in r, r def test_get_delete_var(self): r = self.app.get('/rest3/a/b/c/delete') assert 'rest get delete' in r, r def test_get_method(self): r = self.app.get('/rest/other') assert 'rest other' in r, r @no_warn def test_get_sub_controller(self): r = self.app.get('/rest2/sub') assert 'rest sub index' in r, r @no_warn def test_put_sub_controller(self): r = self.app.put('/rest2/sub') assert 'rest sub index' in r, r def test_post_sub_controller(self): r = self.app.post('/rest2/sub') assert 'rest sub index' in r, r def test_post_miss(self): r = self.app.post('/rest2/something') assert "/['rest2', 'something']" in r, r def test_get_empty(self): r = self.app.get('/empty/') assert "/['empty']" in r, r def test_post_empty(self): r = self.app.post('/empty/') assert "/['empty']" in r, r def test_put_empty(self): r = self.app.put('/empty/') assert "/['empty']" in r, r @no_warn def test_delete_empty(self): r = self.app.delete('/empty/') assert "/['empty']" in r, r def test_put_miss(self): r = self.app.put('/rest/something') assert "/['rest', 'something']" in r, r def test_delete_miss(self): r = self.app.delete('/rest/something') assert "/['rest', 'something']" in r, r def test_get_miss(self): r = self.app.get('/rest2/something/else') assert "/['rest2', 'something', 'else']" in r, r def test_post_method(self): r = self.app.post('/rest/other') assert 'rest other' in r, r def test_new_method(self): r = self.app.post('/rest/new') assert 'rest new' in r, r def test_edit_method(self): r = self.app.get('/rest/1/edit') assert 'rest edit' in r, r def test_delete_method(self): self.app.delete('/rest/other', status=405) def test_sub_with_rest_delete(self): r = self.app.delete('/sub/rest/') assert 'rest delete' in r, r def test_put_method(self): r = self.app.put('/rest/other') assert 'rest other' in r, r def test_sub_get_all_method(self): r = self.app.get('/rest2/1/subrest') assert 'subrest get all' in r, r def test_var_sub_get_all_method(self): r = self.app.get('/rest3/1/3/3/subrest') assert 'subrest get all' in r, r r = self.app.get('/rest3/1/3/subrest') assert 'subrest get all' in r, r r = self.app.get('/rest3/subrest') assert 'subrest get all' in r, r def test_var_sub_get_one_method(self): r = self.app.get('/rest3/1/3/3/subrest/1') assert 'subrest get one' in r, r r = self.app.get('/rest3/1/3/subrest/1') assert 'subrest get one' in r, r r = self.app.get('/rest3/subrest/1') assert 'subrest get one' in r, r def test_var_sub_edit_method(self): r = self.app.get('/rest3/1/3/3/subrest/1/edit') assert 'subrest edit' in r, r r = self.app.get('/rest3/1/3/subrest/1/edit') assert 'subrest edit' in r, r r = self.app.get('/rest3/subrest/1/edit') assert 'subrest edit' in r, r def test_var_sub_edit_var_method(self): r = self.app.get('/rest3/1/3/3/vsubrest/1/edit') assert 'subrest edit' in r, r r = self.app.get('/rest3/1/3/vsubrest/1/a/edit') assert 'subrest edit' in r, r r = self.app.get('/rest3/vsubrest/edit') assert 'subrest edit' in r, r def test_var_sub_delete_method(self): r = self.app.get('/rest3/1/3/3/subrest/1/delete') assert 'subrest get delete' in r, r r = self.app.get('/rest3/1/3/subrest/1/delete') assert 'subrest get delete' in r, r r = self.app.get('/rest3/subrest/1/delete') assert 'subrest get delete' in r, r def test_var_sub_new_method(self): r = self.app.get('/rest3/1/3/3/subrest/new') assert 'subrest new' in r, r r = self.app.get('/rest3/1/3/subrest/new') assert 'subrest new' in r, r r = self.app.get('/rest3/subrest/new') assert 'subrest new' in r, r def test_var_sub_var_get_one_method(self): r = self.app.get('/rest3/1/3/3/vsubrest/1') assert 'subrest get one' in r, r r = self.app.get('/rest3/1/3/vsubrest/1/a') assert 'subrest get one' in r, r r = self.app.get('/rest3/vsubrest/') assert 'subrest get one' in r, r def test_var_sub_var_put_method(self): r = self.app.put('/rest3/1/3/3/vsubrest/1') assert 'subrest put' in r, r r = self.app.put('/rest3/1/3/vsubrest/1/asdf') assert 'subrest put' in r, r r = self.app.put('/rest3/vsubrest/') assert 'subrest put' in r, r def test_var_sub_post_method(self): r = self.app.post('/rest3/1/3/3/subrest/') assert 'subrest post' in r, r r = self.app.post('/rest3/1/3/subrest/') assert 'subrest post' in r, r r = self.app.post('/rest3/subrest/') assert 'subrest post' in r, r def test_var_sub_post_delete_method(self): r = self.app.delete('/rest3/1/3/3/subrest/1') assert 'subrest post delete' in r, r r = self.app.delete('/rest3/1/3/subrest/1') assert 'subrest post delete' in r, r def test_var_sub_put_method(self): r = self.app.put('/rest3/1/3/3/subrest/1') assert 'subrest put' in r, r r = self.app.put('/rest3/1/3/subrest/1') assert 'subrest put' in r, r r = self.app.put('/rest3/subrest/1') assert 'subrest put' in r, r def test_var_sub_put_hack_method(self): r = self.app.post('/rest3/1/3/3/subrest/1?_method=PUT') assert 'subrest put' in r, r r = self.app.post('/rest3/1/3/subrest/1?_method=put') assert 'subrest put' in r, r r = self.app.post('/rest3/subrest/1?_method=put') assert 'subrest put' in r, r def test_var_sub_var_delete_method(self): r = self.app.delete('/rest3/1/3/3/vsubrest/1') assert 'subrest post delete' in r, r r = self.app.delete('/rest3/1/3/vsubrest/1') assert 'subrest post delete' in r, r r = self.app.delete('/rest3/vsubrest/') assert 'subrest post delete' in r, r def test_var_sub_delete_var_hack_method(self): r = self.app.post('/rest3/1/3/3/vsubrest/1?_method=DELETE') assert 'subrest post delete' in r, r r = self.app.post('/rest3/1/3/vsubrest/1?_method=delete') assert 'subrest post delete' in r, r r = self.app.post('/rest3/vsubrest?_method=delete') assert 'subrest post delete' in r, r def test_var_sub_var_put_hack_method(self): r = self.app.post('/rest3/1/3/3/vsubrest/1?_method=PUT') assert 'subrest put' in r, r r = self.app.post('/rest3/1/3/vsubrest/1/a?_method=put') assert 'subrest put' in r, r r = self.app.post('/rest3/vsubrest/?_method=put') assert 'subrest put' in r, r def test_var_sub_delete_hack_method(self): r = self.app.post('/rest3/1/3/3/subrest/1?_method=DELETE') assert 'subrest post delete' in r, r r = self.app.post('/rest3/1/3/subrest/1?_method=delete') assert 'subrest post delete' in r, r r = self.app.post('/rest3/subrest/1?_method=delete') assert 'subrest post delete' in r, r def test_sub_new(self): r = self.app.get('/rest2/1/subrest/new') assert 'subrest new' in r, r def test_sub_edit(self): r = self.app.get('/rest2/1/subrest/1/edit') assert 'subrest edit' in r, r def test_sub_post(self): r = self.app.post('/rest2/1/subrest/') assert 'subrest post' in r, r def test_sub_put(self): r = self.app.put('/rest2/1/subrest/2') assert 'subrest put' in r, r def test_sub_post_opt(self): r = self.app.post('/rest2/1/optsubrest/1') assert 'subrest post' in r, r def test_sub_put_opt(self): r = self.app.put('/rest2/1/optsubrest/1') assert 'subrest put' in r, r def test_sub_put_opt_hack(self): r = self.app.post('/rest2/1/optsubrest/1?_method=PUT') assert 'subrest put' in r, r def test_sub_delete_opt_hack(self): r = self.app.post('/rest2/1/optsubrest/1?_method=DELETE') assert 'subrest ' in r, r def test_put_post_req(self): r = self.app.post('/rest2/reqsubrest', params={'something':'required'}) assert 'subrest post' in r, r def test_sub_put_req(self): r = self.app.post('/rest2/reqsubrest', params={'_method':'PUT', 'something':'required'}) assert 'subrest put' in r, r def test_sub_post_req_bad(self): r = self.app.post('/rest2/reqsubrest',) assert "['rest2', 'reqsubrest']" in r, r def test_sub_delete_hack(self): r = self.app.post('/rest2/1/subrest/2?_method=DELETE') assert 'subrest post delete' in r, r def test_sub_get_delete(self): r = self.app.get('/rest2/1/subrest/2/delete') assert 'subrest get delete' in r, r def test_sub_post_delete(self): r = self.app.delete('/rest2/1/subrest/2') assert 'subrest post delete' in r, r def test_sub_get_fxn(self): r = self.app.get('/rest2/1/subrest/fxn') assert 'subrest fxn' in r, r def test_sub_post_fxn(self): r = self.app.post('/rest2/1/subrest/fxn') assert 'subrest fxn' in r, r TurboGears2-2.1.5/tests/test_jsonify_sqlalchemy.py0000664000175000017500000000605111675520537023165 0ustar marvinmarvin00000000000000from nose.tools import raises from tg import jsonify try: try: import sqlite3 except: import pysqlite2 from sqlalchemy import (MetaData, Table, Column, ForeignKey, Integer, String) from sqlalchemy.orm import create_session, mapper, relation metadata = MetaData('sqlite:///:memory:') test1 = Table('test1', metadata, Column('id', Integer, primary_key=True), Column('val', String(8))) test2 = Table('test2', metadata, Column('id', Integer, primary_key=True), Column('test1id', Integer, ForeignKey('test1.id')), Column('val', String(8))) test3 = Table('test3', metadata, Column('id', Integer, primary_key=True), Column('val', String(8))) test4 = Table('test4', metadata, Column('id', Integer, primary_key=True), Column('val', String(8))) metadata.create_all() class Test2(object): pass mapper(Test2, test2) class Test1(object): pass mapper(Test1, test1, properties={'test2s': relation(Test2)}) class Test3(object): def __json__(self): return {'id': self.id, 'val': self.val, 'customized': True} mapper(Test3, test3) class Test4(object): pass mapper(Test4, test4) test1.insert().execute({'id': 1, 'val': 'bob'}) test2.insert().execute({'id': 1, 'test1id': 1, 'val': 'fred'}) test2.insert().execute({'id': 2, 'test1id': 1, 'val': 'alice'}) test3.insert().execute({'id': 1, 'val': 'bob'}) test4.insert().execute({'id': 1, 'val': 'alberto'}) except ImportError: from warnings import warn warn('SQLAlchemy or PySqlite not installed - cannot run these tests.') else: def test_saobj(): s = create_session() t = s.query(Test1).get(1) encoded = jsonify.encode(t) assert encoded == '{"id": 1, "val": "bob"}' @raises(jsonify.JsonEncodeError) def test_salist(): s = create_session() t = s.query(Test1).get(1) encoded = jsonify.encode(t.test2s) assert encoded == '{rows: [{"test1id": 1, "id": 1, "val": "fred"},' \ ' {"test1id": 1, "id": 2, "val": "alice"}]', encoded @raises(jsonify.JsonEncodeError) def test_select_row(): s = create_session() t = test1.select().execute() encoded = jsonify.encode(t) # this may be added back later on # assert encoded == """{"count": -1, "rows": [{"count": 1, "rows": {"id": 1, "val": "bob"}}]}""", encoded @raises(jsonify.JsonEncodeError) def test_select_rows(): s = create_session() t = test2.select().execute() encoded = jsonify.encode(t) # this may be added back later # assert encoded == '{"count": -1, "rows": [{"count": 1, "rows": {"test1id": 1, "id": 1, "val": "fred"}},\ {"count": 1, "rows": {"test1id": 1, "id": 2, "val": "alice"}}]}', encoded def test_explicit_saobj(): s = create_session() t = s.query(Test3).get(1) encoded = jsonify.encode(t) assert encoded == '{"id": 1, "val": "bob", "customized": true}' TurboGears2-2.1.5/tests/test_stack/0000775000175000017500000000000011737460177020015 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/dispatch/0000775000175000017500000000000011737460177021614 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/dispatch/__init__.py0000664000175000017500000000000011675520537023711 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/dispatch/controllers/0000775000175000017500000000000011737460177024162 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/dispatch/controllers/__init__.py0000664000175000017500000000000011675520537026257 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/dispatch/controllers/root.py0000664000175000017500000001167011736737176025531 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- import tg, pylons from tg.controllers import TGController, CUSTOM_CONTENT_TYPE from tg.decorators import expose, validate, https, variable_decode from formencode import validators from tg import expose, redirect, config from tg.controllers import TGController from tg import dispatched_controller from nose.tools import eq_ class NestedSubController(TGController): @expose() def index(self): return '-'.join((self.mount_point, dispatched_controller().mount_point)) @expose() def hitme(self): return '*'.join((self.mount_point, dispatched_controller().mount_point)) @expose() def _lookup(self, *args): lookup = LookupController() return lookup, args class SubController(TGController): nested = NestedSubController() @expose() def foo(self,): return 'sub_foo' @expose() def index(self): return 'sub index' @expose() def _default(self, *args): return ("recieved the following args (from the url): %s" %list(args)) @expose() def redirect_me(self, target, **kw): tg.redirect(target, **kw) @expose() def redirect_sub(self): tg.redirect('index') @expose() def redirect_list(self): tg.redirect(["/sub2", "list"]) @expose() def hello(self, name): return "Why HELLO! " + name @expose() def hitme(self): return '@'.join((self.mount_point, dispatched_controller().mount_point)) class LookupController(TGController): nested = NestedSubController() @expose() def findme(self, *args, **kw): return 'got to lookup' @expose() def hiddenhitme(self, *args, **kw): return ' '.join((self.mount_point, dispatched_controller().mount_point)) class SubController2(object): @expose() def index(self): tg.redirect('list') @expose() def list(self, **kw): return "hello list" @expose() def lookup(self, *args): lookup = LookupController() return lookup, args class RootController(TGController): @expose() def index(self, **kwargs): return 'hello world' @expose() def _default(self, remainder): return "Main Default Page called for url /%s"%remainder @expose() def feed(self, feed=None): return feed sub = SubController() sub2 = SubController2() @expose() def redirect_me(self, target, **kw): tg.redirect(target, kw) @expose() def hello(self, name, silly=None): return "Hello " + name @expose() def redirect_cookie(self, name): pylons.response.set_cookie('name', name) tg.redirect('/hello_cookie') @expose() def hello_cookie(self): return "Hello " + pylons.request.cookies['name'] @expose() def flash_redirect(self): tg.flash("Wow, flash!") tg.redirect("/flash_after_redirect") @expose() def bigflash_redirect(self): tg.flash('x' * 5000) tg.redirect('/flash_after_redirect') @expose() def flash_unicode(self): tg.flash(u"Привет, мир!") tg.redirect("/flash_after_redirect") @expose() def flash_after_redirect(self): return tg.get_flash() @expose() def flash_status(self): return tg.get_status() @expose() def flash_no_redirect(self): tg.flash("Wow, flash!") return tg.get_flash() @expose('json') @validate(validators={"some_int": validators.Int()}) def validated_int(self, some_int): assert isinstance(some_int, int) return dict(response=some_int) @expose('json') @validate(validators={"a":validators.Int()}) def validated_and_unvalidated(self, a, b): assert isinstance(a, int) assert isinstance(b, unicode) return dict(int=a,str=b) @expose() @expose('json') def stacked_expose(self, tg_format=None): return dict(got_json=True) @expose('json') def json_return_list(self): return [1,2,3] @expose(content_type='image/png') def custom_content_type(self): return 'PNG' @expose(content_type='text/plain') def custom_content_text_plain_type(self): return 'a
bx' @expose(content_type=CUSTOM_CONTENT_TYPE) def custom_content_type2(self): pylons.response.headers['Content-Type'] = 'image/png' return 'PNG2' @expose() def check_params(self, *args, **kwargs): if not args and not kwargs: return "None recieved" else: return "Controler recieved: %s, %s" %(args, kwargs) @expose() def test_url_sop(self): from tg import url eq_('/foo', url('/foo')) u = url("/foo", bar=1, baz=2) assert u in \ ["/foo?bar=1&baz=2", "/foo?baz=2&bar=1"], u @https @expose() def test_https(self, **kw): return '' @expose('json') @variable_decode def test_vardec(self, **kw): return kw TurboGears2-2.1.5/tests/test_stack/dispatch/test_config.py0000664000175000017500000000254411675520537024475 0ustar marvinmarvin00000000000000import os from tests.test_stack import TestConfig from webtest import TestApp def setup_noDB(): global_config = {'debug': 'true', 'error_email_from': 'paste@localhost', 'smtp_server': 'localhost'} base_config = TestConfig(folder = 'config', values = {'use_sqlalchemy': False} ) env_loader = base_config.make_load_environment() app_maker = base_config.setup_tg_wsgi_app(env_loader) app = TestApp(app_maker(global_config, full_stack=True)) return app def test_basic_stack(): app = setup_noDB() resp = app.get('/') assert resp.body == "my foo" def test_config_reading(): """Ensure that the config object can be read via dict and attr access""" app = setup_noDB() resp = app.get('/config_test') assert "default_renderer" in resp.body resp = app.get('/config_attr_lookup') assert "genshi" in resp.body resp = app.get('/config_dotted_values') assert "environ_config" in resp.body def test_config_writing(): """Ensure that new values can be added to the config object""" app = setup_noDB() value = "gooberblue" resp = app.get('/config_attr_set/'+value) assert value in resp.body resp = app.get('/config_dict_set/'+value) assert value in resp.body TurboGears2-2.1.5/tests/test_stack/dispatch/test_url_dispatch.py0000664000175000017500000001410611733765036025706 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- from nose.tools import raises import os from tests.test_stack import TestConfig, app_from_config from webtest import TestApp from nose.tools import eq_ from tg.jsonify import JsonEncodeError from tg.util import no_warn def setup_noDB(): base_config = TestConfig(folder = 'dispatch', values = {'use_sqlalchemy': False, 'ignore_parameters': ["ignore", "ignore_me"] } ) return app_from_config(base_config) app = None def setup(): global app app = setup_noDB() @no_warn #should be _default now def test_tg_style_default(): resp = app.get('/sdfaswdfsdfa') #random string should be caught by the default route assert 'Default' in resp.body def test_url_encoded_param_passing(): resp = app.get('/feed?feed=http%3A%2F%2Fdeanlandolt.com%2Ffeed%2Fatom%2F') assert "http://deanlandolt.com/feed/atom/" in resp.body def test_tg_style_index(): resp = app.get('/index/') assert 'hello' in resp.body, resp def test_tg_style_subcontroller_index(): resp = app.get('/sub/index') assert "sub index" in resp.body def test_tg_style_subcontroller_default(): resp=app.get('/sub/bob/tim/joe') assert 'bob' in resp.body, resp assert 'tim' in resp.body, resp assert 'joe' in resp.body, resp def test_redirect_absolute(): resp = app.get('/redirect_me?target=/') assert resp.status == "302 Found", resp.status assert 'http://localhost/' in resp.headers['location'] resp = resp.follow() assert 'hello world' in resp, resp @no_warn def test_redirect_relative(): resp = app.get('/redirect_me?target=hello&name=abc') resp = resp.follow() assert 'Hello abc' in resp, resp resp = app.get('/sub/redirect_me?target=hello&name=def') resp = resp.follow() assert 'Why HELLO! def' in resp, resp resp = app.get('/sub/redirect_me?target=../hello&name=ghi') resp = resp.follow() assert 'Hello ghi' in resp, resp def test_redirect_external(): resp = app.get('/redirect_me?target=http://example.com') assert resp.status == "302 Found" and resp.headers['location'] == 'http://example.com', resp def test_redirect_param(): resp = app.get('/redirect_me?target=/hello&name=paj') resp = resp.follow() assert 'Hello paj' in resp, resp resp = app.get('/redirect_me?target=/hello&name=pbj') resp = resp.follow() assert 'Hello pbj' in resp, resp resp = app.get('/redirect_me?target=/hello&silly=billy&name=pcj') resp = resp.follow() assert 'Hello pcj' in resp, resp def test_redirect_cookie(): resp = app.get('/redirect_cookie?name=stefanha').follow() assert 'Hello stefanha' in resp def test_subcontroller_redirect_subindex(): resp=app.get('/sub/redirect_sub').follow() assert 'sub index' in resp def test_subcontroller_redirect_sub2index(): resp=app.get('/sub2/').follow() assert 'hello list' in resp #this test does not run because of some bug in nose def _test_subcontroller_lookup(): resp=app.get('/sub2/findme').follow() assert 'lookup' in resp, resp def test_subcontroller_redirect_no_slash_sub2index(): resp=app.get('/sub2/').follow() assert 'hello list' in resp, resp def test_redirect_to_list_of_strings(): resp = app.get('/sub/redirect_list').follow() assert 'hello list' in resp, resp def test_flash_redirect(): resp = app.get('/flash_redirect').follow() assert 'Wow, flash!' in resp, resp @raises(ValueError) def test_bigflash_redirect(): resp = app.get('/bigflash_redirect', status=500) def test_flash_no_redirect(): resp = app.get('/flash_no_redirect') assert 'Wow, flash!' in resp def test_flash_unicode(): resp = app.get('/flash_unicode').follow() content = resp.body.decode('utf8') assert u'Привет, мир!' in content, content def test_flash_status(): resp = app.get('/flash_status') assert 'ok' in resp, resp def test_custom_content_type(): resp = app.get('/custom_content_type') assert 'image/png' == dict(resp.headers)['Content-Type'], resp assert resp.body == 'PNG', resp def test_custom_text_plain_content_type(): resp = app.get('/custom_content_text_plain_type') assert 'text/plain; charset=utf-8' == dict(resp.headers)['Content-Type'], resp assert resp.body == """a
bx""", resp @no_warn def test_custom_content_type2(): resp = app.get('/custom_content_type2') assert 'image/png' == dict(resp.headers)['Content-Type'], resp assert resp.body == 'PNG2', resp @no_warn def test_basicurls(): resp = app.get("/test_url_sop") def test_ignore_parameters(): resp = app.get("/check_params?ignore='bar'&ignore_me='foo'") assert "None Received" @raises(JsonEncodeError) def test_json_return_list(): resp = app.get("/json_return_list") assert "None Received" def test_https_redirect(): resp = app.get("/test_https?foo=bar&baz=bat") assert 'https://' in resp, resp assert resp.location.endswith("/test_https?foo=bar&baz=bat") resp = app.post("/test_https?foo=bar&baz=bat", status=405) def test_variable_decode(): from formencode.variabledecode import variable_encode obj = dict( a=['1','2','3'], b=dict(c=[dict(d='1')])) params = variable_encode(dict(obj=obj), add_repetitions=False) resp = app.get('/test_vardec', params=params) assert resp.json['obj'] == obj, (resp.json['obj'], obj) class TestVisits(object): def test_visit_path_sub1(self): resp = app.get("/sub/hitme") assert str(resp).endswith('/sub@/sub') def test_visit_path_nested(self): resp = app.get("/sub/nested/hitme") assert str(resp).endswith('/sub/nested*/sub/nested') def test_visit_path_nested_index(self): resp = app.get("/sub/nested") assert str(resp).endswith('/sub/nested-/sub/nested') def test_runtime_visit_path_subcontroller(self): resp = app.get("/sub/nested/nested/hitme") assert str(resp).endswith('*/sub/nested') def test_runtime_visit_path(self): resp = app.get("/sub/nested/hiddenhitme") assert str(resp).endswith(' /sub/nested') TurboGears2-2.1.5/tests/test_stack/__init__.py0000664000175000017500000000433211733764570022130 0ustar marvinmarvin00000000000000import os from webtest import TestApp import tg import tests from tg.util import DottedFileNameFinder from tg.configuration import AppConfig class TestConfig(AppConfig): def __init__(self, folder, values=None): if values is None: values = {} AppConfig.__init__(self) #First we setup some base values that we know will work self.renderers = ['genshi', 'mako', 'chameleon_genshi', 'jinja','json', 'kajiki'] self.render_functions = tg.util.Bunch() self.package = tests.test_stack self.default_renderer = 'genshi' self.globals = self self.helpers = {} self.auth_backend = None self.auto_reload_templates = False self.use_legacy_renderer = False self.use_dotted_templatenames = False self.serve_static = False root = os.path.dirname(os.path.dirname(tests.__file__)) test_base_path = os.path.join(root,'tests', 'test_stack',) test_config_path = os.path.join(test_base_path, folder) self.paths=tg.util.Bunch( root=test_base_path, controllers=os.path.join(test_config_path, 'controllers'), static_files=os.path.join(test_config_path, 'public'), templates=[os.path.join(test_config_path, 'templates')], i18n=os.path.join(test_config_path, 'i18n') ) # then we override those values with what was passed in for key, value in values.items(): setattr(self, key, value) def setup_helpers_and_globals(self): tg.config['pylons.app_globals'] = self.globals tg.config['pylons.h'] = self.helpers g = tg.config['pylons.app_globals'] g.dotted_filename_finder = DottedFileNameFinder() def app_from_config(base_config, deployment_config=None): if not deployment_config: deployment_config = {'debug': 'true', 'error_email_from': 'paste@localhost', 'smtp_server': 'localhost'} env_loader = base_config.make_load_environment() app_maker = base_config.setup_tg_wsgi_app(env_loader) app = TestApp(app_maker(deployment_config, full_stack=True)) return app TurboGears2-2.1.5/tests/test_stack/rendering/0000775000175000017500000000000011737460177021772 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/rendering/templates/0000775000175000017500000000000011737460177023770 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/rendering/templates/__init__.py0000664000175000017500000000000011675520537026065 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/rendering/templates/mako_inherits.mak.py0000600000175000017500000000304611737222463027730 0ustar marvinmarvin00000000000000# -*- encoding:utf-8 -*- from mako import runtime, filters, cache UNDEFINED = runtime.UNDEFINED __M_dict_builtin = dict __M_locals_builtin = locals _magic_number = 8 _modified_time = 1333601587.241808 _enable_loop = True _template_filename = '/home/marvin/src/tg2/tests/test_stack/rendering/templates/mako_inherits.mak' _template_uri = 'mako_inherits.mak' _source_encoding = 'utf-8' from webhelpers.html import escape _exports = ['head_tags'] def _mako_get_namespace(context, name): try: return context.namespaces[(__name__, name)] except KeyError: _mako_generate_namespaces(context) return context.namespaces[(__name__, name)] def _mako_generate_namespaces(context): pass def _mako_inherit(template, context): _mako_generate_namespaces(context) return runtime._inherit_from(context, u'/mako_base.mak', _template_uri) def render_body(context,**pageargs): __M_caller = context.caller_stack._push_frame() try: __M_locals = __M_dict_builtin(pageargs=pageargs) __M_writer = context.writer() # SOURCE LINE 2 __M_writer(u'\n\n') # SOURCE LINE 6 __M_writer(u'\n\n

New Page

\n\n

inherited mako page

') return '' finally: context.caller_stack._pop_frame() def render_head_tags(context): __M_caller = context.caller_stack._push_frame() try: __M_writer = context.writer() # SOURCE LINE 4 __M_writer(u'\n \n') return '' finally: context.caller_stack._pop_frame() TurboGears2-2.1.5/tests/test_stack/rendering/templates/mako_base.mak.py0000600000175000017500000000226311737222463027015 0ustar marvinmarvin00000000000000# -*- encoding:utf-8 -*- from mako import runtime, filters, cache UNDEFINED = runtime.UNDEFINED __M_dict_builtin = dict __M_locals_builtin = locals _magic_number = 8 _modified_time = 1333601587.243811 _enable_loop = True _template_filename = u'/home/marvin/src/tg2/tests/test_stack/rendering/templates/mako_base.mak' _template_uri = u'/mako_base.mak' _source_encoding = 'utf-8' from webhelpers.html import escape _exports = [] def render_body(context,**pageargs): __M_caller = context.caller_stack._push_frame() try: __M_locals = __M_dict_builtin(pageargs=pageargs) self = context.get('self', UNDEFINED) __M_writer = context.writer() # SOURCE LINE 2 __M_writer(u'\n\n \n ') # SOURCE LINE 6 __M_writer(escape(self.head_tags())) __M_writer(u'\n \n \n \t

Inside parent template

\n ') # SOURCE LINE 10 __M_writer(escape(self.body())) __M_writer(u'\n \n\n') return '' finally: context.caller_stack._pop_frame() TurboGears2-2.1.5/tests/test_stack/rendering/templates/mako_custom_format.mak.py0000600000175000017500000000213611737222463030764 0ustar marvinmarvin00000000000000# -*- encoding:utf-8 -*- from mako import runtime, filters, cache UNDEFINED = runtime.UNDEFINED __M_dict_builtin = dict __M_locals_builtin = locals _magic_number = 8 _modified_time = 1333601587.298501 _enable_loop = True _template_filename = '/home/marvin/src/tg2/tests/test_stack/rendering/templates/mako_custom_format.mak' _template_uri = 'mako_custom_format.mak' _source_encoding = 'utf-8' from webhelpers.html import escape _exports = [] def render_body(context,**pageargs): __M_caller = context.caller_stack._push_frame() try: __M_locals = __M_dict_builtin(pageargs=pageargs) status = context.get('status', UNDEFINED) format = context.get('format', UNDEFINED) __M_writer = context.writer() # SOURCE LINE 1 __M_writer(u'\n\n ') # SOURCE LINE 3 __M_writer(escape(status)) __M_writer(u'\n ') # SOURCE LINE 4 __M_writer(escape(format)) __M_writer(u'\n') return '' finally: context.caller_stack._pop_frame() TurboGears2-2.1.5/tests/test_stack/rendering/templates/mako_noop.mak.py0000600000175000017500000000141211737222463027051 0ustar marvinmarvin00000000000000# -*- encoding:utf-8 -*- from mako import runtime, filters, cache UNDEFINED = runtime.UNDEFINED __M_dict_builtin = dict __M_locals_builtin = locals _magic_number = 8 _modified_time = 1333601587.232914 _enable_loop = True _template_filename = '/home/marvin/src/tg2/tests/test_stack/rendering/templates/mako_noop.mak' _template_uri = 'mako_noop.mak' _source_encoding = 'utf-8' from webhelpers.html import escape _exports = [] def render_body(context,**pageargs): __M_caller = context.caller_stack._push_frame() try: __M_locals = __M_dict_builtin(pageargs=pageargs) __M_writer = context.writer() # SOURCE LINE 2 __M_writer(u'\n

This is the mako index page

') return '' finally: context.caller_stack._pop_frame() TurboGears2-2.1.5/tests/test_stack/rendering/templates/sub/0000775000175000017500000000000011737460177024561 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/rendering/templates/sub/__init__.py0000664000175000017500000000000011675520537026656 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/rendering/__init__.py0000664000175000017500000000000011675520537024067 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/rendering/test_pagination.py0000664000175000017500000000621411733765570025540 0ustar marvinmarvin00000000000000from tests.test_stack import TestConfig, app_from_config def setup_noDB(): base_config = TestConfig(folder='rendering', values={ 'use_sqlalchemy': False }) return app_from_config(base_config) _pager = ('
1' ' 2' ' 3' ' ..' ' 5
') _data = '
    %s
' % ''.join( '
  • %d
  • ' % i for i in range(10)) class TestPagination: def setup(self): self.app = setup_noDB() def test_basic_pagination(self): url = '/paginated/42' page = self.app.get(url) assert _pager % locals() in page, page assert _data in page, page url = '/paginated/42?page=2' page = self.app.get(url) assert '
  • 0
  • ' not in page assert '
  • 10
  • ' in page def test_pagination_with_validation(self): url = '/paginated_validated/42' page = self.app.get(url) assert _pager % locals() in page, page assert _data in page, page url = '/paginated_validated/42?page=2' page = self.app.get(url) assert '
  • 0
  • ' not in page assert '
  • 10
  • ' in page def test_validation_with_pagination(self): url = '/validated_paginated/42' page = self.app.get(url) assert _pager % locals() in page, page assert _data in page, page url = '/validated_paginated/42?page=2' page = self.app.get(url) assert '
  • 0
  • ' not in page assert '
  • 10
  • ' in page def test_pagination_with_link_args(self): url = '/paginate_with_params/42' page = self.app.get(url) assert 'param1=hi' in page assert 'param2=man' in page assert 'partial' not in page assert '/fake_url' in page url = '/paginate_with_params/42?page=2' page = self.app.get(url) assert '
  • 0
  • ' not in page assert '
  • 10
  • ' in page def test_multiple_paginators(self): url = '/multiple_paginators/42' page = self.app.get(url) assert '/multiple_paginators/42?testdata2_page=2' in page assert '/multiple_paginators/42?testdata_page=2' in page url = '/multiple_paginators/42?testdata_page=2' page = self.app.get(url) assert '/multiple_paginators/42?testdata2_page=2&testdata_page=2' in page assert '/multiple_paginators/42?testdata_page=4' in page assert '
  • 0
  • ' not in page assert '
  • 10
  • ' in page assert '
  • 142
  • ' in page assert '
  • 151
  • ' in page url = '/multiple_paginators/42?testdata2_page=2' page = self.app.get(url) assert '/multiple_paginators/42?testdata2_page=2&testdata_page=2' in page, str(page) assert '/multiple_paginators/42?testdata2_page=4' in page assert '
  • 0
  • ' in page assert '
  • 9
  • ' in page assert '
  • 151
  • ' not in page assert '
  • 161
  • ' in pageTurboGears2-2.1.5/tests/test_stack/rendering/test_decorators.py0000664000175000017500000000335311675520537025552 0ustar marvinmarvin00000000000000from tests.test_stack import TestConfig, app_from_config from tg.util import Bunch from webtest import TestApp from pylons import tmpl_context from tg.util import no_warn def make_app(): base_config = TestConfig(folder = 'rendering', values = {'use_sqlalchemy': False, 'pylons.helpers': Bunch(), 'use_legacy_renderer': False, # this is specific to mako # to make sure inheritance works 'use_dotted_templatenames': False, 'pylons.tmpl_context_attach_args': False } ) return app_from_config(base_config) app = None def setup(): global app app = make_app() class TestTGController(object): def setup(self): self.app = app def test_simple_jsonification(self): resp = self.app.get('/j/json') assert '{"a": "hello world", "b": true}' in resp.body def test_multi_dispatch_json(self): resp = self.app.get('/j/xml_or_json', headers={'accept':'application/json'}) assert '''"status": "missing"''' in resp assert '''"name": "John Carter"''' in resp assert '''"title": "officer"''' in resp def test_json_with_object(self): resp = self.app.get('/j/json_with_object') assert '''"Json": "Rocks"''' in resp.body @no_warn def test_json_with_bad_object(self): try: resp = self.app.get('/j/json_with_bad_object') except TypeError, e: pass assert "is not JSON serializable" in str(e), str(e) TurboGears2-2.1.5/tests/test_stack/rendering/test_dotted_rendering.py0000664000175000017500000000536111733765570026731 0ustar marvinmarvin00000000000000from tests.test_stack import TestConfig, app_from_config from tg.util import Bunch, no_warn from webtest import TestApp from pylons import tmpl_context def setup_noDB(): base_config = TestConfig(folder = 'rendering', values = {'use_sqlalchemy': False, 'pylons.helpers': Bunch(), # we want to test the new renderer functions 'use_legacy_renderer': False, # in this test we want dotted names support 'use_dotted_templatenames': True, } ) return app_from_config(base_config) def test_default_chameleon_genshi_renderer(): app = setup_noDB() resp = app.get('/chameleon_index_dotted') assert "Welcome" in resp, resp assert "TurboGears" in resp, resp def test_default_kajiki_renderer(): app = setup_noDB() resp = app.get('/kajiki_index_dotted') assert "Welcome" in resp, resp assert "TurboGears" in resp, resp def test_jinja_dotted(): app = setup_noDB() resp = app.get('/jinja_dotted') assert "move along, nothing to see here" in resp, resp def test_jinja_inherits_dotted(): app = setup_noDB() resp = app.get('/jinja_inherits_dotted') assert "Welcome on my awsome homepage" in resp, resp def test_jinja_inherits_mixed(): # Mixed notation, dotted and regular app = setup_noDB() resp = app.get('/jinja_inherits_mixed') assert "Welcome on my awsome homepage" in resp, resp def test_default_genshi_renderer(): app = setup_noDB() resp = app.get('/index_dotted') assert "Welcome" in resp, resp assert "TurboGears" in resp, resp def test_genshi_inheritance(): app = setup_noDB() resp = app.get('/genshi_inherits_dotted') assert "Inheritance template" in resp, resp assert "Master template" in resp, resp def test_genshi_sub_inheritance(): app = setup_noDB() resp = app.get('/genshi_inherits_sub_dotted') assert "Inheritance template" in resp, resp assert "Master template" in resp, resp assert "from sub-template: sub.tobeincluded" in resp, resp def test_genshi_sub_inheritance_frombottom(): app = setup_noDB() resp = app.get('/genshi_inherits_sub_dotted_from_bottom') assert "Master template" in resp, resp assert "from sub-template: sub.frombottom_dotted" in resp, resp def test_mako_renderer(): app = setup_noDB() resp = app.get('/mako_index_dotted') assert "

    This is the mako index page

    " in resp, resp def test_mako_inheritance(): app = setup_noDB() resp = app.get('/mako_inherits_dotted') assert "inherited mako page" in resp, resp assert "Inside parent template" in resp, resp TurboGears2-2.1.5/tests/test_stack/rendering/test_toscawidgets.py0000664000175000017500000000212311733764570026101 0ustar marvinmarvin00000000000000from tests.test_stack import TestConfig, app_from_config from tg.util import Bunch from webtest import TestApp from pylons import tmpl_context def setup_noDB(): base_config = TestConfig(folder = 'rendering', values = {'use_sqlalchemy': False, 'pylons.helpers': Bunch(), # we want to test the new renderer functions 'use_legacy_renderer': False, # in this test we want dotted names support 'use_dotted_templatenames': False, 'templating.genshi.method':'xhtml' } ) return app_from_config(base_config) expected_field = """\ """ def test_basic_form_rendering(): app = setup_noDB() resp = app.get('/form') assert "form" in resp assert expected_field in resp, resp TurboGears2-2.1.5/tests/test_stack/rendering/controllers/0000775000175000017500000000000011737460177024340 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/rendering/controllers/__init__.py0000664000175000017500000000000011675520537026435 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/rendering/controllers/root.py0000664000175000017500000002112411736737176025702 0ustar marvinmarvin00000000000000"""Main Controller""" from tg import expose, redirect, config, validate, override_template, response from tg.decorators import paginate, use_custom_format, with_trailing_slash from tg.render import render from tg.controllers import TGController from tw.forms import TableForm, TextField, CalendarDatePicker, SingleSelectField, TextArea from tw.api import WidgetsList from formencode import validators class MovieForm(TableForm): # This WidgetsList is just a container class fields(WidgetsList): title = TextField() year = TextField(size=4, default=1984) description = TextArea() #then, we create an instance of this form base_movie_form = MovieForm("movie_form", action='create') class GoodJsonObject(object): def __json__(self): return {'Json':'Rocks'} class BadJsonObject(object): pass class JsonController(TGController): @expose('json') def json(self): return dict(a='hello world', b=True) @expose('json', exclude_names=["b"]) def excluded_b(self): return dict(a="visible", b="invisible") @expose('json') @expose('genshi:test', content_type='application/xml') def xml_or_json(self): return dict(name="John Carter", title='officer', status='missing') @expose('json') def json_with_object(self): return dict(obj=GoodJsonObject()) @expose('json') def json_with_bad_object(self): return dict(obj=BadJsonObject()) class RootController(TGController): j = JsonController() @expose('genshi:index.html') def index(self): return {} @expose('genshi:genshi_doctype.html') def auto_doctype(self): return {} @expose('genshi:genshi_doctype.html', content_type='text/html') def auto_doctype_html(self): return {} @expose('genshi:genshi_doctype.html', content_type='application/xhtml+xml') def auto_doctype_xhtml(self): return {} @expose('genshi:genshi_doctype.html', render_params=dict(doctype=None)) def explicit_no_doctype(self): return {} @expose('genshi:genshi_doctype.html', render_params=dict(doctype='html')) def explicit_doctype_html(self): return {} @expose('genshi:genshi_doctype.html', render_params=dict(doctype='xhtml')) def explicit_doctype_xhtml(self): return {} @expose('genshi:genshi_form.html') def form(self): return dict(form=base_movie_form) @expose('genshi:genshi_foreign.html') def foreign(self): return {} @expose('json') @validate(form=base_movie_form) def process_form_errors(self, **kwargs): #add error messages to the kwargs dictionary and return it kwargs['errors'] = pylons.tmpl_context.form_errors return dict(kwargs) @expose('genshi:genshi_paginated.html') @paginate('testdata') def paginated(self, n): return dict(testdata=range(int(n))) @expose('genshi:genshi_paginated.html') @paginate('testdata') def paginate_with_params(self, n): url_params = dict(param1='hi', param2='man') return dict(testdata=range(int(n)), url_params=url_params) @expose('genshi:genshi_paginated.html') @paginate('testdata') @validate(dict(n=validators.Int())) def paginated_validated(self, n): return dict(testdata=range(n)) @expose('genshi:genshi_paginated.html') @validate(dict(n=validators.Int())) @paginate('testdata') def validated_paginated(self, n): return dict(testdata=range(n)) @expose('genshi:genshi_paginated.html') @paginate('testdata', use_prefix=True) @paginate('testdata2', use_prefix=True) def multiple_paginators(self, n): n = int(n) return dict(testdata=range(n), testdata2=range(n+100, n+100+n)) @expose('genshi:genshi_inherits.html') def genshi_inherits(self): return {} @expose('genshi:genshi_inherits_sub.html') def genshi_inherits_sub(self): return {} @expose('genshi:sub/frombottom.html') def genshi_inherits_sub_from_bottom(self): return {} @expose('jinja:jinja_noop.html') def jinja_index(self): return {} @expose('jinja:jinja_inherits.html') def jinja_inherits(self): return {} @expose('jinja:tests.test_stack.rendering.templates.jinja_noop') def jinja_dotted(self): return {} @expose('jinja:tests.test_stack.rendering.templates.jinja_inherits_dotted') def jinja_inherits_dotted(self): return {} @expose('jinja:tests.test_stack.rendering.templates.jinja_inherits') def jinja_inherits_mixed(self): return {} @expose('jinja:jinja_extensions.html') def jinja_extensions(self): test_autoescape_on = "Test Autoescape On" test_autoescape_off = "Autoescape Off" return dict(test_autoescape_off=test_autoescape_off, test_autoescape_on=test_autoescape_on) @expose('jinja:jinja_filters.html') def jinja_filters(self): return {} @expose('jinja:jinja_buildins.html') def jinja_buildins(self): return {} @expose('chameleon_genshi:index.html') def chameleon_genshi_index(self): return {} @expose('chameleon_genshi:genshi_inherits.html') def chameleon_genshi_inherits(self): return {} @expose('mako:mako_noop.mak') def mako_index(self): return {} @expose('mako:mako_inherits.mak') def mako_inherits(self): return {} @expose('chameleon_genshi:tests.test_stack.rendering.templates.index') def chameleon_index_dotted(self): return {} @expose('kajiki:tests.test_stack.rendering.templates.index') def kajiki_index_dotted(self): return {} @expose('genshi:tests.test_stack.rendering.templates.index') def index_dotted(self): return {} @expose('genshi:tests.test_stack.rendering.templates.genshi_inherits') def genshi_inherits_dotted(self): return {} @expose('genshi:tests.test_stack.rendering.templates.genshi_inherits_sub_dotted') def genshi_inherits_sub_dotted(self): return {} @expose('genshi:tests.test_stack.rendering.templates.sub.frombottom_dotted') def genshi_inherits_sub_dotted_from_bottom(self): return {} @expose('mako:tests.test_stack.rendering.templates.mako_noop') def mako_index_dotted(self): return {} @expose('mako:tests.test_stack.rendering.templates.mako_inherits_dotted') def mako_inherits_dotted(self): return {} @expose('json') @expose('genshi:index.html') def html_and_json(self): return {} @expose('json', custom_format='json') @expose('mako:mako_custom_format.mak', content_type='text/xml', custom_format='xml') @expose('genshi:genshi_custom_format.html', content_type='text/html', custom_format='html') def custom_format(self, format='default'): if format != 'default': use_custom_format(self.custom_format, format) return dict(format=format, status="ok") else: return 'OK' @expose("genshi:tests.non_overridden") def template_override(self, override=False): if override: override_template(self.template_override, "genshi:tests.overridden") return dict() @with_trailing_slash @expose("genshi:tests.non_overridden") def template_override_wts(self, override=False): if override: override_template(self.template_override_wts, "genshi:tests.overridden") return dict() @expose(content_type='text/javascript') def template_override_content_type(self, override=False): if override: override_template(self.template_override_content_type, "mako:tests.overridden_js") return dict() else: return "alert('Not overridden')" @expose('mako:mako_custom_format.mak', content_type='text/xml') @expose('genshi:genshi_custom_format.html', content_type='text/html') def template_override_multiple_content_type(self, override=False): if override: override_template(self.template_override_multiple_content_type, "mako:mako_noop.mak") return dict(format='something', status="ok") @expose() def jinja2_manual_rendering(self, frompylons=False): if frompylons: from pylons.templating import render_jinja2 return render_jinja2('jinja_inherits.html') else: return render({}, 'jinja', 'jinja_inherits.html') @expose() def genshi_manual_rendering_with_doctype(self, doctype=None): response.content_type = 'text/html' response.charset = 'utf-8' return render({}, 'genshi', 'genshi_doctype.html', doctype=doctype) TurboGears2-2.1.5/tests/test_stack/rendering/test_rendering.py0000664000175000017500000004755411733765570025400 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- import tg from tests.test_stack import TestConfig, app_from_config from tg.util import Bunch from webtest import TestApp from pylons import tmpl_context def setup_noDB(genshi_doctype=None, genshi_method=None, genshi_encoding=None): base_config = TestConfig(folder='rendering', values={ 'use_sqlalchemy': False, 'pylons.helpers': Bunch(), 'use_legacy_renderer': False, # this is specific to mako to make sure inheritance works 'use_dotted_templatenames': False, 'pylons.tmpl_context_attach_args': False }) deployment_config = {} # remove previous option value to avoid using the old one tg.config.pop('templating.genshi.doctype', None) if genshi_doctype: deployment_config['templating.genshi.doctype'] = genshi_doctype tg.config.pop('templating.genshi.method', None) if genshi_method: deployment_config['templating.genshi.method'] = genshi_method tg.config.pop('templating.genshi.encoding', None) if genshi_encoding: deployment_config['templating.genshi.encoding'] = genshi_encoding return app_from_config(base_config, deployment_config) def test_default_genshi_renderer(): app = setup_noDB() resp = app.get('/') assert ('') in resp assert "Welcome" in resp assert "TurboGears" in resp def test_genshi_doctype_html5(): app = setup_noDB(genshi_doctype='html5') resp = app.get('/') assert '' in resp assert "Welcome" in resp assert "TurboGears" in resp def test_genshi_auto_doctype(): app = setup_noDB() resp = app.get('/auto_doctype') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_method_html(): app = setup_noDB(genshi_method='html') resp = app.get('/auto_doctype') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_method_xhtml(): app = setup_noDB(genshi_method='xhtml') resp = app.get('/auto_doctype') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_doctype_html(): app = setup_noDB(genshi_doctype='html') resp = app.get('/auto_doctype') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_doctype_html5(): app = setup_noDB(genshi_doctype='html5') resp = app.get('/auto_doctype') assert '' in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_doctype_xhtml_strict(): app = setup_noDB(genshi_doctype='xhtml-strict') resp = app.get('/auto_doctype') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_doctype_html_maps_to_xhtml(): app = setup_noDB(genshi_doctype={'text/html': ('xhtml', 'html')}) resp = app.get('/auto_doctype_html') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_method_html_maps_to_xhtml(): app = setup_noDB(genshi_method={'text/html': ('xhtml', 'html')}) resp = app.get('/auto_doctype_html') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_method_xml_overridden_by_content_type_html(): app = setup_noDB(genshi_method='xml') resp = app.get('/auto_doctype_html') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_method_xhtml_is_ok_with_content_type_html(): app = setup_noDB(genshi_method='xhtml') resp = app.get('/auto_doctype_html') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_doctype_xhtml_maps_to_html(): app = setup_noDB( genshi_doctype={'application/xhtml+xml': ('html', 'xhtml')}) resp = app.get('/auto_doctype_xhtml') assert ('') in resp assert 'content="application/xhtml+xml; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_method_xhtml_maps_to_html(): app = setup_noDB( genshi_doctype={'application/xhtml+xml': ('html', 'xhtml')}, genshi_method={'application/xhtml+xml': ('html', 'xhtml')}) resp = app.get('/auto_doctype_xhtml') assert ('') in resp assert 'content="application/xhtml+xml; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_method_xml_overridden_by_content_type_xhtml(): app = setup_noDB(genshi_method='xml') resp = app.get('/auto_doctype_xhtml') assert ('') in resp assert 'content="application/xhtml+xml; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_method_html_overridden_by_content_type_xhtml(): app = setup_noDB(genshi_method='html') resp = app.get('/auto_doctype_xhtml') assert ('') in resp assert 'content="application/xhtml+xml; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_explicit_no_doctype(): app = setup_noDB() resp = app.get('/explicit_no_doctype') assert 'DOCTYPE' not in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_explicit_doctype_html(): app = setup_noDB(genshi_doctype='xhtml') resp = app.get('/explicit_doctype_html') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_explicit_doctype_xhtml(): app = setup_noDB(genshi_doctype='html') resp = app.get('/explicit_doctype_xhtml') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "doctype generation" in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_html_priority_for_ie(): app = setup_noDB() resp = app.get('/html_and_json', headers={'Accept': 'application/x-ms-application, image/jpeg, application/xaml+xml,' ' image/gif, image/pjpeg, application/x-ms-xbap, */*'}) assert 'text/html' in str(resp), resp def test_genshi_foreign_characters(): app = setup_noDB() resp = app.get('/foreign') assert "Foreign Cuisine" in resp assert "Crème brûlée with Käsebrötchen" in resp def test_genshi_inheritance(): app = setup_noDB() resp = app.get('/genshi_inherits') assert "Inheritance template" in resp assert "Master template" in resp def test_genshi_sub_inheritance(): app = setup_noDB() resp = app.get('/genshi_inherits_sub') assert "Inheritance template" in resp assert "Master template" in resp assert "from sub-template: sub.tobeincluded" in resp def test_genshi_sub_inheritance_from_bottom(): app = setup_noDB() resp = app.get('/genshi_inherits_sub_from_bottom') assert "from sub-template: sub.frombottom" in resp assert "Master template" in resp def test_chameleon_genshi_base(): app = setup_noDB() resp = app.get('/chameleon_genshi_index') assert ("

    TurboGears 2 is rapid web application development toolkit" " designed to make your life easier.

    ") in resp def test_chameleon_genshi_inheritance(): try: import lxml except ImportError: # match templates need lxml, but since they don're really work anyway # (at least not fully compatible with Genshi), we just skip this test return app = setup_noDB() try: resp = app.get('/chameleon_genshi_inherits') except NameError, e: # known issue with chameleon.genshi 1.0 if 'match_templates' not in str(e): raise except AttributeError, e: # known issue with chameleon.genshi 1.3 if 'XPathResult' not in str(e): raise else: assert "Inheritance template" in resp assert "Master template" in resp def _test_jinja_inherits(): app = setup_noDB() resp = app.get('/jinja_inherits') assert "Welcome on my awsome homepage" in resp, resp def test_jinja_extensions(): base_config = TestConfig(folder = 'rendering', values = {'use_sqlalchemy': False, 'pylons.helpers': Bunch(), 'use_legacy_renderer': False, # this is specific to mako # to make sure inheritance works 'use_dotted_templatenames': False, 'pylons.tmpl_context_attach_args': False, 'renderers':['jinja'], 'jinja_extensions': ['jinja2.ext.do', 'jinja2.ext.i18n', 'jinja2.ext.with_', 'jinja2.ext.autoescape'] } ) app = app_from_config(base_config) resp = app.get('/jinja_extensions') assert "Autoescape Off" in resp, resp assert "<b>Test Autoescape On</b>" in resp, resp def test_jinja_buildin_filters(): app = setup_noDB() resp = app.get('/jinja_buildins') assert 'HELLO JINJA!' in resp, resp def test_jinja_custom_filters(): # Simple test filter to get a md5 hash of a string def codify(value): try: from hashlib import md5 except ImportError: from md5 import md5 string_hash = md5(value) return string_hash.hexdigest() base_config = TestConfig(folder = 'rendering', values = {'use_sqlalchemy': False, 'pylons.helpers': Bunch(), 'use_legacy_renderer': False, # this is specific to mako # to make sure inheritance works 'use_dotted_templatenames': False, 'pylons.tmpl_context_attach_args': False, 'renderers':['jinja'], 'jinja_filters': {'codify': codify} } ) app = app_from_config(base_config) resp = app.get('/jinja_filters') assert '8bb23e0b574ecb147536efacc864891b' in resp, resp def test_jinja_autoload_filters(): app = setup_noDB() resp = app.get('/jinja_filters') assert '29464d5ffe8f8dba1782fffcd6ed9fca6ceb4742' in resp, resp def test_mako_renderer(): app = setup_noDB() resp = app.get('/mako_index') assert "

    This is the mako index page

    " in resp, resp def test_mako_inheritance(): app = setup_noDB() resp = app.get('/mako_inherits') assert "inherited mako page" in resp, resp assert "Inside parent template" in resp, resp def test_template_override(): # app = setup_noDB() base_config = TestConfig(folder = 'rendering', values = {'use_sqlalchemy': False, 'pylons.helpers': Bunch(), 'use_legacy_renderer': False, # this is specific to mako # to make sure inheritance works 'use_dotted_templatenames': True, 'pylons.tmpl_context_attach_args': False, 'renderers':['genshi'] } ) app = app_from_config(base_config) r =app.get('/template_override') assert "Not overridden" in r, r r = app.get('/template_override', params=dict(override=True)) assert "This is overridden." in r, r # now invoke the controller again without override, # it should yield the old result r = app.get('/template_override') assert "Not overridden" in r, r def test_template_override_wts(): # app = setup_noDB() base_config = TestConfig(folder = 'rendering', values = {'use_sqlalchemy': False, 'pylons.helpers': Bunch(), 'use_legacy_renderer': False, # this is specific to mako # to make sure inheritance works 'use_dotted_templatenames': True, 'pylons.tmpl_context_attach_args': False, 'renderers':['genshi'] } ) app = app_from_config(base_config) r = app.get('/template_override_wts', status=302) # ensure with_trailing_slash r =app.get('/template_override_wts/') assert "Not overridden" in r, r r = app.get('/template_override_wts/', params=dict(override=True)) assert "This is overridden." in r, r # now invoke the controller again without override, # it should yield the old result r = app.get('/template_override_wts/') assert "Not overridden" in r, r def test_template_override_content_type(): base_config = TestConfig(folder = 'rendering', values = {'use_sqlalchemy': False, 'pylons.helpers': Bunch(), 'use_legacy_renderer': False, # this is specific to mako # to make sure inheritance works 'use_dotted_templatenames': True, 'pylons.tmpl_context_attach_args': False, 'renderers':['mako', 'genshi'] } ) app = app_from_config(base_config) r =app.get('/template_override_content_type') assert r.content_type == 'text/javascript' assert "Not overridden" in r, r r = app.get('/template_override_content_type', params=dict(override=True)) assert r.content_type == 'text/javascript' assert "This is overridden." in r, r # now invoke the controller again without override, # it should yield the old result r = app.get('/template_override_content_type') assert "Not overridden" in r, r def test_template_custom_format_default(): app = setup_noDB() resp = app.get('/custom_format') assert 'OK' in resp assert resp.content_type == 'text/html' def test_template_custom_format_xml(): app = setup_noDB() resp = app.get('/custom_format?format=xml') assert 'xml' in resp assert resp.content_type == 'text/xml' def test_template_custom_format_json(): app = setup_noDB() resp = app.get('/custom_format?format=json') assert 'json' in resp assert resp.content_type == 'application/json' def test_template_custom_format_html(): app = setup_noDB() resp = app.get('/custom_format?format=html') assert 'html' in resp assert resp.content_type == 'text/html' def test_template_override_multiple_content_type(): app = setup_noDB() resp = app.get('/template_override_multiple_content_type') assert 'something' in resp resp = app.get( '/template_override_multiple_content_type', params=dict(override=True)) assert 'This is the mako index page' in resp def test_jinja2_manual_rendering(): app = setup_noDB() tgresp = app.get('/jinja2_manual_rendering') pyresp = app.get('/jinja2_manual_rendering?frompylons=1') assert str(tgresp) == str(pyresp) def test_genshi_manual_render_no_doctype(): app = setup_noDB() resp = app.get('/genshi_manual_rendering_with_doctype') assert 'DOCTYPE' not in resp, resp assert "
    " in resp assert 'content="text/html; charset=utf-8"' in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_manual_render_auto_doctype(): app = setup_noDB() resp = app.get('/genshi_manual_rendering_with_doctype?doctype=auto') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp def test_genshi_manual_render_html_doctype(): app = setup_noDB() resp = app.get('/genshi_manual_rendering_with_doctype?doctype=html') assert ('') in resp assert 'content="text/html; charset=utf-8"' in resp assert "
    " in resp assert "

    Rendered with Genshi.

    " in resp TurboGears2-2.1.5/tests/test_stack/config/0000775000175000017500000000000011737460177021262 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/config/__init__.py0000664000175000017500000000000011675520537023357 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/config/controllers/0000775000175000017500000000000011737460177023630 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/config/controllers/__init__.py0000664000175000017500000000000011675520537025725 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/config/controllers/root.py0000664000175000017500000000145211675520537025165 0ustar marvinmarvin00000000000000"""Main Controller""" from tg import expose, redirect, config from tg.controllers import TGController class RootController(TGController): @expose() def index(self): return "my foo" @expose() def config_test(self): return str(config) @expose() def config_attr_lookup(self): return str(config.render_functions) @expose() def config_dotted_values(self): return str(config.pylons) @expose() def config_attr_set(self, foo): config.test_value = foo return str(config.test_value) @expose() def config_set_method(self): return str(config.get('pylons')) @expose() def config_dict_set(self, foo): config['test_value'] = foo return str(config.test_value) TurboGears2-2.1.5/tests/test_stack/config/test_config.py0000664000175000017500000000224111675520537024135 0ustar marvinmarvin00000000000000import os from tests.test_stack import TestConfig, app_from_config from webtest import TestApp def setup_noDB(): base_config = TestConfig(folder = 'config', values = {'use_sqlalchemy': False, 'pylons.tmpl_context_attach_args': False } ) return app_from_config(base_config) def test_basic_stack(): app = setup_noDB() resp = app.get('/') assert resp.body == "my foo" def test_config_reading(): """Ensure that the config object can be read via dict and attr access""" app = setup_noDB() resp = app.get('/config_test') assert "default_renderer" in resp.body resp = app.get('/config_attr_lookup') assert "genshi" in resp.body resp = app.get('/config_dotted_values') assert "environ_config" in resp.body def test_config_writing(): """Ensure that new values can be added to the config object""" app = setup_noDB() value = "gooberblue" resp = app.get('/config_attr_set/'+value) assert value in resp.body resp = app.get('/config_dict_set/'+value) assert value in resp.body TurboGears2-2.1.5/tests/test_stack/lib/0000775000175000017500000000000011737460177020563 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/lib/__init__.py0000664000175000017500000000037311675520537022675 0ustar marvinmarvin00000000000000"""Pylons requires that packages have a lib.base and lib.helpers So we've added on here so we can run tests in the context of the tg package itself, pylons will likely remove this restriction before 1.0 and this package can then be removed. """TurboGears2-2.1.5/tests/test_stack/lib/base.py0000664000175000017500000000037211675520537022047 0ustar marvinmarvin00000000000000"""Pylons requires that packages have a lib.base and lib.helpers So we've added on here so we can run tests in the context of the tg package itself, pylons will likely remove this restriction before 1.0 and this module can then be removed. """TurboGears2-2.1.5/tests/test_stack/lib/helpers.py0000664000175000017500000000037211675520537022577 0ustar marvinmarvin00000000000000"""Pylons requires that packages have a lib.base and lib.helpers So we've added on here so we can run tests in the context of the tg package itself, pylons will likely remove this restriction before 1.0 and this module can then be removed. """TurboGears2-2.1.5/tests/test_stack/lib/templatetools/0000775000175000017500000000000011737460177023457 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/lib/templatetools/__init__.py0000664000175000017500000000003311733765036025562 0ustar marvinmarvin00000000000000__author__ = 'clsdaniel' TurboGears2-2.1.5/tests/test_stack/lib/templatetools/jinja_filters.py0000664000175000017500000000033711733765036026655 0ustar marvinmarvin00000000000000try: from hashlib import sha1 except ImportError: from sha1 import sha1 # avoid polluting module namespace __all__ = ['codify'] def codify(value): string_hash = sha1(value) return string_hash.hexdigest() TurboGears2-2.1.5/tests/test_stack/test_authz.py0000664000175000017500000004311711675520537022565 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- """ repoze.what & repoze.what-pylons **integration** tests. Note that it is not necessary to have integration tests for the other auth* software in this package. They must be in tg.devtools, specifically in the test suite of the quickstarted applications (and there's where they are, as of this writing). """ from unittest import TestCase from shutil import rmtree from urllib import unquote import os from paste import httpexceptions from paste.registry import RegistryManager from webob import Response, Request from webtest import TestApp from beaker.middleware import CacheMiddleware, SessionMiddleware from tg import request, response, expose, require, allow_only from tg.controllers import TGController, WSGIAppController, RestController import pylons from pylons import tmpl_context from pylons.controllers.util import abort from pylons.util import ContextObj, PylonsContext from pylons.testutil import ControllerWrap, SetupCacheGlobal from repoze.who.plugins.auth_tkt import AuthTktCookiePlugin from repoze.what.middleware import setup_auth from repoze.what.predicates import Not, is_user, not_anonymous from pylons.middleware import StatusCodeRedirect from tg.error import ErrorHandler #{ AUT's setup NOT_AUTHENTICATED = "The current user must have been authenticated" data_dir = os.path.dirname(os.path.abspath(__file__)) session_dir = os.path.join(data_dir, 'session') # Just in case... rmtree(session_dir, ignore_errors=True) def make_app(controller_klass, environ={}, with_errors=False): """Creates a ``TestApp`` instance.""" # The basic middleware: app = ControllerWrap(controller_klass) app = SetupCacheGlobal(app, environ, setup_cache=True, setup_session=True) if with_errors: app = ErrorHandler(app, {}, debug=False) app = StatusCodeRedirect(app, [403, 404, 500]) app = RegistryManager(app) app = SessionMiddleware(app, {}, data_dir=session_dir) app = CacheMiddleware(app, {}, data_dir=os.path.join(data_dir, 'cache')) # We're not going to use groups or permissions-related predicates here: groups_adapters = None permissions_adapters = None # Setting repoze.who up: cookie = AuthTktCookiePlugin('secret', 'authtkt') identifiers = [('cookie', cookie)] app = setup_auth(app, groups_adapters, permissions_adapters, identifiers=identifiers, authenticators=[], challengers=[], skip_authentication=True) app = httpexceptions.make_middleware(app) return TestApp(app) #{ Mock objects def wsgi_app(environ, start_response): """Mock WSGI application""" req = Request(environ) resp = Response("Hello from %s" % req.script_name + req.path_info) return resp(environ, start_response) class DaRestController(RestController): """Mock REST controller""" allow_only = is_user('gustavo') @expose() def new(self): return "new here" class HRManagementController(TGController): """Mock TG2 protected controller using the .allow_only attribute""" allow_only = is_user('hiring-manager') @expose() def index(self): return 'you can manage Human Resources' @expose() def hire(self, person_name): return "%s was just hired" % person_name class ControlPanel(TGController): """Mock TG2 protected controller using @allow_only directly.""" hr = HRManagementController() allow_only = not_anonymous() @expose() def index(self): return 'you are in the panel' @expose() @require(is_user('admin')) def add_user(self, user_name): return "%s was just registered" % user_name class RootController(TGController): cp = ControlPanel() rest = DaRestController() mounted_app = WSGIAppController(wsgi_app, allow_only=is_user('gustavo')) @expose() def index(self): return "you're in the main page" @expose() @require(is_user('developer')) def commit(self): return 'you can commit' class ControllerWithAllowOnlyAttributeAndAuthzDenialHandler(TGController): """Mock TG2 protected controller using the .allow_only attribute""" allow_only = is_user('foobar') @expose() def index(self): return 'Welcome back, foobar!' @classmethod def _failed_authorization(self, reason): # Pay first! abort(402) class ControllerWithAllowOnlyDecoratorAndAuthzDenialHandler(TGController): """ Mock TG2 protected controller using the @allow_only decorator, but also using ._failed_authorization() """ @expose() def index(self): return 'Welcome back, foobar!' @classmethod def _failed_authorization(self, reason): # Pay first! abort(402) ControllerWithAllowOnlyDecoratorAndAuthzDenialHandler = allow_only( is_user('foobar'))(ControllerWithAllowOnlyDecoratorAndAuthzDenialHandler) #{ The tests themselves class BaseIntegrationTests(TestCase): """Base test case for the integration tests""" controller = RootController def setUp(self): # Creating the session dir: if not os.path.exists(session_dir): os.makedirs(session_dir) # Setting TG2 up: c = ContextObj() py_obj = PylonsContext() py_obj.c = c py_obj.request = py_obj.response = None environ = {'pylons.routes_dict': dict(action='index'), 'pylons.pylons': py_obj} pylons.tmpl_context._push_object(c) # Finally, the app: self.app = make_app(self.controller, environ) def tearDown(self): tmpl_context._pop_object() # Removing the session dir: rmtree(session_dir, ignore_errors=True) def _check_flash(self, response, *expected_messages): """ Check that ``expected_messages`` are defined in the WebFlash cookie. """ assert 'webflash' in response.cookies_set, "Such no WebFlash cookie" flash = unquote(response.cookies_set['webflash']) for msg in expected_messages: msg = '"%s"' % msg assert msg in flash, 'Message %s not in flash: %s' % (msg, flash) class TestRequire(BaseIntegrationTests): """Test case for the @require decorator""" def test_authz_granted_in_root_controller(self): environ = {'REMOTE_USER': 'developer'} resp = self.app.get('/commit', extra_environ=environ, status=200) self.assertEqual("you can commit", resp.body) def test_authz_denied_in_root_controller(self): # As an anonymous user: resp = self.app.get('/commit', status=401) assert "you can commit" not in resp.body self._check_flash(resp, r'The current user must be \"developer\"') # As an authenticated user: environ = {'REMOTE_USER': 'foobar'} resp = self.app.get('/commit', extra_environ=environ, status=403) assert "you can commit" not in resp.body self._check_flash(resp, r'The current user must be \"developer\"') def test_authz_granted_in_sub_controller(self): environ = {'REMOTE_USER': 'admin'} resp = self.app.get('/cp/add_user/foo', extra_environ=environ, status=200) self.assertEqual("foo was just registered", resp.body) def test_authz_denied_in_sub_controller(self): # As an anonymous user: resp = self.app.get('/cp/add_user/foo', status=401) assert "was just registered" not in resp.body self._check_flash(resp, NOT_AUTHENTICATED) # As an authenticated user: environ = {'REMOTE_USER': 'foobar'} resp = self.app.get('/cp/add_user/foo', extra_environ=environ, status=403) assert "was just registered" not in resp.body self._check_flash(resp, r'The current user must be \"admin\"') class TestAllowOnlyDecoratorInSubController(BaseIntegrationTests): """Test case for the @allow_only decorator in a sub-controller""" def test_authz_granted_without_require(self): environ = {'REMOTE_USER': 'someone'} resp = self.app.get('/cp/', extra_environ=environ, status=200) self.assertEqual("you are in the panel", resp.body) def test_authz_denied_without_require(self): resp = self.app.get('/cp/', status=401) assert "you are in the panel" not in resp.body self._check_flash(resp, NOT_AUTHENTICATED) def test_authz_granted_with_require(self): environ = {'REMOTE_USER': 'admin'} resp = self.app.get('/cp/add_user/foo', extra_environ=environ, status=200) self.assertEqual("foo was just registered", resp.body) def test_authz_denied_with_require(self): resp = self.app.get('/cp/add_user/foo', status=401) assert "was just registered" not in resp.body self._check_flash(resp, NOT_AUTHENTICATED) class _TestAllowOnlyDecoratorAndDefaultAuthzDenialHandler(BaseIntegrationTests): """ Test case for the @allow_only decorator in a controller using _failed_authorization() as its denial handler. """ controller = ControllerWithAllowOnlyDecoratorAndAuthzDenialHandler def test_authz_granted(self): environ = {'REMOTE_USER': 'foobar'} resp = self.app.get('/', extra_environ=environ, status=200) self.assertEqual("Welcome back, foobar!", resp.body) def test_authz_denied(self): resp = self.app.get('/', status=402) assert "Welcome back" not in resp.body class TestAllowOnlyAttributeInSubController(BaseIntegrationTests): """Test case for the .allow_only attribute in a sub-controller""" controller = ControlPanel def test_authz_granted_without_require(self): environ = {'REMOTE_USER': 'hiring-manager'} resp = self.app.get('/hr/', extra_environ=environ, status=200) self.assertEqual("you can manage Human Resources", resp.body) def test_authz_denied_without_require(self): # As an anonymous user: resp = self.app.get('/hr/', status=401) assert "you can manage Human Resources" not in resp.body self._check_flash(resp, r'The current user must have been authenticated') # As an authenticated user: environ = {'REMOTE_USER': 'someone'} resp = self.app.get('/hr/', extra_environ = environ, status=403) assert "you can manage Human Resources" not in resp.body self._check_flash(resp, r'The current user must be \"hiring-manager\"') def test_authz_granted_with_require(self): environ = {'REMOTE_USER': 'hiring-manager'} resp = self.app.get('/hr/hire/gustavo', extra_environ=environ, status=200) self.assertEqual("gustavo was just hired", resp.body) def test_authz_denied_with_require(self): # As an anonymous user: resp = self.app.get('/hr/hire/gustavo', status=401) assert "was just hired" not in resp.body self._check_flash(resp, r'The current user must have been authenticated') # As an authenticated user: environ = {'REMOTE_USER': 'someone'} resp = self.app.get('/hr/hire/gustavo', extra_environ = environ, status=403) assert "was just hired" not in resp.body self._check_flash(resp, r'The current user must be \"hiring-manager\"') class TestAllowOnlyAttributeAndDefaultAuthzDenialHandler(BaseIntegrationTests): """ Test case for the .allow_only attribute in a controller using _failed_authorization() as its denial handler. """ controller = ControllerWithAllowOnlyAttributeAndAuthzDenialHandler def test_authz_granted(self): environ = {'REMOTE_USER': 'foobar'} resp = self.app.get('/', extra_environ=environ, status=200) self.assertEqual("Welcome back, foobar!", resp.body) def test_authz_denied(self): resp = self.app.get('/', status=402) assert "Welcome back" not in resp.body class TestAppWideAuthzWithAllowOnlyDecorator(BaseIntegrationTests): """Test case for application-wide authz with the @allow_only decorator""" controller = ControlPanel def test_authz_granted_without_require(self): environ = {'REMOTE_USER': 'someone'} resp = self.app.get('/', extra_environ=environ, status=200) self.assertEqual("you are in the panel", resp.body) def test_authz_denied_without_require(self): resp = self.app.get('/', status=401) assert "you are in the panel" not in resp.body self._check_flash(resp, NOT_AUTHENTICATED) def test_authz_granted_with_require(self): environ = {'REMOTE_USER': 'admin'} resp = self.app.get('/add_user/foo', extra_environ=environ, status=200) self.assertEqual("foo was just registered", resp.body) def test_authz_denied_with_require(self): resp = self.app.get('/add_user/foo', status=401) assert "was just registered" not in resp.body self._check_flash(resp, NOT_AUTHENTICATED) class TestAppWideAuthzWithAllowOnlyAttribute(BaseIntegrationTests): """Test case for application-wide authz with the .allow_only attribute""" controller = HRManagementController def test_authz_granted_without_require(self): environ = {'REMOTE_USER': 'hiring-manager'} resp = self.app.get('/', extra_environ=environ, status=200) self.assertEqual("you can manage Human Resources", resp.body) def test_authz_denied_without_require(self): # As an anonymous user: resp = self.app.get('/', status=401) assert "you can manage Human Resources" not in resp.body self._check_flash(resp, r'The current user must be \"hiring-manager\"') # As an authenticated user: environ = {'REMOTE_USER': 'someone'} resp = self.app.get('/', extra_environ = environ, status=403) assert "you can manage Human Resources" not in resp.body self._check_flash(resp, r'The current user must be \"hiring-manager\"') def test_authz_granted_with_require(self): environ = {'REMOTE_USER': 'hiring-manager'} resp = self.app.get('/hire/gustavo', extra_environ=environ, status=200) self.assertEqual("gustavo was just hired", resp.body) def test_authz_denied_with_require(self): # As an anonymous user: resp = self.app.get('/hire/gustavo', status=401) assert "was just hired" not in resp.body self._check_flash(resp, r'The current user must be \"hiring-manager\"') # As an authenticated user: environ = {'REMOTE_USER': 'someone'} resp = self.app.get('/hire/gustavo', extra_environ = environ, status=403) assert "was just hired" not in resp.body self._check_flash(resp, r'The current user must be \"hiring-manager\"') class TestProtectedRESTContoller(BaseIntegrationTests): """Test case for protected REST controllers""" def test_authz_granted(self): environ = {'REMOTE_USER': 'gustavo'} resp = self.app.get('/rest/new', extra_environ=environ, status=200) self.assertEqual("new here", resp.body) def test_authz_denied(self): # As an anonymous user: resp = self.app.get('/rest/new', status=401) assert "new here" not in resp.body self._check_flash(resp, r'The current user must be \"gustavo\"') # As an authenticated user: environ = {'REMOTE_USER': 'non-gustavo'} resp = self.app.get('/rest/new', extra_environ=environ, status=403) assert "new here" not in resp.body self._check_flash(resp, r'The current user must be \"gustavo\"') class TestProtectedWSGIApplication(BaseIntegrationTests): """Test case for protected WSGI applications mounted on the controller""" def test_authz_granted(self): environ = {'REMOTE_USER': 'gustavo'} resp = self.app.get('/mounted_app/da-path', extra_environ=environ, status=200) self.assertEqual("Hello from /mounted_app/da-path", resp.body) def test_authz_denied(self): # As an anonymous user: resp = self.app.get('/mounted_app/da-path', status=401) assert "Hello from /mounted_app/" not in resp.body self._check_flash(resp, r'The current user must be \"gustavo\"') # As an authenticated user: environ = {'REMOTE_USER': 'non-gustavo'} resp = self.app.get('/mounted_app/da-path', extra_environ=environ, status=403) assert "Hello from /mounted_app/" not in resp.body self._check_flash(resp, r'The current user must be \"gustavo\"') class ErrorController(object): @expose() def document(self, *args, **kwargs): return request.environ.get('repoze.who.identity')['repoze.who.userid'] class DefaultLessTGController(TGController): error = ErrorController() @expose() def index(self): return request.environ.get('repoze.who.identity')['repoze.who.userid'] class TestLoggedErrorTGController(BaseIntegrationTests): def setUp(self): if not os.path.exists(session_dir): os.makedirs(session_dir) # Setting TG2 up: c = ContextObj() py_obj = PylonsContext() py_obj.c = c py_obj.request = py_obj.response = None environ = {'pylons.routes_dict': dict(action='index'), 'pylons.pylons': py_obj} pylons.tmpl_context._push_object(c) self.app = make_app(DefaultLessTGController, environ, with_errors=True) def test_logged_index(self): resp = self.app.get('/index', extra_environ={'REMOTE_USER': 'gustavo'}, expect_errors=True) assert 'gustavo' in resp def test_logged_error(self): resp = self.app.get('/missing_page_for_sure', extra_environ={'REMOTE_USER': 'gustavo'}, expect_errors=True) assert 'gustavo' in resp #} TurboGears2-2.1.5/tests/test_stack/fixture/0000775000175000017500000000000011737460177021503 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/test_stack/fixture/__init__.py0000664000175000017500000000000011675520537023600 0ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/base.py0000664000175000017500000001207511733764570017142 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- import os, shutil from unittest import TestCase from xmlrpclib import loads, dumps import warnings import webob import beaker import pylons from paste.registry import Registry from paste.registry import RegistryManager from webtest import TestApp from paste.wsgiwrappers import WSGIRequest, WSGIResponse from paste import httpexceptions import tg import pylons from tg import tmpl_context from tests.test_stack import app_from_config, TestConfig from pylons import url from routes import URLGenerator, Mapper from tg.util import Bunch from pylons.util import ContextObj, PylonsContext from pylons.controllers.util import Request, Response from tg.controllers import TGController from pylons.configuration import response_defaults response_defaults['headers']['Content-Type'] = None from pylons.testutil import ControllerWrap, SetupCacheGlobal from beaker.middleware import CacheMiddleware data_dir = os.path.dirname(os.path.abspath(__file__)) session_dir = os.path.join(data_dir, 'session') def setup_session_dir(): if not os.path.exists(session_dir): os.makedirs(session_dir) def teardown_session_dir(): shutil.rmtree(session_dir, ignore_errors=True) default_config = { 'debug': False, 'pylons.package': None, 'pylons.paths': {'root': None, 'controllers': None, 'templates': [], 'static_files': None}, 'pylons.db_engines': {}, 'pylons.environ_config': dict(session='beaker.session', cache='beaker.cache'), 'pylons.g': None, 'pylons.h': None, 'pylons.request_options': pylons.configuration.request_defaults.copy(), 'pylons.response_options': pylons.configuration.response_defaults.copy(), 'pylons.strict_c': False, 'pylons.strict_tmpl_context':False, 'pylons.c_attach_args': True, 'pylons.tmpl_context_attach_args': True, 'buffet.template_engines': [], 'buffet.template_options': {}, 'default_renderer':'genshi', 'renderers':['json'], 'render_functions':{'json':tg.render.render_json}, 'use_legacy_renderers':False, 'use_sqlalchemy': False } default_environ = { 'pylons.use_webob' : True, 'pylons.routes_dict': dict(action='index'), 'paste.config': dict(global_conf=dict(debug=True)) } default_map = Mapper() # Setup a default route for the error controller: default_map.connect('error/:action/:id', controller='error') # Setup a default route for the root of object dispatch default_map.connect('*url', controller='root', action='routes_placeholder') def make_app(controller_klass=None, environ=None): """Creates a `TestApp` instance.""" if environ is None: environ = {} environ['pylons.routes_dict'] = {} environ['pylons.routes_dict']['action'] = "routes_placeholder" if controller_klass is None: controller_klass = TGController app = ControllerWrap(controller_klass) app = SetupCacheGlobal(app, environ, setup_cache=True, setup_session=True) app = RegistryManager(app) app = beaker.middleware.SessionMiddleware(app, {}, data_dir=session_dir) app = CacheMiddleware(app, {}, data_dir=os.path.join(data_dir, 'cache')) app = httpexceptions.make_middleware(app) return TestApp(app) def create_request(path, environ=None): """Helper used in test cases to quickly setup a request obj. ``path`` The path will become PATH_INFO ``environ`` Additional environment Returns an instance of the `webob.Request` object. """ # setup the environ if environ is None: environ = {} environ.update(default_environ) # create a "blank" WebOb Request object # using Pylon's Request which is a webob Request plus # some compatibility methods req = Request.blank(path, environ) # setup a Registry reg = environ.setdefault('paste.registry', Registry()) reg.prepare() # setup pylons.request to point to our Registry reg.register(pylons.request, req) # setup tmpl context tmpl_context._push_object(ContextObj()) url._push_object(URLGenerator(default_map, environ)) return req class TestWSGIController(TestCase): def setUp(self): tmpl_options = {} tmpl_options['genshi.search_path'] = ['tests'] self._ctx = ContextObj() tmpl_context._push_object(self._ctx) warnings.simplefilter("ignore") pylons.config.push_process_config(default_config) warnings.resetwarnings() setup_session_dir() def tearDown(self): tmpl_context._pop_object(self._ctx) # pylons.config.pop_thread_config() pylons.config.pop_process_config() teardown_session_dir() def get_response(self, **kargs): url = kargs.pop('_url', '/') self.environ['pylons.routes_dict'].update(kargs) return self.app.get(url, extra_environ=self.environ) def post_response(self, **kargs): url = kargs.pop('_url', '/') return self.app.post(url, extra_environ=self.environ, params=kargs) TurboGears2-2.1.5/tests/test_controllers.py0000664000175000017500000000556311733764765021647 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- import pylons import tg from tg.controllers import * from tg.exceptions import HTTPFound from nose.tools import eq_ from tests.base import TestWSGIController, make_app, setup_session_dir, teardown_session_dir, create_request from tg.util import no_warn def setup(): setup_session_dir() def teardown(): teardown_session_dir() def test_create_request(): environ = { 'SCRIPT_NAME' : '/xxx' } request = create_request('/', environ) eq_('http://localhost/xxx/hello', tg.request.relative_url('hello')) eq_('http://localhost/xxx', tg.request.application_url) def test_approots(): create_request('/subthing/',{ 'SCRIPT_NAME' : '/subthing' }) eq_("foo", url("foo")) eq_("/subthing/foo", url("/foo")) def test_lowerapproots(): create_request( '/subthing/subsubthing/', { 'SCRIPT_NAME' : '/subthing/subsubthing' } ) eq_("/subthing/subsubthing/foo", url("/foo")) @no_warn def test_multi_values(): create_request('/') r = url("/foo", bar=(u"asdf",u"qwer")) assert r in \ ["/foo?bar=qwer&bar=asdf", "/foo?bar=asdf&bar=qwer"], r r = url("/foo", bar=[1,2]) assert r in \ ["/foo?bar=1&bar=2", "/foo?bar=2&bar=1"], r @no_warn def test_unicode(): """url() can handle unicode parameters""" create_request("/") unicodestring = (u'\N{LATIN SMALL LETTER A WITH GRAVE}' u'\N{LATIN SMALL LETTER E WITH GRAVE}' u'\N{LATIN SMALL LETTER I WITH GRAVE}' u'\N{LATIN SMALL LETTER O WITH GRAVE}' u'\N{LATIN SMALL LETTER U WITH GRAVE}') eq_(url('/', x=unicodestring), '/?x=%C3%A0%C3%A8%C3%AC%C3%B2%C3%B9' ) @no_warn def test_list(): """url() can handle list parameters, with unicode too""" create_request("/") value = url('/', foo=['bar', u'\N{LATIN SMALL LETTER A WITH GRAVE}']), assert '/?foo=bar&foo=%C3%A0' in value, value @no_warn def test_url_kwargs_overwrite_tgparams(): params = {'spamm': 'eggs'} result = url('/foo', params, spamm='ham') assert 'spamm=ham' in result def test_url_with_params_key(): params = {'spamm': 'eggs'} result = url('/foo', params=params) assert 'spamm=eggs' in result @no_warn def test_url_strip_None(): params = {'spamm':'eggs', 'hamm':None } result = url('/foo', params=params) assert 'hamm' not in result, result @no_warn def test_url_doesnt_change_tgparams(): params = {'spamm': 'eggs'} result = url('/foo', params, spamm='ham') eq_(params['spamm'], 'eggs') def test_lurl(): params = {'spamm':'eggs', 'hamm':None } assert url('/foo', params=params) == str(lurl('/foo', params=params)) #def test_approotsWithPath(): # create_request('/coolsite/root/subthing/', {'SCRIPT_NAME' : '/subthing'}) # pylons.config.update({"server.webpath":"/coolsite/root"}) # eq_("/coolsite/root/subthing/foo", pylons.url("/foo")) TurboGears2-2.1.5/tests/test_i18n.py0000664000175000017500000000067111675520537020043 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- from tg import i18n def test_sanitize_language_code(): """Check that slightly malformed language codes can be corrected.""" for lang in 'pt', 'PT': assert i18n.sanitize_language_code(lang) == 'pt' for lang in 'pt-br', 'pt_br', 'pt_BR': assert i18n.sanitize_language_code(lang) == 'pt_BR' for lang in 'foo', 'bar', 'foo-bar': assert i18n.sanitize_language_code(lang) == lang TurboGears2-2.1.5/tests/fixtures/0000775000175000017500000000000011737460177017522 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/tests/fixtures/__init__.py0000664000175000017500000000011611675520537021627 0ustar marvinmarvin00000000000000"""TG developers may use this package to store fixtures for the test suite""" TurboGears2-2.1.5/tests/fixtures/model.py0000664000175000017500000000310011675520537021164 0ustar marvinmarvin00000000000000"""A fake application's model objects""" from datetime import datetime from zope.sqlalchemy import ZopeTransactionExtension from sqlalchemy import Table, ForeignKey, Column from sqlalchemy.orm import scoped_session, sessionmaker, relation, backref, \ synonym from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.types import String, Unicode, UnicodeText, Integer, DateTime, \ Boolean, Float # Global session manager. DBSession() returns the session object # appropriate for the current web request. maker = sessionmaker(autoflush=True, autocommit=False, extension=ZopeTransactionExtension()) DBSession = scoped_session(maker) # By default, the data model is defined with SQLAlchemy's declarative # extension, but if you need more control, you can switch to the traditional # method. DeclarativeBase = declarative_base() # Global metadata. # The default metadata is the one from the declarative base. metadata = DeclarativeBase.metadata def init_model(engine): """Call me before using any of the tables or classes in the model.""" DBSession.configure(bind=engine) class Group(DeclarativeBase): """An ultra-simple group definition. """ __tablename__ = 'tg_group' group_id = Column(Integer, autoincrement=True, primary_key=True) group_name = Column(Unicode(16), unique=True) display_name = Column(Unicode(255)) created = Column(DateTime, default=datetime.now) def __repr__(self): return '' % self.group_name TurboGears2-2.1.5/tests/test_configuration.py0000664000175000017500000001065211675520537022133 0ustar marvinmarvin00000000000000""" Testing for TG2 Configuration """ from nose.tools import eq_, raises import atexit from tg.util import Bunch from tg.configuration import AppConfig, config from tests.base import TestWSGIController, make_app, setup_session_dir, teardown_session_dir, create_request def setup(): setup_session_dir() def teardown(): teardown_session_dir() class TestPylonsConfigWrapper: def setup(self): self.config = config def test_create(self): pass def test_getitem(self): expected_keys = ['global_conf', 'use_sqlalchemy', 'package', 'pylons.app_globals', 'call_on_shutdown'] for key in expected_keys: self.config[key] @raises(KeyError) def test_getitem_bad(self): self.config['no_such_key'] def test_setitem(self): self.config['no_such_key'] = 'something' def test_delattr(self): del self.config.use_sqlalchemy eq_(hasattr(self.config, 'use_sqlalchemy'), False) self.config.use_sqlalchemy = True @raises(AttributeError) def test_delattr_bad(self): del self.config.i_dont_exist class TestAppConfig: def setup(self): self.config = AppConfig() # set up some required paths and config settings # FIXME: these seem to be needed so that # other tests don't suffer - but that's a nasty # side-effect. setup for those tests actually needs # fixing. config['pylons.paths']['static_files'] = "test" config["pylons.app_globals"] = Bunch() config["use_sqlalchemy"] = False config["global_conf"] = Bunch() config["package"] = "test" config["call_on_shutdown"] = "foo" config["render_functions"] = Bunch() config['beaker.session.secret'] = 'some_secret' def test_create(self): pass def test_setup_startup_and_shutdown_startup_callable(self): def func(): a = 7 self.config.call_on_startup = [func] self.config.setup_startup_and_shutdown() def test_setup_startup_and_shutdown_callable_startup_with_exception(self): def func(): raise Exception self.config.call_on_startup = [func] self.config.setup_startup_and_shutdown() def test_setup_startup_and_shutdown_startup_not_callable(self): self.config.call_on_startup = ['not callable'] self.config.setup_startup_and_shutdown() def test_setup_startup_and_shutdown_shutdown_not_callable(self): self.config.call_on_shutdown = ['not callable'] self.config.setup_startup_and_shutdown() def test_setup_startup_and_shutdown_shutdown_callable(self): def func(): a = 7 self.config.call_on_shutdown = [func] self.config.setup_startup_and_shutdown() assert (func, (), {}) in atexit._exithandlers #this tests fails def _test_setup_helpers_and_globals(self): self.config.setup_helpers_and_globals() def test_setup_sa_auth_backend(self): self.config.setup_sa_auth_backend() def test_setup_chameleon_genshi_renderer(self): self.config.paths.templates = 'template_path' self.config.setup_chameleon_genshi_renderer() def test_setup_genshi_renderer(self): self.config.paths.templates = 'template_path' self.config.setup_genshi_renderer() def test_setup_jinja_renderer(self): self.config.paths.templates = 'template_path' self.config.setup_jinja_renderer() def test_setup_mako_renderer(self): self.config.paths.templates = ['template_path'] self.config.setup_mako_renderer(use_dotted_templatenames=True) def test_setup_sqlalchemy(self): config['sqlalchemy.url'] = 'sqlite://' class Package: class model: @classmethod def init_model(package, engine): pass self.config.package = Package() self.config.setup_sqlalchemy() def test_add_auth_middleware(self): class Dummy:pass self.config.sa_auth.dbsession = Dummy() self.config.sa_auth.user_class = Dummy self.config.sa_auth.group_class = Dummy self.config.sa_auth.permission_class = Dummy self.config.sa_auth.cookie_secret = 'dummy' self.config.sa_auth.password_encryption_method = 'sha' self.config.add_auth_middleware(None, None) def test_add_static_file_middleware(self): self.config.add_static_file_middleware(None) TurboGears2-2.1.5/tests/test_caching.py0000664000175000017500000001353611733764570020666 0ustar marvinmarvin00000000000000# -*- coding: utf-8 -*- """ Test cases for Pylons caching. See: http://wiki.pylonshq.com/display/pylonsdocs/Caching+in+Templates+and+Controllers For more details. """ import tg from tg.controllers import TGController from tg.decorators import expose from pylons.decorators.cache import beaker_cache from pylons.controllers.util import etag_cache from pylons import cache from routes import Mapper import pylons from routes.middleware import RoutesMiddleware from webob.exc import HTTPNotModified from tests.base import TestWSGIController, make_app, setup_session_dir, teardown_session_dir def setup(): setup_session_dir() def teardown(): teardown_session_dir() # a variable used to represent state held outside the controllers mockdb = {} class MockTime: """ A very simple class to mock the time module. This lets us slide time around to fake expiry in beaker.container. """ mock_time = 0 def time(self): return self.mock_time def set_time(self, v): self.mock_time = v mocktime = MockTime() import beaker.container beaker.container.time = mocktime class SimpleCachingController(TGController): """ Pylons supports a mechanism for arbitrary caches that can be allocated within controllers. Each cache value has a creation function associated with it that is called to retrieve it's results. """ @expose() def simple(self, a): c = cache.get_cache("BasicTGController.index") x = c.get_value(key=a, createfunc=lambda: "cached %s" % a, type="memory", expiretime=3600) return x def createfunc(self): return "cached %s" % mockdb['expiry'] @expose() def expiry(self, a): mockdb['expiry'] = a # inject a value into the context c = cache.get_cache("BasicTGController.index") x = c.get_value(key='test', createfunc=self.createfunc, type="memory", expiretime=100) return x class TestSimpleCaching(TestWSGIController): def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) self.baseenviron = {} self.app = make_app(SimpleCachingController, self.baseenviron) def test_simple_cache(self): """ test that caches get different results for different cache keys. """ resp = self.app.get('/simple/', params={'a':'foo'}) assert resp.body == 'cached foo' resp = self.app.get('/simple/', params={'a':'bar'}) assert resp.body == 'cached bar' resp = self.app.get('/simple/', params={'a':'baz'}) assert resp.body == 'cached baz' def test_expiry(self): """ test that values expire from a single cache key. """ mocktime.set_time(0) resp = self.app.get('/expiry/', params={'a':'foo1'}) assert resp.body == 'cached foo1' mocktime.set_time(1) resp = self.app.get('/expiry/', params={'a':'foo2'}) assert resp.body == 'cached foo1' mocktime.set_time(200) # wind clock past expiry resp = self.app.get('/expiry/', params={'a':'foo2'}) assert resp.body == 'cached foo2' class DecoratorController(TGController): @beaker_cache(expire=100, type='memory') @expose() def simple(self): return "cached %s" % mockdb['DecoratorController.simple'] class TestDecoratorCaching(TestWSGIController): """ Test that the decorators function. """ def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) self.baseenviron = {} self.app = make_app(DecoratorController, self.baseenviron) def test_simple(self): """ Test expiry of cached results for decorated functions. """ mocktime.set_time(0) mockdb['DecoratorController.simple'] = 'foo1' resp = self.app.get('/simple/') assert resp.body == 'cached foo1' mocktime.set_time(1) mockdb['DecoratorController.simple'] = 'foo2' resp = self.app.get('/simple/') assert resp.body == 'cached foo1' mocktime.set_time(200) mockdb['DecoratorController.simple'] = 'foo2' resp = self.app.get('/simple/') assert resp.body == 'cached foo2' class EtagController(TGController): @expose() def etagged(self, etag): etag_cache(etag) return "bar" class TestEtagCaching(TestWSGIController): """ A simple mechanism is provided to set the etag header for returned results. """ def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) self.app = make_app(EtagController) def test_etags(self): """ Test that the etag in the response headers is the one we expect. """ resp = self.app.get('/etagged/', params={'etag':'foo'}) assert resp.etag == 'foo', resp.etag resp = self.app.get('/etagged/', params={'etag':'bar'}) assert resp.etag == 'bar', resp.etag def test_304(self): resp = self.app.get('/etagged/', params={'etag':'foo'}, headers={'if-none-match': '"foo"'}) assert "304" in resp.status, resp class SessionTouchController(TGController): @expose() def session_get(self): if tg.session.accessed(): return 'ACCESSED' else: return 'NOTOUCH' class TestSessionTouch(TestWSGIController): def __init__(self, *args, **kargs): TestWSGIController.__init__(self, *args, **kargs) self.app = make_app(SessionTouchController) def test_prova(self): tg.config['beaker.session.tg_avoid_touch'] = False assert 'ACCESSED' in self.app.get('/session_get') def test_avoid_touch(self): tg.config['beaker.session.tg_avoid_touch'] = True assert 'NOTOUCH' in self.app.get('/session_get') TurboGears2-2.1.5/TurboGears2.egg-info/0000775000175000017500000000000011737460177020340 5ustar marvinmarvin00000000000000TurboGears2-2.1.5/TurboGears2.egg-info/dependency_links.txt0000664000175000017500000000002211737460176024410 0ustar marvinmarvin00000000000000http://tg.gy/215/ TurboGears2-2.1.5/TurboGears2.egg-info/requires.txt0000664000175000017500000000073111737460176022740 0ustar marvinmarvin00000000000000WebOb == 1.0.8 Pylons >= 0.9.7 WebFlash >= 0.1a8 WebError >= 0.10.1 Babel [core-testing] coverage nose TurboKid >= 1.0.4 zope.sqlalchemy >= 0.4 jinja2 Chameleon < 2.0a simplegeneric repoze.what >= 1.0.8 repoze.what-quickstart >= 1.0.3 repoze.who-testutil >= 1.0.1 repoze.what-pylons >= 1.0 repoze.who-friendlyform >=1.0.4 repoze.who repoze.tm2 >= 1.0a4 wsgiref tw.forms Kajiki>=0.2.2 Genshi >= 0.5.1 TurboKid >= 1.0.4 Mako TurboJson >= 1.3 Babel >=0.9.4 tgext.admin>=0.3.9TurboGears2-2.1.5/TurboGears2.egg-info/entry_points.txt0000664000175000017500000000033511737460176023636 0ustar marvinmarvin00000000000000 [paste.global_paster_command] tginfo = tg.commands.info:InfoCommand [turbogears2.command] serve = paste.script.serve:ServeCommand [Config] shell = pylons.commands:ShellCommand TurboGears2-2.1.5/TurboGears2.egg-info/PKG-INFO0000664000175000017500000000255711737460176021445 0ustar marvinmarvin00000000000000Metadata-Version: 1.0 Name: TurboGears2 Version: 2.1.5 Summary: Next generation TurboGears built on Pylons Home-page: http://www.turbogears.org/ Author: Mark Ramm, Christopher Perkins, Jonathan LaCour, Rick Copland, Alberto Valverde, and the TurboGears community Author-email: mark.ramm@gmail.com, alberto@toscat.net, m.pedersen@icelus.org License: MIT Description: TurboGears brings together a best of breed python tools to create a flexible, full featured, and easy to use web framework. TurboGears 2 provides an integrated and well tested set of tools for everything you need to build dynamic, database driven applications. It provides a full range of tools for front end javascript develeopment, back database development and everything in between: * dynamic javascript powered widgets (ToscaWidgets) * automatic JSON generation from your controllers * powerful, designer friendly XHTML based templating (Genshi) * object or route based URL dispatching * powerful Object Relational Mappers (SQLAlchemy) The latest development version is available in the `TurboGears Git repository`_. .. _TurboGears Git repository: https://sourceforge.net/p/turbogears2/tg2/ Keywords: turbogears pylons Platform: UNKNOWN TurboGears2-2.1.5/TurboGears2.egg-info/SOURCES.txt0000664000175000017500000000522211737460176022224 0ustar marvinmarvin00000000000000README.txt setup.cfg setup.py TurboGears2.egg-info/PKG-INFO TurboGears2.egg-info/SOURCES.txt TurboGears2.egg-info/dependency_links.txt TurboGears2.egg-info/entry_points.txt TurboGears2.egg-info/not-zip-safe TurboGears2.egg-info/requires.txt TurboGears2.egg-info/top_level.txt tests/__init__.py tests/base.py tests/test_caching.py tests/test_configuration.py tests/test_controllers.py tests/test_generic_json.py tests/test_i18n.py tests/test_jsonify.py tests/test_jsonify_sqlalchemy.py tests/test_render.py tests/test_rest_controller_dispatch.py tests/test_tg_controller_dispatch.py tests/test_util.py tests/test_validation.py tests/fixtures/__init__.py tests/fixtures/model.py tests/test_stack/__init__.py tests/test_stack/test_authz.py tests/test_stack/config/__init__.py tests/test_stack/config/test_config.py tests/test_stack/config/controllers/__init__.py tests/test_stack/config/controllers/root.py tests/test_stack/dispatch/__init__.py tests/test_stack/dispatch/test_config.py tests/test_stack/dispatch/test_url_dispatch.py tests/test_stack/dispatch/controllers/__init__.py tests/test_stack/dispatch/controllers/root.py tests/test_stack/fixture/__init__.py tests/test_stack/lib/__init__.py tests/test_stack/lib/base.py tests/test_stack/lib/helpers.py tests/test_stack/lib/templatetools/__init__.py tests/test_stack/lib/templatetools/jinja_filters.py tests/test_stack/rendering/__init__.py tests/test_stack/rendering/test_decorators.py tests/test_stack/rendering/test_dotted_rendering.py tests/test_stack/rendering/test_pagination.py tests/test_stack/rendering/test_rendering.py tests/test_stack/rendering/test_toscawidgets.py tests/test_stack/rendering/controllers/__init__.py tests/test_stack/rendering/controllers/root.py tests/test_stack/rendering/templates/__init__.py tests/test_stack/rendering/templates/mako_base.mak.py tests/test_stack/rendering/templates/mako_custom_format.mak.py tests/test_stack/rendering/templates/mako_inherits.mak.py tests/test_stack/rendering/templates/mako_noop.mak.py tests/test_stack/rendering/templates/sub/__init__.py tg/__init__.py tg/amfify.py tg/configuration.py tg/decorators.py tg/error.py tg/exceptions.py tg/flash.py tg/i18n.py tg/jsonify.py tg/paginate.py tg/release.py tg/render.py tg/util.py tg/wsgiapp.py tg/commands/__init__.py tg/commands/info.py tg/controllers/__init__.py tg/controllers/decoratedcontroller.py tg/controllers/dispatcher.py tg/controllers/restcontroller.py tg/controllers/tgcontroller.py tg/controllers/util.py tg/controllers/wsgiappcontroller.py tg/dottednames/__init__.py tg/dottednames/chameleon_genshi_lookup.py tg/dottednames/genshi_lookup.py tg/dottednames/jinja_lookup.py tg/dottednames/mako_lookup.py tg/templates/__init__.pyTurboGears2-2.1.5/TurboGears2.egg-info/not-zip-safe0000664000175000017500000000000111737226714022563 0ustar marvinmarvin00000000000000 TurboGears2-2.1.5/TurboGears2.egg-info/top_level.txt0000664000175000017500000000001111737460176023061 0ustar marvinmarvin00000000000000tg tests TurboGears2-2.1.5/setup.py0000664000175000017500000000461711737217273016226 0ustar marvinmarvin00000000000000import os here = os.path.abspath(os.path.dirname(__file__)) execfile(os.path.join(here, 'tg', 'release.py')) from setuptools import find_packages, setup import sys test_requirements = ['coverage', 'nose', 'TurboKid >= 1.0.4', 'zope.sqlalchemy >= 0.4', 'jinja2', 'Chameleon < 2.0a', 'simplegeneric', 'repoze.what >= 1.0.8', 'repoze.what-quickstart >= 1.0.3', 'repoze.who-testutil >= 1.0.1', 'repoze.what-pylons >= 1.0', "repoze.who-friendlyform >=1.0.4", 'repoze.who', 'repoze.tm2 >= 1.0a4', 'wsgiref', 'tw.forms', 'Kajiki>=0.2.2', 'Genshi >= 0.5.1', 'TurboKid >= 1.0.4', 'Mako', 'TurboJson >= 1.3', 'Babel >=0.9.4', 'tgext.admin>=0.3.9', ] if sys.version_info[:2] == (2,4): test_requirements.extend(['pysqlite', 'hashlib']) setup( name='TurboGears2', version=version, description=description, long_description=long_description, classifiers=[], keywords='turbogears pylons', author=author, author_email=email, url=url, license=license, packages=find_packages(exclude=['ez_setup', 'examples']), include_package_data=True, zip_safe=False, install_requires=[ 'WebOb == 1.0.8', 'Pylons >= 0.9.7', 'WebFlash >= 0.1a8', 'WebError >= 0.10.1', 'Babel', ], extras_require={ #XXX: Perhaps this 'core-testing' extras_require can be removed # since tests_require takes care of that as long as TG is tested # with 'python setup.py test' (which we should IMHO so setuptools # can take care of these details for us) 'core-testing':test_requirements, }, test_suite='nose.collector', tests_require = test_requirements, entry_points=''' [paste.global_paster_command] tginfo = tg.commands.info:InfoCommand [turbogears2.command] serve = paste.script.serve:ServeCommand [Config] shell = pylons.commands:ShellCommand ''', dependency_links=[ "http://tg.gy/215/" ] ) TurboGears2-2.1.5/README.txt0000664000175000017500000000030411675520537016200 0ustar marvinmarvin00000000000000TurboGears is licensed under an MIT-style license (see LICENSE.txt). Other incorporated projects may be licensed under different licenses. All licenses allow for non-commercial and commercial use.