pyscaffold package¶
Subpackages¶
- pyscaffold.extensions package
- Submodules
- pyscaffold.extensions.cirrus module
- pyscaffold.extensions.config module
- pyscaffold.extensions.gitlab_ci module
- pyscaffold.extensions.interactive module
- pyscaffold.extensions.namespace module
- pyscaffold.extensions.no_pyproject module
- pyscaffold.extensions.no_skeleton module
- pyscaffold.extensions.no_tox module
- pyscaffold.extensions.pre_commit module
- pyscaffold.extensions.venv module
- Module contents
- pyscaffold.templates package
Submodules¶
pyscaffold.actions module¶
Default PyScaffold’s actions and functions to manipulate them.
When generating a project, PyScaffold uses a pipeline of functions (each function will
receive as arguments the values returned by the previous function). These functions
have an specific purpose and are called actions. Please follow the Action
signature when developing your own action.
Note
Some actions are more complex and are placed in dedicated modules together with
other auxiliary functions, see pyscaffold.structure
,
pyscaffold.update
.
-
pyscaffold.actions.
Action
¶ Signature of a PyScaffold action, both arguments should be treated as immutable, but a copy of the arguments, modified by the extension might be returned:
Callable[[Structure, ScaffoldOpts], Tuple[Structure, ScaffoldOpts]]
alias of Callable[[Dict[str, Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]], dict]], Dict[str, Any]], Tuple[Dict[str, Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]], dict]], Dict[str, Any]]]
-
pyscaffold.actions.
ActionParams
¶ Both argument and return type of an action
(struct, opts)
, so a sequence of actions work in pipeline:Tuple[Structure, ScaffoldOpts]
When actions run, they can return an updated copy of
Structure
andScaffoldOpts
.alias of Tuple[Dict[str, Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]], dict]], Dict[str, Any]]
-
pyscaffold.actions.
DEFAULT
: List[Callable[[Dict[str, Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]], dict]], Dict[str, Any]], Tuple[Dict[str, Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]], dict]], Dict[str, Any]]]] = [<function get_default_options>, <function verify_options_consistency>, <function define_structure>, <function verify_project_dir>, <function version_migration>, <function create_structure>, <function init_git>, <function report_done>]¶ Default list of actions forming the main pipeline executed by PyScaffold
-
pyscaffold.actions.
ScaffoldOpts
¶ Dictionary with PyScaffold’s options, see
pyscaffold.api.create_project
.alias of Dict[str, Any]
-
pyscaffold.actions.
discover
(extensions)[source]¶ Retrieve the action list.
This is done by concatenating the default list with the one generated after activating the extensions.
- Parameters
extensions – list of functions responsible for activating the extensions.
-
pyscaffold.actions.
get_default_options
(struct, opts)[source]¶ Compute all the options that can be automatically derived.
This function uses all the available information to generate sensible defaults. Several options that can be derived are computed when possible.
- Parameters
struct – project representation as (possibly) nested
dict
.opts – given options, see
create_project
for an extensive list.
- Returns
project representation and options with default values set
- Return type
ActionParams
- Raises
DirectoryDoesNotExist – when PyScaffold is told to update an nonexistent directory
GitNotInstalled – when git command is not available
GitNotConfigured – when git does not know user information
Note
This function uses git to determine some options, such as author name and email.
-
pyscaffold.actions.
init_git
(struct, opts)[source]¶ Add revision control to the generated files.
- Parameters
struct – project representation as (possibly) nested
dict
.opts – given options, see
create_project
for an extensive list.
- Returns
Updated project representation and options
-
pyscaffold.actions.
invoke
(struct_and_opts, action)[source]¶ Invoke action with proper logging.
- Parameters
struct_and_opts – PyScaffold’s arguments for actions
action – to be invoked
- Returns
updated project representation and options
- Return type
ActionParams
-
pyscaffold.actions.
register
(actions, action, before=None, after=None)[source]¶ Register a new action to be performed during scaffold.
- Parameters
actions (List[Action]) – previous action list.
action (Action) –
function with two arguments: the first one is a (nested) dict representing the file structure of the project and the second is a dict with scaffold options. This function MUST return a tuple with two elements similar to its arguments. Example:
def do_nothing(struct, opts): return (struct, opts)
**kwargs (dict) –
keyword arguments make it possible to choose a specific order when executing actions: when
before
orafter
keywords are provided, the argument value is used as a reference position for the new action. Example:register(actions, do_nothing, after='create_structure') # Look for the first action with a name # `create_structure` and inserts `do_nothing` after it. # If more than one registered action is named # `create_structure`, the first one is selected. register( actions, do_nothing, before='pyscaffold.structure:create_structure') # Similar to the previous example, but the probability # of name conflict is decreased by including the module # name.
When no keyword argument is provided, the default execution order specifies that the action will be performed after the project structure is defined, but before it is written to the disk. Example:
register(actions, do_nothing) # The action will take place after # `pyscaffold.structure:define_structure`
- Returns
modified action list.
- Return type
List[Action]
-
pyscaffold.actions.
unregister
(actions, reference)[source]¶ Prevent a specific action to be executed during scaffold.
- Parameters
- Returns
modified action list.
- Return type
List[Action]
-
pyscaffold.actions.
verify_options_consistency
(struct, opts)[source]¶ Perform some sanity checks about the given options.
- Parameters
struct – project representation as (possibly) nested
dict
.opts – given options, see
create_project
for an extensive list.
- Returns
Updated project representation and options
-
pyscaffold.actions.
verify_project_dir
(struct, opts)[source]¶ Check if PyScaffold can materialize the project dir structure.
- Parameters
struct – project representation as (possibly) nested
dict
.opts – given options, see
create_project
for an extensive list.
- Returns
Updated project representation and options
pyscaffold.api module¶
External API for accessing PyScaffold programmatically via Python.
-
pyscaffold.api.
DEFAULT_OPTIONS
= {'config_files': [], 'description': 'Add a short description here!', 'extensions': [], 'force': False, 'license': 'MIT', 'update': False, 'url': 'https://github.com/pyscaffold/pyscaffold/', 'version': 'unknown'}¶ Default values for PyScaffold’s options.
Options that can be derived from the values of other options (e.g.
package
can be derived fromproject_path
when not explicitly passed) are computed inpyscaffold.actions.get_default_options
.When
config_files
is empty, a default value is computed dynamically bypyscaffold.info.config_file
before the start of PyScaffold’s action pipeline.Warning
Default values might be dynamically overwritten by
config_files
or, during updates, existingsetup.cfg
.
-
pyscaffold.api.
NO_CONFIG
= <ConfigFiles.NO_CONFIG: 1>¶ This constant is used to tell PyScaffold to not load any extra configuration file, not even the default ones Usage:
create_project(opts, config_files=NO_CONFIG)
Please notice that the
setup.cfg
file inside an project being updated will still be considered.
-
pyscaffold.api.
bootstrap_options
(opts=None, **kwargs)[source]¶ Internal API: augment the given options with minimal defaults and existing configurations saved in files (e.g.
setup.cfg
)See list of arguments in
create_project
. Returns a dictionary of options.Warning
This function is not part of the public Python API of PyScaffold, and therefore might change even in minor/patch releases (not bounded to semantic versioning).
Note
This function does not replace the
pyscaffold.actions.get_default_options
action. Instead it is needed to ensure that action works correctly.
-
pyscaffold.api.
create_project
(opts=None, **kwargs)[source]¶ Create the project’s directory structure
- Parameters
opts (dict) – options of the project
**kwargs – extra options, passed as keyword arguments
- Returns
a tuple of struct and opts dictionary
- Return type
Valid options include:
- Project Information
project_path (
os.PathLike
orstr
)
- Naming
name (str): as in
pip install
or in PyPIpackage (str): Python identifier as in
import
(without namespace)
- Package Information
author (str)
email (str)
release_date (str)
year (str)
title (str)
description (str)
url (str)
classifiers (str)
requirements (list)
- PyScaffold Control
update (bool)
force (bool)
pretend (bool)
extensions (list)
config_files (list or
NO_CONFIG
)
Some of these options are equivalent to the command line options, others are used for creating the basic python package meta information, but the ones in the “PyScaffold Control” group affects how the “scaffolding” behaves.
When the force flag is
True
, existing files will be overwritten. When the update flag isTrue
, PyScaffold will consider that some files can be updated (usually the packaging boilerplate), but will keep others intact. When the pretend flag isTrue
, the project will not be created/updated, but the expected outcome will be logged.The extensions list may contain any object that follows the extension API. Note that some PyScaffold features, such as cirrus, tox and pre-commit support, are implemented as built-in extensions. In order to use these features it is necessary to include the respective objects in the extension list. All built-in extensions are accessible via
pyscaffold.extensions
submodule.Finally, when
setup.cfg
-like files are added to the config_files list, PyScaffold will read it’s options from there in addition to the ones already passed. If the list is empty, the default configuration file is used. To avoid reading any existing configuration, please passconfig_file=NO_CONFIG
. See https://pyscaffold.org/en/latest/configuration.html for more details.Note that extensions may define extra options. For example, the cookiecutter extension define a
cookiecutter
option that should be the address to the git repository used as template and thenamespace
extension define anamespace
option with the name of a PEP 420 compatible (and possibly nested) namespace.
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.
-
pyscaffold.cli.
add_extension_args
(parser)[source]¶ Add options and arguments defined by extensions to the CLI parser.
Add options that control verbosity/logger level
-
pyscaffold.cli.
get_log_level
(args=None)[source]¶ Get the configured log level directly by parsing CLI options from
args
or obj:sys.argv.Useful when the CLI crashes before applying the changes to the logger.
-
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 – command line arguments
pyscaffold.dependencies module¶
Internal library for manipulating package dependencies and requirements.
-
pyscaffold.dependencies.
BUILD
= ('setuptools_scm>=5', 'wheel')¶ Dependencies that will be required to build the created project
-
pyscaffold.dependencies.
ISOLATED
= ('setuptools>=46.1.0', 'setuptools_scm[toml]>=5', 'wheel')¶ Dependencies for isolated builds (PEP517/518). - setuptools min version might be slightly higher then the version required at runtime. - setuptools_scm requires an optional dependency to work with pyproject.toml
-
pyscaffold.dependencies.
REQ_SPLITTER
= re.compile(';(?!\\s*(python|platform|implementation|os|sys)_)', re.MULTILINE)¶ Regex to split requirements that considers both setup.cfg specs and PEP 508 (in a good enough simplified fashion).
-
pyscaffold.dependencies.
RUNTIME
= ('importlib-metadata; python_version<"3.8"',)¶ Dependencies that will be required at runtime by the created project
-
pyscaffold.dependencies.
add
(requirements, to_add=('setuptools_scm>=5', 'wheel'))[source]¶ Given a sequence of individual requirement strings, add
to_add
to it. By default addsBUILD
ifto_add
is not given.
-
pyscaffold.dependencies.
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.dependencies.
deduplicate
(requirements)[source]¶ Given a sequence of individual requirement strings, e.g.
["appdirs>=1.4.4", "packaging>20.0"]
, remove the duplicated packages. If a package is duplicated, the last occurrence stays.
pyscaffold.exceptions module¶
Functions for exception manipulation + 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
orforce
option was used.
-
exception
pyscaffold.exceptions.
DirectoryDoesNotExist
[source]¶ Bases:
RuntimeError
No directory was found to be updated.
-
exception
pyscaffold.exceptions.
ErrorLoadingExtension
(extension='', entry_point=None)[source]¶ Bases:
RuntimeError
There was an error loading ‘{extension}’. Please make sure you have installed a version of the extension that is compatible with PyScaffold {version}. You can also try unininstalling it.
-
exception
pyscaffold.exceptions.
GitDirtyWorkspace
(message="Your working tree is dirty. Commit your changes first or use '--force'.", *args, **kwargs)[source]¶ Bases:
RuntimeError
Workspace of git is empty.
-
DEFAULT_MESSAGE
= "Your working tree is dirty. Commit your changes first or use '--force'."¶
-
-
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.
ImpossibleToFindConfigDir
(message=None, *args, **kwargs)[source]¶ Bases:
RuntimeError
An expected error occurred when trying to find the config dir.
This might be related to not being able to read the $HOME env var in Unix systems, or %USERPROFILE% in Windows, or even the username.
-
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 (<38.3). 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.
-
DEFAULT_MESSAGE
= 'Your setuptools version is too old (<38.3). 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
[source]¶ Bases:
RuntimeError
Outputs proper logging when a ShellCommand fails
pyscaffold.file_system module¶
Internal library that encapsulate file system manipulation. Examples include: creating/removing files and directories, changing permissions, etc.
Functions in this library usually extend the behaviour of Python’s standard lib by
providing proper error handling or adequate logging/control flow in the context of
PyScaffold (an example of adequate control flow logic is dealing with the pretend
flag).
-
pyscaffold.file_system.
ERROR_INVALID_NAME
= 123¶ Windows-specific error code indicating an invalid pathname.
-
pyscaffold.file_system.
chmod
(path, mode, pretend=False)[source]¶ Change the permissions of file in the given path.
This function reports the operation in the logs.
-
pyscaffold.file_system.
create_directory
(path, update=False, pretend=False)[source]¶ Create a directory in the given path.
This function reports the operation in the logs.
-
pyscaffold.file_system.
create_file
(path, content, pretend=False, encoding='utf-8')[source]¶ Create a file in the given path.
This function reports the operation in the logs.
- Parameters
path – path in the file system where contents will be written.
content – what will be written.
pretend (bool) – false by default. File is not written when pretending, but operation is logged.
- Returns
given path
- Return type
Path
-
pyscaffold.file_system.
is_pathname_valid
(pathname)[source]¶ Check if a pathname is valid
Code by Cecil Curry from StackOverflow
- Parameters
pathname (str) – string to validate
- Returns
True if the passed pathname is a valid pathname for the current OS; False otherwise.
-
pyscaffold.file_system.
localize_path
(path_string)[source]¶ Localize path for Windows, Unix, i.e. / or
-
pyscaffold.file_system.
move
(*src, target, **kwargs)[source]¶ Move files or directories to (into) a new location
- Parameters
*src (PathLike) – one or more files/directories to be moved
- Keyword Arguments
-
pyscaffold.file_system.
on_ro_error
(func, path, exc_info)[source]¶ Error handler for
shutil.rmtree
.If the error is due to an access error (read only file) it attempts to add write permission and then retries.
If the error is for another reason it re-raises the error.
Usage :
shutil.rmtree(path, onerror=onerror)
- Parameters
func (callable) – function which raised the exception
path (str) – path passed to func
exc_info (tuple of str) – exception info returned by sys.exc_info()
pyscaffold.identification module¶
Internal library for manipulating, creating and dealing with names, or more generally identifiers.
-
pyscaffold.identification.
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.identification.
deterministic_name
(obj)[source]¶ Private API that returns an string that can be used to deterministically deduplicate and sort sequences of objects.
-
pyscaffold.identification.
deterministic_sort
(sequence)[source]¶ Private API that order a sequence of objects lexicographically (by
deterministic_name
), removing duplicates, which is needed for determinism.The main purpose of this function is to deterministically sort a sequence of PyScaffold extensions (it will also sort internal extensions before external: “pyscaffold.*” < “pyscaffoldext.*”).
-
pyscaffold.identification.
get_id
(function)[source]¶ Given a function, calculate its identifier.
A identifier is a string in the format
<module name>:<function name>
, similarly to the convention used for setuptools entry points.Note
This function does not return a Python 3
__qualname__
equivalent. If the function is nested inside another function or class, the parent name is ignored.- Parameters
function (callable) – function object
-
pyscaffold.identification.
is_valid_identifier
(string)[source]¶ Check if string is a valid package name
- Parameters
string – package name
- Returns
True if string is valid package name else False
-
pyscaffold.identification.
levenshtein
(s1, s2)[source]¶ Calculate the Levenshtein distance between two strings
- Parameters
s1 – first string
s2 – second string
- Returns
Distance between s1 and s2
-
pyscaffold.identification.
make_valid_identifier
(string)[source]¶ Try to make a valid package name identifier from a string
- Parameters
string – invalid package name
- Returns
Valid package name as string or
RuntimeError
- Raises
InvalidIdentifier – raised if identifier can not be converted
pyscaffold.info module¶
Provide general information about the system, user and the package itself.
-
pyscaffold.info.
CONFIG_FILE
= 'default.cfg'¶ PyScaffold’s own config file name
-
class
pyscaffold.info.
GitEnv
(value)[source]¶ Bases:
enum.Enum
An enumeration.
-
committer_date
= 'GIT_COMMITTER_DATE'¶
-
committer_email
= 'GIT_COMMITTER_EMAIL'¶
-
committer_name
= 'GIT_COMMITTER_NAME'¶
-
-
pyscaffold.info.
RAISE_EXCEPTION
= <default.RAISE_EXCEPTION: 1>¶ When no default value is passed, an exception should be raised
-
pyscaffold.info.
best_fit_license
(txt)[source]¶ Finds proper license name for the license defined in txt
-
pyscaffold.info.
check_git
()[source]¶ Checks for git and raises appropriate exception if not
- Raises
GitNotInstalled – when git command is not available
GitNotConfigured – when git does not know user information
-
pyscaffold.info.
config_dir
(prog='pyscaffold', org=None, default=<default.RAISE_EXCEPTION: 1>)[source]¶ Finds the correct place where to read/write configurations for the given app.
- Parameters
prog – program name (defaults to pyscaffold)
org – organisation/author name (defaults to the same as
prog
)default – default value to return if an exception was raise while trying to find the config dir. If no default value is passed, an
ImpossibleToFindConfigDir
execution is raised.
Please notice even if the directory doesn’t exist, if its path is possible to calculate, this function will return a Path object (that can be used to create the directory)
- Returns
Location somewhere in the user’s home directory where to put the configs.
-
pyscaffold.info.
config_file
(name='default.cfg', prog='pyscaffold', org=None, default=<default.RAISE_EXCEPTION: 1>)[source]¶ Finds a file inside
config_dir
.- Parameters
name – file you are looking for
The other args are the same as in
config_dir
and have the same meaning.- Returns
Location of the config file or default if an error happened.
-
pyscaffold.info.
get_curr_version
(project_path)[source]¶ Retrieves the PyScaffold version that put up the scaffold
- Parameters
project_path – path to project
- Returns
version specifier
- Return type
Version
-
pyscaffold.info.
is_git_configured
()[source]¶ Check if user.name and user.email is set globally in git
Check first git environment variables, then config settings. This will also return false if git is not available at all.
- Returns
True if it is set globally, False otherwise
-
pyscaffold.info.
is_git_workspace_clean
(path)[source]¶ Checks if git workspace is clean
- Parameters
path –
path to git repository
- Raises:
GitNotInstalled
: when git command is not availableGitNotConfigured
: when git does not know user information
-
pyscaffold.info.
project
(opts, config_path=None, config_file=None)[source]¶ Update user options with the options of an existing config file
- Parameters
opts – options of the project
config_path – path where config file can be found (default:
opts["project_path"]
)config_file – if
config_path
is a directory, name of the config file, relative to it (default:setup.cfg
)
- Returns
Options with updated values
- Raises
PyScaffoldTooOld – when PyScaffold is to old to update from
NoPyScaffoldProject – when project was not generated with PyScaffold
-
pyscaffold.info.
read_pyproject
(path, filename='pyproject.toml')[source]¶ Reads-in a configuration file that follows a pyproject.toml format.
- Parameters
path – path where to find the config file
filename – if
path
is a directory,name
will be considered a file relative topath
to read (default: setup.cfg)
- Returns
Object that can be used to read/edit configuration parameters.
-
pyscaffold.info.
read_setupcfg
(path, filename='setup.cfg')[source]¶ Reads-in a configuration file that follows a setup.cfg format. Useful for retrieving stored information (e.g. during updates)
- Parameters
path – path where to find the config file
filename – if
path
is a directory,name
will be considered a file relative topath
to read (default: setup.cfg)
- Returns
Object that can be used to read/edit configuration parameters.
pyscaffold.log module¶
Custom logging infrastructure to provide execution information for the user.
-
class
pyscaffold.log.
ColoredReportFormatter
(fmt=None, datefmt=None, style='%', validate=True)[source]¶ Bases:
pyscaffold.log.ReportFormatter
Format logs with ANSI colors.
-
ACTIVITY_STYLES
: DefaultDict[str, Sequence[str]] = {'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
: DefaultDict[str, Sequence[str]] = {'critical': ('red', 'bold'), 'debug': ('green',), 'error': ('red',), 'info': ('blue',), 'warning': ('yellow',)}¶
-
TARGET_PREFIX
= '\x1b[35m\x1b[1mto\x1b[0m'¶
-
-
pyscaffold.log.
DEFAULT_LOGGER
= 'pyscaffold.log'¶ Name of PyScaffold’s default logger (it can be used with
logging.getLogger
)
-
class
pyscaffold.log.
ReportFormatter
(fmt=None, datefmt=None, style='%', validate=True)[source]¶ Bases:
logging.Formatter
Formatter that understands custom fields in the log record.
-
ACTIVITY_MAXLEN
= 12¶
-
CONTEXT_PREFIX
= 'from'¶
-
SPACING
= ' '¶
-
TARGET_PREFIX
= 'to'¶
-
-
class
pyscaffold.log.
ReportLogger
(logger=None, handler=None, formatter=None, extra=None, propagate=False)[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.
propagate (bool) – whether or not to propagate messages in the logging hierarchy,
False
by default. Seelogging.Logger.propagate
.
-
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.
-
property
formatter
¶ Formatter configured in the default handler
-
property
handler
¶ Stream handler configured for providing user feedback in PyScaffold CLI
-
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.
Note
This method is not thread-safe and should be used with care.
-
property
level
¶ Effective level of the logger
-
property
propagate
¶ Whether or not to propagate messages in the logging hierarchy, See
logging.Logger.propagate
.
-
reconfigure
(opts=None, **kwargs)[source]¶ Reconfigure some aspects of the logger object.
- Parameters
opts (dict) – dict with the same elements as the keyword arguments bellow
- Keyword Arguments
log_level – One of the log levels specified in the
logging
module.use_colors – automatically set a colored formatter to the logger if ANSI codes support is detected. (Defaults to True).
Additional keyword arguments will be ignored.
-
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 or os.PathLike) – usually a path in the file system or an action identifier.
context (str or os.PathLike) – path where the activity take place.
target (str or os.PathLike) – 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
. Seelogging
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')
-
property
wrapped
¶ Underlying logger object
-
pyscaffold.log.
logger
= <ReportLogger pyscaffold.log (WARNING)>¶ Default logger configured for PyScaffold.
pyscaffold.operations module¶
Collection of functions responsible for the “reification” of the file representation in the project structure into a file written to the disk.
A function that “reifies” a file (manifests the programmatic representation of the file
in the project structure dictionary to the disk) is called here a file operation or
simply a file op. Actually file ops don’t even need to be functions strictly
speaking, they can be any callable
object. The only restriction is that file ops
MUST respect the FileOp
signature. The create
function is a good
example of how to write a new file op.
A function (or callable) that modifies the behaviour of an existing file op, by wrapping
it with another function/callable is called here modifier. Modifiers work similarly
to Python decorators and allow extending/refining the existing file ops.
A modifier should receive a file op as argument and return another file op.
no_overwrite
and skip_on_update
are good examples on how to write new file
op modifiers.
While modifiers don’t have a specific signature (the number of parameters might vary, but they always return a single file op value), the following conventions SHOULD be observed when creating new modifiers:
Modifiers should accept at least one argument: the file op they modify (you don’t have to be very creative, go ahead and name this parameter
file_op
, it is a good convention). This parameter should be made optional (the default value ofcreate
usually works, unless there is a better default value for the main use case of the modifier).Modifiers can accept arguments other then the file op they modify. These arguments should precede the file op in the list of arguments (the file op should be the last argument, which interoperates well with
partial
).When writing a modifier that happens to be a function (instead of a callable class), please name the inner function with the same name of the modifier but preceded by an
_
(underscore) char. This allows better inspection/debugging.
Changed in version 4.0: Previously, file operations where simply indicated as a numeric flag
(the members of pyscaffold.structure.FileOp
) in the project structure.
Starting from PyScaffold 4, file operation are functions with signature given by
FileOp
.
-
pyscaffold.operations.
FileContents
¶ When the file content is
None
, the file should not be written to disk (empty files are represented by an empty string""
as content).alias of Optional[str]
-
pyscaffold.operations.
FileOp
¶ Signature of functions considered file operations:
Callable[[Path, FileContents, ScaffoldOpts], Union[Path, None]]
- Parameters
path (pathlib.Path) – file path potentially to be written to/changed in the disk.
contents (
FileContents
) – usually a string that represents a text content of the file.None
indicates the file should not be written.opts (
ScaffoldOpts
) – a dict with PyScaffold’s options.
- Returns
If the file is written (or more generally changed, such as new access permissions), by convention they should return the
file path
. If no file was touched,None
should be returned. Please notice a FileOp might returnNone
if a pre-existing file in the disk is not modified.
Note
A FileOp usually has side effects (e.g. write a file to the disk), see
FileFileContents
andScaffoldOpts
for other conventions.alias of Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]
-
pyscaffold.operations.
ScaffoldOpts
¶ Dictionary with PyScaffold’s options, see
pyscaffold.api.create_project
. Should be treated as immutable (if required, copy before changing).Please notice some behaviours given by the options SHOULD be observed. For example, files should be overwritten when the force option is
True
. Similarly when pretend isTrue
, no operation should be really performed, but any action should be logged as if realized.alias of Dict[str, Any]
-
pyscaffold.operations.
add_permissions
(permissions, file_op=<function create>)[source]¶ File op modifier. Returns a
FileOp
that will add access permissions to the file (on top of the ones given by default by the OS).- Parameters
permissions (int) –
permissions to be added to file:
updated file mode = old mode | permissions (bitwise OR)
Preferably the values should be a combination of
stat.S_*
values (seeos.chmod
).file_op – a
FileOp
that will be “decorated”. If the file exists in disk afterfile_op
is called (either created or pre-existing),permissions
will be added to it. Default:create
.
Warning
This is an experimental file op and might be subject to incompatible changes (or complete removal) even in minor/patch releases.
Note
File access permissions work in a completely different way depending on the operating system. This file op is straightforward on POSIX systems, but a bit tricky on Windows. It should be safe for desirable but not required effects (e.g. making a file with a shebang executable, but that can also run via
python FILE
), or ensuring files are readable/writable.
-
pyscaffold.operations.
create
(path, contents, opts)[source]¶ Default
FileOp
: always create/write the file even during (forced) updates.
-
pyscaffold.operations.
no_overwrite
(file_op=<function create>)[source]¶ File op modifier. Returns a
FileOp
that does not overwrite an existing file during update (still created if not exists).
-
pyscaffold.operations.
remove
(path, _content, opts)[source]¶ Remove the file if it exists in the disk
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 – path to the project
tag_name – name of the tag
message – 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 – if no git root is found, default is returned
- Returns
top-level path or default
- Return type
-
pyscaffold.repo.
git_tree_add
(struct, prefix='', **kwargs)[source]¶ Adds recursively a directory structure to git
- Parameters
struct – directory structure as dictionary of dictionaries
prefix – prefix for the given directory structure
Additional keyword arguments are passed to the
git
callable object.
pyscaffold.shell module¶
Shell commands like git, django-admin etc.
-
pyscaffold.shell.
EDITORS
= ('sensible-editor', 'nvim', 'vim', 'nano', 'subl', 'code', 'notepad', 'vi')¶ Programs to be tried (in sequence) when calling
edit
andget_editor
in the case the environment variables EDITOR and VISUAL are not set.
-
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 – command to handle
shell – run the command in the shell
cwd – 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.
-
run
(*args, **kwargs)[source]¶ Execute command with the given arguments via
subprocess.run
.
-
pyscaffold.shell.
command_exists
(cmd)[source]¶ Check if command exists
- Parameters
cmd – executable name
-
pyscaffold.shell.
edit
(file, *args, **kwargs)[source]¶ Open a text editor and returns back a
Path
to file, after user editing.
-
pyscaffold.shell.
get_command
(name, prefix='/home/docs/checkouts/readthedocs.org/user_builds/pyscaffold/envs/v4.0', include_path=True, **kwargs)[source]¶ Similar to
get_executable
but return an instance ofShellCommand
if it is there to be found. Additional kwargs will be passed to theShellCommand
constructor.
-
pyscaffold.shell.
get_executable
(name, prefix='/home/docs/checkouts/readthedocs.org/user_builds/pyscaffold/envs/v4.0', include_path=True)[source]¶ Find an executable in the system, if available.
- Parameters
name – name of the executable
prefix – look on this directory, exclusively or in additon to $PATH depending on the value of
include_path
. Defaults tosys.prefix
.include_path – when True the functions tries to look in the entire $PATH.
-
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.structure module¶
Functionality to generate and work with the directory structure of a project.
Changed in version 4.0: Callable[[dict], str]
and string.Template
objects can also be used as file
contents. They will be called with PyScaffold’s opts
(string.Template
via
safe_substitute
)
-
pyscaffold.structure.
AbstractContent
¶ Recipe for obtaining file contents
Union[FileContents, Callable[[ScaffoldOpts], FileContents], Template]
alias of Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template]
-
pyscaffold.structure.
ActionParams
¶ See
pyscaffold.actions.ActionParams
alias of Tuple[Dict[str, Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]], dict]], Dict[str, Any]]
-
pyscaffold.structure.
Leaf
¶ Just the content of the file OR a tuple of content + file operation
Union[AbstractContent, ResolvedLeaf]
alias of Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]]]
-
pyscaffold.structure.
Node
¶ Representation of a file system node in the project structure (e.g. files, directories:
Union[Leaf, Structure]
alias of Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]], dict]
-
pyscaffold.structure.
ReifiedLeaf
¶ Similar to
ResolvedLeaf
but with file contents “reified”, i.e. an actual string instead of a “lazy object” (such as a function or template).alias of Tuple[Optional[str], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]]
-
pyscaffold.structure.
ResolvedLeaf
¶ Complete recipe for manipulating a file in disk (not only its contents but also the file operation:
Tuple[AbstractContent, FileOp]
alias of Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]]
-
pyscaffold.structure.
Structure
¶ The directory tree represented as a (possibly nested) dictionary:
Structure = Dict[str, Node] Node = Union[Leaf, Structure]
The keys indicate the path where a file will be written, while the value indicates the content.
A nested dictionary represent a nested directory, while
str
,string.Template
andcallable
values represent a file to be created.tuple
values are also allowed, and in that case, the first element of the tuple represents the file content while the second element is apyscaffold.operations
(which can be seen as a recipe on how to create a file with the given content).Callable
file contents are transformed into strings by calling them withPyScaffold's option dict as argument
. Similarly,string.Template.safe_substitute
are called with PyScaffold’s opts.The top level keys in the dict are file/dir names relative to the project root, while keys in nested dicts are relative to the parent’s key/location.
For example:
from pyscaffold.operations import no_overwrite struct: Structure = { 'namespace': { 'module.py': ('print("Hello World!")', no_overwrite()) } }
represents a
namespace/module.py
file inside the project folder with contentprint("Hello World!")
, that will be created only if not present.Note
None
file contents are ignored and not created in disk.alias of Dict[str, Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template, Tuple[Union[str, None, Callable[[Dict[str, Any]], Optional[str]], string.Template], Callable[[pathlib.Path, Optional[str], Dict[str, Any]], Optional[pathlib.Path]]], dict]]
-
pyscaffold.structure.
create_structure
(struct, opts, prefix=None)[source]¶ Manifests/reifies a directory structure in the filesystem
- Parameters
struct – directory structure as dictionary of dictionaries
opts – options of the project
prefix – 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
- Raises
TypeError – raised if content type in struct is unknown
Changed in version 4.0: Also accepts
string.Template
andcallable
objects as file contents.
-
pyscaffold.structure.
define_structure
(struct, opts)[source]¶ Creates the project structure as dictionary of dictionaries
- Parameters
struct – previous directory structure (usually and empty dict)
opts – options of the project
- Returns
Project structure and PyScaffold’s options
Changed in version 4.0:
string.Template
and functions added directly to the file structure.
-
pyscaffold.structure.
ensure
(struct, path, content=None, file_op=<function create>)[source]¶ Ensure a file exists in the representation of the project tree with the provided content. All the parent directories are automatically created.
- Parameters
struct – project representation as (possibly) nested.
path –
path-like string or object relative to the structure root. See
modify
.Changed in version 4.0: The function no longer accepts a list of strings of path parts.
content – file text contents,
None
by default. The old content is preserved ifNone
.file_op – see
pyscaffold.operations
,create`
by default.
Changed in version 4.0: Instead of a
update_rule
flag, the function now accepts afile_op
.- Returns
Updated project tree representation
Note
Use an empty string as content to ensure a file is created empty.
-
pyscaffold.structure.
merge
(old, new)[source]¶ Merge two dict representations for the directory structure.
Basically a deep dictionary merge, except from the leaf update method.
- Parameters
old – directory descriptor that takes low precedence during the merge.
new – directory descriptor that takes high precedence during the merge.
Changed in version 4.0: Project structure now considers everything under the top level project folder.
- Returns
Resulting merged directory representation
Note
Use an empty string as content to ensure a file is created empty. (
None
contents will not be created).
-
pyscaffold.structure.
modify
(struct, path, modifier)[source]¶ Modify the contents of a file in the representation of the project tree.
If the given path does not exist, the parent directories are automatically created.
- Parameters
struct – project representation as (possibly) nested dict. See
merge
.path –
path-like string or object relative to the structure root. The following examples are equivalent:
from pathlib import Path 'docs/api/index.html' Path('docs', 'api', 'index.html')
Changed in version 4.0: The function no longer accepts a list of strings of path parts.
modifier –
function (or callable object) that receives the old content and the old file operation as arguments and returns a tuple with the new content and new file operation. Note that, if the file does not exist in
struct
,None
will be passed as argument. Example:modifier = lambda old, op: ((old or '') + 'APPENDED CONTENT'!, op) modifier = lambda old, op: ('PREPENDED CONTENT!' + (old or ''), op)
Changed in version 4.0:
modifier
requires 2 arguments and now is a mandatory argument.
Changed in version 4.0:
update_rule
is no longer an argument. Instead the aritymodifier
was changed to accept 2 arguments instead of only 1. This is more suitable to handling the newpyscaffold.operations
API.- Returns
Updated project tree representation
Note
Use an empty string as content to ensure a file is created empty (
None
contents will not be created).
-
pyscaffold.structure.
reify_content
(content, opts)[source]¶ Make content string (via __call__ or safe_substitute with opts if necessary)
-
pyscaffold.structure.
reify_leaf
(contents, opts)[source]¶ Similar to
resolve_leaf
but appliesreify_content
to the first element of the returned tuple.
-
pyscaffold.structure.
reject
(struct, path)[source]¶ Remove a file from the project tree representation if existent.
- Parameters
struct – project representation as (possibly) nested.
path –
path-like string or object relative to the structure root. See
modify
.Changed in version 4.0: The function no longer accepts a list of strings of path parts.
- Returns
Modified project tree representation
pyscaffold.termui module¶
Basic support for ANSI code formatting.
-
pyscaffold.termui.
STYLES
= {'black': 30, 'blue': 34, 'bold': 1, 'clear': 0, 'cyan': 36, 'green': 32, 'magenta': 35, 'on_black': 40, 'on_blue': 44, 'on_cyan': 46, 'on_green': 42, 'on_magenta': 45, 'on_red': 41, 'on_white': 47, 'on_yellow': 43, 'red': 31, 'white': 37, 'yellow': 33}¶ Possible
styles
fordecorate
-
pyscaffold.termui.
SYSTEM_SUPPORTS_COLOR
= True¶ Handy indicator of the system capabilities (relies on colorama if available)
-
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
-
pyscaffold.termui.
init_colorama
()[source]¶ Initialize colorama if it is available.
- Returns
result of check
- Return type
pyscaffold.toml module¶
Thin wrapper around the dependency so we can maintain some stability while being able to swap implementations (e.g. replace tomlkit with toml).
Despite being used in pep517, toml offers limited support for comments, so we prefer tomlkit.
-
pyscaffold.toml.
TOMLMapping
¶ Abstraction on the value returned by
loads
.This kind of object ideally should present a dict-like interface and be able to preserve the formatting and comments of the original TOML file.
alias of
MutableMapping
[str
,Any
]
-
pyscaffold.toml.
dumps
(obj)[source]¶ Serialize a dict-like object into a TOML str, If the object was generated via
loads
, then the style will be preserved.
pyscaffold.update module¶
Functionality to update one PyScaffold version to another
-
pyscaffold.update.
ALWAYS
= <VersionUpdate.ALWAYS: 1>¶ Perform the update action regardless of the version
-
pyscaffold.update.
handover_setup_requires
(setupcfg, opts)[source]¶ When paired with
update_pyproject_toml
, this will transfersetup.cfg :: options.setup_requires
topyproject.toml :: build-system.requires
-
pyscaffold.update.
update_pyproject_toml
(struct, opts)[source]¶ Update old pyproject.toml generated by pyscaffoldext-pyproject and import setup_requires from update_setup_cfg into build-system.requires.