Commits

takanao ENDOH committed 0edb085

Initial import.

Comments (0)

Files changed (10)

+tags
+
+syntax: glob
+*.pyc
+*.swp
+*.tmp
+.DS_Store
+
+syntax: regexp
+(.*/)?(.*\.)?db$
+
+Copyright (c) 2009, the Shell Doctest Team All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the contributors nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+Shell Doctest module.
+
+:Copyright: (c) 2009, the Shell Doctest Team All rights reserved.
+:license: BSD, see LICENSE for more details.
+"""
+
+from distutils.core import setup
+
+if __name__ == "__main__":
+    setup(
+        name='shelldoctest',
+        version='0.1a',
+        author='Takanao ENDOH',
+        author_email='endoh@accense.com',
+        maintainer='Takanao ENDOH',
+        maintainer_email='djmchl@gmail.com',
+        url='http://code.google.com/p/shell-doctest/',
+        description='doctest for shell',
+        download_url='http://code.google.com/p/shell-doctest/',
+        install_requires=[
+            'commandlineapp',
+        ],
+        classifiers=[
+            'Development Status :: 3 - Alpha',
+            'Environment :: Console',
+            'Intended Audience :: Developers',
+            'Intended Audience :: System Administrators',
+            'License :: OSI Approved :: BSD License',
+            'Operating System :: POSIX',
+            'Operating System :: Unix',
+            'Programming Language :: Unix Shell',
+            'Topic :: Software Development :: Testing',
+        ],
+        platforms='Any',
+        license='License :: New BSD License',
+        packages=['shelldoctest'],
+        scripts=['shell-doctest'],
+    )
+
+#!/usr/bin/env python
+"""
+Shell Doctest module.
+
+:Copyright: (c) 2009, the Shell Doctest Team All rights reserved.
+:license: BSD, see LICENSE for more details.
+"""
+
+import fnmatch
+import os.path
+import sys
+
+import shelldoctest
+
+def _get_file_lists(target_paths):
+    exists = list()
+    no_exists = list()
+    for path in target_paths:
+        #path = os.path.abspath(path)
+        if not os.path.exists(path):
+            no_exists.append(path)
+        elif os.path.isfile(path):
+            exists.append(path)
+        else:
+            for i in os.walk(path):
+                if not i:
+                    continue
+                parent, dirs, files = i
+                for f in files:
+                    exists.append(os.path.sep.join([parent, f]))
+    return exists, no_exists
+
+def test(self, *argv):
+    if not argv:
+        argv = ["."]
+    file_lists, labels = _get_file_lists(argv)
+    if not file_lists:
+        file_lists, _labels = _get_file_lists(["."])
+    for f in file_lists:
+        if not fnmatch.fnmatch(f, "*.py"):
+            continue
+        if f.startswith("./"):
+            f = f[2:]
+        mod_name = os.path.splitext(f)[0].replace(os.path.sep, ".")
+        try:
+            mod = __import__(mod_name, globals(), locals(), [], -1)
+        except ImportError, e:
+            self.status_message("%(mod_name)s:ImportError, %(e)s" % vars(), verbose_level=2)
+            continue
+        else:
+            if "." in mod_name:
+                mod = sys.modules[mod_name]
+            self.status_message("Module:%(f)s" % vars(), verbose_level=2)
+            shelldoctest.testmod(mod, verbose=self.verbose_level>2,
+                                    verbose_level=self.verbose_level, filters=labels)
+
+if __name__ == "__main__":
+    from shelldoctest import base_app
+    base_app.start_app(**vars())
+

shelldoctest/__init__.py

+"""
+Shell Doctest module.
+
+:Copyright: (c) 2009, the Shell Doctest Team All rights reserved.
+:license: BSD, see LICENSE for more details.
+"""
+
+from shelldoctest import *

shelldoctest/base_app.py

+#!/usr/bin/env python
+'''
+Shell Doctest module.
+
+:Copyright: (c) 2009, the Shell Doctest Team All rights reserved.
+:license: BSD, see LICENSE for more details.
+
+def _print(arg):
+    print(arg)
+
+def test():
+    """Print `TEST`
+    """
+    _print("TEST")
+
+def echo(msg=None):
+    """Print <message>, Default `None`
+    """
+    _print(msg)
+
+if __name__ == "__main__":
+    import base_app
+    base_app.start_app(**vars())
+'''
+
+import commands
+import inspect
+import sys
+
+from commandlineapp import CommandLineApp
+
+class BaseApp(CommandLineApp):
+    def __init__(self, *argv, **kwargv):
+        if sys.argv[0].endswith('ipython'):
+            sys.argv = sys.argv[1:]
+            self._app_name = sys.argv[0]
+            kwargv.update({'command_line_options': sys.argv[1:]})
+        super(BaseApp, self).__init__(*argv, **kwargv)
+
+    def main(self, *argv):
+        sub_command = dict(enumerate(argv)).get(0, "main")
+        try:
+            getattr(self, "command_%(sub_command)s" % vars())(*(argv[1:]))
+        except AttributeError:
+            if self.debugging:
+                raise
+            print "ERROR:  sub-command %(sub_command)s not recognized" % vars()
+            self.command_help()
+        sys.exit(0)
+
+    def command_help(self):
+        """Displays sub-command help message.
+        """
+        prefix = "command_"
+        methods = inspect.getmembers(self.__class__, inspect.ismethod)
+        print "%s [<options>] sub-command [argv...]\n" % self._app_name
+        print "SUB-COMMANDS:\n"
+        for method_name, method in methods:
+            if method_name.startswith(prefix):
+                print " "*4, method_name[len(prefix):],
+                for arg in method.im_func.func_code.co_varnames[1:method.im_func.func_code.co_argcount]:
+                    if not arg.startswith("_"):
+                        format = "<%s>"
+                        if method.im_func.func_defaults and method.im_func.func_defaults[0]:
+                            format = "[<%s=%s>]" % ("%s", method.im_func.func_defaults[0])
+                        print format % arg,
+                else:
+                    print ""
+                print " "*8, method.__doc__ or ""
+
+    def command_main(self):
+        raise NotImplementedError
+
+    def option_handler_help(self):
+        super(BaseApp, self).option_handler_help()
+        self.command_help()
+
+    def run(self):
+        try:
+            super(BaseApp, self).run()
+        except SystemExit, e:
+            if str(e) not in ["", "0"]: raise
+
+def create_method(attribute):
+    def method(self, *argv, **kwargv):
+        if attribute.func_code.co_varnames[0] == 'self':
+            argv = (self,) + argv
+        return attribute(*argv, **kwargv)
+    method.__name__ = "command_%s" % attribute.__name__
+    method.__doc__ = attribute.__doc__
+    return method
+
+def set_method(cls, attribute):
+    method = create_method(attribute)
+    setattr(cls, method.__name__, method)
+    return cls
+
+def update_app(app, *attributes):
+    for attribute in attributes:
+        app = set_method(app, attribute)
+    return app
+
+def create_app(*attributes):
+    attr_dict = dict((m.__name__, m) for m in map(create_method, attributes))
+    return type('App', (BaseApp,), attr_dict)
+
+def start_app(*attributes, **vars):
+    app = create_app(*attributes)
+    for k,v in vars.items():
+        try:
+            if v.__module__ == "__main__" and not k.startswith("_"):
+                v.__name__ = k
+                app = update_app(app, v)
+        except AttributeError:
+            pass
+    if "main" not in [a.__name__ for a in attributes] + vars.keys():
+        app.command_main = app.command_help
+    app().run()
+
+if __name__ == "__main__":
+    BaseApp().run()
+

shelldoctest/shelldoctest.py

+#!/usr/bin/env python
+"""
+Shell Doctest module.
+
+:Copyright: (c) 2009, the Shell Doctest Team All rights reserved.
+:license: BSD, see LICENSE for more details.
+"""
+
+import commands
+import doctest
+import inspect
+import re
+import sys
+
+master = None
+_EXC_WRAPPER = 'system_command("%s")'
+
+def system_command(cmd, shell="bash"):
+    status, output = commands.getstatusoutput('%(shell)s -c "%(cmd)s"' % vars())
+    if status == 0:
+        format = "%(output)s"
+    else:
+        format = "[%(status)d]%(output)s"
+    result = format % vars()
+    if sys.version_info < (2, 5):
+        print result
+        return
+    print(result)
+
+class ShellExample(doctest.Example):
+    def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
+                     label=None,
+                     options=None):
+        doctest.Example.__init__(self, source, want, exc_msg=None, lineno=0, indent=0,
+                     options=None)
+        self.label = label
+
+class ShellDocTestParser(doctest.DocTestParser):
+    _PROMPT = "$"
+    _EXC_WRAPPER = _EXC_WRAPPER
+    _EXAMPLE_RE = re.compile(r'''
+        # Source consists of a PS1 line followed by zero or more PS2 lines.
+        (?P<source>
+            (?:^  (?P<indent> [ ]*))                   # PS0 line: indent
+            (?:   \[(?P<label>.+)\]\n)?                # PS0 line: label
+            (?:   (?P<user>[\w]*)@(?P<host>[\w-]*)\n)? # PS0 line: user@host
+            (?:   [ ]* \$ .*)                          # PS1 line
+            (?:\n [ ]* \. .*)*)                        # PS2 lines
+        \n?
+        # Want consists of any non-blank lines that do not start with PS1.
+        (?P<want> (?:(?![ ]*$)    # Not a blank line
+                     (?![ ]*\$)   # Not a line starting with PS1
+                     .*$\n?       # But any other line
+                  )*)
+        ''', re.MULTILINE | re.VERBOSE)
+
+    def parse(self, string, name='<string>'):
+        string = string.expandtabs()
+        min_indent = self._min_indent(string)
+        if min_indent > 0:
+            string = '\n'.join([l[min_indent:] for l in string.split('\n')])
+        output = []
+        charno, lineno = 0, 0
+        for m in self._EXAMPLE_RE.finditer(string):
+            output.append(string[charno:m.start()])
+            lineno += string.count('\n', charno, m.start())
+            (source, options, want, exc_msg) = \
+                     self._parse_example(m, name, lineno)
+            if not self._IS_BLANK_OR_COMMENT(source):
+                source = source.replace("\n","; ")
+                user = m.group('user')
+                host = m.group('host')
+                if host:
+                    if user:
+                        cmd_base = "ssh %(user)s@%(host)s '%(source)s'"
+                    else:
+                        cmd_base = "ssh %(host)s '%(source)s'"
+                    source = cmd_base % vars()
+                output.append( ShellExample(self._EXC_WRAPPER % source.replace("\n","; "),
+                                    want, exc_msg, lineno=lineno,
+                                    label=m.group('label'),
+                                    indent=min_indent+len(m.group('indent')),
+                                    options=options) )
+            lineno += string.count('\n', m.start(), m.end())
+            charno = m.end()
+        output.append(string[charno:])
+        return output
+
+    def _parse_example(self, m, name, lineno):
+        indent = len(m.group('indent'))
+        source_lines = [sl for sl in m.group('source').split('\n') if sl.strip()[1] == " "]
+        self._check_prompt_blank(source_lines, indent, name, lineno)
+        self._check_prefix(source_lines[1:], ' '*indent + '.', name, lineno)
+        source = '\n'.join([sl[indent+len(self._PROMPT)+1:] for sl in source_lines])
+        want = m.group('want')
+        want_lines = want.split('\n')
+        if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
+            del want_lines[-1]
+        self._check_prefix(want_lines, ' '*indent, name,
+                           lineno + len(source_lines))
+        want = '\n'.join([wl[indent:] for wl in want_lines])
+        m = self._EXCEPTION_RE.match(want)
+        if m:
+            exc_msg = m.group('msg')
+        else:
+            exc_msg = None
+        options = self._find_options(source, name, lineno)
+        return source, options, want, exc_msg
+
+    def _check_prompt_blank(self, lines, indent, name, lineno):
+        for i, line in enumerate(lines):
+            if len(line) >= indent+len(self._PROMPT)+1 and line[indent+len(self._PROMPT)] != ' ':
+                raise ValueError('line %r of the docstring for %s '
+                                 'lacks blank after %s: %r' %
+                                 (lineno+i+1, name,
+                                  line[indent:indent+len(self._PROMPT)], line))
+
+class ShellDocTestRunner(doctest.DocTestRunner):
+    _EXC_WRAPPER = _EXC_WRAPPER
+    _BEFORE, _AFTER = [len(i) for i in _EXC_WRAPPER.split("%s")]
+
+    def __init__(self, checker=None, verbose=None, verbose_level=None, optionflags=0):
+        doctest.DocTestRunner.__init__(self, checker=checker, verbose=verbose, optionflags=optionflags)
+        self._verbose_level = verbose_level
+
+    def report_start(self, out, test, example):
+        source = example.source[self._BEFORE:-(self._AFTER+1)] + "\n"
+        if self._verbose_level > 1:
+            out('Label:%s\n' % example.label)
+        if self._verbose:
+            if example.want:
+                out('Trying:\n' + doctest._indent(source) +
+                    'Expecting:\n' + doctest._indent(example.want))
+            else:
+                out('Trying:\n' + doctest._indent(source) +
+                    'Expecting nothing\n')
+
+    def _failure_header(self, test, example):
+        out = [self.DIVIDER]
+        if test.filename:
+            if test.lineno is not None and example.lineno is not None:
+                lineno = test.lineno + example.lineno + 1
+            else:
+                lineno = '?'
+            out.append('File "%s", line %s, in %s' %
+                       (test.filename, lineno, test.name))
+        else:
+            out.append('Line %s, in %s' % (example.lineno+1, test.name))
+        out.append('Failed example:')
+        source = example.source[self._BEFORE:-(self._AFTER+1)] + "\n"
+        out.append(doctest._indent(source))
+        return '\n'.join(out)
+
+def testmod(m=None, name=None, globs=None, verbose=None,
+            report=True, optionflags=doctest.ELLIPSIS, extraglobs=None,
+            raise_on_error=False, exclude_empty=False,
+            verbose_level=None, filters=None,
+            ):
+    if globs == None:
+        globs = dict()
+    globs.update({"system_command": system_command})
+    global master
+    if m is None:
+        m = sys.modules.get('__main__')
+    if not inspect.ismodule(m):
+        raise TypeError("testmod: module required; %r" % (m,))
+    if name is None:
+        name = m.__name__
+    finder = doctest.DocTestFinder(parser=ShellDocTestParser(), exclude_empty=exclude_empty)
+    if raise_on_error:
+        runner = doctest.DebugRunner(verbose=verbose, optionflags=optionflags)
+    else:
+        runner = ShellDocTestRunner(verbose=verbose, verbose_level=verbose_level, optionflags=optionflags)
+    tests = finder.find(m, name, globs=globs, extraglobs=extraglobs)
+    if filters:
+        _tests = list()
+        z = dict([(k,v) for v,k in enumerate(filters)])
+        for test in tests:
+            test.examples = sorted(filter(lambda x: x.label in filters, test.examples),
+                                cmp=lambda x,y: cmp(z[x.label], z[y.label]))
+            _tests.append(test)
+        tests = _tests
+    for test in tests:
+        runner.run(test)
+    if report:
+        runner.summarize()
+    if master is None:
+        master = runner
+    else:
+        master.merge(runner)
+    if sys.version_info < (2, 6):
+        return runner.failures, runner.tries
+    return doctest.TestResults(runner.failures, runner.tries)
+
+if __name__ == "__main__":
+    testmod()
+
+"""
+Shell Doctest module.
+
+:Copyright: (c) 2009, the Shell Doctest Team All rights reserved.
+:license: BSD, see LICENSE for more details.
+"""
+"""
+Shell Doctest module.
+
+:Copyright: (c) 2009, the Shell Doctest Team All rights reserved.
+:license: BSD, see LICENSE for more details.
+
+$ echo TEST
+TEST
+
+[#1]
+$ echo TEST1
+TEST1
+
+[#2]
+$ echo TEST2
+TEST2
+"""
+"""
+Shell Doctest module.
+
+:Copyright: (c) 2009, the Shell Doctest Team All rights reserved.
+:license: BSD, see LICENSE for more details.
+
+$ echo TEST
+TEST
+
+[#1]
+$ LANG=C date -r 0 -u
+. date
+Thu Jan  1 00:00:00 UTC 1970
+...
+
+[#2]
+$ LANG=C $
+[...]bash: $: command not found
+
+[#3]
+$ exit 1
+[256]
+
+[#4]
+@localhost
+$ hostname
+. whoami
+. exit 1
+[256]<HOSTNAME>
+<USERNAME>
+
+[#5]
+root@localhost
+$ REMOTE COMMAND
+[...]Received disconnect from ::1: 2: Too many authentication failures for root
+"""