root/galaxy-central/eggs/twill-0.9-py2.6.egg/twill/commands.py @ 3

リビジョン 3, 22.5 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1"""
2Implementation of all of the individual 'twill' commands available through
3twill-sh.
4"""
5
6import sys
7import _mechanize_dist as mechanize
8from _mechanize_dist import ClientForm
9from _mechanize_dist._headersutil import is_html
10
11OUT=None
12ERR=sys.stderr
13
14# export:
15__all__ = ['get_browser',
16           'reset_browser',
17           'extend_with',
18           'exit',
19           'go',
20           'reload',
21           'url',
22           'code',
23           'follow',
24           'find',
25           'notfind',
26           'back',
27           'show',
28           'echo',
29           'save_html',
30           'sleep',
31           'agent',
32           'showforms',
33           'showlinks',
34           'showhistory',
35           'submit',
36           'formvalue',
37           'fv',
38           'formaction',
39           'fa',
40           'formclear',
41           'formfile',
42           'getinput',
43           'getpassword',
44           'save_cookies',
45           'load_cookies',
46           'clear_cookies',
47           'show_cookies',
48           'add_auth',
49           'run',
50           'runfile',
51           'setglobal',
52           'setlocal',
53           'debug',
54           'title',
55           'exit',
56           'config',
57           'tidy_ok',
58           'redirect_output',
59           'reset_output',
60           'redirect_error',
61           'reset_error',
62           'add_extra_header',
63           'show_extra_headers',
64           'clear_extra_headers',
65           'info'
66           ]
67
68import re, getpass, time
69
70from browser import TwillBrowser
71
72from errors import TwillException, TwillAssertionError
73import utils
74from utils import set_form_control_value, run_tidy
75from namespaces import get_twill_glocals
76       
77browser = TwillBrowser()
78
79def get_browser():
80    return browser
81
82def reset_browser():
83    """
84    >> reset_browser
85
86    Reset the browser completely.
87    """
88    global browser
89    browser._browser.close()
90    browser = TwillBrowser()
91
92    global _options
93    _options = {}
94    _options.update(_orig_options)
95
96###
97
98def exit(code="0"):
99    """
100    exit [<code>]
101
102    Exits twill, with the given exit code (defaults to 0, "no error").
103    """
104    raise SystemExit(int(code))
105
106def go(url):
107    """
108    >> go <url>
109   
110    Visit the URL given.
111    """
112    browser.go(url)
113    return browser.get_url()
114
115def reload():
116    """
117    >> reload
118   
119    Reload the current URL.
120    """
121    browser.reload()
122    return browser.get_url()
123
124def code(should_be):
125    """
126    >> code <int>
127   
128    Check to make sure the response code for the last page is as given.
129    """
130    should_be = int(should_be)
131    if browser.get_code() != int(should_be):
132        raise TwillAssertionError("code is %s != %s" % (browser.get_code(),
133                                                        should_be))
134
135def tidy_ok():
136    """
137    >> tidy_ok
138
139    Assert that 'tidy' produces no warnings or errors when run on the current
140    page.
141
142    If 'tidy' cannot be run, will fail silently (unless 'tidy_should_exist'
143    option is true; see 'config' command).
144    """
145    page = browser.get_html()
146    if page is None:
147        raise TwillAssertionError("not viewing HTML!")
148       
149    (clean_page, errors) = run_tidy(page)
150    if clean_page is None:              # tidy doesn't exist...
151        if _options.get('tidy_should_exist'):
152            raise TwillAssertionError("cannot run 'tidy'")
153    elif errors:
154        raise TwillAssertionError("tidy errors:\n====\n%s\n====\n" % (errors,))
155
156    # page is fine.
157
158def url(should_be):
159    """
160    >> url <regexp>
161
162    Check to make sure that the current URL matches the regexp.  The local
163    variable __match__ is set to the matching part of the URL.
164    """
165    regexp = re.compile(should_be)
166    current_url = browser.get_url()
167
168    m = None
169    if current_url is not None:
170        m = regexp.search(current_url)
171    else:
172        current_url = ''
173
174    if not m:
175        raise TwillAssertionError("""\
176current url is '%s';
177does not match '%s'
178""" % (current_url, should_be,))
179
180    if m.groups():
181        match_str = m.group(1)
182    else:
183        match_str = m.group(0)
184
185    global_dict, local_dict = get_twill_glocals()
186    local_dict['__match__'] = match_str
187    return match_str
188
189def follow(what):
190    """
191    >> follow <regexp>
192   
193    Find the first matching link on the page & visit it.
194    """
195    regexp = re.compile(what)
196    link = browser.find_link(regexp)
197
198    if link:
199        browser.follow_link(link)
200        return browser.get_url()
201
202    raise TwillAssertionError("no links match to '%s'" % (what,))
203
204def _parseFindFlags(flags):
205    KNOWN_FLAGS = {
206        'i': re.IGNORECASE,
207        'm': re.MULTILINE,
208        's': re.DOTALL,
209        }
210    finalFlags = 0
211    for char in flags:
212        try:
213            finalFlags |= KNOWN_FLAGS[char]
214        except IndexError:
215            raise TwillAssertionError("unknown 'find' flag %r" % char)
216    return finalFlags
217
218def find(what, flags=''):
219    """
220    >> find <regexp> [<flags>]
221   
222    Succeed if the regular expression is on the page.  Sets the local
223    variable __match__ to the matching text.
224
225    Flags is a string consisting of the following characters:
226
227    * i: ignorecase
228    * m: multiline
229    * s: dotall
230
231    For explanations of these, please see the Python re module
232    documentation.
233    """
234    regexp = re.compile(what, _parseFindFlags(flags))
235    page = browser.get_html()
236
237    m = regexp.search(page)
238    if not m:
239        raise TwillAssertionError("no match to '%s'" % (what,))
240
241    if m.groups():
242        match_str = m.group(1)
243    else:
244        match_str = m.group(0)
245
246    _, local_dict = get_twill_glocals()
247    local_dict['__match__'] = match_str
248
249def notfind(what, flags=''):
250    """
251    >> notfind <regexp> [<flags>]
252   
253    Fail if the regular expression is on the page.
254    """
255    regexp = re.compile(what, _parseFindFlags(flags))
256    page = browser.get_html()
257
258    if regexp.search(page):
259        raise TwillAssertionError("match to '%s'" % (what,))
260
261def back():
262    """
263    >> back
264   
265    Return to the previous page.
266    """
267    browser.back()
268    return browser.get_url()
269
270def show():
271    """
272    >> show
273   
274    Show the HTML for the current page.
275    """
276    html = browser.get_html()
277    print>>OUT, html
278    return html
279
280def echo(*strs):
281    """
282    >> echo <list> <of> <strings>
283   
284    Echo the arguments to the screen.
285    """
286    strs = map(str, strs)
287    s = " ".join(strs)
288    print>>OUT, s
289
290def save_html(filename=None):
291    """
292    >> save_html [<filename>]
293   
294    Save the HTML for the current page into <filename>.  If no filename
295    given, construct the filename from the URL.
296    """
297    html = browser.get_html()
298    if html is None:
299        print>>OUT, "No page to save."
300        return
301
302    if filename is None:
303        url = browser.get_url()
304        url = url.split('?')[0]
305        filename = url.split('/')[-1]
306        if filename is "":
307            filename = 'index.html'
308
309        print>>OUT, "(Using filename '%s')" % (filename,)
310
311    f = open(filename, 'w')
312    f.write(html)
313    f.close()
314
315def sleep(interval=1):
316    """
317    >> sleep [<interval>]
318
319    Sleep for the specified amount of time.
320    If no interval is given, sleep for 1 second.
321    """
322    time.sleep(float(interval))
323
324_agent_map = dict(
325    ie5='Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.1)',
326    ie55='Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.1)',
327    ie6='Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
328    moz17='Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20040616',
329    opera7='Opera/7.0 (Windows NT 5.1; U) [en]',
330    konq32='Mozilla/5.0 (compatible; Konqueror/3.2.3; Linux 2.4.14; X11; i686)',
331    saf11='Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/100 (KHTML, like Gecko) Safari/100',
332    aol9='Mozilla/4.0 (compatible; MSIE 5.5; AOL 9.0; Windows NT 5.1)',)
333
334def agent(what):
335    """
336    >> agent <agent>
337   
338    Set the agent string (identifying the browser brand).
339
340    Some convenient shortcuts:
341      ie5, ie55, ie6, moz17, opera7, konq32, saf11, aol9.
342    """
343    what = what.strip()
344    agent = _agent_map.get(what, what)
345    browser.set_agent_string(agent)
346
347def submit(submit_button=None):
348    """
349    >> submit [<buttonspec>]
350   
351    Submit the current form (the one last clicked on) by clicking on the
352    n'th submission button.  If no "buttonspec" is given, submit the current
353    form by using the last clicked submit button.
354
355    The form to submit is the last form clicked on with a 'formvalue' command.
356
357    The button used to submit is chosen based on 'buttonspec'.  If 'buttonspec'
358    is given, it's matched against buttons using the same rules that
359    'formvalue' uses.  If 'buttonspec' is not given, submit uses the last
360    submit button clicked on by 'formvalue'.  If none can be found,
361    submit submits the form with no submit button clicked.
362    """
363    browser.submit(submit_button)
364
365def showforms():
366    """
367    >> showforms
368   
369    Show all of the forms on the current page.
370    """
371    browser.showforms()
372    return browser._browser.forms()
373
374def showlinks():
375    """
376    >> showlinks
377   
378    Show all of the links on the current page.
379    """
380    browser.showlinks()
381    return browser._browser.links()
382
383def showhistory():
384    """
385    >> showhistory
386
387    Show the browser history (what URLs were visited).
388    """
389    browser.showhistory()
390    return browser._browser._history
391   
392def formclear(formname):
393    """
394    >> formclear <formname>
395   
396    Run 'clear' on all of the controls in this form.
397    """
398    form = browser.get_form(formname)
399    for control in form.controls:
400        if control.readonly:
401            continue
402
403        control.clear()
404
405def formvalue(formname, fieldname, value):
406    """
407    >> formvalue <formname> <field> <value>
408
409    Set value of a form field.
410
411    There are some ambiguities in the way formvalue deals with lists:
412    'formvalue' will *add* the given value to a list of multiple selection,
413    for lists that allow it.
414
415    Forms are matched against 'formname' as follows:
416      1. regexp match to actual form name;
417      2. if 'formname' is an integer, it's tried as an index.
418
419    Form controls are matched against 'fieldname' as follows:
420      1. unique exact match to control name;
421      2. unique regexp match to control name;
422      3. if fieldname is an integer, it's tried as an index;
423      4. unique & exact match to submit-button values.
424
425    Formvalue ignores read-only fields completely; if they're readonly,
426    nothing is done, unless the config options ('config' command) are
427    changed.
428
429    'formvalue' is available as 'fv' as well.
430    """
431    form = browser.get_form(formname)
432    if not form:
433        raise TwillAssertionError("no matching forms!")
434
435    control = browser.get_form_field(form, fieldname)
436
437    browser.clicked(form, control)
438
439    if control.readonly and _options['readonly_controls_writeable']:
440        print>>OUT, 'forcing read-only form field to writeable'
441        control.readonly = False
442       
443    if control.readonly or isinstance(control, ClientForm.IgnoreControl):
444        print>>OUT, 'form field is read-only or ignorable; nothing done.'
445        return
446
447    if isinstance(control, ClientForm.FileControl):
448        raise TwillException('form field is for file upload; use "formfile" instead')
449
450    set_form_control_value(control, value)
451
452fv = formvalue
453
454def formaction(formname, action):
455    """
456    >> formaction <formname> <action_url>
457
458    Sets action parameter on form to action_url
459    """
460    form = browser.get_form(formname)
461    form.action = action
462
463fa = formaction
464
465def formfile(formname, fieldname, filename, content_type=None):
466    """
467    >> formfile <form> <field> <filename> [ <content_type> ]
468
469    Upload a file via an "upload file" form field.
470    """
471    import os.path
472    filename = filename.replace('/', os.path.sep)
473
474    form = browser.get_form(formname)
475    control = browser.get_form_field(form, fieldname)
476
477    if not control.is_of_kind('file'):
478        raise TwillException('ERROR: field is not a file upload field!')
479
480    browser.clicked(form, control)
481    fp = open(filename, 'rb')
482    control.add_file(fp, content_type, filename)
483
484    print>>OUT, '\nAdded file "%s" to file upload field "%s"\n' % (filename,
485                                                             control.name,)
486
487def extend_with(module_name):
488    """
489    >> extend_with <module>
490   
491    Import contents of given module.
492    """
493    global_dict, local_dict = get_twill_glocals()
494
495    exec "from %s import *" % (module_name,) in global_dict
496
497    ### now add the commands into the commands available for the shell,
498    ### and print out some nice stuff about what the extension module does.
499
500    import sys
501    mod = sys.modules.get(module_name)
502
503    ###
504
505    import twill.shell, twill.parse
506   
507    fnlist = getattr(mod, '__all__', None)
508    if fnlist is None:
509        fnlist = [ fn for fn in dir(mod) if callable(getattr(mod, fn)) ]
510
511    for command in fnlist:
512        fn = getattr(mod, command)
513        twill.shell.add_command(command, fn.__doc__)
514        twill.parse.command_list.append(command)
515
516    ###
517   
518    print>>OUT, "Imported extension module '%s'." % (module_name,)
519    print>>OUT, "(at %s)\n" % (mod.__file__,)
520
521    if twill.shell.interactive:
522        if mod.__doc__:
523            print>>OUT, "Description:\n\n%s\n" % (mod.__doc__.strip(),)
524        else:
525            if fnlist:
526                print>>OUT, 'New commands:\n'
527                for name in fnlist:
528                    print>>OUT, '\t', name
529
530                print>>OUT, ''
531
532def getinput(prompt):
533    """
534    >> getinput <prompt>
535    Get input, store it in '__input__'.
536    """
537    _, local_dict = get_twill_glocals()
538
539    inp = raw_input(prompt)
540
541    local_dict['__input__'] = inp
542    return inp
543
544def getpassword(prompt):
545    """
546    >> getpassword <prompt>
547   
548    Get a password ("invisible input"), store it in '__password__'.
549    """
550    _, local_dict = get_twill_glocals()
551
552    inp = getpass.getpass(prompt)
553
554    local_dict['__password__'] = inp
555    return inp
556
557def save_cookies(filename):
558    """
559    >> save_cookies <filename>
560
561    Save all of the current cookies to the given file.
562    """
563    browser.save_cookies(filename)
564
565def load_cookies(filename):
566    """
567    >> load_cookies <filename>
568
569    Clear the cookie jar and load cookies from the given file.
570    """
571    browser.load_cookies(filename)
572
573def clear_cookies():
574    """
575    >> clear_cookies
576
577    Clear the cookie jar.
578    """
579    browser.clear_cookies()
580
581def show_cookies():
582    """
583    >> show_cookies
584
585    Show all of the cookies in the cookie jar.
586    """
587    browser.show_cookies()
588
589def add_auth(realm, uri, user, passwd):
590    """
591    >> add_auth <realm> <uri> <user> <passwd>
592
593    Add HTTP Basic Authentication information for the given realm/uri.
594    """
595    # swap around the type of HTTPPasswordMgr and
596    # HTTPPasswordMgrWithDefaultRealm depending on if with_default_realm
597    # is on or not.
598    if _options['with_default_realm']:
599        realm = None
600
601        if browser.creds.__class__ == mechanize.HTTPPasswordMgr:
602            passwds = browser.creds.passwd
603            browser.creds = mechanize.HTTPPasswordMgrWithDefaultRealm()
604            browser.creds.passwd = passwds
605            print>>OUT, 'Changed to using HTTPPasswordMgrWithDefaultRealm'
606    else:
607        if browser.creds.__class__ == mechanize.HTTPPasswordMgrWithDefaultRealm:
608            passwds = browser.creds.passwd
609            browser.creds = mechanize.HTTPPasswordMgr()
610            browser.creds.passwd = passwds
611            print>>OUT, 'Changed to using HTTPPasswordMgr'
612
613    browser.creds.add_password(realm, uri, user, passwd)
614
615    print>>OUT, "Added auth info: realm '%s' / URI '%s' / user '%s'" % (realm,
616                                                                  uri,
617                                                                  user,)
618
619def debug(what, level):
620    """
621    >> debug <what> <level>
622
623    <what> can be:
624       * http (any level >= 1), to display the HTTP transactions.
625       * commands (any level >= 1), to display the commands being executed.
626       * equiv-refresh (any level >= 1) to display HTTP-EQUIV refresh handling.
627    """
628    import parse
629
630    try:
631        level = int(level)
632    except ValueError:
633        flag = utils.make_boolean(level)
634        if flag:
635            level = 1
636        else:
637            level = 0
638
639    print>>OUT, 'DEBUG: setting %s debugging to level %d' % (what, level)
640   
641    if what == "http":
642        browser._browser.set_debug_http(level)
643    elif what == 'equiv-refresh':
644        if level:
645            utils._debug_print_refresh = True
646        else:
647            utils._debug_print_refresh = False
648    elif what == 'commands':
649        if level:
650            parse.debug_print_commands(True)
651        else:
652            parse.debug_print_commands(False)
653    else:
654        raise TwillException('unknown debugging type: "%s"' % (what,))
655
656def run(cmd):
657    """
658    >> run <command>
659
660    <command> can be any valid python command; 'exec' is used to run it.
661    """
662    # @CTB: use pyparsing to grok the command?  make sure that quoting works...
663   
664    # execute command.
665    global_dict, local_dict = get_twill_glocals()
666   
667    import commands
668
669    # set __url__
670    local_dict['__cmd__'] = cmd
671    local_dict['__url__'] = commands.browser.get_url()
672
673    exec(cmd, global_dict, local_dict)
674
675def runfile(*files):
676    """
677    >> runfile <file1> [ <file2> ... ]
678
679    """
680    import parse
681    global_dict, local_dict = get_twill_glocals()
682
683    for f in files:
684        parse.execute_file(f, no_reset=True)
685
686def setglobal(name, value):
687    """
688    setglobal <name> <value>
689
690    Sets the variable <name> to the value <value> in the global namespace.
691    """
692    global_dict, local_dict = get_twill_glocals()
693    global_dict[name] = value
694
695def setlocal(name, value):
696    """
697    setlocal <name> <value>
698
699    Sets the variable <name> to the value <value> in the local namespace.
700    """
701    global_dict, local_dict = get_twill_glocals()
702    local_dict[name] = value
703
704def title(what):
705    """
706    >> title <regexp>
707   
708    Succeed if the regular expression is in the page title.
709    """
710    regexp = re.compile(what)
711    title = browser.get_title()
712
713    print>>OUT, "title is '%s'." % (title,)
714
715    m = regexp.search(title)
716    if not m:
717        raise TwillAssertionError("title does not contain '%s'" % (what,))
718
719    if m.groups():
720        match_str = m.group(1)
721    else:
722        match_str = m.group(0)
723
724    global_dict, local_dict = get_twill_glocals()
725    local_dict['__match__'] = match_str
726    return match_str
727
728def redirect_output(filename):
729    """
730    >> redirect_output <filename>
731
732    Append all twill output to the given file.
733    """
734    import twill
735    fp = open(filename, 'a')
736    twill.set_output(fp)
737
738def reset_output():
739    """
740    >> reset_output
741
742    Reset twill output to go to the screen.
743    """
744    import twill
745    twill.set_output(None)
746
747def redirect_error(filename):
748    """
749    >> redirect_error <filename>
750
751    Append all twill error output to the given file.
752    """
753    import twill
754    fp = open(filename, 'a')
755    twill.set_errout(fp)
756
757def reset_error():
758    """
759    >> reset_error
760   
761    Reset twill error output to go to the screen.
762    """
763    import twill
764    twill.set_errout(None)
765
766def add_extra_header(header_key, header_value):
767    """
768    >> add_header <name> <value>
769
770    Add an HTTP header to each HTTP request.  See 'show_extra_headers' and
771    'clear_extra_headers'.
772    """
773    browser._browser.addheaders += [(header_key, header_value)]
774
775def show_extra_headers():
776    """
777    >> show_extra_headers
778
779    Show any extra headers being added to each HTTP request.
780    """
781    l = browser._browser.addheaders
782
783    if l:
784        print 'The following HTTP headers are added to each request:'
785   
786        for k, v in l:
787            print '  "%s" = "%s"' % (k, v,)
788           
789        print ''
790    else:
791        print '** no extra HTTP headers **'
792
793def clear_extra_headers():
794    """
795    >> clear_extra_headers
796
797    Remove all user-defined HTTP headers.  See 'add_extra_header' and
798    'show_extra_headers'.
799    """
800    browser._browser.addheaders = []
801
802### options
803
804_orig_options = dict(readonly_controls_writeable=False,
805                     use_tidy=True,
806                     require_tidy=False,
807                     use_BeautifulSoup=True,
808                     require_BeautifulSoup=False,
809                     allow_parse_errors=True,
810                     with_default_realm=False,
811                     acknowledge_equiv_refresh=True
812                     )
813
814_options = {}
815_options.update(_orig_options)           # make a copy
816
817def config(key=None, value=None):
818    """
819    >> config [<key> [<int value>]]
820
821    Configure/report various options.  If no <value> is given, report
822    the current key value; if no <key> given, report current settings.
823
824    So far:
825
826     * 'acknowledge_equiv_refresh', default 1 -- follow HTTP-EQUIV=REFRESH
827     * 'readonly_controls_writeable', default 0 -- make ro controls writeable
828     * 'require_tidy', default 0 -- *require* that tidy be installed
829     * 'use_BeautifulSoup', default 1 -- use the BeautifulSoup parser
830     * 'use_tidy', default 1 -- use tidy, if it's installed
831     * 'with_default_realm', default 0 -- use a default realm for HTTP AUTH
832
833    Deprecated:
834     * 'allow_parse_errors' has been removed.
835    """
836    import utils
837   
838    if key is None:
839        keys = _options.keys()
840        keys.sort()
841
842        print>>OUT, 'current configuration:'
843        for k in keys:
844            print>>OUT, '\t%s : %s' % (k, _options[k])
845        print>>OUT, ''
846    else:
847        v = _options.get(key)
848        if v is None:
849            print>>OUT, '*** no such configuration key', key
850            print>>OUT, 'valid keys are:', ";".join(_options.keys())
851            raise TwillException('no such configuration key: %s' % (key,))
852        elif value is None:
853            print>>OUT, ''
854            print>>OUT, 'key %s: value %s' % (key, v)
855            print>>OUT, ''
856        else:
857            value = utils.make_boolean(value)
858            _options[key] = value
859
860def info():
861    """
862    >> info
863
864    Report information on current page.
865    """
866    current_url = browser.get_url()
867    if current_url is None:
868        print "We're not on a page!"
869        return
870   
871    content_type = browser._browser._response.info().getheaders("content-type")
872    check_html = is_html(content_type, current_url)
873
874    code = browser.get_code()
875
876
877    print >>OUT, '\nPage information:'
878    print >>OUT, '\tURL:', current_url
879    print >>OUT, '\tHTTP code:', code
880    print >>OUT, '\tContent type:', content_type[0],
881    if check_html:
882        print >>OUT, '(HTML)'
883    else:
884        print ''
885    if check_html:
886        title = browser.get_title()
887        print >>OUT, '\tPage title:', title
888
889        forms = browser.get_all_forms()
890        if len(forms):
891            print >>OUT, '\tThis page contains %d form(s)' % (len(forms),)
892           
893    print >>OUT, ''
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。