Name | safdie JSON |
Version |
2.0.4
JSON |
| download |
home_page | https://github.com/coddingtonbear/safdie |
Summary | Easily make your app extensible by you or others via use of setuptools entrypoints. |
upload_time | 2025-03-09 18:53:50 |
maintainer | None |
docs_url | None |
author | Adam Coddington |
requires_python | >=3.6 |
license | MIT |
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": null,
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": null,
"keywords": null,
"author": "Adam Coddington",
"author_email": "me@adamcoddington.net",
"download_url": "https://files.pythonhosted.org/packages/08/42/5cfe15deb32400423cdf223878263e985f0b5eb9c267d0939d1f47217cef/safdie-2.0.4.tar.gz",
"platform": null,
"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",
"bugtrack_url": null,
"license": "MIT",
"summary": "Easily make your app extensible by you or others via use of setuptools entrypoints.",
"version": "2.0.4",
"project_urls": {
"Homepage": "https://github.com/coddingtonbear/safdie",
"Issue Tracker": "https://github.com/coddingtonbear/safdie/issues"
},
"split_keywords": [],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "12acdd3d148d692197ca0041bd8acec163b9f38abaaa01a7279276e282620f70",
"md5": "071e214c2632e12f17c2a2e9442725b9",
"sha256": "3ee15a95cd9778f6800647302ab921fb54c2cde3b955e569f173d66a373e1a9a"
},
"downloads": -1,
"filename": "safdie-2.0.4-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "071e214c2632e12f17c2a2e9442725b9",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": ">=3.6",
"size": 7565,
"upload_time": "2025-03-09T18:53:48",
"upload_time_iso_8601": "2025-03-09T18:53:48.910886Z",
"url": "https://files.pythonhosted.org/packages/12/ac/dd3d148d692197ca0041bd8acec163b9f38abaaa01a7279276e282620f70/safdie-2.0.4-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "08425cfe15deb32400423cdf223878263e985f0b5eb9c267d0939d1f47217cef",
"md5": "133c303f39810506ae22f355b9b38ac7",
"sha256": "19063536ebf00060e4bac636d4028055ab86efad35682ee90f3e969bbda2e3f0"
},
"downloads": -1,
"filename": "safdie-2.0.4.tar.gz",
"has_sig": false,
"md5_digest": "133c303f39810506ae22f355b9b38ac7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 12182,
"upload_time": "2025-03-09T18:53:50",
"upload_time_iso_8601": "2025-03-09T18:53:50.333777Z",
"url": "https://files.pythonhosted.org/packages/08/42/5cfe15deb32400423cdf223878263e985f0b5eb9c267d0939d1f47217cef/safdie-2.0.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-03-09 18:53:50",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "coddingtonbear",
"github_project": "safdie",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "safdie"
}