Metadata-Version: 1.1
Name: begins
Version: 0.9
Summary: Command line programs for busy developers
Home-page: http://begins.readthedocs.org
Author: Aaron Iles
Author-email: aaron.iles@gmail.com
License: ASL
Description: ======
        begins
        ======
        
        --------
        Overview
        --------
        
        Command line programs for *lazy* humans.
        
        * Decorate a function to be your programs starting point.
        * Generate command line parser based on function signature.
        * Search system environment for option default values.
        
        |pypi_version| |build_status| |coverage|
        
        -----------
        Why begins?
        -----------
        
        I write a lot of
        small programs in `Python`_.
        These programs often
        accept a small number of
        simple command line arguments.
        Having to write
        command line parsing code
        in each of these
        small programs both
        breaks my train of thought
        and greatly increases the
        volume of code I am writting.
        
        Begins was implemented to
        remove the boilerplate code
        from these Python programs.
        It's not intended to replace
        the rich command line processing
        needed for larger applications.
        
        ------------
        Requirements
        ------------
        
        For Python versions earlier
        than Python 3.3,
        the `funcsigs`_ package from the
        `Python Package Index`_ is
        required.
        
        For Python version 2.6,
        the `argparse`_ package from the
        `Python Package Index`_ is
        also required.
        
        Both of these dependencies are
        listed in the package configuration.
        If using `Pip`_ to
        install *begins* then
        the required dependencies will
        be automatically installed.
        
        ------------
        Installation
        ------------
        
        *begins* is available
        for download from
        the `Python Package Index`_.
        To install using `Pip`_ ::
        
        $ pip install begins
        
        Alternatively, the latest
        development version can be
        installed directly
        from `Github`_. ::
        
        $ pip install git+https://github.com/aliles/begins.git
        
        Please note that
        *begins* is still in
        an alpha state 
        and therefore
        the API or behaviour
        could change.
        
        ---------------------------------
        Setting a programs starting point
        ---------------------------------
        
        The ``begin.start()`` function can be
        used as a function call
        or a decorator.
        If called as a function
        it returns ``True`` when
        called from the ``__main__`` module.
        To do this it inspects
        the stack frame of the caller,
        checking the ``__name__`` global.
        
        This allows the following Python pattern::
        
            >>> if __name__ == '__main__':
            ...     pass
        
        To be replace with::
        
            >>> import begin
            >>> if begin.start():
            ...    pass
        
        If used as a decorator
        to annotate a function
        the function will be called
        if defined in the ``__main__`` module
        as determined by inspecting
        the current stack frame.
        Any definitions that follow
        the decorated function
        wont be created until
        after the function call
        is complete.
        
        Usage of ``begin.start()`` as
        a decorator looks like::
        
            >>> import begin
            >>> @begin.start
            ... def run():
            ...     pass
        
        By deferring the execution
        of the function until after
        the remainder of the module has loaded
        ensures the main function doesn't fail
        if depending on something
        defined in later code.
        
        ----------------------------
        Parsing command line options
        ----------------------------
        
        If ``begin.start()`` decorates a
        function accepts parameters
        ``begin.start()`` will
        process the command for
        options to pass as
        those parameters::
        
            >>> import begin
            >>> @begin.start
            ... def run(name='Arther', quest='Holy Grail', colour='blue', *knights):
            ...     "tis but a scratch!"
        
        The decorated function above
        will generate the following
        command line help::
        
           usage: example.py [-h] [-n NAME] [-q QUEST] [-c COLOUR]
                             [knights [knights ...]]
        
           tis but a scratch!
        
           positional arguments:
             knights
        
           optional arguments:
             -h, --help            show this help message and exit
             -n NAME, --name NAME  (default: Arther)
             -q QUEST, --quest QUEST
                                   (default: Holy Grail)
             -c COLOUR, --colour COLOUR
                                   (default: blue)
        
        In Python3, any `function annotations`_
        for a parameter become
        the command line option help.
        For example::
        
            >>> import begin
            >>> @begin.start                                         # doctest: +SKIP
            ... def run(name: 'What, is your name?',
            ...         quest: 'What, is your quest?',
            ...         colour: 'What, is your favourite colour?'):
            ...     pass
        
        Will generate command help like::
        
           usage: holygrail_py3.py [-h] -n NAME -q QUEST -c COLOUR
        
           optional arguments:
             -h, --help            show this help message and exit
             -n NAME, --name NAME  What, is your name?
             -q QUEST, --quest QUEST
                                   What, is your quest?
             -c COLOUR, --colour COLOUR
                                   What, is your favourite colour?
        
        Command line parsing supports:
        
        * positional arguments
        * keyword arguments
        * default values
        * variable length arguments
        * annotations
        
        Command line parsing
        does not support
        variable length keyword arguments,
        commonly written as
        ``**kwargs``.
        If variable length keyword arguments
        are used by
        the decorated function
        an exception
        will be raised.
        
        If a parameter
        does not have a default,
        failing to pass a value
        on the command line
        will cause running the program to
        print an error and exit.
        
        For programs that have
        a large number of options
        it may be preferable to
        only use long options.
        To suppress short options,
        pass ``False`` as the
        ``short_args`` keyword argument to
        the ``begin.start`` decorator::
        
            >>> import begin
            >>> @begin.start(short_args=False)
            ... def run(name='Arther', quest='Holy Grail', colour='blue', *knights):
            ...     "tis but a scratch!"
        
        This program will not
        accept ``-n``, ``-q`` or ``-c``
        as option names.
        
        Similarity, a large number of
        command line options may
        be better displayed in
        alphabetical order.
        This can be achieved
        by passing ``lexical_order``
        as ``True``::
        
            >>> import begin
            >>> @begin.start(lexical_order=True)
            ... def main(charlie=3, alpha=1, beta=2):
            ...     pass
        
        This program will list
        the command line options as
        ``alpha``, ``beta``, ``charlie``
        instead of the order
        in which the function
        accepts them.
        
        ---------------
        Boolean options
        ---------------
        
        If a command line option has
        a default value that
        is a ``bool`` object.
        (``True`` or ``False``)
        The command line option
        will be flags
        rather than an option
        that accepts a value.
        Two flags are generated,
        one to set a ``True`` value and
        one to set a ``False`` value.
        The two commands will be of
        the form ``--flag`` and ``--no-flag``.
        For example::
        
            >>> import begin
            >>> @begin.start
            ... def main(enable=False, disable=True):
            ...     pass
        
        Using ``--enable``
        or ``--no-disable`` when
        invoking this program will
        invert the associated option.
        The options ``--no-enable``
        and ``--disable``
        have not effect.
        
        ------------
        Sub-Commands
        ------------
        
        *begins* supports
        using functions as
        `sub-commands`_ with the
        ``begin.subcommand()`` decorator::
        
            >>> import begin
            >>> @begin.subcommand                                    # doctest: +SKIP
            ... def name(answer):
            ...     "What is your name?"
            ...
            >>> @begin.subcommand                                    # doctest: +SKIP
            ... def quest(answer):
            ...     "What is your quest?"
            ...
            >>> @begin.subcommand                                    # doctest: +SKIP
            ... def colour(answer):
            ...     "What is your favourite colour?"
            ...
            >>> @begin.start
            ... def main():
            ...     pass
        
        This example registers
        three sub-commands for
        the program::
        
           usage: subcommands.py [-h] {colour,name,quest} ...
        
           optional arguments:
             -h, --help           show this help message and exit
        
           Available subcommands:
             {colour,name,quest}
               colour             What is your favourite colour?
               name               What is your name?
               quest              What is your quest?
        
        The main function will
        always be called with
        the provided command line arguments.
        If a sub-command was chosen
        the associated function will
        also be called.
        
        It is possible to
        create a sub-command with
        a different name from
        the decorated function's name.
        To do this pass the
        desired sub-command name using
        the ``name`` keyword argument::
        
            >>> import begin
            >>> @begin.subcommand(name='colour')                     # doctest: +SKIP
            ... def question(answer):
            ...     "What is your favourite colour?"
        
        Sub-commands can also be
        registered with a
        specific named group by
        passing a ``group`` argument to
        the ``begin.subcommand`` decorator.
        The ``begin.start()`` decorator can
        use sub-commands from
        a named group by
        passing it a ``sub_group`` argument.
        
        Similarly, sub-commands can be
        load from `entry points`_ by
        passing the name
        of the entry point
        through the ``plugins`` argument
        to the ``begin.start()`` decorator::
        
            >>> import begin
            >>> @begin.start(plugins='begins.plugin.demo')
            ... def main():
            ...     pass
        
        Any functions from
        installed packages
        that are registered with
        the ``begins.plugin.demo`` entry point
        will be loaded as sub-commands.
        
        ---------------------
        Multiple Sub-Commands
        ---------------------
        
        Some commands may benefit
        from being able to be called with
        multiple subcommands on
        the command line.
        The enable multiple sub-commands
        a command separator value needs
        to be passed to be
        passed to ``begin.start()``
        as the ``cmd_delim`` parameter::
        
            >>> import begin
            >>> @begin.subcommand                                    # doctest: +SKIP
            ... def subcmd():
            ...     pass
            ...
            >>> @begin.start(cmd_delim='--')
            ... def main():
            ...     pass
        
        When this program is called
        from the command line
        multiple instances of the
        sub-command may be called
        if separated by the
        command delimiter ``--``.
        
        -------------------
        Sub-Command Context
        -------------------
        
        There are use cases where
        it is desirable to pass
        state from the main function to
        a subsequent sub-command.
        To support this Begins provides
        the ``begin.context`` object.
        This object will have the
        following properties:
        
        * ``last_return``, value returned by previous command function.
        * ``return_values``, iterable of all return values from previous commands.
        * ``opts_previous``, iterable of options object used by previous commands.
        * ``opts_current``, options object for current command.
        * ``opts_next``, iterable of options object for following commands.
        * **(deprecated)** ``return_value``, replaced by ``last_return``.
        
        Any other properties set
        on the ``begin.context`` object
        will not be altered by begins.
        
        The ``last_return`` property
        and ``return_values`` will
        always be populated,
        even in the value
        returned from the
        main function or
        a sub-command function is
        the ``None`` object.
        The length and order of
        the ``return_values`` will
        match those of
        ``opts_previous``.
        
        ---------------------
        Environment Variables
        ---------------------
        
        Environment variables can
        be used to override the
        default values for
        command line options.
        To use environment variables
        pass a prefix string to
        the ``begin.start()`` decorator through
        the ``env_prefix`` parameter::
        
            >>> import begin
            >>> @begin.start(env_prefix='MP_')
            ... def run(name='Arther', quest='Holy Grail', colour='blue', *knights):
            ...     "tis but a scratch!"
        
        In the example above,
        if an environment variable
        ``MP_NAME`` existed,
        it's value would be
        used as the default for
        the ``name`` option.
        The options value can
        still be set by
        explicitly passing a
        new value as
        a command line option.
        
        -------------------
        Configuration files
        -------------------
        
        Configuration files can
        also be used to
        override the default values of
        command line options.
        To use configuration files
        pass a base file name to
        the ``begin.start()`` decorator through
        the ``config_file`` parameter::
        
            >>> import begin
            >>> @begin.start(config_file='.camelot.cfg')
            ... def run(name='Arther', quest='Holy Grail', colour='blue', *knights):
            ...     "tis but a scratch!"
        
        This example will
        look for configuration files named
        ``.camelot.cfg`` in
        the current directory and/or
        the user's home directory.
        A command line option's
        default value can be
        changed by an
        option value in
        a configuration file.
        The configuration section
        used matches the
        decorated function's name
        by default.
        This can be changed by
        passing a ``config_section``
        parameter to ``begin.start()``::
        
            >>> import begin
            >>> @begin.start(config_file='.camelot.cfg', config_section='camelot')
            ... def run(name='Arther', quest='Holy Grail', colour='blue', *knights):
            ...     "tis but a scratch!"
        
        In this second example
        the section ``camelot``
        will be used instead of
        a section named ``run``.
        
        ---------------------
        Argument type casting
        ---------------------
        
        Command line arguments are
        always passed as strings.
        Sometimes thought it is
        more convenient to
        receive arguments of
        different types.
        For example, this is a
        possible function for
        starting a web application::
        
            >>> import begin
            >>> @begin.start
            ... def main(host='127.0.0.1', port='8080', debug='False'):
            ...    port = int(port)
            ...    debug = begin.utils.tobool(debug)
            ...    "Run web application"
        
        Having to convert
        the ``port`` argument to
        an integer and
        the ``debug`` argument to
        a boolean is
        additional boilerplate code.
        To avoid this *begins* provides
        the ``begin.convert()`` decorator.
        This decorator accepts functions
        as keyword arguments where
        the argument name matches that of
        the decorator function.
        These functions are used
        to convert the
        types of arguments.
        
        Rewriting the example above using
        the ``begin.convert()`` decorator::
        
            >>> import begin
            >>> @begin.start
            ... @begin.convert(port=int, debug=begin.utils.tobool)
            ... def main(host='127.0.0.1', port=8080, debug=False):
            ...    "Run web application"
        
        The module ``begin.utils`` contains
        useful functions for
        converting argument types.
        
        -----------------
        Automatic casting
        -----------------
        
        For simple, built-in types
        *begins* can automatically
        type cast arguments.
        This is achieved by
        passing the parameter
        ``_automatic`` to ``begin.convert()``::
        
            >>> import begin
            >>> @begin.start
            ... @begin.convert(_automatic=True)
            ... def main(host='127.0.0.1', port=8080, debug=False):
            ...     "Run web application"
        
        This example is
        functionally equivalent to
        the example above.
        
        Automatic type casting
        works for the following
        built-in types.
        
        * ``int`` or ``long``
        * ``float``
        * ``boolean``
        * ``tuple`` or ``list``
        
        Additional casting functions
        can be provided with
        the same call to the
        ``begin.convert()`` decorator.
        
        Alternatively, use of
        ``begin.convert()`` can be
        dispensed by passing ``True``
        to ``begin.start()`` via
        the ``auto_convert`` parameter::
        
            >>> import begin
            >>> @begin.start(auto_convert=True)
            ... def main(host='127.0.0.1', port=8080, debug=False):
            ...     "Run web application"
        
        Again, this example is
        functionally equivalent to
        the example above.
        
        The limitation of using
        ``auto_convert`` is that
        it is not longer possible to
        provide additional casting functions.
        
        -----------------------
        Command Line Extensions
        -----------------------
        
        There are behaviours that
        are common to many
        command line applications,
        such as configuring the
        ``logging`` and
        ``cgitb`` modules.
        *begins* provides
        function decorators that
        extend a program's
        command line arguments to
        configure these modules.
        
        * ``begin.tracebacks()``
        * ``begin.logging()``
        
        To use these decorators
        they need to decorate
        the main function
        before ``begin.start()``
        is applied.
        
        Tracebacks
        ----------
        
        The ``begin.tracebacks()`` decorator
        adds command line options for
        extended traceback reports to
        be generated for
        unhandled exceptions::
        
           >>> import begin
           >>> @begin.start
           ... @begin.tracebacks
           ... def main(*message):
           ...     pass
        
        The example above will
        now have the following
        additional argument group::
        
           tracebacks:
             Extended traceback reports on failure
        
             --tracebacks   Enable extended traceback reports
             --tbdir TBDIR  Write tracebacks to directory
        
        Passing ``--tracebacks`` will
        cause extended traceback reports
        to be generated for
        unhandled exceptions.
        
        Traceback options may
        also be set using
        configuration files,
        if `Configuration files`_
        are supported.
        The follow options
        are used.
        
        * ``enabled``: use any of ``true``, ``t``, ``yes``, ``y``, ``on`` or ``1``
          to enable tracebacks.
        * ``directory``: write tracebacks to this directory.
        
        Options are expected to
        be in a ``tracebacks`` section.
        
        Logging
        -------
        
        The ``begin.logging()`` decorator
        adds command line options for
        configuring the logging module::
        
           >>> import logging
           >>> import begin
           >>> @begin.start
           ... @begin.logging
           ... def main(*message):
           ...     for msg in message:
           ...         logging.info(msg)
        
        The example above will
        now have two additional
        optional arguments as well as
        an additional argument group::
        
           optional arguments:
             -h, --help            show this help message and exit
             -v, --verbose         Increse logging output
             -q, --quiet           Decrease logging output
        
           logging:
             Detailed control of logging output
        
             --loglvl {DEBUG,INFO,WARNING,ERROR,CRITICAL}
                                   Set explicit log level
             --logfile LOGFILE     Ouput log messages to file
             --logfmt LOGFMT       Log message format
        
        The logging level
        defaults to ``INFO``.
        It can be adjusted
        by passing ``--quiet``,
        ``--verbose`` or
        explicitly using ``--loglvl``.
        
        The default log format
        depends on whether
        log output is
        being directed to
        standard out or file.
        The raw log text
        is written to
        standard out.
        The log message written
        to file output includes:
        
        * Time
        * Log level
        * Filename and line number
        * Message
        
        The message format can
        be overridden using
        the ``--logfmt`` option.
        
        Logging options may
        also be set using
        configuration files,
        if `Configuration files`_
        are supported.
        The follow options
        are used.
        
        * ``level``: log level, must be one of ``DEBUG``, ``INFO``, ``WARNING``,
          ``ERROR`` or ``CRITICAL``.
        * ``file``: output log messages to this file.
        * ``format``: log message format.
        
        Options are expected to
        be in a ``logging`` section.
        
        -----------------------
        Command Line Formatting
        -----------------------
        
        The default `argparse`_ help formatter
        may not always meet your needs.
        An alternate formatter
        can be provided using the
        ``formatter_class`` argument
        to ``begin.start()``::
        
            >>> import begin, argparse
            >>> @begin.start(formatter_class=argparse.RawTextHelpFormatter)
            ... def main():
            ...     pass
        
        Any of the `formatter classes`_
        provided by the argparse module
        can be used.
        
        Alternatively, ``begin.formatters`` provides
        a mechanism to compose
        new formatter class according
        to your requirements.::
        
            >>> from begin import formatters
            >>> formatter_class = formatters.compose(formatters.RawDescription, formatters.RawArguments)
        
        The following mixin classes
        are provided for use with
        ``begin.formatters.compose()``
        
        * RawDescription
        * RawArguments
        * ArgumentDefaults
        * RemoveSubcommandsLine
        
        One or more of
        these may be passed to
        ``begin.formatters.compose()``
        to create a new
        formatter class.
        
        ------------
        Entry Points
        ------------
        
        The `setuptools`_ package supports
        `automatic script creation`_ to
        automatically create
        command line scripts.
        These command line scripts
        use the `entry points`_ system
        from setuptools.
        
        To support the
        use of entry points,
        functions decorated by
        ``begin.start()`` have
        an instance method called
        ``start()`` that must be
        used to configure the
        entry point::
        
            setup(
                # ...
                entry_points = {
                    'console_scripts': [
                        'program = package.module:main.start'
                    ]
                }
        
        Use of the ``start()`` method is
        required because the
        main function is not
        called from the ``__main__`` module
        by the entryp points system.
        
        ------
        Issues
        ------
        
        Any bug reports or
        feature requests can
        be made using GitHub' `issues system`_.
        
        .. _Github: https://github.com/aliles/begins
        .. _Python: http://python.org
        .. _Python Package Index: https://pypi.python.org/pypi
        .. _Pip: http://www.pip-installer.org
        .. _argparse: https://pypi.python.org/pypi/argparse
        .. _automatic script creation: http://peak.telecommunity.com/DevCenter/setuptools#automatic-script-creation
        .. _issues system: https://github.com/aliles/begins/issues
        .. _entry points: http://peak.telecommunity.com/DevCenter/setuptools#dynamic-discovery-of-services-and-plugins
        .. _funcsigs: https://pypi.python.org/pypi/funcsigs
        .. _function annotations: http://www.python.org/dev/peps/pep-3107/
        .. _formatter classes: http://docs.python.org/dev/library/argparse.html#formatter-class
        .. _setuptools: https://pypi.python.org/pypi/setuptools
        .. _sub-commands: http://docs.python.org/dev/library/argparse.html#sub-commands
        
        .. |build_status| image:: https://secure.travis-ci.org/aliles/begins.png?branch=master
           :target: https://travis-ci.org/aliles/begins
           :alt: Current build status
        
        .. |coverage| image:: https://coveralls.io/repos/aliles/begins/badge.png?branch=master
           :target: https://coveralls.io/r/aliles/begins?branch=master
           :alt: Latest PyPI version
        
        .. |pypi_version| image:: https://pypip.in/v/begins/badge.png
           :target: https://crate.io/packages/begins/
           :alt: Latest PyPI version
        
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development :: Libraries :: Python Modules
