Skip to main content

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

Project description

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:
# Module Path: my_app.commands
from safdie import BaseCommand

class MyCommand(BaseCommand):
    def handle(self):
        print("Do whatever you need to do here")
  1. Create your program's main command-line function:
# 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()
  1. In setuptools entrypoints, declare your entrypoints for both your command-line entrypoint and each of your commands:
   setup(
       ...
       entrypoints={
           "console_scripts": [
               "my_command_line_app = my_app.cli:main",
           ],
           "myapp.commands": {
               "somecommand = my_app.commands:MyCommand",
           }
       }
   )
  1. Install your app with python setup.py install

Now you can run my_command_line_app somecommand to execute your function.

Tips

Customizing your argument parser

By default, Safdie will generate a new argument parser for you, but maybe you want to use Gooey or just want to add a few arguments of your own to the parser? If so -- you can provide your own argument parser:

from argparse import ArgumentParser

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--something", action="store_true')

    SafdieRunner("myapp.commands", parser=parser).run()

Performing work between parsing args and executing a command

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

from argparse import ArgumentParser

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--debugger", action="store_true')

    runner = SafdieRunner("myapp.commands", parser=parser)
    args = runner.parse_args()

    if args.debugger:
        import debugpy

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

    runner.run_command_for_parsed_args(args)

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.

# 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")
from .commands import MyAppCommandBase

def main():
    runner = SafdieRunner("myapp.commands", cmd_class=MyAppCommandBase)
    args = runner.parse_args()

    some_value_i_want_to_pass = "Arbitrary"

    runner.run_command_for_parsed_args(
        args,
        init_kwargs={
            'some_additional_init_param': some_value_i_want_to_pass,
        },
        # Note that also `init_args`, `handle_args`, and `handle_kwargs`
        # also exist for extra flexibility.
    )

Why is this named 'Safdie'?

You've probably seen at least a few photos of the famous building named Habitat 67. Moshe Safdie is the man who designed it.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

safdie-1.0.1.tar.gz (11.2 kB view details)

Uploaded Source

Built Distribution

safdie-1.0.1-py2.py3-none-any.whl (6.8 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file safdie-1.0.1.tar.gz.

File metadata

  • Download URL: safdie-1.0.1.tar.gz
  • Upload date:
  • Size: 11.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.4 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.1 CPython/3.9.5

File hashes

Hashes for safdie-1.0.1.tar.gz
Algorithm Hash digest
SHA256 7f966ae3a0e5e23f8f305b0a77d7d7bcc5ffc26b56d03f25f0ee19861e73e2bc
MD5 bbb03e1448b8f6b32af1a36a85598a93
BLAKE2b-256 704c3c126dbb3ea1799fd5535ef11515c6dac0877aae91c889f8b96275adc396

See more details on using hashes here.

File details

Details for the file safdie-1.0.1-py2.py3-none-any.whl.

File metadata

  • Download URL: safdie-1.0.1-py2.py3-none-any.whl
  • Upload date:
  • Size: 6.8 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.6.4 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.1 CPython/3.9.5

File hashes

Hashes for safdie-1.0.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 b643bcf31f7b086a54791a28311accbd25532c68fedbd72b3d60208654ef7b5a
MD5 dbd220e1be4ec987bc2ce45c829881c2
BLAKE2b-256 ae686261d6439816e253e91fcad2e02ef79573714e84735664ff2d9f64b8f4e2

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page