sprox-0.9.6/ 0000755 0000765 0000024 00000000000 12546321746 012766 5 ustar amol staff 0000000 0000000 sprox-0.9.6/MANIFEST.in 0000644 0000765 0000024 00000000502 12472732352 014516 0 ustar amol staff 0000000 0000000 recursive-include sprox/widgets/tw1widgets/templates *
recursive-include sprox/widgets/tw1widgets/static *
recursive-include sprox/widgets/tw2widgets/templates *
recursive-include sprox/widgets/tw2widgets/static *
global-exclude __pycache__/*
global-exclude *.pyc
recursive-exclude tests *
recursive-exclude sprox/test *
sprox-0.9.6/PKG-INFO 0000644 0000765 0000024 00000001253 12546321746 014064 0 ustar amol staff 0000000 0000000 Metadata-Version: 1.1
Name: sprox
Version: 0.9.6
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.9.6/README.rst 0000644 0000765 0000024 00000001356 12472732435 014461 0 ustar amol staff 0000000 0000000 Sprox
==============
.. image:: https://travis-ci.org/TurboGears/sprox.png
:target: https://travis-ci.org/TurboGears/sprox
.. image:: https://coveralls.io/repos/TurboGears/sprox/badge.png
:target: https://coveralls.io/r/TurboGears/sprox
.. image:: https://pypip.in/v/sprox/badge.png
:target: https://pypi.python.org/pypi/sprox
.. image:: https://pypip.in/d/sprox/badge.png
:target: https://pypi.python.org/pypi/sprox
Form Generation from database schema for ToscaWidgets with support for various database backends
License
-----------
Sprox is licensed under an MIT-style license (see LICENSE.txt).
Other incorporated projects may be licensed under different licenses.
All licenses allow for non-commercial and commercial use.
sprox-0.9.6/setup.cfg 0000644 0000765 0000024 00000000201 12546321746 014600 0 ustar amol staff 0000000 0000000 [aliases]
release = egg_info -rDb "" sdist bdist_egg register upload
[egg_info]
tag_build =
tag_svn_revision = 0
tag_date = 0
sprox-0.9.6/setup.py 0000644 0000765 0000024 00000004472 12472732352 014504 0 ustar amol staff 0000000 0000000 #setup.py
import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
exec(compile(open(os.path.join(here, 'sprox', 'release.py')).read(), 'release.py', 'exec'), globals(), locals())
import sys
py_version = sys.version_info[:2]
DEPENDENCIES = ['formencode>=1.3.0a1']
if py_version == (3, 2):
DEPENDENCIES += ['markupsafe<0.16']
else:
DEPENDENCIES += ['markupsafe']
TESTS_DEPENDENCIES = ['sqlalchemy', 'sieve']
TEST_SUITE_DEPENDENCIES = TESTS_DEPENDENCIES + ['tw2.forms', 'genshi', 'mako']
MONGODB_TEST_SUITE_DEPENDENCIES = TEST_SUITE_DEPENDENCIES + ['ming']
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=DEPENDENCIES,
tests_require=TESTS_DEPENDENCIES,
extras_require={
# Used by Travis and Coverage due to setup.py nosetests
# causing a coredump when used with coverage
'testing': TEST_SUITE_DEPENDENCIES,
'testing_mongodb': MONGODB_TEST_SUITE_DEPENDENCIES
},
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.9.6/sprox/ 0000755 0000765 0000024 00000000000 12546321746 014141 5 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/__init__.py 0000644 0000765 0000024 00000000000 12472732352 016235 0 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/_compat.py 0000644 0000765 0000024 00000000603 12472732352 016131 0 ustar amol staff 0000000 0000000 import platform, sys
if platform.system() == 'Windows': # pragma: no cover
WIN = True
else: # pragma: no cover
WIN = False
# True if we are running on Python 3.
PY2 = sys.version_info[0] == 2
if not PY2: # pragma: no cover
string_type = str
unicode_text = str
byte_string = bytes
else:
string_type = basestring
unicode_text = unicode
byte_string = str
sprox-0.9.6/sprox/_validatorselector.py 0000644 0000765 0000024 00000003561 12472732352 020402 0 ustar amol staff 0000000 0000000 """
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-10 Christopher Perkins
Original Version by Christopher Perkins 2007
Released under MIT license.
"""
from formencode import Invalid
from formencode.validators import StringBool, Number, UnicodeString as FEUnicodeString, Email, Int
try: #pragma: no cover
import tw2.forms
from tw2.core.validation import *
class UnicodeString(FEUnicodeString):
outputEncoding = None
except ImportError: #pragma: no cover
from tw.forms.validators import *
DateTimeValidator = DateValidator
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)
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 {}
sprox-0.9.6/sprox/_widgetselector.py 0000644 0000765 0000024 00000002365 12472732352 017701 0 ustar amol staff 0000000 0000000 """
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.
"""
try: #pragma: no cover
from tw2.core import Widget
from tw2.forms.widgets import *
except ImportError as e: #pragma: no cover
from tw.api import Widget
from tw.forms.fields import *
from sprox.widgets import *
class WidgetSelector(object):
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
sprox-0.9.6/sprox/configbase.py 0000644 0000765 0000024 00000020214 12472732352 016607 0 ustar amol staff 0000000 0000000 from formencode.validators import Validator
from sprox.providerselector import ProviderTypeSelector
import copy
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 |
+-----------------------------------+--------------------------------------------+------------------------------+
| __possible_field_name_defaults__ | Default foreign field name list for | ['name', 'title', '_name', |
| | relationship columns. | 'description', |
| | Used when there is no entry in | '_description'] |
| | __possible_field_names__. | |
+-----------------------------------+--------------------------------------------+------------------------------+
"""
# 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
__possible_field_name_defaults__ = ['name', 'title', '_name', 'description', '_description']
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_defaults_from_entity()
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(list(self.__add_fields__.keys()))
fields = self.__remove_duplicates(fields)
return fields
else:
fields = list(self.__metadata__.keys())
fields.extend(list(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__ = {}
def _do_init_defaults_from_entity(self):
"""
Users model __sprox__ attribute to
setup some defaults. This is useful for
TGAdmin to make possible for people to
customize its behavior without having to
write a custom AdminConfig
"""
sprox_meta = getattr(self.__entity__, '__sprox__', None)
if sprox_meta:
for attr, value in list(vars(sprox_meta).items()):
if not attr.startswith('_'):
setattr(self, '__'+attr+'__', copy.deepcopy(value))
sprox-0.9.6/sprox/dojo/ 0000755 0000765 0000024 00000000000 12546321746 015074 5 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/dojo/__init__.py 0000644 0000765 0000024 00000000000 12472732352 017170 0 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/dojo/fillerbase.py 0000755 0000765 0000024 00000001573 12472732352 017564 0 ustar amol staff 0000000 0000000 """
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.pop('start', None)
limit = kw.pop('count', None)
order_by = kw.pop('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=len(items), items=items)
sprox-0.9.6/sprox/dojo/formbase.py 0000644 0000765 0000024 00000020404 12472732352 017241 0 ustar amol staff 0000000 0000000 """
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.widgets.tw1widgets.dojo import SproxDojoSelectShuttleField, SproxDojoSortedSelectShuttleField
SAWidgetSelector = None
SAORMProvider = None
try:
from sprox.sa.widgetselector import SAWidgetSelector
from sprox.sa.provider import SAORMProvider
except ImportError: # pragma: no cover
pass
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`
"""
@property
def __widget_selector_type__(self):
if isinstance(self.__provider__, SAORMProvider):
return DojoSAWidgetSelector
return super(DojoFormBase, self).__widget_selector_type__
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
"""
@property
def __widget_selector_type__(self):
if isinstance(self.__provider__, SAORMProvider):
return DojoSAWidgetSelector
return super(EditableForm, self).__widget_selector_type__
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
"""
@property
def __widget_selector_type__(self):
if isinstance(self.__provider__, SAORMProvider):
return DojoSAWidgetSelector
return super(AddRecordForm, self).__widget_selector_type__
sprox-0.9.6/sprox/dojo/sprockets.py 0000644 0000765 0000024 00000003606 12472732352 017465 0 ustar amol staff 0000000 0000000 """
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 = FillerCache sprox-0.9.6/sprox/dojo/tablebase.py 0000755 0000765 0000024 00000004745 12472732352 017402 0 ustar amol staff 0000000 0000000 from tw.dojo import DojoJsonRestStore
from sprox.widgets.tw1widgets.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:
+-----------------------------------+--------------------------------------------+------------------------------+
| Name | Description | Default |
+===================================+============================================+==============================+
| __url__ | url that points to the method for data | None |
| | filler for this table | |
+-----------------------------------+--------------------------------------------+------------------------------+
| __column_options__ | a pass-thru to the Dojo Table Widget | {} |
| | column_options attribute | |
+-----------------------------------+--------------------------------------------+------------------------------+
also 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.9.6/sprox/dummyentity.py 0000644 0000765 0000024 00000000027 12472732352 017077 0 ustar amol staff 0000000 0000000 class DummyEntity:pass
sprox-0.9.6/sprox/entitiesbase.py 0000644 0000765 0000024 00000010554 12472732352 017174 0 ustar amol staff 0000000 0000000 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())
Name
Definition
password
VARCHAR(40)
user_id
INTEGER
user_name
VARCHAR(16)
email_address
VARCHAR(255)
display_name
VARCHAR(255)
created
DATETIME
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())
"""
__entity__ = DummyEntity
__base_widget_type__ = ContainerWidget
__widget_selector_type__ = EntitiesViewWidgetSelector
__metadata_type__ = EntitiesMetadata
sprox-0.9.6/sprox/fillerbase.py 0000644 0000765 0000024 00000032436 12472732366 016635 0 ustar amol staff 0000000 0000000 """
fillerbase Module
Classes to help fill widgets with data
Copyright (c) 2008-10 Christopher Perkins
Original Version by Christopher Perkins 2008
Released under MIT license.
"""
from .configbase import ConfigBase, ConfigBaseError
from .metadata import FieldsMetadata
import inspect
from datetime import datetime
from sprox._compat import string_type, byte_string, unicode_text
from markupsafe import Markup
encoding = 'utf-8'
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__ | list or dict of names to use for discovery | None |
| | of field names for relationship columns. | (See below.) |
| | (None uses the default list from | |
| | :class:`sprox.configbase:ConfigBase`.) | |
| | A dict provides field-level granularity | |
| | (See also explanation below.) | |
+-----------------------------------+--------------------------------------------+------------------------------+
| __datetime_formatstr__ | format string for the strftime function of | '%Y-%m-%d %H:%M:%S' |
| | datetime objects. | ("simplified" ISO-8601) |
| | Classical american format would be | |
| | '%m/%d/%Y %H:%M%p'. | |
+-----------------------------------+--------------------------------------------+------------------------------+
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 specified
in __possible_field_name_defaults__: _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__ = None
__datetime_formatstr__ = '%Y-%m-%d %H:%M:%S'
def _do_init_attrs(self):
super(TableFiller, self)._do_init_attrs()
if self.__possible_field_names__ is None:
self.__possible_field_names__ = self.__possible_field_name_defaults__
def _get_list_data_value(self, field, values):
l = []
if isinstance(self.__possible_field_names__, dict) and field in self.__possible_field_names__:
view_names = self.__possible_field_names__[field]
if not isinstance(view_names, list):
view_names = [view_names]
elif isinstance(self.__possible_field_names__, list):
view_names = self.__possible_field_names__
else:
view_names = self.__possible_field_name_defaults__
for value in values:
if not isinstance(value, string_type):
name = self.__provider__.get_view_field_name(value.__class__, view_names, value)
l.append(unicode_text(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 = '
"""
__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 args
sprox-0.9.6/sprox/release.py 0000644 0000765 0000024 00000000026 12546321653 016126 0 ustar amol staff 0000000 0000000 __version__ = "0.9.6"
sprox-0.9.6/sprox/sa/ 0000755 0000765 0000024 00000000000 12546321746 014544 5 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/sa/__init__.py 0000644 0000765 0000024 00000000000 12472732352 016640 0 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/sa/provider.py 0000644 0000765 0000024 00000061523 12546303426 016752 0 ustar amol staff 0000000 0000000 """
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, Integer, MetaData, desc as _desc, func
from sqlalchemy import String
from sqlalchemy.engine import Engine
from sqlalchemy.orm.session import Session
from sqlalchemy.orm.scoping import ScopedSession
from sqlalchemy.orm.query import Query
from sqlalchemy.orm import Mapper, _mapper_registry, SynonymProperty, object_mapper, class_mapper
from sqlalchemy.orm.exc import UnmappedClassError, NoResultFound, UnmappedInstanceError
from sqlalchemy.exc import InvalidRequestError
from sqlalchemy.schema import Column
from sprox.sa.support import PropertyLoader, resolve_entity, Binary, LargeBinary
from sprox.iprovider import IProvider
from cgi import FieldStorage
from datetime import datetime, date, timedelta
from warnings import warn
from sprox.sa.widgetselector import SAWidgetSelector
from sprox.sa.validatorselector import SAValidatorSelector
from sprox._compat import string_type
class SAORMProviderError(Exception):pass
class SAORMProvider(IProvider):
default_view_names = ['_name', 'name', 'description', 'title']
default_widget_selector_type = SAWidgetSelector
default_validator_selector_type = SAValidatorSelector
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):
entity = resolve_entity(entity)
mapper = class_mapper(entity)
field_names = list(mapper.c.keys())
for prop in mapper.iterate_properties:
try:
mapper.c[prop.key]
field_names.append(prop.key)
except KeyError:
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):
entity = resolve_entity(entity)
mapper = class_mapper(entity)
try:
return mapper.c[name]
except (InvalidRequestError, KeyError):
try:
return mapper.get_property(name)
except InvalidRequestError:
raise AttributeError
def is_binary(self, entity, name):
field = self.get_field(entity, name)
if isinstance(field, PropertyLoader):
field = self._relationship_local_side(field)[0]
if isinstance(field, SynonymProperty):
field = self.get_field(entity, field.name)
return isinstance(field.type, (Binary, LargeBinary))
def is_nullable(self, entity, name):
field = self.get_field(entity, name)
if isinstance(field, SynonymProperty):
field = self.get_field(entity, field.name)
if isinstance(field, PropertyLoader):
return getattr(self._relationship_local_side(field)[0], 'nullable')
return getattr(field, 'nullable', True)
def is_string(self, entity, name):
field = self.get_field(entity, name)
if isinstance(field, PropertyLoader):
field = self._relationship_local_side(field)[0]
if isinstance(field, SynonymProperty):
field = self.get_field(entity, field.name)
#should cover Unicode, UnicodeText, Text and so on by inheritance
return isinstance(field.type, String)
def get_primary_fields(self, entity):
entity = resolve_entity(entity)
mapper = class_mapper(entity)
fields = []
for field_name in self.get_fields(entity):
try:
value = mapper.c[field_name]
except KeyError:
# Relations won't be attributes, but can't be primary anyway.
continue
if value.primary_key and not field_name in fields:
fields.append(field_name)
return fields
def get_primary_field(self, entity):
fields = self.get_primary_fields(entity)
assert len(fields) > 0
return fields[0]
def _find_title_column(self, entity):
entity = resolve_entity(entity)
for column in class_mapper(entity).columns:
if 'title' in column.info and column.info['title']:
return column.key
return None
def get_view_field_name(self, entity, possible_names, item=None):
view_field = self._find_title_column(entity)
fields = self.get_fields(entity)
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 = self.default_view_names
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
target_field = resolve_entity(target_field)
#some kind of relation
if isinstance(target_field, Mapper):
target_field = target_field.class_
pk_fields = self.get_primary_fields(target_field)
view_name = self.get_view_field_name(target_field, view_names)
rows = self.session.query(target_field).all()
if len(pk_fields) == 1:
def build_pk(row):
return getattr(row, pk_fields[0])
else:
def build_pk(row):
return "/".join([str(getattr(row, pk)) for pk in pk_fields])
return [ (build_pk(row), getattr(row, view_name)) for row in rows ]
def get_relations(self, entity):
entity = resolve_entity(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):
entity = resolve_entity(entity)
mapper = class_mapper(entity)
try:
property = mapper.get_property(field_name)
except InvalidRequestError:
return False
if isinstance(property, PropertyLoader):
return True
def _relates_many(self, entity, field_name):
entity = resolve_entity(entity)
mapper = class_mapper(entity)
property = mapper.get_property(field_name)
return property.uselist
def relation_fields(self, entity, field_name):
field = getattr(entity, field_name)
return [col.name for col in self._relationship_local_side(field.property)]
def is_query(self, entity, value):
"""determines if a field is a query instead of actual list of data"""
return isinstance(value, Query)
def is_unique(self, entity, field_name, value):
entity = resolve_entity(entity)
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):
entity = resolve_entity(entity)
mapper = class_mapper(entity)
return [prop.key for prop in mapper.iterate_properties if isinstance(prop, SynonymProperty)]
def _adapt_type(self, value, primary_key):
if isinstance(primary_key.type, Integer):
value = int(value)
return value
def _relationship_local_side(self, relationship):
if hasattr(relationship, 'local_columns'):
return list(relationship.local_columns)
return list(relationship.local_side) #pragma: no cover
def _modify_params_for_relationships(self, entity, params):
entity = resolve_entity(entity)
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
target = resolve_entity(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:
if hasattr(target, 'primary_key'):
pk = target.primary_key
else:
pk = class_mapper(target).primary_key
if isinstance(v, string_type) and "/" in v:
v = map(self._adapt_type, v.split("/"), pk)
v = tuple(v)
else:
v = self._adapt_type(v, pk[0])
#only add those items that come back
new_v = self.session.query(target).get(v)
if new_v is not None:
target_obj.append(new_v)
elif prop.uselist:
try:
object_mapper(value)
target_obj = [value]
except UnmappedInstanceError:
mapper = target
if not isinstance(target, Mapper):
mapper = class_mapper(target)
value = self._adapt_type(value, mapper.primary_key[0])
target_obj = [self.session.query(target).get(value)]
else:
try:
object_mapper(value)
target_obj = value
except UnmappedInstanceError:
if isinstance(value, string_type) and "/" in value:
value = map(self._adapt_type, value.split("/"), prop.remote_side)
value = tuple(value)
else:
value = self._adapt_type(value, list(prop.remote_side)[0])
target_obj = self.session.query(target).get(value)
params[relation] = target_obj
else:
if prop.uselist:
params[relation] = []
else:
params[relation] = None
return params
def create(self, entity, params):
entity = resolve_entity(entity)
params = self._modify_params_for_dates(entity, params)
params = self._modify_params_for_relationships(entity, params)
obj = entity()
relations = self.get_relations(entity)
mapper = class_mapper(entity)
for key, value in params.items():
if value is not None:
if isinstance(value, FieldStorage):
value = value.file.read()
try:
if key not in relations and value and isinstance(mapper.columns[key].type, Integer):
value = int(value)
except KeyError:
pass
setattr(obj, key, value)
self.session.add(obj)
self.session.flush()
return obj
def flush(self):
self.session.flush()
def dictify(self, obj, fields=None, omit_fields=None):
if obj is None:
return {}
r = {}
mapper = class_mapper(obj.__class__)
for prop in mapper.iterate_properties:
if fields and prop.key not in fields:
continue
if omit_fields and prop.key in omit_fields:
continue
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) or isinstance(value, Query):
#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_field_default(self, field):
if isinstance(field, Column) and field.default and getattr(field.default, 'arg', None) is not None:
if isinstance(field.default.arg, (string_type, int, float)):
return (True, field.default.arg)
elif callable(field.default.arg):
# SQLAlachemy wraps default so that they receive a context, but TW can't provide one
return (True, lambda: field.default.arg(None))
return (False, None)
def get_field_provider_specific_widget_args(self, entity, field, field_name):
args = {}
if isinstance(field, PropertyLoader):
args['provider'] = self
args['nullable'] = self.is_nullable(entity, field_name)
return args
def get_default_values(self, entity, params):
return params
def get_obj(self, entity, params, fields=None, omit_fields=None):
obj = self._get_obj(entity, params)
return obj
def get(self, entity, params, fields=None, omit_fields=None):
obj = self.get_obj(entity, params, fields)
return self.dictify(obj, fields, omit_fields)
def _escape_like(self, value):
return value.replace('*', '**').replace('%', '*%').replace('_', '*_')
def _get_related_class(self, entity, relation):
entity = resolve_entity(entity)
mapper = class_mapper(entity)
prop = mapper.get_property(relation)
target = resolve_entity(prop.argument)
if not hasattr(target, 'class_'):
target = class_mapper(target)
return target.class_
def _modify_params_for_related_searches(self, entity, params, view_names=None, substrings=()):
if view_names is None:
view_names = self.default_view_names
relations = self.get_relations(entity)
for relation in relations:
if relation in params:
value = params[relation]
if not isinstance(value, string_type):
# When not a string consider it the related class primary key
params.update(self._modify_params_for_relationships(entity, {relation: value}))
continue
if not value:
# As we use ``contains``, searching for an empty text
# will just lead to all results so we just remove the filter.
del params[relation]
continue
target_class = self._get_related_class(entity, relation)
view_name = self.get_view_field_name(target_class, view_names)
related_column = getattr(target_class, view_name)
if relation in substrings:
escaped_value = self._escape_like(value.lower())
filter = func.lower(related_column).contains(
escaped_value, escape='*'
)
else:
filter = (func.lower(related_column) == value.lower())
params[relation] = self.session.query(target_class).filter(filter).all()
return params
def query(self, entity, limit=None, offset=None, limit_fields=None,
order_by=None, desc=False, field_names=[], filters={},
substring_filters=[], search_related=False, related_field_names=None,
**kw):
entity = resolve_entity(entity)
query = self.session.query(entity)
filters = self._modify_params_for_dates(entity, filters)
if search_related:
# Values for related fields contain the text to search
filters = self._modify_params_for_related_searches(entity, filters,
view_names=related_field_names,
substrings=substring_filters)
else:
# Values for related fields contain the primary key
filters = self._modify_params_for_relationships(entity, filters)
for field_name, value in filters.items():
field = getattr(entity, field_name)
if self.is_relation(entity, field_name) and isinstance(value, list):
related_class = self._get_related_class(entity, field_name)
related_pk = self.get_primary_field(related_class)
related_pk_col = getattr(related_class, related_pk)
related_pk_values = (getattr(v, related_pk) for v in value)
if self._relates_many(entity, field_name):
field_filter = field.any(related_pk_col.in_(related_pk_values))
else:
field_filter = field.has(related_pk_col.in_(related_pk_values))
query = query.filter(field_filter)
elif field_name in substring_filters and self.is_string(entity, field_name):
escaped_value = self._escape_like(value.lower())
query = query.filter(func.lower(field).contains(escaped_value, escape='*'))
else:
query = query.filter(field==value)
count = query.count()
if order_by is not None:
if self.is_relation(entity, order_by):
mapper = class_mapper(entity)
class_ = None
for prop in mapper.iterate_properties:
try:
class_ = prop.mapper.class_
except (AttributeError, KeyError):
pass
query = self.session.query(entity).join(order_by)
f = self.get_view_field_name(class_, field_names)
field = self.get_field(class_, f)
else:
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):
entity = resolve_entity(entity)
mapper = class_mapper(entity)
for key, value in list(params.items()):
if key in mapper.c and value is not None:
field = mapper.c[key]
if hasattr(field, 'type'):
if isinstance(field.type, DateTime):
if not isinstance(value, datetime):
dt = datetime.strptime(value[:19], '%Y-%m-%d %H:%M:%S')
params[key] = dt
elif isinstance(field.type, Date):
if not isinstance(value, date):
dt = datetime.strptime(value, '%Y-%m-%d').date()
params[key] = dt
elif isinstance(field.type, Interval):
if 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 list(d.items()) )))
params[key] = dt
return params
def _remove_related_empty_params(self, obj, params, omit_fields=None):
entity = obj.__class__
mapper = class_mapper(entity)
relations = self.get_relations(entity)
for relation in relations:
if omit_fields and relation in omit_fields:
continue
#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 _get_obj(self, entity, pkdict):
entity = resolve_entity(entity)
pk_names = self.get_primary_fields(entity)
pks = tuple([pkdict[n] for n in pk_names])
return self.session.query(entity).get(pks)
def update(self, entity, params, omit_fields=None):
params = self._modify_params_for_dates(entity, params)
params = self._modify_params_for_relationships(entity, params)
obj = self._get_obj(entity, params)
relations = self.get_relations(entity)
mapper = object_mapper(obj)
for key, value in params.items():
if omit_fields and key in omit_fields:
continue
if isinstance(value, FieldStorage):
value = value.file.read()
# this is done to cast any integer columns into ints before they are
# sent off to the interpreter. Oracle really needs this.
try:
if key not in relations and value:
value = self._adapt_type(value, mapper.columns[key])
except KeyError:
pass
setattr(obj, key, value)
self._remove_related_empty_params(obj, params, omit_fields)
self.session.flush()
return obj
#this is hard to test because of some kind of rollback issue in the test framework
def delete(self, entity, params):
obj = self._get_obj(entity, params) # pragma: no cover
self.session.delete(obj) # pragma: no cover
return obj # pragma: no cover
def get_field_widget_args(self, entity, field_name, field):
args = {}
prop = getattr(field, 'property', None)
if prop and isinstance(prop, PropertyLoader):
args['provider'] = self
args['nullable'] = self.is_nullable(entity, field_name)
return args
def is_unique_field(self, entity, field_name):
field = self.get_field(entity, field_name)
if hasattr(field, 'unique') and field.unique:
return True
return False
sprox-0.9.6/sprox/sa/support.py 0000644 0000765 0000024 00000001666 12472732352 016640 0 ustar amol staff 0000000 0000000 import inspect
try:
from sqlalchemy.orm import PropertyLoader
except ImportError:
# Compatibility with SQLA0.9
from sqlalchemy.orm import RelationshipProperty as PropertyLoader
try:
from sqlalchemy.ext.declarative.clsregistry import _class_resolver
except ImportError as e: # pragma: no cover
# Compatibility with SQLA < 0.9
_class_resolver = None
try:
# Not available in some SQLA versions
from sqlalchemy.types import LargeBinary
except ImportError: # pragma: no cover
class LargeBinary:
pass
try:
# Future proof as it will probably be removed as deprecated
from sqlalchemy.types import Binary
except ImportError: # pragma: no cover
class Binary(LargeBinary):
pass
def resolve_entity(entity):
if inspect.isfunction(entity):
entity = entity()
if _class_resolver is not None and isinstance(entity, _class_resolver):
entity = entity()
return entity
sprox-0.9.6/sprox/sa/validatorselector.py 0000644 0000765 0000024 00000005254 12472732352 020647 0 ustar amol staff 0000000 0000000 """
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-10 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 formencode.compound import All
from formencode import Invalid
from formencode.validators import StringBool, Number, UnicodeString as FEUnicodeString, Email, Int
from sqlalchemy.orm import SynonymProperty
from sprox.sa.support import PropertyLoader, Binary, LargeBinary
from sprox._validatorselector import ValidatorSelector
try: #pragma: no cover
import tw2.forms
from tw2.core.validation import *
class UnicodeString(FEUnicodeString):
outputEncoding = None
except ImportError: #pragma: no cover
from tw.forms.validators import *
DateTimeValidator = DateValidator
try:
import tw2.forms
from tw2.forms import FileValidator
except ImportError: # pragma: no cover
from formencode.validators import FieldStorageUploadConverter as FileValidator
class SAValidatorSelector(ValidatorSelector):
default_validators = {
StringType: UnicodeString,
Integer: Int,
Numeric: Number,
DateTime: DateTimeValidator,
Date: DateValidator,
Time: DateTimeValidator,
Binary: FileValidator,
LargeBinary: FileValidator,
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, )):
return None
if field.name in self.name_based_validators:
return self.name_based_validators[field.name]
type_ = StringType
for t in list(self.default_validators.keys()):
if isinstance(field.type, t):
type_ = t
break
validator_type = self.default_validators[type_]
return validator_type
sprox-0.9.6/sprox/sa/widgetselector.py 0000644 0000765 0000024 00000005504 12472732352 020143 0 ustar amol staff 0000000 0000000 """
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.types import *
from sprox.widgets import *
from sqlalchemy.schema import Column
from sqlalchemy.orm import SynonymProperty
from sprox.sa.support import PropertyLoader, Binary, LargeBinary
from sprox._widgetselector import WidgetSelector
text_field_limit=100
class SAWidgetSelector(WidgetSelector):
default_widgets = {
String: TextField,
Integer: TextField,
Numeric: TextField,
DateTime: SproxCalendarDateTimePicker,
Date: SproxCalendarDatePicker,
Time: SproxTimePicker,
Binary: FileField,
LargeBinary: FileField,
BLOB: 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
if hasattr(field, 'key') and field.key.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 list(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.9.6/sprox/saormprovider.py 0000644 0000765 0000024 00000001671 12472732352 017411 0 ustar amol staff 0000000 0000000 """
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
This module is deprecated
Copyright (c) 2007-10 Christopher Perkins
Original Version by Christopher Perkins 2007
Released under MIT license.
"""
from .sa.provider import SAORMProvider as _SAORMProvider, SAORMProviderError as _SAORMProviderError
import warnings
class SAORMProviderError(_SAORMProviderError):
def __init__(self, *args, **kw):
warnings.warn('This class has moved to the sprox.sa.provider module.')
_SAORMProviderError.__init__(self, *args, **kw)
class SAORMProvider(_SAORMProvider):
def __init__(self, *args, **kw):
warnings.warn('This class has moved to the sprox.sa.provider module.')
_SAORMProvider.__init__(self, *args, **kw)
sprox-0.9.6/sprox/sprockets.py 0000644 0000765 0000024 00000010545 12472732352 016532 0 ustar amol staff 0000000 0000000 """
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.9.6/sprox/tablebase.py 0000644 0000765 0000024 00000025216 12472732352 016440 0 ustar amol staff 0000000 0000000 """
tablebase Module
Classes to create table widgets.
Copyright (c) 2008-10 Christopher Perkins
Original Version by Christopher Perkins 2008
Released under MIT license.
"""
from operator import itemgetter
try: #pragma: no cover
import tw2.forms
from tw2.core import Widget
from tw2.core.widgets import WidgetMeta
from tw2.forms.datagrid import Column
except ImportError: #pragma: no cover
from tw.forms.datagrid import Column
from tw.api import Widget
class WidgetMeta(object):
pass
from sprox.widgets import SproxDataGrid
from sprox.viewbase import ViewBase
from sprox.metadata import FieldsMetadata
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 dictionary of field/header pairs. | {} |
+-----------------------------------+--------------------------------------------+------------------------------+
| __column_widths__ | A dictionary of field/width(string) pairs. | {} |
+-----------------------------------+--------------------------------------------+------------------------------+
| __default_column_width__ | Header size to use when not specified in | '10em' |
| | __column_widths__ | |
+-----------------------------------+--------------------------------------------+------------------------------+
| __xml_fields__ | fields whose 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()) #doctest: +XML
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(value=value)) #doctest: +SKIP
town_id
name
1
Arvada
2
Denver
3
Golden
4
Boulder
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(value=value)) #doctest: +XML
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 _table_field_is_plain_widget(self, widget):
if widget.__class__ == Widget or\
(widget.__class__ == WidgetMeta and Widget in widget.__bases__):
return True
return False
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_widget_dict = self._do_get_field_widgets(self.__fields__)
field_columns = []
for field in self.__fields__:
widget = field_widget_dict.get(field, None)
if widget is None or self._table_field_is_plain_widget(widget): # yuck
column = Column(field, itemgetter(field), self.__headers__.get(field, field))
else:
column = Column(field, widget, self.__headers__.get(field, field))
field_columns.append(column)
args['fields'] = field_columns
# 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__
args.pop('children', None)
return args
sprox-0.9.6/sprox/util.py 0000644 0000765 0000024 00000007775 12472732352 015505 0 ustar amol staff 0000000 0000000 """
util Module
this contains the class which allows dbsprockets to interface with sqlalchemy.
Copyright (c) 2007 Christopher Perkins
Original Version by Christopher Perkins 2007
Released under MIT license.
"""
from copy import deepcopy, copy
"""
A good portion of this code was lifted from the PyYaml Codebase.
http://pyyaml.org/:
Copyright (c) 2006 Kirill Simonov
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import re, datetime
class ConverterError(Exception):pass
timestamp_regexp = re.compile(
r'''^(?P[0-9][0-9][0-9][0-9])
-(?P[0-9][0-9]?)
-(?P[0-9][0-9]?)
(?:(?:[Tt]|[ \t]+)
(?P[0-9][0-9]?)
:(?P[0-9][0-9])
:(?P[0-9][0-9])
(?:\.(?P[0-9]*))?
(?:[ \t]*(?PZ|(?P[-+])(?P[0-9][0-9]?)
(?::(?P[0-9][0-9]))?))?)?$''', re.X)
def timestamp(value):
match = timestamp_regexp.match(value)
if match is None:
raise ConverterError('Unknown DateTime format, %s try %%Y-%%m-%%d %%h:%%m:%%s.d'%value)
values = match.groupdict()
year = int(values['year'])
month = int(values['month'])
day = int(values['day'])
if not values['hour']:
return datetime.date(year, month, day)
hour = int(values['hour'])
minute = int(values['minute'])
second = int(values['second'])
fraction = 0
if values['fraction']:
fraction = values['fraction'][:6]
while len(fraction) < 6:
fraction += '0'
fraction = int(fraction)
delta = None
if values['tz_sign']:
tz_hour = int(values['tz_hour'])
tz_minute = int(values['tz_minute'] or 0)
delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
if values['tz_sign'] == '-':
delta = -delta
data = datetime.datetime(year, month, day, hour, minute, second, fraction)
if delta:
data -= delta
return data
def name2label(name):
"""
Took from ToscaWidgets2.
Convert a column name to a Human Readable name.
1) Strip _id from the end
2) Convert _ to spaces
3) Convert CamelCase to Camel Case
4) Upcase first character of Each Word
"""
if name.endswith('_id'):
name = name[:-3]
return ' '.join([s.capitalize() for s in
re.findall(r'([A-Z][a-z0-9]+|[a-z0-9]+|[A-Z0-9]+)', name)])
try: #pragma: no cover
from tw2.core import Widget
from tw2.core.widgets import WidgetMeta
from tw2.forms import HiddenField
except ImportError: #pragma: no cover
from tw.api import Widget
from tw.forms import HiddenField
class WidgetMeta(object):
"""TW2 WidgetMetaClass"""
def is_widget(w):
if hasattr(w, 'req'):
return isinstance(w, Widget) or isinstance(w, WidgetMeta) and w.__name__.endswith('_s')
else:
return isinstance(w, Widget)
def is_widget_class(w):
if hasattr(w, 'req'):
return isinstance(w, WidgetMeta) and not w.__name__.endswith('_s')
else:
return issubclass(w, Widget)
sprox-0.9.6/sprox/validators.py 0000644 0000765 0000024 00000001537 12472732366 016673 0 ustar amol staff 0000000 0000000 """
validators Module
Copyright (c) 2008 Christopher Perkins
Original Version by Christopher Perkins 2008
Released under MIT license.
"""
from formencode import FancyValidator, Invalid
from formencode.validators import UnicodeString as FEUnicodeString
from formencode.validators import NotEmpty
class UnicodeString(FEUnicodeString):
outputEncoding = None
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.9.6/sprox/validatorselector.py 0000644 0000765 0000024 00000002204 12472732352 020234 0 ustar amol staff 0000000 0000000 """
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-10 Christopher Perkins
Original Version by Christopher Perkins 2007
Released under MIT license.
"""
from sprox._validatorselector import ValidatorSelector
import warnings
try:
from .sa.validatorselector import SAValidatorSelector as _SAValidatorSelector
class SAValidatorSelector(_SAValidatorSelector):
def __init__(self, *args, **kw):
warnings.warn('This class has moved to the sprox.sa.validatorselector module.') # pragma: no cover
_SAValidatorSelector.__init__(self, *args, **kw) # pragma: no cover
except ImportError: # pragma: no cover
pass # pragma: no cover sprox-0.9.6/sprox/viewbase.py 0000644 0000765 0000024 00000026227 12472732352 016326 0 ustar amol staff 0000000 0000000 import inspect
from sprox.util import name2label, is_widget, is_widget_class
try: #pragma: no cover
from tw2.core import Widget, Deferred
from tw2.core.widgets import WidgetMeta
from tw2.forms import HiddenField
except ImportError: #pragma: no cover
from tw.api import Widget
from tw.forms import HiddenField
class WidgetMeta(object):
"""TW2 WidgetMetaClass"""
from .configbase import ConfigBase, ConfigBaseError
from .widgetselector import WidgetSelector
#sa 0.5 support
try: #pragma:no cover
from sqlalchemy.types import Enum
except: #pragma:no cover
class Enum:
pass
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 is_widget(value):
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 is_widget_class(value):
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__)
return self.___widget__
#try to act like a widget as much as possible
def __call__(self, *args, **kw):
return self.display(*args, **kw)
def display(self, *args, **kw):
if 'value' not in kw and args:
args = list(args)
kw['value'] = args.pop(0)
return self.__widget__.display(*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)
if hasattr(Widget, 'req'):
args.update({'id':'sx_'+field_name, 'key':field_name})
else: #pragma: no cover
args.update({'id':field_name})
args.update({'name':field_name,
'identity':self.__entity__.__name__+'_'+field_name,
'entity':entity, 'provider':self.__provider__,
'label':name2label(field_name), 'label_text':name2label(field_name)})
field_default_value = self.__provider__.get_field_default(entity)
if field_default_value[0]:
if hasattr(Widget, 'req'):
if callable(field_default_value[1]):
args['value'] = Deferred(field_default_value[1])
else:
args['value'] = field_default_value[1]
else: #pragma: no cover
args['default'] = field_default_value[1]
#enum support works completely differently.
#if isinstance(entity, Column) and isinstance(entity.type, Enum):
# args['options'] = entity.type.enums
if field_name in self.__field_attrs__:
args['attrs'] = self.__field_attrs__[field_name]
provider_widget_args = self.__provider__.get_field_provider_specific_widget_args(self.__entity__, field, field_name)
if provider_widget_args:
args.update(provider_widget_args)
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_name in self.__hide_fields__:
if field_name not in self.__omit_fields__:
args = {}
try:
field = self.__metadata__[field_name]
args = self._do_get_field_widget_args(field_name, field)
except KeyError: #pragma: no cover
pass
if field_name in self.__field_widget_args__:
args.update(self.__field_widget_args__[field_name])
fields[field_name] = HiddenField(**args)
return fields
def _do_get_field_widget_type(self, field_name, field):
return self.__field_widget_types__.get(field_name, self.__widget_selector__.select(field))
# This was a typo once, keeping it around for backwards compatibility
_do_get_field_wiget_type = _do_get_field_widget_type
def _do_get_field_widgets(self, fields):
metadata_keys = list(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]
field_widget_type = self._do_get_field_widget_type(field_name, 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
field_widget_args['attrs'] = {'disabled':True}
if hasattr(Widget, 'req'):
hidden_id='disabled_' + field_name.replace('.','_')
else: #pragma: no cover
hidden_id=field_name.replace('.','_')
widgets[field_name] = (HiddenField(id=hidden_id, key=field_name,
name=field_name,
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.9.6/sprox/widgets/ 0000755 0000765 0000024 00000000000 12546321746 015607 5 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/widgets/__init__.py 0000644 0000765 0000024 00000000417 12472732366 017724 0 ustar amol staff 0000000 0000000 try: #pragma: no cover
from .tw2widgets.widgets import *
except ImportError: #pragma: no cover
from .tw1widgets.widgets import *
try: #pragma: no cover
from tw2.forms import CalendarBase
except: #pragma: no cover
class CalendarBase(object):
pass
sprox-0.9.6/sprox/widgets/tw1widgets/ 0000755 0000765 0000024 00000000000 12546321746 017711 5 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/widgets/tw1widgets/__init__.py 0000644 0000765 0000024 00000000000 12472732352 022005 0 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/widgets/tw1widgets/dojo.py 0000755 0000765 0000024 00000010360 12472732352 021216 0 ustar amol staff 0000000 0000000 """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
from tw.dojo import DojoBase, tundragrid_css, tundra_css, dojo_css, dojo_js
from tw.core import JSLink
sprox_grid_js = JSLink(modname="sprox",
filename="widgets/tw1widgets/static/dojo_grid.js",
)
class SproxDojoGrid(DojoBase):
engine_name=None
available_engines = ['mako', 'genshi']
css = [grid_css, tundragrid_css, tundra_css]
javascript=[dojo_js, sprox_grid_js]
dojoType = 'dojox.grid.DataGrid'
require = ['dojox.grid.DataGrid', 'twdojo.data.TWDojoRestStore']
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',
'autoHeight'
]
autoHeight="false"
delayScroll = "true"
cssclass="sprox-dojo-grid"
rowsPerPage = 20
columns = []
columnReordering = "false"
columnResizing="false"
column_widths = {}
column_options = {}
default_column_options = {}
headers = {}
default_column_width = "30px"
include_dynamic_js_calls = True
action='.json'
model = None
actions = True
dojoStoreType = 'dojox.data.QueryReadStore'
dojoStoreWidget = None
template = "sprox.widgets.tw1widgets.templates.dojogrid"
#attrs = {'style':"height:200px"}
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',
'autoHeight'
]
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.tw1widgets.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.9.6/sprox/widgets/tw1widgets/static/ 0000755 0000765 0000024 00000000000 12546321746 021200 5 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/widgets/tw1widgets/static/dojo_grid.js 0000644 0000765 0000024 00000000236 12472732352 023474 0 ustar amol staff 0000000 0000000 //alert('here');
dojo.require("dojo.parser");
dojo.require("dojox.data.QueryReadStore");
dojo.require("dojox.grid.DataGrid");
dojo.require("dojo._base.xhr");
sprox-0.9.6/sprox/widgets/tw1widgets/templates/ 0000755 0000765 0000024 00000000000 12546321746 021707 5 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/widgets/tw1widgets/templates/__init__.py 0000644 0000765 0000024 00000000000 12472732352 024003 0 ustar amol staff 0000000 0000000 sprox-0.9.6/sprox/widgets/tw1widgets/templates/checkbox.html 0000644 0000765 0000024 00000000457 12472732352 024366 0 ustar amol staff 0000000 0000000