Welcome to Boussole’s documentation!

Commandline interface to build Sass projects using libsass-python.

Features

  • Stand on LibSass which is very fast;
  • Per project configuration so you can use it once to compile all of your Sass files from a same project;
  • Simple and useful command line;
  • Watch mode for no waste of time during web design integration;
  • Full Python stack, no Ruby or Node.js stuff needed;
  • Expose a Core API to use it from Python code;
  • Support for Python2.7 and Python3.x;

Dependancies

User’s Guide

Install

pip install boussole

It should be safe enough to install it on Linux, MacOSX and Windows until you have the right environment (needed devel libs, etc..).

Note

Because some requirements need to compile some C modules, this may takes some minutes to install Boussole again for each of your projects under their own virtual environment.

Also Libsass compatibility should be safe enough for your future projects.

So we recommend you to install this software at your system level if installation speed is important to you.

Tutorial

Once Boussole is correctly installed, you will be able to start a project to work on.

  1. Go to a directory where you want to start a new project then execute command:

    boussole startproject
    
  2. Answer to the questions (let the default values for this sample):

    Project base directory [.]:
    Settings file name [settings.json]:
    Sources directory [scss]:
    Target directory [css]:
    Settings format name [json]:
    
  3. Write some Sass file into scss directory;

  4. From your Sass project directory (where belong the settings.json file) just execute command:

    boussole compile
    
  5. And voila, your valid Sass files should have been compiled to the css directory;

Overview

Boussole is working on per-project configuration, it means all your Sass sources to compile have to be organized in the same directory considered as the sources directory. Obviously you can organize them in multiple sub-directories within your sources directory.

Your project can rely on some Sass libraries that must be out of the source directory.

Boussole does not really handle itself compilation, this is the role of libsass-python. But Boussole needs to inspect your Sass sources and so can raise some errors if they are invalid. These errors are almost only about your @import rules.

Boussole is builded following Sass references and all your Sass sources and libraries compatible with libsass should be safe to compile.

Project configuration

A project configuration lives in a file which default attempted name is settings.json with JSON format backend.

Backend format

Default configuration file format is JSON, its backend name is json and involve default configuration filename to settings.json.

YAML is another available format, its backend name is yaml and involve default configuration filename to settings.yml.

To select a backend from command line use argument --backend, value can be either json or yaml.

You can use the argument --config to specify another path to your settings file like myconfig.yml.

If you don’t use default values for --config or --backend options, you will need to provide again them to each commands.

Sample

Here is a full sample of available settings for project configuration with JSON format:

{
    "SOURCES_PATH": "/home/foo",
    "LIBRARY_PATHS": [
        "/home/lib1",
        "/home/lib2"
    ],
    "TARGET_PATH": "/home/bar",
    "OUTPUT_STYLES": "nested",
    "CUSTOM_IMPORT_EXTENSIONS": [
        ".css"
    ],
    "SOURCE_COMMENTS": false,
    "SOURCE_MAP": false,
    "EXCLUDES": [
        "*/*.backup.scss",
        "/home/lib2"
    ]
}
References

Note

Default values are referenced as Python values, you will need to adapt them according to the backend format you are using.

SOURCES_PATH

Default: None, this is a required setting.

(string) Path to the directory containing your project Sass sources to compile.

LIBRARY_PATHS

Default: []

(list) A list of paths (string) to your library imported from your Sass sources. Never try to add your source dir as a library and vice versa, this will trouble resolver and compiler.

TARGET_PATH

Default: None, this is a required setting.

(string) Directory path where will be writed your compiled Sass sources.

OUTPUT_STYLES

Default: nested

(string) keyword of output style type used to compile your Sass sources. Can be either compact, expanded, nested or compressed.

CUSTOM_IMPORT_EXTENSIONS

Default: [".css"]

(list) List of enabled source extensions allowed to be included from @import directive. This aims to allow to treat some sources as Sass source to include. Default value is made so using @import 'foo' will include foo.css source if it exists. Set an empty list if you want to only allow Sass source extensions.

SOURCE_COMMENTS

Default: False

(boolean) If True, comments about source lines will be added to each rule in resulted CSS from compile.

SOURCE_MAP

Default: False

(boolean) If True, generate a source map for each compiled file. Source map filename will be the same that compiled file but with extension changed to .map. The source map file is allways created in the same directory than CSS file.

EXCLUDES

Default: []

(list) A list of glob pattern (string) to exclude some paths/files from compile. Remember these pattern are allways matched against relative paths (from project directory).

Help

You can read help about global options with:

boussole -h

And you can reach help about command options using:

boussole [command name] -h

Start a new project

Create directory and configuration file for a new project. Although you can create your project manually, this is an easy helper to do it and avoid forgetting some details.

Without arguments, command will prompt you to fill required values but you can also directly feed these values from arguments, see command help for details.

Usage

boussole startproject

Compile

Compile simply launch compiler on every eligible Sass source from your SOURCES_PATH directory.

Usage

boussole compile

Watch

Watcher will constantly watch about changes on files in your SOURCES_PATH directory.

When an event occurs, it will compile eligible sources from the file dependencies and itself. Managed events can be :

  • File creation;
  • File modification;
  • File move;
  • File deletion.

Note

Compile errors won’t break the watcher, meaning you can resolve them and it will try again to compile.

Usage

boussole watch

Note

Default behavior is to use the Watchdog native platform observer. It may not work for all environments (like on shared directories through network or Virtual machine), in this case use the --poll to use the Watchdog polling observer instead of the default one.

Boussole has its own internal code to inspect Sass sources to be aware of sources paths it has to watch for.

It results inspection does not have exactly the same path resolution process than libsass.

