Merged upstream
authorDmitriy Morozov <dmitriy@mrzv.org>
Fri, 03 Dec 2010 11:53:57 -0800
changeset 144 c66e1ada4c08
parent 132 b072cb473b47 (current diff)
parent 143 2327cc333e50 (diff)
child 182 f8a82de0540d
Merged upstream
opster.py
--- a/.hgtags	Sat Nov 06 12:14:40 2010 -0700
+++ b/.hgtags	Fri Dec 03 11:53:57 2010 -0800
@@ -11,3 +11,4 @@
 95653a562a05f97e1a969d916d805bc6cf8a8b9b 0.9.10
 bf6908d12aae4a54ac584df5a6f97f84157030d6 0.9.11
 8d3e644647f8b0ebf4c215352f39ad48bf5c5c4c 0.9.12
+e21e182229c16059d00d9b79158ba1f3dd6b70ef 0.9.13
--- a/README	Sat Nov 06 12:14:40 2010 -0700
+++ b/README	Fri Dec 03 11:53:57 2010 -0800
@@ -20,10 +20,10 @@
 
   @command(usage='%name [-n] MESSAGE')
   def main(message,
-           nonewline=('n', False, 'don\'t print a newline')):
+           no_newline=('n', False, 'don\'t print a newline')):
       'Simple echo program'
       sys.stdout.write(message)
-      if not nonewline:
+      if not no_newline:
           sys.stdout.write('\n')
 
   if __name__ == '__main__':
@@ -37,13 +37,20 @@
 
   options:
 
-   -n --nonewline  don't print a newline
-   -h --help       show help
+   -n --no-newline  don't print a newline
+   -h --help        show help
 
-I think this mostly describes what's going on, except that I'd like to mention
-one interesting feature - if you are using long name for option, you can use
-only partial name, for example ``./echo.py --nonew`` a is valid command
-line. This is also true for subcommands: read about that and everything else
-you'd like to know in `documentation`_.
+As you can see, here we have defined option to not print newline: keyword
+argument name is a long name for option, default value is a 3-tuple, containing
+short name for an option (can be empty), default value (on base of which
+processing is applied - `see description`_) and a help string.
+
+Underscores in long names are converted into dashes.
+
+If you are calling a command with option using long name, you can supply it
+partially. In this case it could look like ``./echo.py --nonew``. This is also
+true for subcommands: read about them and everything else you'd like to know in
+`documentation`_.
 
 .. _documentation: http://hg.piranha.org.ua/opster/docs/
+.. _see description: http://hg.piranha.org.ua/opster/docs/overview.html#options-processing
--- a/contrib/PKGBUILD	Sat Nov 06 12:14:40 2010 -0700
+++ b/contrib/PKGBUILD	Fri Dec 03 11:53:57 2010 -0800
@@ -1,18 +1,19 @@
 # Maintainer: Andrey Vlasovskikh <andrey.vlasovskikh@gmail.com>
 
 pkgname=python-opster
-pkgver=0.9.11
-pkgrel=3
+pkgver=0.9.13
+pkgrel=1
 pkgdesc="Python command line parsing speedster"
 arch=(any)
 url="http://hg.piranha.org.ua/opster/"
 license=('BSD')
 depends=('python2')
 source=("http://pypi.python.org/packages/source/o/opster/opster-$pkgver.tar.gz")
-md5sums=('24b2349fa3930eb17e28e6fc7cf78575')
+md5sums=('462b102563886fc9dda9719470549c9e')
 
 build() {
     cd "$srcdir/opster-$pkgver"
     python2 setup.py build || return 1
     python2 setup.py install --root=$pkgdir --optimize=1 || return 1
 }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/_static/custom.css	Fri Dec 03 11:53:57 2010 -0800
@@ -0,0 +1,3 @@
+@import url("default.css");
+
+body { max-width: 70em; margin: 0 auto; }
--- a/docs/changelog.rst	Sat Nov 06 12:14:40 2010 -0700
+++ b/docs/changelog.rst	Fri Dec 03 11:53:57 2010 -0800
@@ -1,6 +1,12 @@
 Changelog
 ---------
 
+0.9.13
+~~~~~~
+
+ - fixed exception handling (cleanup previous fix, actually)
+ - display only name of application, without full path
+
 0.9.12
 ~~~~~~
 
--- a/docs/conf.py	Sat Nov 06 12:14:40 2010 -0700
+++ b/docs/conf.py	Fri Dec 03 11:53:57 2010 -0800
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 
-import sys, os
-sys.path.append('..')
+import sys
+sys.path.insert(0, '..')
 import opster
 
 # -- General configuration -----------------------------------------------------
