Full precept documentation

Usage

Install

Install with pip:

pip install precept

Write async console applications

Precept comes with many classes and functions to build async applications, the main class consist of Precept which you subclass to create your application. Methods of this class decorated with Command are automatically added as sub command to the application.

Basic example defining an echo command:

from precept import Precept, Command, Argument

class App(Precept):
    @Command(
        Argument('name'),
    )
    async def echo(self, name):
        print(f'Hello {name}')

Then call from the terminal like this: app echo bob -> Prints Hello bob

Note

If no command was supplied, main will be called instead.

Starting the application

To create a console application from a precept app you need to add function that will create an instance of your precept subclass and call start then add it to setup.py.

app.py
def cli():
    App().start()
setup.py
from setuptools import setup

setup(
    entry_points: {
        'console_scripts': ['cli = app:cli']
    }
)

You can also create a global instance of the app and assign the entrypoint to it’s start method

Configs

Precept comes with a built in config system, create a subclass of Config with members as config. You can nest classes definition to create sub sections.

Example

from precept import Config, Nestable, ConfigProperty

class MyConfig(Config):
    my_config = ConfigProperty(comment='comment', config_type=str)

    class SubConfig(Nestable):
        nested = ConfigProperty(default='Default')

    sub_config: SubConfig  # A class member will be auto created.

Then you use it in the precept class like so:

from precept import Precept

class MyApp(Precept):
    config = MyConfig()

Config file

To use the config with files, add a config_file argument to precept init:

from precept import Precept

class MyApp(Precept):
    def __init__(self):
        super().__init__(
            config_file='config.yml',
        )

Precept will automatically add a --config-file global argument for the user to override.

It will also add a dump-config command to dump the default config for first use.

Note

The config_file argument can also be a list, in which case the first file found will be used.

Config format

Precept can read and write three config format, default being yaml:

ConfigFormat

  • yaml

  • ini

  • json, doesn’t support comments.

See also

Concepts

Concepts

These concepts can be used to extend and interact with precept applications.

Events

Generic asyncio event consumer system.

The Precept instance and services both comes with an event dispatcher (events member). You can subscribe to events and handle them when they happen.

Subscribe to events

Subscribe to events that are dispatched.

app.events.subscribe('cli_started', lambda e: print('Started'))

Dispatch events

Send events with optional payload as keyword arguments.

app.events.dispatch('my_events', something='foo')

cli events

These events are available when starting the application with start.

Cli events

Event

Description

before_cli_start

Called before everything else.

cli_parsed

Called after parsing the arguments and before the command start, payload with the arguments.

cli_started

The command has started, this is called at the same time.

cli_stopped

The command has stopped and the application will quit after.

Services

Service’s runs alongside the precept application, they are started and stopped at the same time when calling start().

Service events

Services comes with three auto events starting with the service name. If a service is called dummy, it will get:

  • dummy_setup, called with the running application before starting.

  • dummy_start, started before the application.

  • dummy_stop, stopped after the application.

Note

If the application is not started with start, you need to call the services methods:

  • setup_services

  • start_services

  • stop_services

See also

Plugins

Plugins automatically connect to precept applications during initialisation.

They have one method, setup(), which takes the application as argument you can use to set variables.

To add a plugin, you need to set it in setup.py, the entrypoint key needs to be the snake cased version of prog_name variable of the precept application.

from setuptools import setup

setup(
    entry_points={
        'precept_app.plugins': ['my_plugin = plug:plugin']
    }
)

See also

Application list

These applications are created with precept:

  • aiocast, stream videos to chromecast devices.

  • top-drawer, generate valid pypi/npm package name from synonyms.

To add your application to this list, modify docs/applications.rst and open a PR.

precept

precept package

class precept.Argument(*flags: str, type: Optional[type] = None, help: Optional[str] = None, choices: Optional[Iterable] = None, default: Optional[Any] = None, nargs: Optional[Union[str, int]] = None, action: Optional[str] = None, required: Optional[bool] = None, metavar: Optional[str] = None, dest: Optional[str] = None)[source]

