sprox-0.6.4/0000755000076700000240000000000011236057646012472 5ustar cperkins1staffsprox-0.6.4/MANIFEST.in0000644000076700000240000000005411124254300014205 0ustar cperkins1staffrecursive-include sprox/widgets/templates * sprox-0.6.4/PKG-INFO0000644000076700000240000000125311236057646013570 0ustar cperkins1staffMetadata-Version: 1.0 Name: sprox Version: 0.6.4 Summary: A package for creation of web widgets directly from database schema. Home-page: http://www.sprox.org Author: Christopher Perkins 2007-2009 major contributions by Michael Brickenstein Author-email: chris@percious.com License: MIT Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules sprox-0.6.4/setup.cfg0000644000076700000240000000020111236057646014304 0ustar cperkins1staff[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [aliases] release = egg_info -rDb "" sdist bdist_egg register upload sprox-0.6.4/setup.py0000644000076700000240000000314111224440262014166 0ustar cperkins1staff#setup.py from setuptools import setup, find_packages from sprox.release import __version__ setup( name="sprox", version=__version__, zip_safe=False, include_package_data=True, description="""A package for creation of web widgets directly from database schema.""", author="Christopher Perkins 2007-2009 major contributions by Michael Brickenstein", author_email="chris@percious.com", license="MIT", url="http://www.sprox.org", install_requires=['sqlalchemy>=0.5', 'tw.forms>=0.9.7.2', ], packages = find_packages(), classifiers=[ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", ], entry_points = """[toscawidgets] # Use 'widgets' to point to the module where widgets should be imported # from to register in the widget browser widgets = sprox.widgets # Use 'samples' to point to the module where widget examples # should be imported from to register in the widget browser # samples = tw.samples # Use 'resources' to point to the module where resources # should be imported from to register in the widget browser #resources = sprox.widgets.resources """ # entry_points=""" # [paste.paster_create_template] # dbsprockets=sprox.instance.newSprox:Template # """, ) sprox-0.6.4/sprox/0000755000076700000240000000000011236057646013645 5ustar cperkins1staffsprox-0.6.4/sprox/__init__.py0000644000076700000240000000000011123744670015737 0ustar cperkins1staffsprox-0.6.4/sprox/configbase.py0000644000076700000240000001557311211237554016321 0ustar cperkins1stafffrom formencode.validators import Validator from tw.api import Widget from sprox.providerselector import ProviderTypeSelector class ConfigBaseError(Exception):pass class ConfigBase(object): """ Base class for all configurable classes in Sprox. :Modifiers: +-----------------------------------+--------------------------------------------+------------------------------+ | Name | Description | Default | +===================================+============================================+==============================+ | __entity__ (__model__) | Entity used for metadata extraction. | None | +-----------------------------------+--------------------------------------------+------------------------------+ | __sprox_id_ | Id for use in the widget. | None | +-----------------------------------+--------------------------------------------+------------------------------+ | __provider_type_selector_type__ | A type for selecting the provider. | ProviderTypeSelector | +-----------------------------------+--------------------------------------------+------------------------------+ | __field_order__ | A list of ordered field names. | None | +-----------------------------------+--------------------------------------------+------------------------------+ | __hide_fields__ | Fields marked as hidden. | [] | +-----------------------------------+--------------------------------------------+------------------------------+ | __add_fields__ | Additional fields to add to the config. | {} | +-----------------------------------+--------------------------------------------+------------------------------+ | __disable_fields__ | Field marked as disabled. | [] | +-----------------------------------+--------------------------------------------+------------------------------+ | __omit_fields__ | Fields removed from the field list. | [] | +-----------------------------------+--------------------------------------------+------------------------------+ | __limit_fields__ | Limit the field list to this. | None | +-----------------------------------+--------------------------------------------+------------------------------+ | __field_attrs__ | attr parmater to set to the field. | {} | +-----------------------------------+--------------------------------------------+------------------------------+ | __metadata_type__ | Metadata associated with this config. | None | +-----------------------------------+--------------------------------------------+------------------------------+ """ # what object does will this object use for metadata extraction # model and entity are one in the same __model__ = __entity__ = None # this is used by catwalk's validate decorator to lookup the sprocket in the cache __sprox_id__ = None #How should we select a provider __provider_type_selector_type__ = ProviderTypeSelector # field overrides __field_order__ = None __hide_fields__ = None __disable_fields__ = None __omit_fields__ = None __add_fields__ = None __limit_fields__ = None __field_attrs__ = None __metadata_type__ = None def __init__(self, provider_hint=None, **provider_hints): #map __model__ to __entity__, this may be deprecated if self.__entity__ is None and self.__model__ is not None: self.__entity__ = self.__model__ self.__provider_type_selector__ = self.__provider_type_selector_type__() self.provider_hint = provider_hint self.provider_hints = provider_hints self._do_init_attrs() def __remove_duplicates(self, l): l2 = [] for i in l: if i not in l2 and i is not None: l2.append(i) return l2 @property def __fields__(self): return self._do_get_fields() def _do_get_fields(self): fields = [] if self.__field_order__ is not None: #this makes sure all the ordered fields bubble to the start of the list fields.extend(self.__field_order__) if self.__limit_fields__ is not None: fields.extend(self.__limit_fields__) fields.extend(self.__hide_fields__) fields.extend(self.__add_fields__.keys()) fields = self.__remove_duplicates(fields) return fields else: fields = self.__metadata__.keys() fields.extend(self.__add_fields__.keys()) fields.extend(self.__hide_fields__) if self.__field_order__ is not None: fields = set(fields) field_order = set(self.__field_order__) extra_fields = fields.difference(field_order) fields = self.__field_order__+list(extra_fields) for field in self.__omit_fields__: while field in fields: fields.remove(field) r = [] for field in fields: if field not in r and field is not None: r.append(field) return r @property def __metadata__(self): if not hasattr(self, '___metadata__'): if self.__metadata_type__ is None: raise ConfigBaseError('You must define a __metadata_type__ attribute for this object') self.___metadata__=self.__metadata_type__(self.__provider__, self.__entity__) return self.___metadata__ @property def __provider__(self): if self.__entity__ is None: raise ConfigBaseError('You must define a __entity__ attribute for this object') return self.__provider_type_selector__.get_selector(self.__entity__).get_provider(self.__entity__, self.provider_hint, **self.provider_hints) def _do_init_attrs(self): if self.__hide_fields__ is None: self.__hide_fields__ = [] if self.__disable_fields__ is None: self.__disable_fields__ = [] if self.__omit_fields__ is None: self.__omit_fields__ = [] if self.__add_fields__ is None: self.__add_fields__ = {} if self.__field_attrs__ is None: self.__field_attrs__ = {} sprox-0.6.4/sprox/dojo/0000755000076700000240000000000011236057646014600 5ustar cperkins1staffsprox-0.6.4/sprox/dojo/__init__.py0000644000076700000240000000000011131150323016653 0ustar cperkins1staffsprox-0.6.4/sprox/dojo/fillerbase.py0000755000076700000240000000156611211004607017253 0ustar cperkins1staff""" fillerbase Module Classes to help fill widgets with data Copyright (c) 2008 Christopher Perkins Original Version by Christopher Perkins 2008 Released under MIT license. """ from sprox.fillerbase import TableFiller class DojoTableFiller(TableFiller): def get_value(self, value=None, **kw): offset = kw.get('start', None) limit = kw.get('count', None) order_by = kw.get('sort', None) desc = False if order_by is not None and order_by.startswith('-'): order_by = order_by[1:] desc = True items = super(DojoTableFiller, self).get_value(value, limit=limit, offset=offset, order_by=order_by, desc=desc, **kw) count = self.get_count() identifier = self.__provider__.get_primary_field(self.__entity__) return dict(identifier=identifier, numRows=count, totalCount=count, items=items) sprox-0.6.4/sprox/dojo/formbase.py0000644000076700000240000001616611236045316016751 0ustar cperkins1staff""" fillerbase Module Classes to help fill widgets with data Copyright (c) 2008 Christopher Perkins Original Version by Christopher Perkins 2008 Released under MIT license. """ from sprox.formbase import FormBase, EditableForm, AddRecordForm from sprox.widgetselector import SAWidgetSelector from sprox.widgets.dojo import SproxDojoSelectShuttleField, SproxDojoSortedSelectShuttleField class DojoSAWidgetSelector(SAWidgetSelector): """Dojo-Specific Widget Selector""" default_multiple_select_field_widget_type = SproxDojoSelectShuttleField class DojoFormBase(FormBase): """FormBase for Dojo see :class:`sprox.formbase.FormBase` """ __widget_selector_type__ = DojoSAWidgetSelector class DojoEditableForm(EditableForm): """Creates a form for editing records that has select shuttles for the multiple relations. :Modifiers: see :class:`sprox.formbase.FormBase` :Usage: >>> from sprox.dojo.formbase import DojoEditableForm >>> from formencode import Schema >>> from formencode.validators import FieldsMatch >>> class Form(DojoEditableForm): ... __model__ = User ... __limit_fields__ = ['user_name', 'groups'] >>> edit_form = Form() >>> print edit_form() # doctest: +XML
Available



Selected
""" __widget_selector_type__ = DojoSAWidgetSelector class DojoAddRecordForm(AddRecordForm): """ Creates a form for adding records that has select shuttles for the multiple relations. :Modifiers: see :class:`sprox.formbase.FormBase` :Usage: >>> from sprox.dojo.formbase import DojoAddRecordForm >>> from formencode import Schema >>> from formencode.validators import FieldsMatch >>> class Form(DojoAddRecordForm): ... __model__ = User ... __limit_fields__ = ['user_name', 'groups'] >>> add_form = Form() >>> print add_form() # doctest: +XML
Available



Selected
""" __widget_selector_type__ = DojoSAWidgetSelector sprox-0.6.4/sprox/dojo/sprockets.py0000644000076700000240000000360411131150323017146 0ustar cperkins1staff""" Sprockets Module This is sort of like the central nervous system of sprox. Views and Sessions are collected in separate caches and served up as sprockets. The cache objects may be solidified at some point with a parent class. They work for right now. Classes: Name Description SprocketCache A cache of Sprockets Sprocket A binding of Filler and View configs ConfigCache Individual configs cached Functions: None Copyright (c) 2007 Christopher Perkins Original Version by Christopher Perkins 2007 Released under MIT license. """ from sprox.sprockets import ConfigCache, SprocketCache from sprox.providerselector import SAORMSelector from sprox.formbase import FormBase, AddRecordForm, EditableForm from sprox.entitiesbase import EntitiesBase, EntityDefBase from sprox.fillerbase import ModelsFiller, ModelDefFiller, EditFormFiller, AddFormFiller, FormFiller from fillerbase import DojoTableFiller from tablebase import DojoTableBase class ViewCache(ConfigCache): default_configs = { 'model_view' : EntitiesBase, 'edit' : EditableForm, 'add' : AddRecordForm, 'listing' : DojoTableBase, 'metadata' : EntityDefBase, } json_url = 'data' def __getitem__(self, key): view = super(ViewCache, self).__getitem__(key) return view class FillerCache(ConfigCache): default_configs = { 'model_view' : ModelsFiller, 'metadata' : ModelDefFiller, 'view' : FormFiller, 'listing' : DojoTableFiller, 'edit' : EditFormFiller, 'add' : AddFormFiller, } class DojoSprocketCache(SprocketCache): view_type = ViewCache filler_type = FillerCachesprox-0.6.4/sprox/dojo/tablebase.py0000755000076700000240000000263211211004607017060 0ustar cperkins1stafffrom tw.dojo import DojoJsonRestStore from sprox.widgets.dojo import SproxEditableDojoGrid, SproxDojoGrid from sprox.tablebase import TableBase from sprox.metadata import FieldsMetadata class DojoTableBase(TableBase): """This class allows you to credate a table widget. :Modifiers: see modifiers in :mod:`sprox.tablebase` """ #object overrides __base_widget_type__ = SproxDojoGrid __url__ = None __column_options__ = {} def _do_get_widget_args(self): args = super(DojoTableBase, self)._do_get_widget_args() if self.__url__ is not None: args['action'] = self.__url__ args['columns'] = self.__fields__ args['column_options'] = self.__column_options__ args['headers'] = self.__headers__ args['jsId'] = self.__sprox_id__ return args """ Experimental for next version. Will not be included in 0.5""" class DojoEditableTableBase(TableBase): __base_widget_type__ = SproxEditableDojoGrid __url__ = None __column_options__ = {} def _do_get_widget_args(self): args = super(DojoEditableTableBase, self)._do_get_widget_args() if self.__url__ is not None: args['action'] = self.__url__ args['columns'] = self.__fields__ args['column_options'] = self.__column_options__ args['headers'] = self.__headers__ args['jsId'] = self.__sprox_id__ return args sprox-0.6.4/sprox/dummyentity.py0000644000076700000240000000002711133413505016570 0ustar cperkins1staffclass DummyEntity:pass sprox-0.6.4/sprox/entitiesbase.py0000644000076700000240000000651211135127077016674 0ustar cperkins1staffimport inspect from sprox.widgets import ContainerWidget, TableWidget from viewbase import ViewBase from widgetselector import EntitiesViewWidgetSelector, EntityDefWidgetSelector from sprox.metadata import EntitiesMetadata, FieldsMetadata class EntityDefBase(ViewBase): """This view can display all of the entities for a given provider. :Modifiers: see :mod:`sprox.viewbase.ViewBase` :Usage: >>> from sprox.entitiesbase import EntityDefBase >>> class UserEntityDef(EntityDefBase): ... __entity__ = User >>> base = UserEntityDef(session) >>> print base()
NameDefinition
password Unicode(length=40)
user_id Integer()
user_name Unicode(length=16)
email_address Unicode(length=255)
display_name Unicode(length=255)
created DateTime(timezone=False)
town_id Integer()
town relation
password relation
groups relation
""" __base_widget_type__ = TableWidget __widget_selector_type__ = EntityDefWidgetSelector __metadata_type__ = FieldsMetadata from dummyentity import DummyEntity class EntitiesBase(ViewBase): """This view can display all of the entities for a given provider. :Modifiers: see :mod:`sprox.viewbase.ViewBase` :Usage: >>> from sprox.entitiesbase import EntitiesBase >>> class MyEntitiesBase(EntitiesBase): ... __entity__ = User >>> base = MyEntitiesBase(session, metadata=metadata) >>> print base()
Document
Example
Group
Permission
Town
User
""" __entity__ = DummyEntity __base_widget_type__ = ContainerWidget __widget_selector_type__ = EntitiesViewWidgetSelector __metadata_type__ = EntitiesMetadata sprox-0.6.4/sprox/fillerbase.py0000644000076700000240000002464311212321666016326 0ustar cperkins1staff""" fillerbase Module Classes to help fill widgets with data Copyright (c) 2008 Christopher Perkins Original Version by Christopher Perkins 2008 Released under MIT license. """ from configbase import ConfigBase, ConfigBaseError from metadata import FieldsMetadata from genshi import XML import inspect class FillerBase(ConfigBase): """ :Modifiers: see :mod:`sprox.configbase`. The base filler class. :Arguments: values pass through of values. This is typically a set of default values that is updated by the filler. This is useful when updating an existing form. kw Set of keyword arguments for assisting the fill. This is for instance information like offset and limit for a TableFiller. :Usage: >>> filler = FillerBase() >>> filler.get_value() {} """ def get_value(self, values=None, **kw): """ The main function for getting data to fill widgets, """ if values is None: values = {} return values class ModelsFiller(FillerBase): pass class ModelDefFiller(FillerBase): pass class FormFiller(FillerBase): __metadata_type__ = FieldsMetadata def get_value(self, values=None, **kw): values = super(FormFiller, self).get_value(values) values['sprox_id'] = self.__sprox_id__ return values class TableFiller(FillerBase): """ This is the base class for generating table data for use in table widgets. The TableFiller uses it's provider to obtain a dictionary of information about the __entity__ this Filler defines. This class is especially useful when you need to return a json stream, because it allows for customization of attributes. A package which has similar functionality to this is TurboJson, but TurboJson is rules-based, where the semantics for generating dictionaries follows the same :mod:`sprox.configbase` methodology. Modifiers defined in this class +-----------------------------------+--------------------------------------------+------------------------------+ | Name | Description | Default | +===================================+============================================+==============================+ | __actions__ | An overridable function to define how to | a function that creates an | | | display action links in the form. | edit and delete link. | +-----------------------------------+--------------------------------------------+------------------------------+ | __metadata_type__ | How should we get data from the provider. | FieldsMetadata | +-----------------------------------+--------------------------------------------+------------------------------+ | __possible_field_names__ | See explanation below. | See below. | +-----------------------------------+--------------------------------------------+------------------------------+ see modifiers also in :mod:`sprox.configbase`. :Relations: By default, TableFiller will populate relations (join or foreign_key) with either the value from the related table, or a comma-separated list of values. These values are derived from the related object given the field names provided by the __possible_field_names__ modifier. For instance, if you have a User class which is related to Groups, the groups item in the result dictionaries will be populated with Group.group_name. The default field names are: _name, name, description, title. :RESTful Actions: By default, Table filler provides an "__actions__" item in the resultant dictionary list. This provides and edit, and (javascript) delete link which provide edit and DELETE functionality as HTML verbs in REST. For more information on developing RESTful URLs, please visit `http://microformats.org/wiki/rest/urls `_ . :Usage: Here is how we would get the values to fill up a user's table, minus the action column, and created date. >>> class UsersFiller(TableFiller): ... __model__ = User ... __actions__ = False ... __omit_fields__ = ['created'] >>> users_filler = UsersFiller(session) >>> value = users_filler.get_value(values={}, limit=20, offset=0) >>> print value #doctest: +IGNORE_WHITESPACE [{'town': u'Arvada', 'user_id': u'1', 'user_name': u'asdf', 'town_id': u'1', 'groups': u'4', '_password': '******', 'password': '******', 'email_address': u'asdf@asdf.com', 'display_name': u'None'}] """ __actions__ = True __metadata_type__ = FieldsMetadata __possible_field_names__ = ['_name', 'name', 'description', 'title'] def _get_list_data_value(self, field, values): l = [] for value in values: if not isinstance(value, basestring): name = self.__provider__.get_view_field_name(value.__class__, self.__possible_field_names__) l.append(unicode(getattr(value, name))) else: #this is needed for postgres to see array values return values return ', '.join(l) def _get_relation_value(self, field, value): #this may be needed for catwalk, but I am not sure what conditions cause it to be needed #if value is None: # return None name = self.__provider__.get_view_field_name(value.__class__, self.__possible_field_names__) return getattr(value, name) def get_count(self): """Returns the total number of items possible for retrieval. This can only be executed after a get_value() call. This call is useful for creating pagination in the context of a user interface. """ if not hasattr(self, '__count__'): raise ConfigBaseError('Count not yet set for filler. try calling get_value() first.') return self.__count__ def _do_get_fields(self): fields = super(TableFiller, self)._do_get_fields() if '__actions__' not in self.__omit_fields__ and '__actions__' not in fields: fields.insert(0, '__actions__') return fields def __actions__(self, obj): """Override this function to define how action links should be displayed for the given record.""" primary_fields = self.__provider__.get_primary_fields(self.__entity__) pklist = '/'.join(map(lambda x: str(getattr(obj, x)), primary_fields)) value = '
 edit'\ '
