safdie


Namesafdie JSON
Version 2.0.1 PyPI version JSON
download
home_pagehttps://github.com/coddingtonbear/safdie
SummaryEasily make your app extensible by you or others via use of setuptools entrypoints.
upload_time2021-08-23 15:48:18
maintainer
docs_urlNone
authorAdam Coddington
requires_python>=3.6
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Safdie

Easily make your app extensible by you or others via use of setuptools entrypoints.

* Free software: MIT license

I've written roughly the same module system for ten or so command-line apps over the last few years, and by now I've landed on a pattern that I've found pretty flexible and useful.  Here, I've packed it into a module so both you and I can avoid re-inventing it every time we have a new project.

## Installation

```
pip install safdie
```

You can also install the in-development version with:

```

pip install https://github.com/coddingtonbear/safdie/archive/master.zip

```

## Quickstart

The below example isn't particularly useful, but does demonstrate a fully-working use of this.

1. Create your commands as subclasses of `safdie.BaseCommand` and write whatever command classes you need:

```python
# Module Path: my_app.commands
from safdie import BaseCommand

class MyCommand(BaseCommand):
    def handle(self):
        print("Do whatever you need to do here")

```

2. Create your program's main command-line function:

```python
# Module Path: my_app.cli
from safdie import SafdieRunner, BaseCommand

def main():
    # This will look up the command and run it's `handle` function.
    SafdieRunner("myapp.commands").run()

```

3. In setuptools entrypoints, declare your entrypoints for both your command-line entrypoint and each of your commands:

```python
   setup(
       ...
       entrypoints={
           "console_scripts": [
               "my_command_line_app = my_app.cli:main",
           ],
           "myapp.commands": {
               "somecommand = my_app.commands:MyCommand",
           }
       }
   )
```

4. Install your app with `python setup.py install`

Now you can run `my_command_line_app somecommand` to execute your function.

## Tips

### Adding arguments

Maybe you want to add a command-line flag to your app; you can add those by subclassing `SafdieRunner` and defining an override for `add_arguments` as shown below:

```python
from argparse import ArgumentParser
from safdie import SafdieRunner


class MyRunner(SafdieRunner):
    def add_arguments(self, parser: ArgumentParser) -> None:
        parser.add_argument("--something", action="store_true")


def main():
    MyRunner("myapp.commands").run()
```

### Customizing your argument parser

By default, Safdie will generate a new argument parser for you, but maybe you want to use `Gooey` or some other Argparse-compatible parser?  You can provide the class to use for generating the argument parser by specifying the `parser_class` command-line argument:

```python
from gooey import GooeyParser, Gooey
from safdie import SafdieRunner


@Gooey
def main():
    SafdieRunner("myapp.commands", parser_class=GooeyParser).run()
```

### Doing something before executing a command

Maybe you want to be able to optionally start a debugger between parsing args and executing the command?

```python
import argparse
from safdie import SafdieRunner
from typing import Any, Dict, Iterable


class MyRunner(SafdieRunner):
    def add_arguments(self, parser: ArgumentParser) -> None:
        parser.add_argument("--debugger", action="store_true')

    def handle(
        self,
        args: argparse.Namespace,
        init_args: Iterable[Any],
        init_kwargs: Dict[str, Any],
        handle_args: Iterable[Any],
        handle_kwargs: Dict[str, Any],
    ) -> Any:
        if args.debugger:
            import debugpy

            debugpy.listen(("0.0.0.0", 5678))
            debugpy.wait_for_client()

        super().handle(
            args,
            init_args,
            init_kwargs,
            handle_args,
            handle_kwargs
        )


def main():
    MyRunner("myapp.commands").run()
```

### Using your own command subclass

In the below example, you have your own command subclass that requires an additional parameter at init-time.  Although the example below only uses an extra parameter for `__init__`, you can also pass extra parameters to `handle`.  See the source for more details.

```python
# Module Path: my_app.commands
from safdie import BaseCommand


class MyAppCommandBase(BaseCommand):
    def __init__(self, some_additional_init_param, *args, **kwargs):
        # Do something with `some_additional_init_param
        super().__init__(*args, **kwargs)


class MyCommand(MyAppBaseCommand):
    def handle(self):
        print("Do whatever you need to do here")
```

```python
from typing import Any, Dict, Iterable

from safdie import SafdieRunner

from .commands import MyAppCommandBase