It can lead to troubleshooting situations where compile command can build some sources that can fails with watch command because the latter need to inspect sources to be able to find dependencies and choke on unclear path resolution.

These unclear paths are almost allways due to some Sass libraries trying to import components using a relative path outside of itself like with ../. This is often the case with libraries that have been made to be included in your main scss directory.

Developer’s Guide

Development

Development requirement

Boussole is developed with:

  • Test Development Driven (TDD) using Pytest;
  • Respecting flake and pip8 rules using Flake8;
  • Sphinx for documentation with enabled Napoleon extension (using only the Google style);

Every requirement is available in file requirements/dev.txt.

Install for development

First ensure you have pip and python-venv package installed then type:

git clone https://github.com/sveetch/boussole.git
cd boussole
make install-dev

Boussole will be installed in editable mode from the last commit on master branch.

When it’s done, you will be able to check for boussole version, just type:

venv/bin/boussole version
Unittests

Unittests are made to works on Pytest, a shortcut in Makefile is available to start them on your current development install:

make tests
Tox

To ease development against multiple Python versions a tox configuration has been added. You are strongly encouraged to use it to test your pull requests.

Before using it you will need to install tox, it is recommended to install it at your system level (tox dependancy is not in tests requirements file):

sudo pip install tox

Then go in the boussole module directory, where the setup.py and tox.ini live and execute tox:

tox
Documentation

sphinx-autobuild is installed for a watcher which automatically rebuild HTML documentation when you change sources.

When environnement is activated, you can use following command from docs/ directory:

make livehtml

And go on http://127.0.0.1:8002/.

Changelog

Version 1.2.3 - 2018/05/20

  • Introduced new settings CUSTOM_IMPORT_EXTENSIONS which default value is ['.css'] to keep CSS source including behavior as default just like before libsass==3.5.3, close #29;
  • Fixed source map url, close #28;

Version 1.2.2 - 2017/12/12

  • Removed pytest-catchlog from tests requirements since it has been merged in pytest==3.3.0;
  • Upgraded to pytest>=3.3.0 in tests requirements;

Version 1.2.1 - 2017/11/15

  • Updated Makefile and development document to add everything for development install;
  • Validated tests with libsass==0.13.4;
  • Document watcher behavior about inspection, close #24;

Version 1.2.0 - 2017/01/21

  • Fixed pytest warning about deprecated section name in setup.cfg;
  • Updated tests requirements;
  • Removed python 3.4 from tox envs;
  • Added --poll option on watch command to use Watchdog polling observer instead of the native platform observer, close #22;
  • Fixed compiler tests for changes about source map since last libsass version;
  • Fixed Sass brand name according to http://sassnotsass.com/;
  • Validated tests with libsass==0.12.3;

Version 1.1.0 - 2016/11/26

  • YAML backend for settings, close #7 :
    • Added yaml_backend.SettingsBackendYaml backend;
    • Implement YAML backend in unittests;
    • Added helper to discover settings backend from filename extension;
    • Configuration backend now implement a dump method;
    • Changed project.ProjectStarter so it can load Configuration backend;
  • Don’t pass anymore logger to objects, just use logging.getLogger("boussole"), close #11;
  • Validate tests on Python 3.5 through tox;

Version 1.0.2 - 2016/10/26

  • Upgrade libsass-python dependancy to >=0.11.2 to profit from libsass==3.3.6 (include bugfix for segfault with @extends and :not);

Version 1.0.1 - 2016/09/10

  • Fixed encoding issue with inspector that leaded to some bugs with watcher, close #17;

Version 1.0.0 - 2016/08/01

Added Python 3.4 support, thanks to @feth for its contributions.

  • Added six as requirement;

  • Use the ‘key’ param in sorted: ‘cmp’ is removed

    • Factored out the calls to sorted into paths_by_depth.
    • removed path_parts_cmp, used by removed keyword arg cmp (replaced by a lambda function);
  • More pythonic way of checking the match in Finder;

  • Fixed parser.py for filter builtin function usage;

  • Use StringIO object from ‘io’ module instead of deprecated ‘StringIO’ module;

  • Don’t use anymore message class attribute with Exceptions;

  • Don’t open JSON settings file with rb inside tests, mode r is enough;

  • Fixed os.listdir usage in tests (using sorted results);

  • Fixed logging messages to be unicode string;

  • Added Python 3.4 interpreter in available tox environments;

Version 0.9.2 - 2016/07/30

  • Fixed some tests related to directory/files structures that were not consistant because of os.walk arbitrary order, close #16;

Version 0.9.1 - 2016/07/29

  • Added tox configuration file starting with Python2.7;
  • Fixed some postprocessor that was failing because of usage of os.envrion['HOME'] not working inside tox env;
  • Disabled flake8-format-ansi since it seems to cause errors in some cases, it is recommended to do pip uninstall flake8-format-ansi for now;
  • Fixed some inspector tests failing on some wrong result orders because of set() vs list();
  • Fixed setup.py so tests directory is not installed anymore as a Python packages;
  • Updated development documentation;

Version 0.9.0 - 2016/05/01

  • Added new settings to enabled sourcemap generation, close #6;
  • Finalize documentation, close #10

Version 0.8.3 - 2016/04/23

  • New CLI action to start a project, close #8;
  • Added logo to documentation;

Version 0.8.0 - 2016/04/16

  • Relaxed libsass version in requirements;
  • Moved colorama from test to default requirements;
  • Removed every use of click.echo/secho within core API, use logger instead, close #1;
  • Added colorlog in requirements and use it to have colors for each logging level, close #4;
  • Changed verbosity option on CLI action so default verbosity is INFO logging level, then user can choose totally silent verbosity or any other logging level, definitively close #1;
  • Better CLI actions helps, close #5;
  • Manage every API exception from CLI, should be ok now (in fact since previous commit), close #3;
  • Break unittests into subdirectories per module, close #9;
    • A subdirectory per module;
    • Renamed test files to be less verbose;
    • Renamed test functions to be less verbose;
  • Added some settings validation, close #2;