'\ '
'\ ''\ ''\ '
'\ '
' return value def _do_get_provider_count_and_objs(self, **kw): limit = kw.get('limit', None) offset = kw.get('offset', None) order_by = kw.get('order_by', None) desc = kw.get('desc', False) count, objs = self.__provider__.query(self.__entity__, limit, offset, self.__limit_fields__, order_by, desc) self.__count__ = count return count, objs def get_value(self, values=None, **kw): """ Get the values to fill a form widget. :Arguments: offset offset into the records limit number of records to return order_by name of the column to the return values ordered by desc order the columns in descending order """ count, objs = self._do_get_provider_count_and_objs(**kw) self.__count__ = count rows = [] for obj in objs: row = {} for field in self.__fields__: field_method = getattr(self, field, None) if inspect.ismethod(field_method): argspec = inspect.getargspec(field_method) if argspec and (len(argspec[0])-2>=len(kw) or argspec[2]): value = getattr(self, field)(obj, **kw) else: value = getattr(self, field)(obj) else: value = getattr(obj, field) if 'password' in field.lower(): row[field] = '******' continue elif isinstance(value, list): value = self._get_list_data_value(field, value) elif self.__provider__.is_relation(self.__entity__, field) and value is not None: value = self._get_relation_value(field, value) elif self.__provider__.is_binary(self.__entity__, field) and value is not None: value = '' row[field] = unicode(value) rows.append(row) return rows class EditFormFiller(FormFiller): """ This class will help to return a single record for use within a form or otherwise. The values are returned in dictionary form. :Modifiers: see :mod:`sprox.configbase`. :Usage: >>> class UserFiller(EditFormFiller): ... __model__ = User >>> users_filler = UsersFiller(session) >>> value = users_filler.get_value(values={'user_id':'1'}) >>> value # doctest: +SKIP {'town': u'Arvada', 'user_id': u'1', 'created': u'2008-12-28 17:33:11.078931', 'user_name': u'asdf', 'town_id': u'1', 'groups': u'4', '_password': '******', 'password': '******', 'email_address': u'asdf@asdf.com', 'display_name': u'None'} """ def get_value(self, values=None, **kw): values = super(EditFormFiller, self).get_value(values, **kw) values = self.__provider__.get(self.__entity__, params=values) return values class RecordFiller(EditFormFiller):pass class AddFormFiller(FormFiller): def get_value(self, values=None, **kw): """xxx: get the server/entity defaults.""" kw = super(AddFormFiller, self).get_value(values, **kw) return self.__provider__.get_default_values(self.__entity__, params=values)sprox-0.6.4/sprox/formbase.py0000644000076700000240000006064111236045467016022 0ustar cperkins1staff""" formbase Module Classes to create form widgets. Copyright (c) 2008 Christopher Perkins Original Version by Christopher Perkins 2008 Released under MIT license. """ import inspect from tw.api import Widget from tw.forms import HiddenField, TableForm from viewbase import ViewBase, ViewBaseError from formencode import Schema, All from formencode import Validator from sprox.validators import UniqueValue from formencode.validators import UnicodeString, String from widgetselector import SAWidgetSelector from sprox.metadata import FieldsMetadata from validatorselector import SAValidatorSelector from sprox.widgets.widgets import SproxMethodPutHiddenField class FilteringSchema(Schema): """This makes formencode work for most forms, because some wsgi apps append extra values to the parameter list.""" filter_extra_fields = True allow_extra_fields = True class Field(object): """Used to handle the case where you want to override both a validator and a widget for a given field""" def __init__(self, widget=None, validator=None): self.widget = widget self.validator = validator class FormBase(ViewBase): """ :Modifiers: Modifiers defined in this class +-----------------------------------+--------------------------------------------+------------------------------+ | Name | Description | Default | +===================================+============================================+==============================+ | __base_widget_type__ | What widget to use for the form. | TableForm | +-----------------------------------+--------------------------------------------+------------------------------+ | __widget_selector_type__ | What class to use for widget selection. | SAWidgetSelector | +-----------------------------------+--------------------------------------------+------------------------------+ | __validator_selector_type__ | What class to use for validator selection. | SAValidatorSelector | +-----------------------------------+--------------------------------------------+------------------------------+ | __require_fields__ | Specifies which fields are required. | [] | +-----------------------------------+--------------------------------------------+------------------------------+ | __check_if_unique__ | Set this to True for "new" forms. This | False | | | causes Sprox to check if there is an | | | | existing record in the database which | | | | matches the field data. | | +-----------------------------------+--------------------------------------------+------------------------------+ | __field_validators__ | A dictionary of validators indexed by | {} | | | fieldname. | | +-----------------------------------+--------------------------------------------+------------------------------+ | __field_validator_types__ | Types of validators to use for each field | {} | | | (allow sprox to set the attribute of the | | | | validators). | | +-----------------------------------+--------------------------------------------+------------------------------+ | __base_validator__ | A validator to attch to the form. | None | +-----------------------------------+--------------------------------------------+------------------------------+ | __validator_selector__ | What object to use to select field | None | | | validators. | | +-----------------------------------+--------------------------------------------+------------------------------+ | __metadata_type__ | What metadata type to use to get schema | FieldsMetadata | | | info on this object | | +-----------------------------------+--------------------------------------------+------------------------------+ | __dropdown_field_names__ | list or dict of names to use for discovery | None | | | of field names for dropdowns (None uses | | | | sprox default names.) | | | | a dict provides field-level granularity | | +-----------------------------------+--------------------------------------------+------------------------------+ Modifiers inherited from :class:`sprox.viewbase.ViewBase` +-----------------------------------+--------------------------------------------+------------------------------+ | Name | Description | Default | +===================================+============================================+==============================+ | __field_widgets__ | A dictionary of widgets to replace the | {} | | | ones that would be chosen by the selector | | +-----------------------------------+--------------------------------------------+------------------------------+ | __field_widget_types__ | A dictionary of types of widgets, allowing | {} | | | sprox to determine the widget args | | +-----------------------------------+--------------------------------------------+------------------------------+ | __widget_selector__ | an instantiated object to use for widget | None | | | selection. | | +-----------------------------------+--------------------------------------------+------------------------------+ Modifiers inherited from :class:`sprox.configbase.ConfigBase` :Example Usage: One of the more useful things sprox does for you is to fill in the arguments to a drop down automatically. Here is the userform, limited to just the town field, which gets populated with the towns. >>> from sprox.formbase import FormBase >>> class UserOnlyTownForm(FormBase): ... __model__ = User ... __limit_fields__ = ['town'] >>> >>> town_form = UserOnlyTownForm(session) >>> >>> print town_form() # doctest: +XML
Forms created with sprox can be validated as you would any other widget. >>> class UserOnlyTownForm(FormBase): ... __model__ = User ... __limit_fields__ = ['town'] ... __required_fields__ = ['town'] >>> town_form = UserOnlyTownForm(session) >>> town_form.validate(params={'sprox_id':1}) Traceback (most recent call last): ... Invalid: town: Missing value """ __require_fields__ = None __check_if_unique__ = False #object overrides __base_widget_type__ = TableForm __widget_selector_type__ = SAWidgetSelector __validator_selector__ = None __validator_selector_type__ = SAValidatorSelector __field_validators__ = None __field_validator_types__ = None __base_validator__ = FilteringSchema __metadata_type__ = FieldsMetadata __dropdown_field_names__ = None def _do_init_attrs(self): super(FormBase, self)._do_init_attrs() if self.__require_fields__ is None: self.__require_fields__ = [] if self.__field_validators__ is None: self.__field_validators__ = {} if self.__validator_selector__ is None: self.__validator_selector__ = self.__validator_selector_type__(self.__provider__) if self.__field_validator_types__ is None: self.__field_validator_types__ = {} if self.__dropdown_field_names__ is None: self.__dropdown_field_names__ = ['name', '_name', 'description', '_description'] #bring in custom declared validators for attr in dir(self): if not attr.startswith('__'): value = getattr(self, attr) if isinstance(value, Field): widget = value.widget if isinstance(widget, Widget): if not getattr(widget, 'id', None): raise ViewBaseError('Widgets must provide an id argument for use as a field within a ViewBase') self.__add_fields__[attr] = widget try: if issubclass(widget, Widget): self.__field_widget_types__[attr] = widget except TypeError: pass validator = value.validator if isinstance(validator, Validator): self.__field_validators__[attr] = validator try: if issubclass(validator, Validator): self.__field_validator_types__[attr] = validator except TypeError: pass if isinstance(value, Validator): self.__field_validators__[attr] = value continue try: if issubclass(value, Validator): self.__field_validator_types__[attr] = value except TypeError: pass def validate(self, params, state=None): """A pass-thru to the widget's validate function.""" return self.__widget__.validate(params, state) def _do_get_widget_args(self): """Override this method to define how the class get's the arguments for the main widget """ d = super(FormBase, self)._do_get_widget_args() if self.__base_validator__ is not None: d['validator'] = self.__base_validator__ return d def _do_get_field_widget_args(self, field_name, field): """Override this method do define how this class gets the field widget arguemnts """ args = super(FormBase, self)._do_get_field_widget_args( field_name, field) v = self.__field_validators__.get(field_name, self._do_get_field_validator(field_name, field)) if self.__provider__.is_relation(self.__entity__, field_name): args['entity'] = self.__entity__ args['field_name'] = field_name if isinstance(self.__dropdown_field_names__, dict) and field_name in self.__dropdown_field_names__: view_names = self.__dropdown_field_names__[field_name] if not isinstance(view_names, list): view_names = [view_names] args['dropdown_field_names'] = view_names elif isinstance(self.__dropdown_field_names__, list): args['dropdown_field_names'] = self.__dropdown_field_names__ if v: args['validator'] = v return args def _do_get_fields(self): """Override this function to define how """ fields = super(FormBase, self)._do_get_fields() if 'sprox_id' not in fields: fields.append('sprox_id') return fields def _do_get_field_widgets(self, fields): widgets = super(FormBase, self)._do_get_field_widgets(fields) widgets['sprox_id'] = HiddenField('sprox_id') return widgets def _do_get_field_validator(self, field_name, field): """Override thius function to define how a field validator is chosen for a given field. """ v_type = self.__field_validator_types__.get(field_name, self.__validator_selector__[field]) if field_name in self.__require_fields__ and v_type is None: v_type = String if v_type is None: return args = self._do_get_validator_args(field_name, field, v_type) v = v_type(**args) if hasattr(field, 'unique') and field.unique and self.__check_if_unique__: v = All(UniqueValue(self.__provider__, self.__entity__, field_name), v) return v def _do_get_validator_args(self, field_name, field, validator_type): """Override this function to define how to get the validator arguments for the field's validator. """ args = {} args['not_empty'] = (not self.__provider__.is_nullable(self.__entity__, field_name)) or \ field_name in self.__require_fields__ if hasattr(field, 'type') and hasattr(field.type, 'length') and\ issubclass(validator_type, String): args['max'] = field.type.length return args class EditableForm(FormBase): """A form for editing a record. :Modifiers: see :class:`sprox.formbase.FormBase` """ def _do_get_disabled_fields(self): fields = self.__disable_fields__[:] fields.append(self.__provider__.get_primary_field(self.__entity__)) return fields def _do_get_fields(self): """Override this function to define how """ fields = super(EditableForm, self)._do_get_fields() if '_method' not in fields: fields.append('_method') return fields def _do_get_field_widgets(self, fields): widgets = super(EditableForm, self)._do_get_field_widgets(fields) widgets['_method'] = SproxMethodPutHiddenField(id='_method', validator=String(if_missing=None)) return widgets __check_if_unique__ = False class AddRecordForm(FormBase): """An editable form who's purpose is record addition. :Modifiers: see :class:`sprox.formbase.FormBase` +-----------------------------------+--------------------------------------------+------------------------------+ | Name | Description | Default | +===================================+============================================+==============================+ | __check_if_unique__ | Set this to True for "new" forms. This | True | | | causes Sprox to check if there is an | | | | existing record in the database which | | | | matches the field data. | | +-----------------------------------+--------------------------------------------+------------------------------+ Here is an example registration form, as generated from the vase User model. >>> from sprox.formbase import AddRecordForm >>> from formencode import Schema >>> from formencode.validators import FieldsMatch >>> from tw.forms import PasswordField, TextField >>> form_validator = Schema(chained_validators=(FieldsMatch('password', ... 'verify_password', ... messages={'invalidNoMatch': ... 'Passwords do not match'}),)) >>> class RegistrationForm(AddRecordForm): ... __model__ = User ... __require_fields__ = ['password', 'user_name', 'email_address'] ... __omit_fields__ = ['_password', 'groups', 'created', 'user_id', 'town'] ... __field_order__ = ['user_name', 'email_address', 'display_name', 'password', 'verify_password'] ... __base_validator__ = form_validator ... email_address = TextField ... display_name = TextField ... verify_password = PasswordField('verify_password') >>> registration_form = RegistrationForm() >>> print registration_form() # doctest: +XML
What is unique about the AddRecord form, is that if the fields in the database are labeled unique, it will automatically vaidate against uniqueness for that field. Here is a simple user form definition, where the user_name in the model is unique: >>> class AddUserForm(AddRecordForm): ... __entity__ = User ... __limit_fields__ = ['user_name'] >>> user_form = AddUserForm(session) >>> user_form.validate(params={'sprox_id':'asdf', 'user_name':u'asdf'}) # doctest: +SKIP Traceback (most recent call last): ... Invalid: user_name: That value already exists The validation fails because there is already a user with the user_name 'asdf' in the database """ __check_if_unique__ = True def _do_get_disabled_fields(self): fields = self.__disable_fields__[:] fields.append(self.__provider__.get_primary_field(self.__entity__)) return fields class DisabledForm(FormBase): """A form who's set of fields is disabled. :Modifiers: see :class:`sprox.formbase.FormBase` Here is an example disabled form with only the user_name and email fields. >>> from sprox.test.model import User >>> from sprox.formbase import DisabledForm >>> class DisabledUserForm(DisabledForm): ... __model__ = User ... __limit_fields__ = ['user_name', 'email_address'] >>> disabled_user_form = DisabledUserForm() >>> print disabled_user_form(values=dict(user_name='percious', email='chris@percious.com')) # doctest: +XML
You may notice in the above example that disabled fields pass in a hidden value for each disabled field. """ def _do_get_disabled_fields(self): return self.__fields__sprox-0.6.4/sprox/iprovider.py0000644000076700000240000000636211131150323016205 0ustar cperkins1staff""" iprovider Module This contains the class which allows dbsprockets to interface with any database. Copyright © 2008 Christopher Perkins Original Version by Christopher Perkins 2008 Released under MIT license. """ class IProvider: def get_field(self, entity, name): """Get a field with the given field name.""" raise NotImplementedError def get_fields(self, entity): """Get all of the fields for a given entity.""" raise NotImplementedError def get_entity(self, name): """Get an entity with the given name.""" raise NotImplementedError def get_entities(self): """Get all entities available for this provider.""" raise NotImplementedError def get_primary_fields(self, entity): """Get the fields in the entity which uniquely identifies a record.""" raise NotImplementedError def get_primary_field(self, entity): """Get the single primary field for an entity""" raise NotImplementedError def get_view_field_name(self, entity, possible_names): """Get the name of the field which first matches the possible colums :Arguments: entity the entity where the field is located possible_names a list of names which define what the view field may contain. This allows the first field that has a name in the list of names will be returned as the view field. """ raise NotImplementedError def get_dropdown_options(self, entity, field_name, view_names=None): """Get all dropdown options for a given entity field. :Arguments: entity the entity where the field is located field_name name of the field in the entity view_names a list of names which define what the view field may contain. This allows the first field that has a name in the list of names will be returned as the view field. :Returns: A list of tuples with (id, view_value) as items. """ raise NotImplementedError def get_relations(self, entity): """Get all of the field names in an enity which are related to other entities.""" raise NotImplementedError def is_relation(self, entity, field_name): """Determine if a field is related to a field in another entity.""" raise NotImplementedError def is_nullable(self, entity, field_name): """Determine if a field is nullable.""" raise NotImplementedError def get_default_values(self, entity, params): """Get the default values for form filling based on the database schema.""" raise NotImplementedError def create(self, entity, params): """Create an entry of type entity with the given params.""" raise NotImplementedError def get(self, entity, params): """Get a single entry of type entity which matches the params.""" raise NotImplementedError def update(self, entity, params): """Update an entry of type entity which matches the params.""" raise NotImplementedError def delete(self, entity, params): """Delete an entry of typeentity which matches the params.""" raise NotImplementedError sprox-0.6.4/sprox/metadata.py0000644000076700000240000000534511131150323015762 0ustar cperkins1staff""" matadata Module This contains the class which defines the generic interface for metadata. Basically, it provides an interface for how data is extracted from the provider for widget generation. Copyright (c) 2008 Christopher Perkins Original Version by Christopher Perkins 2007 Released under MIT license. """ from sprox.iprovider import IProvider class MetadataError(Exception):pass class NotFoundError(Exception):pass class Metadata(dict): """Base Metadata class Metadatas are dictionary-like. They map attributes of the entity they wrap, so that attributes of the entity can be examined without being explicitly set. Elements of a metadata can be set if they are not already part of the wrapped entity. This allows for customization of the metadata without modification to the wrapped metadata. """ def __init__(self, provider, entity=None): self.provider = provider self.entity = entity def __setitem__(self, key, value): self._do_check_set_item(key, value) dict.__setitem__(self, key, value) def _do_get_item(self, item): raise NotImplementedError def _do_keys(sekf): raise NotImplementedError def _do_check_set_item(self, key, value): raise NotImplementedError def __getitem__(self, item): try: value = self._do_get_item(item) return value except NotFoundError: return dict.__getitem__(self, item) def keys(self): r = self._do_keys() r.extend(dict.keys(self)) return r class EntitiesMetadata(Metadata): """A class to extract entities from a database definition. """ def _do_get_item(self, name): if name in self.provider.get_entities(): return self.provider.get_entity(name) raise NotFoundError def _do_keys(self): entities = sorted(self.provider.get_entities()) return entities class FieldsMetadata(Metadata): """A class to extract fields from an entity. """ def __init__(self, provider, entity): Metadata.__init__(self, provider, entity) self.provider = provider self.entity = entity def _do_check_set_item(self, key, value): if key in self.provider.get_fields(self.entity): raise MetadataError('%s is already found in entity: %s'%(key, self.entity)) def _do_get_item(self, item): try: return self.provider.get_field(self.entity, item) except: pass raise NotFoundError def _do_keys(self): return self.provider.get_fields(self.entity) class FieldMetadata(Metadata): """In the future, if the Field attributes need to be extracted, this is where it will happen. """ pass sprox-0.6.4/sprox/mootools/0000755000076700000240000000000011236057646015520 5ustar cperkins1staffsprox-0.6.4/sprox/mootools/__init__.py0000644000076700000240000000000011217767371017621 0ustar cperkins1staffsprox-0.6.4/sprox/mootools/formbase.py0000644000076700000240000000176011217772540017670 0ustar cperkins1staff""" Mootools Formbase Module Classes to create Mootools forms (client side validation!) Copyright (c) 2008 Christopher Perkins Original Version by Christopher Perkins 2008 Released under MIT license. """ from sprox.formbase import FormBase, EditableForm, AddRecordForm from sprox.widgetselector import SAWidgetSelector from sprox.widgets import TableForm from tw.mootools.forms import CustomisedForm #class MootoolsSAWidgetSelector(SAWidgetSelector): # """Mootools-Specific Widget Selector""" # default_multiple_select_field_widget_type = SproxMootoolsSelectShuttleField class MootoolsTableForm(TableForm, CustomisedForm):pass class MootoolsFormBase(FormBase): """FormBase for Mootools see :class:`sprox.formbase.FormBase` """ __base_widget_type__ = MootoolsTableForm # __widget_selector_type__ = MootoolsSAWidgetSelector class MootoolsEditableForm(EditableForm): # __widget_selector_type__ = MootoolsSAWidgetSelector __base_widget_type__ = MootoolsTableForm sprox-0.6.4/sprox/providerselector.py0000644000076700000240000001020611135127077017603 0ustar cperkins1staff""" Provider Locator Module a module to help dbsprockets automatically find providers Copyright (c) 2008 Christopher Perkins Original Version by Christopher Perkins 2007 Released under MIT license. """ import inspect from sqlalchemy import MetaData from sqlalchemy.engine import Engine from sqlalchemy.orm import _mapper_registry, class_mapper from sqlalchemy.orm.session import Session from sqlalchemy.orm.scoping import ScopedSession from sqlalchemy.orm.attributes import ClassManager from sprox.saormprovider import SAORMProvider from sprox.dummyentity import DummyEntity class ProviderSelector: def __init__(self): self._identifiers = {} self._entities = {} def get_entity(self, name, **hints): raise NotImplementedError def get_identifier(self, entity, **hints): raise NotImplementedError def get_provider(self, entity, **hints): raise NotImplementedError class _SAORMSelector(ProviderSelector): def __init__(self): self._providers = {} def _get_engine(self, hint, hints): metadata = hints.get('metadata', None) metadata = hints.get('metadata', None) engine = hints.get('engine', None) session = hints.get('session', None) if isinstance(hint, Engine): engine=hint if isinstance(hint, MetaData): metadata=hint if isinstance(hint, (Session, ScopedSession)): session = hint if session is not None and engine is None: engine = session.bind if metadata is not None and engine is None: engine = metadata.bind return engine def get_entity(self, identifier, hint=None, **hints): engine = self._get_engine(hint, hints) for mapper in _mapper_registry: if mapper.class_.__name__ == identifier: if engine is None: return mapper.class_ if engine is not None and mapper.tables[0].bind == engine: return mapper.class_ raise KeyError('could not find model by the name %s in %s'%(model_name, metadata)) def get_identifier(self, entity, **hints): return entity.__name__ def get_provider(self, entity=None, hint=None, **hints): """ :Arguments: Entity Mapped class to find a provider for hint/hints variables sent in to the provider to give more information about how the provider connects to the database. Get a provider related to the entity. (They should share the same engine) The provider's are cached as not to waste computation/memory. :Usage: >>> from sprox.providerselector import SAORMSelector >>> provider = SAORMSelector.get_provider(User, session=session) >>> provider.engine.url.drivername 'sqlite' """ if entity is None and isinstance(hint, Engine): engine = hint if engine not in self._providers: self._providers[engine] = SAORMProvider(hint, **hints) return self._providers[engine] if hint is None and entity is not None: mapper = class_mapper(entity) hint = mapper.tables[0].bind engine = self._get_engine(hint, hints) if engine not in self._providers: if hint is None and len(hints) == 0: hint = engine self._providers[engine] = SAORMProvider(hint, **hints) return self._providers[engine] SAORMSelector = _SAORMSelector() #XXX: #StormSelector = _StormSelector() #SOSelector = _SOSelector() class ProviderTypeSelectorError(Exception):pass class ProviderTypeSelector(object): def get_selector(self, entity=None, **hints): #use a SA Helper if hasattr(entity, '_sa_class_manager') and isinstance(entity._sa_class_manager, ClassManager): return SAORMSelector elif inspect.isclass(entity) and issubclass(entity, DummyEntity): return SAORMSelector #other helper definitions are going in here else: raise ProviderTypeSelectorError('Entity %s has no known provider mapping.'%entity) sprox-0.6.4/sprox/recordviewbase.py0000644000076700000240000000535211135127077017222 0ustar cperkins1stafffrom viewbase import ViewBase from metadata import FieldsMetadata from widgetselector import RecordViewWidgetSelector from widgets import RecordViewWidget class RecordViewBase(ViewBase): """This class allows you to create a view for a single record. :Modifiers: see modifiers in :mod:`sprox.viewbase` Here is an example listing of the first user in the test database. from sprox.test.base import User >>> class UserRecordView(RecordViewBase): ... __model__ = User ... __omit_fields__ = ['created'] >>> user_view = UserRecordView(session) >>> from sprox.fillerbase import RecordFiller >>> class UserRecordFiller(RecordFiller): ... __model__ = User >>> user_filler = UserRecordFiller(session) >>> value = user_filler.get_value({'user_id':1}) >>> print user_view(value=value)
NameValue
_password
user_id 1
user_name asdf
email_address asdf@asdf.com
display_name
town_id 1
town 1
password
groups 5
""" __metadata_type__ = FieldsMetadata __widget_selector_type__ = RecordViewWidgetSelector __base_widget_type__ = RecordViewWidget def _do_get_field_widget_args(self, field_name, field): """Override this method do define how this class gets the field widget arguemnts """ args = super(RecordViewBase, self)._do_get_field_widget_args( field_name, field) args['field_name'] = field_name if self.__provider__.is_relation(self.__entity__, field_name): args['entity'] = self.__entity__ args['field_name'] = field_name return argssprox-0.6.4/sprox/release.py0000644000076700000240000000002611236056672015633 0ustar cperkins1staff__version__ = "0.6.4" sprox-0.6.4/sprox/saormprovider.py0000644000076700000240000003242611226720162017107 0ustar cperkins1staff""" saprovider Module this contains the class which allows dbsprockets to interface with sqlalchemy. Classes: Name Description SAProvider sqlalchemy metadata/crud provider Exceptions: None Functions: None Copyright (c) 2007 Christopher Perkins Original Version by Christopher Perkins 2007 Released under MIT license. """ import inspect import re from sqlalchemy import and_, or_, DateTime, Date, Interval, Binary, MetaData, desc as _desc from sqlalchemy.engine import Engine from sqlalchemy.orm.session import Session from sqlalchemy.orm.scoping import ScopedSession from sqlalchemy.orm import class_mapper, Mapper, PropertyLoader, _mapper_registry, SynonymProperty, object_mapper from sqlalchemy.orm.exc import UnmappedClassError, NoResultFound, UnmappedInstanceError from sprox.iprovider import IProvider from cgi import FieldStorage from datetime import datetime, timedelta from warnings import warn class SAORMProviderError(Exception):pass class SAORMProvider(IProvider): def __init__(self, hint=None, **hints): """ initialize me with a engine, bound metadata or bound session object or a combination of the above. """ #if hint is None and len(hints) == 0: # raise SAORMProviderError('You must provide a hint to this provider') self.engine, self.session, self.metadata = self._get_engine(hint, hints) def _get_engine(self, hint, hints): metadata = hints.get('metadata', None) engine = hints.get('engine', None) session = hints.get('session', None) if isinstance(hint, Engine): engine=hint if isinstance(hint, MetaData): metadata=hint if isinstance(hint, (Session, ScopedSession)): session = hint if session is not None and engine is None: engine = session.bind if metadata is not None and engine is None: engine = metadata.bind return engine, session, metadata def get_fields(self, entity): if inspect.isfunction(entity): entity = entity() mapper = class_mapper(entity) field_names = mapper.c.keys() for prop in mapper.iterate_properties: try: getattr(mapper.c, prop.key) field_names.append(prop.key) except AttributeError: mapper.get_property(prop.key) field_names.append(prop.key) return field_names def get_entity(self, name): for mapper in _mapper_registry: if mapper.class_.__name__ == name: engine = mapper.tables[0].bind if engine is not None and mapper.tables[0].bind != self.engine: continue return mapper.class_ raise KeyError('could not find model by the name %s'%(name)) def get_entities(self): entities = [] for mapper in _mapper_registry: engine = mapper.tables[0].bind if engine is not None and mapper.tables[0].bind != self.engine: continue entities.append(mapper.class_.__name__) return entities def get_field(self, entity, name): mapper = class_mapper(entity) try: return getattr(mapper.c, name) except AttributeError: return mapper.get_property(name) def is_binary(self, entity, name): field = self.get_field(entity, name) if isinstance(field, PropertyLoader): field = field.local_side[0] # I am unsure what this is needed for, so it will be removed in the next version, and is for now # commented until someone reports a bug. #if not hasattr(field, 'type'): # return False return isinstance(field.type, Binary) def is_nullable(self, entity, name): field = self.get_field(entity, name) if isinstance(field, SynonymProperty): return if isinstance(field, PropertyLoader): return field.local_side[0].nullable return field.nullable def get_primary_fields(self, entity): #for now we are only supporting entities with a single primary field return [self.get_primary_field(entity)] def get_primary_field(self, entity): #sometimes entities get surrounded by functions, not sure why. if inspect.isfunction(entity): entity = entity() mapper = class_mapper(entity) for field_name in self.get_fields(entity): value = getattr(mapper.c, field_name) if value.primary_key: return value.key def get_view_field_name(self, entity, possible_names): fields = self.get_fields(entity) view_field = None for column_name in possible_names: for actual_name in fields: if column_name == actual_name: view_field = actual_name break if view_field: break; for actual_name in fields: if column_name in actual_name: view_field = actual_name break if view_field: break; if view_field is None: view_field = fields[0] return view_field def get_dropdown_options(self, entity, field_name, view_names=None): if view_names is None: view_names = ['_name', 'name', 'description', 'title'] if self.session is None: warn('No dropdown options will be shown for %s. ' 'Try passing the session into the initialization' 'of your form base object so that this sprocket' 'can have values in the drop downs'%entity) return [] field = self.get_field(entity, field_name) target_field = entity if isinstance(field, PropertyLoader): target_field = field.argument if inspect.isfunction(target_field): target_field = target_field() #some kind of relation if isinstance(target_field, Mapper): target_field = target_field.class_ pk_name = self.get_primary_field(target_field) view_name = self.get_view_field_name(target_field, view_names) rows = self.session.query(target_field).all() return [(getattr(row, pk_name), getattr(row, view_name)) for row in rows] def get_relations(self, entity): mapper = class_mapper(entity) return [prop.key for prop in mapper.iterate_properties if isinstance(prop, PropertyLoader)] def is_relation(self, entity, field_name): mapper = class_mapper(entity) if isinstance(mapper.get_property(field_name), PropertyLoader): return True def is_unique(self, entity, field_name, value): field = getattr(entity, field_name) try: self.session.query(entity).filter(field==value).one() except NoResultFound: return True return False def get_synonyms(self, entity): mapper = class_mapper(entity) return [prop.key for prop in mapper.iterate_properties if isinstance(prop, SynonymProperty)] def _modify_params_for_relationships(self, entity, params, delete_first=True): mapper = class_mapper(entity) relations = self.get_relations(entity) for relation in relations: if relation in params: prop = mapper.get_property(relation) target = prop.argument if inspect.isfunction(target): target = target() value = params[relation] if value: if prop.uselist and isinstance(value, list): target_obj = [] for v in value: try: object_mapper(v) target_obj.append(v) except UnmappedInstanceError: target_obj.append(self.session.query(target).get(v)) elif prop.uselist: try: object_mapper(value) target_obj = [value] except UnmappedInstanceError: target_obj = [self.session.query(target).get(value)] else: try: object_mapper(value) target_obj = value except UnmappedInstanceError: target_obj = self.session.query(target).get(value) params[relation] = target_obj else: del params[relation] return params def create(self, entity, params): params = self._modify_params_for_dates(entity, params) params = self._modify_params_for_relationships(entity, params) obj = entity() for key, value in params.iteritems(): if value is not None: setattr(obj, key, value) self.session.add(obj) self.session.flush() return obj def dictify(self, obj): if obj is None: return {} r = {} mapper = class_mapper(obj.__class__) for prop in mapper.iterate_properties: value = getattr(obj, prop.key) if value is not None: if isinstance(prop, PropertyLoader): klass = prop.argument if isinstance(klass, Mapper): klass = klass.class_ pk_name = self.get_primary_field(klass) if isinstance(value, list): #joins value = [getattr(value, pk_name) for value in value] else: #fks value = getattr(value, pk_name) r[prop.key] = value return r def get_default_values(self, entity, params): return params def get(self, entity, params): pk_name = self.get_primary_field(entity) obj = self.session.query(entity).get(params[pk_name]) return self.dictify(obj) def query(self, entity, limit=None, offset=None, limit_fields=None, order_by=None, desc=False, **kw): query = self.session.query(entity) count = query.count() if order_by is not None: field = self.get_field(entity, order_by) if desc: field = _desc(field) query = query.order_by(field) if offset is not None: query = query.offset(offset) if limit is not None: query = query.limit(limit) objs = query.all() return count, objs def _modify_params_for_dates(self, entity, params): mapper = class_mapper(entity) for key, value in params.iteritems(): if key in mapper.c and value is not None: field = mapper.c[key] if hasattr(field, 'type') and isinstance(field.type, DateTime) and not isinstance(value, datetime): dt = datetime.strptime(value[:19], '%Y-%m-%d %H:%M:%S') params[key] = dt if hasattr(field, 'type') and isinstance(field.type, Date) and not isinstance(value, datetime): dt = datetime.strptime(value, '%Y-%m-%d') params[key] = dt if hasattr(field, 'type') and isinstance(field.type, Interval) and not isinstance(value, timedelta): d = re.match( r'((?P\d+) days, )?(?P\d+):' r'(?P\d+):(?P\d+)', str(value)).groupdict(0) dt = timedelta(**dict(( (key, int(value)) for key, value in d.items() ))) params[key] = dt return params def _remove_related_empty_params(self, obj, params): entity = obj.__class__ mapper = class_mapper(entity) relations = self.get_relations(entity) for relation in relations: #clear out those items which are not found in the params list. if relation not in params or not params[relation]: related_items = getattr(obj, relation) if related_items is not None: if hasattr(related_items, '__iter__'): setattr(obj, relation, []) else: setattr(obj, relation, None) def update(self, entity, params): params = self._modify_params_for_dates(entity, params) params = self._modify_params_for_relationships(entity, params) pk_name = self.get_primary_field(entity) obj = self.session.query(entity).get(params[pk_name]) relations = self.get_relations(entity) for key, value in params.iteritems(): setattr(obj, key, value) self._remove_related_empty_params(obj, params) self.session.flush() return obj def delete(self, entity, params): pk_name = self.get_primary_field(entity) obj = self.session.query(entity).get(params[pk_name]) self.session.delete(obj) return obj sprox-0.6.4/sprox/sprockets.py0000644000076700000240000001054011131150323016210 0ustar cperkins1staff""" Sprockets Module This is sort of like the central nervous system of sprox. Views and Sessions are collected in separate caches and served up as sprockets. The cache objects may be solidified at some point with a parent class. They work for right now. Classes: Name Description SprocketCache A cache of Sprockets Sprocket A binding of Filler and View configs ConfigCache Individual configs cached Functions: None Copyright (c) 2007 Christopher Perkins Original Version by Christopher Perkins 2007 Released under MIT license. """ from providerselector import SAORMSelector from formbase import FormBase, AddRecordForm, EditableForm from tablebase import TableBase from entitiesbase import EntitiesBase, EntityDefBase from fillerbase import ModelsFiller, ModelDefFiller, EditFormFiller, AddFormFiller, FormFiller, TableFiller class ConfigCacheError(Exception): pass class ConfigCache(object): default_configs = {} def __init__(self, session, metadata=None): self.session = session self.metadata = metadata self._provider = SAORMSelector.get_provider(hint=session.bind, metadata=self.metadata) separator = '__' def _split_identifiers(self, key): separator = '__' if self.separator not in key: identifier = None view_type = key else: view_type, identifier = key.split(self.separator) return view_type, identifier def _get(self, key): view_type, identifier = self._split_identifiers(key) if view_type not in self.default_configs: raise ConfigCacheError('view_type:%s not found in default bases'%view_type) base = self.default_configs[view_type] if key != 'model_view': base.__entity__ = self._provider.get_entity(identifier) base.__provider__ = self._provider base.__sprox_id__ = key return base(self.session) def __getitem__(self, key): #xxx: turn caching back on #if key in self.__dict__: # return self.__dict__[key] view = self._get(key) #self.__dict__[key] = view return view class ViewCache(ConfigCache): default_configs = { 'model_view' : EntitiesBase, 'edit' : EditableForm, 'add' : AddRecordForm, 'listing' : TableBase, 'metadata' : EntityDefBase, } class FillerCache(ConfigCache): """ Container for Fillers """ default_configs = { 'model_view' : ModelsFiller, 'metadata' : ModelDefFiller, 'view' : FormFiller, 'listing' : TableFiller, 'edit' : EditFormFiller, 'add' : AddFormFiller, } class Sprocket: """Association between a view and a sessionConfig""" def __init__(self, view, filler): """Construct a Sprocket Object view a ``view`` object which has been instantiated from a ``ViewConfig`` filler defines how the view should be filled """ self.view = view self.filler = filler class SprocketCache(object): """Set of Associations between widgets and the method to obtain their data caching is disabled for now """ def __init__(self, session, metadata=None): self.views = self.view_type(session, metadata=metadata) self.fillers = self.filler_type(session, metadata=metadata) view_type = ViewCache filler_type = FillerCache sprocket_type = Sprocket def __getitem__(self, key): """ """ #xxx: enable caching #if key in self.__dict__: # import pdb; pdb.set_trace() # return self.__dict__.__getitem__(key) sprocket = self._get_sprocket(key) #self.__dict__[key] = sprocket return sprocket def _get_sprocket(self, key): view = self.views[key] filler = self.fillers[key] return self.sprocket_type(view, filler) #xxx: enable caching #def __setitem__(self, key, item): # return #if not isinstance(item, Sprocket): # raise TypeError('item must be of type Sprocket') #return self.__dict__.__setitem__(key, item) sprox-0.6.4/sprox/tablebase.py0000644000076700000240000002337011211240544016126 0ustar cperkins1stafffrom sprox.widgets import SproxDataGrid from viewbase import ViewBase from metadata import FieldsMetadata from tw.api import Widget from operator import itemgetter class TableBase(ViewBase): """This class allows you to create a table widget. :Modifiers: +-----------------------------------+--------------------------------------------+------------------------------+ | Name | Description | Default | +===================================+============================================+==============================+ | __base_widget_type__ | Base widget for fields to go into. | SproxDataGrid | +-----------------------------------+--------------------------------------------+------------------------------+ | __metadata_type__ | Type the widget is based on. | FieldsMetadata | +-----------------------------------+--------------------------------------------+------------------------------+ | __headers__ | A dictionay of field/header pairs. | {} | +-----------------------------------+--------------------------------------------+------------------------------+ | __column_widths__ | A dictionay of field/width(string) pairs. | {} | +-----------------------------------+--------------------------------------------+------------------------------+ | __default_column_width__ | Header size to use when not specified in | '10em' | | | __column_widths__ | | +-----------------------------------+--------------------------------------------+------------------------------+ | __xml_fields__ | fields whos values should show as html | | +-----------------------------------+--------------------------------------------+------------------------------+ see modifiers in :mod:`sprox.viewbase` Here is an example listing of the towns in the test database. >>> from sprox.tablebase import TableBase >>> class TownTable(TableBase): ... __model__ = Town >>> town_table = TownTable(session) >>> print town_table()
actions town_id name
No Records Found.
As you can see, this is none too interesting, because there is no data in the table. Here is how we fill the table with data using TableFillerBase >>> from sprox.fillerbase import TableFiller >>> class TownFiller(TableFiller): ... __model__ = Town >>> town_filler = TownFiller(session) >>> value = town_filler.get_value() >>> print town_table.__widget__(value=value) #doctest: +SKIP
town_id name
edit | delete 1Arvada
edit | delete 2Denver
edit | delete 3Golden
edit | delete 4Boulder
And now you can see the table has some data in it, and some restful links to the data. But what if you don't want those links? You can omit the links by adding '__actions__' to omitted fields as follows: >>> class TownTable(TableBase): ... __model__ = Town ... __omit_fields__ = ['__actions__'] >>> town_table = TownTable(session) >>> print town_table.__widget__(value=value)
town_id name
1 Arvada
2 Denver
3 Golden
4 Boulder
""" #object overrides __base_widget_type__ = SproxDataGrid __metadata_type__ = FieldsMetadata __headers__ = None __column_widths__ = None __xml_fields__ = None __default_column_width__ = "10em" def _do_get_fields(self): fields = super(TableBase, self)._do_get_fields() if '__actions__' not in self.__omit_fields__ and '__actions__' not in fields: fields.insert(0, '__actions__') if '__actions__' not in self.__headers__: self.__headers__['__actions__'] = 'actions' return fields def _do_init_attrs(self): super(TableBase, self)._do_init_attrs() if self.__headers__ is None: self.__headers__ = {} if self.__column_widths__ is None: self.__column_widths__ = {} if self.__xml_fields__ is None: self.__xml_fields__ = {} def _do_get_widget_args(self): args = super(TableBase, self)._do_get_widget_args() args['pks'] = None args['column_widths'] = self.__column_widths__ args['default_column_width'] = self.__default_column_width__ # Okay: the trunk version of Sprox creates its args['fields'] # very simply, as a list of lambdas that do an item lookup on # the field name. This means that TableBase inherently ignores # any attempt to specify widgets for displaying or formatting # model values; in fact, the field widget list that the # TableBase grows at some point during processing appears to be # completely ignored. (You will see if it you add "print" # statements around your code to watch how your tables are # behaving.) # To make widgets active, we need to put the widgets in place of # the lambdas in the the args['fields'] that we build. There # are challenges to building this list, however: # 1. The widgets supplied by default are useless. Instead of # being something that can actually display text, the list of # widgets somehow winds up just being bare Widget instances, # which seem to display absolutely nothing when rendered. # Therefore, when we see a bare Widget supplied for a # particular column, we need to ignore it. # 2. Some fields (like '__action__') do not even appear in our # list of fields-plus-widgets called self.__fields__, so we # have to be willing to fall back to a lambda in that case # too. # 3. For some reason, the list of field widgets is not always # present, so we have to wastefully re-compute it here by # calling the _do_get_field_widgets() method. It would be # nice if this were produced once before these computations # started and could be relied upon to be present, but it's # not so far as I could tell. But, then, I was reading code # late at night. # Anyway, with the stanza below, I am able to provide my table # classes with a __field_widget_types__ dictionary and have # those fields rendered differently. field_headers = [ self.__headers__.get(field, field) for field in self.__fields__ ] field_widget_dict = self._do_get_field_widgets(self.__fields__) field_widgets = [] for field in self.__fields__: widget = field_widget_dict.get(field, None) if widget is None or widget.__class__ is Widget: # yuck widget = itemgetter(field) field_widgets.append(widget) args['fields'] = zip(field_headers, field_widgets) # And, now back to our regularly-scheduled trunk-derived Sprox. if '__actions__' not in self.__omit_fields__: args['pks'] = self.__provider__.get_primary_fields(self.__entity__) args['xml_fields'] = self.__xml_fields__ return args sprox-0.6.4/sprox/test/0000755000076700000240000000000011236057646014624 5ustar cperkins1staffsprox-0.6.4/sprox/test/__init__.py0000644000076700000240000000000011131150323016677 0ustar cperkins1staffsprox-0.6.4/sprox/test/base.py0000644000076700000240000001254411217752012016102 0ustar cperkins1staffimport os, re from copy import copy from difflib import unified_diff from sqlalchemy import * from sqlalchemy.orm import * from model import * from cStringIO import StringIO from cgi import FieldStorage from tw import framework framework.default_view = 'mako' #try: import xml.etree.ElementTree as etree #except ImportError: # import cElementTree as etree session = None engine = None connect = None sorted_user_columns = ['_password', 'created', 'display_name', 'email_address', 'groups', 'password', 'sprox_id', 'town', 'town_id', 'user_id', 'user_name'] def remove_whitespace_nodes(node): new_node = copy(node) new_node._children = [] if new_node.text and new_node.text.strip() == '': new_node.text = '' if new_node.tail and new_node.tail.strip() == '': new_node.tail = '' for child in node.getchildren(): if child is not None: child = remove_whitespace_nodes(child) new_node.append(child) return new_node def remove_namespace(doc): """Remove namespace in the passed document in place.""" for elem in doc.getiterator(): match = re.match('(\{.*\})(.*)', elem.tag) if match: elem.tag = match.group(2) def replace_escape_chars(needle): needle = needle.replace(' ', ' ') return needle def fix_xml(needle): needle = replace_escape_chars(needle) needle_node = etree.fromstring(needle) needle_node = remove_whitespace_nodes(needle_node) remove_namespace(needle_node) needle_s = etree.tostring(needle_node) return needle_s def in_xml(needle, haystack): needle_s, haystack_s = map(fix_xml, (needle, haystack)) return needle_s in haystack_s def eq_xml(needle, haystack): needle_s, haystack_s = map(fix_xml, (needle, haystack)) return needle_s == haystack_s def assert_in_xml(needle, haystack): assert in_xml(needle, haystack), "%s not found in %s"%(needle, haystack) def assert_eq_xml(needle, haystack): assert eq_xml(needle, haystack), "%s does not equal %s"%(needle, haystack) database_setup=False def setup_database(): global session, engine, database_setup, connect, metadata #singletonizes things if not database_setup: engine = create_engine(os.environ.get('DBURL', 'sqlite://'), strategy="threadlocal") connect = engine.connect() # print 'testing on', engine metadata.bind = engine metadata.drop_all() metadata.create_all() Session = sessionmaker(bind=engine, autoflush=True, autocommit=False) session = Session() database_setup = True return session, engine, metadata records_setup = None def setup_records(session): session.expunge_all() user = User() user.user_name = u'asdf' user.email_address = u"asdf@asdf.com" user.password = u"asdf" session.add(user) arvada = Town(name=u'Arvada') session.add(arvada) session.flush() user.town = arvada session.add(Town(name=u'Denver')) session.add(Town(name=u'Golden')) session.add(Town(name=u'Boulder')) #test_table.insert(values=dict(BLOB=FieldStorage('asdf', StringIO()).value)).execute() #user_reference_table.insert(values=dict(user_id=user.user_id)).execute() # print user.user_id for i in range (5): group = Group(group_name=unicode(i)) session.add(group) user.groups.append(group) session.flush() return user def teardown_database(): pass #metadata.drop_all() def _reassign_from_metadata(): global visits_table, visit_identity_table, groups_table, town_table global users_table, permissions_table, user_group_table global group_permission_table, test_table visits_table = metadata.tables['visit'] visit_identity_table = metadata.tables['visit_identity'] groups_table = metadata.tables['tg_group'] town_table = metadata.tables['town_table'] users_table = metadata.tables['tg_user'] permissions_table = metadata.tables['permission'] user_group_table = metadata.tables['user_group'] group_permission_table = metadata.tables['group_permission'] test_table = metadata.tables['test_table'] def setup_reflection(): #if os.environ.get('AUTOLOAD', False): metadata.clear() metadata.reflect() _reassign_from_metadata() clear_mappers() tables = metadata.tables mapper(Town, tables['town_table']) mapper(Example, tables['test_table']) mapper(Visit, tables['visit']) mapper(VisitIdentity, tables['visit_identity'], properties=dict(users=relation(User, backref='visit_identity'))) mapper(User, tables['tg_user']) mapper(Group, tables['tg_group'], properties=dict(users=relation(User, secondary=tables['user_group'], backref='groups'))) mapper(Permission, tables['permission'], properties=dict(groups=relation(Group, secondary=tables['group_permission'], backref='permissions'))) class SproxTest(object): def setup(self): self.session = session self.engine = engine try: self.user = setup_records(session) except: self.session.rollback() def teardown(self): self.session.rollback() if __name__ == '__main__': setupDatabase() sprox-0.6.4/sprox/test/model.py0000644000076700000240000001707311226740743016302 0ustar cperkins1staff#most of this file was taken from turbogears default template from hashlib import sha1 import os import md5 import sha from datetime import datetime #from sqlalchemy.types import * from sqlalchemy import * from sqlalchemy.orm import relation, backref, synonym from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base, synonym_for DeclarativeBase = declarative_base() metadata = DeclarativeBase.metadata # This is the association table for the many-to-many relationship between # groups and permissions. group_permission_table = Table('tg_group_permission', metadata, Column('group_id', Integer, ForeignKey('tg_group.group_id', onupdate="CASCADE", ondelete="CASCADE")), Column('permission_id', Integer, ForeignKey('tg_permission.permission_id', onupdate="CASCADE", ondelete="CASCADE")) ) # This is the association table for the many-to-many relationship between # groups and members - this is, the memberships. user_group_table = Table('tg_user_group', metadata, Column('user_id', Integer, ForeignKey('tg_user.user_id', onupdate="CASCADE", ondelete="CASCADE")), Column('group_id', Integer, ForeignKey('tg_group.group_id', onupdate="CASCADE", ondelete="CASCADE")) ) # auth model 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) users = relation('User', secondary=user_group_table, backref='groups') def __repr__(self): return '' % self.group_name class Town(DeclarativeBase): __tablename__ = 'town' town_id = Column(Integer, primary_key=True) name = Column(String(32)) class User(DeclarativeBase): """Reasonably basic User definition. Probably would want additional attributes. """ __tablename__ = 'tg_user' user_id = Column(Integer, autoincrement=True, primary_key=True) user_name = Column(Unicode(16), unique=True) email_address = Column(Unicode(255), unique=True) display_name = Column(Unicode(255)) _password = Column('password', Unicode(40)) created = Column(DateTime, default=datetime.now) town_id = Column(Integer, ForeignKey('town.town_id')) town = relation(Town) def __repr__(self): return '' % ( self.email_address, self.display_name) @property def permissions(self): perms = set() for g in self.groups: perms = perms | set(g.permissions) return perms @classmethod def by_email_address(cls, email): """A class method that can be used to search users based on their email addresses since it is unique. """ return DBSession.query(cls).filter(cls.email_address==email).first() @classmethod def by_user_name(cls, username): """A class method that permits to search users based on their user_name attribute. """ return DBSession.query(cls).filter(cls.user_name==username).first() def _set_password(self, password): """encrypts password on the fly using the encryption algo defined in the configuration """ #unfortunately, this causes coverage not to work #self._password = self._encrypt_password(algorithm, password) def _get_password(self): """returns password """ return self._password password = synonym('password', descriptor=property(_get_password, _set_password)) def _encrypt_password(self, algorithm, password): """Hash the given password with the specified algorithm. Valid values for algorithm are 'md5' and 'sha1'. All other algorithm values will be essentially a no-op.""" hashed_password = password if isinstance(password, unicode): password_8bit = password.encode('UTF-8') else: password_8bit = password #creates a salted sha password salt = sha1() salt.update(os.urandom(60)) hash = sha1() hash.update(password_8bit + salt.hexdigest()) hashed_password = salt.hexdigest() + hash.hexdigest() # make sure the hased password is an UTF-8 object at the end of the # process because SQLAlchemy _wants_ a unicode object for Unicode columns if not isinstance(hashed_password, unicode): hashed_password = hashed_password.decode('UTF-8') return hashed_password def validate_password(self, password): """Check the password against existing credentials. this method _MUST_ return a boolean. @param password: the password that was provided by the user to try and authenticate. This is the clear text version that we will need to match against the (possibly) encrypted one in the database. @type password: unicode object """ hashed_pass = sha1() hashed_pass.update(password + self.password[:40]) return self.password[40:] == hashed_pass.hexdigest() class Permission(DeclarativeBase): """A relationship that determines what each Group can do """ __tablename__ = 'tg_permission' permission_id = Column(Integer, autoincrement=True, primary_key=True) permission_name = Column(Unicode(16), unique=True) description = Column(Unicode(255)) groups = relation(Group, secondary=group_permission_table, backref='permissions') class Example(DeclarativeBase): __tablename__ = 'example' example_id = Column(Integer, primary_key=True) created = Column(DateTime, default=datetime.now) blob = Column(BLOB ) binary = Column(Binary ) boolean = Column(Boolean ) char = Column(CHAR(200) ) cLOB = Column(CLOB(200) ) date_ = Column( DATE ) datetime_ = Column( DATETIME ) decimal = Column(DECIMAL ) date = Column(Date ) dateTime = Column(DateTime ) float__ = Column( FLOAT ) float_ = Column(Float ) int_ = Column(INT ) integer = Column(Integer, default=10) interval = Column(Interval ) # (NCHAR = #Column NCHAR ) numeric = Column(Numeric ) pickletype = Column(PickleType ) smallint = Column(SMALLINT ) smalliunteger = Column(SmallInteger ) string = Column(String(20) ) text = Column(TEXT(20) ) time_ = Column(TIME ) time = Column(Time ) timestamp = Column(TIMESTAMP ) unicode_ = Column(Unicode(200) ) varchar = Column(VARCHAR(200) ) password = Column(String(20) ) class Document(DeclarativeBase): __tablename__ = 'document' document_id = Column(Integer, primary_key=True) created = Column(DateTime, default=datetime.now) blob = Column(BLOB ) owner = Column(Integer, ForeignKey('tg_user.user_id')) url = Column(String(500)) def _get_address(self): return self.url def _set_address(self, value): self.url = value address = synonym('address', descriptor=property(_get_address, _set_address)) sprox-0.6.4/sprox/util.py0000644000076700000240000000131311131150323015146 0ustar cperkins1staff""" util Module this contains the class which allows dbsprockets to interface with sqlalchemy. Classes: Name Description MultiDict A class that allows dicts with multiple keys of the same value Exceptions: None Functions: None Copyright (c) 2007 Christopher Perkins Original Version by Christopher Perkins 2007 Released under MIT license. """ from copy import deepcopy, copy class MultiDict(dict): def __setitem__(self, key, value): self.setdefault(key, []).append(value) def iteritems(self): for key in self: values = dict.__getitem__(self, key) for value in values: yield (key, value) sprox-0.6.4/sprox/validators.py0000644000076700000240000000125611131150323016347 0ustar cperkins1staff""" validators Module Copyright (c) 2008 Christopher Perkins Original Version by Christopher Perkins 2008 Released under MIT license. """ from formencode import FancyValidator, Invalid class UniqueValue(FancyValidator): def __init__(self, provider, entity, field_name, *args, **kw): self.provider = provider self.entity = entity self.field_name = field_name FancyValidator.__init__(self, *args, **kw) def _to_python(self, value, state): if not self.provider.is_unique(self.entity, self.field_name, value): raise Invalid( 'That value already exists', value, state) return value sprox-0.6.4/sprox/validatorselector.py0000644000076700000240000000564311131150323017731 0ustar cperkins1staff""" validatorselecter Module this contains the class which allows the ViewConfig to select the appropriate validator for the given field Classes: Name Description ValidatorSelecter Parent Class SAValidatorSelector Selecter Based on sqlalchemy field types DatabaseViewValidatorSelector Database View always selects the same validator TableDefValidatorSelector Table def fields use the same validator Exceptions: None Functions: None Copyright (c) 2007 Christopher Perkins Original Version by Christopher Perkins 2007 Released under MIT license. """ from sqlalchemy.schema import Column from sqlalchemy.types import * from sqlalchemy.types import String as StringType from tw.forms.validators import * from formencode.compound import All from formencode import Invalid from formencode.validators import StringBool from sqlalchemy.orm import PropertyLoader, SynonymProperty class ValidatorSelector(object): _name_based_validators = {} def __new__(cls, *args, **kw): bases = cls.mro() chained_attrs = ['_name_based_validators'] for base in bases: for attr in chained_attrs: if hasattr(base, attr): current = getattr(cls, attr) current.update(getattr(base, attr)) return object.__new__(cls, *args, **kw) def __getitem__(self, field): return self.select(field) def __init__(self, *args, **kw): pass @property def name_based_validators(self): validators = self._do_get_name_based_validators() validators.update(self._name_based_validators) return validators def select(self, field): return UnicodeString def _do_get_name_based_validators(self): return {} class SAValidatorSelector(ValidatorSelector): default_validators = { StringType: UnicodeString, Integer: Int, Numeric: Number, DateTime: DateValidator, Date: DateValidator, Time: DateValidator, # Binary: UnicodeString, PickleType: UnicodeString, # Boolean: UnicodeString, # NullType: TextField } _name_based_validators = {'email_address':Email} def __init__(self, provider): self.provider = provider def select(self, field): if isinstance(field, PropertyLoader): return if isinstance(field, SynonymProperty): return #do not validate boolean or binary arguments if isinstance(field.type, (Boolean, Binary)): return None if field.name in self.name_based_validators: return self.name_based_validators[field.name] type_ = StringType for t in self.default_validators.keys(): if isinstance(field.type, t): type_ = t break validator_type = self.default_validators[type_] return validator_type sprox-0.6.4/sprox/viewbase.py0000644000076700000240000002163711213551634016024 0ustar cperkins1staffimport inspect from tw.api import Widget from tw.forms import HiddenField from configbase import ConfigBase, ConfigBaseError from sqlalchemy.orm import PropertyLoader from widgetselector import WidgetSelector class ClassViewer(object): """class wrapper to expose items of a class. Needed to pass classes to TW as params""" def __init__(self, klass): self.__name__ = klass.__name__ class ViewBaseError(Exception):pass class ViewBase(ConfigBase): """ :Modifiers: +-----------------------------------+--------------------------------------------+------------------------------+ | Name | Description | Default | +===================================+============================================+==============================+ | __widget_selector_type__ | What class to use for widget selection. | WidgetSelector | +-----------------------------------+--------------------------------------------+------------------------------+ | __field_widgets__ | A dictionary of widgets to replace the | {} | | | ones that would be chosen by the selector | | +-----------------------------------+--------------------------------------------+------------------------------+ | __field_widget_types__ | A dictionary of types of widgets, allowing | {} | | | sprox to determine the widget args | | +-----------------------------------+--------------------------------------------+------------------------------+ | __field_widget_args__ | A dictionary of types of args for widgets, | {} | | | you to override the args sent to the fields| | +-----------------------------------+--------------------------------------------+------------------------------+ | __base_widget_type__ | The base widget for this config | Widget | +-----------------------------------+--------------------------------------------+------------------------------+ | __base_widget_args__ | Args to pass into the widget overrides any | {} | | | defaults that are set in sprox creation | | +-----------------------------------+--------------------------------------------+------------------------------+ | __widget_selector__ | an instantiated object to use for widget | None | | | selection. | | +-----------------------------------+--------------------------------------------+------------------------------+ Also, see the :mod:`sprox.configbase` modifiers. """ __field_widgets__ = None __field_widget_types__ = None __field_widget_args__ = None __ignore_field_names__ = None #object overrides __base_widget_type__ = Widget __base_widget_args__ = None __widget_selector_type__ = WidgetSelector __widget_selector__ = None def _do_init_attrs(self): super(ViewBase, self)._do_init_attrs() if self.__base_widget_args__ is None: self.__base_widget_args__ = {} if self.__field_widgets__ is None: self.__field_widgets__ = {} if self.__field_widget_args__ is None: self.__field_widget_args__ = {} if self.__field_widget_types__ is None: self.__field_widget_types__ = {} if self.__widget_selector__ is None: self.__widget_selector__ = self.__widget_selector_type__() if self.__ignore_field_names__ is None: self.__ignore_field_names__ = ['sprox_id', '_method'] for attr in dir(self): if not attr.startswith('__'): value = getattr(self, attr) if isinstance(value, Widget): if not getattr(value, 'id', None): raise ViewBaseError('Widgets must provide an id argument for use as a field within a ViewBase') self.__add_fields__[attr] = value try: if issubclass(value, Widget): self.__field_widget_types__[attr] = value except TypeError: pass @property def __widget__(self): widget = getattr(self, '___widget__', None) if not widget: self.___widget__ = self.__base_widget_type__(**self.__widget_args__) widget = self.___widget__ return self.___widget__ #try to act like a widget as much as possible def __call__(self, *args, **kw): return self.__widget__.__call__(*args, **kw) @property def __widget_args__(self): return self._do_get_widget_args() def _do_get_widget_args(self): widget_dict = self._do_get_field_widgets(self.__fields__) field_widgets = [] for key in self.__fields__: if key not in widget_dict: continue value = widget_dict[key] #sometimes a field will have two widgets associated with it (disabled fields) if hasattr(value,'__iter__'): field_widgets.extend(value) continue field_widgets.append(value) d = dict(children=field_widgets) d.update(self.__base_widget_args__) return d def _do_get_disabled_fields(self): return self.__disable_fields__ def _do_get_field_widget_args(self, field_name, field): # toscawidgets does not like ids that have '.' in them. This does not # work for databases with schemas. field_name = field_name.replace('.', '_') args = {} #this is sort of a hack around TW evaluating _some_ params that are classes. entity = field if inspect.isclass(field): entity = ClassViewer(field) args = {'id':field_name, 'identity':self.__entity__.__name__+'_'+field_name, 'entity':entity} if field_name in self.__field_attrs__: args['attrs'] = self.__field_attrs__[field_name] if isinstance(field, PropertyLoader): args['provider'] = self.__provider__ args['nullable'] = self.__provider__.is_nullable(self.__entity__, field_name) if field_name in self.__field_widget_args__: args.update(self.__field_widget_args__[field_name]) return args def __create_hidden_fields(self): fields = {} fields['sprox_id'] = HiddenField(id='sprox_id') for field in self.__hide_fields__: if field not in self.__omit_fields__: args = {} if field in self.__field_widget_args__: args.update(self.__field_widget_args__[field]) fields[field] = HiddenField(id=field, identifier=field, **args) return fields def _do_get_field_widgets(self, fields): metadata_keys = self.__metadata__.keys() widgets = {} for field_name in fields: if field_name in self.__field_widgets__: widgets[field_name] = self.__field_widgets__[field_name] continue if field_name in self.__add_fields__: widget = self.__add_fields__[field_name] if widget is None: widget = Widget(field_name) widgets[field_name] = widget continue if field_name in self.__ignore_field_names__: continue if field_name in self.__hide_fields__: continue if field_name not in metadata_keys: continue field = self.__metadata__[field_name] if inspect.isclass(field): identifier = ClassViewer(field) field_widget_type = self.__field_widget_types__.get(field_name, self.__widget_selector__.select(field)) field_widget_args = self._do_get_field_widget_args(field_name, field) if field_name in self._do_get_disabled_fields(): # in this case, we display the current field, disabling it, and also add # a hidden field into th emix field_widget_args['disabled'] = True widgets[field_name] = (HiddenField(id=field_name.replace('.','_'), identifier=field_name), field_widget_type(**field_widget_args)) else: widgets[field_name] = field_widget_type(**field_widget_args) widgets.update(self.__create_hidden_fields()) return widgets sprox-0.6.4/sprox/widgets/0000755000076700000240000000000011236057646015313 5ustar cperkins1staffsprox-0.6.4/sprox/widgets/__init__.py0000644000076700000240000000002511123744670017414 0ustar cperkins1stafffrom widgets import *sprox-0.6.4/sprox/widgets/dojo.py0000755000076700000240000000743411220007356016615 0ustar cperkins1staff"""Dojo Specific Widgets""" from tw.dojo import DojoQueryReadStore, DojoBase, grid_css, tundragrid_css, DojoJsonRestStore, buildService from tw.dojo.selectshuttle import DojoSelectShuttleField, DojoSortedSelectShuttleField from tw.api import JSSource from sprox.widgets import PropertyMixin class SproxDojoGrid(DojoBase): engine_name=None available_engines = ['mako','genshi'] css = [grid_css, tundragrid_css] require = ['dojox.grid.DataGrid', 'dojox.data.QueryReadStore'] dojoType = 'dojox.grid.DataGrid' params = ['id', 'attrs', 'columns', 'jsId', 'action', 'rowsPerPage', 'model', 'delayScroll', 'cssclass', 'actions', 'columnResizing', 'columnReordering', 'column_widths', 'default_column_width', 'headers','column_options', 'default_column_options','dojoStoreType','dojoStoreWidget' ] delayScroll = "true" cssclass="sprox-dojo-grid" rowsPerPage = 20 columns = [] columnReordering = "false" columnResizing="false" column_widths = {} column_options = {} default_column_options = {} headers = {} default_column_width = "10em" include_dynamic_js_calls = True action='.json' model = None actions = True dojoStoreType = 'dojox.data.QueryReadStore' dojoStoreWidget = None template = "sprox.widgets.templates.dojogrid" def update_params(self,d): d['dojoStoreWidget']=DojoQueryReadStore() super(SproxDojoGrid, self).update_params(d) class DojoJsonRestStoreInstance(JSSource): engine_name='mako' require = ['twdojo.data.TWDojoRestStore'] target='.json' url = '.json' idAttribute = 'id' autoSave = 'true' source_vars = ["varId","target","url","idAttribute","autoSave"] src = """ dojo.require("twdojo.data.TWDojoRestStore") var ${varId}=new twdojo.data.TWDojoRestStore({target:"${target}",autoSave:"${autoSave and 'true' or 'false'}", service:buildService("${url}"),idAttribute:"${idAttribute}"}) """ class SproxEditableDojoGrid(DojoBase): engine_name=None available_engines = ['genshi', 'mako'] css = [grid_css, tundragrid_css] require = ['dojox.grid.DataGrid', 'twdojo.data.TWDojoRestStore'] dojoType = 'dojox.grid.DataGrid' params = ['id', 'attrs', 'columns', 'jsId', 'action', 'rowsPerPage', 'model', 'delayScroll', 'cssclass', 'actions', 'columnResizing', 'columnReordering', 'column_widths', 'default_column_width', 'headers','column_options', 'default_column_options','dojoStoreType','dojoStoreWidget' ] delayScroll = "true" cssclass="sprox-dojo-grid" rowsPerPage = 20 columns = [] columnReordering = "false" columnResizing="false" column_widths = {} column_options = {} default_column_options = {'editable':"true"} headers = {} default_column_width = "10em" include_dynamic_js_calls = True action='.json' model = None actions = True dojoStoreType = 'twdojo.data.TWDojoRestStore' dojoStoreWidget = None template = "sprox.widgets.templates.dojogrid" def __init__(self,**kw): super(SproxEditableDojoGrid, self).__init__(**kw) storeName = kw.get('jsId','') or '' storeName = storeName+'_store' self.javascript.append(buildService) self.javascript.append(DojoJsonRestStoreInstance(varId=storeName,target=kw['action'],url=kw['action'])) class SproxDojoSelectShuttleField(DojoSelectShuttleField, PropertyMixin): def update_params(self, d): self._my_update_params(d) super(SproxDojoSelectShuttleField, self).update_params(d) class SproxDojoSortedSelectShuttleField(DojoSortedSelectShuttleField, PropertyMixin): def update_params(self, d): self._my_update_params(d) super(SproxDojoSortedSelectShuttleField, self).update_params(d) sprox-0.6.4/sprox/widgets/templates/0000755000076700000240000000000011236057646017311 5ustar cperkins1staffsprox-0.6.4/sprox/widgets/templates/__init__.py0000644000076700000240000000000011123744670021403 0ustar cperkins1staffsprox-0.6.4/sprox/widgets/templates/__init__.pyc0000644000076700000240000000023711123754614021561 0ustar cperkins1staff³ò ¸ÉOIc@sdS(N((((sH/Users/cperkins1/nrel/pdil/src/sprox/sprox/widgets/templates/__init__.pysssprox-0.6.4/sprox/widgets/templates/checkbox.html0000644000076700000240000000045711123744670021766 0ustar cperkins1staff sprox-0.6.4/sprox/widgets/templates/container.html0000644000076700000240000000037511123744670022161 0ustar cperkins1staff
${child(value, controller=controller)}
sprox-0.6.4/sprox/widgets/templates/datagrid.html0000644000076700000240000000176511211255002021742 0ustar cperkins1staff
${col.title}
${XML(col.get_field(row, displays_on='genshi'))} ${col.get_field(row, displays_on='genshi')}
No Records Found.
sprox-0.6.4/sprox/widgets/templates/datagrid.mak0000644000076700000240000000141711211236163021547 0ustar cperkins1staff
% for i, col in enumerate(columns): % endfor % for i, row in enumerate(value): % for col in columns: % endfor
${col.title}
% if col.title == 'actions' | col.title in xml_fields: ${col.get_field(row, displays_on='mako', engine='mako') | n} % else: ${col.get_field(row, displays_on='mako', engine='mako')} % endif
% if not value: No Records Found. % endif
sprox-0.6.4/sprox/widgets/templates/dojogrid.html0000644000076700000240000000143111220011251021746 0ustar cperkins1staff
$column
sprox-0.6.4/sprox/widgets/templates/dojogrid.mak0000644000076700000240000000152211220010073021554 0ustar cperkins1staff % for column in columns: % endfor % if not(dojoStoreWidget is None):
% endif
${column}
sprox-0.6.4/sprox/widgets/templates/entityDef.html0000644000076700000240000000056011123744670022126 0ustar cperkins1staff $entity.key $entity.type relation sprox-0.6.4/sprox/widgets/templates/entityLabel.html0000644000076700000240000000033111123744670022443 0ustar cperkins1staffsprox-0.6.4/sprox/widgets/templates/hidden_put.html0000644000076700000240000000031311235661700022306 0ustar cperkins1staffsprox-0.6.4/sprox/widgets/templates/modelLabel.html0000644000076700000240000000034011123744670022227 0ustar cperkins1staffsprox-0.6.4/sprox/widgets/templates/recordField.html0000644000076700000240000000035711131150323022402 0ustar cperkins1staff $field_name ${value[field_name]} sprox-0.6.4/sprox/widgets/templates/recordViewTable.html0000644000076700000240000000042311123744670023252 0ustar cperkins1staff ${child.display(value)}
NameValue
sprox-0.6.4/sprox/widgets/templates/table.html0000644000076700000240000000051511211050236021244 0ustar cperkins1staff ${child.display(value, css_class=((i%2 and 'even') or 'odd'))}
NameDefinition
sprox-0.6.4/sprox/widgets/templates/tableDef.html0000644000076700000240000000036211123744670021701 0ustar cperkins1staff $identifier.name $identifier.type sprox-0.6.4/sprox/widgets/templates/tableForm.html0000644000076700000240000000327511213531124022100 0ustar cperkins1staff
${error_message}
${field.display(value_for(field), **args_for(field))}
sprox-0.6.4/sprox/widgets/templates/tableLabel.html0000644000076700000240000000032311123744670022217 0ustar cperkins1staffsprox-0.6.4/sprox/widgets/test/0000755000076700000240000000000011236057646016272 5ustar cperkins1staffsprox-0.6.4/sprox/widgets/test/__init__.py0000644000076700000240000000000011123744670020364 0ustar cperkins1staffsprox-0.6.4/sprox/widgets/widgets.py0000644000076700000240000000701711235661724017335 0ustar cperkins1stafffrom tw.api import Widget from tw.forms import CalendarDatePicker, CalendarDateTimePicker, TableForm, DataGrid from tw.forms.fields import SingleSelectField, MultipleSelectField, InputField, HiddenField from formencode.schema import Schema from formencode.validators import StringBool from formencode import Invalid import inspect class SproxMethodPutHiddenField(HiddenField): template="genshi:sprox.widgets.templates.hidden_put" class SproxCalendarDatePicker(CalendarDatePicker): date_format = '%Y-%m-%d' class SproxTimePicker(CalendarDateTimePicker): date_format = '%H:%M:%S' class SproxCalendarDateTimePicker(CalendarDateTimePicker): date_format = '%Y-%m-%d %H:%M:%S' class SproxDataGrid(DataGrid): template = "genshi:sprox.widgets.templates.datagrid" params = ['pks', 'controller', 'xml_fields'] xml_fields = ['actions'] class ContainerWidget(Widget): template = "genshi:sprox.widgets.templates.container" params = ["controller",] class TableLabelWidget(Widget): template = "genshi:sprox.widgets.templates.tableLabel" params = ["identifier", "controller"] class ModelLabelWidget(Widget): template = "genshi:sprox.widgets.templates.modelLabel" params = ["identifier", "controller"] class EntityLabelWidget(Widget): template = "genshi:sprox.widgets.templates.entityLabel" params = ["entity", "controller"] class RecordViewWidget(Widget): template = "genshi:sprox.widgets.templates.recordViewTable" params = ["entity"] class RecordFieldWidget(Widget): template = "genshi:sprox.widgets.templates.recordField" params = ['field_name'] class TableDefWidget(Widget): template = "genshi:sprox.widgets.templates.tableDef" params = ["identifier"] class EntityDefWidget(Widget): available_engines = ['genshi'] template = "sprox.widgets.templates.entityDef" params = ["entity"] class TableWidget(Widget): available_engines = ['genshi'] template = "genshi:sprox.widgets.templates.table" class SproxTableForm(TableForm): available_engines = ['genshi'] validator = Schema(ignore_missing_keys=True, allow_extra_fields=True) template = "genshi:sprox.widgets.templates.tableForm" #custom checkbox widget since I am not happy with the behavior of the TW one class SproxCheckBox(InputField): available_engines = ['genshi'] template = "sprox.widgets.templates.checkbox" validator = StringBool def update_params(self, d): InputField.update_params(self, d) try: checked = self.validator.to_python(d.value) except Invalid: checked = False d.attrs['checked'] = checked or None class PropertyMixin(Widget): params = ['entity', 'field_name', 'provider', 'dropdown_field_names'] def _my_update_params(self, d, nullable=False): entity = self.entity options = self.provider.get_dropdown_options(self.entity, self.field_name, self.dropdown_field_names) if nullable: options.append([None,"-----------"]) if len(options) == 0: return {} d['options']= options return d class PropertySingleSelectField(SingleSelectField, PropertyMixin): params=["nullable"] nullable=False def update_params(self, d): self._my_update_params(d,nullable=self.nullable) SingleSelectField.update_params(self, d) return d class PropertyMultipleSelectField(MultipleSelectField, PropertyMixin): def update_params(self, d): self._my_update_params(d) MultipleSelectField.update_params(self, d) return d sprox-0.6.4/sprox/widgetselector.py0000644000076700000240000000610111200055755017227 0ustar cperkins1staff""" widgetselecter Module this contains the class which allows the ViewConfig to select the appropriate widget for the given field Classes: Name Description WidgetSelecter Parent Class SAWidgetSelector Selecter Based on sqlalchemy field types DatabaseViewWidgetSelector Database View always selects the same widget TableDefWidgetSelector Table def fields use the same widget Exceptions: None Functions: None Copyright (c) 2007 Christopher Perkins Original Version by Christopher Perkins 2007Database Released under MIT license. """ from sqlalchemy.schema import Column from sqlalchemy.types import * from sqlalchemy.orm import PropertyLoader, SynonymProperty from tw.api import Widget from tw.forms.fields import * from sprox.widgets import * class WidgetSelector: def select(self, field): return Widget class EntitiesViewWidgetSelector(WidgetSelector): def select(self, field): return EntityLabelWidget class EntityDefWidgetSelector(WidgetSelector): def select(self, field): return EntityDefWidget class RecordViewWidgetSelector(WidgetSelector): def select(self, field): return RecordFieldWidget text_field_limit=100 class SAWidgetSelector(WidgetSelector): default_widgets = { String: TextField, Integer: TextField, Numeric: TextField, DateTime: SproxCalendarDateTimePicker, Date: SproxCalendarDatePicker, Time: SproxTimePicker, Binary: FileField, PickleType: TextField, Boolean: SproxCheckBox, # NullType: TextField } default_name_based_widgets = {} default_multiple_select_field_widget_type = PropertyMultipleSelectField default_single_select_field_widget_type = PropertySingleSelectField def select(self, field): if hasattr(field, 'name'): if field.name in self.default_name_based_widgets: return self.default_name_based_widgets[field.name] if field.name.lower() == 'password': return PasswordField # this is really the best we can do, since we cannot know # what type the field represents until execution occurs. if isinstance(field, SynonymProperty): #fix to handle weird synonym prop stuff if isinstance(field.descriptor, property) or field.descriptor.__class__.__name__.endswith('SynonymProp'): return TextField if isinstance(field, PropertyLoader): if field.uselist: return self.default_multiple_select_field_widget_type return self.default_single_select_field_widget_type type_ = String for t in self.default_widgets.keys(): if isinstance(field.type, t): type_ = t break widget = self.default_widgets[type_] if widget is TextField and hasattr(field.type, 'length') and (field.type.length is None or field.type.length>text_field_limit): widget = TextArea return widget sprox-0.6.4/sprox.egg-info/0000755000076700000240000000000011236057646015337 5ustar cperkins1staffsprox-0.6.4/sprox.egg-info/dependency_links.txt0000644000076700000240000000000111236057645021404 0ustar cperkins1staff sprox-0.6.4/sprox.egg-info/entry_points.txt0000644000076700000240000000102111236057645020626 0ustar cperkins1staff[toscawidgets] # Use 'widgets' to point to the module where widgets should be imported # from to register in the widget browser widgets = sprox.widgets # Use 'samples' to point to the module where widget examples # should be imported from to register in the widget browser # samples = tw.samples # Use 'resources' to point to the module where resources # should be imported from to register in the widget browser #resources = sprox.widgets.resources sprox-0.6.4/sprox.egg-info/not-zip-safe0000644000076700000240000000000111123744722017556 0ustar cperkins1staff sprox-0.6.4/sprox.egg-info/PKG-INFO0000644000076700000240000000125311236057645016434 0ustar cperkins1staffMetadata-Version: 1.0 Name: sprox Version: 0.6.4 Summary: A package for creation of web widgets directly from database schema. Home-page: http://www.sprox.org Author: Christopher Perkins 2007-2009 major contributions by Michael Brickenstein Author-email: chris@percious.com License: MIT Description: UNKNOWN Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Programming Language :: Python Classifier: Topic :: Internet :: WWW/HTTP Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Libraries :: Python Modules sprox-0.6.4/sprox.egg-info/requires.txt0000644000076700000240000000004111236057645017731 0ustar cperkins1staffsqlalchemy>=0.5 tw.forms>=0.9.7.2sprox-0.6.4/sprox.egg-info/SOURCES.txt0000644000076700000240000000442111236057646017224 0ustar cperkins1staffMANIFEST.in setup.cfg setup.py sprox/__init__.py sprox/configbase.py sprox/dummyentity.py sprox/entitiesbase.py sprox/fillerbase.py sprox/formbase.py sprox/iprovider.py sprox/metadata.py sprox/providerselector.py sprox/recordviewbase.py sprox/release.py sprox/saormprovider.py sprox/sprockets.py sprox/tablebase.py sprox/util.py sprox/validators.py sprox/validatorselector.py sprox/viewbase.py sprox/widgetselector.py sprox.egg-info/PKG-INFO sprox.egg-info/SOURCES.txt sprox.egg-info/dependency_links.txt sprox.egg-info/entry_points.txt sprox.egg-info/not-zip-safe sprox.egg-info/requires.txt sprox.egg-info/top_level.txt sprox/dojo/__init__.py sprox/dojo/fillerbase.py sprox/dojo/formbase.py sprox/dojo/sprockets.py sprox/dojo/tablebase.py sprox/mootools/__init__.py sprox/mootools/formbase.py sprox/test/__init__.py sprox/test/base.py sprox/test/model.py sprox/widgets/__init__.py sprox/widgets/dojo.py sprox/widgets/widgets.py sprox/widgets/templates/__init__.py sprox/widgets/templates/__init__.pyc sprox/widgets/templates/checkbox.html sprox/widgets/templates/container.html sprox/widgets/templates/datagrid.html sprox/widgets/templates/datagrid.mak sprox/widgets/templates/dojogrid.html sprox/widgets/templates/dojogrid.mak sprox/widgets/templates/entityDef.html sprox/widgets/templates/entityLabel.html sprox/widgets/templates/hidden_put.html sprox/widgets/templates/modelLabel.html sprox/widgets/templates/recordField.html sprox/widgets/templates/recordViewTable.html sprox/widgets/templates/table.html sprox/widgets/templates/tableDef.html sprox/widgets/templates/tableForm.html sprox/widgets/templates/tableLabel.html sprox/widgets/test/__init__.py tests/__init__.py tests/test_configbase.py tests/test_doctests.py tests/test_entitiesbase.py tests/test_fillerbase.py tests/test_formbase.py tests/test_iprovider.py tests/test_metadata.py tests/test_providerselector.py tests/test_saormprovider.py tests/test_sprockets.py tests/test_tablebase.py tests/test_testbase.py tests/test_util.py tests/test_validators.py tests/test_validatorselector.py tests/test_viewbase.py tests/test_widgets.py tests/test_widgetselector.py tests/dojo/__init__.py tests/dojo/test_fillerbase.py tests/dojo/test_formbase.py tests/dojo/test_sprockets.py tests/dojo/test_tablebase.py tests/widgets/__init__.py tests/widgets/test_widgets.pysprox-0.6.4/sprox.egg-info/top_level.txt0000644000076700000240000000001411236057645020063 0ustar cperkins1staffsprox tests sprox-0.6.4/tests/0000755000076700000240000000000011236057646013634 5ustar cperkins1staffsprox-0.6.4/tests/__init__.py0000644000076700000240000000000011123744670015726 0ustar cperkins1staffsprox-0.6.4/tests/dojo/0000755000076700000240000000000011236057646014567 5ustar cperkins1staffsprox-0.6.4/tests/dojo/__init__.py0000644000076700000240000000000011131150323016642 0ustar cperkins1staffsprox-0.6.4/tests/dojo/test_fillerbase.py0000644000076700000240000000332011211004607020264 0ustar cperkins1stafffrom sprox.dojo.fillerbase import DojoTableFiller from sprox.configbase import ConfigBaseError from sprox.test.base import setup_database, sorted_user_columns, SproxTest, User, Example from nose.tools import raises, eq_ session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class UserFiller(DojoTableFiller): __entity__ = User class TestTableFiller(SproxTest): def setup(self): super(TestTableFiller, self).setup() self.filler = UserFiller(session) def test_create(self): pass def test_get_value(self): value = self.filler.get_value() eq_(len(value), 4) value = value['items'][0] eq_(value['groups'], u'4') eq_(value['town'], 'Arvada') def test_get_value_with_binary_field(self): class ExampleFiller(DojoTableFiller): __entity__ = Example example = Example(binary='datadatadata') session.add(example) filler = ExampleFiller(session) value = filler.get_value() eq_(value['items'][0]['binary'], '') def test_get_value_with_orderby_desc(self): class ExampleFiller(DojoTableFiller): __entity__ = Example example = Example(binary='datadatadata') session.add(example) filler = ExampleFiller(session) value = filler.get_value(sort='-example_id') eq_(value['items'][0]['binary'], '') @raises(ConfigBaseError) def _test_count_without_get(self): self.filler.get_count() def test_count(self): v = self.filler.get_value() c = self.filler.get_count() assert c == 1, v sprox-0.6.4/tests/dojo/test_formbase.py0000644000076700000240000000300211211016141017743 0ustar cperkins1stafffrom sprox.dojo.formbase import DojoFormBase from sprox.widgets.dojo import SproxDojoSortedSelectShuttleField from sprox.test.base import setup_database, sorted_user_columns, SproxTest, User, Example from nose.tools import raises, eq_ session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class UserForm(DojoFormBase): __entity__ = User groups = SproxDojoSortedSelectShuttleField class TestFormBase(SproxTest): def setup(self): super(TestFormBase, self).setup() self.base = UserForm(session) def test_create(self): pass def test__widget__(self): rendered = self.base.__widget__() assert """
Available



