summaryrefslogtreecommitdiffstats
path: root/funcweb/funcweb
diff options
context:
space:
mode:
Diffstat (limited to 'funcweb/funcweb')
-rw-r--r--funcweb/funcweb/config/app.cfg3
-rw-r--r--funcweb/funcweb/controllers.py144
-rw-r--r--funcweb/funcweb/static/css/style.css10
-rw-r--r--funcweb/funcweb/static/images/loading.gifbin0 -> 46766 bytes
-rw-r--r--funcweb/funcweb/static/javascript/ajax.js83
-rw-r--r--funcweb/funcweb/templates/master.html16
-rw-r--r--funcweb/funcweb/templates/method.html9
-rw-r--r--funcweb/funcweb/templates/method_args.html16
-rw-r--r--funcweb/funcweb/templates/minion.html5
-rw-r--r--funcweb/funcweb/templates/minions.html7
-rw-r--r--funcweb/funcweb/templates/module.html2
-rw-r--r--funcweb/funcweb/templates/run.html5
-rw-r--r--funcweb/funcweb/tests/test_widget_automation.py130
-rw-r--r--funcweb/funcweb/tests/test_widget_validation.py339
-rw-r--r--funcweb/funcweb/widget_automation.py263
-rw-r--r--funcweb/funcweb/widget_validation.py333
16 files changed, 1337 insertions, 28 deletions
diff --git a/funcweb/funcweb/config/app.cfg b/funcweb/funcweb/config/app.cfg
index e691bde..336dc84 100644
--- a/funcweb/funcweb/config/app.cfg
+++ b/funcweb/funcweb/config/app.cfg
@@ -7,7 +7,8 @@
# The commented out values below are the defaults
# VIEW
-
+#tg.include_widgets = ['turbogears.mochikit']
+tg.mochikit_all = True
# which view (template engine) to use if one is not specified in the
# template name
tg.defaultview = "genshi"
diff --git a/funcweb/funcweb/controllers.py b/funcweb/funcweb/controllers.py
index b45d81b..f2c030f 100644
--- a/funcweb/funcweb/controllers.py
+++ b/funcweb/funcweb/controllers.py
@@ -1,10 +1,35 @@
import logging
log = logging.getLogger(__name__)
-from turbogears import controllers, expose, flash, identity, redirect
+from turbogears import controllers, expose, flash, identity, redirect, error_handler,validate
from func.overlord.client import Overlord, Minions
+from funcweb.widget_automation import WidgetListFactory,RemoteFormAutomation,RemoteFormFactory
+from funcweb.widget_validation import WidgetSchemaFactory
+
+# it is assigned into method_display on every request
+global_form = None
+
+def validate_decorator_updater(validator_value=None):
+ """
+ When we pass the global_form directly to
+ turbogears.validate it is not updated on
+ every request we should pass a callable
+ to trigger it ;)
+
+ @param :validator_value : Does nothing in the code
+ of validate it is passed but is irrelevant in our case
+ because we compute the global_form in the method_display
+
+ @return : the current form and schema to validate the
+ current input in cherrypy's request
+ """
+ global global_form
+ return global_form
class Root(controllers.RootController):
+
+
+ #will be reused for widget validation
@expose(template="funcweb.templates.minions")
@identity.require(identity.not_anonymous())
@@ -16,7 +41,7 @@ class Root(controllers.RootController):
@expose(template="funcweb.templates.minion")
@identity.require(identity.not_anonymous())
- def minion(self, name, module=None, method=None):
+ def minion(self, name="*", module=None, method=None):
""" Display module or method details for a specific minion.
If only the minion name is given, it will display a list of modules
@@ -26,7 +51,18 @@ class Root(controllers.RootController):
"""
fc = Overlord(name)
if not module: # list all modules
+ #just list those who have get_method_args
modules = fc.system.list_modules()
+ display_modules = []
+ #FIXME slow really i know !
+ for module in modules.itervalues():
+ for mod in module:
+ #if it is not empty
+ if getattr(fc,mod).get_method_args()[name]:
+ display_modules.append(mod)
+ modules = {}
+ modules[name]=display_modules
+
return dict(modules=modules)
else: # a module is specified
if method: # minion.module.method specified; bring up execution form
@@ -38,13 +74,41 @@ class Root(controllers.RootController):
tg_template="funcweb.templates.module")
- @expose(template="funcweb.templates.run")
+ @expose(template="funcweb.templates.method_args")
@identity.require(identity.not_anonymous())
- def run(self, minion="*", module=None, method=None, arguments=''):
+ def method_display(self,minion=None,module=None,method=None):
+
+ global global_form
fc = Overlord(minion)
- results = getattr(getattr(fc, module), method)(*arguments.split())
- cmd = "%s.%s.%s(%s)" % (minion, module, method, arguments)
- return dict(cmd=cmd, results=results)
+ method_args = getattr(fc,module).get_method_args()
+
+ if not method_args.values():
+ print "Not registered method here"
+ return dict(minion_form = None,minion=minion,module=module,method=method)
+
+ minion_arguments = method_args[minion][method]['args']
+ if minion_arguments:
+ wlist_object = WidgetListFactory(minion_arguments,minion=minion,module=module,method=method)
+ wlist_object = wlist_object.get_widgetlist_object()
+ #create the validation parts for the remote form
+ wf = WidgetSchemaFactory(minion_arguments)
+ schema_man=wf.get_ready_schema()
+
+ #create the final form
+ minion_form = RemoteFormAutomation(wlist_object,schema_man)
+ global_form = minion_form.for_widget
+ #print global_form
+ #i use that when something goes wrong to check the problem better to stay here ;)
+ #self.minion_form =RemoteFormFactory(wlist_object,schema_man).get_remote_form()
+
+ del wlist_object
+ del minion_arguments
+
+ return dict(minion_form =minion_form,minion=minion,module=module,method=method)
+ else:
+ return dict(minion_form = None,minion=minion,module=module,method=method)
+
+
@expose(template="funcweb.templates.login")
def login(self, forward_url=None, previous_url=None, *args, **kw):
@@ -71,6 +135,72 @@ class Root(controllers.RootController):
return dict(message=msg, previous_url=previous_url, logging_in=True,
original_parameters=request.params,
forward_url=forward_url)
+
+
+ @expose()
+ @identity.require(identity.not_anonymous())
+ def handle_minion_error(self,tg_errors=None):
+ """
+ The method checks the result from turbogears.validate
+ decorator so if it has the tg_errors we know that the
+ form validation is failed. That prevents the extra traffic
+ to be sent to the minions!
+ """
+ if tg_errors:
+ #print tg_errors
+ return str(tg_errors)
+
+
+ @expose(allow_json=True)
+ @error_handler(handle_minion_error)
+ @validate(form=validate_decorator_updater)
+ @identity.require(identity.not_anonymous())
+ def post_form(self,**kw):
+ """
+ Data processing part
+ """
+ if kw.has_key('minion') and kw.has_key('module') and kw.has_key('method'):
+ #assign them because we need the rest so dont control everytime
+ #and dont make lookup everytime ...
+ minion = kw['minion']
+ del kw['minion']
+ module = kw['module']
+ del kw['module']
+ method = kw['method']
+ del kw['method']
+
+ #everytime we do that should be a clever way for that ???
+ fc = Overlord(minion)
+ #get again the method args to get their order :
+ arguments=getattr(fc,module).get_method_args()
+ #so we know the order just allocate and put them there
+ cmd_args=['']*(len(kw.keys()))
+
+ for arg in kw.keys():
+ #wow what a lookup :)
+ index_of_arg = arguments[minion][method]['args'][arg]['order']
+ cmd_args[index_of_arg]=kw[arg]
+
+ #now execute the stuff
+ result = getattr(getattr(fc,module),method)(*cmd_args)
+ return str(result)
+
+ else:
+ return "Missing arguments sorry can not proceess the form"
+
+ @expose(template="funcweb.templates.method_args")
+ @identity.require(identity.not_anonymous())
+ def execute_link(self,minion=None,module=None,method=None):
+ """
+ Method is fot those minion methods that dont accept any
+ arguments so they provide only some information,executed
+ by pressing only the link !
+ """
+ fc = Overlord(minion)
+ result = getattr(getattr(fc,module),method)()
+ return str(result)
+
+
@expose()
def logout(self):
diff --git a/funcweb/funcweb/static/css/style.css b/funcweb/funcweb/static/css/style.css
index b320cb6..703e22e 100644
--- a/funcweb/funcweb/static/css/style.css
+++ b/funcweb/funcweb/static/css/style.css
@@ -506,7 +506,7 @@ background-position:100% -24px;
/*********** My Fedora Widget stuff *************/
.col {
- margin: 5px
+ margin: 10px
padding: 0 0 2ex;
}
@@ -642,7 +642,7 @@ background-position:100% -24px;
.col {
float: left;
- margin: 5px;
+ margin: 30px;
padding: 0 0 2ex;
padding-bottom: 32767px;
margin-bottom: -32767px;
@@ -677,6 +677,10 @@ background-position:100% -24px;
}
+#col5 {
+ width: 200px;
+ margin-left: 500px;
+}
.widget-list {
/*display: table-cell;*/
}
@@ -699,6 +703,8 @@ background-position:100% -24px;
background-color: white;
}
+
+
.widget h2 {
border-width: 1px 1px 1px 1px;
font-weight: bold;
diff --git a/funcweb/funcweb/static/images/loading.gif b/funcweb/funcweb/static/images/loading.gif
new file mode 100644
index 0000000..83729ec
--- /dev/null
+++ b/funcweb/funcweb/static/images/loading.gif
Binary files differ
diff --git a/funcweb/funcweb/static/javascript/ajax.js b/funcweb/funcweb/static/javascript/ajax.js
new file mode 100644
index 0000000..7df4749
--- /dev/null
+++ b/funcweb/funcweb/static/javascript/ajax.js
@@ -0,0 +1,83 @@
+function remoteFormRequest(form, target, options) {
+ var query = Array();
+ var contents = formContents(form);
+ for (var j=0; j<contents[0].length; j++)
+ query[contents[0][j]] = contents[1][j];
+ query["tg_random"] = new Date().getTime();
+ //makePOSTRequest(form.action, target, queryString(query));
+ remoteRequest(form, form.action, target, query, options);
+ return true;
+}
+
+function remoteRequest(source, target_url, target_dom, data, options) {
+ //before
+ if (options['before']) {
+ eval(options['before']);
+ }
+ if ((!options['confirm']) || confirm(options['confirm'])) {
+ makePOSTRequest(source, target_url, getElement(target_dom), queryString(data), options);
+ //after
+ if (options['after']) {
+ eval(options['after']);
+ }
+ }
+ return true;
+}
+
+function makePOSTRequest(source, url, target, parameters, options) {
+ var http_request = false;
+ if (window.XMLHttpRequest) { // Mozilla, Safari,...
+ http_request = new XMLHttpRequest();
+ if (http_request.overrideMimeType) {
+ http_request.overrideMimeType('text/xml');
+ }
+ } else if (window.ActiveXObject) { // IE
+ try {
+ http_request = new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (e) {
+ try {
+ http_request = new ActiveXObject("Microsoft.XMLHTTP");
+ } catch (e) {}
+ }
+ }
+ if (!http_request) {
+ alert('Cannot create XMLHTTP instance');
+ return false;
+ }
+
+ var insertContents = function () {
+ if (http_request.readyState == 4) {
+ // loaded
+ if (options['loaded']) {
+ eval(options['loaded']);
+ }
+ if (http_request.status == 200) {
+ if(target) {
+ target.innerHTML = http_request.responseText;
+ }
+ //success
+ if (options['on_success']) {
+ eval(options['on_success']);
+ }
+ } else {
+ //failure
+ if (options['on_failure']) {
+ eval(options['on_failure']);
+ } else {
+ alert('There was a problem with the request. Status('+http_request.status+')');
+ }
+ }
+ //complete
+ if (options['on_complete']) {
+ eval(options['on_complete']);
+ }
+ }
+ }
+
+ http_request.onreadystatechange = insertContents;
+ http_request.open('POST', url, true);
+ http_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+ http_request.setRequestHeader("Content-length", parameters.length);
+ http_request.setRequestHeader("Connection", "close");
+ http_request.send(parameters);
+}
diff --git a/funcweb/funcweb/templates/master.html b/funcweb/funcweb/templates/master.html
index ab14ca0..073adc1 100644
--- a/funcweb/funcweb/templates/master.html
+++ b/funcweb/funcweb/templates/master.html
@@ -9,9 +9,9 @@
<title py:content="'Your Title Goes Here'"></title>
<script type="text/javascript" src="${tg.url('/static/javascript/jquery.js')}" />
-
- <link py:for="js in tg_js_head" py:strip="">${XML(js)}</link>
- <link py:for="css in tg_css" py:strip="">${XML(css)}</link>
+ <link py:for="js in tg_js_head" py:strip="">${ET(js.display())}</link>
+ <link py:for="css in tg_css" py:strip="">${ET(css.display())}</link>
+ <script type="text/javascript" src="${tg.url('/static/javascript/ajax.js')}" />
<link href="${tg.url('/static/images/favicon.ico')}"
type="image/vnd.microsoft.icon" rel="shortcut icon" />
@@ -20,10 +20,16 @@
<style type="text/css" media="screen">
@import url("/static/css/style.css");
- </style>
+ </style>
+
+ <script type="text/javascript">
+ jQuery._$ = MochiKit.DOM.getElement;
+ var myj = jQuery.noConflict();
+ </script>
+
</head>
<body py:match="body" py:attrs="select('@*')">
- <div py:for="js in tg_js_bodytop" py:replace="XML(js.display())" />
+ <div py:for="js in tg_js_bodytop" py:replace="ET(js.display())" />
<div class="wrapper">
<div class="head">
<h1><a href="http://fedorahosted.org/func">Func</a></h1>
diff --git a/funcweb/funcweb/templates/method.html b/funcweb/funcweb/templates/method.html
index 1f67ce9..af20d86 100644
--- a/funcweb/funcweb/templates/method.html
+++ b/funcweb/funcweb/templates/method.html
@@ -2,18 +2,17 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude">
+
+
<body>
<div class="method">
${minion}.${module}.${method}
-
- <form action="" method="GET" onsubmit="$('#results').hide().load('/run/${minion}/${module}/${method}/').show('slow'); return false;">
+
+ <form action="" method="GET" onsubmit="myj('#results').hide().load('/run/${minion}/${module}/${method}/').show('slow'); return false;">
<input type="text" name="arguments" id="methodargs" class="methodargs"/>
</form>
<div class="results" id="results" />
- <script type="text/javascript">
- $(document).ready($("#methodargs").focus());
- </script>
</div>
</body>
</html>
diff --git a/funcweb/funcweb/templates/method_args.html b/funcweb/funcweb/templates/method_args.html
new file mode 100644
index 0000000..2e7d4bd
--- /dev/null
+++ b/funcweb/funcweb/templates/method_args.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<body>
+ <div py:if="minion_form" id="men">
+ ${ET(minion_form.display(displays_on='genshi'))}
+ </div>
+ <div py:if="not minion_form" id="men">
+ <a href="#" onclick="myj('#results').hide().load('/execute_link/${minion}/${module}/${method}/').show('slow');">Run Method</a>
+ <div class="results" id="results" />
+ </div>
+</body>
+</html>
+
diff --git a/funcweb/funcweb/templates/minion.html b/funcweb/funcweb/templates/minion.html
index f171b00..a526764 100644
--- a/funcweb/funcweb/templates/minion.html
+++ b/funcweb/funcweb/templates/minion.html
@@ -2,12 +2,13 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude">
+
<body>
- <div id="modules" class="modules">
+ <div id="modules" class="modules">
<ul py:for="minion, mods in modules.items()">
<h2>${minion[:13]}</h2>
<li py:for="module in mods">
- <a href="#" onclick="$('#col4').hide();$('#col3').hide().load('/minion/${minion}/${module}').show('slow');">${module}</a>
+ <a href="#" onclick="myj('#col5').hide();myj('#col3').hide().load('/minion/${minion}/${module}').show('slow');">${module}</a>
</li>
</ul>
</div>
diff --git a/funcweb/funcweb/templates/minions.html b/funcweb/funcweb/templates/minions.html
index 94ccbc1..6a39f54 100644
--- a/funcweb/funcweb/templates/minions.html
+++ b/funcweb/funcweb/templates/minions.html
@@ -3,20 +3,21 @@
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="master.html"/>
-<head/>
+ <head/>
<body>
- <div class="col-group">
+ <div class="col-group">
<div class="col" id="col1">
<ul>
<li><h2>minions</h2></li>
<li py:for="minion in minions">
- <a onclick="$('#col3').hide();$('#col4').hide();$('#col2').hide().load('/minion/${minion}').show('slow');" href="#">${minion}</a>
+ <a onclick="jQuery('#col3').hide();myj('#col4').hide();myj('#col5').hide();getElement('col2').innerHTML=toHTML(IMG({src:'../static/images/loading.gif',width:'80',height:'80'}));myj('#col2').hide().load('/minion/${minion}').show('slow');" href="#">${minion}</a>
</li>
</ul>
</div>
<div class="col" id="col2" />
<div class="col" id="col3" />
<div class="col" id="col4" />
+ <div class="col" id="col5" />
</div>
</body>
</html>
diff --git a/funcweb/funcweb/templates/module.html b/funcweb/funcweb/templates/module.html
index 2d433f6..a4794d0 100644
--- a/funcweb/funcweb/templates/module.html
+++ b/funcweb/funcweb/templates/module.html
@@ -7,7 +7,7 @@
<ul py:for="minion, methods in modules.items()">
<h2>${module}</h2>
<li py:for="method in methods">
- <a href="#" onclick="$('#col4').hide().load('/minion/${minion}/${module}/${method}').show('slow')">${method}</a>
+ <a href="#" onclick="myj('#col2').hide();myj('#col5').hide().show('slow');myj('#col4').hide().load('/method_display/${minion}/${module}/${method}').show('slow')">${method}</a>
</li>
</ul>
</div>
diff --git a/funcweb/funcweb/templates/run.html b/funcweb/funcweb/templates/run.html
index cb17cdd..7ae047b 100644
--- a/funcweb/funcweb/templates/run.html
+++ b/funcweb/funcweb/templates/run.html
@@ -2,7 +2,8 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude">
-<body>
- ${results.values()[0]}
+ <body>
+
+ ${results.values()[0]}
</body>
</html>
diff --git a/funcweb/funcweb/tests/test_widget_automation.py b/funcweb/funcweb/tests/test_widget_automation.py
new file mode 100644
index 0000000..d02de93
--- /dev/null
+++ b/funcweb/funcweb/tests/test_widget_automation.py
@@ -0,0 +1,130 @@
+import unittest
+import turbogears
+from turbogears import testutil
+
+from funcweb.widget_automation import WidgetListFactory,RemoteFormAutomation,RemoteFormFactory
+from funcweb.widget_validation import WidgetSchemaFactory
+
+class TestWidgetListFactory(unittest.TestCase):
+
+ def setUp(self):
+ self.widget_factory = WidgetListFactory(self.get_test_default_args(),minion="myminion",module="mymodule",method="my_method")
+
+
+ def tearDown(self):
+ pass
+
+ def test_default_args(self):
+ compare_with = self.get_test_default_args()
+ widget_list=self.widget_factory.get_widgetlist()
+
+ #print "The widget list is like :",widget_list
+
+ for argument_name,argument_options in compare_with.iteritems():
+ assert widget_list.has_key(argument_name) == True
+ #print "The argument name is :",argument_name
+ #because some of them dont have it like boolean
+ if argument_options.has_key('default'):
+ assert argument_options['default'] == getattr(widget_list[argument_name],'default')
+
+ if argument_options.has_key("description"):
+ assert argument_options['description']==getattr(widget_list[argument_name],'help_text')
+
+ if argument_options.has_key("options"):
+ assert argument_options['options'] == getattr(widget_list[argument_name],"options")
+
+ #that should be enough
+ def test_get_widgetlist_object(self):
+ compare_with = self.get_test_default_args()
+ widget_list_object = self.widget_factory.get_widgetlist_object()
+
+ #print widget_list_object
+
+ all_fields = [getattr(field,"name") for field in widget_list_object]
+ #print all_fields
+ for argument_name in compare_with.keys():
+ print argument_name
+ assert argument_name in all_fields
+ #print getattr(widget_list_object,argument_name)
+
+
+ def test_remote_form(self):
+ schema_factory = WidgetSchemaFactory(self.get_test_default_args())
+ schema_validator=schema_factory.get_ready_schema()
+ widget_list_object = self.widget_factory.get_widgetlist_object()
+ remote_form = RemoteFormAutomation(widget_list_object,schema_validator)
+ #print remote_form
+
+ def test_remote_form_factory(self):
+ from turbogears.view import load_engines
+ load_engines()
+
+ # WidgetsList object
+ widget_list_object = self.widget_factory.get_widgetlist_object()
+ #print widget_list_object
+ remote_form = RemoteFormFactory(widget_list_object).get_remote_form()
+
+ #it is a key,value dict
+ widget_list=self.widget_factory.get_widgetlist()
+ #print widget_list
+ all_fields = [getattr(field,"name") for field in remote_form.fields]
+ #print all_fields
+ #will check if the remote form object hass all the names in it
+ for argument_name in widget_list.items():
+ argument_name in all_fields
+
+
+ #print remote_form.render()
+
+ def get_test_default_args(self):
+ return {
+ 'string_default':{
+ 'type':'string',
+ 'default':'default string',
+ 'optional':False,
+ 'description':'default description'
+ },
+ 'int_default':{
+ 'type':'int',
+ 'default':'default int',
+ 'optional':False,
+ 'description':'default description'
+ },
+ #no sense to have default
+ 'boolean_default':{
+ 'type':'boolean',
+ 'optional':False,
+ 'description':'default description'
+ },
+ 'float_default':{
+ 'type':'float',
+ 'default':'default float',
+ 'optional':False,
+ 'description':'default description'
+
+ },
+ 'hash_default':{
+ 'type':'hash',
+ 'default':'default hash',
+ 'optional':False,
+ 'description':'default description'
+
+ },
+ 'list_default':{
+ 'type':'list',
+ 'default':'default list',
+ 'optional':False,
+ 'description':'default description'
+
+ },
+ #will be converted to dropdown
+ 'special_string':{
+ 'type':'string',
+ 'default':'myfirst',
+ 'options':['myfirst','mysecond','mythird'],
+ 'optional':False,
+ 'description':'default dropdown list'
+ }
+
+ }
+
diff --git a/funcweb/funcweb/tests/test_widget_validation.py b/funcweb/funcweb/tests/test_widget_validation.py
new file mode 100644
index 0000000..c800d41
--- /dev/null
+++ b/funcweb/funcweb/tests/test_widget_validation.py
@@ -0,0 +1,339 @@
+import unittest
+import turbogears
+from turbogears import testutil
+from funcweb.widget_validation import WidgetSchemaFactory,MinionIntValidator,MinionFloatValidator,MinionListValidator,MinionHashValidator
+from turbogears import validators
+
+class TestWidgetValidator(unittest.TestCase):
+
+ def test_string_validator(self):
+ wf = WidgetSchemaFactory(self.get_string_params())
+ schema_man=wf.get_ready_schema()
+
+ conversion_schema = {
+ 'max_length':'max',
+ 'min_length':'min',
+ 'validator':'regex'
+ }
+
+ #do better test here
+ for argument_name,arg_options in self.get_string_params().iteritems():
+ #print argument_name
+ assert hasattr(schema_man,argument_name)==True
+ #not very efficient but it si just a test :)
+ if argument_name != 'string_mix':
+ for arg,value in arg_options.iteritems():
+ #print getattr(schema_man,argument_name)
+ if conversion_schema.has_key(arg):
+ if hasattr(getattr(schema_man,argument_name),conversion_schema[arg]):
+ #print arg,value
+ #couldnt find a way to test it !??
+ if arg != 'validator':
+ assert getattr(getattr(schema_man,argument_name),conversion_schema[arg])==value
+ #print getattr(getattr(schema_man,argument_name),conversion_schema[arg])
+ else:
+ #just print it to see what is inside because the test will be very hardcoded otherwise
+ #print getattr(schema_man,argument_name)
+ continue
+ print "Happy tests !"
+
+ def test_int_validator(self):
+ wf = WidgetSchemaFactory(self.get_int_params())
+ schema_man=wf.get_ready_schema()
+
+ for argument_name,arg_options in self.get_int_params().iteritems():
+ #print argument_name
+ assert hasattr(schema_man,argument_name)==True
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+
+ #if the argument includes some range
+ if arg_options.has_key('range'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert getattr(getattr(schema_man,argument_name),'max') == arg_options['range'][1]
+ assert getattr(getattr(schema_man,argument_name),'min') == arg_options['range'][0]
+ if arg_options.has_key('min'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert getattr(getattr(schema_man,argument_name),'min') == arg_options['min']
+
+ if arg_options.has_key('max'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert getattr(getattr(schema_man,argument_name),'max') == arg_options['max']
+
+ if arg_options.has_key('optional'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert not getattr(getattr(schema_man,argument_name),'not_empty') == arg_options['optional']
+
+
+ print "Happy test!"
+
+ def test_float_validator(self):
+ wf = WidgetSchemaFactory(self.get_float_params())
+ schema_man=wf.get_ready_schema()
+
+ for argument_name,arg_options in self.get_float_params().iteritems():
+ #print argument_name
+ assert hasattr(schema_man,argument_name)==True
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+
+ if arg_options.has_key('min'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert getattr(getattr(schema_man,argument_name),'min') == arg_options['min']
+
+ if arg_options.has_key('max'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert getattr(getattr(schema_man,argument_name),'max') == arg_options['max']
+
+ if arg_options.has_key('optional'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert not getattr(getattr(schema_man,argument_name),'not_empty') == arg_options['optional']
+
+
+ print "Happy test!"
+
+ def test_bool_validator(self):
+ testing_data = self.get_bool_params()
+ wf = WidgetSchemaFactory(testing_data)
+ schema_man=wf.get_ready_schema()
+
+ for argument_name,arg_options in testing_data.iteritems():
+ #print argument_name
+ #should all the argument names really
+ assert hasattr(schema_man,argument_name)==True
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+
+ if arg_options.has_key('optional'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert not getattr(getattr(schema_man,argument_name),'not_empty') == arg_options['optional']
+
+ print "Happy test!"
+
+
+
+ def test_list_validator(self,the_type='list'):
+ if the_type == 'list':
+ testing_data = self.get_list_params()
+ else:
+ testing_data = self.get_hash_params()
+
+ wf = WidgetSchemaFactory(testing_data)
+ schema_man=wf.get_ready_schema()
+
+ for argument_name,arg_options in testing_data.iteritems():
+ #print argument_name
+ #should all the argument names really
+ assert hasattr(schema_man,argument_name)==True
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+
+ if arg_options.has_key('validator'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert getattr(getattr(schema_man,argument_name),'regex_string') == arg_options['validator']
+
+ if arg_options.has_key('optional'):
+ #print " ",argument_name," : ",getattr(schema_man,argument_name)
+ assert not getattr(getattr(schema_man,argument_name),'not_empty') == arg_options['optional']
+
+
+ print "Happy test!"
+
+
+ def test_hash_validator(self):
+ self.test_list_validator(the_type = 'hash')
+
+ def test_minion_int_validator(self):
+ mv=MinionIntValidator(max = 44,min=2)
+ self.assertRaises(validators.Invalid,mv.to_python,100)
+ self.assertRaises(validators.Invalid,mv.to_python,1)
+ self.assertRaises(validators.Invalid,mv.to_python,'some_string')
+ assert mv.to_python(21) == 21
+
+ #dont use the min
+ mv=MinionIntValidator(max = 44)
+ self.assertRaises(validators.Invalid,mv.to_python,100)
+ assert mv.to_python(1)==1
+ self.assertRaises(validators.Invalid,mv.to_python,'some_string')
+ assert mv.to_python(21) == 21
+
+ mv=MinionIntValidator(min=12)
+ self.assertRaises(validators.Invalid,mv.to_python,10)
+ assert mv.to_python(14)==14
+ self.assertRaises(validators.Invalid,mv.to_python,'some_string')
+ assert mv.to_python(21) == 21
+
+ mv=MinionIntValidator()
+ assert mv.to_python(14)==14
+ self.assertRaises(validators.Invalid,mv.to_python,'some_string')
+
+ def test_minion_float_validator(self):
+ mv=MinionFloatValidator(max = 44.0,min=2.0)
+ self.assertRaises(validators.Invalid,mv.to_python,100.0)
+ self.assertRaises(validators.Invalid,mv.to_python,1.0)
+ self.assertRaises(validators.Invalid,mv.to_python,'some_string')
+ assert mv.to_python(21.0) == 21.0
+
+ #dont use the min
+ mv=MinionFloatValidator(max = 44.0)
+ self.assertRaises(validators.Invalid,mv.to_python,100.0)
+ assert mv.to_python(1.0)==1.0
+ self.assertRaises(validators.Invalid,mv.to_python,'some_string')
+ assert mv.to_python(21.0) == 21.0
+
+ mv=MinionFloatValidator(min=12.0)
+ self.assertRaises(validators.Invalid,mv.to_python,10.0)
+ assert mv.to_python(14.0)==14.0
+ self.assertRaises(validators.Invalid,mv.to_python,'some_string')
+ assert mv.to_python(21.0) == 21.0
+
+ mv=MinionFloatValidator()
+ assert mv.to_python(14.0)==14.0
+ self.assertRaises(validators.Invalid,mv.to_python,'some_string')
+
+ def test_minion_list_validator(self):
+
+ #test default
+ mv = MinionListValidator()
+ assert mv.to_python(['fedora','debian','others']) == ['fedora','debian','others']
+ del mv
+
+ #test with regex
+ mv = MinionListValidator(regex_string='^[A-Z]+$',not_empty=True)
+ assert mv.to_python(['FEDORA','MACOSX']) == ['FEDORA','MACOSX']
+ self.assertRaises(validators.Invalid,mv.to_python,[])
+ self.assertRaises(validators.Invalid,mv.to_python,['hey_error'])
+ self.assertRaises(validators.Invalid,mv.to_python,{})
+ del mv
+
+
+ print "Happy testing !"
+
+
+ def test_minion_hash_validator(self):
+
+ #test default
+ mv = MinionHashValidator()
+ assert mv.to_python({'fedora':1,'debian':2,'others':3}) == {'fedora':1,'debian':2,'others':3}
+ del mv
+
+ #test with regex
+ mv = MinionHashValidator(regex_string='^[A-Z]+$',not_empty=True)
+ assert mv.to_python({'FEDORA':'FEDORA','MACOSX':'MACOSX'}) == {'FEDORA':'FEDORA','MACOSX':'MACOSX'}
+ self.assertRaises(validators.Invalid,mv.to_python,{})
+ self.assertRaises(validators.Invalid,mv.to_python,{'hey_error':12})
+ self.assertRaises(validators.Invalid,mv.to_python,"hwy")
+ del mv
+
+ print "Happy testing !"
+
+
+ def get_string_params(self):
+ return {
+ 'string_default':{
+ 'type':'string',
+ 'default':'default string',
+ 'description':'default description'
+ },
+ 'string_regex':{
+ 'type':'string',
+ 'default':'some',
+ 'validator':'^[a-z]*$'
+ }
+ ,
+ 'min_max_string':{
+ 'type':'string',
+ 'default':'myfirst',
+ 'optional':False,
+ 'description':'default dropdown list',
+ 'max_length':12,
+ 'min_length':5
+ },
+ 'string_mix':{
+ 'type':'string',
+ 'optional':False,
+ 'max_length':123,
+ 'min_length':12,
+ 'validator':'^[A-Z]+$'
+ }
+ }
+
+ def get_int_params(self):
+ return {
+ 'int_default':{
+ 'type':'int',
+ 'default':2,
+ 'description':'default integer'
+ },
+ 'min_max':{
+ 'type':'int',
+ 'default':12,
+ 'optional':False,
+ 'description':'default dropdown list',
+ 'max':12,
+ 'min':5
+ },
+ 'range_int':{
+ 'type':'int',
+ 'optional':False,
+ 'range':[1,55]
+ }
+ }
+
+ def get_float_params(self):
+ return {
+ 'float_default':{
+ 'type':'float',
+ 'default':2.0,
+ 'description':'default float'
+ },
+ 'min_max':{
+ 'type':'float',
+ 'default':11.0,
+ 'optional':False,
+ 'description':'default dropdown list',
+ 'max':12.0,
+ 'min':5.0
+ },
+ }
+
+ def get_list_params(self):
+ return {
+ 'list_default':{
+ 'type':'list',
+ 'default':'cooler',
+ 'description':'default list'
+ },
+ 'list_regex':{
+ 'type':'list',
+ 'default':'hey',
+ 'optional':False,
+ 'description':'default regex list',
+ 'validator':'^[A-Z]$'
+ },
+ }
+
+ def get_hash_params(self):
+ return {
+ 'hash_default':{
+ 'type':'hash',
+ 'default':{'hey':12},
+ 'description':'default hash'
+ },
+ 'hash_regex':{
+ 'type':'hash',
+ 'default':{'hey':12},
+ 'optional':False,
+ 'description':'default regex hash',
+ 'validator':'^[A-Z]$'
+ },
+ }
+
+ def get_bool_params(self):
+ return {
+ 'bool_default':{
+ 'type':'boolean',
+ 'default':{'hey':12},
+ 'description':'default hash',
+ 'optional':False,
+ },
+ }
+
+
+
diff --git a/funcweb/funcweb/widget_automation.py b/funcweb/funcweb/widget_automation.py
new file mode 100644
index 0000000..5d299bd
--- /dev/null
+++ b/funcweb/funcweb/widget_automation.py
@@ -0,0 +1,263 @@
+#the purpose of that module is to make widget automation
+#for registered minion modules so we dont hace to write
+#that same boring stuff for every added module !
+
+from turbogears.widgets.base import Widget,WidgetsList
+from turbogears import widgets
+
+class WidgetListFactory(object):
+ """
+ The class is responsible for taking the method arguments
+ and converting them to the appropriate widget equivalents
+
+ Examples :
+ """
+ #which type matches for which InputWidget
+ __convert_table={
+ 'int':{
+ 'default_value':"TextField",
+ },
+ 'string':{
+ 'default_value':"TextField",
+ 'options':"SingleSelectField"},
+ 'boolean':{
+ 'default_value':"CheckBox"},
+ 'float':{
+ 'default_value':"TextField",
+ },
+ 'hash':{
+ 'default_value':"TextArea"},
+ 'list':{
+ 'default_value':"TextArea"}
+ }
+ #will contain the input widget created in that class
+
+ def __init__(self,argument_dict,minion=None,module=None,method=None):
+ """
+ Initiated with argument_dict of a method to return back
+ a WidgetsList object to be placed into a form object
+
+ @param:argument_dict : The structure we got here is like
+ {'arg1':{'type':'int'..},'arg2':{'min':111} ...}
+ """
+
+ self.__argument_dict = argument_dict
+ self.__widget_list={}
+
+ #these fields will be passed ass hidden so we need them
+ self.minion = minion
+ self.module = module
+ self.method = method
+
+ def __add_general_widget(self):
+
+ #key is the argument_name and the argument are options
+ for key,argument in self.__argument_dict.iteritems():
+ #get the type of the argument
+ current_type = argument['type']
+
+ act_special = False #if it has some special parameters
+ #it should be passed to its specialized method,if it has
+ #for example options in its key it should be shown as a
+ #SingleSelectField not a TextFiled
+
+ for type_match in self.__convert_table[current_type].keys():
+ if type_match!='default_value' and argument.has_key(type_match):
+ act_special = True
+
+ # print key,argument
+
+ if act_special:
+ #calling for example __add_specialized_string(..)
+ getattr(self,"_%s__add_specialized_%s"%(self.__class__.__name__,current_type))(argument,key)
+ else:
+ temp_object = getattr(widgets,self.__convert_table[current_type]['default_value'])()
+ #add common options to it
+ self.__add_commons_to_object(temp_object,argument,key)
+ #add a new entry to final list
+ self.__widget_list[key]=temp_object
+ #print "That have the object :",getattr(self.__widget_list[key],"default")
+ del temp_object
+
+ #print "That have the object :",getattr(self.__widget_list["list_default"],"default")
+
+ #adding the hidden fields (that part wass adde later can be made more generic)
+ if self.minion:
+ self.__widget_list['minion']= getattr(widgets,'HiddenField')(name="minion",value=self.minion,default=self.minion)
+ if self.module:
+ self.__widget_list['module']= getattr(widgets,'HiddenField')(name="module",value=self.module,default=self.module)
+ if self.method:
+ self.__widget_list['method']= getattr(widgets,'HiddenField')(name="method",value=self.method,default=self.method)
+
+
+
+ def __add_specialized_string(self,argument,argument_name):
+ """
+ Specialized option adder, called when the type:string is used
+ with option 'options' so we should create a new SingleSelectField
+ that one canno be created like others because user should supply options
+ in the constructor of the SingleSelectField so it becomes a special one
+
+ @param : argument : the argument options,
+ @param : argument_name : the name of the argument also the name of the widget
+ @return : Nothing
+ """
+
+ #allittle bit difficult to follow but that structure does
+ #temp_object = SingleSelectField() for example
+
+ temp_object = getattr(widgets,self.__convert_table[argument['type']]['options'])(options = argument['options'])
+ self.__add_commons_to_object(temp_object,argument,argument_name)
+ #add a new entry to final list
+ self.__widget_list[argument_name]=temp_object
+ del temp_object
+
+ def __add_commons_to_object(self,object,argument,argument_name):
+ """
+ As it was thought all input widgets have the same
+ common parameters they take so that method will add
+ them to instantiated object for ex (TextField) if they
+ occur into the argument ...
+
+ @param object : instantiated inputwidget object
+ @param method argument to lookup {type:'int','max':12 ...}
+ @return :None
+ """
+ #firstly set the name of the argument
+ setattr(object,"name",argument_name)
+
+ #print "The argument name is :",argument_name
+ #print "The argument options are :",argument
+
+ if argument.has_key('default'):
+ setattr(object,"default",argument["default"])
+ if argument.has_key('description'):
+ setattr(object,'help_text',argument['description'])
+
+ def get_widgetlist(self):
+ """
+ Return back a dictionay with argument_name : input_widget
+ pairs. That method may not be called directly,get_widgetlist_object
+ is better for using in web interface
+ """
+ #compute the list
+ self.__add_general_widget()
+ return self.__widget_list
+
+ def get_widgetlist_object(self):
+ """
+ Method return back the final widgetlist object
+ which is turbogears.widgets.WidgetsList
+ """
+
+ #print self.__widget_list
+ if len(self.__widget_list.keys())==0:
+ self.__add_general_widget() #not very efficient
+
+ widget_list_object = widgets.WidgetsList()
+ for name,input_widget in self.__widget_list.iteritems():
+ #it is a list indeed
+ widget_list_object.append(input_widget)
+
+ #get the object back
+ #print widget_list_object
+ return widget_list_object
+
+####################################################################################################################
+from turbogears.widgets.base import CoreWD
+from turbogears.widgets import RemoteForm
+from turbogears import validators, expose
+
+class RemoteFormAutomation(CoreWD):
+ """
+ Base class for ajaxian Form creation
+ """
+
+ name = "Ajaxian Minion Submit Form"
+
+ template = """
+ <div>
+ ${for_widget.display(action='post_form')}
+ <div id="loading"></div>
+ <div id="post_data"></div>
+ </div>
+ """
+
+ full_class_name = "funcweb.controllers.Root"
+
+ def __init__(self,generated_fields,validator_schema,*args,**kwarg):
+ """
+ The constructor part same as normal one except
+ it takes a WidgetsList object into generated_fields
+ which is generated by WidgetListFactory
+ """
+ #call the master :)
+ super(RemoteFormAutomation,self).__init__(*args,**kwarg)
+ self.for_widget = RemoteForm(
+ fields = generated_fields,
+ validator = validator_schema,
+ name = "minion_form",
+ update = "col5",
+ before='getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../static/images/loading.gif\',width:\'80\',height:\'80\'}));',
+ on_complete='getElement(\'loading\' ).innerHTML=\'Done!\';',
+ )
+
+####################################################################################################
+class RemoteFormFactory(object):
+ """
+ Gets the WidgetListFactory object
+ and return back a RemoteForm the same as above
+ just for testing
+ """
+ #some values that may want to change later
+ name = "minion_form",
+ update = "col5",
+ before='getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../static/images/loading.gif\',width:\'80\',height:\'80\'}));',
+ on_complete='getElement(\'loading\' ).innerHTML=\'Done!\';',
+ submit_text = "Send Minion Form"
+ action = "/post_form"
+
+ def __init__(self,wlist_object,validator_schema):
+ self.wlist_object = wlist_object
+ self.validator_schema = validator_schema
+
+ def get_remote_form(self):
+
+ #print self.wlist_object
+
+ return RemoteForm(
+ name = self.name,
+ fields = self.wlist_object,
+ before = self.before,
+ on_complete = self.on_complete,
+ update = self.update,
+ submit_text = self.submit_text,
+ action = self.action,
+ validator = self.validator_schema
+ )
+
+class RemoteLinkFactory(CoreWD):
+ """
+ A rpc executer for the methods without arguments
+ """
+
+ name = "Minion Remote Link Executer"
+
+ template ="""
+ <div>
+ ${for_widget.display()}
+ <div id="items">Minion Result</div>
+ </div>
+ """
+
+ def __init__(self,*args,**kwargs):
+ """The init part here"""
+ super(SomeRemoteLink,self).__init__(*args,**kwargs)
+ self.for_widget = LinkRemoteFunction(
+ name = "catexecuter",
+ action = "/catlister",
+ data = dict(give_all="all"),
+ update = "items"
+ )
+
+
diff --git a/funcweb/funcweb/widget_validation.py b/funcweb/funcweb/widget_validation.py
new file mode 100644
index 0000000..0347fa6
--- /dev/null
+++ b/funcweb/funcweb/widget_validation.py
@@ -0,0 +1,333 @@
+from turbogears import validators #the shiny validator part
+
+class WidgetSchemaFactory(object):
+ """
+ The purpose of the class is to produce a
+ validators.Schema object according to method
+ arguments that are retrieved from minions
+ """
+
+ def __init__(self,method_argument_dict):
+ """
+ @param method_argument_dict : The dict that is
+ from minion in format of {'arg':{'type':'string','options':[...]}}
+ the format is defined in func/minion/func_arg.py
+ """
+
+ self.method_argument_dict = method_argument_dict
+ self.validator_list = {} #the validator that will create final schema
+
+ def _add_validators(self):
+ """
+ Method is an entry point of factory iters over the all arguments
+ and according to their types it sends the process to more specialized
+ validator adders
+ """
+
+ for argument_name,argument_values in self.method_argument_dict.iteritems():
+ #some lazy stuff :)
+ #for ex : _add_int_validator(some_arg)
+ getattr(self,"_add_%s_validator"%(argument_values['type']))(argument_name)
+
+ def _add_boolean_validator(self,argument_name):
+ bool_data_set = {}
+
+ #the optional keyword
+ if self.method_argument_dict[argument_name].has_key('optional'):
+ if self.method_argument_dict[argument_name]['optional']:
+ bool_data_set['not_empty']=False
+ else:
+ bool_data_set['not_empty']=True
+
+
+ if bool_data_set:
+ self.validator_list[argument_name]=validators.Bool(**bool_data_set)
+ else:
+ self.validator_list[argument_name]=validators.Bool()
+
+
+
+
+ def _add_int_validator(self,argument_name):
+ """
+ Gets the options of the int type and adds a
+ new validator to validator_list
+ """
+ #the initializer for the int_validator
+ int_data_set = {}
+
+ #the optional keyword
+ if self.method_argument_dict[argument_name].has_key('optional'):
+ if self.method_argument_dict[argument_name]['optional']:
+ int_data_set['not_empty']=False
+ else:
+ int_data_set['not_empty']=True
+
+ if self.method_argument_dict[argument_name].has_key('range'):
+ #because the range is [min,max] list the 0 is min 1 is the max
+ int_data_set['min']=self.method_argument_dict[argument_name]['range'][0]
+ int_data_set['max']=self.method_argument_dict[argument_name]['range'][1]
+ if self.method_argument_dict[argument_name].has_key('min'):
+ int_data_set['min']=self.method_argument_dict[argument_name]['min']
+ if self.method_argument_dict[argument_name].has_key('max'):
+ int_data_set['max']=self.method_argument_dict[argument_name]['max']
+
+ #add the validator to the list
+ if int_data_set:
+ self.validator_list[argument_name]=MinionIntValidator(**int_data_set)
+ else:
+ self.validator_list[argument_name]=MinionIntValidator()
+
+
+
+
+ def _add_string_validator(self,argument_name):
+ """
+ Gets the options of the string type and adds a
+ new validator to validator_list
+ """
+
+ string_data_set={}
+ str_validator_list =[]
+
+ if self.method_argument_dict[argument_name].has_key('optional'):
+ if self.method_argument_dict[argument_name]['optional']:
+ string_data_set['not_empty']=False
+ else:
+ string_data_set['not_empty']=True
+
+ if self.method_argument_dict[argument_name].has_key('min_length'):
+ string_data_set['min']=self.method_argument_dict[argument_name]['min_length']
+ if self.method_argument_dict[argument_name].has_key('max_length'):
+ string_data_set['max']=self.method_argument_dict[argument_name]['max_length']
+ if self.method_argument_dict[argument_name].has_key('validator'):
+ str_validator_list.append(getattr(validators,'Regex')(self.method_argument_dict[argument_name]['validator']))
+
+ #if we have set a string_data_set
+ if string_data_set:
+ str_validator_list.append(getattr(validators,'String')(**string_data_set))
+
+ #if true it should be a validator.All thing
+ if len(str_validator_list)>1:
+ self.validator_list[argument_name]=getattr(validators,'All')(*str_validator_list)
+ elif str_validator_list:
+ self.validator_list[argument_name]=str_validator_list[0]
+ else: #if there is no option
+ self.validator_list[argument_name]=getattr(validators,'String')()
+
+
+
+
+ def _add_float_validator(self,argument_name):
+ """
+ Gets the options of the float type and adds a
+ new validator to validator_list
+ """
+
+ #the initializer for the float_validator
+ float_data_set = {}
+
+ #is it optional
+ if self.method_argument_dict[argument_name].has_key('optional'):
+ if self.method_argument_dict[argument_name]['optional']:
+ float_data_set['not_empty']=False
+ else:
+ float_data_set['not_empty']=True
+
+
+ if self.method_argument_dict[argument_name].has_key('min'):
+ float_data_set['min']=self.method_argument_dict[argument_name]['min']
+ if self.method_argument_dict[argument_name].has_key('max'):
+ float_data_set['max']=self.method_argument_dict[argument_name]['max']
+
+ #add the validator to the list
+ if float_data_set:
+ self.validator_list[argument_name]=MinionFloatValidator(**float_data_set)
+ else:
+ self.validator_list[argument_name]=MinionFloatValidator()
+
+
+
+ def _add_list_validator(self,argument_name,the_type='list'):
+ """
+ Gets the options of the list type and adds a
+ new validator to validator_list
+ """
+ list_data_set = {}
+
+ #is it optional
+ if self.method_argument_dict[argument_name].has_key('optional'):
+ if self.method_argument_dict[argument_name]['optional']:
+ list_data_set['not_empty']=False
+ else:
+ list_data_set['not_empty']=True
+
+ if self.method_argument_dict[argument_name].has_key('validator'):
+ list_data_set['regex_string'] = self.method_argument_dict[argument_name]['validator']
+
+ if list_data_set:
+ if the_type == 'list':
+ self.validator_list[argument_name]=MinionListValidator(**list_data_set)
+ else:
+ self.validator_list[argument_name]=MinionHashValidator(**list_data_set)
+
+ else:
+ if the_type == 'list':
+ self.validator_list[argument_name]=MinionListValidator()
+ else:
+ self.validator_list[argument_name]=MinionHashValidator()
+
+
+
+ def _add_hash_validator(self,argument_name):
+ """
+ Gets the options of the hash type and adds a
+ new validator to validator_list
+ """
+ self._add_list_validator(argument_name,the_type = 'hash')
+
+
+ def get_ready_schema(self):
+ """
+ Get the final validator schema
+ """
+ final_schema = validators.Schema()
+ if not self.validator_list:
+ self._add_validators()
+
+ for vd_name,vd in self.validator_list.iteritems():
+ #setattr(final_schema,vd_name,vd)
+ getattr(final_schema,'fields')[vd_name]= vd
+
+ return final_schema
+
+########################################################################
+class MinionIntValidator(validators.FancyValidator):
+
+ """
+ Confirms that the input/output is of the proper type of int.
+
+ """
+ #automatically will be assigned
+ min = None
+ max = None
+
+ def _to_python(self,value,state):
+ """
+ Will check just the type here and return
+ value to be validated in validate_python
+ """
+ try:
+ value = int(value)
+ except (ValueError, TypeError):
+ raise validators.Invalid('The field should be integer',value,state)
+
+ return int(value)
+
+
+ def validate_python(self,value,state):
+ """
+ The actual validator
+ """
+ #firstly run the supers one
+ if self.min and self.min:
+ if value < self.min:
+ raise validators.Invalid('The number you entered should be bigger that %d'%(self.min),value,state)
+
+ if self.max and self.max:
+ if value > self.max:
+ raise validators.Invalid('The number you entered exceeds the %d'%(self.max),value,state)
+
+
+##################################################################
+class MinionFloatValidator(MinionIntValidator):
+
+ def _to_python(self,value,state):
+ """
+ Will check just the type here and return
+ value to be validated in validate_python
+ """
+ try:
+ value = float(value)
+ except (ValueError, TypeError):
+ raise validators.Invalid('The field should be a float',value,state)
+
+ return float(value)
+
+#################################################################
+class MinionListValidator(validators.FancyValidator):
+
+ regex_string = None
+
+ def _to_python(self,value,state):
+ """
+ Will check just the type here and return
+ value to be validated in validate_python
+ """
+ #will add more beautiful validation here after
+ #integrate the complex widgets for lists and dicts
+ if self.not_empty:
+ if len(value)==0:
+ raise validators.Invalid('Empty list passed when not_empty is set',value,state)
+
+
+ tmp = []
+ if type(tmp) != type(value):
+ value = list(value)
+ value = [list_value.strip() for list_value in value]
+
+ return value
+
+ def validate_python(self,value,state):
+ import re
+ if self.regex_string:
+ try:
+ compiled_regex = re.compile(self.regex_string)
+ except Exception,e:
+ raise validators.Invalid('The passed regex_string is not a valid expression'%self.regex_string,value,state)
+
+ for list_value in value:
+ if not re.match(compiled_regex,str(list_value)):
+ raise validators.Invalid('The %s doesnt match to the regex expression that was supplied'%list_value,value,state)
+
+ #there is no else for now :)
+
+class MinionHashValidator(validators.FancyValidator):
+
+ regex_string = None
+
+ def _to_python(self,value,state):
+ """
+ Will check just the type here and return
+ value to be validated in validate_python
+ """
+ #will add more beautiful validation here after
+ #integrate the complex widgets for lists and dicts
+ if self.not_empty:
+ if len(value)==0:
+ raise validators.Invalid('Empty hash passed when not_empty is set',value,state)
+
+ #check the type firstly
+ tmp = {}
+ if type(tmp) != type(value):
+ raise validators.Invalid('The value passed to MinionHashValidator should be a dict object',value,state)
+
+ #print value
+ return value
+
+ def validate_python(self,value,state):
+ #print value
+ import re
+ if self.regex_string:
+ try:
+ compiled_regex = re.compile(self.regex_string)
+ except Exception,e:
+ raise validators.Invalid('The passed regex_string is not a valid expression'%self.regex_string,value,state)
+ for dict_value in value.itervalues():
+ if not re.match(compiled_regex,str(dict_value)):
+ raise validators.Invalid('The %s doesnt match to the regex expression that was supplied'%dict_value,value,state)
+
+
+
+if __name__ == "__main__":
+ pass