Quickstart

Creating New Project

Having installed colifrapy, initialize a new project with the Scaffolder by typing into your console:

colifrapy new [name-of-project]

options :
    {-a/--author: Author of the project}
    {-o/--organization: Organization of the author}

To test your new project, enter your project’s directory and type:

python [name-of-project].py test

It should launch it and output a header and some strings in the console telling you everything is going to be OK.

Command Line Hub

[name-of-project].py

A colifrapy project relies on a command line hub extending Colifrapy base class. This is the file you have to call in your shell to launch the program. The duty of this hub is to initialize your tool, analyze the arguments given to it and call upon the relevant controller methods.

In fact, this hub can be compared to a basic router for web frameworks.

This is the hub as generated by the scaffolder

# Dependencies
#=============
from colifrapy import Colifrapy
from model.controller import Controller

# Hub
#======
class NameOfYourProject(Colifrapy):

    # From this hub, you can access several things :
    #    self.settings (Settings Instance)
    #    self.log (Logger Instance)
    #    self.opts (Options passed to your hub)
    #    self.controller (Your Controller)

    def launch(self):

        # Welcoming visitors
        self.log.header('main:title')

        # Calling upon the controller
        self.controller.test()

# Launching
#===========
if __name__ == '__main__':
    # By default, the hub will load config/settings.yml
    hub = NameOfYourProject(
        controller=Controller,
        settings_path='path/to/your/settings.yml'
    )
    hub.launch()

Note that if you just want to use colifrapy features but don’t want to be tied to its architecture, you can just use this hub which can access any critical utilities as well as any colifrapy Model would.

Settings

config/settings.yml

The Settings class is the first class loaded by colifrapy to perform its magic. It will parse your settings.yml file and configure your logger, cacher, arguments and every other configuration you want for your application.

# Basic Informations
version: '[project-name] 0.1.0'
description: 'Description of the program.'
usage: 'How to deal with your program'
arguments:
- [ ['-t', '--test'], {'help' : 'Test', 'type' : 'int'} ]
- [ ['positionnal'] ]

# Logger Settings
logger:
    strings: 'config/strings.yml'
    flavor: 'default'

# Generic Settings needed by your program
settings:
    hello: 'world'
    bonjour: 3.4
    hash: {'test' : 2}

Also, note that paths are automatically considered by colifrapy either as relative (config/test.yml) or absolute ones (/var/usr/test.yml).

For further information see Settings.

Arguments

config/settings.yml[‘arguments’]

Settings Usage

Arguments are to be defined as for the python ArgParser class. In fact, the colifrapy Commander class extends the ArgParser one, so if you need complicated things not handled by colifrapy, just use the Commander class like the ArgParser one.

arguments:
- [ ['-t', '--test'], {'help' : 'Test', 'type' : 'int', 'default' : 5} ]
- [ ['-b', '--blue'], {'help' : 'Blue option', 'type' : 'int', 'required' : 'True'} ]
- [ ['some_positionnal_argument'] ]

In the command hub and in your models, you can access the options passed to your commander through self.opts . However, even if those are accessible in models for commodity, only the main hub should use them and one should restrain their usage in models.

Special Arguments

Help, Version, Verbose and Settings

As for standard python command line tool, yours will accept three default arguments you should not try to override (verbose is the only one you can override because it is not one of ArgumentParser defaults):