""" in rendered, renderedsprox-0.6.4/tests/dojo/test_sprockets.py0000644000076700000240000000116411131150323020173 0ustar cperkins1stafffrom sprox.dojo.sprockets import DojoSprocketCache from sprox.test.base import setup_database, sorted_user_columns, SproxTest, User from nose.tools import raises, eq_ session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class TestDojoSprocketCache: def setup(self): self.cache = DojoSprocketCache(session) def test_create(self): pass def test_get_sprocket(self): base = self.cache['listing__User'] assert base.view is not None assert base.filler is not None sprox-0.6.4/tests/dojo/test_tablebase.py0000644000076700000240000001125311220011445020100 0ustar cperkins1stafffrom sprox.dojo.tablebase import DojoTableBase, DojoEditableTableBase from sprox.test.base import setup_database, sorted_user_columns, SproxTest, setup_records, Example, assert_in_xml from sprox.test.model import User from sprox.widgetselector import SAWidgetSelector from sprox.metadata import FieldsMetadata from nose.tools import raises, eq_ from formencode import Invalid session = None engine = None connection = None def setup(): global session, engine, metadata session, engine, metadata = setup_database() user = setup_records(session) def teardown(): session.rollback() class UserTable(DojoTableBase): __entity__ = User __url__ = './something.json' class EditableUserTable(DojoEditableTableBase): __entity__ = User __url__ = './something.json' class TestDojoTableBase: def setup(self): self.base = UserTable(session) def test_create(self): pass def test__widget__(self): rendered = self.base.__widget__() assert_in_xml("""
__actions__ _password user_id user_name email_address display_name created town_id town password groups
""",rendered) class TestDojoEditableTableBase: def setup(self): self.base = EditableUserTable(session) def test_create(self): pass def test__widget__(self): rendered = self.base.__widget__() assert_in_xml("""
__actions__ _password user_id user_name email_address display_name created town_id town password groups
""", rendered) sprox-0.6.4/tests/test_configbase.py0000644000076700000240000000120711131150323017321 0ustar cperkins1stafffrom sprox.configbase import ConfigBase, ConfigBaseError from sprox.test.base import setup_database from sprox.test.model import User from nose.tools import raises, eq_ session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class TestConfigBase: def setup(self): self.base = ConfigBase() def test_create(self): pass @raises(ConfigBaseError) def test__metadata__bad(self): self.base.__metadata__ @raises(ConfigBaseError) def test__provider__bad(self): self.base.__provider__ sprox-0.6.4/tests/test_doctests.py0000644000076700000240000000470011212067164017064 0ustar cperkins1stafffrom sprox.configbase import ConfigBase, ConfigBaseError from sprox.test.base import setup_database, sorted_user_columns, SproxTest, setup_records, Example, Document, eq_xml from sprox.test.model import User, Town import os.path, re from nose.tools import raises, eq_ from nose.util import anyp, getpackage, test_address, resolve_name, src, tolist import inspect import doctest import unittest from nose.plugins import doctests as nose_doctest from sprox import configbase, fillerbase, formbase, saormprovider, sprockets, tablebase, metadata, validators, validatorselector, widgets, widgetselector from sprox.dojo import formbase as dojo_formbase import sprox session = None engine = None connection = None trans = None metadata = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() user = setup_records(session) #this may be needed if we end up testing the provider with doctests #session.commit() def check_output_xml(want, got, optionsflags): return eq_xml(want, got) from doctest import OutputChecker original_check_output = OutputChecker.check_output import doctest XML_OUTPUT = doctest.register_optionflag("XML") class MyOutputChecker(doctest.OutputChecker): def check_output(self, want, got, optionflags): if optionflags & XML_OUTPUT: return check_output_xml(want, got, optionflags) return original_check_output(self, want, got, optionflags) doctest.OutputChecker = MyOutputChecker def teardown(): session.rollback() def test_doctests(): global session, metadata import unittest import doctest def setUp(self): #this may be needed if we end up testing the provider with doctests pass def tearDown(self): #this may be needed if we end up testing the provider with doctests #session.rollback() pass suite = unittest.TestSuite() for mod in dir(sprox): mod = getattr(sprox, mod) if inspect.ismodule(mod): try: suite.addTest(doctest.DocTestSuite(mod, globs={'session':session, 'User': User, 'Town':Town, 'metadata':metadata}, setUp=setUp, tearDown=tearDown)) except ValueError: pass suite.addTest(doctest.DocTestSuite(dojo_formbase, globs={'session':session, 'User': User, 'Town':Town, 'metadata':metadata}, setUp=setUp, tearDown=tearDown)) runner = unittest.TextTestRunner(verbosity=10) runner.run(suite) sprox-0.6.4/tests/test_entitiesbase.py0000644000076700000240000000123611131150323017702 0ustar cperkins1stafffrom sprox.entitiesbase import EntitiesBase from sprox.test.base import setup_database from nose.tools import raises, eq_ from sprox.test.model import User session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class ModelsView(EntitiesBase): __entity__ = User class TestViewBase: def setup(self): self.view = ModelsView(session) def test_create(self): pass def test__widget__(self): rendered = self.view() assert """""" in rendered, renderedsprox-0.6.4/tests/test_fillerbase.py0000644000076700000240000000511311210776556017355 0ustar cperkins1stafffrom sprox.fillerbase import FillerBase, TableFiller, EditFormFiller, AddFormFiller, FormFiller, ConfigBaseError from sprox.test.base import setup_database, sorted_user_columns, SproxTest, User, Example from nose.tools import raises, eq_ session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class UserFiller(TableFiller): __entity__ = User class TestFillerBase(SproxTest): def setup(self): super(TestFillerBase, self).setup() class UserFiller(FillerBase): __entity__ = User self.filler = UserFiller(session) def test_get_value(self): value = self.filler.get_value() assert value =={}, value class TestTableFiller(SproxTest): def setup(self): super(TestTableFiller, self).setup() self.filler = UserFiller(session) def test_create(self): pass def test_get_value(self): value = self.filler.get_value() eq_(len(value), 1) value = value[0] eq_(value['groups'], u'4') eq_(value['town'], 'Arvada') def test_get_value_with_binary_field(self): class ExampleFiller(TableFiller): __entity__ = Example example = Example(binary='datadatadata') session.add(example) filler = ExampleFiller(session) value = filler.get_value() eq_(value[0]['binary'], '') def test_get_list_data_value_array_values(self): r = self.filler._get_list_data_value(User, ['something', 'something else']) assert r == ['something', 'something else'], r @raises(ConfigBaseError) def test_count_without_get(self): self.filler.get_count() def test_count(self): self.filler.get_value() c = self.filler.get_count() assert c == 1, c class TestEditFormFiller(SproxTest): def setup(self): super(TestEditFormFiller, self).setup() self.filler = EditFormFiller(session) self.filler.__entity__ = User def test_create(self): pass def test_get_value(self): value = self.filler.get_value(values={'user_id':1}) eq_(value['groups'], [5]) eq_(value['town'], 1) class TestAddFormFiller(SproxTest): def setup(self): super(TestAddFormFiller, self).setup() self.filler = AddFormFiller(session) self.filler.__entity__ = User def test_create(self): pass def test_get_value(self): value = self.filler.get_value(values={'user_id':1}) eq_(value['user_id'], 1) sprox-0.6.4/tests/test_formbase.py0000644000076700000240000002730511217757100017041 0ustar cperkins1stafffrom sprox.formbase import FormBase, AddRecordForm, DisabledForm, EditableForm, Field from sprox.viewbase import ViewBaseError from sprox.test.base import setup_database, sorted_user_columns, SproxTest, setup_records, Example, Document, assert_in_xml from sprox.test.model import User, Group from sprox.widgetselector import SAWidgetSelector from sprox.metadata import FieldsMetadata from nose.tools import raises, eq_ from formencode import Invalid, Schema from formencode.validators import FieldsMatch, NotEmpty, OpenId from tw.forms import PasswordField, TextField class MyTextField(TextField):pass session = None engine = None connection = None user = None def setup(): global session, engine, metadata, user session, engine, metadata = setup_database() user = setup_records(session) class UserForm(FormBase): __entity__ = User class TestField: def setup(self): self.field = Field(TextField, NotEmpty) def test_create(self): assert self.field.widget == TextField assert self.field.validator == NotEmpty class TestsEmptyDropdownWorks: def setup(self): self.base = UserForm(session) def test__widget__(self): rendered = self.base.__widget__() assert_in_xml(""" """, rendered) class TestFormBase(SproxTest): def setup(self): super(TestFormBase, self).setup() self.base = UserForm(session) def test_create(self): pass def test_formbase_with_validator_class(self): class UserForm(FormBase): __entity__ = User user_name = OpenId user_form = UserForm(session) widget = user_form.__widget__ try: widget.validate({'user_name':'something'}) except Invalid, e: assert u'"something" is not a valid OpenId (it is neither an URL nor an XRI)' in e.msg, e.msg def test_formbase_with_validator_instance(self): class UserForm(FormBase): __entity__ = User user_name = OpenId() user_form = UserForm(session) widget = user_form.__widget__ try: widget.validate({'user_name':'something'}) except Invalid, e: assert u'"something" is not a valid OpenId (it is neither an URL nor an XRI)' in e.msg, e.msg def test_formbase_with_field_validator_instance(self): class UserForm(FormBase): __entity__ = User user_name = Field(validator=OpenId()) user_form = UserForm(session) widget = user_form.__widget__ try: widget.validate({'user_name':'something'}) except Invalid, e: assert u'"something" is not a valid OpenId (it is neither an URL nor an XRI)' in e.msg, e.msg def test_formbase_with_field_validator_class(self): class UserForm(FormBase): __entity__ = User user_name = Field(validator=OpenId()) user_form = UserForm(session) widget = user_form.__widget__ try: widget.validate({'user_name':'something'}) except Invalid, e: assert u'"something" is not a valid OpenId (it is neither an URL nor an XRI)' in e.msg, e.msg def test_formbase_with_field_widget_class(self): class UserForm(FormBase): __entity__ = User user_name = Field(MyTextField) user_form = UserForm(session) widget = user_form.__widget__ assert isinstance(widget.children['user_name'], MyTextField) def test_formbase_with_field_widget_instance(self): class UserForm(FormBase): __entity__ = User user_name = Field(MyTextField('user_name')) user_form = UserForm(session) widget = user_form.__widget__ assert isinstance(widget.children['user_name'], MyTextField) @raises(ViewBaseError) def test_formbase_with_field_widget_instance_no_id(self): class UserForm(FormBase): __entity__ = User user_name = Field(MyTextField()) user_form = UserForm(session) widget = user_form.__widget__ assert isinstance(widget.children['user_name'], MyTextField) def test_formbase_with_field_widget_and_validator_instance(self): class UserForm(FormBase): __entity__ = User user_name = Field(MyTextField, OpenId) user_form = UserForm(session) widget = user_form.__widget__ assert isinstance(widget.children['user_name'], MyTextField) try: widget.validate({'user_name':'something'}) except Invalid, e: assert u'"something" is not a valid OpenId (it is neither an URL nor an XRI)' in e.msg, e.msg def test__fields__(self): eq_(sorted_user_columns, sorted(self.base.__fields__)) def test__widget__(self): rendered = self.base.__widget__() assert_in_xml(""" """, rendered) @raises(ViewBaseError) def test_form_field_with_no_id(self): class BogusUserForm(FormBase): __entity__ = User field = TextField() bogus = BogusUserForm(session) def test_entity_with_synonym(self): class DocumentForm(FormBase): __entity__ = Document form = DocumentForm(session) rendered = form() assert_in_xml(""" """, rendered) def test_entity_with_dropdown_field_names(self): class UserFormFieldNames(FormBase): __entity__ = User __dropdown_field_names__ = ['group_name'] form = UserFormFieldNames(session) rendered = form() assert_in_xml(""" """, rendered) def test_entity_with_dropdown_field_names2(self): class UserFormFieldNames(FormBase): __entity__ = User __dropdown_field_names__ = {'groups':'group_name'} form = UserFormFieldNames(session) rendered = form() assert_in_xml(""" """, rendered) def test_entity_with_dropdown_field_names_dict(self): class UserFormFieldNames(FormBase): __entity__ = User __dropdown_field_names__ = {'groups':['group_name']} form = UserFormFieldNames(session) rendered = form() assert_in_xml( """ """, rendered) def test_require_field(self): class RegistrationForm(FormBase): __entity__ = User __require_fields__ = ['user_name'] form = RegistrationForm(session) eq_(form.__widget__.children['user_name'].validator.not_empty, True) class TestAddRecordForm(SproxTest): def setup(self): super(TestAddRecordForm, self).setup() #setup_records(session) class AddUserForm(AddRecordForm): __entity__ = User __limit_fields__ = ['user_name'] self.base = AddUserForm(session) @raises(Invalid) def test_validate(self): self.base.validate(params={'sprox_id':'asdf', 'user_name':'asdf'}) def test_example_form(self): class AddExampleForm(AddRecordForm): __entity__ = Example example_form = AddExampleForm() #print example_form() #assert "checkbox" in example_form() assert "checkbox" in example_form({'boolean':"asdf"}) def test_form_with_base_validator(self): form_validator = Schema(chained_validators=(FieldsMatch('password', 'verify_password', messages={'invalidNoMatch': 'Passwords do not match'}),)) class RegistrationForm(AddRecordForm): __model__ = User __require_fields__ = ['password', 'user_name', 'email_address'] __omit_fields__ = ['_password', 'groups', 'created', 'user_id', 'town'] __field_order__ = ['user_name', 'email_address', 'display_name', 'password', 'verify_password'] __base_validator__ = form_validator email_address = TextField display_name = TextField verify_password = PasswordField('verify_password') registration_form = RegistrationForm() try: registration_form.validate(params={'password':'blah', 'verify_password':'not_blah'}) except Invalid, exc: assert 'Passwords do not match' in exc.message class TestEditableForm(SproxTest): def setup(self): super(TestEditableForm, self).setup() #setup_records(session) class UserForm(EditableForm): __entity__ = User __limit_fields__ = ['user_name'] self.base = UserForm(session) def test__widget__(self): rendered = self.base.__widget__() assert_in_xml(""" """, rendered) class TestDisabledForm(SproxTest): def setup(self): super(TestDisabledForm, self).setup() #setup_records(session) class UserForm(DisabledForm): __entity__ = User __limit_fields__ = ['user_name'] self.base = UserForm(session) def test__widget__(self): rendered = self.base.__widget__() assert_in_xml( """ """, rendered)sprox-0.6.4/tests/test_iprovider.py0000644000076700000240000000566311131150323017236 0ustar cperkins1stafffrom sprox.iprovider import IProvider from nose.tools import raises, eq_ from sprox.test.base import User class TestSAORMProvider: def setup(self): self.provider = IProvider() def test_create(self): pass @raises(NotImplementedError) def test_get_entity(self): entity = self.provider.get_entity('User') @raises(NotImplementedError) def test_get_field(self): entity = self.provider.get_field(User, 'asdf') @raises(NotImplementedError) def test_get_entities(self): entity = self.provider.get_entities() @raises(NotImplementedError) def test_get_fields(self): entity = self.provider.get_fields(User) @raises(NotImplementedError) def test_get_primary_fields(self): fields = self.provider.get_primary_fields(User) @raises(NotImplementedError) def test_is_relation(self): entity = self.provider.is_relation(User, 'asdf') @raises(NotImplementedError) def test_is_nullable(self): entity = self.provider.is_nullable(User, 'asdf') @raises(NotImplementedError) def test_get_primary_field_function(self): field = self.provider.get_primary_field(lambda: User) @raises(NotImplementedError) def test_get_view_field_name(self): field = self.provider.get_view_field_name(User, ['name']) @raises(NotImplementedError) def test_get_view_field_name_not_found(self): field = self.provider.get_view_field_name(User, []) @raises(NotImplementedError) def test_get_dropdown_options_fk(self): options = self.provider.get_dropdown_options(User, 'town') @raises(NotImplementedError) def test_get_dropdown_options_join(self): options = self.provider.get_dropdown_options(User, 'groups') @raises(NotImplementedError) def test_get_relations(self): relations = self.provider.get_relations(User) # @raises(NotImplementedError) # def test_get_synonyms(self): # synonyms = self.provider.get_synonyms(User) # @raises(NotImplementedError) # def test_dictify(self): # d = self.provider.dictify(self.user) @raises(NotImplementedError) def test_create(self): params = {'user_name':u'asdf2', 'password':u'asdf2', 'email_address':u'email@addy.com', 'groups':[1,4], 'town':2} new_user = self.provider.create(User, params) @raises(NotImplementedError) def test_update(self): params = {'user_name':u'asdf2', 'password':u'asdf2', 'email_address':u'email@addy.com', 'groups':[1,4], 'town':2} new_user = self.provider.update(User, params) @raises(NotImplementedError) def test_get_default_values(self): assert {} == self.provider.get_default_values(User, {}) @raises(NotImplementedError) def test_get(self): user = self.provider.get(User, params={'user_id':1}) @raises(NotImplementedError) def test_delete(self): user = self.provider.delete(User, params={'user_id':1})sprox-0.6.4/tests/test_metadata.py0000644000076700000240000000576611226740743017037 0ustar cperkins1stafffrom nose.tools import raises, eq_ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sprox.metadata import Metadata, MetadataError, FieldsMetadata, FieldMetadata, EntitiesMetadata from sprox.saormprovider import SAORMProvider from sprox.iprovider import IProvider from sprox.test.base import * session = None engine = None connect = None trans = None def setup(): global session, engine, connect, trans session, engine, metadata = setup_database() # trans = engine.begin() class MetadataTest(SproxTest): obj = Metadata provider = IProvider() def setup(self): super(MetadataTest, self).setup() self.metadata = self.obj(self.provider) def test_create(self): pass @raises(NotImplementedError) def test_set_item(self): self.metadata['asdf'] = 'asdf' @raises(NotImplementedError) def test_get_item(self): value = self.metadata['asdf'] @raises(NotImplementedError) def test_keys(self): value = self.metadata.keys() class TestMetadata(MetadataTest):pass class TestFieldsMetadata(MetadataTest): def setup(self): super(TestFieldsMetadata, self).setup() provider = SAORMProvider(engine, metadata=metadata) self.metadata = FieldsMetadata(provider, Example) def test_get_item(self): field = self.metadata['binary'] eq_(field.name, 'binary') @raises(KeyError) def test_get_item_key_error(self): self.metadata['asdf'] def test_set_item(self): self.metadata['asdf'] = '1234' assert self.metadata['asdf'] == '1234' @raises(MetadataError) def test_set_item_bad(self): self.metadata['binary'] = '1234' def test_keys(self): self.metadata['asdf'] = '1234' keys = sorted(self.metadata.keys()) eq_(keys, ['asdf', 'binary', 'binary', 'blob', 'blob', 'boolean', 'boolean', 'cLOB', 'cLOB', 'char', 'char', 'created', 'created', 'date', 'date', 'dateTime', 'dateTime', 'date_', 'date_', 'datetime_', 'datetime_', 'decimal', 'decimal', 'example_id', 'example_id', 'float_', 'float_', 'float__', 'float__', 'int_', 'int_', 'integer', 'integer', 'interval', 'interval', 'numeric', 'numeric', 'password', 'password', 'pickletype', 'pickletype', 'smallint', 'smallint', 'smalliunteger', 'smalliunteger', 'string', 'string', 'text', 'text', 'time', 'time', 'time_', 'time_', 'timestamp', 'timestamp', 'unicode_', 'unicode_', 'varchar', 'varchar']) class TestEntitiesMetadata: def setup(self): provider = SAORMProvider(engine, metadata=metadata) self.metadata = EntitiesMetadata(provider) def test_create(self): pass def test_get_item(self): eq_(User, self.metadata['User']) @raises(KeyError) def test_get_item_not_found(self): self.metadata['no_findy'] sprox-0.6.4/tests/test_providerselector.py0000644000076700000240000000472711135127077020644 0ustar cperkins1stafffrom sprox.providerselector import SAORMSelector, ProviderTypeSelector, ProviderSelector, ProviderTypeSelectorError from sprox.test.base import setup_database from sprox.test.model import User from nose.tools import raises, eq_ from sprox.dummyentity import DummyEntity session = None engine = None connection = None trans = None metadata = None def setup(): global session, engine, metadata, trans, metadata session, engine, metadata = setup_database() from sprox.test.base import metadata as meta metadata = meta import sprox.providerselector as p #this un-singleton-izes this module for testing with reflection (sqlsoup) p.SAORMSelector = p._SAORMSelector() class TestProviderSelector: def setup(self): self.selector = ProviderSelector() def test_create(self): pass @raises(NotImplementedError) def test_get_entity(self): self.selector.get_entity('User') @raises(NotImplementedError) def test_get_provider(self): self.selector.get_provider(User) @raises(NotImplementedError) def test_get_identifier(self): self.selector.get_identifier(User) class TestSAORMProviderSelector: def setup(self): self.selector = SAORMSelector def test_get_entity(self): eq_(User, self.selector.get_entity('User')) def test_get_entity_engine_not_none(self): eq_(User, self.selector.get_entity('User', hint=engine)) def test_get_provider(self): eq_(engine, self.selector.get_provider(User).engine) def test_get_identifier(self): eq_('User', self.selector.get_identifier(User)) def test_get_provider_with_metadata(self): eq_(engine, self.selector.get_provider(User, hint=metadata).engine) @raises(NameError) def test_entity_not_found(self): self.selector.get_entity('Dummy') def test_get_provider_engine_none(self): self.selector.get_provider() #xxx: this is not super clean, and I think it should be removed. def test_get_provider_with_cleared_providers(self): self.selector._providers = {} self.selector.get_provider(hint=engine) class TestProviderTypeSelector: def setup(self): self.type_selector = ProviderTypeSelector() def test_create(self): pass @raises(ProviderTypeSelectorError) def test_no_provider_type(self): self.type_selector.get_selector('asdf') def test_dummy_provider_type(self): self.type_selector.get_selector(DummyEntity)sprox-0.6.4/tests/test_saormprovider.py0000644000076700000240000001472311226740743020144 0ustar cperkins1stafffrom sprox.saormprovider import SAORMProvider from sprox.test.base import setup_database, setup_records, SproxTest from sprox.test.model import * from sprox.widgetselector import SAWidgetSelector from sqlalchemy.orm import mapper from sqlalchemy import MetaData, Table, Column, Integer from sqlalchemy.engine import Engine from nose.tools import raises, eq_ import datetime session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class DummyEngine(Engine): def __init__(self): pass url = 'dummy!' other_engine = DummyEngine() other_metadata = MetaData(bind=other_engine) class OtherClass(object):pass other_table = Table('other_table', other_metadata, Column('other_id', Integer, primary_key=True)) mapper(OtherClass, other_table) class TestSAORMProvider(SproxTest): def setup(self): super(TestSAORMProvider, self).setup() self.provider = SAORMProvider(session) def test_get_fields_with_func(self): eq_(self.provider.get_fields(lambda: Town), ['town_id', 'name', 'town_id', 'name']) def test_create(self): pass def test_isbinary_related(self): assert not self.provider.is_binary(User, 'groups') def test_create_with_engine(self): provider = SAORMProvider(engine) assert provider.engine == engine def test_create_with_metadata(self): provider = SAORMProvider(metadata) assert provider.engine == engine def test_create_with_session(self): provider = SAORMProvider(session) assert provider.engine == engine def test_get_entity(self): entity = self.provider.get_entity('User') assert entity == User @raises(KeyError) def test_get_entity_non_matching_engine(self): entity = self.provider.get_entity('OtherClass') def test_get_primary_fields(self): fields = self.provider.get_primary_fields(User) eq_(fields, ['user_id']) def test_get_primary_field_function(self): field = self.provider.get_primary_field(lambda: User) eq_(field, 'user_id') def test_get_view_field_name(self): field = self.provider.get_view_field_name(User, ['name']) eq_(field, 'user_name') def test_get_view_field_name_not_found(self): field = self.provider.get_view_field_name(User, []) eq_(field, '_password') def test_get_dropdown_options_fk(self): options = self.provider.get_dropdown_options(User, 'town') eq_(options, [(1, u'Arvada'), (2, u'Denver'), (3, u'Golden'), (4, u'Boulder')]) def test_get_dropdown_options_join(self): options = self.provider.get_dropdown_options(User, 'groups') eq_(options, [(1, u'0'), (2, u'1'), (3, u'2'), (4, u'3'), (5, u'4')]) def test_get_dropdown_options_join_2(self): options = self.provider.get_dropdown_options(Group, 'users') eq_(options, [(1, u'asdf'),]) def test_dropdown_options_warn(self): provider = SAORMProvider(metadata) options = provider.get_dropdown_options(User, 'town') eq_(options, []) def test_get_relations(self): relations = self.provider.get_relations(User) eq_(relations, ['town', 'groups']) def test_get_synonyms(self): synonyms = self.provider.get_synonyms(User) eq_(synonyms, ['password']) def test_dictify(self): d = self.provider.dictify(self.user) eq_(d['groups'], [5]) eq_(d['user_name'], 'asdf') def test_dictify_none(self): d = self.provider.dictify(None) eq_(d, {}) def test_create(self): params = {'user_name':u'asdf2', 'password':u'asdf2', 'email_address':u'email@addy.com', 'groups':[1,4], 'town':2} new_user = self.provider.create(User, params) q_user = self.session.query(User).get(2) assert q_user == new_user def test_query(self): r = self.provider.query(User, limit=20, offset=0) eq_(len(r), 2) def test_update(self): params = {'user_name':u'asdf2', 'password':u'asdf2', 'email_address':u'email@addy.com', 'groups':[1,4], 'town':2} new_user = self.provider.create(User, params) params['email_address'] = u'asdf@asdf.commy' params['created'] = '2008-3-30 12:21:21' params['user_id'] = 2 new_user = self.provider.update(User, params) q_user = self.session.query(User).get(2) eq_(new_user.email_address, u'asdf@asdf.commy') def test_get_default_values(self): assert {} == self.provider.get_default_values(User, {}) def test_get(self): user = self.provider.get(User, params={'user_id':1}) eq_(user['user_name'], 'asdf') def test_delete(self): user = self.provider.delete(User, params={'user_id':1}) users = self.session.query(User).all() assert len(users) == 0 def test_modify_params_for_dates(self): params = self.provider._modify_params_for_dates(Example, {'date_': '1978-8-29'}) eq_(params, {'date_': datetime.datetime(1978, 8, 29, 0, 0)}) def test_modify_params_for_intervals(self): params = self.provider._modify_params_for_dates(Example, {'interval': '1 days, 3:20:01'}) eq_(params, {'interval': datetime.timedelta(days=1, hours=3, minutes=20, seconds=1)}) def test_modify_params_for_relationships_params_with_instance_already(self): group = self.session.query(Group).get(1) params = {'groups':group} params = self.provider._modify_params_for_relationships(User, params) assert params['groups'] == [group], params def test_create_relationships_with_wacky_relation(self): obj = session.query(Group).first() params = {'group_id':obj.group_id, 'users':1} self.provider.update(Group, params) user = session.query(User).get(1) assert user in obj.users def test_create_relationships_remove_groups(self): obj = session.query(Group).first() obj.users.append(self.user) self.provider.update(User, {'user_id':self.user.user_id, 'groups':[]}) session.flush() user = session.query(User).get(1) assert user not in obj.users def test_create_relationships_remove_town(self): town = session.query(Town).first() self.user.town = town self.session.flush() self.provider.update(User, {'user_id':self.user.user_id, 'town':None}) assert self.user.town is None sprox-0.6.4/tests/test_sprockets.py0000644000076700000240000000475711210053407017256 0ustar cperkins1stafffrom sprox.sprockets import Sprocket, SprocketCache, ConfigCache, FillerCache, ViewCache, ConfigCacheError from sprox.test.base import setup_database, sorted_user_columns, SproxTest, User from nose.tools import raises, eq_ session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class TestViewCache(SproxTest): def setup(self): super(TestViewCache, self).setup() self.cache = ViewCache(session) def test_create(self): pass @raises(ConfigCacheError) def test_config_not_found(self): self.cache['never_find_me'] def test_get_model_view(self): base = self.cache['model_view'] eq_(base(), """""") def test_get_empty(self): base = self.cache['listing__User'] b = base() assert """
actions _password user_id user_name email_address display_name created town_id town password groups
No Records Found. """ in b, b @raises(ConfigCacheError) def get_not_found(self): self.cache['not_find_me'] class TestSprocketCache: def setup(self): self.cache = SprocketCache(session) def test_create(self): pass def test_get_sprocket(self): base = self.cache['listing__User'] assert base.view is not None assert base.filler is not None sprox-0.6.4/tests/test_tablebase.py0000644000076700000240000000215411210054420017144 0ustar cperkins1stafffrom sprox.tablebase import TableBase from sprox.test.base import setup_database, sorted_user_columns, SproxTest, setup_records, Example from sprox.test.model import User from sprox.widgetselector import SAWidgetSelector from sprox.metadata import FieldsMetadata from nose.tools import raises, eq_ from formencode import Invalid session = None engine = None connection = None def setup(): global session, engine, metadata session, engine, metadata = setup_database() user = setup_records(session) def teardown(): session.rollback() class UserTable(TableBase): __entity__ = User class TestTableBase: def setup(self): self.base = UserTable(session) def test_create(self): pass def test__widget__(self): rendered = self.base.__widget__() assert """ actions _password user_id user_name email_address """ in rendered, rendered sprox-0.6.4/tests/test_testbase.py0000644000076700000240000000206111221216471017041 0ustar cperkins1stafffrom sprox.test.base import eq_xml, in_xml, fix_xml def test_fix_xml(): s = """
""" e = """
""" r =fix_xml(s) assert r == e, r def test_fix_xml_with_escapes(): s = """
 
