Code Monkey home page Code Monkey logo

argh's Introduction

Argh: The Effortless CLI

image

image

image

image

image

image

image

image

The power of Argparse with plain Python functions!

Building a command-line interface? Found yourself uttering "argh!" while struggling with the API of argparse? Don't like the complexity but need the power?

Argh builds on the power of argparse (which comes with Python) and makes it really easy to use. It eliminates the complex API and lets you "dispatch" ordinary Python functions as CLI commands.

Installation

$ pip install argh

Example

import argh

def verify_paths(paths: list[str], *, verbose: bool = False):
    """
    Verify that all given paths exist.
    """
    for path in paths:
        if verbose:
            print(f"Checking {path}...")
        assert os.path.exists(path)

argh.dispatch_command(verify_paths)

Now you can run the script like this:

$ python app.py foo.txt bar/quux.txt

$ python app.py foo.txt bar/quux.txt --verbose
Checking foo.txt...
Checking bar/quux.txt...

$ python app.py -h
usage: app.py [-h] [-v] [paths ...]

Verify that all given paths exist.

positional arguments:
  paths          -

options:
  -h, --help     show this help message and exit
  -v, --verbose  False

Please check the documentation for examples of multiple commands, modularity, help generation, advanced type annotations inspection, decorators and more:

Why Argh?

Argh-powered applications are simple but flexible:

Pythonic, KISS

Commands are plain Python functions. Almost no CLI-specific API to learn.

Reusable

Endpoint functions can be used directly outside of CLI context.

Static typing friendly

100% of the code including endpoint functions can be type-checked. Argh is driven primarily by type annotations.

DRY

Don't Repeat Yourself. The amount of boilerplate code is minimal. Among other things, Argh will:

  • infer command name from function name;
  • infer arguments from function signature;
  • infer argument types, actions and much more from annotations.
Modular

Declaration of commands can be decoupled from assembling and dispatching.

Layered

The complexity of code raises with requirements.

Transparent

You can directly access argparse.ArgumentParser if needed.

Subcommands

Easily nested commands. Argh isolates the complexity of subparsers.

NIH free

Argh supports completion, progress bars and everything else by being friendly to excellent 3rd-party libraries. No need to reinvent the wheel.

Compact

No dependencies apart from Python's standard library.

See also the project page on GitHub, documentation and PyPI page.

Author

Developed by Andrey Mikhaylenko since 2010.

See contributors for a list of contributors to this library.

Contribute

The fastest way to improve this project is to submit tested and documented patches or detailed bug reports.

Donate

You can donate via Liberapay. This may speed up development or simply make the original author happy :)

Licensing

Argh is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

Argh is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with Argh. If not, see <http://gnu.org/licenses/>.

argh's People

Contributors

coolcold avatar dwf avatar ekimekim avatar felixonmars avatar floppym avatar invl avatar jakirkham avatar jelly avatar joequery avatar jwilk avatar lucretiel avatar madjar avatar mafrosis avatar melor avatar mnencia avatar mrdavidlaing avatar mtelka avatar neithere avatar saaros avatar sanga avatar tanriol avatar tony avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

argh's Issues

Specify preprocessor for wrapped errors

Use cases:

  • every wrapped error should be printed in red colour.
  • every wrapped error should have the prefix "ERR:".

Example code:

import termcolor

def format_error(excinfo):
    return termcolor.colored('ERR: {0}!'.format(excinfo), 'red')

@wrap_errors([KeyError], processor=format_error)
def func(key):
    return db[key]

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2013-01-14 05:54:56+00:00, last updated: 2013-01-14 06:57:17+00:00

Refactoring

The original code structure became inadequate by now.

File helpers.py contains almost everything. It should be split into functional parts such as:

  • declaration: set_default_command(), add_commands();
  • dispatching: dispatch(), dispatch_command(), dispatch_commands(), _execute_command();
  • output processing: _encode();
  • interaction: confirm();
  • helpers: ArghParser;
  • decorators: _wrap_errors.

The docstrings may be moved to docs/ as they are currently too long to stay with the code. Another option is to move only examples.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2012-12-17 03:50:03+00:00, last updated: 2012-12-17 22:49:35+00:00

Proxy definitions

Let's say we want to add a command to the parser with slightly different configuration:

class Foo:
    def meth(self):
        pass

foo = Foo()

command = argh.named('another-name')(foo.meth)    # WRONG!

dispatch_commands([command])