Bases: precept._immutable.ImmutableDict

Argument of a Command, can either be optional or not depending on the flags

__init__(*flags: str, type: Optional[type] = None, help: Optional[str] = None, choices: Optional[Iterable] = None, default: Optional[Any] = None, nargs: Optional[Union[str, int]] = None, action: Optional[str] = None, required: Optional[bool] = None, metavar: Optional[str] = None, dest: Optional[str] = None)[source]
Parameters
  • flags – How to call the argument, prefixing with - makes the argument a keyword. Example: '-d', '--date' make the variable available as date, but can be supplied as -d from the cli.

  • type – The type of the variable to cast to, default to str.

  • help – Description to go along with

  • choices – The available choices to choose from.

  • default – The value to take if not supplied.

  • nargs – Number of times the argument can be supplied.

  • action – What to do with the argument.

  • required – Makes a keyword argument required.

  • metavar – Name in help.

  • dest – The name of the variable to add the value to once parsed.

action
choices
default
dest
property flag_key
flags
help
metavar
nargs
register(parser)[source]

Register a virtual subclass of an ABC.

Returns the subclass, to allow usage as a class decorator.

required
type
class precept.AsyncExecutor(loop=None, executor=None, max_workers=None)[source]

Bases: object

Execute functions in a Pool Executor

__init__(loop=None, executor=None, max_workers=None)[source]
Parameters
  • loop – asyncio event loop.

  • executor – Set to use an already existing PoolExecutor, default to a new ThreadPoolExecutor if not supplied.

  • max_workers – Max workers of the created ThreadPoolExecutor.

async execute(func, *args, **kwargs)[source]

Execute a sync function asynchronously in the executor.

Parameters
  • func – Synchronous function.

  • args – Argument to give to the function.

  • kwargs – Keyword arguments to give to the function

Returns

async execute_with_lock(func, *args, **kwargs)[source]

Acquire lock before executing the function.

Parameters
  • func – Synchronous function.

  • args

  • kwargs

Returns

wraps(func)[source]

Wraps a synchronous function to execute in the pool when called, making it async.

Parameters

func – The function to wraps

Returns

Async wrapped function.

class precept.AutoNameEnum(value)[source]

Bases: enum.Enum

An enumeration.

class precept.Command(*arguments: precept._cli.Argument, name: Optional[str] = None, description: Optional[str] = None, help: Optional[str] = None, auto: bool = False, services: Optional[List[precept._services.Service]] = None)[source]

Bases: object

Command decorator, methods of CliApp subclasses decorated with this gets a sub-command in the parser.

Wrapped methods will gets the arguments by the Argument flag.

__init__(*arguments: precept._cli.Argument, name: Optional[str] = None, description: Optional[str] = None, help: Optional[str] = None, auto: bool = False, services: Optional[List[precept._services.Service]] = None)[source]
arguments: Iterable[precept._cli.Argument]
property command_name
description: str
register(subparsers)[source]
class precept.Config(config_format: precept._configs.ConfigFormat = ConfigFormat.TOML, root_name='config')[source]

Bases: precept._configs.Nestable

Root config class, assign ConfigProperties as class members.

__init__(config_format: precept._configs.ConfigFormat = ConfigFormat.TOML, root_name='config')[source]
property config_format: precept._configs.ConfigFormat
read_dict(data: dict)[source]
read_file(path: str)[source]
save(path: str)[source]
class precept.ConfigFormat(value)[source]

Bases: precept._tools.AutoNameEnum

Available formats to use with configs.

  • TOML provided by tomlkit, supports comments and more complex types.

  • YML provided by ruamel.yaml, supports comments and more complex types.

  • JSON stdlib, no support for comments and types.

  • INI stdlib, support for comments.

INI = 'ini'
JSON = 'json'
TOML = 'toml'
YML = 'yml'
serializer(config)[source]
class precept.ConfigProperty(default=None, comment=None, config_type=None, environ_name=None, auto_environ=False, name=None, auto_global=False, global_name=None)[source]

