foxcli


Namefoxcli JSON
Version 0.4.1 PyPI version JSON
download
home_pageNone
SummaryA lightweight and minimal CLI framework
upload_time2025-10-27 20:27:14
maintainerNone
docs_urlNone
authordepthbomb
requires_python>=3.12
licenseMIT
keywords cli framework
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            from cli import UnknownCommandError> [!IMPORTANT]
> While foxcli is pre-1.0.0, breaking changes may be made without bumping the major version!

_foxcli_ is a minimal-by-design CLI framework for Python.

There are many great CLI frameworks out there, but some features I like in one aren't present in another. Likewise, one framework I like may have features that I don't like or has a bunch of extra features that I don't need.

foxcli being minimal-by-design means that it does not include any built-in commands, no TUI helpers, no command usage generation. You will have to handle all of this yourself.

This framework features:

- Class-based commands + being able to subclass its `Command` class
- Multi-level commands (like `user create`)
- Global options that can appear anywhere in command invocation
- Hooks to customize error handling

foxcli is still very much in early development but certainly usable, in fact I am using it in a testdrive with my project [WinUtils](https://github.com/depthbomb/winutils)!

Planned features include:

- Counted arguments like `-vvv`

# Installation

```shell
pip install foxcli
```

# Sample

```py
from sys import exit
from foxcli.cli import CLI
from foxcli.command import Command
from foxcli.argument import Argument
from foxcli.option import Opt, Option

class App(CLI):
    # hooks to customize error handling
    def on_unknown_command(self, e):
        # command not found, show a custom usage message?
        return 1

app = App(
    name='myapp',
    version='1.0.0',
    description='My app',
    global_options=[
        # global options, accessible in commands via `self.ctx.global_options`
        Option(name='verbose', short='v', default=False, help='Show verbose output'),
    ]
)

@app.command()
class Version(Command):
    name = 'version'
    description = 'Show version'

    def run(self, args) -> int:
        print(self.ctx.cli.version)
        return 0

# subclassing `Command` to add options
class UserableCommand(Command):
    arguments = [
        Argument('username'),  # supports `nargs` which takes int, '*', '+', and '?'. defaults to 1, which implicitly makes it required
    ]

@app.command()
class User(Command):
    name = 'user'
    aliases = ['u']
    description = 'User management commands'

# multi-level command
@app.command(parent='user')
class UserCreate(UserableCommand):
    name = 'create'
    description = 'Creates a new user'
    aliases = ['c', 'add']
    arguments = [
        # positional arguments
        Argument('avatar', default='https://website.com/image.png'),  # supports default values
    ]
    options = [
        Opt('rank', short='r', required=True)  # shortcut for `Option`, `Arg` also exists
    ]

    # `myapp user add Caim -r "Super Admin" -v`
    def run(self, args) -> int:
        # self.ctx.global_options.get('verbose', bool) -> True
        print(self.ctx.global_options.to_dict())  # {'verbose': True}

        # args.get('username', str) -> 'Caim'
        # args.get('avatar', str) -> 'https://website.com/image.png'
        # args.get('rank', str) -> 'Super Admin'
        print(args.to_dict())  # {'username': 'Caim', 'avatar': 'https://website.com/image.png', 'rank': 'Super Admin'}
        return 0

exit(app.run())
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "foxcli",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.12",
    "maintainer_email": null,
    "keywords": "cli, framework",
    "author": "depthbomb",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/5b/f2/4fc4ba2a2e07e796e5f842176bece6f4d3b53f8ebb093e3531f5294e1678/foxcli-0.4.1.tar.gz",
    "platform": null,
    "description": "from cli import UnknownCommandError> [!IMPORTANT]\n> While foxcli is pre-1.0.0, breaking changes may be made without bumping the major version!\n\n_foxcli_ is a minimal-by-design CLI framework for Python.\n\nThere are many great CLI frameworks out there, but some features I like in one aren't present in another. Likewise, one framework I like may have features that I don't like or has a bunch of extra features that I don't need.\n\nfoxcli being minimal-by-design means that it does not include any built-in commands, no TUI helpers, no command usage generation. You will have to handle all of this yourself.\n\nThis framework features:\n\n- Class-based commands + being able to subclass its `Command` class\n- Multi-level commands (like `user create`)\n- Global options that can appear anywhere in command invocation\n- Hooks to customize error handling\n\nfoxcli is still very much in early development but certainly usable, in fact I am using it in a testdrive with my project [WinUtils](https://github.com/depthbomb/winutils)!\n\nPlanned features include:\n\n- Counted arguments like `-vvv`\n\n# Installation\n\n```shell\npip install foxcli\n```\n\n# Sample\n\n```py\nfrom sys import exit\nfrom foxcli.cli import CLI\nfrom foxcli.command import Command\nfrom foxcli.argument import Argument\nfrom foxcli.option import Opt, Option\n\nclass App(CLI):\n    # hooks to customize error handling\n    def on_unknown_command(self, e):\n        # command not found, show a custom usage message?\n        return 1\n\napp = App(\n    name='myapp',\n    version='1.0.0',\n    description='My app',\n    global_options=[\n        # global options, accessible in commands via `self.ctx.global_options`\n        Option(name='verbose', short='v', default=False, help='Show verbose output'),\n    ]\n)\n\n@app.command()\nclass Version(Command):\n    name = 'version'\n    description = 'Show version'\n\n    def run(self, args) -> int:\n        print(self.ctx.cli.version)\n        return 0\n\n# subclassing `Command` to add options\nclass UserableCommand(Command):\n    arguments = [\n        Argument('username'),  # supports `nargs` which takes int, '*', '+', and '?'. defaults to 1, which implicitly makes it required\n    ]\n\n@app.command()\nclass User(Command):\n    name = 'user'\n    aliases = ['u']\n    description = 'User management commands'\n\n# multi-level command\n@app.command(parent='user')\nclass UserCreate(UserableCommand):\n    name = 'create'\n    description = 'Creates a new user'\n    aliases = ['c', 'add']\n    arguments = [\n        # positional arguments\n        Argument('avatar', default='https://website.com/image.png'),  # supports default values\n    ]\n    options = [\n        Opt('rank', short='r', required=True)  # shortcut for `Option`, `Arg` also exists\n    ]\n\n    # `myapp user add Caim -r \"Super Admin\" -v`\n    def run(self, args) -> int:\n        # self.ctx.global_options.get('verbose', bool) -> True\n        print(self.ctx.global_options.to_dict())  # {'verbose': True}\n\n        # args.get('username', str) -> 'Caim'\n        # args.get('avatar', str) -> 'https://website.com/image.png'\n        # args.get('rank', str) -> 'Super Admin'\n        print(args.to_dict())  # {'username': 'Caim', 'avatar': 'https://website.com/image.png', 'rank': 'Super Admin'}\n        return 0\n\nexit(app.run())\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A lightweight and minimal CLI framework",
    "version": "0.4.1",
    "project_urls": {
        "Changelog": "https://github.com/depthbomb/foxcli/blob/master/CHANGELOG.md",
        "Issues": "https://github.com/depthbomb/foxcli/issues",
        "Repository": "https://github.com/depthbomb/foxcli"
    },
    "split_keywords": [
        "cli",
        " framework"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b6e25aa1c82be2d7e37527f10e709a6b0701c16ffb8a1d320616d80b7ad34606",
                "md5": "0d0d598a970e9a88b0f8168d1cba4cbe",
                "sha256": "4cc0436429b40f998d3836cd4a89f73dcbb783ca924fd4bedb7256e649698ed0"
            },
            "downloads": -1,
            "filename": "foxcli-0.4.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0d0d598a970e9a88b0f8168d1cba4cbe",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.12",
            "size": 10238,
            "upload_time": "2025-10-27T20:27:13",
            "upload_time_iso_8601": "2025-10-27T20:27:13.416121Z",
            "url": "https://files.pythonhosted.org/packages/b6/e2/5aa1c82be2d7e37527f10e709a6b0701c16ffb8a1d320616d80b7ad34606/foxcli-0.4.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5bf24fc4ba2a2e07e796e5f842176bece6f4d3b53f8ebb093e3531f5294e1678",
                "md5": "52fb902fcb5403d12a62bb9b3399c0e7",
                "sha256": "e5068ce97af1af63f3fb31434e1ba2e09bf7886eae593ff8304b475c1f85428c"
            },
            "downloads": -1,
            "filename": "foxcli-0.4.1.tar.gz",
            "has_sig": false,
            "md5_digest": "52fb902fcb5403d12a62bb9b3399c0e7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.12",
            "size": 8007,
            "upload_time": "2025-10-27T20:27:14",
            "upload_time_iso_8601": "2025-10-27T20:27:14.406240Z",
            "url": "https://files.pythonhosted.org/packages/5b/f2/4fc4ba2a2e07e796e5f842176bece6f4d3b53f8ebb093e3531f5294e1678/foxcli-0.4.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-27 20:27:14",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "depthbomb",
    "github_project": "foxcli",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "foxcli"
}
        
Elapsed time: 1.74052s