[twill] Twill/Flunc blocks

Ian Bicking ianb at colorstudy.com
Fri Oct 19 14:11:48 PDT 2007


Just throwing an idea out for Twill/Flunc (Flunc is our test runner that 
uses Twill).  Our basic problem: we need some higher-level constructs to 
generalize our tests.  So what if we add Tcl style strings?

For people who don't know Tcl -- probably most of you -- it has a string 
literal syntax that looks very much like a programming structure.  But 
it's actually just a string literal syntax.

When you do this in Tcl:

   proc function_name {args} {
       stuff you do, maybe with $args
   }

what it actually does is call the function "proc" and pass it the 
arguments "function_name", "args", and "\n    stuff you do, maybe with 
$args\n".  Specifically {} is just another way to quote a string -- when 
you use that kind of quoting there's no backslash quoting or 
substitution (so $args doesn't get substituted), and the {}'s are kept 
balanced.  Here's what the implementation of proc might look like:

def proc(func_name, args, body):
     if isinstance(args, basestring):
         args = args.split()
     func = ProcFunction(func_name, args, body)
     twill.namespaces.get_twill_glocals()[0][func_name] = func
     twill.parse.command_list.append(func_name)

class ProcFunction(object):
     def __init__(self, name, args, body):
         self.name = name
         self.args = args
         self.body = body
     def __repr__(self):
         return '<Twill function %s(%s)>' % (
             self.name, ', '.join(self.args))
     def __call__(self, *args):
         ns = twill.namespaces.new_local_dict()
         try:
             # Javascript style:
             ns['arguments'] = args
             if len(args) < len(self.args):
                 args = list(args) + [None]*(len(self.args)-len(args))
             for name, value in zip(self.args, args):
                 ns[name] = value
             twill.parse.execute_string(
                 self.body, source='proc %s' % self.name)
         finally:
             twill.namespaces.pop_local_dict()

There's no return values here.  Not sure what to do about that.  Twill 
just doesn't have return values generally.  Implementing all the 
fundamentals of Tcl would not actually be that hard; I think the only 
missing piece is being able to do [func args...] in an expression, which 
is similar to `command args` in a shell script.  That and some notion of 
eval in addition to just execute.

Note that I showed function definitions because they seem hardest, but 
things like a for loop, try/except, or other higher-level constructs are 
entirely possible as well.

A quick look at the twill code doesn't make this look terribly hard, but 
I'm not immediately sure how to do this in pyparsing; it's really just a 
change to how the line is lexed, but balanced characters for strings is 
not something that parsers necessarily make easy -- they all want to get 
inside the string and start parsing its innards, which exactly what we 
want to avoid here.

-- 
Ian Bicking : ianb at colorstudy.com : http://blog.ianbicking.org




More information about the twill mailing list