def title(self, id, searchvalues=None): thetitle = Title.get(id) searchform = widgets.TableForm(fields=PrivateSearchFields(), submit_text="Search!") titleform = widgets.TableForm( name="titleform", fields=PrivateTitleFields(), submit_text="modify this title's sections and distributor") titlepersistenceform = widgets.TableForm( fields=PrivateTitlePersistenceFields(), submit_text="") persisting_sections = [] # try: # persisting_sections=session['persisting_sections'] # except: # session['persisting_sections']=[] # print persisting_sections # sections=list(set(thetitle.get_tag_collection(category='inventory',key='section'))) # sections=thetitle.sections # sections.extend(persisting_sections) print[s.id for s in list(thetitle.sections)] return dict(thetitle=thetitle, authorswidget=PrivateAuthorsWidget(), searchform=searchform, searchvalues=searchvalues, titleform=titleform, today=strftime("%Y-%m-%d", gmtime()), titlepersistenceform=titlepersistenceform, titlesections=[s.id for s in list(thetitle.sections)], persisting_sections=persisting_sections)
def test_required_fields(): """ Required field are automatically discovered from the form validator and marked with the "requiredfield" css class. """ class MyFields(widgets.WidgetsList): name = widgets.TextField(validator=validators.String()) comment = widgets.TextArea(validator=validators.String(not_empty=True)) form = widgets.TableForm(fields=MyFields()) class MyRoot(turbogears.controllers.RootController): def test(self): return dict(form=form) test = turbogears.expose(template=".form")(test) cherrypy.root = MyRoot() testutil.create_request("/test") output = cherrypy.response.body[0].lower() print output name_p = 'name="comment"' class_p = 'class="textarea requiredfield"' assert (re.compile('.*'.join([class_p, name_p])).search(output) or re.compile('.*'.join([name_p, class_p])).search(output)) name_p = 'name="name"' class_p = 'class="textfield"' assert (re.compile('.*'.join([class_p, name_p])).search(output) or re.compile('.*'.join([name_p, class_p])).search(output))
def storefront(self): searchform = widgets.TableForm(fields=SearchFields(), submit_text="Search!") conn = db.connect() cursor = conn.cursor() cursor.execute(""" select booktitle,count(book.id) as blah,title_id from book,title where book.title_id=title.id and book.status='SOLD' and title.kind_id=1 group by title_id order by blah desc limit 30 """) results = cursor.fetchall() cursor.close() best_sellers = [ Title.get(x[2]) for x in results if Title.get(x[2]).copies_in_status("STOCK") > 0 ] new_titles = Title.select(""" book.title_id=title.id AND book.status ='STOCK' """, orderBy="-title.id", clauseTables=['book'], distinct=True) return dict(authorswidget=AuthorsWidget(), titlelistwidget=TitleListWidget(), searchform=searchform, new_titles=new_titles[:10], best_sellers=best_sellers)
def reinventory(self, isbn="", author="", title=""): searchform = widgets.TableForm(fields=PrivateSearchFields(), submit_text="Search!") if author == "" and title == "" and isbn == "": the_titles = False else: the_titles = Title.select(""" title.isbn LIKE '%%%s%%' AND author.id=author_title.author_id AND author_title.title_id=title.id AND author.author_name LIKE '%%%s%%' AND title.booktitle LIKE '%%%s%%' """ % (escape_string(isbn), escape_string(author), escape_string(title)), orderBy="booktitle", clauseTables=['author', 'author_title'], distinct=True) title_count = 0 try: title_count = the_titles.count() except: pass if title_count > 0: if the_titles.count() == 1: return self.title(the_titles[0].id, searchvalues=dict(author=author, title=title, isbn=isbn)) return dict(the_titles=the_titles, authorswidget=PrivateAuthorsWidget(), titlelistwidget=PrivateTitleListWidget(), searchform=searchform, values=dict(author=author, title=title, isbn=isbn))
class TestNestedWidgetsWMixedValidation: form = widgets.TableForm( name="myform", validator=s_validator, fields=[ widgets.TextField("name"), widgets.TextField("age"), widgets.TextField("number", validator=int_validator), widgets.FieldSet( name="sub", validator=s_validator, fields=[ widgets.TextField("name"), widgets.TextField("age"), widgets.TextField("number", validator=int_validator), widgets.FieldSet( name="sub2", fields=[ widgets.TextField("name"), widgets.TextField("age", validator=int_validator), widgets.TextField("number", validator=int_validator), ]), ]), ]) def test_mixed_validators(self): """ Tests that schema validators and single validators can be mixed safely. """ values = dict(age="bad", number="22", sub=dict(age="bad", number="bad", sub2=dict( age="bad", number="bad", ))) values, errors = catch_validation_errors(self.form, values) print values, errors assert errors.pop('age', False) #assert values['number'] == 22 # assert errors are not getting poluted errors from other levels of # the tree assert errors.keys() == ['sub'] errors = errors['sub'] assert errors.pop('age', False) assert errors.pop('number', False) assert errors.keys() == ['sub2'] errors = errors['sub2'] assert errors.pop('age', False) assert errors.pop('number', False) assert not errors
def test_disabled_widget(): form = widgets.TableForm(fields=[ widgets.TextField("name"), widgets.TextField("age", validator=validators.Int()) ], submit_text="Submit") output = form.render(disabled_fields=["age"]) assert "age" not in output
def test_creation_overriding(): class TestFormFields(widgets.WidgetsList): foo = widgets.TextField() bar = widgets.CheckBox() fields = TestFormFields() fields[1] = widgets.TextField('bar') t = widgets.TableForm(fields=fields) assert len(t.fields) == 2, '%s' % [x.name for x in t.fields]
def test_input_errors(): """Data is stored in the request object if there are errors""" form = widgets.TableForm(fields=[ widgets.TextField("name"), widgets.TextField("age", validator=validators.Int()) ]) values = dict(name="ed", age="ed") values, errors = catch_validation_errors(form, values) assert "enter an integer" in str(errors["age"])
def test_creation(): class TestFormFields(widgets.WidgetsList): foo = widgets.TextField() bar = widgets.CheckBox() t = widgets.TableForm(fields=TestFormFields() + [widgets.TextField('a')]) wlist = t.fields assert len(wlist) == 3, '%s' % [x.name for x in wlist] assert wlist[0].name == 'foo' assert wlist[1].name == 'bar' assert wlist[2].name == 'a'
def test_input_conversion(): """Input for the whole form can be validated and converted""" form = widgets.TableForm(fields=[ widgets.TextField("name"), widgets.TextField("age", validator=validators.Int()) ], submit_text="Submit") values = dict(name="ed", age="15") values = form.validate(values) assert values["name"] == "ed" assert values["age"] == 15 assert not values.has_key("submit")
def test_passing_instance(): """You can pass an instance to a form for the value""" form = widgets.TableForm(fields=[ widgets.TextField("name"), widgets.TextField("age", validator=validators.Int()) ], submit_text="Submit") class Person(object): name = "ed" age = 892 output = form.render(Person(), format="xhtml") assert 'value="ed"' in output assert 'value="892"' in output
class TestSchemaValidationWithChildWidgetsValidators: """Tests the validation of a CompoundWidget is done correctly with a Schema validator and independent validators on the each of the child widgets.""" class Fields(widgets.WidgetsList): name = widgets.TextField(validator=validators.UnicodeString()) age = widgets.TextField(validator=validators.Int()) passwd = widgets.PasswordField(validator=validators.NotEmpty()) passwd2 = widgets.PasswordField(validator=validators.UnicodeString()) class FieldsSchema(validators.Schema): chained_validators = [validators.FieldsMatch('passwd', 'passwd2')] form = widgets.TableForm(fields=Fields(), validator=FieldsSchema()) def test_goodvalues(self): values = dict(name=u'Jos\xc3\xa9', age="99", passwd="fado", passwd2="fado") values, errors = catch_validation_errors(self.form, values) assert values['age'] == 99 assert not errors.keys() def test_widget_validator_failure(self): values = dict(name=u'Jos\xc3\xa9', age="ninetynine", passwd="fado", passwd2="fado") values, errors = catch_validation_errors(self.form, values) assert "age" in errors.keys() def test_widget_validator_and_schema_failure(self): values = dict(name=u'Jos\xc3\xa9', age="ninetynine", passwd="fado", passwd2="fadO") values, errors = catch_validation_errors(self.form, values) assert "age" in errors.keys() assert "passwd2" in errors.keys()
def search(self, author="", title=""): searchform = widgets.TableForm(fields=SearchFields(), submit_text="Search!") if author == "" and title == "": the_titles = False else: the_titles = Title.select( """ book.title_id=title.id AND book.status ='STOCK' AND author.id=author_title.author_id AND author_title.title_id=title.id AND author.author_name LIKE '%%%s%%' AND title.booktitle LIKE '%%%s%%' """ % (escape_string(author), escape_string(title)), orderBy="booktitle", clauseTables=['book', 'author', 'author_title'], distinct=True) return dict(the_titles=the_titles, authorswidget=AuthorsWidget(), titlelistwidget=TitleListWidget(), searchform=searchform, values=dict(author=author, title=title))
class TestSchemaValidation: """Tests the validation of a CompoundWidget is done correctly with a Schema validator and no validators on the child widgets.""" class Fields(widgets.WidgetsList): name = widgets.TextField() age = widgets.TextField() passwd = widgets.PasswordField() passwd2 = widgets.PasswordField() class FieldsSchema(validators.Schema): chained_validators = [validators.FieldsMatch('passwd', 'passwd2')] name = validators.UnicodeString() age = validators.Int() passwd = validators.NotEmpty() passwd2 = validators.UnicodeString() form = widgets.TableForm(fields=Fields(), validator=FieldsSchema()) def test_goodvalues(self): values = dict(name=u'Jos\xc3\xa9', age="99", passwd="fado", passwd2="fado") values, errors = catch_validation_errors(self.form, values) assert values['age'] == 99 assert not errors def test_badvalues(self): values = dict(name=u'Jos\xc3\xa9', age="99", passwd="fado", passwd2="fadO") values, errors = catch_validation_errors(self.form, values) assert "passwd2" in errors.keys()
class TestNestedSchemaValidators: #XXX: Age is always validated by the nested schemas, number is # validated with widget validator. form = widgets.TableForm( name="myform", validator=OuterSchema(), fields=[ widgets.TextField("age"), widgets.TextField("number", validator=int_validator), widgets.FieldSet( name="sub", fields=[ widgets.TextField("age"), widgets.TextField("number", validator=int_validator), widgets.FieldSet( name="sub2", fields=[ widgets.TextField("age"), widgets.TextField("number", validator=int_validator), ]), ]), ]) def test_nested_schemas(self): """ Tests that we can nest schema validators safely. """ values = dict(age="bad", number="22", sub=dict(age="27", number="bad", sub2=dict( age="bad", number="bad", ))) values, errors = catch_validation_errors(self.form, values) print values, errors assert errors.pop('age', False) #assert values['number'] == 22 # assert errors are not getting poluted errors from other levels of # the tree assert errors.keys() == ['sub'] errors = errors['sub'] values = values['sub'] #XXX This assertion fails :( #XXX But it's normal as the Schema doesn't convert good values in # invalid Schemas, ATM #assert values['age'] == 27 assert errors.pop('number', False) assert errors.keys() == ['sub2'] errors = errors['sub2'] assert errors.pop('age', False) assert errors.pop('number', False) assert not errors def test_nested_schemas_good_values(self): values = dict(age="21", number="22", sub=dict(age="27", number="28", sub2=dict( age="33", number="34", ))) values, errors = catch_validation_errors(self.form, values) print values, errors assert not errors assert (values["age"], values['number']) == (21, 22) values = values['sub'] assert (values["age"], values['number']) == (27, 28) values = values['sub2'] assert (values["age"], values['number']) == (33, 34)
class TestNestedWidgets: form = widgets.TableForm( name="myform", fields=[ widgets.TextField("name"), widgets.TextField("age", validator=int_validator), widgets.FieldSet("sub", fields=[ widgets.TextField("name"), widgets.TextField("age", validator=int_validator), widgets.FieldSet( "sub2", fields=[ widgets.TextField("name"), widgets.TextField( "age", validator=int_validator), ], validator=TestSchema()), ], validator=TestSchema()), ], validator=TestSchema()) def test_display(self): """ Checks if names fo the widgets are set correctly depending on their path. """ output = self.form.render(dict(sub=dict(sub2=dict(age=22))), format='xhtml') value_p = 'value="22"' name_p = 'name="sub.sub2.age"' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) output = self.form.render(dict(sub=dict(age=22)), format='xhtml') value_p = 'value="22"' name_p = 'name="sub.age"' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) output = self.form.render(dict(sub=dict(age=22)), format='xhtml') id_p = 'id="myform_sub_age"' name_p = 'name="sub.age"' assert (re.compile('.*'.join([value_p, id_p])).search(output) or re.compile('.*'.join([id_p, value_p])).search(output)) output = self.form.render(dict(age=22), format='xhtml') value_p = 'value="22"' name_p = 'name="age"' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) def test_validate_outermost(self): values = dict(age="twenty") values, errors = catch_validation_errors(self.form, values) print values, errors assert errors.pop('age', False) assert not errors def test_validate_sub(self): values = dict(sub=dict(age="twenty")) values, errors = catch_validation_errors(self.form, values) print values, errors # check the outermost dict is not poluted with errors from the inner # dicts assert not errors.has_key('age') errors = errors['sub'] assert errors.pop('age', False) assert not errors def test_validate_sub2(self): values = dict(sub=dict(sub2=dict(age="twenty"))) values, errors = catch_validation_errors(self.form, values) print values, errors assert not errors.has_key('age') errors = errors['sub'] print values, errors assert not errors.has_key('age') errors = errors['sub2'] print values, errors assert errors.pop('age', False) assert not errors def test_validate_sub_and_sub2(self): values = dict(sub=dict(age="fhg", sub2=dict(age="twenty"))) values, errors = catch_validation_errors(self.form, values) print values, errors assert not errors.has_key('age') errors = errors['sub'] print values, errors assert errors.pop('age', False) errors = errors['sub2'] print values, errors assert errors.pop('age', False) assert not errors def test_good_values(self): values = dict(age=22, sub=dict(sub2=dict(age=20))) values, errors = catch_validation_errors(self.form, values) print values, errors assert errors == {} assert values['age'] == 22 def test_good_and_bad_values(self): values = dict(age="ddd", sub=dict(age="20", sub2=dict())) values, errors = catch_validation_errors(self.form, values) print values, errors assert errors.pop('age', False) assert not errors
class TestNestedWidgetsWSchemaValidation: form = widgets.TableForm(name="myform", validator=s_validator, fields=[ widgets.TextField("name"), widgets.TextField("age"), widgets.FieldSet( name="sub", validator=s_validator, fields=[ widgets.TextField("name"), widgets.TextField("age"), widgets.FieldSet( name="sub2", validator=s_validator, fields=[ widgets.TextField("name"), widgets.TextField("age"), ]), ]), ]) def test_validate_sub_schema(self): values = dict(sub=dict(age="twenty")) values, errors = catch_validation_errors(self.form, values) print values, errors # check the outermost dict is not poluted with errors from the inner # dicts assert not errors.has_key('age') errors = errors['sub'] assert errors.pop('age', False) assert not errors def test_good_and_bad_values_schema(self): values = dict(age="ddd", sub=dict(age="20", sub2=dict())) values, errors = catch_validation_errors(self.form, values) print values, errors assert errors.pop('age', False) assert not errors #assert values['sub']['age'] == 20 def test_good_values_schema(self): values = dict(age=22, sub=dict(sub2=dict(age=20))) values, errors = catch_validation_errors(self.form, values) print values, errors assert errors == {} assert values['age'] == 22 def test_validate_sub_and_sub2_schema(self): values = dict(sub=dict(age="fhg", sub2=dict(age="twenty"))) values, errors = catch_validation_errors(self.form, values) print values, errors assert not errors.has_key('age') errors = errors['sub'] print values, errors assert errors.pop('age', False) errors = errors['sub2'] print values, errors assert errors.pop('age', False) assert not errors def test_validate_sub2_schema(self): values = dict(sub=dict(sub2=dict(age="twenty"))) values, errors = catch_validation_errors(self.form, values) print values, errors assert not errors.has_key('age') errors = errors['sub'] print values, errors assert not errors.has_key('age') errors = errors['sub2'] print values, errors assert errors.pop('age', False) def test_validate_outermost_schema(self): values = dict(age="twenty") values, errors = catch_validation_errors(self.form, values) print values, errors assert errors.pop('age', False) assert not errors assert not errors
class Recipes(RPCRoot): # For XMLRPC methods in this class. exposed = True hidden_id = widgets.HiddenField(name='id') confirm = widgets.Label( name='confirm', default="Are you sure you want to release the system?") return_reservation_form = widgets.TableForm( 'end_recipe_reservation', fields=[hidden_id, confirm], action='./really_return_reservation', submit_text=_(u'Yes')) tasks = RecipeTasks() recipe_widget = RecipeWidget() log_types = dict( R=LogRecipe, T=LogRecipeTask, E=LogRecipeTaskResult, ) @cherrypy.expose @identity.require(identity.not_anonymous()) def by_log_server(self, server, limit=50): """ Returns a list of recipe IDs which have logs stored on the given server. By default, returns at most 50 at a time. Only returns recipes where the whole recipe set has completed. Also excludes recently completed recipe sets, since the system may continue uploading logs for a short while until beaker-provision powers it off. """ finish_threshold = datetime.utcnow() - timedelta(minutes=2) recipes = Recipe.query.join(Recipe.recipeset)\ .filter(RecipeSet.status.in_([s for s in TaskStatus if s.finished]))\ .filter(not_(RecipeSet.recipes.any(Recipe.finish_time >= finish_threshold)))\ .filter(Recipe.log_server == server)\ .limit(limit) return [recipe_id for recipe_id, in recipes.values(Recipe.id)] @cherrypy.expose @identity.require(identity.not_anonymous()) def register_file(self, server, recipe_id, path, filename, basepath): """ register file and return path to store """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) if recipe.is_finished(): raise BX('Cannot register file for finished recipe %s' % recipe.t_id) # Add the log to the DB if it hasn't been recorded yet. log_recipe = LogRecipe.lazy_create( recipe_id=recipe.id, path=path, filename=filename, ) log_recipe.server = server log_recipe.basepath = basepath # Pull log_server out of server_url. recipe.log_server = urlparse.urlparse(server)[1] return '%s' % recipe.filepath @cherrypy.expose @identity.require(identity.not_anonymous()) def files(self, recipe_id): """ Return an array of logs for the given recipe. :param recipe_id: id of recipe :type recipe_id: integer .. deprecated:: 0.9.4 Use :meth:`taskactions.files` instead. """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) return [log for log in recipe.all_logs] @cherrypy.expose @identity.require(identity.not_anonymous()) def change_files(self, recipe_id, server, basepath): """ Change the server and basepath where the log files lives, Usually used to move from lab controller cache to archive storage. """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) for mylog in recipe.all_logs: myserver = '%s/%s/' % (server, mylog['filepath']) mybasepath = '%s/%s/' % (basepath, mylog['filepath']) self.change_file(mylog['tid'], myserver, mybasepath) recipe.log_server = urlparse.urlparse(server)[1] return True @cherrypy.expose @identity.require(identity.not_anonymous()) def change_file(self, tid, server, basepath): """ Change the server and basepath where the log file lives, Usually used to move from lab controller cache to archive storage. """ log_type, log_id = tid.split(":") if log_type.upper() in self.log_types.keys(): try: mylog = self.log_types[log_type.upper()].by_id(log_id) except InvalidRequestError: raise BX(_("Invalid %s" % tid)) mylog.server = server mylog.basepath = basepath return True @cherrypy.expose @identity.require(identity.not_anonymous()) def extend(self, recipe_id, kill_time): """ Extend recipe watchdog by kill_time seconds """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) return recipe.extend(kill_time) @cherrypy.expose def console_output(self, recipe_id, output_length=None, offset=None): """ Get text console log output from OpenStack """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) manager = dynamic_virt.VirtManager(recipe.recipeset.job.owner) return manager.get_console_output(recipe.resource.instance_id, output_length) @cherrypy.expose def watchdog(self, recipe_id): try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) return recipe.status_watchdog() @cherrypy.expose @identity.require(identity.not_anonymous()) def stop(self, recipe_id, stop_type, msg=None): """ Set recipe status to Completed """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) if stop_type not in recipe.stop_types: raise BX( _('Invalid stop_type: %s, must be one of %s' % (stop_type, recipe.stop_types))) kwargs = dict(msg=msg) return getattr(recipe, stop_type)(**kwargs) @cherrypy.expose @identity.require(identity.not_anonymous()) def install_start(self, recipe_id=None): """ Report comencement of provisioning of a recipe's resource, extend first task's watchdog, and report 'Install Started' against it. """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_("Invalid Recipe ID %s" % recipe_id)) first_task = recipe.first_task if not recipe.resource.install_started: recipe.resource.install_started = datetime.utcnow() # extend watchdog by 3 hours 60 * 60 * 3 kill_time = 10800 # XXX In future releases where 'Provisioning' # is a valid recipe state, we will no longer # need the following block. log.debug('Extending watchdog for %s', first_task.t_id) first_task.extend(kill_time) log.debug('Recording /start for %s', first_task.t_id) first_task.pass_(path=u'/start', score=0, summary=u'Install Started') return True else: log.debug('Already recorded /start for %s', first_task.t_id) return False @cherrypy.expose @identity.require(identity.not_anonymous()) def postinstall_done(self, recipe_id=None): """ Report completion of postinstallation """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_(u'Invalid Recipe ID %s' % recipe_id)) recipe.resource.postinstall_finished = datetime.utcnow() return True @cherrypy.expose @identity.require(identity.not_anonymous()) def install_done(self, recipe_id=None, fqdn=None): """ Report completion of installation with current FQDN """ if not recipe_id: raise BX(_("No recipe id provided!")) if not fqdn: raise BX(_("No fqdn provided!")) try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_("Invalid Recipe ID %s" % recipe_id)) recipe.resource.install_finished = datetime.utcnow() # We don't want to change an existing FQDN, just set it # if it hasn't been set already (see BZ#879146) configured = recipe.resource.fqdn if configured is None: recipe.resource.fqdn = configured = fqdn elif configured != fqdn: # We use eager formatting here to make this easier to test log.info("Configured FQDN (%s) != reported FQDN (%s) in R:%s" % (configured, fqdn, recipe_id)) return configured @identity.require(identity.not_anonymous()) @expose() def really_return_reservation(self, id, msg=None): try: recipe = Recipe.by_id(id) except InvalidRequestError: raise BX(_("Invalid Recipe ID %s" % id)) recipe.return_reservation() flash(_(u"Successfully released reserved system for %s" % recipe.t_id)) redirect('/jobs/mine') @expose(template="bkr.server.templates.form") @identity.require(identity.not_anonymous()) def return_reservation(self, recipe_id=None): """ End recipe reservation """ if not recipe_id: raise BX(_("No recipe id provided!")) return dict( title='Release reserved system for Recipe %s' % recipe_id, form=self.return_reservation_form, action='./really_return_reservation', options={}, value=dict(id=recipe_id), ) @cherrypy.expose @identity.require(identity.not_anonymous()) def postreboot(self, recipe_id=None): # Backwards compat only, delete this after 0.10: # the recipe_id arg used to be hostname try: int(recipe_id) except ValueError: system = System.by_fqdn(recipe_id, identity.current.user) system.action_power('reboot', service=u'XMLRPC', delay=30) return system.fqdn try: recipe = Recipe.by_id(int(recipe_id)) except (InvalidRequestError, NoResultFound, ValueError): raise BX(_('Invalid recipe ID %s') % recipe_id) if isinstance(recipe.resource, SystemResource): recipe.resource.system.action_power('reboot', service=u'XMLRPC', delay=30) return True @cherrypy.expose def to_xml(self, recipe_id=None): """ Pass in recipe id and you'll get that recipe's xml """ if not recipe_id: raise BX(_("No recipe id provided!")) try: recipexml = Recipe.by_id(recipe_id).to_xml().toprettyxml() except InvalidRequestError: raise BX(_("Invalid Recipe ID %s" % recipe_id)) return recipexml def _recipe_search(self, recipe, **kw): recipe_search = search_utility.Recipe.search(recipe) for search in kw['recipesearch']: col = search['table'] try: recipe_search.append_results(search['value'], col, search['operation'], **kw) except KeyError, e: log.error(e) return recipe_search.return_results() return recipe_search.return_results()
def test_callable_options_for_selection_field(): cc = CallableCounter() w = widgets.CheckBoxList('collections', label='Collections', options=cc) assert cc.counter == 1 # called once to guess validator cc = CallableCounter() w = widgets.CheckBoxList('collections', label='Collections', validator=validators.Int(), options=cc) assert cc.counter == 0 # cc shouldn't be called if validator is provided nestedform = widgets.TableForm(fields=[ widgets.FieldSet( "foo", fields=[widgets.TextField("name"), widgets.TextField("age")]) ]) class NestedController(controllers.Controller): [expose()] [validate(form=nestedform)] def checkform(self, foo): self.foo = foo def test_nested_variables(): cherrypy.request = oldrequest
def test_two_form_in_the_same_page(): """ Two different forms containing some fields with the same name can be validated and re-displayed on the same page with right values and errors. """ class MyFields(widgets.WidgetsList): age = widgets.TextField(validator=validators.Int()) email = widgets.TextArea(validator=validators.Email()) form1 = widgets.TableForm(name="form1", fields=MyFields()) form2 = widgets.TableForm(name="form2", fields=MyFields()) class MyRoot(turbogears.controllers.RootController): def test(self): return dict(form1=form1, form2=form2) test = turbogears.expose(template=".two_forms")(test) test = turbogears.validate(form=form1)(test) test = turbogears.error_handler(test)(test) def test2(self): return dict(form=form2) test2 = turbogears.expose(template=".form")(test2) test2 = turbogears.validate(form=form2)(test2) test2 = turbogears.error_handler(test2)(test2) def test3(self): return dict(form=form1) test3 = turbogears.expose(template=".form")(test3) test3 = turbogears.validate(form=form2)(test3) test3 = turbogears.error_handler(test3)(test3) cherrypy.root = MyRoot() testutil.create_request("/test?age=foo&email=bar") output = cherrypy.response.body[0].lower() iv = cherrypy.request.input_values validation_errors = cherrypy.request.validation_errors validated_form = cherrypy.request.validated_form print output print iv print validation_errors print validated_form assert form1 is validated_form assert form1.is_validated assert form2 is not validated_form assert not form2.is_validated value_p = 'value="foo"' id_p = 'id="form1_age"' assert (re.compile('.*'.join([value_p, id_p])).search(output) or re.compile('.*'.join([id_p, value_p])).search(output)) value_p = 'value="foo"' id_p = 'id="form2_age"' assert not (re.compile('.*'.join([value_p, id_p])).search(output) or re.compile('.*'.join([id_p, value_p])).search(output)) cherrypy.root = MyRoot() testutil.create_request("/test2?age=foo&email=bar") output = cherrypy.response.body[0].lower() iv = cherrypy.request.input_values validation_errors = cherrypy.request.validation_errors validated_form = cherrypy.request.validated_form print output print iv print validation_errors print validated_form assert form1 is not validated_form assert not form1.is_validated assert form2 is validated_form assert form2.is_validated assert 'value="foo"' in output assert '>bar<' in output assert 'class="fielderror"' in output cherrypy.root = MyRoot() testutil.create_request("/test3?age=foo&email=bar") output = cherrypy.response.body[0].lower() iv = cherrypy.request.input_values validation_errors = cherrypy.request.validation_errors validated_form = cherrypy.request.validated_form print output print iv print validation_errors print validated_form assert form1 is not validated_form assert not form1.is_validated assert form2 is validated_form assert form2.is_validated assert 'value="foo"' not in output assert '>bar<' not in output assert 'class="fielderror"' not in output
def test_repeating_fields(): repetitions = 5 class MyFields(widgets.WidgetsList): name = widgets.TextField(validator=validators.String(not_empty=True)) comment = widgets.TextField(validator=validators.String()) form = widgets.TableForm(name="form", fields=[ widgets.RepeatingFieldSet( name="repeat", fields=MyFields(), repetitions=repetitions) ]) class MyRoot(turbogears.controllers.RootController): def test(self): return dict(form=form) test = turbogears.expose(template=".form")(test) def test_value(self): value = dict(repeat=[{ 'name': 'foo', 'comment': 'hello' }, None, None, { 'name': 'bar', 'comment': 'byebye' }]) return dict(form=form, value=value) test_value = turbogears.expose(template=".form")(test_value) def test_validation(self): return dict(form=form) test_validation = turbogears.expose(template=".form")(test_validation) test_validation = turbogears.validate(form=form)(test_validation) test_validation = turbogears.error_handler(test_validation)( test_validation) cherrypy.root = MyRoot() testutil.create_request("/test") output = cherrypy.response.body[0].lower() for i in range(repetitions): assert 'id="form_repeat_%i"' % i in output assert 'name="repeat-%i.name"' % i in output assert 'id="form_repeat_%i_name"' % i in output assert 'name="repeat-%i.comment"' % i in output assert 'id="form_repeat_%i_comment"' % i in output cherrypy.root = MyRoot() testutil.create_request("/test_value") output = cherrypy.response.body[0].lower() name_p = 'name="repeat-0.name"' value_p = 'value="foo"' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) name_p = 'name="repeat-0.comment"' value_p = 'value="hello"' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) name_p = 'name="repeat-3.name"' value_p = 'value="bar"' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) name_p = 'name="repeat-3.comment"' value_p = 'value="byebye"' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) name_p = 'name="repeat-1.name"' value_p = 'value=""' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) name_p = 'name="repeat-1.comment"' value_p = 'value=""' assert (re.compile('.*'.join([value_p, name_p])).search(output) or re.compile('.*'.join([name_p, value_p])).search(output)) cherrypy.root = MyRoot() testutil.create_request("/test_validation?repeat-0.name=foo&repeat-1.name=" "&repeat-2.name=bar&repeat-3.name=&repeat-4.name=") output = cherrypy.response.body[0].lower() validation_errors = cherrypy.request.validation_errors assert validation_errors.has_key("repeat") assert isinstance(validation_errors["repeat"], list) assert validation_errors["repeat"][0] is None assert validation_errors["repeat"][1].has_key("name") assert validation_errors["repeat"][2] is None assert validation_errors["repeat"][3].has_key("name") assert validation_errors["repeat"][4].has_key("name")
import turbogears import cherrypy from turbogears import widgets from turbogears import controllers from turbogears import validators from turbogears import testutil myform = widgets.TableForm(fields = [ widgets.FieldSet( name = "p_data", fields = [ widgets.TextField(name="name"), widgets.TextField(name="age", validator=validators.Int()), ]), ]) class MyRoot(controllers.RootController): def testform(self, p_data, tg_errors=None): if tg_errors: self.has_errors = True self.name = p_data['name'] self.age = p_data['age'] testform = turbogears.validate(form=myform)(testform) testform = turbogears.expose(template="turbogears.tests.othertemplate")( testform) def set_errors(self): self.has_errors = True def testform_new_style(self, p_data):
class Jobs(RPCRoot): # For XMLRPC methods in this class. exposed = True job_list_action_widget = JobActionWidget() job_page_action_widget = JobPageActionWidget() recipeset_widget = RecipeSetWidget() recipe_widget = RecipeWidget() priority_widget = PriorityWidget( ) #FIXME I have a feeling we don't need this as the RecipeSet widget declares an instance of it product_widget = ProductWidget() retention_tag_widget = RetentionTagWidget() job_type = {'RS': RecipeSet, 'J': Job} whiteboard_widget = JobWhiteboard() hidden_id = widgets.HiddenField(name='id') confirm = widgets.Label(name='confirm', default="Are you sure you want to cancel?") message = widgets.TextArea(name='msg', label=_(u'Reason?'), help_text=_(u'Optional')) _upload = widgets.FileField(name='filexml', label='Job XML') form = HorizontalForm('jobs', fields=[_upload], action='save_data', submit_text=_(u'Submit Data')) del _upload cancel_form = widgets.TableForm('cancel_job', fields=[hidden_id, message, confirm], action='really_cancel', submit_text=_(u'Yes')) job_form = JobForm() job_schema_doc = lxml.etree.parse( pkg_resources.resource_stream('bkr.common', 'schema/beaker-job.rng')) @classmethod def success_redirect(cls, id, url='/jobs/mine', *args, **kw): flash(_(u'Success! job id: %s' % id)) redirect('%s' % url) @expose(template='bkr.server.templates.form-post') @identity.require(identity.not_anonymous()) def new(self, **kw): return dict( title='New Job', form=self.form, action='./clone', options={}, value=kw, ) def _check_job_deletability(self, t_id, job): if not isinstance(job, Job): raise TypeError('%s is not of type %s' % (t_id, Job.__name__)) if not job.can_delete(identity.current.user): raise BeakerException( _(u'You do not have permission to delete %s' % t_id)) def _delete_job(self, t_id): job = TaskBase.get_by_t_id(t_id) self._check_job_deletability(t_id, job) Job.delete_jobs([job]) return [t_id] @expose() @identity.require(identity.not_anonymous()) @restrict_http_method('post') def delete_job_page(self, t_id): try: self._delete_job(t_id) flash(_(u'Succesfully deleted %s' % t_id)) except (BeakerException, TypeError): flash(_(u'Unable to delete %s' % t_id)) redirect('.') redirect('./mine') @expose() @identity.require(identity.not_anonymous()) @restrict_http_method('post') def delete_job_row(self, t_id): try: self._delete_job(t_id) return [t_id] except (BeakerException, TypeError), e: log.debug(str(e)) response.status = 400 return ['Unable to delete %s' % t_id]
import cherrypy from turbogears import widgets, config, controllers, expose, mochikit, \ validate, validators, testutil class MyFormFields(widgets.WidgetsList): #XXX: Since allow_extra_fields should be removed from validators.Schema, # we need a validator for every input-expecting widget name = widgets.TextField(validator=validators.String()) age = widgets.TextField(validator=validators.Int(), default=0) date = widgets.CalendarDatePicker(validator=validators.DateConverter( if_empty=datetime.now())) myfields = MyFormFields() myform = widgets.TableForm(fields=myfields) class MyRoot(controllers.RootController): [expose(template="turbogears.tests.form")] def index(self): return dict(form=myform) [expose(template="turbogears.tests.form")] def fields(self): myfields.display = lambda **kw: kw.values() return dict(form=myfields)
def test_javascriptsets(): """JavaScripts are only added once""" form = widgets.TableForm(fields=[w1("foo"), w2("bar")]) assert len(form.retrieve_javascript()) == 3
def test_csssets(): """CSS references are added once""" form = widgets.TableForm(fields=[w1("foo"), w2("bar")]) assert len(form.retrieve_css()) == 1
class RecipeSets(RPCRoot): # For XMLRPC methods in this class. exposed = True hidden_id = widgets.HiddenField(name='id') confirm = widgets.Label(name='confirm', default="Are you sure you want to cancel?") message = widgets.TextArea(name='msg', label=_(u'Reason?'), help_text=_(u'Optional')) cancel_form = widgets.TableForm('cancel_recipeset', fields=[hidden_id, message, confirm], action='really_cancel', submit_text=_(u'Yes')) @identity.require(identity.not_anonymous()) @expose(template="bkr.server.templates.form") def cancel(self, id): """ Confirm cancel recipeset """ try: recipeset = RecipeSet.by_id(id) except InvalidRequestError: flash(_(u"Invalid recipeset id %s" % id)) redirect("/jobs/%s" % recipeset.job.id) if not recipeset.can_cancel(identity.current.user): flash( _(u"You don't have permission to cancel recipeset id %s" % id)) redirect("/jobs/%s" % recipeset.job.id) return dict( title='Cancel RecipeSet %s' % id, form=self.cancel_form, action='./really_cancel', options={}, value=dict(id=recipeset.id, confirm='really cancel recipeset %s?' % id), ) @identity.require(identity.not_anonymous()) @expose() def really_cancel(self, id, msg=None): """ Confirm cancel recipeset """ try: recipeset = RecipeSet.by_id(id) except InvalidRequestError: flash(_(u"Invalid recipeset id %s" % id)) redirect("/jobs/%s" % recipeset.job.id) if not recipeset.can_cancel(identity.current.user): flash( _(u"You don't have permission to cancel recipeset id %s" % id)) redirect("/jobs/%s" % recipeset.job.id) recipeset.cancel(msg) recipeset.record_activity(user=identity.current.user, service=u'WEBUI', field=u'Status', action=u'Cancelled', old='', new='') flash(_(u"Successfully cancelled recipeset %s" % id)) redirect("/jobs/%s" % recipeset.job.id) @cherrypy.expose @identity.require(identity.not_anonymous()) def stop(self, recipeset_id, stop_type, msg=None): """ Set recipeset status to Completed """ try: recipeset = RecipeSet.by_id(recipeset_id) except InvalidRequestError: raise BX(_('Invalid recipeset ID: %s' % recipeset_id)) if stop_type not in recipeset.stop_types: raise BX( _('Invalid stop_type: %s, must be one of %s' % (stop_type, recipeset.stop_types))) kwargs = dict(msg=msg) return getattr(recipeset, stop_type)(**kwargs)
def test_ticket272(): """TextFields with a "name" attribute = "title" should be OK.""" w = widgets.TableForm(fields=[widgets.TextField(name='title')]) output = w.render(format='xhtml') assert 'value' not in output
class Recipes(RPCRoot): # For XMLRPC methods in this class. exposed = True hidden_id = widgets.HiddenField(name='id') confirm = widgets.Label( name='confirm', default="Are you sure you want to release the system?") return_reservation_form = widgets.TableForm( 'end_recipe_reservation', fields=[hidden_id, confirm], action='./really_return_reservation', submit_text=_(u'Yes')) tasks = RecipeTasks() recipe_widget = RecipeWidget() log_types = dict( R=LogRecipe, T=LogRecipeTask, E=LogRecipeTaskResult, ) @cherrypy.expose @identity.require(identity.not_anonymous()) def by_log_server(self, server, limit=50): """ Returns a list of recipe IDs which have logs stored on the given server. By default, returns at most 50 at a time. Only returns recipes where the whole recipe set has completed. Also excludes recently completed recipe sets, since the system may continue uploading logs for a short while until beaker-provision powers it off. """ finish_threshold = datetime.utcnow() - timedelta(minutes=2) recipes = Recipe.query.join(Recipe.recipeset)\ .join(RecipeSet.job)\ .filter(not_(Job.is_deleted))\ .filter(RecipeSet.status.in_([s for s in TaskStatus if s.finished]))\ .filter(not_(RecipeSet.recipes.any(Recipe.finish_time >= finish_threshold)))\ .filter(Recipe.log_server == server)\ .limit(limit) return [recipe_id for recipe_id, in recipes.values(Recipe.id)] @cherrypy.expose @identity.require(identity.not_anonymous()) def register_file(self, server, recipe_id, path, filename, basepath): """ register file and return path to store """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) if recipe.is_finished(): raise BX('Cannot register file for finished recipe %s' % recipe.t_id) # Add the log to the DB if it hasn't been recorded yet. log_recipe = LogRecipe.lazy_create( recipe_id=recipe.id, path=path, filename=filename, ) log_recipe.server = server log_recipe.basepath = basepath # Pull log_server out of server_url. recipe.log_server = urlparse.urlparse(server)[1] return '%s' % recipe.filepath @cherrypy.expose @identity.require(identity.not_anonymous()) def files(self, recipe_id): """ Return an array of logs for the given recipe. :param recipe_id: id of recipe :type recipe_id: integer .. deprecated:: 0.9.4 Use :meth:`taskactions.files() <bkr.server.task_actions.taskactions.files>` instead. """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) # Build a list of logs excluding duplicate paths, to mitigate: # https://bugzilla.redhat.com/show_bug.cgi?id=963492 logdicts = [] seen_paths = set() for log in recipe.all_logs(): logdict = log.dict # The path we care about here is the path which beaker-transfer # will move the file to. # Don't be tempted to use os.path.join() here since log['path'] # is often '/' which does not give the result you would expect. path = os.path.normpath( '%s/%s/%s' % (logdict['filepath'], logdict['path'], logdict['filename'])) if path in seen_paths: logger.warn('%s contains duplicate log %s', log.parent.t_id, path) else: seen_paths.add(path) logdicts.append(logdict) return logdicts @cherrypy.expose @identity.require(identity.in_group('lab_controller')) def change_files(self, recipe_id, server, basepath): """ Change the server and basepath where the log files lives, Usually used to move from lab controller cache to archive storage. """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) for mylog in recipe.all_logs(): mylog.server = '%s/%s/' % (server, mylog.parent.filepath) mylog.basepath = '%s/%s/' % (basepath, mylog.parent.filepath) recipe.log_server = urlparse.urlparse(server)[1] return True @cherrypy.expose @identity.require(identity.not_anonymous()) def extend(self, recipe_id, kill_time): """ Extend recipe watchdog by kill_time seconds """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) return recipe.extend(kill_time) @cherrypy.expose def console_output(self, recipe_id, output_length=None, offset=None): """ Get text console log output from OpenStack """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) manager = dynamic_virt.VirtManager(recipe.recipeset.job.owner) return manager.get_console_output(recipe.resource.instance_id, output_length) @cherrypy.expose def watchdog(self, recipe_id): try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) return recipe.status_watchdog() @cherrypy.expose @identity.require(identity.not_anonymous()) def stop(self, recipe_id, stop_type, msg=None): """ Set recipe status to Completed """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_('Invalid recipe ID: %s' % recipe_id)) if stop_type not in recipe.stop_types: raise BX( _('Invalid stop_type: %s, must be one of %s' % (stop_type, recipe.stop_types))) kwargs = dict(msg=msg) return getattr(recipe, stop_type)(**kwargs) @cherrypy.expose @identity.require(identity.not_anonymous()) def install_start(self, recipe_id=None): """ Records the start of a recipe's installation. The watchdog is extended by 3 hours to allow the installation to complete. """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_("Invalid Recipe ID %s" % recipe_id)) if not recipe.installation: raise BX(_('Recipe %s not provisioned yet') % recipe_id) installation = recipe.installation if not installation.install_started: installation.install_started = datetime.utcnow() # extend watchdog by 3 hours 60 * 60 * 3 kill_time = 10800 logger.debug('Extending watchdog for %s', recipe.t_id) recipe.extend(kill_time) return True else: logger.debug('Already recorded install_started for %s', recipe.t_id) return False @cherrypy.expose @identity.require(identity.not_anonymous()) def postinstall_done(self, recipe_id=None): """ Report completion of postinstallation """ try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_(u'Invalid Recipe ID %s' % recipe_id)) if not recipe.installation: raise BX(_('Recipe %s not provisioned yet') % recipe_id) recipe.installation.postinstall_finished = datetime.utcnow() return True @cherrypy.expose @identity.require(identity.not_anonymous()) def install_done(self, recipe_id=None, fqdn=None): """ Report completion of installation with current FQDN """ if not recipe_id: raise BX(_("No recipe id provided!")) try: recipe = Recipe.by_id(recipe_id) except InvalidRequestError: raise BX(_("Invalid Recipe ID %s" % recipe_id)) if not recipe.installation: raise BX(_('Recipe %s not provisioned yet') % recipe_id) recipe.installation.install_finished = datetime.utcnow() # We don't want to change an existing FQDN, just set it # if it hasn't been set already (see BZ#879146) configured = recipe.resource.fqdn if configured is None and fqdn: recipe.resource.fqdn = configured = fqdn elif configured != fqdn: # We use eager formatting here to make this easier to test logger.info("Configured FQDN (%s) != reported FQDN (%s) in R:%s" % (configured, fqdn, recipe_id)) return configured @identity.require(identity.not_anonymous()) @expose() def really_return_reservation(self, id, msg=None): try: recipe = Recipe.by_id(id) except InvalidRequestError: raise BX(_("Invalid Recipe ID %s" % id)) recipe.return_reservation() flash(_(u"Successfully released reserved system for %s" % recipe.t_id)) redirect('/jobs/mine') @expose(template="bkr.server.templates.form") @identity.require(identity.not_anonymous()) def return_reservation(self, recipe_id=None): """ End recipe reservation """ if not recipe_id: raise BX(_("No recipe id provided!")) return dict( title='Release reserved system for Recipe %s' % recipe_id, form=self.return_reservation_form, action='./really_return_reservation', options={}, value=dict(id=recipe_id), ) @cherrypy.expose @identity.require(identity.not_anonymous()) def postreboot(self, recipe_id=None): # Backwards compat only, delete this after 0.10: # the recipe_id arg used to be hostname try: int(recipe_id) except ValueError: system = System.by_fqdn(recipe_id, identity.current.user) system.action_power('reboot', service=u'XMLRPC', delay=30) return system.fqdn try: recipe = Recipe.by_id(int(recipe_id)) except (InvalidRequestError, NoResultFound, ValueError): raise BX(_('Invalid recipe ID %s') % recipe_id) if isinstance(recipe.resource, SystemResource): recipe.resource.system.action_power('reboot', service=u'XMLRPC', delay=30) return True @cherrypy.expose def to_xml(self, recipe_id=None): """ Pass in recipe id and you'll get that recipe's xml """ if not recipe_id: raise BX(_("No recipe id provided!")) try: recipexml = etree.tostring(Recipe.by_id(recipe_id).to_xml(), pretty_print=True, encoding='utf8') except InvalidRequestError: raise BX(_("Invalid Recipe ID %s" % recipe_id)) return recipexml def _recipe_search(self, recipe, **kw): recipe_search = search_utility.Recipe.search(recipe) for search in kw['recipesearch']: col = search['table'] try: recipe_search.append_results(search['value'], col, search['operation'], **kw) except KeyError, e: logger.error(e) return recipe_search.return_results() return recipe_search.return_results()
r'^[^\x00-\x09\x0B-\x0C\x0E-\x1F\x21-\x2F\x3A-\x3C\x3F-\x40\x5B-\x5E\x60\x7B\x7D-\x7F]*$' )) enzyme = validators.OneOf([ "Chymotrypsin", "Chymotrypsin Low Specificity", "Trypsin", "Pepsin (ph = 1.3)", "Pepsin (ph >= 2.0)" ]) misses = validators.Int(if_empty=0, min=0, max=50) minlen = validators.Int(if_empty=0, min=0) maxlen = validators.Int(if_empty=1000000000, min=0) minweight = validators.Int(if_empty=500, min=0) maxweight = validators.Int(if_empty=1000000000, min=0) # Turbogears form creation using input fields and validation schema input_form = widgets.TableForm(fields=InputFields(), action="digest_submit", submit_text="Digest", validator=InputFieldsSchema()) class Root(controllers.RootController): """The root controller of the application.""" @expose(template="proteindigest.templates.welcome") def index(self): """"Show the welcome page.""" # log.debug("Happy TurboGears Controller Responding For Duty") return dict(form=input_form) @expose(template="proteindigest.templates.digest_submit") @expose(template="proteindigest.templates.digest_submitxml", as_format='xml', format='xml')