@@ -11,7 +11,7 @@
 source_suffix = '.rst'
 master_doc = 'index'
 project = u'Opster'
-copyright = u'2009, Alexander Solovyov'
+copyright = u'2009-2010, Alexander Solovyov'
 version = release = opster.__version__
 exclude_trees = ['_build']
 pygments_style = 'sphinx'
@@ -20,21 +20,9 @@
 # -- Options for HTML output ---------------------------------------------------
 
 html_theme = 'default'
-# "<project> v<release> documentation".
-#html_title = None
-# A shorter title for the navigation bar.  Default is the same as html_title.
-#html_short_title = None
-
-#html_logo = None
-#html_favicon = None
+html_style = 'custom.css'
+html_title = "%s v%s" % (project, version)
 html_static_path = ['_static']
 html_use_smartypants = True
-htmlhelp_basename = 'Opsterdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_documents = [
-  ('index', 'Opster.tex', u'Opster Documentation',
-   u'Alexander Solovyov', 'manual'),
-]
+html_use_index = False
+html_show_sourcelink = False
--- a/docs/overview.rst	Sat Nov 06 12:14:40 2010 -0700
+++ b/docs/overview.rst	Fri Dec 03 11:53:57 2010 -0800
@@ -1,6 +1,6 @@
-===================
+==============
  Opster usage
-===================
+==============
 
 Options
 -------
@@ -12,6 +12,9 @@
           ('d', 'daemonize', False, 'daemonize process'),
           ('', 'pid-file', '', 'name of file to write process ID to')]
 
+Options contents
+^^^^^^^^^^^^^^^^
+
 Each tuple is a definition of some option, consisting of 4 elements:
 
  1. short name
@@ -20,14 +23,21 @@
  4. help string
 
 If a short name renders to False (for example, empty string), then it's not used
-at all. Long name is pretended to be available in any case. Default value also
-determines how supplied argument should be parsed:
+at all. Long name is pretended to be available in any case.
+
+Options processing
+^^^^^^^^^^^^^^^^^^
+
+Default value also determines how supplied argument should be parsed:
 
  - function: return value of function called with a specified value is passed
  - integer: value is convert to integer
  - string: value is passed as is
  - list: value is appended to this list
- - boolean/None: ``not default`` is passed and option takes no argument
+ - boolean/None: ``not default`` is passed and option takes no value
+
+Usage
+^^^^^
 
 Usage is easy like that::
 
--- a/opster.py	Sat Nov 06 12:14:40 2010 -0700
+++ b/opster.py	Fri Dec 03 11:53:57 2010 -0800
@@ -6,7 +6,7 @@
 from itertools import imap
 
 __all__ = ['command', 'dispatch']
-__version__ = '0.9.12'
+__version__ = '0.9.13'
 __author__ = 'Alexander Solovyov'
 __email__ = 'piranha@piranha.org.ua'
 
@@ -87,12 +87,19 @@
                 # no catcher here because this is call from Python
                 return call_cmd_regular(func, options_)(*args, **opts)
 
-            opts, args = catcher(lambda: parse(argv, options_), help_func)
+            try:
+                opts, args = catcher(lambda: parse(argv, options_), help_func)
+            except Abort:
+                return -1
 
             if opts.pop('help', False):
                 return help_func()
-            return catcher(lambda: call_cmd(name_, func)(*args, **opts),
-                           help_func)
+
+            try:
+                return catcher(lambda: call_cmd(name_, func)(*args, **opts),
+                               help_func)
+            except Abort:
+                return -1
 
         return inner
     return wrapper
@@ -132,17 +139,22 @@
 
     autocomplete(cmdtable, args, middleware)
 
-    name, func, args, kwargs = catcher(
-        lambda: _dispatch(args, cmdtable, globaloptions),
-        help_func)
+    try:
+        name, func, args, kwargs = catcher(
+            lambda: _dispatch(args, cmdtable, globaloptions),
+            help_func)
+    except Abort:
+        return -1
+
     if name == '_completion':       # skip middleware
-        return catcher(
-            lambda: call_cmd(name, func)(*args, **kwargs),
-            help_func)
+        worker = lambda: call_cmd(name, func)(*args, **kwargs)
     else:
-        return catcher(
-            lambda: call_cmd(name, middleware(func))(*args, **kwargs),
-            help_func)
+        worker = lambda: call_cmd(name, middleware(func))(*args, **kwargs)
+
+    try:
+        return catcher(worker, help_func)
+    except Abort:
+        return -1
 
 # --------
 # Help
