pyscaffold package

Submodules

pyscaffold.cli module

Command-Line-Interface of PyScaffold

pyscaffold.cli.add_default_args(parser)[source]

Add the default options and arguments to the CLI parser.

Parameters:parser (argparse.ArgumentParser) – CLI parser object
pyscaffold.cli.list_actions(opts)[source]

Do not create a project, just list actions considering extensions

Parameters:opts (dict) – command line options as dictionary
pyscaffold.cli.main(args)[source]

Main entry point for external applications

Parameters:args ([str]) – command line arguments
pyscaffold.cli.parse_args(args)[source]

Parse command line parameters

Parameters:args ([str]) – command line parameters as list of strings
Returns:command line parameters
Return type:dict
pyscaffold.cli.run()[source]

Entry point for console script

pyscaffold.cli.run_scaffold(opts)[source]

Actually scaffold the project, calling the python API

Parameters:opts (dict) – command line options as dictionary

pyscaffold.exceptions module

Custom exceptions used by PyScaffold to identify common deviations from the expected behavior.

exception pyscaffold.exceptions.ActionNotFound(name, *args, **kwargs)[source]

Bases: KeyError

Impossible to find the required action.

exception pyscaffold.exceptions.DirectoryAlreadyExists[source]

Bases: RuntimeError

The project directory already exists, but no update or force option was used.

exception pyscaffold.exceptions.DirectoryDoesNotExist[source]

Bases: RuntimeError

No directory was found to be updated.