Bases: object

__init__(default=None, comment=None, config_type=None, environ_name=None, auto_environ=False, name=None, auto_global=False, global_name=None)[source]
class precept.ImmutableDict(**kwargs)[source]

Bases: collections.abc.Mapping

__init__(**kwargs)[source]
class precept.ImmutableMeta(name, bases, attributes)[source]

Bases: abc.ABCMeta

class precept.ImmutableProp[source]

Bases: object

class precept.Nestable(parent=None, parent_len=0)[source]

Bases: collections.abc.Mapping

__init__(parent=None, parent_len=0)[source]
get_prop_paths(parent='')[source]
get_root(current=None)[source]
class precept.Plugin[source]

Bases: object

Plugin’s are automatically added to a precept application upon installation.

Set the entry point in setup to register the plugin:

entry_point = {‘{app_name}.plugins’: [‘plugin = my_plugin:plugin’]}

name: str = ''
async setup(application)[source]

Setup the plugin

Parameters

application (precept.Precept) – The running precept application.

Returns

class precept.Precept(config_file: Optional[Union[str, List[str]]] = None, loop=None, executor=None, executor_max_workers=None, add_dump_config_command=False, help_formatter=<class 'precept._cli.CombinedFormatter'>, logger_level=20, logger_fmt=None, logger_datefmt=None, logger_stream=<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, logger_colors=None, logger_style='%', services: Optional[List[precept._services.Service]] = None, print_version: bool = True)[source]

Bases: object

Auto cli generator, methods decorated with Command will have a corresponding sub-command in the cli application.

Commands will get the arguments named as the last element of the command flags.

Override main method for root handler, it gets all the global_arguments

__init__(config_file: Optional[Union[str, List[str]]] = None, loop=None, executor=None, executor_max_workers=None, add_dump_config_command=False, help_formatter=<class 'precept._cli.CombinedFormatter'>, logger_level=20, logger_fmt=None, logger_datefmt=None, logger_stream=<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, logger_colors=None, logger_style='%', services: Optional[List[precept._services.Service]] = None, print_version: bool = True)[source]
Parameters
  • config_file – Path to the default config file to use. Can be specified with --config-file

  • loop – Asyncio loop to use.

  • executor – concurrent executor to use.

  • add_dump_config_command – Add a dump-config command.

  • help_formatter – The cli formatter to use.

  • logger_level – Set logger level when setting up logging.

  • logger_fmt – The format of the logger.

  • logger_datefmt – Date format of the logger.

  • logger_stream – The stream to print the logs.

  • logger_colors – Dictionary with key logger level name and values of bg/fg/style dict.

  • logger_style – The symbol to use for formatting.

  • services – List of global services to start with the program.

  • print_version – Print the version & name of the app before start.

config: precept._configs.Config = None
config_class = None
property config_path
default_configs: dict = {}
global_arguments = []
async main(**kwargs)[source]

Handler when no command has been entered. Gets the globals arguments.

Parameters

kwargs – Global arguments.

Returns

prog_name = ''
async setup_plugins()[source]

Load and setup the registered plugins.

To register a plugin, subclass Plugin and instantiate then add to setup.py entry_points:

‘{app_name}.plugins’: [‘my_plugin = plugin_module:plugin’]

Returns

async setup_services(command: Optional[precept._cli.Command] = None)[source]

Setup the services for the command or the main application.

Parameters

command – The command that was run.

Returns

start(args=None)[source]

Start the application loop.

Returns

async start_services(command: Optional[precept._cli.Command] = None)[source]

Start the services, automatically called by start.

If the application if run with another method you can call this to start the global services without the command argument.

Parameters

command – The command that was run.

Returns

async stop_services(command: Optional[precept._cli.Command] = None)[source]

Stop the services, automatically called by start.

Call this if your application is not run with start and you have running services.

Parameters

command – The command that was run.

Returns

