Welcome to chuda’s documentation!¶
Chuda is a very simple Python3 framework to create CLI (Command-Line-Interface) tools.
Features¶
- Represent commands and argparse arguments by Python classes
- Handle parsing of a configuration file for you (INI, JSON, or YAML with pyyaml)
- Provide you a configurable logger, and some basic options to quiet/verbose mode
- Provide you a simple interface to run some shell commands
- Signals handling by decorator
The User Guide¶
Installation of chuda¶
This part of the documentation covers the installation of chuda. The first step to using any software package is getting it properly installed.
$ pipenv install chuda¶
To install chuda, simply run this simple command in your terminal of choice:
$ pipenv install chuda
If you don’t have pipenv installed, head over to the Pipenv website for installation instructions. Or, if you prefer to just use pip and don’t have it installed, this Python installation guide can guide you through the process.
Get the Source Code¶
chuda is developed on GitHub, where the code is always available.
You can either clone the public repository:
$ git clone git://github.com/Varkal/chuda.git
Or, download the tarball:
$ curl -OL https://github.com/Varkal/chuda/tarball/master
# optionally, zipball is also available (for Windows users).
Once you have a copy of the source, you can embed it in your own Python package, or install it into your site-packages easily:
$ cd chuda
$ pip install .
Quickstart¶
Eager to get started? This page gives a good introduction in how to get started with chuda.
First, make sure that:
- chuda is installed
- chuda is up-to-date
Let’s get started with some simple examples.
Hello World¶
Create an app with chuda is very simple
from chuda import App, autorun
@autorun() # Equivalent to if __name__ == "__main__"
class HelloWorldApp(App):
def main(self):
self.logger.info("Hello Word")
Parse a config file¶
Chuda will handle for you the parsing of a configuration file
For example, with this configuration file:
# ./config.ini
[hello]
name = John
This code will parse it automatically:
from chuda import App, autorun
@autorun()
class ConfigApp(App):
config_path = ["./config.ini", "../config.ini"]
def main(self):
self.logger.info("Hello {}".format(self.config["hello"]["name"]))
chuda can handle ini (default), json and yaml files (only if pyyaml is installed).
You must specified which parser will be used with the config_parser
attribute
As you can see, config_path
is a list.
Chuda will try to load each file in the order in which they have been declared until it find one that exists.
Handle arguments¶
Chuda gives you a declarative interface to add options and parameters to your applications
from chuda import App, autorun, Option, Parameter
@autorun()
class ArgumentsApp(App):
arguments = [
Option(["--language"], default="en", choices=["en", "fr"]),
Option(["--polite", "-p"], action="store_true"),
Parameter("name"),
]
def main(self):
salutation = ""
if self.arguments.language == "en":
salutation = "Hello " if self.arguments.polite else "Hi "
elif self.arguments.language == "fr":
salutation = "Bonjour " if self.arguments.polite else "Salut "
salutation += self.arguments.name
self.logger.info(salutation)
An Option
represent an UNIX style option (“e.g: git commit -m stuff”)
A Parameter
represent a simple parameter (“e.g: git checkout stuff”)
Both takes the same parameters as the add_argument()
method.
By default, chuda proposes three basic options :
-q
/--quiet
: The logger stop logging-v
/--verbose
: The logging level is lowered to debug--version
: print the content of theversion
attribute and exit
Create subcommands¶
Chuda gives you a very simple way to create subcommands in your
application by defining Command
subclasses
from chuda import App, autorun, Command
# Should be split in mutiple files
class FirstCommand(Command):
command_name = "first"
description = "this is the first command"
def main(self):
self.logger.info("first from {}".format(self.app.app_name))
class SecondCommand(Command):
command_name = "second"
description = "this is the second command"
def main(self):
self.logger.info("second from {}".format(self.app.app_name))
@autorun()
class SubCommandsApp(App):
app_name = "my_app"
subcommands = [
FirstCommand,
SecondCommand
]
subcommands
is transformed to a dictionnary at runtime. So, if you need to call a subcommand from
an other subcommand :
from chuda import App, autorun, Command
# Should be split in mutiple files
class FirstCommand(Command):
command_name = "first"
description = "this is the first command"
def main(self):
self.logger.info("first from {}".format(self.app.app_name))
class SecondCommand(Command):
command_name = "second"
description = "this is the second command"
def main(self):
self.app.subcommands["first"].run()
@autorun()
class SubCommandsApp(App):
app_name = "my_app"
subcommands = [
FirstCommand,
SecondCommand
]
Add plugins¶
Chuda apps encourage separation of concerns with a system of plugins
A plugin is created by extend the Plugin
class
from chuda import App, autorun, Plugin
import requests
class HttpPlugin(Plugin):
base_url = None
def on_create(self):
self.enrich_app("http", self)
def on_config_read(self):
try:
self.base_url = self.app.config["base_url"]
except KeyError:
self.base_url = "http://www.example.com"
def get_root(self):
return requests.get(self.base_url)
@autorun()
class HttpApp(App):
http = None
plugins = [
HttpPlugin()
]
def main(self):
response = self.http.get_root()
self.logger.info(response.text)
Plugins provides mutliple methods to execute code at key points
in the lifecycle of the application. See Plugin
documentation for more informations
The Api Guide¶
Developer Interface¶
Application and Commands¶
-
class
chuda.app.
App
[source]¶ Base class for create an application in chuda
-
app_name
= ''¶ Name of the application, show in the help and version strings
-
config
= {}¶ The configuration file will be loaded here
-
config_parser
= 'ini'¶ The parser used to parse the configuration file. Possible values are: ini, json, yaml
-
config_path
= []¶ Acceptable paths to find the configuration file. Stop searching on the first one exists
-
description
= ''¶ Description of the command. Print in help
-
merge_arguments_in_subcommands
= True¶ Should
arguments
be merged in subcommands instead of being accesibble globally ?
-
parser
= None¶ Instance of
ArgumentParser
-
plugins
= []¶ List of Plugins
-
subcommands
= []¶ List of
Command
-
version
= '0.0.1'¶ version of your application. Display withe –version flag
-
-
class
chuda.commands.
Command
[source]¶ A subcommand for multicommands cli tool
-
command_name
= None¶ Name of the command, use on the command-line (like “add”, in “git add”)
-
use_subconfig
= False¶ Should use config_parser and config_path to generate a config for this command
-
config
= {}¶ The configuration file will be loaded here
-
config_parser
= 'ini'¶ The parser used to parse the configuration file. Possible values are: ini, json, yaml
-
config_path
= []¶ Acceptable paths to find the configuration file. Stop searching on the first one exists
-
merge_parent_arguments
= True¶ Should parent arguments be merge with local arguments ? True by default.
-
Arguments¶
-
class
chuda.arguments.
Argument
(name=None, action='store', nargs=None, const=None, default=None, type=None, choices=None, required=None, help=None, metavar=None, dest=None)[source]¶ Abstract parent class for
Option
andParameter
.For attributes who are not documented here, please see
add_argument()
documentation-
convert_to_argument
()[source]¶ Convert the Argument object to a tuple use in
add_argument()
calls on the parser
-
-
class
chuda.arguments.
Option
(name=None, action='store', nargs=None, const=None, default=None, type=None, choices=None, required=None, help=None, metavar=None, dest=None)[source]¶ Represent an option on the command-line (
mycommand --whatever
)-
get_default_name
()[source]¶ Return the default generated name to store value on the parser for this option.
eg. An option [‘-s’, ‘–use-ssl’] will generate the use_ssl name
Returns: the default name of the option Return type: str
-
convert_to_argument
()[source]¶ Convert the Argument object to a tuple use in
add_argument()
calls on the parser
-
-
class
chuda.arguments.
Parameter
(name=None, action='store', nargs=None, const=None, default=None, type=None, choices=None, required=None, help=None, metavar=None, dest=None)[source]¶ Represent a parameter on the command-line (
mycommand whatever
)-
convert_to_argument
()[source]¶ Convert the Argument object to a tuple use in
add_argument()
calls on the parser
-
Plugins¶
-
class
chuda.plugins.
Plugin
[source]¶ Class represent a Plugin for a Chuda application A plugin can register hooks for steps in the application lifecycle or enrich the app with new properties
Decorators¶
Shell¶
-
class
chuda.shell.
Runner
(logger=None, cwd=None)[source]¶ Factory for
ShellCommand
-
run
(command, block=True, cwd=None, stdin=-1, stdout=-1, stderr=-1)[source]¶ Create an instance of
ShellCommand
and run itParameters: - command (str) –
ShellCommand
- block (bool) – See
ShellCommand
- cwd (str) – Override the runner cwd. Useb by the
ShellCommand
instance
- command (str) –
-
-
class
chuda.shell.
ShellCommand
(command, logger, cwd=None, block=True, stdin=-1, stdout=-1, stderr=-1)[source]¶ DEPRECATED: Please use sh.py instead
Abstraction layer for shell subprocess
You can disable stdout, stdin, stderr
-
error
¶ everything the command will write on stderr will be here
Type: str|list
-
output
¶ everything the command will write on stdout will be here
Type: str|list
-
writer
¶ Instance of
TextIOWrapper
plugged on stdinType: TextIOWrapper
-
run
()[source]¶ Run the shell command
Returns: return this ShellCommand instance for chaining Return type: ShellCommand
-
send
(value)[source]¶ Send text to stdin. Can only be used on non blocking commands
Parameters: value (str) – the text to write on stdin Raises: TypeError
– If command is blockingReturns: return this ShellCommand instance for chaining Return type: ShellCommand
-
poll_output
()[source]¶ Append lines from stdout to self.output.
Returns: The lines added since last call Return type: list
-
poll_error
()[source]¶ Append lines from stderr to self.errors.
Returns: The lines added since last call Return type: list
-
wait_for
(pattern, timeout=None)[source]¶ Block until a pattern have been found in stdout and stderr
Parameters: - pattern (
Pattern
) – The pattern to search - timeout (int) – Maximum number of second to wait. If None, wait infinitely
Raises: TimeoutError
– When timeout is reach- pattern (
-