exception pyscaffold.exceptions.GitNotConfigured(message='Make sure git is configured. Run:n git config --global user.email "you@example.com"n git config --global user.name "Your Name"nto set your account's default identity.', *args, **kwargs)[source]

Bases: RuntimeError

PyScaffold tries to read user.name and user.email from git config.

DEFAULT_MESSAGE = 'Make sure git is configured. Run:\n git config --global user.email "you@example.com"\n git config --global user.name "Your Name"\nto set your account\'s default identity.'
exception pyscaffold.exceptions.GitNotInstalled(message='Make sure git is installed and working.', *args, **kwargs)[source]

Bases: RuntimeError

PyScaffold requires git to run.

DEFAULT_MESSAGE = 'Make sure git is installed and working.'
exception pyscaffold.exceptions.InvalidIdentifier[source]

Bases: RuntimeError

Python requires a specific format for its identifiers.

https://docs.python.org/3.6/reference/lexical_analysis.html#identifiers

exception pyscaffold.exceptions.NoPyScaffoldProject(message='Could not update project. Was it generated with PyScaffold?', *args, **kwargs)[source]

Bases: RuntimeError

PyScaffold cannot update a project that it hasn’t generated

DEFAULT_MESSAGE = 'Could not update project. Was it generated with PyScaffold?'
exception pyscaffold.exceptions.OldSetuptools(message='Your setuptools version is too old (<30.3.0). Use `pip install -U setuptools` to upgrade.nIf you have the deprecated `distribute` package installed remove it or update to version 0.7.3.', *args, **kwargs)[source]

Bases: RuntimeError

PyScaffold requires a recent version of setuptools (>= 12).

DEFAULT_MESSAGE = 'Your setuptools version is too old (<30.3.0). Use `pip install -U setuptools` to upgrade.\nIf you have the deprecated `distribute` package installed remove it or update to version 0.7.3.'
exception pyscaffold.exceptions.PyScaffoldTooOld(message='setup.cfg has no section [pyscaffold]! Are you trying to update a pre 3.0 version?', *args, **kwargs)[source]

Bases: RuntimeError

PyScaffold cannot update a pre 3.0 version

DEFAULT_MESSAGE = 'setup.cfg has no section [pyscaffold]! Are you trying to update a pre 3.0 version?'
exception pyscaffold.exceptions.ShellCommandException(message, *args, **kwargs)[source]

Bases: RuntimeError

Outputs proper logging when a ShellCommand fails

pyscaffold.info module

Provide general information about the system, user etc.

pyscaffold.info.check_git()[source]

Checks for git and raises appropriate exception if not

Raises:
pyscaffold.info.email()[source]

Retrieve the user’s email

Returns:user’s email
Return type:str
pyscaffold.info.is_git_configured()[source]

Check if user.name and user.email is set globally in git

This will also return false if git is not available at all.

Returns:True if it is set globally, False otherwise
Return type:bool
pyscaffold.info.is_git_installed()[source]

Check if git is installed

Returns:True if git is installed, False otherwise
Return type:bool
pyscaffold.info.project(opts)[source]

Update user options with the options of an existing PyScaffold project

Params:
opts (dict): options of the project
Returns:

options with updated values

Return type:

dict

Raises:
pyscaffold.info.username()[source]

Retrieve the user’s name

Returns:user’s name
Return type:str

pyscaffold.integration module

Integration part for hooking into distutils/setuptools

Rationale: The use_pyscaffold keyword is unknown to setuptools’ setup(…) command, therefore the entry_points are checked for a function to handle this keyword which is pyscaffold_keyword below. This is where we hook into setuptools and apply the magic of setuptools_scm as well as other commands.

class pyscaffold.integration.PyTest(dist, **kw)[source]

Bases: pyscaffold.contrib.ptr.PyTest

run_tests()[source]

Invoke pytest, replacing argv.

pyscaffold.integration.build_cmd_docs()[source]

Return Sphinx’s BuildDoc if available otherwise a dummy command

Returns:command object
Return type:Command
pyscaffold.integration.local_version2str(version)[source]

Create the local part of a PEP440 version string

Parameters:version (setuptools_scm.version.ScmVersion) – version object
Returns:local version
Return type:str
pyscaffold.integration.pyscaffold_keyword(dist, keyword, value)[source]

Handles the use_pyscaffold keyword of the setup(…) command

Parameters:
  • dist (setuptools.dist) – distribution object as
  • keyword (str) – keyword argument = ‘use_pyscaffold’
  • value – value of the keyword argument
pyscaffold.integration.version2str(version)[source]

Creates a PEP440 version string

Parameters:version (setuptools_scm.version.ScmVersion) – version object
Returns:version string
Return type:str

pyscaffold.log module

Custom logging infrastructure to provide execution information for the user.

class pyscaffold.log.ColoredReportFormatter(fmt=None, datefmt=None, style='%')[source]

Bases: pyscaffold.log.ReportFormatter

Format logs with ANSI colors.

ACTIVITY_STYLES = {'create': ('green', 'bold'), 'delete': ('red', 'bold'), 'invoke': ('bold',), 'move': ('green', 'bold'), 'remove': ('red', 'bold'), 'run': ('magenta', 'bold'), 'skip': ('yellow', 'bold')}
CONTEXT_PREFIX = '\x1b[35m\x1b[1mfrom\x1b[0m'
LOG_STYLES = {'critical': ('red', 'bold'), 'debug': ('green',), 'error': ('red',), 'info': ('blue',), 'warning': ('yellow',)}
SUBJECT_STYLES = {'invoke': ('blue',)}
TARGET_PREFIX = '\x1b[35m\x1b[1mto\x1b[0m'
format_activity(activity)[source]

Format the activity keyword.

format_default(record)[source]

Format default log messages.

format_subject(subject, activity=None)[source]

Format the subject of the activity.

class pyscaffold.log.ReportFormatter(fmt=None, datefmt=None, style='%')[source]

Bases: logging.Formatter

Formatter that understands custom fields in the log record.

ACTIVITY_MAXLEN = 12
CONTEXT_PREFIX = 'from'
SPACING = ' '
TARGET_PREFIX = 'to'
create_padding(activity)[source]

Create the appropriate padding in order to align activities.

format(record)[source]

Compose message when a record with report information is given.

format_activity(activity)[source]

Format the activity keyword.

format_context(context, _activity=None)[source]

Format extra information about the activity context.

format_default(record)[source]

Format default log messages.

format_path(path)[source]

Simplify paths to avoid wasting space in terminal.

format_report(record)[source]

Compose message when a custom record is given.

format_subject(subject, _activity=None)[source]

Format the subject of the activity.

format_target(target, _activity=None)[source]

Format extra information about the activity target.

class pyscaffold.log.ReportLogger(logger=None, handler=None, formatter=None, extra=None)[source]

Bases: logging.LoggerAdapter

Suitable wrapper for PyScaffold CLI interactive execution reports.

Parameters:
  • logger (logging.Logger) – custom logger to be used. Optional: the default logger will be used.
  • handlers (logging.Handler) – custom logging handler to be used. Optional: a logging.StreamHandler is used by default.
  • formatter (logging.Formatter) – custom formatter to be used. Optional: by default a ReportFormatter is created and used.
  • extra (dict) – extra attributes to be merged into the log record. Options, empty by default.
wrapped

logging.Logger – underlying logger object.

handler

logging.Handler – stream handler configured for providing user feedback in PyScaffold CLI.

formatter

logging.Formatter – formatter configured in the default handler.

nesting

int – current nesting level of the report.

copy()[source]

Produce a copy of the wrapped logger.

Sometimes, it is better to make a copy of th report logger to keep indentation consistent.

indent(count=1)[source]

Temporarily adjust padding while executing a context.

Example

from pyscaffold.log import logger
logger.report('invoke', 'custom_action')
with logger.indent():
   logger.report('create', 'some/file/path')

# Expected logs:
# --------------------------------------
#       invoke  custom_action
#       create    some/file/path
# --------------------------------------
# Note how the spacing between activity and subject in the
# second entry is greater than the equivalent in the first one.
process(msg, kwargs)[source]

Method overridden to augment LogRecord with the nesting attribute.

report(activity, subject, context=None, target=None, nesting=None, level=20)[source]

Log that an activity has occurred during scaffold.

Parameters:
  • activity (str) – usually a verb or command, e.g. create, invoke, run, chdir
  • subject (str) – usually a path in the file system or an action identifier.
  • context (str) – path where the activity take place.
  • target (str) – path affected by the activity
  • nesting (int) – optional nesting level. By default it is calculated from the activity name.
  • level (int) – log level. Defaults to logging.INFO. See logging for more information.

Notes

This method creates a custom log record, with additional fields: activity, subject, context, target and nesting, but an empty msg field. The ReportFormatter creates the log message from the other fields.

Often target and context complement the logs when subject does not hold all the necessary information. For example:

logger.report('copy', 'my/file', target='my/awesome/path')
logger.report('run', 'command', context='current/working/dir')
pyscaffold.log.configure_logger(opts)[source]

Configure the default logger

Parameters:opts (dict) – command line parameters
pyscaffold.log.logger = <pyscaffold.log.ReportLogger object>

Default logger configured for PyScaffold.

pyscaffold.repo module

Functionality for working with a git repository

pyscaffold.repo.add_tag(project, tag_name, message=None, **kwargs)[source]

Add an (annotated) tag to the git repository.

Parameters:
  • project (str) – path to the project
  • tag_name (str) – name of the tag
  • message (str) – optional tag message

Additional keyword arguments are passed to the git callable object.

pyscaffold.repo.get_git_root(default=None)[source]

Return the path to the top-level of the git repository or default.

Parameters:default (str) – if no git root is found, default is returned
Returns:top-level path or default
Return type:str
pyscaffold.repo.git_tree_add(struct, prefix='', **kwargs)[source]

Adds recursively a directory structure to git

Parameters:
  • struct (dict) – directory structure as dictionary of dictionaries
  • prefix (str) – prefix for the given directory structure

Additional keyword arguments are passed to the git callable object.

pyscaffold.repo.init_commit_repo(project, struct, **kwargs)[source]

Initialize a git repository

Parameters:
  • project (str) – path to the project
  • struct (dict) – directory structure as dictionary of dictionaries

Additional keyword arguments are passed to the git callable object.

pyscaffold.repo.is_git_repo(folder)[source]

Check if a folder is a git repository

Parameters:folder (str) – path

pyscaffold.shell module

Shell commands like git, django-admin.py etc.

class pyscaffold.shell.ShellCommand(command, shell=True, cwd=None)[source]

Bases: object

Shell command that can be called with flags like git(‘add’, ‘file’)

Parameters:
  • command (str) – command to handle
  • shell (bool) – run the command in the shell
  • cwd (str) – current working dir to run the command

The produced command can be called with the following keyword arguments:

  • log (bool): log activity when true. False by default.
  • pretend (bool): skip execution (but log) when pretending. False by default.

The positional arguments are passed to the underlying shell command.

pyscaffold.shell.command_exists(cmd)[source]

Check if command exists

Parameters:cmd – executable name
pyscaffold.shell.django_admin = <pyscaffold.shell.ShellCommand object>

Command for django-admin.py

pyscaffold.shell.get_git_cmd(**args)[source]

Retrieve the git shell command depending on the current platform

Parameters:**args – additional keyword arguments to ShellCommand
pyscaffold.shell.git = <pyscaffold.shell.ShellCommand object>

Command for git

pyscaffold.shell.shell_command_error2exit_decorator(func)[source]

Decorator to convert given ShellCommandException to an exit message

This avoids displaying nasty stack traces to end-users

pyscaffold.structure module

Functionality to generate and work with the directory structure of a project

class pyscaffold.structure.FileOp[source]

Bases: object

Namespace for file operations during an update

NO_CREATE = 1

Do not create the file during an update

NO_OVERWRITE = 0

Do not overwrite an existing file during update (still created if not exists)

pyscaffold.structure.apply_update_rule_to_file(path, value, opts)[source]

Applies the update rule to a given file path

Parameters:
  • path (str) – file path
  • value (tuple or str) – content (and update rule)
  • opts (dict) –

    options of the project, containing the following flags:

    • update: when the project already exists and should be updated
    • force: overwrite all the files that already exist
Returns:

content of the file if it should be generated or None otherwise.

pyscaffold.structure.apply_update_rules(struct, opts, prefix=None)[source]

Apply update rules using FileOp to a directory structure.

As a result the filtered structure keeps only the files that actually will be written.

Parameters:
  • opts (dict) –

    options of the project, containing the following flags:

    • update: when the project already exists and should be updated
    • force: overwrite all the files that already exist
  • struct (dict) – directory structure as dictionary of dictionaries (in this tree representation, each leaf can be just a string or a tuple also containing an update rule)
  • prefix (str) – prefix path for the structure
Returns:

directory structure with keys removed according to the rules (in this tree representation, all the leaves are strings) and input options

Return type:

tuple(dict, dict)

pyscaffold.structure.create_structure(struct, opts, prefix=None)[source]

Manifests a directory structure in the filesystem

Parameters:
  • struct (dict) – directory structure as dictionary of dictionaries
  • opts (dict) – options of the project
  • prefix (str) – prefix path for the structure
Returns:

directory structure as dictionary of dictionaries (similar to input, but only containing the files that actually changed) and input options

Return type:

tuple(dict, dict)

Raises:

RuntimeError – raised if content type in struct is unknown

pyscaffold.structure.define_structure(_, opts)[source]

Creates the project structure as dictionary of dictionaries

Parameters:
  • struct (dict) – previous directory structure (ignored)
  • opts (dict) – options of the project
Returns:

structure as dictionary of dictionaries and input options

Return type:

tuple(dict, dict)

pyscaffold.termui module

Basic support for ANSI code formatting.

pyscaffold.termui.curses_available()[source]

Check if the curses package from stdlib is available.

Usually not available for windows, but its presence indicates that the terminal is capable of displaying some UI.

Returns:result of check
Return type:bool
pyscaffold.termui.decorate(msg, *styles)[source]

Use ANSI codes to format the message.

Parameters:
  • msg (str) – string to be formatted
  • *styles (list) – the remaining arguments should be strings that represent the 8 basic ANSI colors. clear and bold are also supported. For background colors use on_<color>.
Returns:

styled and formatted message

Return type:

str

pyscaffold.termui.init_colorama()[source]

Initialize colorama if it is available.

Returns:result of check
Return type:bool
pyscaffold.termui.isatty(stream=None)[source]

Detect if the given stream/stdout is part of an interactive terminal.

Parameters:stream – optionally the stream to check
Returns:result of check
Return type:bool
pyscaffold.termui.supports_color(stream=None)[source]

Check if the stream is supposed to handle coloring.

Returns:result of check
Return type:bool

pyscaffold.utils module

Miscellaneous utilities and tools

pyscaffold.utils.best_fit_license(txt)[source]

Finds proper license name for the license defined in txt

Parameters:txt (str) – license name
Returns:license name
Return type:str
pyscaffold.utils.chdir(path, **kwargs)[source]

Contextmanager to change into a directory

Parameters:

path (str) – path to change current working directory to

Keyword Arguments:
 
  • log (bool) – log activity when true. Default: False.
  • pretend (bool) – skip execution (but log) when pretending. Default False.
pyscaffold.utils.check_setuptools_version()[source]

Check minimum required version of setuptools

Check that setuptools has all necessary capabilities for setuptools_scm as well as support for configuration with the help of setup.cfg.

Raises:OldSetuptools – raised if necessary capabilities are not met
pyscaffold.utils.create_directory(path, update=False, pretend=False)[source]

Create a directory in the given path.

This function reports the operation in the logs.

Parameters:
  • path (str) – path in the file system where contents will be written.
  • update (bool) – false by default. A OSError is raised when update is false and the directory already exists.
  • pretend (bool) – false by default. Directory is not created when pretending, but operation is logged.
pyscaffold.utils.create_file(path, content, pretend=False)[source]

Create a file in the given path.

This function reports the operation in the logs.

Parameters:
  • path (str) – path in the file system where contents will be written.
  • content (str) – what will be written.
  • pretend (bool) – false by default. File is not written when pretending, but operation is logged.
pyscaffold.utils.dasherize(word)[source]

Replace underscores with dashes in the string.

Example:

>>> dasherize("foo_bar")
"foo-bar"
Parameters:word (str) – input word
Returns:input word with underscores replaced by dashes
pyscaffold.utils.exceptions2exit(exception_list)[source]

Decorator to convert given exceptions to exit messages

This avoids displaying nasty stack traces to end-users

Parameters:[Exception] (exception_list) – list of exceptions to convert
pyscaffold.utils.is_valid_identifier(string)[source]

Check if string is a valid package name

Parameters:string (str) – package name
Returns:True if string is valid package name else False
Return type:bool
pyscaffold.utils.levenshtein(s1, s2)[source]

Calculate the Levenshtein distance between two strings

Parameters:
  • s1 (str) – first string
  • s2 (str) – second string
Returns:

distance between s1 and s2

Return type:

int

pyscaffold.utils.list2str(lst, indent=0, brackets=True, quotes=True, sep=', ')[source]

Generate a Python syntax list string with an indention

Parameters:
  • lst ([str]) – list of strings
  • indent (int) – indention
  • brackets (bool) – surround the list expression by brackets
  • quotes (bool) – surround each item with quotes
  • sep (str) – separator for each item
Returns:

string representation of the list

Return type:

str

pyscaffold.utils.make_valid_identifier(string)[source]

Try to make a valid package name identifier from a string

Parameters:string (str) – invalid package name
Returns:valid package name as string or RuntimeError
Return type:str
Raises:InvalidIdentifier – raised if identifier can not be converted
pyscaffold.utils.move(*src, **kwargs)[source]

Move files or directories to (into) a new location

Parameters:

*src (str[]) – one or more files/directories to be moved

Keyword Arguments:
 
  • target (str) – if target is a directory, src will be moved inside it. Otherwise, it will be the new path (note that it may be overwritten)
  • log (bool) – log activity when true. Default: False.
  • pretend (bool) – skip execution (but log) when pretending. Default False.
pyscaffold.utils.prepare_namespace(namespace_str)[source]

Check the validity of namespace_str and split it up into a list

Parameters:namespace_str (str) – namespace, e.g. “com.blue_yonder”
Returns:list of namespaces, e.g. [“com”, “com.blue_yonder”]
Return type:[str]
Raises:InvalidIdentifier – raised if namespace is not valid
pyscaffold.utils.utf8_decode(string)[source]

Decode a Python 2 str object to unicode for compatibility with Python 3

Parameters:string (str) – Python 2 str object or Python 3 str object
Returns:Python 2 unicode object or Python 3 str object
Return type:str
pyscaffold.utils.utf8_encode(string)[source]

Encode a Python 2 unicode object to str for compatibility with Python 3

Parameters:string (str) – Python 2 unicode object or Python 3 str object
Returns:Python 2 str object or Python 3 str object
Return type:str

Module contents