version = '0.0.1'
class precept.Service(events: Optional[precept.events._dispatcher.EventDispatcher] = None)[source]

Bases: object

Service’s runs alongside the main application.

Communicate via events.

Events
  • {name}_setup when added to services.

  • {name}_start after calling start.

  • {name}_stop after calling stop.

__init__(events: Optional[precept.events._dispatcher.EventDispatcher] = None)[source]
name: str = 'service'
async setup(application)[source]

Called when added to services.

Use this to set events and other post initialization that may need the application instance.

Parameters

application (precept.Precept) – Precept application

Returns

async start()[source]

Start the service.

Returns

async stop()[source]

Stop the service.

Returns

precept.config_factory(data, root=None, key=None)[source]
precept.is_windows()[source]

Errors

exception precept.errors.ConfigError[source]

Bases: precept.errors.PreceptError

Error in the config system.

exception precept.errors.ImmutableError[source]

Bases: precept.errors.PreceptError

Immutable properties cannot change

exception precept.errors.PreceptError[source]

Bases: Exception

Base exception thrown by precept

Subpackages

precept.console
class precept.console.KeyHandler(handlers, loop=None, default_handler=None)[source]

Bases: object

__init__(handlers, loop=None, default_handler=None)[source]
async handle()[source]
print_keys(file=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>)[source]
read()[source]
stop()[source]
class precept.console.Keys[source]

Bases: object