@@ -451,17 +463,22 @@
         return target()
     except UnknownCommand, e:
         err("unknown command: '%s'\n" % e)
+        raise Abort()
     except AmbiguousCommand, e:
         err("command '%s' is ambiguous:\n    %s\n" %
             (e.args[0], ' '.join(e.args[1])))
+        raise Abort()
     except ParseError, e:
         err('%s: %s\n' % (e.args[0], e.args[1]))
         help_func(e.args[0])
+        raise Abort()
     except getopt.GetoptError, e:
-        err('error: %s\n' % e)
+        err('error: %s\n\n' % e)
         help_func()
+        raise Abort()
     except OpsterError, e:
         err('%s\n' % e)
+        raise Abort()
 
 def call_cmd(name, func):
     def inner(*args, **kwargs):
@@ -495,7 +512,9 @@
 
 def sysname():
     name = sys.argv[0]
-    if name.startswith('./'):
+    if name.startswith('/'):
+        return name.rsplit('/', 1)[1]
+    elif name.startswith('./'):
         return name[2:]
     return name
 
@@ -608,17 +627,17 @@
 # --------
 
 # Command exceptions
-class CommandException(Exception):
-    'Base class for command exceptions'
+class OpsterError(Exception):
+    'Base opster exception'
 
-class AmbiguousCommand(CommandException):
+class AmbiguousCommand(OpsterError):
     'Raised if command is ambiguous'
 
-class UnknownCommand(CommandException):
+class UnknownCommand(OpsterError):
     'Raised if command is unknown'
 
-class ParseError(CommandException):
+class ParseError(OpsterError):
     'Raised on error in command line parsing'
 
-class OpsterError(CommandException):
-    'Raised on trouble with opster configuration'
+class Abort(OpsterError):
+    'Processing error, abort execution'
--- a/setup.cfg	Sat Nov 06 12:14:40 2010 -0700
+++ b/setup.cfg	Fri Dec 03 11:53:57 2010 -0800
@@ -1,2 +1,7 @@
+[build_sphinx]
+source-dir = docs/
+build-dir = docs/_build
+all_files = 1
+
 [upload_docs]
 upload-dir = docs/_build/html
--- a/tests/multicommands.py	Sat Nov 06 12:14:40 2010 -0700
+++ b/tests/multicommands.py	Fri Dec 03 11:53:57 2010 -0800
@@ -22,7 +22,7 @@
 
 @command(cplx_opts, usage='[-p] [--exit value] ...', name='complex', hide=True)
 def complex_(ui, *args, **opts):
-    u'''That's more complex command indented to do something
+    u'''That's more complex command intended to do something
 
     И самое главное - мы тут немножечко текста не в ascii напишем
     и посмотрим, что будет. :)
--- a/tests/opster.t	Sat Nov 06 12:14:40 2010 -0700
+++ b/tests/opster.t	Fri Dec 03 11:53:57 2010 -0800
@@ -8,7 +8,7 @@
 Check if usage is working::
 
   $ run multicommands.py
-  usage: /Users/piranha/dev/misc/opster/tests/multicommands.py <command> [options]
+  usage: multicommands.py <command> [options]
   
   commands:
   
@@ -23,9 +23,9 @@
 check it out::
 
   $ run multicommands.py help complex
-  /Users/piranha/dev/misc/opster/tests/multicommands.py complex [-p] [--exit value] ...
+  multicommands.py complex [-p] [--exit value] ...
   
-  That's more complex command indented to do something
+  That's more complex command intended to do something
   
       И самое главное - мы тут немножечко текста не в ascii напишем
       и посмотрим, что будет. :)
@@ -44,7 +44,7 @@
 
   $ run test_opts.py
   another: invalid arguments
-  /Users/piranha/dev/misc/opster/tests/test_opts.py [-l HOST] DIR
+  test_opts.py [-l HOST] DIR
   
   Command with option declaration as keyword arguments
   
@@ -67,4 +67,22 @@
    'port': 8000,
    'test': 'test'}
 
+Should we check passing some invalid arguments? I think so::
+
+  $ run test_opts.py --wrong-option
+  error: option --wrong-option not recognized
+  
+  test_opts.py [-l HOST] DIR
+  
+  Command with option declaration as keyword arguments
+  
+  options:
+  
+   -l --listen     ip to listen on (default: localhost)
+   -p --port       port to listen on (default: 8000)
+   -d --daemonize  daemonize process
+      --pid-file   name of file to write process ID to
+   -t --test       testing help for a function (default: test)
+   -h --help       show help
+
 That's all for today; see you next time!