-v/--version (outputting your program's version)

-h/--help (displaying your program's help)

-V/--verbose (overriding settings to enable the logger to display every messages)

--settings (overriding settings file if needed)

Controller

model/controller.py

The controller is a class whose goal is to call upon other models. The controller itself is in fact also a colifrapy model and is more a convention that something enforced by colifrapy’s code.

The controller is totally optional and just illustrate a way to organize your code. If you don’t want to follow this logic, just don’t pass a controller to your hub instance.

Controller as generated by the scaffolder

# Dependencies
#=============
from colifrapy import Model
from example_model import ExampleModel

# Main Class
#=============
class Controller(Model):

    # Properties
    example_model = None

    def __init__(self):
        self.example_model = ExampleModel()

    # Example of controller action
    def test(self):
        self.log.write('main:controller')
        self.example_model.hello()

Model

model/example_model.py

Models are the bulk of Colifrapy. You can extend them to access your settings and commands easily.

A standard model is generated for you by the Scaffolder when you create a new project.

Minimalist example of a model usage

from colifrapy import Model

class MyModel(Model):
    def test(self):
        print self.settings.hello

m = MyModel()
m.test()
>>> 'world'
Reserved attributes names are:
  • cache (access to cache)
  • log (access to the logger described hereafter)
  • opts (access to the command line options)
  • settings (access to the program’s settings)

Logger

Basic

The logger is the outputting class of colifrapy. It should be loaded with some strings by the settings. If no strings are given, the logger will just output normally the argument strings you give to it.

For full logger documentation, see Logger.

Levels

The logger accepts five levels :
  • INFO (green output)
  • VERBOSE (cyan output)
  • DEBUG (blue output)
  • WARNING (yellow ouput)
  • ERROR (red output)
  • CRITICAL (purple output) –> will throw an exception for you to catch or not

By default, if no level is specified for a message, DEBUG will always be taken.

Strings

config/strings.yml

Colifrapy offers to externalize your strings in order to enable you to quickly modify them if needed, or even translate them easily.

The string format used is a mustache-like one, so variables come likewise : {{some_variable}}

Strings given must follow this yaml layout

main:
    process:

        # String with a variable contained within the mustaches
        start: 'Starting corpus analysis (path : {{path}})//INFO'

        # Simply write two slashes at the end to specify the level of the message
        end: 'Exiting//WARNING'
        test_line_break: '\nBonjour'

    title: 'Colifrapy'

other_string_category:
    test: 'Hello everyone//INFO'
    you:
        can:
            make: 'any levels that you want'
            so: 'you can organize your strings however you need.'

Usage

This is how you would use the logger in a colifrapy model

from colifrapy import Model

class MyModel(Model):
    def test(self):

        # Main method
        #------------

        # Outputting a message
        self.log.write('main:process:end')
        >>> '[WARNING] :: Exiting'

        # Overriding the message level
        self.log.write('main:process:end', level='INFO')
        >>> '[INFO] :: Exiting'



        # Passing variables
        self.log.write('main:protocol:start', {'path' : 'test'})
        >>> '[INFO] :: Starting corpus analysis (path : test)'

        # Variables can be passed to the logger as:
        # a hash, a list, a tuple, a single string or integer or float

        # Examples
        self.log.write('{{variable}}', 'test')
        >>> '[DEBUG] :: test'

        self.log.write('{{var1}} is {{var2}}', ['python', 'cool'])
        >>> '[DEBUG] :: python is cool'



        # When yml file is not specified or if message does not match
        self.log.write('Test string')
        >>> '[DEBUG] :: Test string'

        # Named arguments of write
        # variables --> mixed
        # level --> log level

        # Helper methods
        #---------------

        # Printing a header (yellow color by default)
        self.log.header('main:title', [optional]color)
        >>> Colifrapy
        >>> ---------

        # Write methods shorteners
        self.log.critical(message, vars)
        self.log.error(...)
        self.log.warning(...)
        self.log.info(...)
        self.log.debug(...)
        self.log.verbose(...)

Asking for confirmation

from colifrapy import Model

class MyModel(Model):
    def test(self):

        # Confirmation
        #---------------

        # 'y' will be taken by default in arg 2
        # will return True for y and False for n
        response = self.log.confirm('Are you sure you want to continue?')
        >>> 'Are you sure you want to continue? (Y/n)'
        >>> y --> True

        response = self.log.confirm('Are you sure you want to continue?', 'n')
        >>> 'Are you sure you want to continue? (y/N)'
        >>> n --> False

Getting user input

from colifrapy import Model

class MyModel(Model):
    def test(self):

        # User Input
        #---------------

        response = self.log.input('What up ?')
        >>> 'What up ?'
        >>> 'feeling fine' --> 'feeling fine'

        # You can also provide a lambda to the function as second argument
        # This lambda will affect the input given
        response = self.log.input('What up ?', lambda x: x.upper())
        >>> 'What up ?'
        >>> 'feeling fine' --> 'FEELING FINE'

Cacher

Colifrapy gives you acces, in your hub and models to a caching class able to store data on files for long-term access. There are currently to types of cacher : line and yaml. The first one consist in a text file containing one line read by the cacher while the second archive any python key-value data in a yaml file.

To enable the cacher in the settings.yml file

cache:
    kind: 'line'
    directory: 'config'
    filename: 'last_update.txt'

    # Whether you want the cache to be written each time a value is changed
    # Defaults to False
    auto_write: True

Then in your model

from colifrapy import Model

class MyModel(Model):
    def test(self):

        # Line Cacher
        #-------------

        # Setting cache
        self.cache.set("test")

        # Getting cache
        self.cache.get()
        >>> "test"

        # Yaml Cacher
        #-------------

        # Setting cache
        self.cache.set("one", "red")
        self.cache.set("two:deep", "blue")

        # Getting cache
        self.cache.get("one")
        >>> "red"

        self.cache.get("two")
        >>> {"deep" : "blue"}

        self.cache.get("two:deep")
        >>> "blue"

        self.cache.get
        >>> {"two" : "red", {"deep" : "blue"}}

Note that the path separator for deep levels in yaml is always ”:” in Colifrapy.

For full documentation see Cacher.