BACKSPACE = <Key 'backspace'>
CTRL_A = <Key 'ctrl-a'>
CTRL_ALT_A = <Key 'ctrl-alt-a'>
CTRL_ALT_DEL = <Key 'ctrl-alt-del'>
CTRL_B = <Key 'ctrl-b'>
CTRL_C = <Key 'ctrl-c'>
CTRL_D = <Key 'ctrl-d'>
CTRL_E = <Key 'ctrl-e'>
CTRL_F = <Key 'ctrl-f'>
CTRL_Z = <Key 'ctrl-z'>
DELETE = <Key 'delete'>
DOWN = <Key 'down'>
END = <Key 'end'>
ENTER = <Key 'enter'>
ESCAPE = <Key 'escape'>
F1 = <Key 'F1'>
F10 = <Key 'F10'>
F11 = <Key 'F11'>
F12 = <Key 'F12'>
F2 = <Key 'F2'>
F3 = <Key 'F3'>
F4 = <Key 'F4'>
F5 = <Key 'F5'>
F6 = <Key 'F6'>
F7 = <Key 'F7'>
F8 = <Key 'F8'>
F9 = <Key 'F9'>
HOME = <Key 'home'>
INSERT = <Key 'insert'>
LEFT = <Key 'left'>
RIGHT = <Key 'right'>
SPACE = <Key 'space'>
SPECIAL_KEYS = (<Key 'space'>, <Key 'backspace'>, <Key 'enter'>, <Key 'escape'>, <Key 'insert'>, <Key 'end'>, <Key 'home'>, <Key 'delete'>, <Key 'down'>, <Key 'up'>, <Key 'left'>, <Key 'right'>, <Key 'F1'>, <Key 'F2'>, <Key 'F3'>, <Key 'F4'>, <Key 'F5'>, <Key 'F6'>, <Key 'F7'>, <Key 'F8'>, <Key 'F9'>, <Key 'F10'>, <Key 'F11'>, <Key 'F12'>, <Key 'ctrl-c'>, <Key 'ctrl-a'>, <Key 'ctrl-alt-a'>, <Key 'ctrl-alt-del'>, <Key 'ctrl-b'>, <Key 'ctrl-d'>, <Key 'ctrl-e'>, <Key 'ctrl-f'>, <Key 'ctrl-z'>)
UP = <Key 'up'>
classmethod get_key(value, default=None)[source]
keys = {'\x01': <Key 'ctrl-a'>, '\x02': <Key 'ctrl-b'>, '\x03': <Key 'ctrl-c'>, '\x04': <Key 'ctrl-d'>, '\x05': <Key 'ctrl-e'>, '\x06': <Key 'ctrl-f'>, '\r': <Key 'enter'>, '\x1a': <Key 'ctrl-z'>, '\x1b': <Key 'escape'>, '\x1b\x01': <Key 'ctrl-alt-a'>, '\x1bO15~': <Key 'F5'>, '\x1bO17~': <Key 'F6'>, '\x1bO18~': <Key 'F7'>, '\x1bO19~': <Key 'F8'>, '\x1bO20~': <Key 'F9'>, '\x1bO21~': <Key 'F10'>, '\x1bO23~': <Key 'F11'>, '\x1bO24~': <Key 'F12'>, '\x1bOP': <Key 'F1'>, '\x1bOQ': <Key 'F2'>, '\x1bOR': <Key 'F3'>, '\x1bOS': <Key 'F4'>, '\x1b[2~': <Key 'insert'>, '\x1b[3^': <Key 'ctrl-alt-del'>, '\x1b[3~': <Key 'delete'>, '\x1b[A': <Key 'up'>, '\x1b[B': <Key 'down'>, '\x1b[C': <Key 'right'>, '\x1b[D': <Key 'left'>, '\x1b[F': <Key 'end'>, '\x1b[H': <Key 'home'>, ' ': <Key 'space'>, '0': <Key '0'>, '1': <Key '1'>, '2': <Key '2'>, '3': <Key '3'>, '4': <Key '4'>, '5': <Key '5'>, '6': <Key '6'>, '7': <Key '7'>, '8': <Key '8'>, '9': <Key '9'>, 'A': <Key 'A'>, 'B': <Key 'B'>, 'C': <Key 'C'>, 'D': <Key 'D'>, 'E': <Key 'E'>, 'F': <Key 'F'>, 'G': <Key 'G'>, 'H': <Key 'H'>, 'I': <Key 'I'>, 'J': <Key 'J'>, 'K': <Key 'K'>, 'L': <Key 'L'>, 'M': <Key 'M'>, 'N': <Key 'N'>, 'O': <Key 'O'>, 'P': <Key 'P'>, 'Q': <Key 'Q'>, 'R': <Key 'R'>, 'S': <Key 'S'>, 'T': <Key 'T'>, 'U': <Key 'U'>, 'V': <Key 'V'>, 'W': <Key 'W'>, 'X': <Key 'X'>, 'Y': <Key 'Y'>, 'Z': <Key 'Z'>, 'a': <Key 'a'>, 'b': <Key 'b'>, 'c': <Key 'c'>, 'd': <Key 'd'>, 'e': <Key 'e'>, 'f': <Key 'f'>, 'g': <Key 'g'>, 'h': <Key 'h'>, 'i': <Key 'i'>, 'j': <Key 'j'>, 'k': <Key 'k'>, 'l': <Key 'l'>, 'm': <Key 'm'>, 'n': <Key 'n'>, 'o': <Key 'o'>, 'p': <Key 'p'>, 'q': <Key 'q'>, 'r': <Key 'r'>, 's': <Key 's'>, 't': <Key 't'>, 'u': <Key 'u'>, 'v': <Key 'v'>, 'w': <Key 'w'>, 'x': <Key 'x'>, 'y': <Key 'y'>, 'z': <Key 'z'>, '\x7f': <Key 'backspace'>}
precept.console.colorize(text, bg=None, fg=None, style=None)[source]
precept.console.format_table(data, formatting=None)[source]
precept.console.goto_xy(stream, x, y)[source]
precept.console.print_table(data, formatting=None, file=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>)[source]
async precept.console.progress_bar(value_func, max_value, value_formatter=None, include_value=True, dents=50, sleep_time=0.005, file=None, full_symbol='#', empty_symbol='-', start_symbol='[', end_symbol=']')[source]
async precept.console.spinner(condition, sleep_time=0.25, message='', fg='\x1b[37m', bg=None, symbols=('|', '/', '-', '\\', '|', '/', '-', '\\'))[source]
precept.events
class precept.events.Event(name: str, payload: dict)[source]

