Metadata-Version: 2.1
Name: handofcats
Version: 3.1.2
Summary: python function to command translator
Home-page: https://github.com/podhmo/handofcats
Author: podhmo
Author-email: 
License: mit
Description: # handofcats
        
        [![Build Status](https://travis-ci.org/podhmo/handofcats.svg?branch=master)](https://travis-ci.org/podhmo/handofcats)
        
        A tiny magically Converter that making executable command from
        plain python function. If the function is type annotated, it is used.
        
        ## Feature
        
        - ✨Using plain python function as Console application
        
          - If you want to treat python function as single-command, `as_command()` is helpful
          - If you want to treat python function as sub-commands, `as_subcommand()` is helpful
        
        -  ◀️Escape from dependencies, if dislike this library
        
          - If you want something like [create-react-app's eject](https://github.com/facebook/create-react-app#philosophy), use [`--expose` option](https://github.com/podhmo/handofcats#--expose)
        
        ## Installing
        
        You can install via pip command, as you know.
        
        ```console
        $ pip install handofcats
        ```
        
        ## Using plain python function as Console application
        
        ### `as_command()`
        
        If you want plain python function to treat as single command, you can attach with `as_command` decorator. Then it acts as executable command.
        
        greeting.py
        
        ```python
        from handofcats import as_command
        
        @as_command
        def greeting(message: str, is_surprised: bool = False, name: str = "foo") -> None:
            """greeting message"""
            suffix = "!" if is_surprised else ""
            print("{name}: {message}{suffix}".format(name=name, message=message, suffix=suffix))
        ```
        
        🚀 It acts as single-command.
        
        ``` console
        $ python greeting.py hello
        foo: hello
        $ python greeting.py --is-surprised hello
        foo: hello!
        $ python greeting.py --is-surprised --name=bar bye
        bar: bye!
        ```
        
        Then, help message is here.
        
        ``` console
        $ python greeting.py -h
        usage: greeting [-h] [--is-surprised] [--name NAME] [--expose] [--inplace]
                        [--simple]
                        [--logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}]
                        message
        
        greeting message
        
        positional arguments:
          message               -
        
        optional arguments:
          -h, --help            show this help message and exit
          --is-surprised        - (default: False)
          --name NAME           - (default: foo)
          --expose              dump generated code. with --inplace, eject from handofcats dependency (default: False)
          --inplace             overwrite file (default: False)
          --simple              use minimum expression (default: False)
          --logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}positional arguments:
          message               -
        
        optional arguments:
          -h, --help            show this help message and exit
          --is-surprised        - (default: False)
          --name NAME           - (default: foo)
          --expose              dump generated code. with --inplace, eject from handofcats dependency (default: False)
          --inplace             overwrite file (default: False)
          --simple              use minimum expression (default: False)
          --logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}
        ```
        
        ( :warning: TODO: detail description )
        
        ### `as_subcommand()` and `as_subcommand.run()`
        
        Sub-command support is also included, so handofcats can be useful, when using plain python functions as sub-commands.
        
        Using `as_subcommand` decorator, and calling `as_subcommand.run()`. There is no need to write `if __name__ == "__main__"`.
        
        cli.py
        
        ``` python
        from handofcats import as_subcommand
        
        
        @as_subcommand
        def hello(*, name: str = "world") -> None:
            print(f"hello {name}")
        
        
        @as_subcommand
        def byebye(name: str) -> None:
            print(f"byebye {name}")
        
        
        # :warning: don't forget this
        as_subcommand.run()
        ```
        
        🚀 It acts as sub-commands. 
        
        ``` cosole
        $ python cli.py hello
        hello world
        
        $ python cli.py hello --name foo
        hello foo
        
        $ python cli.py byebye foo
        byebye foo
        ```
        
        Then, help message is here.
        
        ```cosole
        $ python cli.py -h
        usage: cli.py [-h] [--expose] [--inplace] [--simple]
                      [--logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}]
                      {hello,byebye} ...
        
        optional arguments:
          -h, --help            show this help message and exit
          --expose              dump generated code. with --inplace, eject from handofcats dependency (default: False)
          --inplace             overwrite file (default: False)
          --simple              use minimum expression (default: False)
          --logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}
        
        subcommands:
          {hello,byebye}
            hello
            byebye
        
        
        $ python cli.py hello -h
        usage: cli.py hello [-h] [--name NAME]
        
        optional arguments:
          -h, --help   show this help message and exit
          --name NAME  (default: 'world')
        ```
        
        ## Dropping dependencies
        
        If you dislike handofcats, you can drop it.
        
        ### `--expose`
        
        > No Lock-In: You can “eject” to a custom setup at any time. Run a single-command, and all the configuration and build dependencies will be moved directly into your project, so you can pick up right where you left off.
        
        Something like [create-react-app'seject](https://github.com/facebook/create-react-app#philosophy) , runing with `--expose` option, generationg the code that dropping dependencies of handofcats module.
        
        If you want to eject from [the code described above](https://github.com/podhmo/handofcats#as_command), `--expose` is helpful, maybe.
        
        ``` console
        $ python greeting.py --expose
        import typing as t
        
        def greeting(message: str, is_surprised: bool = False, name: str = "foo") -> None:
            """greeting message"""
            suffix = "!" if is_surprised else ""
            print("{name}: {message}{suffix}".format(name=name, message=message, suffix=suffix))
        
        
        def main(argv: t.Optional[t.List[str]] = None) -> t.Any:
            import argparse
        
            parser = argparse.ArgumentParser(prog=greeting.__name__, description=greeting.__doc__, formatter_class=type('_HelpFormatter', (argparse.ArgumentDefaultsHelpFormatter, argparse.RawTextHelpFormatter), {}))
            parser.print_usage = parser.print_help  # type: ignore
            parser.add_argument('message', help='-')
            parser.add_argument('--is-surprised', action='store_true', help='-')
            parser.add_argument('--name', required=False, default='foo', help='-')
            args = parser.parse_args(argv)
            params = vars(args).copy()
            return greeting(**params)
        
        
        if __name__ == '__main__':
            main()
        ```
        
        ### `--expose` with `--inplace`
        
        In addition, running with `inplace` option, when `--expose`, overwrite
        target source code.
        
        For handofcats, eject action is `--inplace --exepose`.
        
        ## If you're lazy, you can even skip using decorators
        
        If you're lazy, passing file to `handofcats` command. After installing this package, you can use the `handofcats` command.
        
        For example, pass the following file to `handofcats` command:
        
        sum.py
        
        ``` python
        def sum(x: int, y: int) -> None:
            print(f"{x} + {y} = {x + y}")
        ```
        
        It acts as single-command, even not decorated by the decorators introduced earlier.
        
        ``` console
        $ handofcats sum.py:sum 10 20
        10 + 20 = 30
        
        $ handofcats sum.py:sum -h
        handofcats sum.py:sum -h
        usage: sum [-h] [--expose] [--inplace] [--simple]
                   [--logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}]
                   x y
        
        positional arguments:
          x
          y
        
        optional arguments:
          -h, --help            show this help message and exit
          --expose              dump generated code. with --inplace, eject from handofcats dependency (default: False)
          --inplace             overwrite file (default: False)
          --simple              use minimum expression (default: False)
          --logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}
        ```
        
        ### `--expose` with handofcats command
        
        Passed in the form `<filename>.py`, it will be interpreted as a
        sub-commands. Of course, the `--expose` option also works.
        
        And passed in the form `<filename>.py:<function name>`, it will be
        interpreted as a single-command.
        
        So, plain python function only needed.
        
        cli.py
        
        ``` python
        def hello(*, name: str = "world"):
            print(f"hello {name}")
        
        
        # FIXME: default arguments (positional arguments)
        def byebye(name: str):
            print(f"byebye {name}")
        
        
        # ignored
        def _ignore(name: str):
            print("ignored")
        ```
        
        ``` console
        # treated as sub-commands
        $ handofcats cli.py --expose
        import typing as t
        
        def hello(*, name: str = "world"):
            print(f"hello {name}")
        
        
        # FIXME: default arguments (positional arguments)
        def byebye(name: str):
            print(f"byebye {name}")
        
        
        # ignored
        def ignore(name: str):
            print(f"ignored {name}")
        
        
        def _ignore(name: str):
            print("of cource, ignored")
        
        
        def main(argv: t.Optional[t.List[str]] = None) -> t.Any:
            import argparse
        
            parser = argparse.ArgumentParser(formatter_class=type('_HelpFormatter', (argparse.ArgumentDefaultsHelpFormatter, argparse.RawTextHelpFormatter), {}))
            subparsers = parser.add_subparsers(title='subcommands', dest='subcommand')
            subparsers.required = True
        
            fn = hello
            sub_parser = subparsers.add_parser(fn.__name__, help=fn.__doc__, formatter_class=parser.formatter_class)
            sub_parser.add_argument('--name', required=False, default='world', help='-')
            sub_parser.set_defaults(subcommand=fn)
        
            fn = byebye  # type: ignore
            sub_parser = subparsers.add_parser(fn.__name__, help=fn.__doc__, formatter_class=parser.formatter_class)
            sub_parser.add_argument('name', help='-')
            sub_parser.set_defaults(subcommand=fn)
        
            args = parser.parse_args(argv)
            params = vars(args).copy()
            subcommand = params.pop('subcommand')
            return subcommand(**params)
        
        
        if __name__ == '__main__':
            main()
        
        
        # treated as single-command
        $ handofcats cli.py:hello --expose
        ...
        ```
        
        ## experimental
        
        ### sequences
        
        ``` python
        from typing import List, Optional
        
        def psum(xs: List[int], *, ys: Optional[List[int]] = None):
            # treated as
            # parser.add_argument('xs', nargs='*', type=int)
            # parser.add_argument('--ys', action='append', required=False, type=int)
            ..
        ```
        
        ### choices
        
        ``` python
        from typing_extensions import Literal
        
        
        DumpFormat = Literal["json", "csv"]   # this: (experimental)
        
        
        def run(*, format: DumpFormat = "json"):
            # treated as
            # parser.add_argument("--format", defaul="json", choices=("json", "csv"), required=False)
            ...
        ```
        
        
        3.1.2
        
        - fix falsy default value is treated as None
        
        3.1.1
        
        - fix `--cont` option support completely, in handofcats command
        
        3.1.0
        
        - add `--cont` option
        - add `--simple` option, for `--expose`
        - remove `--untyped` option, for `--expose`
        
        3.0.1
        
        - (README uploading is failed)
        
        3.0.0
        
        - add sub-commands support
        - some refactoring
        - on `--expose`, default format is typed code, changes to more mypy friendly output
        
        2.5.0
        
        - logging option for lazy person
        - run with DEBUG=1 envvar, then logging feature is actuvated, automatically
        
        2.4.3
        
        - catch up magicalimport 0.8.1
        
        2.4.2
        
        - Injector with callback option
        
        2.4.1
        
        - Injector support ignore_arguments and ignore_flags
        
        2.4.0
        
        - some refactoring
        - use magicalimport for reducing code
        - use fastentrypoint for fast bootstrap time editable installed
        
        2.3.2
        
        - fix, with Literal Types, detect type is failed
        
        2.3.1
        
        - fix, choices's type is list, not dict
        
        2.3.0
        
        - support Literal types
        - fix, error is occured, running with `from __future__ import annotations`
        - fix, generated code is invalid when positional arguments with "_"
        - fix, unable to use the function named "main"
        - `--typed` option, with `--expose`
        
        2.2.0
        
        - `--inplace` option, with `--expose`
        
        2.1.0
        
        - `choices` function
        - fix bug that it is not working, importing with physical filepath
        
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: License :: OSI Approved :: MIT License
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Provides-Extra: testing
Provides-Extra: docs
Provides-Extra: dev