""" e = """
""" r =fix_xml(s) assert r == e, r def test_fix_xml_with_namespace(): s = """
 
""" e = """
""" r =fix_xml(s) sprox-0.6.4/tests/test_util.py0000644000076700000240000000061511131150323016200 0ustar cperkins1stafffrom sprox.util import MultiDict from nose.tools import eq_ class TestMultiDict: def setup(self): self.m = MultiDict() self.m['a'] = 1 self.m['b'] = 2 self.m['a'] = 3 def test_create(self): pass def TestIteritems(self): actual = [(key, value) for key, value in self.m.iteritems()] eq_(actual, [('a', 1), ('a', 3), ('b', 2)])sprox-0.6.4/tests/test_validators.py0000644000076700000240000000137611131150323017400 0ustar cperkins1stafffrom nose.tools import raises from sprox.validators import UniqueValue from sprox.test.base import * from formencode import Invalid from sprox.saormprovider import SAORMProvider session = None engine = None connection = None trans = None def setup(): global session, engine, connect, trans session, engine, connect = setup_database() def teardown(): global session, trans class TestUniqueValue(SproxTest): def setup(self): super(TestUniqueValue, self).setup() self.validator = UniqueValue(SAORMProvider(session), User, 'user_name') @raises(Invalid) def test_to_python_invalid(self): self.validator.to_python(u'asdf', None) def test_to_python_valid(self): self.validator.to_python(u'asdf1234', None) sprox-0.6.4/tests/test_validatorselector.py0000644000076700000240000000541311131150323020752 0ustar cperkins1stafffrom nose.tools import raises, eq_ from sprox.validatorselector import ValidatorSelector, SAValidatorSelector from sprox.test.base import * from formencode.validators import * from formencode.compound import All from sqlalchemy import Column, Integer from sqlalchemy.databases.oracle import * from sprox.saormprovider import SAORMProvider from types import NoneType session = None engine = None connection = None trans = None def setup(): global session, engine, connect, trans session, engine, connect = setup_database() def teardown(): global session, trans provider = SAORMProvider(metadata=metadata) class TestValidatorSelector(SproxTest): def setup(self): self.validatorSelector = ValidatorSelector() super(TestValidatorSelector, self).setup() def test_createObj(self): pass def testSelect(self): assert issubclass(self.validatorSelector.select('lala'), UnicodeString) class TestSAValidatorSelector(SproxTest): testColumns = ( (BLOB, NoneType), (BOOLEAN, NoneType), (Binary, NoneType), (Boolean, NoneType), (CHAR, UnicodeString), (CLOB, UnicodeString), (DATE, DateValidator), (DATETIME, DateValidator), (DECIMAL, Number), (Date, DateValidator), (DateTime, DateValidator), (FLOAT, Number), (Float, Number), (INT, Int), (Integer, Int), (Numeric, Number), (PickleType, UnicodeString), (SMALLINT, Int), (SmallInteger,Int), (String, UnicodeString), (TEXT, UnicodeString), (TIME, DateValidator), (Time, DateValidator), (TIMESTAMP, DateValidator), (Unicode, UnicodeString), (VARCHAR, UnicodeString), (OracleNumeric, Number), (OracleDate, DateValidator), (OracleDateTime, DateValidator), (OracleInteger, Int), (OracleSmallInteger, Int), ) def setup(self): super(TestSAValidatorSelector, self).setup() self.validator_selector = SAValidatorSelector(provider) def test_createObj(self): pass def test_select(self): for type, expected in self.testColumns: args={} if isinstance(type, Text): args['size'] = 100 c = Column('asdf', type, args) yield self._test_select, c, expected def _test_select(self, column, expected): validator = self.validator_selector.select(column) assert isinstance(validator, expected) or issubclass(validator, expected), validator def test_name_based_validator_select(self): c = Column('email_address', String) validator = self.validator_selector.select(c) assert issubclass(validator, Email), validator sprox-0.6.4/tests/test_viewbase.py0000644000076700000240000001057711212067752017055 0ustar cperkins1stafffrom sprox.viewbase import ViewBase from sprox.test.base import setup_database from sprox.test.model import User from sprox.widgetselector import SAWidgetSelector from nose.tools import raises, eq_ from tw.forms import TextField, HiddenField, Widget session = None engine = None connection = None trans = None def setup(): global session, engine, metadata, trans session, engine, metadata = setup_database() class DummyWidgetSelector(object): def select(self, *args, **kw): return TextField class DummyMetadata(object): def __init__(self, provider, entity): self.entity = entity self.provider = provider def keys(self): return self.provider.get_fields(self.entity) def __getitem__(self, name): return self.provider.get_field(self.entity, name) class DummyWidget(Widget): params = ['test_param'] class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __widget_selector__ = SAWidgetSelector() class TestViewBase: def setup(self): self.base = UserView() def test_create(self): pass def test__fields__(self): eq_(['_password', 'created', 'display_name', 'email_address', 'groups', 'password', 'town', 'town_id', 'user_id', 'user_name'], sorted(self.base.__fields__)) def test__widget__(self): eq_(None, self.base.__widget__()) def test_widget_with_attrs(self): class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __field_attrs__ = {'password':{'class':'mypassclass'}} __widget_selector_type__ = DummyWidgetSelector user_view = UserView() widget = user_view.__widget__ child = widget.children['password'] eq_(child.attrs, {'class':'mypassclass'}) def test_hidden_fields(self): class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __hide_fields__ = ['password'] user_view = UserView() widget = user_view.__widget__ child = widget.children['password'] assert isinstance(child, HiddenField), child.__class__ def test_custom_field(self): class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __field_widgets__ = {'password':TextField(id='password')} user_view = UserView() widget = user_view.__widget__ child = widget.children['password'] assert isinstance(child, TextField), child.__class__ def test_custom_with_none(self): class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __add_fields__ = {'password':None} user_view = UserView() widget = user_view.__widget__ child = widget.children['password'] assert isinstance(child, Widget), str(child.__class__) def test_omit_fields(self): class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __omit_fields__ = ['password'] user_view = UserView() widget = user_view.__widget__ assert 'password' not in widget.children.keys() def test_bad_fieldname_in_limit(self): class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __limit_fields__ = ['junk'] user_view = UserView() widget = user_view.__widget__ assert 'junk' not in widget.children.keys() def test_widget_attrs(self): class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __field_widget_args__ = {'password':{'test_param':'crazy_param'}} password = DummyWidget user_view = UserView() widget = user_view.__widget__ assert widget.children['password'].test_param == 'crazy_param' def test_widget_attrs_hidden_field(self): class UserView(ViewBase): __entity__ = User __metadata_type__ = DummyMetadata __field_widget_args__ = {'password':{'css_classes':['crazy_param']}} __hide_fields__ = ['password'] user_view = UserView() widget = user_view.__widget__ assert widget.children['password'].css_classes == ['crazy_param'], widget.children['password'].css_classes sprox-0.6.4/tests/test_widgets.py0000644000076700000240000000035611141405217016701 0ustar cperkins1stafffrom sprox.widgets import SproxCheckBox from nose.tools import raises, eq_ class TestSproxCheckbox: def setup(self): self.widget = SproxCheckBox() def test_checkbox_invalid_data(self): self.widget(value = 'asdf')sprox-0.6.4/tests/test_widgetselector.py0000644000076700000240000000731111133174000020247 0ustar cperkins1stafffrom nose.tools import raises, eq_ from tw.forms.fields import * from tw.api import Widget from sqlalchemy import Column, Integer from sqlalchemy.types import * from sqlalchemy.databases.oracle import * from sqlalchemy.orm import class_mapper from sprox.widgetselector import WidgetSelector, SAWidgetSelector, EntityDefWidget, EntityDefWidgetSelector, RecordFieldWidget, RecordViewWidgetSelector from sprox.widgets.widgets import * from sprox.saormprovider import SAORMProvider from sprox.test.model import Document class TestWidgetSelector: def setup(self): self.widgetSelector = WidgetSelector() def test_createObj(self): pass def testSelect(self): assert self.widgetSelector.select('lala') == Widget class DummySAWidgetSelector(SAWidgetSelector): default_name_based_widgets = { 'goodGollyMissMolly': TextField, } class TestEntityDefWidgetSelector: def setup(self): self.selector = EntityDefWidgetSelector() def test_select(self): r = self.selector.select('something') eq_(r, EntityDefWidget) class TestRecordViewWidgetSelector: def setup(self): self.selector = RecordViewWidgetSelector() def test_select(self): r = self.selector.select('something') eq_(r, RecordFieldWidget) class TestSAWidgetSelector: testColumns = ( (BLOB, FileField), (BOOLEAN, SproxCheckBox), (Binary, FileField), (Boolean, SproxCheckBox), (CHAR(100), TextField), (CLOB, TextArea), (DATE, SproxCalendarDatePicker), (DATETIME, SproxCalendarDateTimePicker), (DECIMAL, TextField), (Date, SproxCalendarDatePicker), (DateTime, SproxCalendarDateTimePicker), (FLOAT, TextField), (Float, TextField), (INT, TextField), (Integer, TextField), (Numeric, TextField), (PickleType, TextArea), (SMALLINT, TextField), (SmallInteger,TextField), (String(100),TextField), (TEXT, TextArea), (TIME, SproxTimePicker), (Time, SproxTimePicker), (TIMESTAMP, SproxCalendarDateTimePicker), (Unicode(100), TextField), (Unicode, TextArea), (VARCHAR(100), TextField), (OracleNumeric, TextField), (OracleDate, SproxCalendarDatePicker), (OracleDateTime, SproxCalendarDateTimePicker), (OracleInteger, TextField), (OracleSmallInteger, TextField), ) def setup(self): self.widgetSelector = SAWidgetSelector() def test_createObj(self): pass def _testSelect(self, column, expected): widget = self.widgetSelector.select(column) assert widget == expected, "expected: %s\nactual: %s"%(expected, widget) def testSelect(self): for type, expected in self.testColumns: args={} if isinstance(type, Text): args['size'] = 100 c = Column('asdf', type, args) yield self._testSelect, c, expected @raises(TypeError) def _select(self, arg1): self.widgetSelector.select(arg1) def testPasswordField(self): c = Column('password', String(100)) self._testSelect(c, PasswordField) def testTextArea(self): c = Column('long_text', String(1000)) self._testSelect(c, TextArea) def testNameBasedWidgetSelect(self): c = Column('goodGollyMissMolly', Integer) selector = DummySAWidgetSelector() widget = selector.select(c) assert widget is TextField def test_synonym_property(self): mapper = class_mapper(Document) c = mapper.get_property('address') field = self.widgetSelector.select(c) eq_(field, TextField)sprox-0.6.4/tests/widgets/0000755000076700000240000000000011236057646015302 5ustar cperkins1staffsprox-0.6.4/tests/widgets/__init__.py0000644000076700000240000000000011123744670017374 0ustar cperkins1staffsprox-0.6.4/tests/widgets/test_widgets.py0000644000076700000240000000065211131150323020340 0ustar cperkins1stafffrom __future__ import absolute_import from nose.tools import eq_ from sprox.widgets import ContainerWidget from sprox.test.base import setup_database def setup(): setup_database() class TestContainerWidget: def setup(self): self.widget = ContainerWidget() def test_createObj(self): pass def test_display(self): s = self.widget.render() assert 'class="containerwidget"' in s