Bases: object

Event with payload and stop property.

__init__(name: str, payload: dict)[source]
class precept.events.EventDispatcher[source]

Bases: object

Dispatch events to subscribers functions.

__init__()[source]
async dispatch(event: str, **payload)[source]

Dispatch an event with optional payload data.

Parameters
  • event – Name of the event.

  • payload – Data of the event.

Returns

subscribe(event: str, func)[source]

Subscribe func to execute every time event is dispatched.

Parameters
  • event – The event to subscribe to.

  • func – The func to call when event is dispathed.

Returns

class precept.events.PreceptEvent(value)[source]

Bases: precept._tools.AutoNameEnum

Precept cli events.

BEFORE_CLI_START = 'before_cli_start'
CLI_PARSED = 'cli_parsed'
CLI_STARTED = 'cli_started'
CLI_STOPPED = 'cli_stopped'

License

MIT License

Copyright (c) 2020 Philippe Duval

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Changelog

Versions follow semver.

warning

Expect breaking changes between minor versions prior to 1.0.0 while the api stabilize.

[0.6.7]

Fixed

  • bug

    Fixed Python 10 support.

[0.6.6]

Fixed

  • bug

    Fixed reading toml config file with more keys than defined in the config class.

  • bug

    Fixed default config property auto_environ to false.

[0.6.5]

Fixed

  • bug

    Fix Toml dump config of type bool with a default and a comment with less than 40 characters. #22

  • bug

    Fix Toml dump config of type str with no comment and no default. #23

  • bug

    Use repr in case of error instead of __class__.__name__ which might exist if the given type is wrong.

[0.6.4]

Fixed

bug

Fix config nestable not updated from file.

[0.6.3]

Fixed

  • bug

    Fix config type.

  • construction

    Add KeyboardInterrupt event in case some resources need to be cleaned up.

  • hammer

    Add global name argument to config property for use with auto global.

  • construction

    Add raw_args to cli attributes.

  • hammer

    Allow for start arguments to be a string command.

[0.6.2]

Fixed

  • bug

    Fix config multi instance

[0.6.1]

Fixed

  • bug

    Fix config order of reading (argument > code > file).

  • bug

    Fix comment below variables in toml config format.

  • bug

    Fix plugin registration for running loops instantiation.

  • bug

    Fix config_class instantiation

  • bug

    Fix config from cli arguments with default value.

  • bug

    Fix toml null values.

[0.6.0]

Added

  • sparkles

    Add TOML config format.

Changed

  • hammer

    Change default config format to TOML.

  • bug

    Change config_format to property auto updating serializer.

[0.5.1]

Fixed

  • hammer

    Removed star imports.

[0.5.0]

Changed

  • hammer

    Allow configs to be set on the instance.

  • hammer

    Add print_version option.

Added

  • sparkles

    Add services to run alongside applications and commands.

  • sparkles

    Add plugin system.

[0.4.0]

Changed

  • construction

    Executor default to ThreadPoolExecutor.

  • construction

    Export AsyncExecutor.

Added

  • sparkles

    Add Executor wraps

  • construction

    Add Executor max workers argument

  • sparkles

    Add Event & Dispatcher

  • sparkles

    Add cli events.

[0.3.1]

Fixed

  • bug

    Fix multiple logging handlers registered during tests.

  • construction

    Add options for configuring the logger.

[0.3.0]

Changed

  • feet

    Moved console related functions to console package.

  • feet

    Moved keyhandler to console package.

Added

  • sparkles

    console.progress_bar

  • sparkles

    Add auto arguments from command functions.

  • sparkles

    Add auto global argument for config.

  • construction

    Add symbols argument to console.spinner

Fixed

  • bug

    Config get_root return self if root.

[0.2.1]

Fixed

  • hammer

    Allow config instance to be set directly.

  • hammer

    Add root config class docstring as the first config comment.

[0.2.0]

Changed

  • boom

    Rename CliApp -> Precept.

  • hocho

    Removed old ConfigProp.

  • hocho

    Removed Precept.configs, now Precept.config with new config api.

