-
+
@@ -37,11 +35,17 @@
{% if test_grid %}
-
-
+
+
+
+
+
+
-
+
+
+
{% endif %}
@@ -56,6 +60,7 @@
}
"""
+
@register('testwidget')
class TestWidget(TkOutWidget):
strfield = StringField(default='str', max_length=5)
@@ -69,6 +74,7 @@ class TestWidget(TkOutWidget):
def test(self):
pass
+
class TestWidgetWithCss(TkOutWidget):
strfield = StringField(default='str', max_length=5)
boolfield = BoolField(default=True)
@@ -83,35 +89,48 @@ def test(self):
for b in self.select('button'):
b.config(text='change')
+
class TestWidgetWithoutLayout(TkOutWidget):
pass
+
class TestTagUnRecognizedError(TkOutWidget):
layout = """ invalid """
+
class TestDataNotExistError(TkOutWidget):
- layout = """"""
+ layout = """
+ """
+
class TestTagInWrongScopeOutSide(TkOutWidget):
layout = """"""
+
class TestTagInWrongScopeHead(TkOutWidget):
layout = """"""
+
class TestTagInWrongScopeMenu(TkOutWidget):
- layout = """"""
+ layout = """
+ """
+
class TestTagInWrongScopeBody(TkOutWidget):
layout = """"""
+
class TestTagInWrongScopeGrid(TkOutWidget):
layout = """"""
+
class TestTagInWrongScopeGr(TkOutWidget):
layout = """"""
+
class TestTagInWrongScopeGd(TkOutWidget):
- layout = """"""
+ layout = """
+ """
class TestTkOutWidget(unittest.TestCase):
@@ -135,7 +154,6 @@ def test_widget(self):
left = self.select_one_element('body left')
notebook = self.select_one_element('body > notebook')
button = self.select_one_element('left > button')
- command = self.select_one_element('menu > command')
radiobutton = self.select_one_element('menu > radiobutton')
entry_0 = self.select_one_element('left > entry#0')
grid = self.select_one_element('body > grid')
@@ -154,7 +172,8 @@ def test_widget(self):
self.assertTrue(head.is_scope and not title.is_scope)
self.assertTrue(left.is_side and not body.is_side)
self.assertTrue(grid.is_grid and gr_0.is_gr and gd_0.is_gd)
- self.assertTrue(not grid.is_grid_element and gr_0.is_grid_element and gd_0.is_grid_element)
+ self.assertTrue(not grid.is_grid_element and gr_0.is_grid_element and
+ gd_0.is_grid_element)
self.assertTrue(top_menu.is_menu and sub_menu.is_menu)
self.assertTrue(top_menu.is_top_menu)
self.assertTrue(sub_menu.is_sub_menu)
@@ -167,20 +186,24 @@ def test_widget(self):
self.assertTrue(gd_0.is_in_gr and not gr_0.is_in_gr)
self.assertTrue(button_g0.is_in_gd and not gd_0.is_in_gd)
self.assertTrue(css.can_under_head and not left.can_under_head)
- self.assertTrue(radiobutton.can_under_menu and not button.can_under_menu)
+ self.assertTrue(radiobutton.can_under_menu and
+ not button.can_under_menu)
self.assertTrue(notebook.can_under_body and not title.can_under_body)
self.assertFalse(top_menu.can_under_body or sub_menu.can_under_body)
self.assertTrue(gr_0.can_in_grid and not grid.can_in_grid)
self.assertTrue(gd_0.can_in_gr and not gr_0.can_in_gr)
- self.assertTrue(button_g0.can_in_gd and not gd_0.can_in_gd and not top_menu.can_in_gd)
+ self.assertTrue(button_g0.can_in_gd and not gd_0.can_in_gd and
+ not top_menu.can_in_gd)
# widget checker
self.assertTrue(title.has_no_widget_type and html.has_no_widget_type)
self.assertTrue(button.has_widget_type and radiobutton.has_widget_type)
self.assertTrue(button.has_widget_name and not title.has_widget_name)
self.assertTrue(left.has_widget_cls and not title.has_widget_cls)
self.assertTrue(button.has_options and not notebook.has_options)
- self.assertTrue(button.has_widget and top_menu.has_widget and not css.has_widget)
- self.assertTrue(grid.has_gridmgr and not gr_0.has_gridmgr and not gd_0.has_gridmgr)
+ self.assertTrue(button.has_widget and top_menu.has_widget and
+ not css.has_widget)
+ self.assertTrue(grid.has_gridmgr and not gr_0.has_gridmgr and
+ not gd_0.has_gridmgr)
# widget attr
self.assertIsNone(title.widget_type)
self.assertEqual(left.widget_type, 'labelframe')
@@ -198,10 +221,13 @@ def test_widget(self):
self.assertEqual(grid.gridmgr, gd_0.gridmgr)
self.assertEqual(button._options['command'], self.tkoutw.test)
self.assertEqual(button._options['text'], 'test button')
- self.assertEqual(entry_0._options['textvariable'], self.tkoutw.__class__.__dict__['strfield'].var)
+ self.assertEqual(entry_0._options['textvariable'],
+ self.tkoutw.__class__.__dict__['strfield'].var)
self.assertEqual(left.pack_options['fill'], 'both')
self.assertEqual(gd_0.grid_options, {'row': 0, 'column': 0})
- self.assertEqual(gd_1.grid_options, {'row': 0, 'column': 1, 'rowspan': '2', 'columnspan': '2'})
+ self.assertEqual(gd_1.grid_options, {'row': 0, 'column': 1,
+ 'rowspan': '2',
+ 'columnspan': '2'})
self.assertEqual(gd_2.grid_options, {'row': 1, 'column': 0})
self.assertIsNone(title.widget)
self.assertIsInstance(button.widget, Button)
@@ -269,4 +295,4 @@ def test_grid_mgr(self):
if __name__ == '__main__':
- unittest.main()
\ No newline at end of file
+ unittest.main()
diff --git a/tkouter/core.py b/tkouter/core.py
index b8cfc20..c752ef8 100644
--- a/tkouter/core.py
+++ b/tkouter/core.py
@@ -2,14 +2,13 @@
"""
-__all__ = [
+__all__ = [
'register',
'TkOutWidget',
]
from io import StringIO
-from html.parser import HTMLParser
from tkinter import Frame, Menu
from tkinter import ttk
@@ -24,8 +23,8 @@
def register(name):
""" function to add additional widget to BODY_WIDGETS
- usage:
- register('my_widget_name')(MyWidgetClass)
+ usage:
+ register('my_widget_name')(MyWidgetClass)
"""
def _register(widget_cls):
settings.WIDGETS[name] = widget_cls
@@ -42,7 +41,7 @@ def get_column(self, row, rowspan=1, colspan=1):
rsegments = self._segments.setdefault(row, [])
if not rsegments:
return 0
- lo = rsegments[0][0]
+
hi = rsegments[-1][-1]
for col in range(0, hi + 2):
if self._has_space(row, col, rowspan, colspan):
@@ -115,12 +114,14 @@ def init(self, tkoutw):
# top checker
def _check_valid(self):
- if not (self.is_html or self.is_scope or self.can_under_head or self.can_under_body):
+ if not (self.is_html or self.is_scope or self.can_under_head or
+ self.can_under_body):
msg = 'unrecognized tag <{}>'
raise TagUnRecognizedError(msg.format(self.tag))
def _check_scope(self):
- if not (self.is_html or self.is_scope or self.is_under_head or self.is_under_body):
+ if not (self.is_html or self.is_scope or self.is_under_head or
+ self.is_under_body):
msg = 'tag <{}> should be under tag or '
raise TagInWrongScope(msg.format(self.tag))
elif self.is_under_head and not self.can_under_head:
@@ -151,8 +152,8 @@ def _handle_options(self, options):
execution.
Some options are special or complicated, we should pre-set their values
- and assign to some variables then specify the variable in symbol "{" and
- "}" as option value.
+ and assign to some variables then specify the variable in symbol
+ "{" and "}" as option value.
"""
modified_options = {}
for name, value in options.items():
@@ -170,7 +171,7 @@ def _handle_options(self, options):
elif attr in data:
data = data[attr]
modified_options[name] = data
- except:
+ except TypeError:
msg = 'data "{}" does not exist'
raise DataNotExistError(msg.format(value))
else:
@@ -182,7 +183,7 @@ def _parse_options(self):
if attr in ['name', 'type', 'class', 'id']:
continue
elif '-' in attr:
- method, _, attr = attr.partition('-')
+ method, _, attr = attr.partition('-')
options = self._widget_method_options.setdefault(method, {})
options[attr] = value
else:
@@ -225,7 +226,7 @@ def _init_grid_options(self):
# tag category
@property
def is_html(self):
- return self.tag == 'html' or self.tag =='xml'
+ return self.tag == 'html' or self.tag == 'xml'
@property
def is_head(self):
@@ -285,7 +286,8 @@ def is_sub_menu(self):
@property
def is_notebook(self):
- return self.has_widget_cls and issubclass(self.widget_cls, ttk.Notebook)
+ return (self.has_widget_cls and
+ issubclass(self.widget_cls, ttk.Notebook))
# scope checker
@property
@@ -318,15 +320,18 @@ def is_in_gd(self):
@property
def can_under_head(self):
- return self.is_root_attr or self.is_link or self.is_menu or self.can_under_menu
+ return (self.is_root_attr or self.is_link or self.is_menu or
+ self.can_under_menu)
@property
def can_under_menu(self):
- return self.tag in ['separator', 'command', 'radiobutton', 'checkbutton'] or self.is_sub_menu
+ return (self.tag in ['separator', 'command', 'radiobutton',
+ 'checkbutton'] or self.is_sub_menu)
@property
def can_under_body(self):
- return (self.tag in self.widgets and not self.is_menu) or self.is_side or self.is_grid or self.is_grid_element
+ return ((self.tag in self.widgets and not self.is_menu) or
+ self.is_side or self.is_grid or self.is_grid_element)
@property
def can_in_grid(self):
@@ -343,7 +348,8 @@ def can_in_gd(self):
# widget checker
@property
def has_no_widget_type(self):
- return self.is_html or self.is_scope or self.is_root_attr or self.is_grid_element
+ return (self.is_html or self.is_scope or self.is_root_attr or
+ self.is_grid_element)
@property
def has_widget_type(self):
@@ -389,7 +395,8 @@ def widget_name(self):
self.widget_type_counter[self.widget_type] += 1
else:
self.widget_type_counter[self.widget_type] = 0
- self._name = self.widget_type + '_' + str(self.widget_type_counter[self.widget_type])
+ self._name = (self.widget_type + '_' +
+ str(self.widget_type_counter[self.widget_type]))
return self._name
@property
@@ -429,7 +436,8 @@ def widget(self):
if self._widget is None:
assert(self.parent_widget)
if self.is_under_body and not self.is_grid_element:
- self._widget = self.widget_cls(self.parent_widget, **self._options)
+ self._widget = self.widget_cls(self.parent_widget,
+ **self._options)
setattr(self.tkoutw, self.widget_name, self._widget)
elif self.is_menu:
self._widget = self.widget_cls(self.parent_widget)
@@ -438,13 +446,16 @@ def widget(self):
# core function
def display(self):
- if self.is_html or self.is_scope or self.is_link or self.is_grid_element:
+ if (self.is_html or self.is_scope or self.is_link or
+ self.is_grid_element):
pass
elif self.is_under_head:
if self.is_sub_menu:
- self.parent_widget.add_cascade(menu=self.widget, **self._options)
+ self.parent_widget.add_cascade(menu=self.widget,
+ **self._options)
elif self.is_under_menu:
- self.parent_widget.add(itemType=self.widget_type, **self._options)
+ self.parent_widget.add(itemType=self.widget_type,
+ **self._options)
elif self.is_top_menu:
self.parent_widget['menu'] = self.widget
elif self.is_root_attr:
@@ -456,14 +467,16 @@ def display(self):
else:
self.widget.pack(**self.pack_options)
if self.getparent().is_notebook:
- self.parent_widget.add(child=self.widget, text=self.widget_name)
+ self.parent_widget.add(child=self.widget,
+ text=self.widget_name)
class TkOutWidget(Frame):
""" Design a user-defined widget with html-based layout
User could define a html-based layout widget just by inheriting this class.
- Subclass may override some class attributes to make its own widget or layout.
+ Subclass may override some class attributes
+ to make its own widget or layout.
Public attributes:
- widgets: available widgets (dictionary)
@@ -507,7 +520,6 @@ def _build(self):
self._proxy_cache = list(self._tree.getroot().iter())
# css
- css = None
for e in self._tree.getroot().iter():
if e.is_css and e.get('href'):
self._css = env.get_template(e.get('href')).render()
@@ -526,7 +538,8 @@ def _build(self):
e.display()
except TagError as err:
print('Error when parsing tag: ')
- print(etree.tostring(e, pretty_print=True, encoding=str, method='html'))
+ print(etree.tostring(e, pretty_print=True, encoding=str,
+ method='html'))
raise err
def _select(self, selector_str):
@@ -536,4 +549,5 @@ def _select(self, selector_str):
def select(self, selector_str):
""" use css selector string to query corresponding widgets """
- return (e.widget for e in self._select(selector_str) if e.widget is not None)
\ No newline at end of file
+ return (e.widget for e in self._select(selector_str)
+ if e.widget is not None)
diff --git a/tkouter/errors.py b/tkouter/errors.py
index f0a76cf..0ff24d6 100644
--- a/tkouter/errors.py
+++ b/tkouter/errors.py
@@ -13,14 +13,18 @@
class Error(Exception):
""" Base-class for all exceptions raised by this module. """
+
class TagError(Error):
""" There is a problem in the tag of layout html. """
+
class TagUnRecognizedError(TagError):
""" There is unknown tag in tkouter layout html. """
+
class DataNotExistError(TagError):
""" can not find the data specified in tag from data_context. """
+
class TagInWrongScope(TagError):
- """ tag in wrong scope """
\ No newline at end of file
+ """ tag in wrong scope """
diff --git a/tkouter/fields.py b/tkouter/fields.py
index 75d2817..fc451e6 100644
--- a/tkouter/fields.py
+++ b/tkouter/fields.py
@@ -80,4 +80,4 @@ def __get__(self, instance, owner):
return self.var.get()
def __set__(self, instance, value):
- self.var.set(value)
\ No newline at end of file
+ self.var.set(value)
diff --git a/tkouter/settings.py b/tkouter/settings.py
index 6d34c33..ea0d725 100644
--- a/tkouter/settings.py
+++ b/tkouter/settings.py
@@ -29,4 +29,4 @@
'menu': Menu,
}
-LOADER = FileSystemLoader('./')
\ No newline at end of file
+LOADER = FileSystemLoader('./')