Git Product home page Git Product logo

parsedcmd's Introduction

ParsedCmd - A Cmd with argument list parsing

ParsedCmd is an extension built around the excellent cmd module of the standard library. Cmd allows one to build simple custom shells using do_* methods, taking care in particular of the REPL loop and the interactive help. However, no facility is given for parsing the argument line (do_* methods are passed the rest of the line as a single string argument).

With ParsedCmd, do_* methods can be type-annotated, either using Python 3's function annotation syntax, or with the ad-hoc annotate decorator, allowing the dispatcher to parse the argument list for them. Arguments can also be marked as keyword-only, either using Python 3's dedicated syntax, or with the ad-hoc kw_only decorator, in which case they will be assigned only if given as explicit arguments, i.e. method -option opt translates into do_method(option=opt) if option is keyword-only.

These annotations can also used to enhance the output of the default do_help method, by setting the show_usage attribute of the ParsedCmd object to True.

Example (Python 2.6-2.7)

from parsedcmd import *

class UI(ParsedCmd):
    # Non-annotated arguments default to str.
    # boolean is a utility function, that casts every string to True,
    # except "f", "false", "off" and "0" (case-insensitive).
    @annotate(flag=boolean, repeat=int)
    @kw_only("flag", "repeat")
    def do_print(self, line="abc", flag=True, repeat=1):
        """Print a given string (defaults to "abc").
        Print nothing if -flag is set to false.
        Print multiple copies if -repeat N option is given.
        """
        if flag:
            for i in range(repeat):
                print(line, file=self.stdout)

    # *args can also be annotated.
    # Python 2's usual limitations about mixing keyword arguments and *args
    # applies.
    @annotate(mul=int, nums=int)
    def do_multiply(self, mul, *nums):
        """Print `mul` times the numbers given.
        """
        for num in nums:
            print(mul * num, file=self.stdout)

    # Do not parse the argument line for do_shell.
    @gets_raw
    def do_shell(self, line):
        """Evaluates the given line.
        """
        eval(line)

Example (Python 3)

from parsedcmd import *

class UI(ParsedCmd):
    def do_print(self, line="abc", *, flag: boolean=True, repeat: int=1):
        """Print a given string (defaults to "abc").
        Print nothing if -flag is set to false.
        Print multiple copies if -repeat N option is given.
        """
        if flag:
            for i in range(repeat):
                print(line, file=self.stdout)

    def do_multiply(self, mul: int, *nums: int):
        """Print `mul` times the numbers given.
        """
        for num in nums:
            print(mul * num, file=self.stdout)

    @gets_raw
    def do_shell(self, line):
        """Evaluates the given line.
        """
        eval(line)

Remarks

The parsing is done in the following steps:

  • the input line is passed to the split() method (by default shlex.split()), and the result is bound to the argument list of the do_* method.
  • initial options (-opt val) are assigned to keyword-only arguments (which can be simulated in Python 2 using the @kw_only decorator).
  • each value bound to an argument annotated with a callable, either through @annotate([arg=callable]*), or through Python 3's function annotation syntax (f(arg[=default]: callable)), is passed to it; however, this does not affect default values),
  • if do_* has an annotated *args argument, then each element of args / each value in kwargs is casted.
  • in theory, **kwargs are also parsed and cast but there is currently effectively no way to assign to them.

ParsedCmd interacts imperfectly with decorated functions. Currently, it follows the __wrapped__ attribute until finding a function that either doesn't have this attribute or is decorated with @use_my_annotations, uses the signature and the annotations of this function to create the argument list, which is then passed to the wrapper function. In particular, ParsedCmd provides a wraps function that works like the one provided in functools, but also sets the __wrapped__ attribute (as in Python 3.3 or higher).

Testing

Just run py.test in the source folder.

parsedcmd's People

Contributors

anntzer avatar

Stargazers

briggySmalls avatar James Synge avatar xorr0@riseup.net avatar Isaul Vargas avatar  avatar  avatar Doug Hellmann avatar

Watchers

James Cloos avatar  avatar  avatar

Forkers

aeternocap

parsedcmd's Issues

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.