This is wrong because:

  1. the code won't work because accessing the method's function is not the same as accessing the method (extra checks are needed);
  2. the decorator (re)sets an object's attribute. If we only need to set a value right here, we should not touch the object itself; a proxy/wrapper should be applied instead.

For example (syntax to be improved):

@named('one')
def foo():
    pass

bar = proxy_named(foo, 'one')

assert foo.argh_name == 'one'
assert bar.argh_name == 'two'

The named decorator may be used for this purpose, too; it should be less transparent in that case.

Using argh with no subcommand

Perhaps it's just a documentation failing, but I can't see how to use argh for what must be the most common case: a script with no subcommands. Can this be done easily? I want to be able to say e.g:

from argh import arg, dispatch

@arg('--foo', default=1)
def main(args):
    print args.foo

dispatch(my_function)

and then run python myscript.py --foo 2 or -h. Thanks!

Note: This issue has been automatically migrated from Bitbucket
Created by @pag on 2012-02-28 16:26:43+00:00, last updated: 2012-02-29 11:27:41+00:00

Tests fail in Python 3.3+

Tests pass in PyPy, CPython 2.7, and CPython 3.2 but fail in CPython 3.3.

1) ERROR: A command can be resolved to a function, not a namespace.

   Traceback (most recent call last):
    tests.py line 172 in test_bare_namespace
      self.assert_cmd_fails('greet', 'too few arguments')
    tests.py line 130 in assert_cmd_fails
      self.assert_cmd_exits(command_string, message_regex)
    tests.py line 126 in assert_cmd_exits
      self.assertRaisesRegexp(SystemExit, message_regex, f)
    tests.py line 125 in <lambda>
      f = lambda: self.parser.dispatch(command_string.split())
    argh/helpers.py line 403 in dispatch
      return dispatch(self, *args, **kwargs)
    argh/helpers.py line 295 in dispatch
      f.write(output)
   TypeError: TypeError: string argument expected, got 'bytes'

There are two such errors. In both cases the help message is converted from str to bytes and is rejected by the io.StringIO() object (by the way, why not BytesIO?).

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2012-10-20 20:06:05+00:00, last updated: 2012-12-17 01:32:47+00:00

Disable completion when not attached to a TTY

I'm using argh as a dependency of the watchdog project. When I daemonise my watchdog process, I end up with the bash warnings in my logfile (as per #39).

This is easily handled with something like the following:

