Scons Tool Util

Welcome to scons-tool-util documentation!

Purpose

SCons Tool Util package is a library of reusable functions and objects for SCons tools’ developers.

Table of Contents

User documentation

Introduction

The SCons Tool Utilities package is a library of reusable functions and objects designed to be used by newly developed SCons tools.

Utilities

ToolFinder
Description

ToolFinder is a configurable functor used to search for executable files within predefined search paths. Once created (configured), an instance of ToolFinder is expected to return same search result, every time it’s applied to a given SCons environment.

python = ToolFinder('python')
def generate(env):
   env['PYTHON'] = python(env)   # same result here ...
def exists(env):
   return python(env)            # ... and here

The program being searched for is identified by a name. By default, tool name is used ('python' in the above example). This may be overwritten with the name parameter

python = ToolFinder('python', name='python3')

The above finder will search for 'python3' file for the purpose of SCons tool named 'python'. Cumbersome strings may be used for name, including variable substitutions, like name="$PYTHONNAME".

python = ToolFinder('python', name='$PYTHONNAME')

A sequence of file names may also be passed in as name (alternative names for the program).

# Will search for 'python3', then 'python', then 'python2' in each path
python = ToolFinder('python', name=['python3', 'python', 'python2'])

By default, ToolFinder searches within the standard SCons PATH (env['ENV']['PATH']). This can be changed, by providing path argument to the constructor

# Will search in custom path, instead of env['ENV']['PATH']
python = ToolFinder('python', path=['/home/user/.local/virtualenvs/foo/bin',
                                    '/home/user/.local/bin'])
prog = python(env)

If file is found in path (or SCons PATH, if path not given), its name is returned. By setting strip_path to False, the object is being told to return absolute path instead

# Will return absolute path to the file found
python = ToolFinder('python', strip_path=False)
prog = python(env)    # '/usr/bin/python', for example

ToolFinder accepts two extra search paths: priority_path, and fallback_path. The priority_path is searched prior to the SCons PATH, the fallback_path is examined after the SCons PATH.

# Will search in priority_path, then env['ENV']['PATH'], then fallback_path.
python = ToolFinder('python', priority_path=['/home/user/.local/bin'],
                              fallback_path=['/opt/bin'])
prog = python(env)

The priority-/fallback- paths are used by ToolFinder at the tool configuration time, but it’s assumed that they’re not used by SCons during the build phase (later), when the program has to be invoked. Following this assumption, to ensure that same program will be picked up at the build stage, ToolFinder returns an absolute path to any program found within either priority_path or fallback_path. This behavior may be changed with strip_priority_path and strip_fallback_path, respectively

# Will return 'python', instead of '/home/user/.local/bin/python'
python = ToolFinder('python', priority_path=['/home/user/.local/bin'],
                              strip_priority_path=True)
prog = python(env)
Examples
Iconv tool

The iconv(1) command translates texts between encodings. The following simple tool makes use of iconv(1) installed in standard location (within SCons search PATH).

Example:Tool implementation
Tool module: site_scons/site_tools/iconv.py
from sconstool.util import *
from SCons.Builder import Builder

_iconv = ToolFinder('iconv')


def generate(env):
    env.SetDefault(ICONVFROM='utf8', ICONVTO='utf8')
    env.SetDefault(ICONV=_iconv(env))
    env['ICONVCOM'] = '$ICONV -f $ICONVFROM -t $ICONVTO $SOURCE > $TARGET'
    env['BUILDERS']['Iconv'] = Builder(action='$ICONVCOM')


def exists(env):
    return _iconv(env)
Example:A project using the iconv tool
Project file: SConstruct
# SConstruct
env = Environment(tools=['iconv'])
env.Iconv('utf8.txt', 'latin2.txt', ICONVFROM='latin2')
Input file: latin2.txt
Zaźółć  gęślą jaźń
Hammer tool

This tool will use our own python script hammer.py stored in a non-standard path. The hammer.py will replace all the occurrences of "nail" with "drived in nail".

Example:The hammer command
Command implmementation: bin/hammer.py
#!/usr/bin/env python3
import sys
with open(sys.argv[2], 'rt') as ifile, open(sys.argv[1], 'wt') as ofile:
    ofile.write(ifile.read().replace('nail', 'drived in nail'))
Example:Tool implementation
The tool module: site_scons/site_tool/hammer.py
from sconstool.util import *
from SCons.Builder import Builder
import sys

_hammer = ToolFinder('hammer', name='hammer.py', pathext=['.py'], priority_path='bin')


def generate(env):
    env.SetDefault(PYTHON=sys.executable)
    env.SetDefault(HAMMER=_hammer(env))
    env['HAMMERCOM'] = '$PYTHON $HAMMER $TARGET $SOURCE'
    env['BUILDERS']['Hammer'] = Builder(action='$HAMMERCOM')


def exists(env):
    return _hammer(env)
Example:A project using the hammer tool.
Project file: SConstruct
# SConstruct
env = Environment(tools=['hammer'])
env.Hammer('output.txt', 'input.txt')
Input file: input.txt
We have twenty nails.

Developer documentation

scons-tool-util - notes for developers

This module is designed to be developed with the help of pipenv.

Initialization

On a fresh clone do:

pipenv install --dev
pipenv run bin/downloads.py
Running tests

There are some end-to-end tests. They can be ran this way:

pipenv run python runtest.py -e test/system

Unit tests may also be executed, for example:

pipenv run python -m unittest discover -t . -s test/unit

All tests may be executed at once

pipenv run python runtest.py -e -a
Creating package for distribution
pipenv run python setup.py sdist bdist_wheel
Uploading to test.pypi.org
pipenv run twine upload -r testpypi dist/*
Uploading to pypi.org
pipenv run twine upload dist/*
Synchronizing requirements-dev.txt with Pipfile.lock
pipenv lock -r --dev > requirements-dev.txt
Generating HTML documentation
pipenv run make html

The generated documentation is writen to build/docs/html, with the index file build/docs/html/index.html.

LICENSE

Copyright (c) 2018 by Paweł Tomulik <ptomulik@meil.pw.edu.pl>

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

API Documentation

This is an official API documentation for the scons-tool-util python package.

Introduction

For specific documentation, please skip to the next sections.

The sconstool.util is an implicit namespaced package (see PEP 420) within sconstool namespace. Because of this, there is no lib/sconstool/__init__.py.

Classes

This section documents classes provided by scons-tool-util package. The summary below provides links to a full documentation for each class.

ToolFinder(tool, **kw) Callable object which helps searching for programs used by SCons tools.

Functions

This section documents functions provided by scons-tool-util package. The summary below provides links to a full documentation for each function.

add_ro_dict_property(cls, dictattr, attr[, …]) Add to class cls a read-only property returning a predefined entry from a dict.
ensure_kwarg_in(caller, key, allowed) Checks a single key from keyword arguments against allowed keys.
ensure_kwarg_not_in(caller, key, forbidden) Checks a single key from keyword arguments against forbidden keys.
check_kwarg(caller, key[, allowed, forbidden]) Checks a single key from keyword arguments against allowed and forbidden keys.
check_kwargs(caller, kw[, allowed, forbidden]) Checks all keys from keyword arguments kw against allowed and forbidden keys.
import_all_from(target, modules[, …]) Imports symbols from multiple modules.

Indices and tables