{ "info": { "author": "Joni Turunen", "author_email": "rojun.itu@gmail.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: Microsoft :: Windows :: Windows 10", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Software Development :: Build Tools", "Topic :: Software Development :: Libraries", "Topic :: Utilities" ], "description": "# clima - command line interface with a schema\n\n![PyPI](https://img.shields.io/pypi/v/clima) [![Build status](https://travis-ci.com/d3rp/clima.svg?branch=master)](https://travis-ci.com/d3rp/clima) [![PyPI license](https://img.shields.io/pypi/l/clima)]()\n\n[![Scrutinizer score](https://img.shields.io/scrutinizer/quality/g/d3rp/clima)](https://scrutinizer-ci.com/g/d3rp/clima) [![Dependencies](https://img.shields.io/librariesio/github/d3rp/clima)]()\n\n[![Python versions](https://img.shields.io/pypi/pyversions/clima)]()\n\nCreate a command line interface out of your script with quick default behaviour for configuration, minimal setup and less maintenance. It handles loading and parsing configuration\nfiles and overriding it with env variables by defining a simple schema of the configuration and a class with your \"business logic\".\n\nExample: to setup a configuration and a command line interface ready to go:\n\n from clima import c, Schema\n \n class C(Schema):\n a = 1\n \n @c\n class Cli:\n def foo(self):\n # using configuration\n print(c.a)\n \nUsage would then be e.g.:\n\n ./script.py foo\n ./script.py foo --a 42\n \n## Long description\n\nIn other words, you can use this to wrap your scripts as command line commands without resorting to bash or maintaining argument parsing in python. This removes the need of duplicating comments in order `--help` to remember what the arguments were and what they did. Sprinkling some decorator magic offers a typical use experience of a cli program (e.g. argument parsing and validation, --help, subcommands, ...).\n\nThe implementation is focused on a premise that for a simple script there's usually a script wide global configuration which would be used through out the user code i.e. a context for the program that is refered to in different parts of the code. That configuration is populated with given arguments falling back on defaults in the code and some further complimentary options. Those are then made accessible via a global `c` variable that can be tossed around the code base with very little additional effort. With a small adjustment this can made to autocomplete in IDEs (as attributes). This helps when the schema of the configuration grows larger as the autocomplete kicks in after typing `c.` offering those fields in your \"schema\" as attributes.\n\n## Installing\n\n pip install --user clima\n \nor with [pipx](https://pipxproject.github.io/pipx/) to use dedicated virtualenv:\n \n pipx install --user clima\n \n### Installing from source\n\nChoose your favourite flavour of build system. Check their documentation if puzzled ([poetry](https://poetry.eustace.io), [flit](https://flit.readthedocs.io/en/latest), [pipx](https://pipxproject.github.io/pipx/), [pipx](https://pipxproject.github.io/pipx/), [pipenv](https://docs.pipenv.org/en/latest)..)\n\nThe tooling here has been exported with [DepHell](https://github.com/dephell/dephell) from the poetry declarations. In case your favourite build tool flavour files are not up to date, see the `publish.py` for its `convert` subcommand, which should convert to all the possible alternatives once dephell is installed.\n\n## Usage\n\nSee the example file in [`examples/script_example.py`](examples/script_example.py). Here's a run down of the individual\nparts in such a script (adapted from another example at [module example](examples/module_example)).\n\nFirst import the required components:\n\n from clima import c, Schema\n \nIn your code define the `Schema` subclass by decorating the class with `c`:\n\n class Configuration(Schema):\n a: str = 'A' # a description\n x: int = 1 # x description\n\n\"Configuration\" is an arbitrary name, no magic there. The inherited `Schema` class\nsimplifies the schema's templating to defining just the attributes (i.e. `a` and `x` in this\nexample). Those have a set way:\n\n # attribute[: type] = default value [# Description for the --help]\n a: str = 'A' # a description\n \n`a` is the attribute which can be called in the code later with `c.a`. It has a type of 'str', default\nvalue of 'A'. The comment after it is parsed for the command line so it's not redundant. The values in square brackets `[]` are\noptional. All of these parts will be parsed for the '--help' for the subcommands of the cli, which should be defined as follows:\n\n @c\n class Cli:\n def subcommand_foo(self):\n \"\"\"This will be shown in --help for subcommand-foo\"\"\"\n print('foo')\n print(c.a)\n print(c.x)\n\n def subcommand_bar(self):\n \"\"\"This will be shown in --help for subcommand-bar\"\"\"\n print('bar')\n\nThe methods are parsed as subcommands and their respective doc strings will show in the \nsubcommands' help printout. Note the usage of the parsed configuration `c` inside the method:\n\n ...\n ...\n print(c.a)\n print(c.x)\n \nAlso, to enable autocompletion in IDEs, this hack suffices:\n\n c: Configuration = c\n\nPut it in the \"global space\" e.g. just after defining the template. See the [`examples/script_example.py`](examples/script_example.py) for a specific example.\n\nWhen all is complete, the imported `c` variable should have all the bits and pieces for the configuration. It can be\nused inside the Cli class as well as imported around the codebase thus encapsulating all the configurations into one\ncontainer with quick access with attributes `c.a`, `c.x`, etc...\n\n## Examples and platforms\n\nShould work for linux, macos and windows.\n\nMore examples in the [examples directory](examples) with printouts of the defined subcommands and helps.\n\n### Post init hook\n\nIn some occasions it's useful to deduce specific defaults from the given parameters e.g. in a cross platform build allowing\nonly minimal cli arguments. For those cases there's an `post_init` hook in which the fields can be refered to as in a\ntypical class, but that still allows validation and type casting etc.:\n\n class SoAdvanced(Schema):\n platform: str = 'win' # a description\n bin_path: pathlib.Path = '' # x description\n \n def post_init(self, *args):\n if self.platform = 'win':\n self.bin_path = 'c:/Users/foo/bar'\n else:\n self.bin_path = '/Users/mac/sth'\n\n### Testing the examples\n\nThe [examples](examples) can be tried out by cloning the repo and running from repo directory root (on linux and the like):\n\n PYTHONPATH=$PWD python ./examples/module_example/__main__.py -- -h\n PYTHONPATH=$PWD python ./examples/module_example/__main__.py subcommand-foo -- -h\n PYTHONPATH=$PWD python ./examples/module_example/__main__.py subcommand-bar\n ...\n\nOutput should resemble this (fire v0.1.3 prints out Args, fire v0.2.1 doesn't (though looks much nicer))\n\n```\n$ tester subcommand-foo -- -h\n\nType: method\nString form: >\nFile: C:\\Users\\foobar\\code\\py\\clima\\tester\\__main__.py\nLine: 18\nDocstring: This will be shown in --help for subcommand-foo\nArgs:\n --a (str): a description (Default is 'A')\n --x (int): x description (Default is 1)\n\nUsage: __main__.py subcommand-foo [--X ...]\n```\n\n## Configuration file and environment variables\n\nThe `c` decorator/configuration chains multiple configuration options together in order of priority (lower number overrides higher number):\n\n1. command line arguments\n1. Environment variables\n1. configuration file definitions\n1. defaults in the schema/template/namedtuple class\n\nThe configuration file should be named with postfix `.cfg` e.g. `foo.cfg` and have an ini type formatting with\na 'Default' section:\n\n # foo.cfg\n [Default]\n x = 2\n\nThe keys are the same as what you define in the schema. You can define all, some or none of the attributes.\nSame applies for the env variables.\n \n # linux example\n X=2 tester subcommand-foo\n \n## Additional features via Fire\n\nSee the [Python Fire's Flags](https://github.com/google/python-fire/blob/master/docs/using-cli.md#python-fires-flags)\ndocumentation for nice additional features such as:\n\n # e.g. tester.py is our cli program\n tester.py subcommand-foo -- --trace\n tester.py -- --interactive\n tester.py -- --completion\n \n## Why another cli framework?\n\nThis is just a tool to slap together a cli program in python instead that grew out of the need of having a build automation system and an entrypoint script to build various flavours of C++ projects. The intention is to get something reasonably configurable and generic up and running as fast as possible while still having the \"power\" of python. I can't bother to memorize argparses syntax, even though it's a very good package. Also click works nice for more elaborate things though fire is my personal favourite for the time being. Often times when I kick off a bash script for this it ends up too elaborate very quick and then I miss python.\n\nAlso docopt looks very nice, but it doesn't provide autocompletion and all the configuration chaining magic I was after.\n\nOther options for full cli experience:\n\n* [docopt](https://docopt.org)\n* [fire](https://github.com/google/python-fire)\n* [click](https://click.palletsprojects.com)\n\n\n### Dependencies\n\n* fire - [python-fire](https://github.com/google/python-fire) from google does the cli wrapping\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/d3rp/clima.git", "keywords": "cli", "license": "", "maintainer": "Joni Turunen", "maintainer_email": "rojun.itu@gmail.com", "name": "clima", "package_url": "https://pypi.org/project/clima/", "platform": "", "project_url": "https://pypi.org/project/clima/", "project_urls": { "Homepage": "https://github.com/d3rp/clima.git" }, "release_url": "https://pypi.org/project/clima/0.2.3/", "requires_dist": [ "fire (==0.1.3)" ], "requires_python": ">=3.6", "summary": "Simple boilerplate for cli scripts", "version": "0.2.3" }, "last_serial": 5788893, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "ee41312a151f7a580e15e4ddf7ccf451", "sha256": "c2cdbbdd104e15f3ee174b33378d5c427bbfd2d329b07c824ecfb18f22845ac1" }, "downloads": -1, "filename": "clima-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "ee41312a151f7a580e15e4ddf7ccf451", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 14188, "upload_time": "2019-08-24T20:14:01", "url": "https://files.pythonhosted.org/packages/83/be/4ff31b3068877b7dd8ce6d22729a016ab1a8c82c6fb183c4e9a36965676a/clima-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "89459f138f44c764d0a9eab7db259526", "sha256": "98d22d93baf035bc0adb6fa4dbd61ae56e0e11f5f2ab28dfa8fe4ffa588e4c20" }, "downloads": -1, "filename": "clima-0.1.0.tar.gz", "has_sig": false, "md5_digest": "89459f138f44c764d0a9eab7db259526", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 11776, "upload_time": "2019-08-24T20:14:11", "url": "https://files.pythonhosted.org/packages/d0/38/de61209535176f10b5437fb0ed80788d056cd3aa3b81ee847d51958f33ad/clima-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "9507b3a44a52f6adfd8dc2a8e09cb783", "sha256": "487f264670e84caa6570c3355ab0f6f3b175785dad9e8418a25be3d3a0b6830c" }, "downloads": -1, "filename": "clima-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "9507b3a44a52f6adfd8dc2a8e09cb783", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 14494, "upload_time": "2019-08-24T22:39:19", "url": "https://files.pythonhosted.org/packages/66/99/1e13ef0f5b96d16a9891f9e02a1c242d09c6d6266582c24e7458d0adec86/clima-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cf17fce5e06c9345793e31de5f7749bb", "sha256": "21c972644b040af6ae3f992f3c54d169cf5f79d1a8bd55dac48423d31d226970" }, "downloads": -1, "filename": "clima-0.1.1.tar.gz", "has_sig": false, "md5_digest": "cf17fce5e06c9345793e31de5f7749bb", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 14171, "upload_time": "2019-08-24T22:39:28", "url": "https://files.pythonhosted.org/packages/84/18/08db2678f49532f1fcc3b3786b681085d2b22bae4b58e3aa5b288e038749/clima-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "502351f717adbc148757c513b0e1cdc1", "sha256": "20de976f006e803c9616527c93fc2dc88d7320c8d387d62a9230250d7c58dbd6" }, "downloads": -1, "filename": "clima-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "502351f717adbc148757c513b0e1cdc1", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 9657, "upload_time": "2019-09-03T20:10:25", "url": "https://files.pythonhosted.org/packages/23/36/1fb36ffe4843a3e3d3a7c4772c727a8875fba58375651bdada8a41b240a6/clima-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5432d8aa020eaf958cf191243ca89517", "sha256": "8fc406a393f6ed440707d2891475be2973cff2844e384ade61a513331d64783b" }, "downloads": -1, "filename": "clima-0.2.0.tar.gz", "has_sig": false, "md5_digest": "5432d8aa020eaf958cf191243ca89517", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 10254, "upload_time": "2019-09-03T20:10:28", "url": "https://files.pythonhosted.org/packages/9c/7a/80412ec27277bb33c559fc97159aa67240eb75f70286da4ddcb83b46bef6/clima-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "da3569ca891737f4bdb44ea2b878b5b6", "sha256": "b737c69d3b4bf65cc2843b0f2559bc86bab278abbfa418c5dab244d0340d83f4" }, "downloads": -1, "filename": "clima-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "da3569ca891737f4bdb44ea2b878b5b6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 9655, "upload_time": "2019-09-03T20:19:20", "url": "https://files.pythonhosted.org/packages/61/19/32ecba3675ca328c3881ac486c967b33ed12a8e10987cb026ff7b088a3c7/clima-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5126259f448808a24c427e3bab924071", "sha256": "0861d15fecda144813a91959a5a186704ab59afb7836852155507ec0d9ca8029" }, "downloads": -1, "filename": "clima-0.2.1.tar.gz", "has_sig": false, "md5_digest": "5126259f448808a24c427e3bab924071", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 10251, "upload_time": "2019-09-03T20:19:28", "url": "https://files.pythonhosted.org/packages/5b/9d/b417b931d8fa0bb7181eacff42fa9e494fc13d187a9cce3c236774720c30/clima-0.2.1.tar.gz" } ], "0.2.3": [ { "comment_text": "", "digests": { "md5": "c90be8a5455a7545496e6dde632d3776", "sha256": "78f0eea5327d3e7c315679bba040b64d8af65e68180d8ed5a1219ab05ad51eaf" }, "downloads": -1, "filename": "clima-0.2.3-py3-none-any.whl", "has_sig": false, "md5_digest": "c90be8a5455a7545496e6dde632d3776", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 10856, "upload_time": "2019-09-05T23:11:56", "url": "https://files.pythonhosted.org/packages/15/57/b7fdf88e91282446cffe6ba434dc73ef8e50dbb2ca9933c7070baabae487/clima-0.2.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "26aa9d2b522725faea3cb7edab541af2", "sha256": "4242ee2131c269df3ea722911453ce1d972223fdf2a7cf7a20865b9ea5b2af54" }, "downloads": -1, "filename": "clima-0.2.3.tar.gz", "has_sig": false, "md5_digest": "26aa9d2b522725faea3cb7edab541af2", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 11217, "upload_time": "2019-09-05T23:11:57", "url": "https://files.pythonhosted.org/packages/aa/13/742e5911fa83c8fcb80d7dc1e776fee28c9502fcdda65403fd2845c227c3/clima-0.2.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c90be8a5455a7545496e6dde632d3776", "sha256": "78f0eea5327d3e7c315679bba040b64d8af65e68180d8ed5a1219ab05ad51eaf" }, "downloads": -1, "filename": "clima-0.2.3-py3-none-any.whl", "has_sig": false, "md5_digest": "c90be8a5455a7545496e6dde632d3776", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 10856, "upload_time": "2019-09-05T23:11:56", "url": "https://files.pythonhosted.org/packages/15/57/b7fdf88e91282446cffe6ba434dc73ef8e50dbb2ca9933c7070baabae487/clima-0.2.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "26aa9d2b522725faea3cb7edab541af2", "sha256": "4242ee2131c269df3ea722911453ce1d972223fdf2a7cf7a20865b9ea5b2af54" }, "downloads": -1, "filename": "clima-0.2.3.tar.gz", "has_sig": false, "md5_digest": "26aa9d2b522725faea3cb7edab541af2", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 11217, "upload_time": "2019-09-05T23:11:57", "url": "https://files.pythonhosted.org/packages/aa/13/742e5911fa83c8fcb80d7dc1e776fee28c9502fcdda65403fd2845c227c3/clima-0.2.3.tar.gz" } ] }