@@ -84,7 +84,7 @@ def dispatch(parser, argv=None, add_help_command=True,
     You can also mark arbitrary exceptions as "wrappable" by using the
     :func:`~argh.decorators.wrap_errors` decorator.
     """
-    if completion:
+    if completion and sys.stdout.isatty():
         autocomplete(parser)

Apologies for the lack of a pull req; I had a quick look but I'm unfamiliar with Bitbucket and I've never touched Mercurial :)

Note: This issue has been automatically migrated from Bitbucket
Created by @mafrosis on 2013-08-20 02:09:01+00:00, last updated: 2013-08-20 08:39:17+00:00

argh fails to install if argparse isn't pre-installed

I can't install argh or anything that depends on argh without first installing argparse:

thomas@normandy:~$ pythonbrew venv create arghtest
Creating `arghtest` environment into /Users/thomas/.pythonbrew/venvs/Python-2.6.5
Already using interpreter /Users/thomas/.pythonbrew/pythons/Python-2.6.5/bin/python
New python executable in /Users/thomas/.pythonbrew/venvs/Python-2.6.5/arghtest/bin/python
Installing setuptools............done.
Installing pip...............done.
thomas@normandy:~$ pip install argh
Downloading/unpacking argh
  Downloading argh-0.17.0.tar.gz
  Running setup.py egg_info for package argh
    Traceback (most recent call last):
      File "<string>", line 14, in <module>
      File "/Users/thomas/build/argh/setup.py", line 25, in <module>
        from argh import __version__
      File "argh/__init__.py", line 26, in <module>
        from .helpers import *
      File "argh/helpers.py", line 15, in <module>
        import argparse
    ImportError: No module named argparse
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "<string>", line 14, in <module>

  File "/Users/thomas/build/argh/setup.py", line 25, in <module>

    from argh import __version__

  File "argh/__init__.py", line 26, in <module>

    from .helpers import *

  File "argh/helpers.py", line 15, in <module>

    import argparse

ImportError: No module named argparse

----------------------------------------
Command python setup.py egg_info failed with error code 1 in /Users/thomas/build/argh
Storing complete log in /Users/thomas/.pip/pip.log
thomas@normandy:~$ 

This might be happening because setup.py imports from argh/init.py, which imports from helpers, which imports argparse.

Note: This issue has been automatically migrated from Bitbucket
Created by thethomasw on 2012-11-19 10:51:55+00:00, last updated: 2012-11-19 21:40:32+00:00

Store dispatch() result without printing to stdout?

I like the default assumption to print to stdout. It’s the most common case, and it makes developing with argh faster.

However, I’ve stumbled upon a case where I want argh to dispatch a command, but then return the result of that function, so I can process it further. Is there a way to do this?

Note: This issue has been automatically migrated from Bitbucket
Created by Zearin on 2013-03-01 16:49:30+00:00, last updated: 2013-03-01 22:32:30+00:00

Wrapped errors should go to stderr

Use case

db = {'a': 1}

@wrap_errors([KeyError])
def func(key):
    return db[key]
$ app a
→ stdout: 1
→ stderr:

$ app b
→ stdout:
→ stderr: KeyError: 'b'

Motivation

The use case above implies that the command output may be redirected to another command or a file. Current implementation would have the following negative effect:

  1. the user will be unaware of the error;
  2. the error message will be misinterpreted as an actually retrieved value and processed, generating a further error somewhere in the toolchain.

Solution

Normal flow and catched errors should be separated in the dispatcher.

  • If an error is wrapped, the result should go to the object defined as dispatch(errors_file=sys.stderr).
  • The rest goes to the object defined as dispatch(output_file=sys.stdout).

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2013-01-14 10:18:47+00:00, last updated: 2013-01-30 01:06:04+00:00

Argh fails with parameter action type 'count' if a default value is provided

Consider the following code:

#!python
@arg('-v', '--verbose',
     dest='verbose',
     action='count',
     default=0,
     help="Display verbose output.")
def cmd(foo, bar=1, *args, **kwargs):
    yield kwargs.get('verbose', -1)
    yield foo
    yield bar
    yield ', '.join(args)

# dispatching:
parser = ArghParser()
parser.add_commands([cmd])

if __name__ == '__main__':
    parser.dispatch()

Running this code throws the following exception:

#!pytb
Traceback (most recent call last):
  File ".\engineer_script.py", line 37, in <module>
    parser.add_commands([cmd])
  File "C:\Users\Tyler\.virtualenvs\engineer-dev\lib\site-packages\argh\helpers.py", line 40, in add_commands
    return add_commands(self, *args, **kwargs)
  File "C:\Users\Tyler\.virtualenvs\engineer-dev\lib\site-packages\argh\assembling.py", line 373, in add_commands
    set_default_command(command_parser, func)
  File "C:\Users\Tyler\.virtualenvs\engineer-dev\lib\site-packages\argh\assembling.py", line 266, in set_default_command
    args='/'.join(dest_or_opt_strings), func=function.__name__, msg=e))
TypeError: cmd: cannot add arg -v/--verbose: __init__() got an unexpected keyword argument 'type'

Removing the default=0 parameter from the arg decorator works, but then the default is set to None, which is not ideal.

Note: This issue has been automatically migrated from Bitbucket
Created by @tylerbutler on 2012-12-31 22:46:04+00:00, last updated: 2012-12-31 23:34:25+00:00

[Feature request] Generate bash-completion support

hi,

I'd really like if argh had the ability to
allow bash to complete commands/options provided
by argh. That would really make it easier for
users to issue commands running python programs.

Would it possible to add such a thing to argh?

Thank you. =)
Cheers.

Note: This issue has been automatically migrated from Bitbucket
Created by @gorakhargosh on 2010-12-01 18:01:12+00:00, last updated: 2010-12-01 18:24:50+00:00

Include a __version__ attribute

It would be really nice if we could inspect the version of argh we've imported, especially so if it used the common version attribute ;)

There is a workaround to fetching this information now by pulling in the PKG_INFO data, but that is far less easy to use.

Note: This issue has been automatically migrated from Bitbucket
Created by Anonymous on 2012-04-28 14:13:03+00:00, last updated: 2012-11-04 05:14:41+00:00

Autocompletion

Some readline stuff.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2010-11-13 00:36:25+00:00, last updated: 2010-12-02 00:13:51+00:00

Adding Controllers

Typical case:

class Controller:
    db = {1: 'foo', 2: 'bar'}

    def index(self):
        return self.db.keys()

    def detail(self, key):
        return self.db[key]

c = Controller()

# now
parser.add_commands([c.index, c.detail])

# ideally
parser.add_controller(c)
parser.add_controller(c, namespace='my-controller')

# ideally — paranoid mode (requires an @expose decorator on methods)
parser.add_controller(c, only_exposed=True)

Modules can be added in the same way despite they are unlikely to be controllers:

# commands.py

def foo(): pass

def bar(): pass

# cli.py

import commands

parser.add_controller(commands)

# paranoid mode; really makes sense here
parser.add_controller(commands, only_exposed=True)

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2013-01-10 03:39:11+00:00, last updated: 2013-01-30 01:10:54+00:00

Configurable output stream

Mika Eloranta: //Adding another dispatch() parameter 'output_file' (default: sys.stdout) where all output would be written with .write() would 1) be handy in some use cases and 2) could be used in test automation (write output to a temp file or a pipe and read it from there).//

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2010-12-06 10:23:04+00:00, last updated: 2010-12-06 12:00:19+00:00

Remove argh.six

Problem

  1. Licensing issue: Argh is published under LGPL, Six is under MIT. It may or may not be a problem, IANAL.
  2. Currently Argh relies on: six.PY3, six.string_types, six.text_type, six.binary_type, six.BytesIO, six.StringIO. This stuff is trivial and does not require 12K worth of code or an external dependency. It's very unlikely that Argh is ever going to require anything else from six.

Solution

There are two possible solutions:

  1. add http://pypi.python.org/pypi/six/ as an external dependency;
  2. completely remove it and stick to a simple chunk of code. (PREFERRED)

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2013-01-01 18:30:43+00:00, last updated: 2013-01-01 23:34:04+00:00

Option/argument with underscore matching fails even if `dest` value matches parameter name

I'm not sure whether this is a bug or an API design decision or I'm making some obvious mistake. I can't force match between decorator defined option and function argument. They contain hyphens and underscores. I tried to set this with dest value:

import argh                                                                      

@argh.arg('--long-option', dest='long_option')                                   
def command(long_option):                                                        
    pass                                                                         

 argh.ArghParser().add_commands([command])

above snippet raises: ValueError: command: argument --long-option does not fit function signature: long-option

Shorter version also fails, but I understand that it is not so explicit:

@argh.arg('--long-option')                                                       
def command(long_option):                                                        
    pass 

I'm aware that parsing and matching arguments can lead to many ambiguities, so maybe there is other way to force such option naming. Can I add options to parser manually and force my naming (maybe I've missed this in docs)?

Annotations

If {{{help}}} is not passed to {{{@arg()}}}, peek into {{{func.annotations}}} (if present).

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2010-11-13 11:28:03+00:00, last updated: 2012-12-22 05:16:32+00:00

Don't issue bash warnings when not using bash

It would be nice if the warnings were only issued if you're running bash. Perhaps, something like the following?

diff --git i/argh/completion.py w/argh/completion.py
index 82febd0..0624310 100644
--- i/argh/completion.py
+++ w/argh/completion.py
@@ -77,8 +77,9 @@ def autocomplete(parser):
     """ Adds support for shell completion by patching given
     `argparse.ArgumentParser` (sub)class.
     """
+    import os
     if COMPLETION_ENABLED:
         argcomplete.autocomplete(parser)
-    else:
+    elif os.getenv('BASH'):
         import warnings
         warnings.warn('Bash completion not available. Install argcomplete.')

Thanks,

James

PS. FWIW, the GitHub mirror appears to be far far behind this repo.

Note: This issue has been automatically migrated from Bitbucket
Created by Anonymous on 2013-01-24 20:57:04+00:00, last updated: 2013-01-24 23:02:37+00:00

More informative exception on explicit vs inferred arg type clash

I see in the documentation that underscores are converted to hyphens, but this seems to happen only for positional arguments. I seem to be unable to create optional arguments with either hyphens or underscores. For example:

#!/usr/bin/env python
import argparse,argcomplete,argh

@argh.arg('--my_switch', default="full")
def mycommand(my_switch):
    print("Hello world.")

parser = argh.ArghParser()
parser.add_commands([mycommand])
argh.completion.autocomplete(parser)
parser.dispatch()

outputs:

ValueError: mycommand: argument --my_switch does not fit function signature: my-switch

whereas this works fine:

@argh.arg('--myswitch', default="full")
def mycommand(myswitch):

How do I create an optional parameter with either a hyphen or an underscore?

append default value of each optional argument to its help message

When a parser is constructed with

argparse.ArgumentParser(format_class=argparse.ArgumentDefaultsHelpFormatter)

the default value of each parameter is automatically appended to the help message.

Is this possible to add this quite helpful functionality to argh?

Note: This issue has been automatically migrated from Bitbucket
Created by @yangle on 2013-06-04 19:24:58+00:00, last updated: 2013-06-07 05:43:13+00:00

"Lazy" subparsers

Building the complete ArgumentParser tree in complex apps (with namespaced commands i.e. subparsers) can take considerable time (as it imports just about everything from the sub-apps). A "lazy" parsing tree could solve the problem. Also, plug-ins may require the tree to be "lazy".

This may help: http://code.google.com/p/argparse/issues/detail?id=52

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2013-04-19 11:36:31+00:00

namespace help is not part of `program help`

here, the help argument seem to work for program help debug, but not program help. the later prints debug in the first column, but nothing on the second - where docstring of regular subcommands appear.

parser.add_commands(
    [start, stop],
    namespace='debug', 
    help='internal commands')

Note: This issue has been automatically migrated from Bitbucket
Created by Anonymous on 2012-04-13 18:34:21+00:00, last updated: 2012-12-16 15:20:07+00:00

Partial command names

..like in Mercurial:

#!bash
$ hg sta
$ hg status

This doesn't seem to be available in argparse in any form.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2010-11-13 00:40:09+00:00, last updated: 2012-12-18 15:33:49+00:00

Argparse dependency

Hi,

thanks for making argh, it is really great ! I am using it for sigal but I have an issue when packaging it for Archlinux. When calling sigal I get the following error:

#!python

pkg_resources.DistributionNotFound: argparse>=1.1

This is because you are adding argparse as a dependency in your setup.py even for python 2.7. So when installing argh with the system package I have a file /usr/lib/python2.7/site-packages/argh-0.23.0-py2.7.egg-info/requires.txt which contains argparse. And when calling my command with the entry_point system, it checks this dependency and fails.

Could you change your setup.py to add argparse only for python 2.6 ?

Note: This issue has been automatically migrated from Bitbucket
Created by @saimn on 2013-03-10 23:20:21+00:00, last updated: 2013-03-11 13:34:37+00:00

Enable custom per-argument shell completion

Marco Nenciarini writes:

I noticed that argh can get argument completion very easily with a very little patch I attached.

Basically it allows to specify completer=completer_function as @arg() parameter.

TBD:

  1. check if this is DRY and the best way to do it;
  2. write the test;
  3. apply the patch;
  4. update the list of authors.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2013-01-08 02:37:28+00:00, last updated: 2013-01-08 16:14:14+00:00

Broken pipe: recognize "intentionally" closed streams

Observation

$ timetra find -a sleep -f 'foooooooooooooooooooooooooooooooooooooooooooo' | head
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
foooooooooooooooooooooooooooooooooooooooooooo
Traceback (most recent call last):
  File "/home/andy/src/timetra/bin/timetra", line 7, in <module>
    main()
  File "/home/andy/src/timetra/timetra/cli.py", line 172, in main
    p.dispatch()
  File "/usr/lib/python3.3/site-packages/argh/helpers.py", line 53, in dispatch
    return dispatch(self, *args, **kwargs)
  File "/usr/lib/python3.3/site-packages/argh/dispatching.py", line 128, in dispatch
    io.dump(line, f)
  File "/usr/lib/python3.3/site-packages/argh/io.py", line 101, in dump
    output_file.write(data)
BrokenPipeError: [Errno 32] Broken pipe

Cause

When a (sufficiently long) line is written to an already closed stream, the BrokenPipeError is raised.

Problem

When the stream is closed, it is probably intentional. In the above case it is head that has closed the stream after getting 10 lines from argh. The exception should not be raised in this situation.

Solution

  • gather information: what exceptions are raised in this case in which conditions (Python version + stream type)
  • catch such exception and simply return

confirm does not work on python 3

Confirm doesn't work because raw_input has been replaced by input in python 3.

Note: This issue has been automatically migrated from Bitbucket
Created by @madjar on 2012-03-07 18:39:10+00:00, last updated: 2012-03-10 15:42:28+00:00

Migrate to py.test

...from unittest. Because it's easier to refactor tests written by convention, not by subclassing. And also py.test is simply more fun (pytest-xdist's --looponfail is a killer feature!).

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2012-12-24 12:54:10+00:00, last updated: 2012-12-24 13:56:27+00:00

store_true is not set for inferred bool argument

Example:

#!python

@command 
def save(dry_run=False):
    return dry_run

dispatch_command(save)

This fails:

$ python2 x.py --dry-run
usage: x.py [-h] [-d DRY_RUN]
x.py: error: argument -d/--dry-run: expected one argument

Clearly store_true is not set for some reason.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2012-12-23 08:11:11+00:00, last updated: 2012-12-24 02:25:59+00:00

Remove magic from output encoding

Currently the function behaves differently in Python 2.x and 3.x; the documentation is confusing.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2012-12-17 19:52:07+00:00, last updated: 2012-12-17 23:36:42+00:00

Update the list of features in docs

Can be grouped the same way the code is grouped into modules.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2012-12-24 05:44:32+00:00, last updated: 2012-12-30 17:37:15+00:00

Installation fails on Python 2.5

I'm using argh as a dependency for http://github.com/gorakhargosh/watchdog and when installing argh as a dependency using python2.5 I see this traceback:

{{{

!python

Searching for argh>=0.6.0
Reading http://pypi.python.org/simple/argh/
Reading http://bitbucket.org/neithere/argh/
Reading http://bitbucket.org/neithere/argh/src/
Best match: argh 0.8.0
Downloading http://pypi.python.org/packages/source/a/argh/argh-0.8.0.tar.gz#md5=e2733be992b788d57fa18795c9622d53
Processing argh-0.8.0.tar.gz
Running argh-0.8.0/setup.py -q bdist_egg --dist-dir /tmp/easy_install-XSVX1J/argh-0.8.0/egg-dist-tmp-NoEKoD
File "build/bdist.macosx-10.6-i386/egg/argh/init.py", line 16
from .exceptions import *
SyntaxError: 'import *' not allowed with 'from .'

build/bdist.macosx-10.6-i386/egg/argh/helpers.py:186: Warning: 'as' will become a reserved keyword in Python 2.6
File "build/bdist.macosx-10.6-i386/egg/argh/helpers.py", line 186
except CommandError as e:
^
SyntaxError: invalid syntax

}}}

Note: This issue has been automatically migrated from Bitbucket
Created by @gorakhargosh on 2010-11-27 11:44:34+00:00, last updated: 2010-11-27 12:25:30+00:00

dispatch() can't write to stdout under python 3(.2)

I'm not 100% about this, as it seems like basic functionality, but when porting some code that uses argh to python 3.2 I have the following problem:

code looking like:

p = ArghParser()
p.add_commands([convert, catalog, clean,  mv,  cp],  namespace='charts', title="Convert, catalog and move")

try:
    p.dispatch()
...

(where 'convert' yields a string)

results in:

Traceback (most recent call last):
  File "/home/jcs/src/jknav/jacknife-sdk/lib/jk.py", line 333, in <module>
    p.dispatch()
  File "/usr/lib/python3.2/site-packages/argh-0.15.0-py3.2.egg/argh/helpers.py", line 304, in dispatch
    return dispatch(self, *args, **kwargs)
  File "/usr/lib/python3.2/site-packages/argh-0.15.0-py3.2.egg/argh/helpers.py", line 205, in dispatch
    f.write(output)
TypeError: must be str, not bytes

'output' does seem to be a byte array, not string, at line 205 in dispatch()

I worked around this with a change of my call to dispatch():

    p.dispatch( output_file=open('/dev/stdout', 'wb') )

but this is clearly non-portable and undesirable. perhaps I am missing something obvious??

Note: This issue has been automatically migrated from Bitbucket
Created by jcs on 2012-03-13 20:55:56+00:00, last updated: 2012-12-17 03:27:05+00:00

Support more levels for nested commands

Currently "only" three levels are supported: prog, subparser and subsubparser.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2010-11-13 00:34:12+00:00, last updated: 2012-12-18 15:34:21+00:00

Tests fail in certain conditions

Tests fail.

 * python3.2: running distutils-r1_run_phase python_test
python3.2
/mnt/gen2/TmpDir/portage/dev-python/argh-0.22.0/work/argh-0.22.0
.....................EE...E
======================================================================
ERROR: Failure: ValueError (Attempted relative import in non-package)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/nose/failure.py", line 37, in runTest
    raise self.exc_class(self.exc_val).with_traceback(self.tb)
  File "/usr/lib64/python3.2/site-packages/nose/loader.py", line 412, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/lib64/python3.2/site-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/lib64/python3.2/site-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/mnt/gen2/TmpDir/portage/dev-python/argh-0.22.0/work/argh-0.22.0/test/test_dispatching.py", line 8, in <module>
    from .base import make_IO
ValueError: Attempted relative import in non-package

======================================================================
ERROR: Failure: ValueError (Attempted relative import in non-package)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/nose/failure.py", line 37, in runTest
    raise self.exc_class(self.exc_val).with_traceback(self.tb)
  File "/usr/lib64/python3.2/site-packages/nose/loader.py", line 412, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/lib64/python3.2/site-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/lib64/python3.2/site-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/mnt/gen2/TmpDir/portage/dev-python/argh-0.22.0/work/argh-0.22.0/test/test_integration.py", line 15, in <module>
    from .base import DebugArghParser, run
ValueError: Attempted relative import in non-package

======================================================================
ERROR: Failure: ValueError (Attempted relative import in non-package)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.2/site-packages/nose/failure.py", line 37, in runTest
    raise self.exc_class(self.exc_val).with_traceback(self.tb)
  File "/usr/lib64/python3.2/site-packages/nose/loader.py", line 412, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/lib64/python3.2/site-packages/nose/importer.py", line 39, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/lib64/python3.2/site-packages/nose/importer.py", line 86, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/mnt/gen2/TmpDir/portage/dev-python/argh-0.22.0/work/argh-0.22.0/test/test_regressions.py", line 6, in <module>
    from .base import DebugArghParser, run
ValueError: Attempted relative import in non-package

Name               Stmts   Miss  Cover   Missing
------------------------------------------------
argh                   7      0   100%   
argh.assembling      135     14    90%   36-37, 50, 58, 83, 136, 152-158, 241-242, 260, 350-351
argh.compat           15      5    67%   8-12, 23
argh.completion       13      5    62%   70, 80-84
argh.constants         7      0   100%   
argh.decorators       48      0   100%   
argh.dispatching      80     65    19%   80-129, 142-198, 216-218, 236-238
argh.exceptions        2      0   100%   
argh.helpers          15      2    87%   43, 47
argh.interaction      27      3    89%   58, 76-77
argh.io               31     19    39%   26-29, 36-39, 43, 76-93, 100-101
argh.utils            19      4    79%   36-39, 57
------------------------------------------------
TOTAL                399    117    71%   
----------------------------------------------------------------------
Ran 27 tests in 0.156s

FAILED (errors=3)

archtester argh # ls  /mnt/gen2/TmpDir/portage/dev-python/argh-0.22.0/work/argh-0.22.0/test/
test_assembling.py  test_dispatching.py  test_interaction.py
test_decorators.py  test_integration.py  test_regressions.py

.oh ooopsie. No base.py, and

archtester argh # ls  /mnt/gen2/TmpDir/portage/dev-python/argh-0.22.0/work/argh-0.22.0/
argh  argh.egg-info  cover  PKG-INFO  README  setup.cfg  setup.py  test

No Mainifest.in.

Pacakge argh can't won't be version bumped missing source files.

Note: This issue has been automatically migrated from Bitbucket
Created by Anonymous on 2013-01-21 09:46:22+00:00, last updated: 2013-01-28 14:52:12+00:00

Class methods as commands

Use case:

class Controller:
    db = {1: 'foo', 2: 'bar'}

    def index(self):
        return self.db.keys()

    def detail(self, key):
        return self.db[key]

c = Controller()
parser.add_commands([c.index, c.detail])

Argh should omit argument self while introspecting methods.

Static methods should work, too.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2013-01-09 20:55:13+00:00, last updated: 2013-01-10 03:29:44+00:00

Python 3: arguments lost in edge cases

import argh
def process(*points, parameter=0):
  print(points, parameter) # STUB

if __name__ == '__main__':
  argh.dispatch_command(process)

argh does not detect parameter as an argument and does not allow me to

python3.3 test.py a b c --parameter=3

@command broken if 2+ arguments start with same character

Example:

#!python
@command
def my_command(skip_foo=False, skip_bar=False):
    pass

Result:

Traceback (most recent call last):
  File "/home/andy/example.py", line 44, in <module>
    my_command
  File "/usr/local/lib/python2.7/dist-packages/argh/helpers.py", line 297, in add_commands
    return add_commands(self, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/argh/helpers.py", line 115, in add_commands
    command_parser.add_argument(*a_args, **a_kwargs)
  File "/usr/lib/python2.7/argparse.py", line 1287, in add_argument
    return self._add_action(action)
  File "/usr/lib/python2.7/argparse.py", line 1661, in _add_action
    self._optionals._add_action(action)
  File "/usr/lib/python2.7/argparse.py", line 1488, in _add_action
    action = super(_ArgumentGroup, self)._add_action(action)
  File "/usr/lib/python2.7/argparse.py", line 1301, in _add_action
    self._check_conflict(action)
  File "/usr/lib/python2.7/argparse.py", line 1439, in _check_conflict
    conflict_handler(action, confl_optionals)
  File "/usr/lib/python2.7/argparse.py", line 1446, in _handle_conflict_error
    raise ArgumentError(action, message % conflict_string)
argparse.ArgumentError: argument -s/--skip_foo: conflicting option string(s): -s

Possible solutions:

  1. omit short names for all arguments created by @command (may be excessive);
  2. omit short names for conflicting arguments;
  3. omit short names for all but the first of the conflicting arguments (but will the first always remain first?);
  4. generate short names for conflicting arguments from other chars (but we thus cannot guarantee the stability of the API as the order of the arguments may change; also the solution seems to be too complex).

I'd prefer the 2nd solution.

P.S.: don't forget unittests.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2011-09-03 12:28:56+00:00, last updated: 2012-12-23 03:29:06+00:00

Allow adding functions to parser without decorators

Current state

Functions cannot be assembled without decorators:

#!python
@command
def simple_one(): pass

@command 
def simple_two(a): pass

@command 
def simple_three(a=1): pass

# function with a merged explicit argument
@arg('-a', '--a', help='foo')
@command 
def simple_four(a=1): pass

# WRONG. this will raise an error
@arg('-x')
@command 
def simple_five(y): pass

Functions that expect a namespace object are considered "normal" despite being a marginal case and looking unpythonic:

#!python
def namespace_one(args): pass

@arg('a')
def namespace_two(args): pass

Desired state

Functions can be assembled without decorators:

#!python
# function with no arguments
def simple_one(): pass

# functions with arguments
def simple_two(a): pass
def simple_three(a=1): pass

# function with a merged explicit argument
@arg('-a', '--a', help='foo')
def simple_four(a=1): pass

# WRONG. this will raise an error
@arg('-x')
def simple_five(y): pass

Functions that expect a namespace object are a special case despite being "classic" from the argparse POV:

#!python
@expects_obj
def namespace_one(args): pass

@arg('a')
@expects_obj
def namespace_two(args): pass

Two possible improvements which I consider "magic" and generally unnecessary and therefore prefer to omit:

  1. detect "classic" command function by signature ("arg" as the first and only argument);
  2. restrict NS-expecting functions (via expects_obj() deco) to only have a single argument called args.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2012-12-24 08:55:32+00:00, last updated: 2012-12-30 16:34:04+00:00

Coercing strings to Unicode

This fails:

@arg('foo', type=unicode)
def xyz(args):
    print args.foo
./app.py xyz привет!

So we have to decode str objects to utf-8 every time for every Unicode argument. This is very annoying. Argh should at least provide a fix_unicode(ns, *list_of_args) function or somehow handle the coercion when type=unicode is specified (maybe by forcing type=str, setting a flag and adding a custom namespace object).

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2011-01-05 13:44:19+00:00, last updated: 2012-12-18 15:01:56+00:00

Mixing of declared and inferred arguments

At present, the following will not copy myfn's signature default to the argparse argument's default value:

#!python

@arg('--foo')
@plain_signature
def myfn(foo=5):
  pass

It should be unnecessary to redundantly provide default values:

#!python

@arg('--foo', default=5)
@plain_signature
def myfn(foo=5):
  pass

Note: This issue has been automatically migrated from Bitbucket
Created by @jnothman on 2012-11-11 02:00:25+00:00, last updated: 2012-12-23 01:42:33+00:00

Indicate argument that caused error during add_argument

In set_default_command, ArgumentParser.add_argument is called in a loop with arguments that had otherwise not been validate. If any of these calls are found invalid, insufficient context is given in the exception TraceBack to determine which argument definition is broken. The add_argument call should hence be wrapped with a try-except that gives some context (i.e. what args and kwargs caused the error) and reraises the exception.

Note: This issue has been automatically migrated from Bitbucket
Created by @jnothman on 2012-11-22 04:33:10+00:00, last updated: 2012-12-23 03:52:23+00:00

Autocompletion of options

Autocompletion currently works for commands (see issue #2) but not for options.

Note: This issue has been automatically migrated from Bitbucket
Created by @neithere on 2010-12-04 16:38:42+00:00, last updated: 2012-12-31 22:44:21+00:00

Commands that are a substring of the functions they call?

Is it possible to register a command (e.g. spam) that calls a function with a slightly different name (e.g. do_spam)?

Note: This issue has been automatically migrated from Bitbucket
Created by Zearin on 2012-04-17 11:57:04+00:00, last updated: 2012-11-04 05:19:27+00:00

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.