Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release/2.1.0'

  • Loading branch information...
commit 02b7bc3a0d598e37d52dcaf886081732c7597f2a 2 parents 644877f + 077cad1
@ralphbean ralphbean authored
View
45 CHANGELOG.rst
@@ -0,0 +1,45 @@
+Changelog
+=========
+
+2.1.0
+-----
+
+- Metadata fixups, tw2.core#90 `382a27e60 <https://github.com/toscawidgets/tw2.sqla/commit/382a27e607be5e4812b6e025b36ed465ededae10>`_
+- Add missing require for the tests `2af2469a4 <https://github.com/toscawidgets/tw2.sqla/commit/2af2469a481c478aea3625f44edeccf63edbfde6>`_
+- Fix tw.Param: the attribute is always defined and required. `517406037 <https://github.com/toscawidgets/tw2.sqla/commit/5174060376cb144ddcd6b705e42fbcba9ad6d11b>`_
+- s/setup/setUp/g `515586419 <https://github.com/toscawidgets/tw2.sqla/commit/515586419d0190963b54983671709ce3c2957b96>`_
+- Fix tests `78c544376 <https://github.com/toscawidgets/tw2.sqla/commit/78c544376951f422134c26af100b36d2d0de81ea>`_
+- For genshi we should not call __call__ many times on the same the widget `82a997a50 <https://github.com/toscawidgets/tw2.sqla/commit/82a997a5070246ab0fff4a40cf0de88feeed215c>`_
+- Some refactoring `f4b7caccb <https://github.com/toscawidgets/tw2.sqla/commit/f4b7caccb11f49f36c1b4926f7ddaff404429320>`_
+- Display the onetoone field in a label when we view the data. In this way the HTML table is not too big according to the DB. `e97c34285 <https://github.com/toscawidgets/tw2.sqla/commit/e97c342851d77033bdc0c985f7e6202991ed2371>`_
+- Use first the widget defined in the hint `168811e9b <https://github.com/toscawidgets/tw2.sqla/commit/168811e9b8724225e16198bdbaca735295162a6c>`_
+- Do not instantiate many times the widget in order to not have a validator defined by the __post_define__. `cbc36dbc4 <https://github.com/toscawidgets/tw2.sqla/commit/cbc36dbc485a861e0624de13e0c007c12d3d2658>`_
+- Do not force a validator if it is already defined. Now we can pass a validator in the hint without overwriting it! `480870d22 <https://github.com/toscawidgets/tw2.sqla/commit/480870d222f54bd9403a688f5007a4100880e41d>`_
+- Sometimes we don't have any validator `81d953ec9 <https://github.com/toscawidgets/tw2.sqla/commit/81d953ec9d4d333963de23d738ffd80a93a77d6b>`_
+- Require the latest sieve. `89d0b44ce <https://github.com/toscawidgets/tw2.sqla/commit/89d0b44cedc8d1998f559a746203fe0ca0d91d6d>`_
+- Fix typo `b60d53541 <https://github.com/toscawidgets/tw2.sqla/commit/b60d53541d2b6cfbe70f98335d9e5b351db3b132>`_
+- Merge pull request #15 from LeResKP/develop `90d8d15c3 <https://github.com/toscawidgets/tw2.sqla/commit/90d8d15c3c87bff826164ee88642c4960286ffea>`_
+- Hack to make sure the tests in tw2test.WidgetTest are called. `3933cd242 <https://github.com/toscawidgets/tw2.sqla/commit/3933cd2425058b5b27dc8326c6a8f6ea65da4d9d>`_
+- label_field template need escape param defined `5e92a00c9 <https://github.com/toscawidgets/tw2.sqla/commit/5e92a00c98477b2f4753f485a70ce36b016bffed>`_
+- Merge pull request #16 from LeResKP/develop `e2c49b77e <https://github.com/toscawidgets/tw2.sqla/commit/e2c49b77e525e916de986f8fb4fca3fb97161289>`_
+- Fix test `a3f270cd6 <https://github.com/toscawidgets/tw2.sqla/commit/a3f270cd6d6191743c7d7529a0c1eadc1f8547c7>`_
+- Also get first the hint for the relation fields. `9c60f4e66 <https://github.com/toscawidgets/tw2.sqla/commit/9c60f4e66c4721e2bdee3fccec0f93b07ad4ec27>`_
+- Add FactoryWidget which is used to pass parameters to the widget choosed by the factory `cebe3c75d <https://github.com/toscawidgets/tw2.sqla/commit/cebe3c75d790bf1c78ae2d169f1147e1b8f35053>`_
+- Be able to display HTML in the view if get_tws_view_text function is defined on the object. We don't want to poluate __unicode__ with some HTML. `e8bbe8fae <https://github.com/toscawidgets/tw2.sqla/commit/e8bbe8faef706d746f42d5eb6981bc2bbc549f10>`_
+- Sort all the relation properties `b3f31e29b <https://github.com/toscawidgets/tw2.sqla/commit/b3f31e29be09707fcfcfcaea4ef4002dbf2f3f86>`_
+- Merge pull request #17 from LeResKP/develop `fbdb8337f <https://github.com/toscawidgets/tw2.sqla/commit/fbdb8337fc1d77be8ab36940758fa8046952c175>`_
+
+2.0.6
+-----
+
+- Add forgotten doc `4d44d1f54 <https://github.com/toscawidgets/tw2.sqla/commit/4d44d1f5435405d02ad6b83f2060ed2ef8f45a00>`_
+- On the non required onetoone relations, we only validate the required children if at least one value is posted. `bae333c44 <https://github.com/toscawidgets/tw2.sqla/commit/bae333c44f7e95bdf294c2a3041ace8c580174fa>`_
+- * Delete the old value from the DB for the onetoone field * Improve the tests `8d75aa8f2 <https://github.com/toscawidgets/tw2.sqla/commit/8d75aa8f27e6d9dc079d21fd6604b4988e00a2ab>`_
+- If no value posted for onetoone field, we return None to delete the value from the DB `538e48eb9 <https://github.com/toscawidgets/tw2.sqla/commit/538e48eb94584cd97961a12b1104e252ef7fd418>`_
+- Test the non required onetoone field `35430e7d1 <https://github.com/toscawidgets/tw2.sqla/commit/35430e7d15a38fb1b5498ceaf4ccd9522d308926>`_
+- Merge pull request #12 from LeResKP/feature/onetoone_relation `aab98fa59 <https://github.com/toscawidgets/tw2.sqla/commit/aab98fa59e39f83b46f86539ed9236ea908f9ab8>`_
+- 2.0.5 `704e5a38b <https://github.com/toscawidgets/tw2.sqla/commit/704e5a38b13fa00a3d062927b78f5ddf17eb0815>`_
+- 2.0.5 `e62b6f975 <https://github.com/toscawidgets/tw2.sqla/commit/e62b6f97512e76406ea512b738d38f0f8d14867c>`_
+- Some progress on modernizing tests. `c19f41fd2 <https://github.com/toscawidgets/tw2.sqla/commit/c19f41fd2c6bfa691f3c7ff757e2d7d5f3ccc5bc>`_
+- Failures done. Errors left. `7a58fb7ca <https://github.com/toscawidgets/tw2.sqla/commit/7a58fb7ca28931a8cf620466808550a05b29e807>`_
+- Last errors dealt with. Thank god. `3a75628d8 <https://github.com/toscawidgets/tw2.sqla/commit/3a75628d80a2cd2aac663756a80478e6396dd8c9>`_
View
36 LICENSE
@@ -1,23 +1,29 @@
-/*
-Copyright (c) 2012 Paul Johnston & Contributors
+License
+=======
-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:
+MIT license
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+http://www.opensource.org/licenses/mit-license.php
+
+Copyright (c) 2006-2013, Paul Johnston and contributors
+
+Based on the widgets package of the TurboGears Framework which is Copyright (c)
+2005-2008 Kevin Dangoor and contributors.
+
+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.
-
- */
-
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
View
6 setup.py
@@ -22,12 +22,13 @@
setup(
name='tw2.sqla',
- version='2.0.6',
- description='SQLAlchemy database layer for ToscaWidgets 2',
+ version='2.1.0',
+ description='SQLAlchemy database layer for ToscaWidgets 2, a web widget toolkit.',
long_description=open('README.rst').read().split('.. split here', 1)[1],
author='Paul Johnston',
author_email='paj@pajhome.org.uk',
url='http://github.com/toscawidgets/tw2.sqla',
+ download_url="https://pypi.python.org/pypi/tw2.sqla/",
license='MIT',
install_requires=requires,
packages=find_packages(exclude=['ez_setup', 'tests']),
@@ -44,6 +45,7 @@
'tw2.core>=2.0.1',
'tw2.forms',
'elixir',
+ 'sieve>=0.1.9',
] + _extra_cheetah + _extra_genshi + _extra_kid + _extra_mako,
extras_require = {
'cheetah': _extra_cheetah,
View
479 tests/test_widgets.py
@@ -9,6 +9,27 @@
class WidgetTest(tw2test.WidgetTest):
engines = ['mako', 'genshi']
+ declarative = True
+ # NOTE: widget should have a default value to make sure the tests in
+ # tw2test.WidgetTest are run.
+ widget = twc.Widget
+
+
+class WidgetEntityTest(WidgetTest):
+
+ def setUp(self):
+ self.widget = self._widget_cls(
+ entity=getattr(self, self._entity_cls_str))
+ return super(WidgetEntityTest, self).setUp()
+
+class WidgetRequiredEntityTest(WidgetTest):
+
+ def setUp(self):
+ self.widget = self._widget_cls(
+ entity=getattr(self, self._entity_cls_str),
+ validator=twc.Required
+ )
+ return super(WidgetRequiredEntityTest, self).setUp()
# Only run elixir tests if it is importable.
@@ -19,8 +40,12 @@ class WidgetTest(tw2test.WidgetTest):
pass
+class InfoField(twf.InputField): pass
+class FakeValidator(twc.Validator): pass
+
+
class ElixirBase(object):
- def setup(self):
+ def setUp(self):
el.metadata = sa.MetaData('sqlite:///:memory:')
el.session = tws.transactional_session()
# Make sure the DB is clean between the tests
@@ -100,6 +125,27 @@ class DbTestCls12(el.Entity):
def __unicode__(self):
return self.name
+ class DbTestCls13(el.Entity):
+ name = el.Field(el.String, info={'edit_widget': InfoField},
+ required=True)
+ def __unicode__(self):
+ return self.name
+
+ class DbTestCls14(el.Entity):
+ name = el.Field(
+ el.String,
+ info={'edit_widget': InfoField(validator=FakeValidator)},
+ required=True)
+ other_id = el.Field(el.Integer, required=True)
+ other = el.ManyToOne(
+ DbTestCls13,
+ field=other_id,
+ backref='others',
+ info={'view_widget': tws.NoWidget,
+ 'edit_widget': tws.FactoryWidget(css_class='myclass')}
+ )
+ def __unicode__(self):
+ return self.name
self.DbTestCls1 = DbTestCls1
self.DbTestCls2 = DbTestCls2
@@ -113,6 +159,8 @@ def __unicode__(self):
self.DbTestCls10 = DbTestCls10
self.DbTestCls11 = DbTestCls11
self.DbTestCls12 = DbTestCls12
+ self.DbTestCls13 = DbTestCls13
+ self.DbTestCls14 = DbTestCls14
el.setup_all()
el.metadata.create_all()
@@ -146,14 +194,14 @@ def __unicode__(self):
assert(self.DbTestCls12.query.first().account == account1)
transaction.commit()
- return super(ElixirBase, self).setup()
+ return super(ElixirBase, self).setUp()
def teardown(self):
transaction.abort()
class SQLABase(object):
- def setup(self):
+ def setUp(self):
self.session = tws.transactional_session()
Base = declarative_base(metadata=sa.MetaData('sqlite:///:memory:'))
Base.query = self.session.query_property()
@@ -246,6 +294,31 @@ class DbTestCls12(Base):
def __unicode__(self):
return self.name
+ class DbTestCls13(Base):
+ __tablename__ = 'Test13'
+ id = sa.Column(sa.Integer, primary_key=True)
+ name = sa.Column(sa.String(50), info={'edit_widget': InfoField},
+ nullable=False)
+ def __unicode__(self):
+ return self.name
+
+ class DbTestCls14(Base):
+ __tablename__ = 'Test14'
+ id = sa.Column(sa.Integer, primary_key=True)
+ name = sa.Column(
+ sa.String(50),
+ info={'edit_widget': InfoField(validator=FakeValidator)},
+ nullable=False)
+ other_id = sa.Column(sa.Integer, sa.ForeignKey('Test13.id'), nullable=False)
+ other = sa.orm.relation(
+ DbTestCls13,
+ backref=sa.orm.backref('others'),
+ info={'view_widget': tws.NoWidget,
+ 'edit_widget': tws.FactoryWidget(css_class='myclass')}
+ )
+ def __unicode__(self):
+ return self.name
+
self.DbTestCls1 = DbTestCls1
self.DbTestCls2 = DbTestCls2
@@ -259,6 +332,8 @@ def __unicode__(self):
self.DbTestCls10 = DbTestCls10
self.DbTestCls11 = DbTestCls11
self.DbTestCls12 = DbTestCls12
+ self.DbTestCls13 = DbTestCls13
+ self.DbTestCls14 = DbTestCls14
Base.metadata.create_all()
@@ -299,15 +374,15 @@ def __unicode__(self):
assert(self.DbTestCls12.query.first().account == account1)
transaction.commit()
- return super(SQLABase, self).setup()
+ return super(SQLABase, self).setUp()
def teardown(self):
transaction.abort()
-class RadioButtonT(WidgetTest):
- widget = tws.DbRadioButtonList
- declarative = True
+class RadioButtonT(WidgetEntityTest):
+ _widget_cls = tws.DbRadioButtonList
+ _entity_cls_str = 'DbTestCls1'
attrs = {'css_class':'something', 'id' : 'something'}
params = {'checked':None}
expected = """
@@ -326,18 +401,14 @@ def test_validation(self):
value = self.widget.validate({'something':'1'})
assert(value is self.DbTestCls1.query.get(1))
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(RadioButtonT, self).setup()
-
if el:
class TestRadioButtonElixir(ElixirBase, RadioButtonT): pass
class TestRadioButtonSQLA(SQLABase, RadioButtonT): pass
-class RadioButtonRequiredT(WidgetTest):
- widget = tws.DbRadioButtonList
- declarative = True
+class RadioButtonRequiredT(WidgetRequiredEntityTest):
+ _widget_cls = tws.DbRadioButtonList
+ _entity_cls_str = 'DbTestCls1'
attrs = {'css_class':'something', 'id' : 'something'}
params = {'checked':None}
expected = """
@@ -361,19 +432,15 @@ def test_validation(self):
value = self.widget.validate({'something':'1'})
assert(value is self.DbTestCls1.query.get(1))
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1, validator=twc.Required)
- return super(RadioButtonRequiredT, self).setup()
-
if el:
class TestRadioButtonRequiredElixir(ElixirBase, RadioButtonRequiredT): pass
class TestRadioButtonRequiredSQLA(SQLABase, RadioButtonRequiredT): pass
-class CheckBoxT(WidgetTest):
- widget = tws.DbCheckBoxList
+class CheckBoxT(WidgetEntityTest):
+ _widget_cls = tws.DbCheckBoxList
+ _entity_cls_str = 'DbTestCls1'
attrs = {'css_class':'something', 'id' : 'something'}
- declarative = True
params = {'checked':None}
expected = """
<ul class="something" id="something">
@@ -391,19 +458,15 @@ def test_validation(self):
value = self.widget.validate({'something':'1'})
assert(value == [self.DbTestCls1.query.get(1)])
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(CheckBoxT, self).setup()
-
if el:
class TestCheckBoxElixir(ElixirBase, CheckBoxT): pass
class TestCheckBoxSQLA(SQLABase, CheckBoxT): pass
-class CheckBoxRequiredT(WidgetTest):
- widget = tws.DbCheckBoxList
+class CheckBoxRequiredT(WidgetRequiredEntityTest):
+ _widget_cls = tws.DbCheckBoxList
+ _entity_cls_str = 'DbTestCls1'
attrs = {'css_class':'something', 'id' : 'something'}
- declarative = True
params = {'checked':None}
expected = """
<ul class="something" id="something">
@@ -428,19 +491,15 @@ def test_validation(self):
value = self.widget.validate({'something':['1', '2']})
assert(value == [self.DbTestCls1.query.get(1), self.DbTestCls1.query.get(2)])
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1, validator=twc.Required)
- return super(CheckBoxRequiredT, self).setup()
-
if el:
class TestCheckBoxRequiredElixir(ElixirBase, CheckBoxRequiredT): pass
class TestCheckBoxRequiredSQLA(SQLABase, CheckBoxRequiredT): pass
-class CheckBoxTableT(WidgetTest):
- widget = tws.DbCheckBoxTable
+class CheckBoxTableT(WidgetEntityTest):
+ _widget_cls = tws.DbCheckBoxTable
+ _entity_cls_str = 'DbTestCls1'
attrs = {'css_class':'something', 'id' : 'something'}
- declarative = True
params = {'checked':None}
expected = """
<table class="something" id="something"><tbody>
@@ -462,19 +521,15 @@ def test_validation(self):
value = self.widget.validate({'something':'1'})
assert(value == [self.DbTestCls1.query.get(1)])
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(CheckBoxTableT, self).setup()
-
if el:
class TestCheckBoxTableElixir(ElixirBase, CheckBoxTableT): pass
class TestCheckBoxTableSQLA(SQLABase, CheckBoxTableT): pass
-class CheckBoxTableRequiredT(WidgetTest):
- widget = tws.DbCheckBoxTable
+class CheckBoxTableRequiredT(WidgetRequiredEntityTest):
+ _widget_cls = tws.DbCheckBoxTable
+ _entity_cls_str = 'DbTestCls1'
attrs = {'css_class':'something', 'id' : 'something'}
- declarative = True
params = {'checked':None}
expected = """
<table class="something" id="something"><tbody>
@@ -501,19 +556,15 @@ def test_validation(self):
value = self.widget.validate({'something':'1'})
assert(value == [self.DbTestCls1.query.get(1)])
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1, validator=twc.Required)
- return super(CheckBoxTableRequiredT, self).setup()
-
if el:
class TestCheckBoxTableRequestElixir(ElixirBase, CheckBoxTableRequiredT): pass
class TestCheckBoxTableRequestSQLA(SQLABase, CheckBoxTableRequiredT): pass
-class SingleSelectT(WidgetTest):
- widget = tws.DbSingleSelectField
+class SingleSelectT(WidgetEntityTest):
+ _widget_cls = tws.DbSingleSelectField
+ _entity_cls_str = 'DbTestCls1'
attrs = {'css_class':'something', 'id' : 'something'}
- declarative = True
params = {'checked':None}
expected = """
<select class="something" name="something" id="something">
@@ -526,19 +577,15 @@ def test_validation(self):
value = self.widget.validate({'something':'1'})
assert(value is self.DbTestCls1.query.get(1))
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(SingleSelectT, self).setup()
-
if el:
class TestSingleSelectElixir(ElixirBase, SingleSelectT): pass
class TestSingleSelectSQLA(SQLABase, SingleSelectT): pass
-class SingleSelectRequiredT(WidgetTest):
- widget = tws.DbSingleSelectField
+class SingleSelectRequiredT(WidgetRequiredEntityTest):
+ _widget_cls = tws.DbSingleSelectField
+ _entity_cls_str = 'DbTestCls1'
attrs = {'css_class':'something', 'id' : 'something'}
- declarative = True
params = {'checked':None}
expected = """
<select class="something" name="something" id="something">
@@ -556,21 +603,14 @@ def test_validation(self):
value = self.widget.validate({'something':'1'})
assert(value is self.DbTestCls1.query.get(1))
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1, validator=twc.Required)
- return super(SingleSelectRequiredT, self).setup()
-
if el:
class TestSingleSelectRequiredElixir(ElixirBase, SingleSelectRequiredT): pass
class TestSingleSelectRequiredSQLA(SQLABase, SingleSelectRequiredT): pass
-class ListPageT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(ListPageT, self).setup()
-
- widget = tws.DbListPage
+class ListPageT(WidgetEntityTest):
+ _widget_cls = tws.DbListPage
+ _entity_cls_str = 'DbTestCls1'
attrs = {
'child': twf.GridLayout(
children=[
@@ -579,7 +619,8 @@ def setup(self):
twf.LinkField(id='id', link='foo?id=$',
text='Edit', label='Edit'),
]),
- 'newlink' : twf.LinkField(link='cls1', text='New', value=1)
+ 'newlink': twf.LinkField(link='cls1', text='New', value=1),
+ 'title': 'Db Test Cls1'
}
# This is kind of non-sensical. A DbListPage with no call to fetch_data?
@@ -596,7 +637,6 @@ def setup(self):
</body>
</html>"""
- declarative = True
def test_request_get(self):
# This makes much more sense.
environ = {
@@ -643,12 +683,9 @@ class TestListPageElixir(ElixirBase, ListPageT): pass
class TestListPageSQLA(SQLABase, ListPageT): pass
-class FormPageT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(FormPageT, self).setup()
-
- widget = tws.DbFormPage
+class FormPageT(WidgetEntityTest):
+ _widget_cls = tws.DbFormPage
+ _entity_cls_str = 'DbTestCls1'
attrs = {
'child': twf.TableForm(
children=[
@@ -678,7 +715,6 @@ def setup(self):
</form></body>
</html>"""
- declarative = True
def test_request_get_edit(self):
# TODO -- this never actually tests line 68 of tw2.sqla.widgets
environ = {
@@ -858,12 +894,9 @@ def test_no_query_property(self):
self.widget.entity.query = old_prop
-class ListFormT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(ListFormT, self).setup()
-
- widget = tws.DbListForm
+class ListFormT(WidgetEntityTest):
+ _widget_cls = tws.DbListForm
+ _entity_cls_str = 'DbTestCls1'
attrs = {
'child': twf.Form(
child=twf.GridLayout(
@@ -887,7 +920,6 @@ def setup(self):
</form></body>
</html>"""
- declarative = True
def test_request_get_edit(self):
environ = {
'REQUEST_METHOD': 'GET',
@@ -1033,13 +1065,10 @@ class TestListFormElixir(ElixirBase, ListFormT): pass
class TestListFormSQLA(SQLABase, ListFormT): pass
-class AutoListPageT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(AutoListPageT, self).setup()
-
-
- widget = tws.AutoListPage
+class AutoListPageT(WidgetEntityTest):
+ _widget_cls = tws.AutoListPage
+ _entity_cls_str = 'DbTestCls1'
+ attrs = {'title': 'Db Test Cls1'}
# Doesn't make much sense... an AutoList widget with fetch_data not called?
expected = """
@@ -1056,7 +1085,6 @@ def setup(self):
</html>
"""
- declarative = True
def test_exception_manytoone(self):
class WackPolicy(tws.WidgetPolicy):
pass
@@ -1126,15 +1154,66 @@ class AwesomePolicy(tws.WidgetPolicy):
assert(False)
def test_info_on_prop(self):
- class AwesomePolicy(tws.WidgetPolicy):
+ """Test we use first the data defined in the hint
+ """
+ class AwesomePolicy(tws.EditPolicy):
name_widgets = { 'name' : twf.LabelField, }
props = filter(
lambda x : x.key == 'name',
- sa.orm.class_mapper(self.DbTestCls1).iterate_properties)
+ sa.orm.class_mapper(self.DbTestCls13).iterate_properties)
assert(len(props) == 1)
try:
w = AwesomePolicy.factory(props[0])
+ assert(issubclass(w, InfoField))
+ assert(w.validator)
+ except twc.WidgetError, e:
+ assert(False)
+
+ def test_info_validator_on_prop(self):
+ """Test we use first the data defined in the hint
+ """
+ class AwesomePolicy(tws.EditPolicy): pass
+
+ props = filter(
+ lambda x: x.key == 'name',
+ sa.orm.class_mapper(self.DbTestCls14).iterate_properties)
+ assert(len(props) == 1)
+ try:
+ w = AwesomePolicy.factory(props[0])
+ assert(issubclass(w, InfoField))
+ assert(isinstance(w.validator, FakeValidator))
+ except twc.WidgetError, e:
+ assert(False)
+
+ def test_info_widget_on_relation(self):
+ """Test we use first the data defined in the hint
+ """
+ class AwesomePolicy(tws.ViewPolicy): pass
+
+ props = filter(
+ lambda x: x.key == 'other',
+ sa.orm.class_mapper(self.DbTestCls14).iterate_properties)
+ assert(len(props) == 1)
+ try:
+ w = AwesomePolicy.factory(props[0])
+ assert(w is None)
+ except twc.WidgetError, e:
+ assert(False)
+
+ def test_info_factory_widget_on_relation(self):
+ """Test we use first the data defined in the hint
+ """
+ class AwesomePolicy(tws.EditPolicy): pass
+
+ props = filter(
+ lambda x: x.key == 'other',
+ sa.orm.class_mapper(self.DbTestCls14).iterate_properties)
+ assert(len(props) == 1)
+ try:
+ w = AwesomePolicy.factory(props[0])
+ assert(issubclass(w, tws.DbSingleSelectField))
+ assert(w.css_class == 'myclass')
except twc.WidgetError, e:
assert(False)
@@ -1144,6 +1223,7 @@ def test_orig_children(self):
class SomeListPage(tws.DbListPage):
_no_autoid = True
entity = self.DbTestCls1
+ title = 'Db Test Cls1'
class child(tws.AutoViewGrid):
name = twf.InputField(type='text')
@@ -1179,7 +1259,6 @@ class child(tws.AutoViewGrid):
</td></tr></table></body></html>""")
-
def test_request_get(self):
""" Good lookin' """
environ = {
@@ -1222,20 +1301,16 @@ def test_request_get(self):
</td></tr>
</table></body></html>""")
-
if el:
class TestAutoListPageElixir(ElixirBase, AutoListPageT): pass
class TestAutoListPageSQLA(SQLABase, AutoListPageT): pass
-class AutoListPageOneToOneRelationT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls9)
- return super(AutoListPageOneToOneRelationT, self).setup()
-
-
- widget = tws.AutoListPage
+class AutoListPageOneToOneRelationT(WidgetEntityTest):
+ _widget_cls = tws.AutoListPage
+ _entity_cls_str = 'DbTestCls9'
+ attrs = {'title': 'Db Test Cls9'}
# Doesn't make much sense... an AutoList widget with fetch_data not called?
expected = """
@@ -1252,7 +1327,6 @@ def setup(self):
</html>
"""
- declarative = True
def test_request_get(self):
environ = {
'REQUEST_METHOD': 'GET',
@@ -1272,22 +1346,7 @@ def test_request_get(self):
<span>bob1<input type="hidden" name="autolistpage_d:0:name" value="bob1" id="autolistpage_d:0:name"/></span>
</td>
<td>
- <fieldset id="autolistpage_d:0:account:fieldset">
- <legend></legend>
- <table id="autolistpage_d:0:account">
- <tr class="odd required" id="autolistpage_d:0:account:account_name:container">
- <th><label for="account_name">Account Name</label></th>
- <td >
- <span>account1<input type="hidden" name="account:account_name" value="account1" id="autolistpage_d:0:account:account_name"/></span>
-
- <span id="autolistpage_d:0:account:account_name:error"></span>
- </td>
- </tr>
- <tr class="error"><td colspan="2">
- <span id="autolistpage_d:0:account:error"></span>
- </td></tr>
- </table>
- </fieldset>
+ <span>account1<input type="hidden" name="autolistpage_d:0:account" value="account1" id="autolistpage_d:0:account" required="required" /></span>
</td>
<td>
</td>
@@ -1306,12 +1365,9 @@ class TestAutoListPageOneToOneRelationSQLA(SQLABase, AutoListPageOneToOneRelatio
# TODO -- do AutoListPageEDIT here
-class AutoTableFormT1(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(AutoTableFormT1, self).setup()
-
- widget = tws.AutoTableForm
+class AutoTableFormT1(WidgetEntityTest):
+ _widget_cls = tws.AutoTableForm
+ _entity_cls_str = 'DbTestCls1'
attrs = { 'id' : 'foo_form' }
expected = """
<form method="post" id="foo_form:form" enctype="multipart/form-data">
@@ -1355,12 +1411,9 @@ class TestAutoTableForm1Elixir(ElixirBase, AutoTableFormT1): pass
class TestAutoTableForm1SQLA(SQLABase, AutoTableFormT1): pass
-class AutoTableFormT2(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls2)
- return super(AutoTableFormT2, self).setup()
-
- widget = tws.AutoTableForm
+class AutoTableFormT2(WidgetEntityTest):
+ _widget_cls = tws.AutoTableForm
+ _entity_cls_str = 'DbTestCls2'
attrs = { 'id' : 'foo_form' }
expected = """
<form id="foo_form:form" enctype="multipart/form-data" method="post">
@@ -1398,12 +1451,9 @@ class TestAutoTableForm2Elixir(ElixirBase, AutoTableFormT2): pass
class TestAutoTableForm2SQLA(SQLABase, AutoTableFormT2): pass
-class AutoTableFormT4(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls4)
- return super(AutoTableFormT4, self).setup()
-
- widget = tws.AutoTableForm
+class AutoTableFormT4(WidgetEntityTest):
+ _widget_cls = tws.AutoTableForm
+ _entity_cls_str = 'DbTestCls4'
attrs = { 'id' : 'foo_form' }
expected = """
<form method="post" id="foo_form:form" enctype="multipart/form-data">
@@ -1448,12 +1498,9 @@ class TestAutoTableForm4Elixir(ElixirBase, AutoTableFormT4): pass
class TestAutoTableForm4SQLA(SQLABase, AutoTableFormT4): pass
-class AutoTableFormT5(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls5)
- return super(AutoTableFormT5, self).setup()
-
- widget = tws.AutoTableForm
+class AutoTableFormT5(WidgetEntityTest):
+ _widget_cls = tws.AutoTableForm
+ _entity_cls_str = 'DbTestCls5'
attrs = { 'id' : 'foo_form' }
expected = """
<form method="post" id="foo_form:form" enctype="multipart/form-data">
@@ -1494,12 +1541,9 @@ class TestAutoTableForm5Elixir(ElixirBase, AutoTableFormT5): pass
class TestAutoTableForm5SQLA(SQLABase, AutoTableFormT5): pass
-class AutoTableFormT6(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls6)
- return super(AutoTableFormT6, self).setup()
-
- widget = tws.AutoTableForm
+class AutoTableFormT6(WidgetEntityTest):
+ _widget_cls = tws.AutoTableForm
+ _entity_cls_str = 'DbTestCls6'
attrs = { 'id' : 'foo_form' }
expected = """
<form method="post" id="foo_form:form" enctype="multipart/form-data">
@@ -1540,12 +1584,9 @@ class TestAutoTableForm6Elixir(ElixirBase, AutoTableFormT6): pass
class TestAutoTableForm6SQLA(SQLABase, AutoTableFormT6): pass
-class AutoTableFormT7(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls7)
- return super(AutoTableFormT7, self).setup()
-
- widget = tws.AutoTableForm
+class AutoTableFormT7(WidgetEntityTest):
+ _widget_cls = tws.AutoTableForm
+ _entity_cls_str = 'DbTestCls7'
attrs = { 'id' : 'foo_form' }
expected = """
<form id="foo_form:form" enctype="multipart/form-data" method="post">
@@ -1583,12 +1624,9 @@ class TestAutoTableForm7Elixir(ElixirBase, AutoTableFormT7): pass
class TestAutoTableForm7SQLA(SQLABase, AutoTableFormT7): pass
-class AutoViewGridT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(AutoViewGridT, self).setup()
-
- widget = tws.AutoViewGrid
+class AutoViewGridT(WidgetEntityTest):
+ _widget_cls = tws.AutoViewGrid
+ _entity_cls_str = 'DbTestCls1'
attrs = { 'id' : 'autogrid' }
expected = """
@@ -1695,12 +1733,9 @@ class TestAutoViewGridElixir(ElixirBase, AutoViewGridT): pass
class TestAutoViewGridSQLA(SQLABase, AutoViewGridT): pass
-class AutoGrowingGridT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(AutoGrowingGridT, self).setup()
-
- widget = tws.AutoGrowingGrid
+class AutoGrowingGridT(WidgetEntityTest):
+ _widget_cls = tws.AutoGrowingGrid
+ _entity_cls_str = 'DbTestCls1'
attrs = { 'id' : 'autogrid' }
# TBD -- should the values from the db show up here?
expected = """
@@ -1760,12 +1795,9 @@ class TestAutoGrowingGridElixir(ElixirBase, AutoGrowingGridT): pass
class TestAutoGrowingGridSQLA(SQLABase, AutoGrowingGridT): pass
-class AutoGrowingGridAsChildT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1)
- return super(AutoGrowingGridAsChildT, self).setup()
-
- widget = tws.DbFormPage
+class AutoGrowingGridAsChildT(WidgetEntityTest):
+ _widget_cls = tws.DbFormPage
+ _entity_cls_str = 'DbTestCls1'
attrs = { 'id' : 'autogrid', 'title' : 'Test',
'child' : tws.AutoGrowingGrid}
# TBD -- should the values from the db show up here?
@@ -1828,12 +1860,9 @@ class TestAutoGrowingGridAsChildElixir(ElixirBase, AutoGrowingGridAsChildT): pas
class TestAutoGrowingGridAsChildSQLA(SQLABase, AutoGrowingGridAsChildT): pass
-class AutoGrowingGridAsChildWithRelationshipT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls2)
- return super(AutoGrowingGridAsChildWithRelationshipT, self).setup()
-
- widget = twf.TableForm
+class AutoGrowingGridAsChildWithRelationshipT(WidgetEntityTest):
+ _widget_cls = twf.TableForm
+ _entity_cls_str = 'DbTestCls2'
attrs = { 'title' : 'Test',
'child' : tws.AutoGrowingGrid(id='others')}
# TBD -- should the values from the db show up here?
@@ -1885,9 +1914,9 @@ class TestAutoGrowingGridAsChildWithRelationshipSQLA(
SQLABase, AutoGrowingGridAsChildWithRelationshipT): pass
-class AutoEditRelationInTableT(WidgetTest):
- widget = tws.AutoTableForm
- declarative = True
+class AutoEditRelationInTableT(WidgetEntityTest):
+ _widget_cls = tws.AutoTableForm
+ _entity_cls_str = 'DbTestCls9'
attrs = {'css_class':'something', 'id' : 'something'}
params = {'checked':None}
expected = """
@@ -1949,21 +1978,14 @@ def test_validation_no_account(self):
# The exception is raise but it's very strange that the error was lost
assert(ve.widget.error_msg == '')
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls9)
- return super(AutoEditRelationInTableT, self).setup()
-
if el:
class TestAutoEditRelationInTableElixir(ElixirBase, AutoEditRelationInTableT): pass
class TestAutoEditRelationInTableSQLA(SQLABase, AutoEditRelationInTableT): pass
-class AutoEditRelationInFormT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls9)
- return super(AutoEditRelationInFormT, self).setup()
-
- widget = tws.DbFormPage
+class AutoEditRelationInFormT(WidgetEntityTest):
+ _widget_cls = tws.DbFormPage
+ _entity_cls_str = 'DbTestCls9'
attrs = { 'id' : 'autoedit', 'title' : 'Test',
'child' : tws.AutoTableForm}
@@ -2009,7 +2031,6 @@ def setup(self):
</html>
"""
- declarative = True
def test_request_get_edit(self):
environ = {'REQUEST_METHOD': 'GET', 'QUERY_STRING' :'id=1'}
req=Request(environ)
@@ -2238,13 +2259,9 @@ class TestAutoEditRelationInFromElixir(ElixirBase, AutoEditRelationInFormT): pas
class TestAutoEditRelationInFormSQLA(SQLABase, AutoEditRelationInFormT): pass
-class NonRequiredOneToOneRelationT(WidgetTest):
-
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls12)
- return super(NonRequiredOneToOneRelationT, self).setup()
-
- widget = tws.DbFormPage
+class NonRequiredOneToOneRelationT(WidgetEntityTest):
+ _widget_cls = tws.DbFormPage
+ _entity_cls_str = 'DbTestCls12'
attrs = { 'id' : 'autoedit', 'title' : 'Test',
'child' : tws.AutoTableForm}
@@ -2297,7 +2314,6 @@ def setup(self):
</html>
"""
- declarative = True
def test_request_get_edit(self):
environ = {'REQUEST_METHOD': 'GET', 'QUERY_STRING' :'id=1'}
req=Request(environ)
@@ -2645,12 +2661,9 @@ class TestNonRequiredOneToOneRelationSQLA(SQLABase,
NonRequiredOneToOneRelationT): pass
-class AutoTableFormAsChildT(WidgetTest):
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls7)
- return super(AutoTableFormAsChildT, self).setup()
-
- widget = tws.DbFormPage
+class AutoTableFormAsChildT(WidgetEntityTest):
+ _widget_cls = tws.DbFormPage
+ _entity_cls_str = 'DbTestCls7'
attrs = { 'id' : 'autotable', 'title' : 'Test',
'child' : tws.AutoTableForm}
expected = """
@@ -2685,7 +2698,6 @@ def setup(self):
</html>
"""
- declarative = True
def test_request_get_edit(self):
environ = {
'REQUEST_METHOD': 'GET',
@@ -2908,7 +2920,7 @@ class TestAutoTableFormAsChildTElixir(ElixirBase, AutoTableFormAsChildT): pass
class TestAutoTableFormAsChildTSQLA(SQLABase, AutoTableFormAsChildT): pass
class FormPageRequiredCheckboxT(WidgetTest):
- def setup(self):
+ def setUp(self):
attrs = {
'child': twf.TableForm(
children=[
@@ -2919,10 +2931,10 @@ def setup(self):
'title': 'some title',
'entity': self.DbTestCls1,
}
- self.widget = self.widget(**attrs)
- return super(FormPageRequiredCheckboxT, self).setup()
+ self.widget = self._widget_cls(**attrs)
+ return super(FormPageRequiredCheckboxT, self).setUp()
- widget = tws.DbFormPage
+ _widget_cls = tws.DbFormPage
expected = """
<html>
<head><title>some title</title></head>
@@ -3179,14 +3191,13 @@ class TestFormPageRequiredCheckboxTSQLA(SQLABase, FormPageRequiredCheckboxT): pa
class DbLinkFieldT(WidgetTest):
- widget = tws.DbLinkField
- declarative = True
+ _widget_cls = tws.DbLinkField
params = {'link':'/test'}
expected = """<a href="/test?id=1">foo1</a>"""
- def setup(self):
- self.widget = self.widget(entity=self.DbTestCls1, value=self.DbTestCls1.query.get(1))
- return super(DbLinkFieldT, self).setup()
+ def setUp(self):
+ self.widget = self._widget_cls(entity=self.DbTestCls1, value=self.DbTestCls1.query.get(1))
+ return super(DbLinkFieldT, self).setUp()
def test_encode(self):
d = self.DbTestCls10(name="fr&ed")
@@ -3225,6 +3236,14 @@ def test_no_link(self):
w = tws.DbLinkField(entity=self.DbTestCls10, text='edit')
tw2test.assert_eq_xml(w.display(), '<a>edit</a>')
+ def test_get_tws_view_html(self):
+ class TestCls(self.DbTestCls10):
+ def get_tws_view_html(self):
+ return '<strong>name:</strong> %s' % self.name
+ w = tws.DbLinkField(entity=TestCls, value=TestCls(name='Fred'))
+ tw2test.assert_eq_xml(w.display(),
+ '<a><strong>name:</strong> Fred</a>')
+
def test_parent_value(self):
d = self.DbTestCls10(name="fred")
w = tws.AutoTableForm(
@@ -3232,7 +3251,9 @@ def test_parent_value(self):
tws.DbLinkField(
'edit', entity=self.DbTestCls10, link='/test/$')
],
- value=d)
+ value=d,
+ entity=None
+ )
tw2test.assert_eq_xml(w.display(), """
<form enctype="multipart/form-data" method="post">
<span class="error"></span>
@@ -3257,3 +3278,27 @@ def test_parent_value(self):
class TestLinkFieldElixir(ElixirBase, DbLinkFieldT): pass
class TestLinkFieldSQLA(SQLABase, DbLinkFieldT): pass
+
+
+class DbLabelFieldT(WidgetTest):
+ _widget_cls = tws.DbLabelField
+ params = {}
+ expected = """<span>foo1<input value="foo1" type="hidden" /></span>"""
+
+ def setUp(self):
+ self.widget = self._widget_cls(entity=self.DbTestCls1, value=self.DbTestCls1.query.get(1))
+ return super(DbLabelFieldT, self).setUp()
+
+ def test_get_tws_view_html(self):
+ class TestCls(self.DbTestCls1):
+ def get_tws_view_html(self):
+ return '<strong>name:</strong> %s' % self.name
+ w = tws.DbLabelField(entity=TestCls, value=TestCls(name='Fred'))
+ expected = ('<span><strong>name:</strong> Fred'
+ '<input type="hidden" value="Fred"/></span>')
+ tw2test.assert_eq_xml(w.display(), expected)
+
+if el:
+ class TestDbLabelFieldElixir(ElixirBase, DbLabelFieldT): pass
+
+class TestDbLabelFieldSQLA(SQLABase, DbLabelFieldT): pass
View
4 tw2/sqla/__init__.py
@@ -2,13 +2,13 @@
RelatedValidator, DbFormPage, DbListForm, DbListPage, DbLinkField,
commit_veto, transactional_session,
DbSelectionField, DbSingleSelectField, DbCheckBoxList, DbRadioButtonList, DbCheckBoxTable,
- DbSingleSelectLink)
+ DbSingleSelectLink, DbLabelField)
from factory import (
WidgetPolicy, ViewPolicy, EditPolicy,
AutoTableForm, AutoViewGrid, AutoGrowingGrid,
AutoListPage, AutoListPageEdit,
AutoEditFieldSet, AutoViewFieldSet,
- NoWidget)
+ NoWidget, FactoryWidget)
import utils
import widgets
View
125 tw2/sqla/factory.py
@@ -33,17 +33,20 @@ def sort_func(prop1, prop2):
When a relation has a column on the local side, we put the relation at
the place of the column.
"""
- weight1 = 0
- weight2 = 0
- if is_onetoone(prop1):
- weight1 += 2
- if is_onetoone(prop2):
- weight2 += 2
- if is_manytomany(prop1):
- weight1 += 1
- if is_manytomany(prop2):
- weight2 += 1
-
+ def get_weight(prop):
+ if is_onetoone(prop):
+ return 4
+ elif is_onetomany(prop):
+ return 3
+ elif is_manytoone(prop):
+ return 2
+ elif is_manytomany(prop):
+ return 1
+ return 0
+
+ weight1 = get_weight(prop1)
+ weight2 = get_weight(prop2)
+
res = cmp(weight1, weight2)
if res != 0:
return res
@@ -144,21 +147,37 @@ class WidgetPolicy(object):
@classmethod
def factory(cls, prop):
widget = None
+ widget_kw = {}
+ factory_widget = None
cols = getattr(prop, 'columns', [])
- if is_onetomany(prop):
+ if cls.hint_name:
+ if is_relation(prop):
+ widget = prop.info.get(cls.hint_name)
+ elif cols:
+ widget = cols[0].info.get(cls.hint_name)
+ if widget:
+ if issubclass(widget, NoWidget):
+ # We don't want to display this field!
+ return None
+ if issubclass(widget, FactoryWidget):
+ factory_widget = widget
+ widget = None
+
+ if widget:
+ pass
+ elif is_onetomany(prop):
if not cls.onetomany_widget:
raise twc.WidgetError(
"Cannot automatically create a widget " +
"for one-to-many relation '%s'" % prop.key)
prop_cls = prop.mapper.class_
edit_link = getattr(prop_cls, 'tws_edit_link', None)
- params = {}
if cls.add_edit_link:
- params['link'] = edit_link
- widget = cls.onetomany_widget(
- id=prop.key,
- entity=prop_cls,
- **params)
+ widget_kw['link'] = edit_link
+ widget_kw.update({
+ 'entity': prop_cls,
+ })
+ widget = cls.onetomany_widget
elif sum([c.primary_key for c in getattr(prop, 'columns', [])]):
widget = cls.pkey_widget
elif is_manytoone(prop):
@@ -166,7 +185,10 @@ def factory(cls, prop):
raise twc.WidgetError(
"Cannot automatically create a widget " +
"for many-to-one relation '%s'" % prop.key)
- widget = cls.manytoone_widget(id=prop.key,entity=prop.mapper.class_)
+ widget_kw = {
+ 'entity': prop.mapper.class_
+ }
+ widget = cls.manytoone_widget
elif is_manytomany(prop):
# Use the same widget as onetomany
if not cls.onetomany_widget:
@@ -175,34 +197,32 @@ def factory(cls, prop):
"for many-to-many relation '%s'" % prop.key)
prop_cls = prop.mapper.class_
edit_link = getattr(prop_cls, 'tws_edit_link', None)
- params = {}
if cls.add_edit_link:
- params['link'] = edit_link
- widget = cls.onetomany_widget(
- id=prop.key,
- entity=prop_cls,
- reverse_property_name=get_reverse_property_name(prop),
- **params
- )
+ widget_kw['link'] = edit_link
+
+ widget = cls.onetomany_widget
+ widget_kw.update({
+ 'id': prop.key,
+ 'entity': prop_cls,
+ 'reverse_property_name': get_reverse_property_name(prop),
+ })
elif is_onetoone(prop):
if not cls.onetoone_widget:
raise twc.WidgetError(
"Cannot automatically create a widget " +
"for one-to-one relation '%s'" % prop.key)
required = required_widget(prop)
- widget = cls.onetoone_widget(
- id=prop.key,
- entity=prop.mapper.class_,
- required=required,
- reverse_property_name=get_reverse_property_name(prop),
- required_on_parent=(not required),
- )
+ widget = cls.onetoone_widget
+ widget_kw = {
+ 'id': prop.key,
+ 'entity': prop.mapper.class_,
+ 'required': required,
+ 'reverse_property_name': get_reverse_property_name(prop),
+ 'required_on_parent': (not required),
+ }
elif prop.key in cls.name_widgets:
- widget = cls.name_widgets[prop.key]
- elif cols and cls.hint_name and cls.hint_name in cols[0].info:
- if not issubclass(cols[0].info[cls.hint_name], NoWidget):
- widget = cols[0].info[cls.hint_name]
- else:
+ widget = cls.name_widgets[prop.key]
+ else:
for t, c in product(cls.type_widgets, cols):
if isinstance(c.type, t):
widget = cls.type_widgets[t]
@@ -215,10 +235,15 @@ def factory(cls, prop):
widget = cls.default_widget
if widget:
- args = {'id': prop.key}
- if required_widget(prop):
- args['validator'] = twc.Required
- widget = widget(**args)
+ widget_kw['id'] = prop.key
+ if factory_widget:
+ for k, v in widget._all_params.items():
+ value = getattr(factory_widget, k, None)
+ if value and value != v.default:
+ widget_kw[k] = value
+ if 'validator' not in widget_kw and not getattr(widget, 'validator', None) and required_widget(prop):
+ widget_kw['validator'] = twc.Required
+ widget = widget(**widget_kw)
return widget
@@ -227,6 +252,12 @@ class NoWidget(twc.Widget):
pass
+class FactoryWidget(twc.Widget):
+ """Widget to use when we want to let the factory decides the widget to use
+ but we want to apply some specifics parameters
+ """
+ pass
+
class ViewPolicy(WidgetPolicy):
"""Base WidgetPolicy for viewing data."""
hint_name = 'view_widget'
@@ -275,10 +306,10 @@ class AutoContainer(twc.Widget):
@classmethod
def post_define(cls):
- if not hasattr(cls, 'entity') and hasattr(cls, 'parent') and hasattr(cls.parent, 'entity'):
+ if not getattr(cls, 'entity', None) and getattr(cls.parent, 'entity', None):
cls.entity = cls.parent.entity
- if hasattr(cls, 'entity') and not getattr(cls, '_auto_widgets', False):
+ if getattr(cls, 'entity', None) and not getattr(cls, '_auto_widgets', False):
cls._auto_widgets = True
fkey = dict((compat.local_name(p), p)
for p in sa.orm.class_mapper(cls.entity).iterate_properties
@@ -339,7 +370,7 @@ def child_filter(w):
cls.required_children = []
if getattr(cls, 'required_on_parent', False):
for c in new_children:
- if c.validator.required:
+ if c.validator and c.validator.required:
cls.required_children += [c]
c.validator.required = False
cls.child = cls.child(children=new_children, entity=cls.entity)
@@ -372,7 +403,7 @@ def post_define(cls):
# This is assigned here and not above because of a circular dep.
ViewPolicy.onetomany_widget = DbListLinkField
-ViewPolicy.onetoone_widget = AutoViewFieldSet
+ViewPolicy.onetoone_widget = DbLabelField
EditPolicy.onetoone_widget = AutoEditFieldSet
class AutoListPage(DbListPage):
View
41 tw2/sqla/widgets.py
@@ -68,7 +68,7 @@ class RelatedItemValidator(twc.Validator):
def __init__(self, entity, required=False, **kw):
super(RelatedItemValidator, self).__init__(**kw)
- self.required=required
+ self.required = required
self.entity = entity
self.item_validator = RelatedValidator(entity=self.entity)
@@ -95,7 +95,7 @@ class RelatedOneToOneValidator(twc.Validator):
def __init__(self, entity, required=False, required_children=None, **kw):
super(RelatedOneToOneValidator, self).__init__(**kw)
- self.required=required
+ self.required = required
self.entity = entity
self.required_children = required_children
@@ -145,11 +145,12 @@ def from_python(self, value, state=None):
class DbPage(twc.Page):
- entity = twc.Param('SQLAlchemy mapped class to use', request_local=False)
+ entity = twc.Param('SQLAlchemy mapped class to use', request_local=False,
+ default=None)
_no_autoid = True
@classmethod
def post_define(cls):
- if hasattr(cls, 'entity') and not hasattr(cls, 'title'):
+ if getattr(cls, 'entity', None) and not hasattr(cls, 'title'):
cls.title = twc.util.name2label(cls.entity.__name__)
class DbFormPage(DbPage, twf.FormPage):
@@ -158,7 +159,8 @@ class DbFormPage(DbPage, twf.FormPage):
from the database, based on the primary key in the URL (no parameters for a new record). The
`validated_request` method saves the data to the database.
"""
- redirect = twc.Param('Location to redirect to after successful POST', request_local=False)
+ redirect = twc.Param('Location to redirect to after successful POST',
+ request_local=False, default=None)
_no_autoid = True
def fetch_data(self, req):
@@ -177,7 +179,7 @@ def validated_request(cls, req, data, protect_prm_tamp=True, do_commit=True):
if do_commit:
transaction.commit()
- if hasattr(cls, 'redirect'):
+ if cls.redirect is not None:
return webob.Response(request=req, status=302, location=cls.redirect)
else:
return super(DbFormPage, cls).validated_request(req, data)
@@ -188,12 +190,13 @@ class DbListForm(DbPage, twf.FormPage):
A page that contains a list form with database synchronisation. The `fetch_data` method loads a full
table from the database. The `validated_request` method saves the data to the database.
"""
- redirect = twc.Param('Location to redirect to after successful POST', request_local=False)
+ redirect = twc.Param('Location to redirect to after successful POST',
+ request_local=False, default=None)
_no_autoid = True
def fetch_data(self, req):
self.value = self.entity.query.all()
-
+
@classmethod
def validated_request(cls, req, data, protect_prm_tamp=True, do_commit=True):
utils.from_list(cls.entity, cls.entity.query.all(), data,
@@ -201,7 +204,7 @@ def validated_request(cls, req, data, protect_prm_tamp=True, do_commit=True):
if do_commit:
transaction.commit()
- if hasattr(cls, 'redirect'):
+ if cls.redirect is not None:
return webob.Response(request=req, status=302, location=cls.redirect)
else:
return super(DbListForm, cls).validated_request(req, data)
@@ -235,12 +238,23 @@ def prepare(self):
self.newlink.prepare()
+class DbLabelField(twf.LabelField):
+
+ def prepare(self):
+ super(DbLabelField, self).prepare()
+ if self.value and hasattr(self.value, 'get_tws_view_html'):
+ self.value = self.value.get_tws_view_html() or ''
+ # We can have HTML in get_tws_view_html
+ self.escape = False
+
+
# Note: this does not inherit from LinkField, as few of the parameters apply
class DbLinkField(twc.Widget):
template = "tw2.forms.templates.link_field"
link = twc.Param('Path to link to', default=None)
text = twc.Param('Link text', default='')
entity = twc.Param('SQLAlchemy mapped class to use', request_local=False)
+ escape = twc.Param('Whether text shall be html-escaped or not', default=True)
def encode(self, value):
return urllib.quote(unicode(value).encode('utf-8'))
@@ -270,7 +284,12 @@ def prepare(self):
self.attrs['href'] = self.link + '?' + qs
if not self.text:
- self.text = unicode(self.value or '')
+ if self.value and hasattr(self.value, 'get_tws_view_html'):
+ self.text = self.value.get_tws_view_html() or ''
+ # We can have HTML in get_tws_view_html
+ self.escape = False
+ else:
+ self.text = unicode(self.value or '')
class DbListLinkField(twc.RepeatingWidget):
@@ -334,7 +353,7 @@ class DbSingleSelectLink(twd.LinkContainer):
class child(DbSingleSelectField):
@classmethod
def post_define(cls):
- if hasattr(cls.parent, 'entity') and not hasattr(cls, 'entity'):
+ if getattr(cls.parent, 'entity', None) and not cls.entity:
cls.entity = cls.parent.entity
Please sign in to comment.
Something went wrong with that request. Please try again.