Added

  • sparkles

    Command help from docstring.

  • construction

    Add help formatter argument.

  • sparkles

    Nested commands support, wrap a class into a Command.

  • sparkles

    Config class

    • Comment support

    • Ini/yaml/json format choices

    • value from environ

    • nestable config attribute lookup

    • config factory.

  • construction

    Errors classes: PreceptError, ConfigError, ImmutableError

[0.1.1]

Fixed

  • KeyHandler fixes:

    • Remove no handler print.

    • Add Keys class with most specials keys.

    • Handle ctrl-c by default.

  • Fix single argument casing (auto convert to snake_case).

[0.1.0]

Added

  • Added global --log-file option

  • Added execute_with_lock to AsyncExecutor (CliApp.executor)

  • Added add_dump_config_command, adds prog dump-config outfile command to output the currently used config file.

  • Added ImmutableDict, immutable mapping with auto attribute lookup from __init__ arguments.

  • Added goto_xy, getch.

  • Added KeyHandler, reads each sys.stdin keys as they come and apply a function according to the key.

Changed

  • Default main command on CliApp now async.

  • Removed _ prefix from prog_name, global_arguments, default_configs, version.

  • Argument and configs are now ImmutableDict.

  • Removed kwargs from Argument, all parser.add_argument parameters now available as key argument.

  • config_file can be a list of paths to check for existence in order.

[0.0.2]

Fixed

  • Added help to Command

  • Set spinner default background to None

[0.0.1]

  • Initial release

Contributing to Precept

Getting Started

  • Fork and clone the repo

  • Create, activate & install dependencies

    $ python -m venv venv
    $ . venv/bin/activate
    $ pip install -r requirements.txt
    

Submit a PR with your changes.

Coding style

Linters

  • pylint: $ pylint precept tests

  • flake8: $ flake8 dazzler tests

Commit messages

Prefix your commit messages with an emoji according to this list:

Commit type

Emoji

Initial commit

tada

:tada:

Version tag

bookmark

:bookmark:

New feature

sparkles

:sparkles:

Bugfix

bug

:bug:

Metadata

card_index

:card_index:

Documentation

books

:books:

Documenting source code

bulb

:bulb:

Performance

racehorse

:racehorse:

Cosmetic

lipstick

:lipstick:

Tests

rotating_light

:rotating_light:

Adding a test

white_check_mark

:white_check_mark:

General update

construction

:construction:

Improve format/structure

art

:art:

Move code

feet

:feet:

Refactor code

hammer

:hammer:

DRY up code

camel

:camel:

Removing code/files

hocho

:hocho:

Continuous Integration

green_heart

:green_heart:

Security

lock

:lock:

Upgrading dependencies

arrow_up

:arrow_up:

Downgrading dependencies

arrow_down

:arrow_down:

Lint

shirt

:shirt:

Translation

alien

:alien:

Text

pencil

:pencil:

Critical hotfix

ambulance

:ambulance:

Deploying stuff

rocket

:rocket:

Fixing on MacOS

apple

:apple:

Fixing on Linux

penguin

:penguin:

Fixing on Windows

checkered_flag

:checkered_flag:

Adding CI build system

construction_worker

:construction_worker:

Analytics or tracking code

chart_with_upwards_trend

:chart_with_upwards_trend:

Removing a dependency

heavy_minus_sign

:heavy_minus_sign:

Adding a dependency

heavy_plus_sign

:heavy_plus_sign:

Docker

whale

:whale:

Configuration files

wrench

:wrench:

Bundles update

package

:package:

Merging branches

twisted_rightwards_arrows

:twisted_rightwards_arrows:

Bad code / need improv.

hankey

:hankey:

Reverting changes

rewind

:rewind:

Breaking changes

boom

:boom:

Code review changes

ok_hand

:ok_hand:

Accessibility

wheelchair

:wheelchair:

Move/rename repository

truck

:truck:

Other

Be creative