Version 0.7.0 - 2016/04/07

This is almost near Beta version.

  • Fixed a bug with comment removal from parser: url protocol separator (the // in http://) was matched and leaded to errors in import rule parsing;
  • Added logs module;
  • Removed --config commandline option from console script entry point because some cli actions don’t need to load a settings. Until i find a way to disable it for some action, the option will have to be duplicated on each action that require it (sic);
  • Added flake8-format-ansi as a development requirement and use it in setup.cfg;
  • Added Unittests for compile commandline action;
  • Added compiler module for some helper on top of libsass-python compiler;
  • Improved finder to have a common method to match conditions on filepath (is partial, is allowed, etc..);
  • Added new exception FinderException;
  • Unittest for Watcher event handler (but not on watch commandline because of some limit from click CliRunner)
  • Added pytest-catchlog plugin to have nice logging management within tests;
  • Moved flake8 config to .flake8 instead of setup.cfg since flake8-format-ansi plugin config cause issues with pytest-catchlog install;
  • Finished working version for command line action watch;
  • Updated documentation;

Version 0.6.0 - 2016/03/25

  • Modified conf backend to be more flexible with given base dir and file path;
  • Accorded settings manifest to libsass-python compiler options;
  • Finished first working version for command line action compile;
  • Upgraded libsass-python requirement to version 0.11.0
  • Improved command line action version to include both libsass-python and libsass versions;

Version 0.5.0 - 2016/03/19

  • Added CLI structure with click;
  • Lowered click version requirement to 5.1 (since 6.x is not stable yet);
  • Restructured tests for conf module and added some new ones for Settings object
  • Moved all settings files up the sample project;
  • Finished conf management;

Version 0.4.0 - 2016/03/14

  • Added conf module to manage project settings;
  • Doc, flake8, unittests for conf;

Version 0.3.0 - 2016/03/10

  • Added finder module;
  • Doc, flake8, unittests for finder;

Version 0.2.0 - 2016/03/09

  • Finished changes for the right path resolving/checking behavior with unclear resolutions;

Version 0.1.0 - 2016/03/06

  • Made changes to pass Flake8 validation on API;
  • Started Sphinx documentation;

Version 0.0.9.5 - 2016/03/06

  • Document core using Sphinx+Napoleon syntax;
  • Cleaned all debug pointers;
  • Minor improvements;
  • Added some last inspector tests;

Version 0.0.9 - 2016/03/05

  • Finished inspector to detect almost all circular import;
  • Improved tests;
  • Did some cleaning;
  • Still need some debug pointer cleaning and then documentation;

Version 0.0.8 - 2016/03/01

  • Updated project to use pytest for unittests;
  • updated unittests to fit to pytest usage;
  • Added first inspector tests;

Version 0.0.7 - 2016/02/29

  • Improved tests;
  • Finished working inspector but not unittested yet;

Version 0.0.6 - 2016/02/25

  • Added inspector
  • Improved parser to remove comments before looking for import rules, this will avoid to catch commented import rules;
  • Updated tests;
  • Added click as requirement;

Version 0.0.5 - 2016/02/22

  • Changed resolver behavior to return absolute instead of relative
  • Fixed tests;

Version 0.0.4 - 2016/02/22

  • Finished stable and unittested parser and resolver;

Version 0.0.3 - 2016/02/21

  • Finished first resolver version, still need to do the library_paths thing;

Version 0.0.2 - 2016/02/21

  • Improved test;
  • Continued on resolver (was named validate previously);

Version 0.0.1 - 2016/02/20

  • First commit

Core API

Boussole is mainly a commandeline tool but it relies on a core API that may be used to implement another frontend.

This part of Boussole should not concern end users because they don’t directly exploit it, it documents some behaviors but they should be better documented from Tutorial.

The core API should be 100% covered for documentation and unittests.

Modules

Exceptions

Specific exceptions that Boussole code can raise.

exception boussole.exceptions.BoussoleBaseException[source]

Bases: exceptions.Exception

Base for Boussole exceptions.

exception boussole.exceptions.CircularImport[source]

Bases: boussole.exceptions.BoussoleBaseException

Exception to be raised when inspector detect a circular import from sources.

exception boussole.exceptions.FinderException[source]

Bases: boussole.exceptions.BoussoleBaseException

Exception to be raised when error occurs with finder usage.

exception boussole.exceptions.InvalidImportRule[source]

Bases: boussole.exceptions.BoussoleBaseException

Exception to be raised when the parser encounts an invalid import rule.

exception boussole.exceptions.SettingsBackendError[source]

Bases: boussole.exceptions.BoussoleBaseException

Exception to be raised when config loading has failed from a backend.

exception boussole.exceptions.SettingsInvalidError[source]

Bases: boussole.exceptions.BoussoleBaseException

Exception to be raised when a settings is detected as invalid.

exception boussole.exceptions.UnclearResolution[source]

Bases: boussole.exceptions.BoussoleBaseException

Exception to be raised when the resolver encounts multiple existing candidates for a path.

exception boussole.exceptions.UnresolvablePath[source]

Bases: boussole.exceptions.BoussoleBaseException

Exception to be raised when the resolver can not resolve a given path.

Parser

Parser is in charge to find every @import rules in given Sass content.

It has been builded following Sass Reference about @import rule.

class boussole.parser.ScssImportsParser[source]

SCSS parser to find import rules.

This does not support the old Sass syntax (also known as “indented syntax”).

It’s a mixin, meaning without own __init__ method so it’s should be safe enough to inherit it from another class.

REGEX_IMPORT_RULE

Compiled regex used to find import rules.

REGEX_COMMENTS

Compiled regex used to find and remove comments.

filter_rules(path)[source]

Lambda to filter items that: * Starts with http:// or https:// (this for external load only) * Ends with “.css” (they are not intended to be compiled)

flatten_rules(declarations)[source]

Flatten returned import rules from regex.

Because import rules can contains multiple items in the same rule (called multiline import rule), the regex REGEX_IMPORT_RULE return a list of unquoted items for each rule.

Parameters:declarations (list) – A SCSS source.
Returns:Given SCSS source with all comments removed.
Return type:list
parse(content)[source]

Parse a stylesheet document with a regex (REGEX_IMPORT_RULE) to extract all import rules and return them.

Parameters:content (str) – A SCSS source.
Returns:Finded paths in import rules.
Return type:list
remove_comments(content)[source]

Remove all comment kind (inline and multiline) from given content.

Parameters:content (str) – A SCSS source.
Returns:Given SCSS source with all comments removed.
Return type:string
strip_quotes(content)[source]

Unquote given rule.

Parameters:

content (str) – An import rule.

Raises:
  • InvalidImportRule – Raise exception if the rule is badly quoted
  • (not started or not ended quotes).
Returns:

The given rule unquoted.

Return type:

string

Resolver

Resolver is in charge to resolve path in import rules. Resolving is done using given source directory and libraries directories paths.

class boussole.resolver.ImportPathsResolver[source]

Import paths resolver.

Resolve given paths from SCSS source to absolute paths.

It’s a mixin, meaning without own __init__ method so it’s should be safe enough to inherit it from another class.

CANDIDATE_EXTENSIONS

list – List of extensions available to build candidate paths. Beware, order does matter, the first extension will be the top candidate.

STRICT_PATH_VALIDATION

bool – A switch to enabled (True) or disable (False) exception raising when a path can not be resolved.

candidate_paths(filepath)[source]

Return candidates path for given path

  • If Filename does not starts with _, will build a candidate for both with and without _ prefix;
  • Will build For each available extensions if filename does not have an explicit extension;
  • Leading path directory is preserved;
Parameters:filepath (str) – Relative path as finded in an import rule from a SCSS source.
Returns:Builded candidate paths (as relative paths).
Return type:list
check_candidate_exists(basepath, candidates)[source]

Check that at least one candidate exist into a directory.

Parameters:
  • basepath (str) – Directory path where to search for candidate.
  • candidates (list) – List of candidate file paths.
Returns:

List of existing candidates.

Return type:

list

resolve(sourcepath, paths, library_paths=None)[source]

Resolve given paths from given base paths

Return resolved path list.

Note

Resolving strategy is made like libsass do, meaning paths in import rules are resolved from the source file where the import rules have been finded.

If import rule is not explicit enough and two file are candidates for the same rule, it will raises an error. But contrary to libsass, this happen also for files from given libraries in library_paths (oposed to libsass just silently taking the first candidate).

Parameters:
  • sourcepath (str) – Source file path, its directory is used to resolve given paths. The path must be an absolute path to avoid errors on resolving.
  • paths (list) – Relative paths (from sourcepath) to resolve.
  • library_paths (list) – List of directory paths for libraries to resolve paths if resolving fails on the base source path. Default to None.
Raises:

UnresolvablePath – If a path does not exist and STRICT_PATH_VALIDATION attribute is True.

Returns:

List of resolved path.

Return type:

list

Inspector

Inspector is in charge to inspect a project about Sass stylesheets to search for their dependencies.

class boussole.inspector.ScssInspector(*args, **kwargs)[source]

Bases: boussole.resolver.ImportPathsResolver, boussole.parser.ScssImportsParser

Project inspector for SCSS sources

Inspector is stateful, meaning you will need to invoke reset() then inspect() each time a project change, else the parents and children maps will be eventually incorrects.

__init__ method use reset method to initialize some internal buffers.

_CHILDREN_MAP

Dictionnary of finded direct children for each inspected sources.

_PARENTS_MAP

Dictionnary of finded direct parents for each inspected sources.

_get_recursive_dependancies(dependencies_map, sourcepath, recursive=True)[source]

Return all dependencies of a source, recursively searching through its dependencies.

This is a common method used by children and parents methods.

Parameters:
  • dependencies_map (dict) – Internal buffer (internal buffers _CHILDREN_MAP or _PARENTS_MAP) to use for searching.
  • sourcepath (str) – Source file path to start searching for dependencies.
Keyword Arguments:
 

recursive (bool) – Switch to enable recursive finding (if True). Default to True.

Raises:

CircularImport – If circular error is detected from a source.

Returns:

List of dependencies paths.

Return type:

set

children(sourcepath, recursive=True)[source]

Recursively find all children that are imported from the given source path.

Parameters:sourcepath (str) – Source file path to search for.
Keyword Arguments:
 recursive (bool) – Switch to enabled recursive finding (if True). Default to True.
Returns:List of finded parents path.
Return type:set
inspect(*args, **kwargs)[source]

Recursively inspect all given SCSS files to find imported dependencies.

This does not return anything. Just fill internal buffers about inspected files.

Note

This will ignore orphan files (files that are not imported from any of given SCSS files).

Parameters:*args – One or multiple arguments, each one for a source file path to inspect.
Keyword Arguments:
 library_paths (list) – List of directory paths for libraries to resolve paths if resolving fails on the base source path. Default to None.
look_source(sourcepath, library_paths=None)[source]

Open a SCSS file (sourcepath) and find all involved file through imports.

This will fill internal buffers _CHILDREN_MAP and _PARENTS_MAP.

Parameters:sourcepath (str) – Source file path to start searching for imports.
Keyword Arguments:
 library_paths (list) – List of directory paths for libraries to resolve paths if resolving fails on the base source path. Default to None.
parents(sourcepath, recursive=True)[source]

Recursively find all parents that import the given source path.

Parameters:sourcepath (str) – Source file path to search for.
Keyword Arguments:
 recursive (bool) – Switch to enabled recursive finding (if True). Default to True.
Returns:List of finded parents path.
Return type:set
reset()[source]

Reset internal buffers _CHILDREN_MAP and _PARENTS_MAP.

Finder

Finder is in charge to find main Sass stylesheets files to compile to CSS files, meaning it will ignore all partials Sass stylesheets (see Sass partials Reference).

class boussole.finder.ScssFinder[source]

Project finder for SCSS sources

FINDER_STYLESHEET_EXTS

List of file extensions regarded as compilable stylesheet sources.

change_extension(filepath, new_extension)[source]

Change final filename extension.

Parameters:
  • filepath (str) – A file path (relative or absolute).
  • new_extension (str) – New extension name (without leading dot) to apply.
Returns:

Filepath with new extension.

Return type:

str

compilable_sources(sourcedir, absolute=False, recursive=True, excludes=[])[source]

Find all scss sources that should be compiled, aka all sources that are not “partials” Sass sources.

Parameters:

sourcedir (str) – Directory path to scan.

Keyword Arguments:
 
  • absolute (bool) – Returned paths will be absolute using sourcedir argument (if True), else return relative paths.
  • recursive (bool) – Switch to enabled recursive finding (if True). Default to True.
  • excludes (list) – A list of excluding patterns (glob patterns). Patterns are matched against the relative filepath (from its sourcedir).
Returns:

List of source paths.

Return type:

list

get_destination(filepath, targetdir=None)[source]

Return destination path from given source file path.

Destination is allways a file with extension .css.

Parameters:
  • filepath (str) – A file path. The path is allways relative to sources directory. If not relative, targetdir won’t be joined.
  • absolute (bool) – If given will be added at beginning of file path.
Returns:

Destination filepath.

Return type:

str

get_relative_from_paths(filepath, paths)[source]

Find the relative filepath from the most relevant multiple paths.

This is somewhat like a os.path.relpath(path[, start]) but where start is a list. The most relevant item from paths will be used to apply the relative transform.

Parameters:
  • filepath (str) – Path to transform to relative.
  • paths (list) – List of absolute paths to use to find and remove the start path from filepath argument. If there is multiple path starting with the same directories, the biggest will match.
Raises:
  • boussole.exception.FinderException – If no filepath start could
  • be finded.
Returns:

Relative filepath where the start coming from paths is

removed.

Return type:

str

is_allowed(filepath, excludes=[])[source]

Check from exclude patterns if a relative filepath is allowed

Parameters:filepath (str) – A relative file path. (exclude patterns are allways based from the source directory).
Keyword Arguments:
 excludes (list) – A list of excluding (glob) patterns. If filepath matchs one of patterns, filepath is not allowed.
Raises:boussole.exception.FinderException – If given filepath is absolute.
Returns:Filepath with new extension.
Return type:str
is_partial(filepath)[source]

Check if file is a Sass partial source (see Sass partials Reference).

Parameters:
  • filepath (str) – A file path. Can be absolute, relative or just a
  • filename.
Returns:

True if file is a partial source, else False.

Return type:

bool

match_conditions(filepath, sourcedir=None, nopartial=True, exclude_patterns=[], excluded_libdirs=[])[source]

Find if a filepath match all required conditions.

Available conditions are (in order):

  • Is allowed file extension;
  • Is a partial source;
  • Is from an excluded directory;
  • Is matching an exclude pattern;
Parameters:

filepath (str) – Absolute filepath to match against conditions.

Keyword Arguments:
 
  • sourcedir (str or None) – Absolute sources directory path. Can be None but then the exclude_patterns won’t be matched against (because this method require to distinguish source dir from lib dirs).
  • nopartial (bool) – Accept partial sources if False. Default is True (partial sources fail matchind condition). See Finder.is_partial().
  • exclude_patterns (list) – List of glob patterns, if filepath match one these pattern, it wont match conditions. See Finder.is_allowed().
  • excluded_libdirs (list) – A list of directory to match against filepath, if filepath starts with one them, it won’t match condtions.
Returns:

True if match all conditions, else False.

Return type:

bool

mirror_sources(sourcedir, targetdir=None, recursive=True, excludes=[])[source]

Mirroring compilable sources filepaths to their targets.

Parameters:

sourcedir (str) – Directory path to scan.

Keyword Arguments:
 
  • absolute (bool) – Returned paths will be absolute using sourcedir argument (if True), else return relative paths.
  • recursive (bool) – Switch to enabled recursive finding (if True). Default to True.
  • excludes (list) – A list of excluding patterns (glob patterns). Patterns are matched against the relative filepath (from its sourcedir).
Returns:

A list of pairs (source, target). Where target is the

source path but renamed with .css extension. Relative directory from source dir is left unchanged but if given, returned paths will be absolute (using sourcedir for sources and targetdir for targets).

Return type:

list

boussole.finder.paths_by_depth(paths)[source]

Sort list of paths by number of directories in it

Parameters:paths (iterable) – iterable containing paths (str)
Return type:list
Logging
boussole.logs.init_logger(level, printout=True)[source]

Initialize app logger to configure its level/handler/formatter/etc..

Parameters:level (str) – Level name (debug, info, etc..).
Keyword Arguments:
 printout (bool) – If False, logs will never be outputed.
Returns:Application logger.
Return type:logging.Logger
Project configuration

Boussole work on per project configurations stored in a settings file for each project.

Backends behavior is to search for a settings file in the given directory, read it, possibly patch its values and then return a boussole.conf.model.Settings object.

Almost all paths in settings will be expanded to absolute paths if they are not allready so:

  • If the path start with a home directory character, the home directory is used to expand the path;
  • If the path is relative, expand it to absolute using directory from settings file location;

Also note, that Sass files from libraries directories are never compiled.

Settings model

This define the model object containing settings that will be passed to interfaces.

class boussole.conf.model.Settings(initial={})[source]

Settings model object

Class init method fills object attributes from default settings (DEFAULT_SETTINGS) then update it with initial settings if given.

Settings are available as object attributes, there is also a private _settings attribute containing a dict of all stored settings. You are strongly advised to never directly manipulate the _settings attribute. Instead, allways use the update() method.

Note

Model is only about data model, there is no other validation that available ‘fields’ from DEFAULT_SETTINGS.

If you intend to manually open and fill a Settings instance, remember to allways use absolute paths in your settings. Relative path will cause issues in resolving that lead to wrong compilations.

You may also apply post processor validation to ensure your datas.

Keyword Arguments:
 initial (dict) – A dictionnary of settings for initial values.
clean(settings)[source]

Filter given settings to keep only key names available in DEFAULT_SETTINGS.

Parameters:settings (dict) – Loaded settings.
Returns:Settings object filtered.
Return type:dict
set_settings(settings)[source]

Set every given settings as object attributes.

Parameters:settings (dict) – Dictionnary of settings.
update(settings)[source]

Update object attributes from given settings

Parameters:settings (dict) – Dictionnary of elements to update settings.
Returns:Dictionnary of all current saved settings.
Return type:dict
Settings backend post processing

Post processing methods are used to modify or validate given settings items.

Backends inherit from SettingsPostProcessor to be able to use it in their clean() method.

class boussole.conf.post_processor.SettingsPostProcessor[source]

Mixin object for all available post processing methods to use in settings manifest (default manifest comes from SETTINGS_MANIFEST).

_patch_expand_path(settings, name, value)[source]

Patch a path to expand home directory and make absolute path.

Parameters:
  • settings (dict) – Current settings.
  • name (str) – Setting name.
  • value (str) – Path to patch.
Returns:

Patched path to an absolute path.

Return type:

str

_patch_expand_paths(settings, name, value)[source]

Apply SettingsPostProcessor._patch_expand_path to each element in list.

Parameters:
  • settings (dict) – Current settings.
  • name (str) – Setting name.
  • value (list) – List of paths to patch.
Returns:

Patched path list to an absolute path.

Return type:

list

_validate_path(settings, name, value)[source]

Validate path exists

Parameters:
  • settings (dict) – Current settings.
  • name (str) – Setting name.
  • value (str) – Path to validate.
Raises:

boussole.exceptions.SettingsInvalidError – If path does not exists.

Returns:

Validated path.

Return type:

str

_validate_paths(settings, name, value)[source]

Apply SettingsPostProcessor._validate_path to each element in list.

Parameters:
  • settings (dict) – Current settings.
  • name (str) – Setting name.
  • value (list) – List of paths to patch.
Raises:

boussole.exceptions.SettingsInvalidError – Once a path does not exists.

Returns:

Validated paths.

Return type:

list

_validate_required(settings, name, value)[source]

Validate a required setting (value can not be empty)

Parameters:
  • settings (dict) – Current settings.
  • name (str) – Setting name.
  • value (str) – Required value to validate.
Raises:

boussole.exceptions.SettingsInvalidError – If value is empty.

Returns:

Validated value.

Return type:

str

post_process(settings)[source]

Perform post processing methods on settings according to their definition in manifest.

Post process methods are implemented in their own method that have the same signature:

  • Get arguments: Current settings, item name and item value;
  • Return item value possibly patched;
Parameters:settings (dict) – Loaded settings.
Returns:
Settings object possibly modified (depending from applied
post processing).
Return type:dict
Base settings backend

Backends are responsible to find settings file, parse it, load its values then return a Settings object.

Backends inherit from boussole.conf.post_processor so they can post process each loaded settings values following the settings manifest rules.

Actually available backends are JSON and YAML.

class boussole.conf.base_backend.SettingsBackendBase(basedir=None)[source]

Bases: boussole.conf.post_processor.SettingsPostProcessor

Base project settings backend

Parameters:basedir (str) –

Directory path where to search for settings filepath.

Default is empty, meaning it will resolve path from current directory. Don’t use an empty basedir attribute to load settings from non-absolute filepath.

Given value will fill intial value for projectdir attribute.

_default_filename

Filename for settings file to load. Value is settings.txt.

_kind_name

Backend format name. Value is txt.

_file_extension

Default filename extension. Value is txt.

check_filepath(path, filename)[source]

Check and return the final filepath to settings

Parameters:
  • path (str) – Directory path where to search for settings file.
  • filename (str) – Filename to use to search for settings file.
Raises:

boussole.exceptions.SettingsBackendError – If determined filepath does not exists or is a directory.

Returns:

Settings file path, joining given path and filename.

Return type:

string

clean(settings)[source]

Clean given settings for backend needs.

Default backend only apply available post processor methods.

Parameters:dict – Loaded settings.
Returns:Settings object cleaned.
Return type:dict
dump(content, filepath)[source]

Dump settings content to filepath.

Base method do nothing because dumping is dependent from backend.

Parameters:
  • content (str) – Settings content.
  • filepath (str) – Settings file location.
Returns:

Dictionnary containing parsed setting options.

Return type:

dict

load(filepath=None)[source]

Load settings file from given path and optionnal filepath.

During path resolving, the projectdir is updated to the file path directory.

Keyword Arguments:
 filepath (str) – Filepath to the settings file.
Returns:Settings object with loaded options.
Return type:boussole.conf.model.Settings
open(filepath)[source]

Open settings backend to return its content

Parameters:filepath (str) – Settings object, depends from backend
Returns:File content.
Return type:string
parse(filepath, content)[source]

Load and parse opened settings content.

Base method do nothing because parsing is dependent from backend.

Parameters:
  • filepath (str) – Settings file location.
  • content (str) – Settings content from opened file, depends from backend.
Returns:

Dictionnary containing parsed setting options.

Return type:

dict

parse_filepath(filepath=None)[source]

Parse given filepath to split possible path directory from filename.

  • If path directory is empty, will use basedir attribute as base filepath;
  • If path directory is absolute, ignore basedir attribute;
  • If path directory is relative, join it to basedir attribute;
Keyword Arguments:
 filepath (str) –

Filepath to use to search for settings file. Will use value from _default_filename class attribute if empty.

If filepath contain a directory path, it will be splitted from filename and used as base directory (and update object basedir attribute).

Returns:Separated path directory and filename.
Return type:tuple
JSON settings backend
class boussole.conf.json_backend.SettingsBackendJson(basedir=None)[source]

Bases: boussole.conf.base_backend.SettingsBackendBase

JSON backend for settings

_default_filename

Filename for settings file to load. Value is settings.json.

_kind_name

Backend format name. Value is json.

_file_extension

Default filename extension. Value is json.

dump(content, filepath, indent=4)[source]

Dump settings content to filepath.

Parameters:
  • content (str) – Settings content.
  • filepath (str) – Settings file location.
parse(filepath, content)[source]

Parse opened settings content using JSON parser.

Parameters:
  • filepath (str) – Settings object, depends from backend
  • content (str) – Settings content from opened file, depends from backend.
Raises:

boussole.exceptions.SettingsBackendError – If parser can not decode a valid JSON object.

Returns:

Dictionnary containing parsed setting elements.

Return type:

dict

YAML settings backend
class boussole.conf.yaml_backend.SettingsBackendYaml(basedir=None)[source]

Bases: boussole.conf.base_backend.SettingsBackendBase

YAML backend for settings

Use PyYaml for parsing and pyaml for dumping.

_default_filename

Filename for settings file to load. Value is settings.yml.

_kind_name

Backend format name. Value is yaml.

_file_extension

Default filename extension. Value is yml.

dump(content, filepath, indent=4)[source]

Dump settings content to filepath.

Parameters:
  • content (str) – Settings content.
  • filepath (str) – Settings file location.
parse(filepath, content)[source]

Parse opened settings content using YAML parser.

Parameters:
  • filepath (str) – Settings object, depends from backend
  • content (str) – Settings content from opened file, depends from backend.
Raises:

boussole.exceptions.SettingsBackendError – If parser can not decode a valid YAML object.

Returns:

Dictionnary containing parsed setting elements.

Return type:

dict

Backend discover
boussole.conf.discover.get_backend(filepath, kind=None)[source]

From given filepath try to discover which backend format to use.

Discovering is pretty naive as it find format from file extension.

Parameters:filepath (str) – Settings filepath or filename.
Keyword Arguments:
 kind (str) – A format name to enforce a specific backend. Can be either json or yaml. Default to None.
Raises:boussole.exceptions.SettingsBackendError – If extension is unknowed or if given format name is unknowed.
Returns:Backend object.
Return type:object
Sass compile helper

This is not a real compiler, just an helper wrapping common methods to compile a Sass source using libsass-python.

class boussole.compiler.SassCompileHelper[source]

Sass compile helper mixin

safe_compile(settings, sourcepath, destination)[source]

Safe compile

It won’t raise compile error and instead return compile success state as a boolean with a message.

It will create needed directory structure first if it contain some directories that does not allready exists.

Parameters:
  • settings (boussole.conf.model.Settings) – Project settings.
  • sourcepath (str) – Source file path to compile to CSS.
  • destination (str) – Destination path for compiled CSS.
Returns:

A tuple of (success state, message).

  • success state: is boolean weither the compile is a success or not;
  • message: Message accorded to success. If compile fails, the message will contains returned error from libsass, if success just the destination path.

Return type:

tuple

write_content(content, destination)[source]

Write given content to destination path.

It will create needed directory structure first if it contain some directories that does not allready exists.

Parameters:
  • content (str) – Content to write to target file.
  • destination (str) – Destination path for target file.
Returns:

Path where target file has been written.

Return type:

str

Source watcher

Watcher is almost isolated from command line code because it runs in an infinite loop, so note that handlers directly output some informations on a logging.logger.

class boussole.watcher.SassLibraryEventHandler(settings, inspector, *args, **kwargs)[source]

Bases: object

Watch mixin handler for library sources

Handler does not compile source which triggered an event, only its parent dependencies. Because libraries are not intended to be compiled.

Parameters:
settings

boussole.conf.model.Settings – Filled from argument.

logger

logging.Logger – Boussole logger.

inspector

boussole.inspector.ScssInspector – Filled from argument.

finder

boussole.finder.ScssFinder – Finder instance.

compiler

boussole.compiler.SassCompileHelper – Sass compile helper object.

compilable_files

dict – Pair of (source path, destination path) to compile. Automatically update from index() method.

source_files

list – List of source path to compile. Automatically update from index() method.

_event_error

bool – Internal flag setted to True if error has occured within an event. index() will reboot it to False each time a new event occurs.

compile_dependencies(sourcepath, include_self=False)[source]

Apply compile on all dependencies

Parameters:sourcepath (string) – Sass source path to compile to its destination using project settings.
Keyword Arguments:
 include_self (bool) – If True the given sourcepath is add to items to compile, else only its dependencies are compiled.
compile_source(sourcepath)[source]

Compile source to its destination

Check if the source is eligible to compile (not partial and allowed from exclude patterns)

Parameters:sourcepath (string) – Sass source path to compile to its destination using project settings.
Returns:
A pair of (sourcepath, destination), if source has
been compiled (or at least tried). If the source was not eligible to compile, return will be None.
Return type:tuple or None
index()[source]

Reset inspector buffers and index project sources dependencies.

This have to be executed each time an event occurs.

Note

If a Boussole exception occurs during operation, it will be catched and an error flag will be set to True so event operation will be blocked without blocking or breaking watchdog observer.

on_any_event(event)[source]

Catch-all event handler (moved, created, deleted, changed).

Before any event, index project to have the right and current dependencies map.

Parameters:event – Watchdog event watchdog.events.FileSystemEvent.
on_created(event)[source]

Called when a new file or directory is created.

Parameters:event – Watchdog event, either watchdog.events.DirCreatedEvent or watchdog.events.FileCreatedEvent.
on_deleted(event)[source]

Called when a file or directory is deleted.

Parameters:event – Watchdog event, watchdog.events.DirDeletedEvent or watchdog.events.FileDeletedEvent.
on_modified(event)[source]

Called when a file or directory is modified.

Parameters:event – Watchdog event, watchdog.events.DirModifiedEvent or watchdog.events.FileModifiedEvent.
on_moved(event)[source]

Called when a file or a directory is moved or renamed.

Many editors don’t directly change a file, instead they make a transitional file like *.part then move it to the final filename.

Parameters:event – Watchdog event, either watchdog.events.DirMovedEvent or watchdog.events.FileModifiedEvent.
class boussole.watcher.SassProjectEventHandler(settings, inspector, *args, **kwargs)[source]

Bases: boussole.watcher.SassLibraryEventHandler

Watch mixin handler for project sources.

Warning

DO NOT use this handler to watch libraries, there is a risk the compiler will try to compile their sources in a wrong directory.

Source that trigger event is compiled (if eligible) with its dependencies.

compile_dependencies(sourcepath, include_self=True)[source]

Same as inherit method but the default value for keyword argument ìnclude_self is True.

class boussole.watcher.WatchdogLibraryEventHandler(settings, inspector, *args, **kwargs)[source]

Bases: boussole.watcher.SassLibraryEventHandler, watchdog.events.PatternMatchingEventHandler

Watchdog event handler for library sources

class boussole.watcher.WatchdogProjectEventHandler(settings, inspector, *args, **kwargs)[source]

Bases: boussole.watcher.SassProjectEventHandler, watchdog.events.PatternMatchingEventHandler

Watchdog event handler for project sources.

Warning

DO NOT use this handler to watch libraries, there is a risk the compiler will try to compile their sources in a wrong directory.

Project management
class boussole.project.ProjectBase(backend_name='json', **kwargs)[source]

Project base

Keyword Arguments:
 backend_name (string) – Default backend name, can be either json or yaml. Default value is json.
_engines

Available Configuration backends. Read only.

backend_name

Backend name to use from available ones.

backend_engine

Backend engine selected from given name.

get_backend_engine(name, **kwargs)[source]

Get backend engine from given name.

Parameters:(string) – Path to validate.
Raises:boussole.exceptions.SettingsBackendError – If given backend name does not match any available engine.
Returns:Instance of selected backend engine.
Return type:object
class boussole.project.ProjectStarter(backend_name='json', **kwargs)[source]

Provide methods to create a new Sass Project

commit(sourcedir, targetdir, abs_config, abs_sourcedir, abs_targetdir)[source]

Commit project structure and configuration file

Parameters:
  • sourcedir (string) – Source directory path.
  • targetdir (string) – Compiled files target directory path.
  • abs_config (string) – Configuration file absolute path.
  • abs_sourcedir (string) – sourcedir expanded as absolute path.
  • abs_targetdir (string) – targetdir expanded as absolute path.
expand(basedir, config, sourcedir, targetdir, cwd)[source]

Validate that given paths are not the same.

Parameters:
  • basedir (string) – Project base directory used to prepend relative paths. If empty or equal to ‘.’, it will be filled with current directory path.
  • config (string) – Settings file path.
  • sourcedir (string) – Source directory path.
  • targetdir (string) – Compiled files target directory path.
  • cwd (string) – Current directory path to prepend base dir if empty.
Returns:

Expanded arguments in the same order

Return type:

tuple

init(basedir, config, sourcedir, targetdir, cwd='', commit=True)[source]

Init project structure and configuration from given arguments

Parameters:
  • basedir (string) – Project base directory used to prepend relative paths. If empty or equal to ‘.’, it will be filled with current directory path.
  • config (string) – Settings file path.
  • sourcedir (string) – Source directory path.
  • targetdir (string) – Compiled files target directory path.
Keyword Arguments:
 
  • cwd (string) – Current directory path to prepend base dir if empty.
  • commit (bool) – If False, directory structure and settings file won’t be created.
Returns:

A dict containing expanded given paths.

Return type:

dict

valid_paths(*args)[source]

Validate that given paths are not the same.

Parameters:(string) – Path to validate.
Raises:boussole.exceptions.SettingsInvalidError – If there is more than one occurence of the same path.
Returns:True if paths are validated.
Return type:bool

Credits

Logo has been created by Sébastien Bianco.