class MyRunner(SafdieRunner):
    def handle(
        self,
        args: argparse.Namespace,
        init_args: Iterable[Any],
        init_kwargs: Dict[str, Any],
        handle_args: Iterable[Any],
        handle_kwargs: Dict[str, Any],
    ) -> Any:
        some_value_i_want_to_pass = "Arbitrary"

        init_kwargs['some_additional_init_param'] = (
            some_value_i_want_to_pass
        )

        super().handle(
            args,
            init_args,
            init_kwargs,
            handle_args,
            handle_kwargs
        )

def main():
    MyRunner("myapp.commands", cmd_class=MyAppCommandBase).run()
```

## Why is this named 'Safdie'?

You've probably seen at least a few photos of the famous building named [Habitat 67](https://en.wikipedia.org/wiki/Habitat_67). [Moshe Safdie](https://en.wikipedia.org/wiki/Moshe_Safdie) is the man who designed it.



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/coddingtonbear/safdie",
    "name": "safdie",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "",
    "author": "Adam Coddington",
    "author_email": "me@adamcoddington.net",
    "download_url": "https://files.pythonhosted.org/packages/c0/f5/2ca88fb8f0433a82ba12ae8610d9f1d71b9083b64911c7d030e42d3fece4/safdie-2.0.1.tar.gz",
    "platform": "",
    "description": "# Safdie\n\nEasily make your app extensible by you or others via use of setuptools entrypoints.\n\n* Free software: MIT license\n\nI've written roughly the same module system for ten or so command-line apps over the last few years, and by now I've landed on a pattern that I've found pretty flexible and useful.  Here, I've packed it into a module so both you and I can avoid re-inventing it every time we have a new project.\n\n## Installation\n\n```\npip install safdie\n```\n\nYou can also install the in-development version with:\n\n```\n\npip install https://github.com/coddingtonbear/safdie/archive/master.zip\n\n```\n\n## Quickstart\n\nThe below example isn't particularly useful, but does demonstrate a fully-working use of this.\n\n1. Create your commands as subclasses of `safdie.BaseCommand` and write whatever command classes you need:\n\n```python\n# Module Path: my_app.commands\nfrom safdie import BaseCommand\n\nclass MyCommand(BaseCommand):\n    def handle(self):\n        print(\"Do whatever you need to do here\")\n\n```\n\n2. Create your program's main command-line function:\n\n```python\n# Module Path: my_app.cli\nfrom safdie import SafdieRunner, BaseCommand\n\ndef main():\n    # This will look up the command and run it's `handle` function.\n    SafdieRunner(\"myapp.commands\").run()\n\n```\n\n3. In setuptools entrypoints, declare your entrypoints for both your command-line entrypoint and each of your commands:\n\n```python\n   setup(\n       ...\n       entrypoints={\n           \"console_scripts\": [\n               \"my_command_line_app = my_app.cli:main\",\n           ],\n           \"myapp.commands\": {\n               \"somecommand = my_app.commands:MyCommand\",\n           }\n       }\n   )\n```\n\n4. Install your app with `python setup.py install`\n\nNow you can run `my_command_line_app somecommand` to execute your function.\n\n## Tips\n\n### Adding arguments\n\nMaybe you want to add a command-line flag to your app; you can add those by subclassing `SafdieRunner` and defining an override for `add_arguments` as shown below:\n\n```python\nfrom argparse import ArgumentParser\nfrom safdie import SafdieRunner\n\n\nclass MyRunner(SafdieRunner):\n    def add_arguments(self, parser: ArgumentParser) -> None:\n        parser.add_argument(\"--something\", action=\"store_true\")\n\n\ndef main():\n    MyRunner(\"myapp.commands\").run()\n```\n\n### Customizing your argument parser\n\nBy default, Safdie will generate a new argument parser for you, but maybe you want to use `Gooey` or some other Argparse-compatible parser?  You can provide the class to use for generating the argument parser by specifying the `parser_class` command-line argument:\n\n```python\nfrom gooey import GooeyParser, Gooey\nfrom safdie import SafdieRunner\n\n\n@Gooey\ndef main():\n    SafdieRunner(\"myapp.commands\", parser_class=GooeyParser).run()\n```\n\n### Doing something before executing a command\n\nMaybe you want to be able to optionally start a debugger between parsing args and executing the command?\n\n```python\nimport argparse\nfrom safdie import SafdieRunner\nfrom typing import Any, Dict, Iterable\n\n\nclass MyRunner(SafdieRunner):\n    def add_arguments(self, parser: ArgumentParser) -> None:\n        parser.add_argument(\"--debugger\", action=\"store_true')\n\n    def handle(\n        self,\n        args: argparse.Namespace,\n        init_args: Iterable[Any],\n        init_kwargs: Dict[str, Any],\n        handle_args: Iterable[Any],\n        handle_kwargs: Dict[str, Any],\n    ) -> Any:\n        if args.debugger:\n            import debugpy\n\n            debugpy.listen((\"0.0.0.0\", 5678))\n            debugpy.wait_for_client()\n\n        super().handle(\n            args,\n            init_args,\n            init_kwargs,\n            handle_args,\n            handle_kwargs\n        )\n\n\ndef main():\n    MyRunner(\"myapp.commands\").run()\n```\n\n### Using your own command subclass\n\nIn the below example, you have your own command subclass that requires an additional parameter at init-time.  Although the example below only uses an extra parameter for `__init__`, you can also pass extra parameters to `handle`.  See the source for more details.\n\n```python\n# Module Path: my_app.commands\nfrom safdie import BaseCommand\n\n\nclass MyAppCommandBase(BaseCommand):\n    def __init__(self, some_additional_init_param, *args, **kwargs):\n        # Do something with `some_additional_init_param\n        super().__init__(*args, **kwargs)\n\n\nclass MyCommand(MyAppBaseCommand):\n    def handle(self):\n        print(\"Do whatever you need to do here\")\n```\n\n```python\nfrom typing import Any, Dict, Iterable\n\nfrom safdie import SafdieRunner\n\nfrom .commands import MyAppCommandBase\n\n\nclass MyRunner(SafdieRunner):\n    def handle(\n        self,\n        args: argparse.Namespace,\n        init_args: Iterable[Any],\n        init_kwargs: Dict[str, Any],\n        handle_args: Iterable[Any],\n        handle_kwargs: Dict[str, Any],\n    ) -> Any:\n        some_value_i_want_to_pass = \"Arbitrary\"\n\n        init_kwargs['some_additional_init_param'] = (\n            some_value_i_want_to_pass\n        )\n\n        super().handle(\n            args,\n            init_args,\n            init_kwargs,\n            handle_args,\n            handle_kwargs\n        )\n\ndef main():\n    MyRunner(\"myapp.commands\", cmd_class=MyAppCommandBase).run()\n```\n\n## Why is this named 'Safdie'?\n\nYou've probably seen at least a few photos of the famous building named [Habitat 67](https://en.wikipedia.org/wiki/Habitat_67). [Moshe Safdie](https://en.wikipedia.org/wiki/Moshe_Safdie) is the man who designed it.\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Easily make your app extensible by you or others via use of setuptools entrypoints.",
    "version": "2.0.1",
    "project_urls": {
        "Homepage": "https://github.com/coddingtonbear/safdie",
        "Issue Tracker": "https://github.com/coddingtonbear/safdie/issues"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "59d9f4d9667509f30448a4d10f3359ec3b67d8cd3bcba88eb68a76f9ded0426a",
                "md5": "cd84e2ed6fbdcd0c6afb57b6c7ba23d7",
                "sha256": "ee9e2ff0a382b88060d6a00824560a77a609ff2f37f0298db49ebecc5e0a083e"
            },
            "downloads": -1,
            "filename": "safdie-2.0.1-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "cd84e2ed6fbdcd0c6afb57b6c7ba23d7",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.6",
            "size": 7539,
            "upload_time": "2021-08-23T15:48:16",
            "upload_time_iso_8601": "2021-08-23T15:48:16.730506Z",
            "url": "https://files.pythonhosted.org/packages/59/d9/f4d9667509f30448a4d10f3359ec3b67d8cd3bcba88eb68a76f9ded0426a/safdie-2.0.1-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c0f52ca88fb8f0433a82ba12ae8610d9f1d71b9083b64911c7d030e42d3fece4",
                "md5": "2e334e68f9ce1c9ad94bd93bf00463b6",
                "sha256": "4b2cb5e442054b5f5c2062b89cc374db76fc343e03516658cf40c4cde353a4b9"
            },
            "downloads": -1,
            "filename": "safdie-2.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "2e334e68f9ce1c9ad94bd93bf00463b6",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 12010,
            "upload_time": "2021-08-23T15:48:18",
            "upload_time_iso_8601": "2021-08-23T15:48:18.718312Z",
            "url": "https://files.pythonhosted.org/packages/c0/f5/2ca88fb8f0433a82ba12ae8610d9f1d71b9083b64911c7d030e42d3fece4/safdie-2.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2021-08-23 15:48:18",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "coddingtonbear",
    "github_project": "safdie",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "safdie"
}
        
Elapsed time: 0.07504s