
PyScaffold helps you setup a new Python project. It is as easy as:
putup my_project
This will create a new folder called my_project
containing a perfect project
template with everything you need for some serious coding. After the usual:
python setup.py develop
you are all set and ready to go which means in a Python shell you can do the following:
>>> from my_project.skeleton import fib
>>> fib(10)
55
Type putup -h
to learn about more configuration options. PyScaffold assumes
that you have Git installed and set up on your PC,
meaning at least your name and email are configured.
The project template in my_project
provides you with a lot of
features. PyScaffold is compatible with Python 2.7 and Python
3.4 and greater.
Note
Currently PyScaffold 3.0 needs at least Python 3.4 due to a bug in setuptools that only affects Python 2. For the time being use PyScaffold 2.5.* for Python 2.7 instead.
Contents¶
Features¶
PyScaffold comes with a lot of elaborated features and configuration defaults to make the most common tasks in developing, maintaining and distributing your own Python package as easy as possible.
Configuration & Packaging¶
All configuration can be done in setup.cfg
like changing the description,
url, classifiers, installation requirements and so on as defined by setuptools.
That means in most cases it is not necessary to tamper with setup.py
.
The syntax of setup.cfg
is pretty much self-explanatory and well commented,
check out this example or setuptools’ documentation.
In order to build a source, binary or wheel distribution, just run
python setup.py sdist
, python setup.py bdist
or
python setup.py bdist_wheel
.
Namespace Packages
Optionally, namespace packages can be used, if you are planning to distribute a larger package as a collection of smaller ones. For example, use:
putup my_project --package my_package --namespace com.my_domain
to define my_package
inside the namespace com.my_domain
in java-style.
Package and Files Data
Additional data, e.g. images and text files, that reside within your package and
are tracked by Git will automatically be included
(include_package_data = True
in setup.cfg
).
It is not necessary to have a MANIFEST.in
file for this to work. Just make
sure that all files are added to your repository.
To read this data in your code, use:
from pkgutil import get_data
data = get_data('my_package', 'path/to/my/data.txt')
Complete Git Integration¶
Your project is already an initialised Git repository and setup.py
uses
the information of tags to infer the version of your project with the help of
setuptools_scm.
To use this feature you need to tag with the format MAJOR.MINOR[.PATCH]
, e.g. 0.0.1
or 0.1
.
Run python setup.py --version
to retrieve the current PEP440-compliant version. This version
will be used when building a package and is also accessible through
my_project.__version__
.
Unleash the power of Git by using its pre-commit hooks. This feature is available through the
--pre-commit
flag. After your project’s scaffold was generated, make
sure pre-commit is installed, e.g. pip install pre-commit
, then just run
pre-commit install
.
It goes unsaid that also a default .gitignore
file is provided that is well
adjusted for Python projects and the most common tools.
Sphinx Documentation¶
Build the documentation with python setup.py docs
and run doctests with
python setup.py doctest
after you have Sphinx installed.
Start editing the file docs/index.rst
to extend the documentation.
The documentation also works with Read the Docs.
The Numpy and Google style docstrings are activated by default. Just make sure Sphinx 1.3 or above is installed.
Unittest & Coverage¶
Run python setup.py test
to run all unittests defined in the subfolder
tests
with the help of py.test and
pytest-runner. Some sane
default flags for py.test are already defined in the [pytest]
section of
setup.cfg
. The py.test plugin
pytest-cov is used to automatically
generate a coverage report. It is also possible to provide additional
parameters and flags on the commandline, e.g., type:
python setup.py test --addopts -h
to show the help of py.test.
JUnit and Coverage HTML/XML
For usage with a continuous integration software JUnit and Coverage XML output
can be activated in setup.cfg
. Use the flag --travis
to generate
templates of the Travis configuration files
.travis.yml
and tests/travis_install.sh
which even features the
coverage and stats system Coveralls.
In order to use the virtualenv management and test tool Tox the flag --tox
can be specified.
If you are using GitLab you can get a default
.gitlab-ci.yml also running pytest-cov with the flag --gitlab
.
Managing test environments with tox
Run tox
to generate test virtual environments for various python
environments defined in the generated tox.ini
. Testing and building
sdists for python 2.7 and python 3.4 is just as simple with tox as:
tox -e py27,py34
Environments for tests with the the static code analyzers pyflakes and pep8 which are bundled in flake8 are included as well. Run it explicitly with:
tox -e flake8
With tox, you can use the --recreate
flag to force tox to create new
environments. By default, PyScaffold’s tox configuration will execute tests for
a variety of python versions. If an environment is not available on the system
the tests are skipped gracefully. You can rely on the tox documentation
for detailed configuration options.
Management of Requirements & Licenses¶
Installation requirements of your project can be defined inside setup.cfg
,
e.g. install_requires = numpy; scipy
. To avoid package dependency problems
it is common to not pin installation requirements to any specific version,
although minimum versions, e.g. sphinx>=1.3
, or maximum versions, e.g.
pandas<0.12
, are used sometimes.
More specific installation requirements should go into requirements.txt
.
This file can also be managed with the help of pip compile
from pip-tools
that basically pins packages to the current version, e.g. numpy==1.13.1
.
The packages defined in requirements.txt
can be easily installed with:
pip install -r requirements.txt
All licenses from choosealicense.com can be easily selected with the help
of the --license
flag.
Extensions¶
PyScaffold comes with several extensions:
- Create a Django project with the flag
--django
which is equivalent todjango-admin.py startproject my_project
enhanced by PyScaffold’s features. - With the help of Cookiecutter it is possible to further customize your project
setup with a template tailored for PyScaffold. Just use the flag
--cookiecutter TEMPLATE
to use a cookiecutter template which will be refined by PyScaffold afterwards. - … and many more like
--gitlab
to create the necessary files for GitLab.
There is also documentation about writing extensions.
Easy Updating¶
Keep your project’s scaffold up-to-date by applying
putput --update my_project
when a new version of PyScaffold was released.
An update will only overwrite files that are not often altered by users like
setup.py
. To update all files use --update --force
.
An existing project that was not setup with PyScaffold can be converted with
putup --force existing_project
. The force option is completely safe to use
since the git repository of the existing project is not touched!
Also check out if configuration options in
setup.cfg
have changed.
Updates from PyScaffold 2¶
Since the overall structure of a project set up with PyScaffold 2 differs quite
much from a project generated with PyScaffold 3 it is not possible to just use
the --update
parameter. Still with some manual efforts an update from
a scaffold generated with PyScaffold 2 to PyScaffold 3’s scaffold is quite easy.
Assume the name of our project is old_project
with a package called
old_package
and no namespaces then just:
- make sure your worktree is not dirty, i.e. commit all your changes,
- run
putup old_project --force --no-skeleton -p old_package
to generate the new structure inplace andcd
into your project, - move with
git mv old_package/* src/old_package/ --force
your old package over to the newsrc
directory, - check
git status
and add untracked files from the new structure, - use
git difftool
to check all overwritten files, especiallysetup.cfg
, and transfer custom configurations from the old structure to the new, - check if
python setup.py test sdist
works and commit your changes.
Adding features¶
With the help of an experimental updating functionality it is also possible to
add additional features to your existing project scaffold. If a scaffold lacking
.travis.yml
was created with putup my_project
it can later be added by issuing
putup --update my_project --travis
. For this to work, PyScaffold stores all
options that were initially used to put up the scaffold under the [pysaffold]
section in setup.cfg
. Be aware that right now PyScaffold provides no way to
remove a feature which was once added.
Installation¶
Requirements¶
The installation of PyScaffold only requires a recent version of setuptools,
i.e. at least version 30.3.0, as well as a working installation of Git.
Especially Windows users should make sure that the command git
is available on
the command line. Otherwise, check and update your PATH
environment
variable or run PyScaffold from the Git Bash.
Additionally, if you want to create a Django project or want to use cookiecutter:
Note
It is recommended to use an isolated environment as provided by virtualenv or even better Anaconda for your work with Python in general.
Installation¶
Make sure you have pip
installed, then simply type:
pip install --upgrade pyscaffold
to get the latest stable version. The most recent development version can be installed with:
pip install --pre --upgrade pyscaffold
Using pip
also has the advantage that all requirements are automatically
installed.
If you want to install PyScaffold with all features like Django and cookiecutter support, run:
pip install --upgrade pyscaffold[ALL]
PyScaffold is also available at conda-forge and thus can be installed with conda:
conda install -c conda-forge pyscaffold
Additional Requirements¶
If you run commands like python setup.py test
and python setup.py docs
within your project, some additional requirements like py.test will be
installed automatically as egg-files inside the .eggs
folder. This is
quite comfortable but can be confusing because these packages won’t be
available to other packages inside your virtual environment. In order to avoid
this just install following packages inside your virtual environment before you
run setup.py
commands like doc and test:
Examples¶
Just a few examples to get you an idea of how easy PyScaffold is to use:
putup my_little_project
- The simplest way of using PyScaffold. A directory
my_little_project
is created with a Python package named exactly the same. The MIT license will be used. putup skynet -l gpl3 -d "Finally, the ultimate AI!" -u http://sky.net
- This will create a project and package named skynet licensed under the GPL3.
The summary inside
setup.cfg
is directly set to “Finally, the ultimate AI!” and the homepage to http://sky.net. putup Scikit-Gravity -p skgravity -l new-bsd
- This will create a project named Scikit-Gravity but the package will be named skgravity with license new-BSD.
putup youtub --django --pre-commit -d "Ultimate video site for hot tub fans"
- This will create a web project and package named youtub that also includes
the files created by Django’s
django-admin
. The summary description insetup.cfg
will be set and a file.pre-commit-config.yaml
is created with a default setup for pre-commit. putup thoroughly_tested --tox --travis
- This will create a project and package thoroughly_tested with files
tox.ini
and.travis.yml
for Tox and Travis. putup my_zope_subpackage --namespace zope -l gpl3
- This will create a project and subpackage named my_zope_subpackage in the namespace zope. To be honest, there is really only the Zope project that comes to my mind which is using this exotic feature of Python’s packaging system. Chances are high, that you will never ever need a namespace package in your life.
Configuration¶
Projects set up with PyScaffold feature an easy package configuration with
setup.cfg
. Check out the example below as well as documentation of
setuptools.
[metadata]
name = my_project
description = A test project that was set up with PyScaffold
author = Florian Wilhelm
author-email = Florian.Wilhelm@blue-yonder.com
license = MIT
url = https://...
long-description = file: README.rst
platforms = any
classifiers =
Development Status :: 5 - Production/Stable
Topic :: Utilities
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Environment :: Console
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: POSIX :: Linux
Operating System :: Unix
Operating System :: MacOS
Operating System :: Microsoft :: Windows
[options]
zip_safe = False
packages = find:
include_package_data = True
package_dir =
=src
# Add here dependencies of your project (semicolon-separated)
install_requires = pandas; scikit-learn
# Add here test requirements (semicolon-separated)
tests_require = pytest; pytest-cov
[options.packages.find]
where = src
exclude =
tests
[options.extras_require]
# Add here additional requirements for extra features, like:
# pdf = ReportLab>=1.2; RXP
# rest = docutils>=0.3; pack ==1.1, ==1.3
all = django; cookiecutter
[test]
# py.test options when running `python setup.py test`
addopts = tests --verbose
[tool:pytest]
# Options for py.test:
# Specify command line options as you would do when invoking py.test directly.
# e.g. --cov-report html (or xml) for html/xml output or --junitxml junit.xml
# in order to write a coverage file that can be read by Jenkins.
addopts =
-p coverage
--cov pyscaffold --cov-report term-missing
--verbose
norecursedirs =
dist
build
.tox
[aliases]
release = sdist bdist_wheel upload
[bdist_wheel]
universal = 1
[build_sphinx]
# Options for Sphinx build
source_dir = docs
build_dir = docs/_build
[devpi:upload]
# Options for the devpi: PyPI server and packaging tool
# VCS export must be deactivated since we are using setuptools-scm
no-vcs = 1
formats =
sdist
bdist_wheel
[pyscaffold]
# PyScaffold's parameters when the project was created.
# This will be used when updating. Do not change!
version = 3.0
package = my_package
extensions =
namespace
namespace = ns1.ns2
Migration¶
Migrating your existing project to PyScaffold is in most cases quite easy and requires
only a few steps. We assume your project resides in the Git repository my_project
and includes a package directory my_package
with your Python modules.
Since you surely don’t want to lose your Git history, we will just deploy a new scaffold in the same repository and move as well as change some files. But before you start, please make that your working tree is not dirty, i.e. all changes are committed and all important files are under version control.
Let’s start:
Change into the parent folder of
my_package
and type:putup old_project --force --no-skeleton -p old_package
in order to deploy the new project structure in your repository.
Now move your old package folder into
src
with:git mv old_package/* src/old_package/
Use the same technique if your project has a test folder other than
tests
or a documentation folder other thandocs
.Use
git status
to check for untracked files and add them withgit add
.Eventually, use
git difftool
to check all overwritten files for changes that need to be transferred. Most important is that all configuration that you may have done insetup.py
by passing parameters tosetup(...)
need to be moved tosetup.cfg
. You will figure that out quite easily by putting your oldsetup.py
and the newsetup.cfg
template side by side. Checkout the documentation of setuptools for more information about this conversion. In most cases you will not need to make changes to the newsetup.py
file provided by PyScaffold. The only exceptions are if your project uses compiled resources, e.g. Cython, or if you need to specifyentry_points
.In order to check that everything works, run
python setup.py install
andpython setup.py sdist
. If those two commands don’t work, checksetup.cfg
,setup.py
as well as your package undersrc
again. Where all modules moved correctly? Is there maybe some__init__.py
file missing? After these basic commands, try also to runpython setup.py docs
andpython setup.py test
to check that Sphinx and PyTest runs correctly.
Extending PyScaffold¶
PyScaffold is carefully designed to cover the essentials of authoring and
distributing Python packages. Most of time, tweaking putup
options is
enough to ensure proper configuration of a project.
However, for advanced use cases a deeper level of programmability may be
required and PyScaffold’s extension systems provides this.
PyScaffold can be extended at runtime by other Python packages.
Therefore it is possible to change the behavior of the putup
command line
tool without changing the PyScaffold code itself. In order to explain how this
mechanism works, the following sections define a few important concepts and
present a comprehensive guide about how to create custom extensions.
Additionally, Cookiecutter templates can also be used but writing a native PyScaffold extension is the preferred way.
Project Structure Representation¶
Each Python package project is internally represented by PyScaffold as a tree
data structure, that directly relates to a directory entry in the file system.
This tree is implemented as a simple (and possibly nested) dict
in which
keys indicate the path where files will be generated, while values indicate
their content. For instance, the following dict:
{
'project': {
'folder': {
'file.txt': 'Hello World!',
'another-folder': {'empty-file.txt': ''}
}
}
}
represents a project/folder
directory in the file system containing two
entries. The first entry is a file named file.txt with content Hello World!
while the second entry is a sub-directory named another-folder. In turn,
another-folder contains an empty file named empty-file.txt.
Additionally, tuple values are also allowed in order to specify some useful metadata. In this case, the first element of the tuple is the file content. For example, the dict:
{
'project': {
'namespace': {
'module.py': ('print("Hello World!")', helpers.NO_OVERWRITE)
}
}
}
represents a project/namespace/module.py
file with content
print("Hello World!")
, that will not be overwritten if already exists.
This tree representation is often referred in this document as project structure or simply structure.
Scaffold Actions¶
PyScaffold organizes the generation of a project into a series of steps with well defined purposes. Each step is called action and is implemented as a simple function that receives two arguments: a project structure and a dict with options (some of them parsed from command line arguments, other from default values).
An action MUST return a tuple also composed by a project structure and a dict with options. The return values, thus, are usually modified versions of the input arguments. Additionally an action can also have side effects, like creating directories or adding files to version control. The following pseudo-code illustrates a basic action:
def action(project_structure, options):
new_struct, new_opts = modify(project_structure, options)
some_side_effect()
return new_struct, new_opts
The output of each action is used as the input of the subsequent action, and
initially the structure argument is just an empty dict. Each action is uniquely
identified by a string in the format <module name>:<function name>
,
similarly to the convention used for a setuptools entry point.
For example, if an action is defined in the action
function of the
extras.py
file that is part of the pyscaffoldext.contrib
project,
the action identifier is pyscaffoldext.contrib.extras:action
.
By default, the sequence of actions taken by PyScaffold is:
pyscaffold.api:get_default_options
pyscaffold.api:verify_options_consistency
pyscaffold.structure:define_structure
pyscaffold.structure:apply_update_rules
pyscaffold.structure:create_structure
pyscaffold.api:init_git
The project structure is usually empty until define_structure. This action just loads the in-memory dict representation, that is only written to disk by the create_structure action.
Note that, this sequence varies according to the command line options.
To retrieve an updated list, please use putup --list-actions
or
putup --dry-run
.
What are Extensions?¶
From the standpoint of PyScaffold, an extension is just an class inheriting
from Extension
overriding and
implementing certain methods. This methods allow inject actions at arbitrary
positions in the aforementioned list. Furthermore, extensions can also remove
actions.
Creating an Extension¶
In order to create an extension it is necessary to write a class that inherits
from Extension
and implements the method
activate
that receives a list of actions,
registers a custom action that will be called later and returns a modified version
of the list of actions:
from ..api import Extension
from ..api import helpers
class MyExtension(Extension):
"""Help text on commandline when running putup -h"""
def activate(self, actions):
"""Activate extension
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
actions = helpers.register(actions, self.action, after='create_structure')
actions = helpers.unregister(actions, 'init_git')
return actions
def action(self, struct, opts):
"""Perform some actions that modifies the structure and options
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
....
return new_actions, new_opts
Action List Helper Methods¶
As implied by the previous example, the helpers
module
provides a series of useful functions and makes it easier to manipulate the
action list, by using register
and
unregister
.
Since the action order is relevant, the first function accepts special keyword
arguments (before
and after
) that should be used to place the extension
actions precisely among the default actions. The value of these arguments can
be presented in 2 different forms:
helpers.register(actions, hook1, before='define_structure')
helpers.register(actions, hook2, after='pyscaffold.structure:create_structure')
The first form uses as a position reference the first action with a matching
name, regardless of the module. Accordingly, the second form tries to find an
action that matches both the given name and module. When no reference is given,
register
assumes as default position
after='pyscaffold.structure:define_structure'
. This position is special
since most extensions are expected to create additional files inside the
project. Therefore, it is possible to easily amend the project structure before
it is materialized by create_structure
.
The unregister
function accepts as second
argument a position reference which can similarly present the module name:
helpers.unregister(actions, 'init_git')
helpers.unregister(actions, 'pyscaffold.api:init_git')
Note
These functions DO NOT modify the actions list, instead they return a new list with the changes applied.
Structure Helper Methods¶
PyScaffold also provides extra facilities to manipulate the project structure.
The following functions are accessible through the
helpers
module:
The first function can be used to deep merge a dictionary argument with the current representation of the to-be-generated directory tree, automatically considering any metadata present in tuple values. On the other hand, the last two functions can be used to ensure a single file is present or absent in the current representation of the project structure, automatically handling parent directories.
Note
Similarly to the actions list helpers, these functions also DO NOT modify the project structure. Instead they return a new structure with the changes applied.
The following example illustrates the implementation of a AwesomeFiles
extension which defines the define_awesome_files
action:
from ..api import Extension
from ..api import helpers
MY_AWESOME_FILE = """\
# -*- coding: utf-8 -*-
from __future__ import print_function
__author__ = "{author}"
__copyright__ = "{author}"
__license__ = "{license}"
def awesome():
return "Awesome!"
"""
MY_AWESOME_TEST = """\
import pytest
from {qual_pkg}.awesome import awesome
def test_awesome():
assert awesome() == "Awesome!"
"""
class AwesomeFiles(Extension):
"""Adding some additional awesome files"""
def activate(self, actions):
return helpers.register(actions, self.define_awesome_files)
def define_awesome_files(self, struct, opts):
struct = helpers.merge(struct, {
opts['project']: {
opts['package']: {
'awesome.py': MY_AWESOME_FILE.format(**opts)
},
'tests': {
'awesome_test.py': (
MY_AWESOME_TEST.format(**opts),
helpers.NO_OVERWRITE
)
}
}
})
struct['.python-version'] = ('3.6.1', helpers.NO_OVERWRITE)
for filename in ['awesome_file1', 'awesome_file2']:
struct = helpers.ensure(
struct, [opts['project'], 'awesome', filename],
content='AWESOME!', update_rule=helpers.NO_CREATE)
# The second argument is the file path, represented by a
# list of file parts or a string.
# Alternatively in this example:
# path = '{project}/awesome/{filename}'.format(
# filename=filename, **opts)
# The `reject` can be used to avoid default files being generated.
struct = helpers.reject(
struct, '{project}/{package}/skeleton.py'.format(**opts))
# Alternatively in this example:
# path = [opts['project'], opts['package'], 'skeleton.py'])
# It is import to remember the return values
return struct, opts
Note
The project
and package
options should be used to provide
the correct location of the files relative to the current working
directory.
As shown by the previous example, the helpers
module
also presents constants that can be used as metadata. The NO_OVERWRITE
flag
avoids an existing file to be overwritten when putup
is used in update
mode. Similarly, NO_CREATE
avoids creating a file from template in update
mode, even if it does not exist.
For more sophisticated extensions which need to read and parse their
own command line arguments it is necessary to override
activate
that receives an
argparse.ArgumentParser
argument. This object can then be modified
in order to add custom command line arguments that will later be stored in the
opts
dictionary.
Just remember the convention that after the command line arguments parsing,
the extension function should be stored under the extensions
attribute
(a list) of the argparse
generated object. For reference check out the
implementation of the namespace extension,
Activating Extensions¶
PyScaffold extensions are not activated by default. Instead, it is necessary
to add a CLI option to do it.
This is possible by setting up a setuptools entry point under the
pyscaffold.cli
group.
This entry point should point to our extension class, e.g. AwesomeFiles
like defined above. If you for instance use a scaffold generated by PyScaffold
to write a PyScaffold extension (we hope you do ;-), you would add the following
to the entry_points
variable in setup.py
:
entry_points = """
[pyscaffold.cli]
awesome_files = your_package.your_module:AwesomeFiles
"""
Examples¶
Some options for the putup
command are already implemented as extensions
and can be used as reference implementation:
Namespace Extension¶
# -*- coding: utf-8 -*-
"""
Extension that adjust project file tree to include a namespace package.
This extension adds a **namespace** option to
:obj:`~pyscaffold.api.create_project` and provides correct values for the
options **root_pkg** and **namespace_pkg** to the following functions in the
action list.
"""
from __future__ import absolute_import
import argparse
import os
from os.path import join as join_path
from os.path import isdir
from .. import templates, utils
from ..api import Extension
from ..api import helpers
from ..log import logger
class Namespace(Extension):
"""Omit creation of skeleton.py"""
def augment_cli(self, parser):
"""Add an option to parser that enables the namespace extension.
Args:
parser (argparse.ArgumentParser): CLI parser object
"""
parser.add_argument(
self.flag,
dest=self.name,
default=None,
action=create_namespace_parser(self),
metavar="NS1[.NS2]",
help="put your project inside a namespace package")
def activate(self, actions):
"""Register an action responsible for adding namespace to the package.
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
actions = helpers.register(actions, enforce_namespace_options,
after='get_default_options')
actions = helpers.register(actions, add_namespace,
before='apply_update_rules')
return helpers.register(actions, move_old_package,
after='create_structure')
def create_namespace_parser(obj_ref):
"""Create a namespace parser.
Args:
obj_ref (Extension): object reference to the actual extension
Returns:
NamespaceParser: parser for namespace cli argument
"""
class NamespaceParser(argparse.Action):
"""Consumes the values provided, but also appends the extension
function to the extensions list.
"""
def __call__(self, parser, namespace, values, option_string=None):
# First ensure the extension function is stored inside the
# 'extensions' attribute:
extensions = getattr(namespace, 'extensions', [])
extensions.append(obj_ref)
setattr(namespace, 'extensions', extensions)
# Now the extra parameters can be stored
setattr(namespace, self.dest, values)
# save the namespace cli argument for later
obj_ref.args = values
return NamespaceParser
def enforce_namespace_options(struct, opts):
"""Make sure options reflect the namespace usage."""
opts.setdefault('namespace', None)
if opts['namespace']:
opts['namespace'] = utils.prepare_namespace(opts['namespace'])
opts['root_pkg'] = opts['namespace'][0]
opts['qual_pkg'] = ".".join([opts['namespace'][-1], opts['package']])
return struct, opts
def add_namespace(struct, opts):
"""Prepend the namespace to a given file structure
Args:
struct (dict): directory structure as dictionary of dictionaries
opts (dict): options of the project
Returns:
tuple(dict, dict):
directory structure as dictionary of dictionaries and input options
"""
if not opts['namespace']:
return struct, opts
namespace = opts['namespace'][-1].split('.')
base_struct = struct
struct = base_struct[opts['project']]['src']
pkg_struct = struct[opts['package']]
del struct[opts['package']]
for sub_package in namespace:
struct[sub_package] = {'__init__.py': templates.namespace(opts)}
struct = struct[sub_package]
struct[opts['package']] = pkg_struct
return base_struct, opts
def move_old_package(struct, opts):
"""Move old package that may be eventually created without namespace
Args:
struct (dict): directory structure as dictionary of dictionaries
opts (dict): options of the project
Returns:
tuple(dict, dict):
directory structure as dictionary of dictionaries and input options
"""
old_path = join_path(opts['project'], 'src', opts['package'])
namespace_path = opts['qual_pkg'].replace('.', os.sep)
target = join_path(opts['project'], 'src', namespace_path)
old_exists = opts['pretend'] or isdir(old_path)
# ^ When pretending, pretend also an old folder exists
# to show a worst case scenario log to the user...
if old_exists and opts['qual_pkg'] != opts['package']:
if not opts['pretend']:
logger.warning(
'\nA folder %r exists in the project directory, and it is '
'likely to have been generated by a PyScaffold extension or '
'manually by one of the current project authors.\n'
'Moving it to %r, since a namespace option was passed.\n'
'Please make sure to edit all the files that depend on this '
'package to ensure the correct location.\n',
opts['package'], namespace_path)
utils.move(old_path, target=target,
log=True, pretend=opts['pretend'])
return struct, opts
No Skeleton Extension¶
# -*- coding: utf-8 -*-
"""
Extension that omits the creation of file `skeleton.py`
"""
from ..api import Extension
from ..api import helpers
class NoSkeleton(Extension):
"""Omit creation of skeleton.py and test_skeleton.py"""
def activate(self, actions):
"""Activate extension
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
return self.register(
actions,
self.remove_files,
after='define_structure')
def remove_files(self, struct, opts):
"""Remove all skeleton files from structure
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
# Namespace is not yet applied so deleting from package is enough
file = [opts['project'], 'src', opts['package'], 'skeleton.py']
struct = helpers.reject(struct, file)
file = [opts['project'], 'tests', 'test_skeleton.py']
struct = helpers.reject(struct, file)
return struct, opts
Cookiecutter Extension¶
# -*- coding: utf-8 -*-
"""
Extension that integrates cookiecutter templates into PyScaffold.
"""
from __future__ import absolute_import
import argparse
from ..api.helpers import register, logger
from ..api import Extension
from ..contrib.six import raise_from
class Cookiecutter(Extension):
"""Additionally apply a Cookiecutter template"""
mutually_exclusive = True
def augment_cli(self, parser):
"""Add an option to parser that enables the Cookiecutter extension
Args:
parser (argparse.ArgumentParser): CLI parser object
"""
parser.add_argument(
self.flag,
dest=self.name,
action=create_cookiecutter_parser(self),
metavar="TEMPLATE",
help="additionally apply a Cookiecutter template. "
"Note that not all templates are suitable for PyScaffold. "
"Please refer to the docs for more information.")
def activate(self, actions):
"""Register before_create hooks to generate project using Cookiecutter
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
# `get_default_options` uses passed options to compute derived ones,
# so it is better to prepend actions that modify options.
actions = register(actions, enforce_cookiecutter_options,
before='get_default_options')
# `apply_update_rules` uses CWD information,
# so it is better to prepend actions that modify it.
actions = register(actions, create_cookiecutter,
before='apply_update_rules')
return actions
def create_cookiecutter_parser(obj_ref):
"""Create a Cookiecutter parser.
Args:
obj_ref (Extension): object reference to the actual extension
Returns:
NamespaceParser: parser for namespace cli argument
"""
class CookiecutterParser(argparse.Action):
"""Consumes the values provided, but also append the extension function
to the extensions list.
"""
def __call__(self, parser, namespace, values, option_string=None):
# First ensure the extension function is stored inside the
# 'extensions' attribute:
extensions = getattr(namespace, 'extensions', [])
extensions.append(obj_ref)
setattr(namespace, 'extensions', extensions)
# Now the extra parameters can be stored
setattr(namespace, self.dest, values)
# save the cookiecutter cli argument for later
obj_ref.args = values
return CookiecutterParser
def enforce_cookiecutter_options(struct, opts):
"""Make sure options reflect the cookiecutter usage.
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
opts['force'] = True
return struct, opts
def create_cookiecutter(struct, opts):
"""Create a cookie cutter template
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
try:
from cookiecutter.main import cookiecutter
except Exception as e:
raise_from(NotInstalled, e)
extra_context = dict(full_name=opts['author'],
author=opts['author'],
email=opts['email'],
project_name=opts['project'],
package_name=opts['package'],
repo_name=opts['package'],
project_short_description=opts['description'],
release_date=opts['release_date'],
version='unknown', # will be replaced later
year=opts['year'])
if 'cookiecutter' not in opts:
raise MissingTemplate
logger.report('run', 'cookiecutter ' + opts['cookiecutter'])
if not opts.get('pretend'):
cookiecutter(opts['cookiecutter'],
no_input=True,
extra_context=extra_context)
return struct, opts
class NotInstalled(RuntimeError):
"""This extension depends on the ``cookiecutter`` package."""
DEFAULT_MESSAGE = ("cookiecutter is not installed, "
"run: pip install cookiecutter")
def __init__(self, message=DEFAULT_MESSAGE, *args, **kwargs):
super(NotInstalled, self).__init__(message, *args, **kwargs)
class MissingTemplate(RuntimeError):
"""A cookiecutter template (git url) is required."""
DEFAULT_MESSAGE = "missing `cookiecutter` option"
def __init__(self, message=DEFAULT_MESSAGE, *args, **kwargs):
super(MissingTemplate, self).__init__(message, *args, **kwargs)
Django Extension¶
# -*- coding: utf-8 -*-
"""
Extension that creates a base structure for the project using django-admin.py.
"""
from __future__ import absolute_import
from .. import shell
from ..api import helpers
from ..api import Extension
from ..contrib.six import raise_from
class Django(Extension):
"""Generate Django project files"""
mutually_exclusive = True
def activate(self, actions):
"""Register hooks to generate project using django-admin.
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
# `get_default_options` uses passed options to compute derived ones,
# so it is better to prepend actions that modify options.
actions = helpers.register(actions, enforce_django_options,
before='get_default_options')
# `apply_update_rules` uses CWD information,
# so it is better to prepend actions that modify it.
actions = helpers.register(actions, create_django_proj,
before='apply_update_rules')
return actions
def enforce_django_options(struct, opts):
"""Make sure options reflect the Django usage.
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
opts['package'] = opts['project'] # required by Django
opts['force'] = True
opts.setdefault('requirements', []).append('django')
return struct, opts
def create_django_proj(struct, opts):
"""Creates a standard Django project with django-admin.py
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
Raises:
:obj:`RuntimeError`: raised if django-admin.py is not installed
"""
try:
shell.django_admin('--version')
except Exception as e:
raise raise_from(DjangoAdminNotInstalled, e)
shell.django_admin('startproject', opts['project'],
log=True, pretend=opts.get('pretend'))
return struct, opts
class DjangoAdminNotInstalled(RuntimeError):
"""This extension depends on the ``django-admin.py`` cli script."""
DEFAULT_MESSAGE = ("django-admin.py is not installed, "
"run: pip install django")
def __init__(self, message=DEFAULT_MESSAGE, *args, **kwargs):
super(DjangoAdminNotInstalled, self).__init__(message, *args, **kwargs)
Pre Commit Extension¶
# -*- coding: utf-8 -*-
"""
Extension that generates configuration files for Yelp `pre-commit`_.
.. _pre-commit: http://pre-commit.com
"""
from __future__ import absolute_import
from ..templates import pre_commit_config
from ..api import Extension
from ..api import helpers
class PreCommit(Extension):
"""Generate pre-commit configuration file"""
def activate(self, actions):
"""Activate extension
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
return self.register(
actions,
self.add_files,
after='define_structure')
def add_files(self, struct, opts):
"""Add .pre-commit-config.yaml file to structure
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
files = {
'.pre-commit-config.yaml': (
pre_commit_config(opts), helpers.NO_OVERWRITE
),
}
return helpers.merge(struct, {opts['project']: files}), opts
Tox Extension¶
# -*- coding: utf-8 -*-
"""
Extension that generates configuration files for the Tox test automation tool.
"""
from __future__ import absolute_import
from ..templates import tox as tox_ini
from ..api import Extension
from ..api import helpers
class Tox(Extension):
"""Generate Tox configuration file"""
def activate(self, actions):
"""Activate extension
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
return self.register(
actions,
self.add_files,
after='define_structure')
def add_files(self, struct, opts):
"""Add .tox.ini file to structure
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
files = {
'tox.ini': (tox_ini(opts), helpers.NO_OVERWRITE)
}
return helpers.merge(struct, {opts['project']: files}), opts
Travis Extension¶
# -*- coding: utf-8 -*-
"""
Extension that generates configuration and script files for Travis CI.
"""
from __future__ import absolute_import
from ..templates import travis, travis_install
from ..api import Extension
from ..api import helpers
class Travis(Extension):
"""Generate Travis CI configuration files"""
def activate(self, actions):
"""Activate extension
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
return self.register(
actions,
self.add_files,
after='define_structure')
def add_files(self, struct, opts):
"""Add some Travis files to structure
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
files = {
'.travis.yml': (travis(opts), helpers.NO_OVERWRITE),
'tests': {
'travis_install.sh': (travis_install(opts),
helpers.NO_OVERWRITE)
}
}
return helpers.merge(struct, {opts['project']: files}), opts
GitLab-CI Extension¶
# -*- coding: utf-8 -*-
"""
Extension that generates configuration and script files for GitLab CI.
"""
from __future__ import absolute_import
from ..templates import gitlab_ci
from ..api import Extension
from ..api import helpers
class GitLab(Extension):
"""Generate GitLab CI configuration files"""
def activate(self, actions):
"""Activate extension
Args:
actions (list): list of actions to perform
Returns:
list: updated list of actions
"""
return self.register(
actions,
self.add_files,
after='define_structure')
def add_files(self, struct, opts):
"""Add .gitlab-ci.yml file to structure
Args:
struct (dict): project representation as (possibly) nested
:obj:`dict`.
opts (dict): given options, see :obj:`create_project` for
an extensive list.
Returns:
struct, opts: updated project representation and options
"""
files = {
'.gitlab-ci.yml': (gitlab_ci(opts), helpers.NO_OVERWRITE)
}
return helpers.merge(struct, {opts['project']: files}), opts
Conventions for Community Extensions¶
In order to make it easy to find PyScaffold extensions, community packages
should be namespaced as in pyscaffoldext.${EXTENSION}
(where ${EXTENSION}
is the name of the extension being developed). Although this naming convention
slightly differs from PEP423, it is close enough and shorter.
Similarly to sphinxcontrib-*
packages, names registered in PyPI should
contain a dash -
, instead of a dot .
. This way, third-party extension
development can be easily bootstrapped with the command:
putput pyscaffoldext-${EXTENSION} -p ${EXTENSION} --namespace pyscaffoldext
Final Considerations¶
When writing extensions, it is important to be consistent with the default
PyScaffold behavior. In particular, PyScaffold uses a pretend
option to
indicate when the actions should not run but instead just indicate the
expected results to the user, that MUST be respected.
The pretend
option is automatically observed for files registered in
the project structure representation, but complex actions may require
specialized coding. The helpers
module provides a
special logger
object useful in
these situations. Please refer to No Skeleton Extension for a
practical example.
Other options that should be considered are the update
and force
flags. See pyscaffold.api.create_project
for a list of available
options.
Embedding PyScaffold¶
PyScaffold is expected to be used from terminal, via putup
command line
application. It is, however, possible to write an external script or program
that embeds PyScaffold and use it to perform some custom actions.
The public Python API is exposed by the pyscaffold.api
module, which
contains the main function create_project
.
The following example illustrates a typical embedded usage of PyScaffold:
import logging
from pyscaffold.api import create_project
from pyscaffold.extenstions import tox, travis, namespace
from pyscaffold.log import DEFAULT_LOGGER as LOGGER_NAME
logging.getLogger(LOGGER_NAME).setLevel(logging.INFO)
create_project(project="my-proj-name", author="Your Name",
namespace="some.namespace", license="mit",
extensions=[tox.extend_project,
travis.extend_project,
namespace.extend_project])
Note that no built-in extension (e.g. tox, travis and namespace support) is
activated by default. The extensions
option should be manually populated
when convenient.
PyScaffold uses the logging infrastructure from Python standard library, and
emits notifications during its execution. Therefore, it is possible to control
which messages are logged by properly setting the log level (internally, most
of the messages are produced under the INFO
level). By default, a
StreamHandler
is attached to the logger, however it is
possible to replace it with a custom handler using
logging.Logger.removeHandler
and logging.Logger.addHandler
. The
logger object is available under the logger
variable of
the pyscaffold.log
module. The default handler is available under the
handler
property of the
logger
object.
Cookiecutter templates with PyScaffold¶
Cookiecutter is a flexible utility that allows the definition of templates
for a diverse range of software projects.
On the other hand, PyScaffold is focused in a good out-of-the-box
experience for developing distributable Python packages (exclusively).
Despite the different objectives, it is possible to combine the power of both
tools to create a custom Python project setup. For instance, the following
command creates a new package named mypkg
, that uses a Cookiecutter template,
but is enhanced by PyScaffold features:
$ putup mypkg --cookiecutter gh:audreyr/cookiecutter-pypackage
Note
Although using Cookiecutter templates is a viable solution to customize a project that was set up with PyScaffold, the recommended way is to help improve PyScaffold by contributing an extension.
Suitable templates¶
Note that PyScaffold will overwrite some files generated by Cookiecutter,
like setup.py
, the __init__.py
file under the package folder
and most of the docs
folder, in order to provide setuptools_scm
and sphinx integration.
Therefore not all Cookiecutter templates are suitable for this approach.
Ideally, interoperable templates should focus on the file structure inside the package folder instead of packaging or distributing, since PyScaffold already handles it under-the-hood. However, the following files can be safely generated by a template (will not be overwritten):
<project root>/docs/index.rst
<project root>/tests/conftest.py
<project root>/README.rst
<project root>/AUTHORS.rst
<project root>/LICENSE.txt
<project root>/CHANGES.rst
<project root>/setup.cfg
<project root>/requirements.txt
<project root>/test-requirements.txt
<project root>/.coveragerc
In addition, PyScaffold runs Cookiecutter with the --no-input
flag
activated and thus the user is not prompted for manual configuration. Instead,
PyScaffold injects the following parameters:
author
email
project_name
package_name
project_short_description
Accordingly, the template file structure should be similar to:
cookiecutter-something/
└── {{cookiecutter.project_name}}/
└── {{cookiecutter.package_name}}/
└── ...
See Cookiecutter for more information about template creation.
Contributing¶
PyScaffold was started by Blue Yonder developers to help automating and standardizing the process of project setups. Nowadays it is a pure community project and you are very welcome to join in our effort if you would like to contribute.
Issue Reports¶
If you experience bugs or in general issues with PyScaffold, please file an issue report on our issue tracker.
Code Contributions¶
Submit an issue¶
Before you work on any non-trivial code contribution it’s best to first create an issue report to start a discussion on the subject. This often provides additional considerations and avoids unnecessary work.
Create an environment¶
Before you start coding we recommend to install Miniconda which allows
to setup a dedicated development environment named pyscaffold
with:
conda create -n pyscaffold python=3 six virtualenv pytest pytest-cov
Then activate the environment pyscaffold
with:
source activate pyscaffold
Clone the repository¶
Create a Gitub account if you do not already have one.
Fork the project repository: click on the Fork button near the top of the page. This creates a copy of the code under your account on the GitHub server.
Clone this copy to your local disk:
git clone git@github.com:YourLogin/pyscaffold.git
Run
python setup.py egg_info --egg-base .
after a fresh checkout. This will generate some critically needed files. Typically after that, you should runpython setup.py develop
to be able runputup
.Create a branch to hold your changes:
git checkout -b my-feature
and start making changes. Never work on the master branch!
Start your work on this branch. When you’re done editing, do:
git add modified_files git commit
to record your changes in Git, then push them to GitHub with:
git push -u origin my-feature
Please check that your changes don’t break any unit tests with:
python setup.py test
or even a more thorough test with
tox
after having installed tox withpip install tox
. Don’t forget to also add unit tests in case your contribution adds an additional feature and is not just a bugfix.Use flake8 to check your code style.
Add yourself to the list of contributors in
AUTHORS.rst
.Go to the web page of your PyScaffold fork, and click “Create pull request” to send your changes to the maintainers for review. Find more detailed information creating a PR.
Release¶
As a PyScaffold maintainer following steps are needed to release a new version:
- Make sure all unit tests on Travis are green.
- Tag the current commit on the master branch with a release tag, e.g.
v1.2.3
. - Clean up the
dist
andbuild
folders withrm -rf dist build
to avoid confusion with old builds and Sphinx docs. - Run
python setup.py test_release
and check that the files indist
have the correct version (no.dirty
or Git hash) according to the Git tag. Also sizes of the distributions should be less then 500KB, otherwise unwanted clutter may have been included. - Run
python setup.py release
and that everything was uploaded to PyPI correctly.
Frequently Asked Questions¶
In case you have a general question that is not answered here, consider submitting a new issue.
Why would I use PyScaffold instead of Cookiecutter?
PyScaffold is focused in a good out-of-the-box experience for developing distributable Python packages (exclusively). The idea is to standardize the structure of Python packages. The long-term goal is that PyScaffold becomes for Python what Cargo is for Rust.
Cookiecutter on the other hand is a really flexible templating tool that allows you to define own templates according to your needs. Although some standard templates are provided that will give you quite similar results as PyScaffold, the overall goal of the project is quite different.
Does my project depend on PyScaffold when I use it to set my project up?
The short answer is no if you later distribute your project in the recommended wheel format. The longer answer is that only during development PyScaffold is needed as a setup dependency. That means if someone clones your repository and runs
setup.py
,setuptools
checks for thesetup_requires
argument which includes PyScaffold and installs PyScaffold automatically as egg file into.eggs
if PyScaffold is not yet installed. This mechanism is provided bysetuptools
and definitely beyond the scope of this answer. The same applies for the deprecated source distribution (sdist
) but not for a binary distribution (bdist
). Anyways, the recommend way is nowadays a binary wheel distribution (bdist_wheel
) which will not depend on PyScaffold at all.
Why does PyScaffold 3.0 have a
src
folder which holds the actual Python package?This avoids quite many problems compared to the case when the actual Python package resides in the same folder as
setup.py
. A nice blog post by Ionel gives a thorough explanation why this is so. In a nutshell, the most severe problem comes from the fact that Python imports a package by first looking at the current working directory and then into thePYTHONPATH
environment variable. If your current working directory is the root of your project directory you are thus not testing the installation of your package but the local package directly. Eventually, this always leads to huge confusion (“But the unit tests ran perfectly on my machine!”).
License¶
The MIT License (MIT)
Copyright (c) 2014 Blue Yonder GmbH
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.
Contributors¶
- Florian Wilhelm <Florian.Wilhelm@gmail.com>
- Felix Wick <Felix.Wick@blue-yonder.com>
- Holger Peters <Holger.Peters@blue-yonder.com>
- Uwe Korn <Uwe.Korn@blue-yonder.com>
- Patrick Mühlbauer <Patrick.Muehlbauer@blue-yonder.com>
- Florian Rathgeber <florian.rathgeber@gmail.com>
- Eva Schmücker <email@evaschmuecker.de>
- Tim Werner <tim.werner@blue-yonder.com>
- Julian Gethmann <julian.gethmann@kit.edu>
- Will Usher <william.usher@ouce.ox.ac.uk>
- Anderson Bravalheri <andersonbravalheri@gmail.com>
- David Hilton <david.hilton.p@gmail.com>
- Pablo Aguiar <scorphus@gmail.com>
- Vicky C Lau <vcl2@sfu.ca>
Changelog¶
Current versions¶
Version 3.0.3, 2018-04-14¶
- Set install_requires to setuptools>=30.3.0
Version 2.5.11, 2018-04-14¶
- Updated pbr to version 4.0.2
- Fixes Sphinx version 1.6 regression, issue #152
Older versions¶
Version 3.0.2, 2018-03-21¶
- Updated setuptools_scm to version 1.17.0
- Fix wrong docstring in skeleton.py about entry_points, issue #147
- Fix error with setuptools version 39.0 and above, issue #148
- Fixes in documentation, thanks Vicky
Version 2.5.10, 2018-03-21¶
- Updated setuptools_scm to version 1.17.0
Version 2.5.9, 2018-03-20¶
- Updated setuptools_scm to version 1.16.1
- Fix error with setuptools version 39.0 and above, issue #148
Version 3.0.1, 2018-02-13¶
- Fix confusing error message when
python setup.py docs
and Sphinx is not installed, issue #142 - Fix ‘unknown’ version in case project name differs from the package name, issue #141
- Fix missing
file:
attribute in long-description of setup.cfg - Fix
sphinx-apidoc
invocation problem with Sphinx 1.7
Version 3.0, 2018-01-07¶
- Improved Python API thanks to an extension system
- Dropped pbr in favor of setuptools >= 30.3.0
- Updated setuptools_scm to v1.15.6
- Changed
my_project/my_package
to recommendedmy_project/src/my_package
structure - Renamed
CHANGES.rst
to more standardCHANGELOG.rst
- Added platforms parameter in
setup.cfg
- Call Sphinx api-doc from
conf.py
, issue #98 - Included six 1.11.0 as contrib sub-package
- Added
CONTRIBUTING.rst
- Removed
test-requirements.txt
from template - Added support for GitLab
- License change from New BSD to MIT
- FIX: Support of git submodules, issue #98
- Support of Cython extensions, issue #48
- Removed redundant
--with-
from most command line flags - Prefix
n
was removed from the local_version string of dirty versions - Added a
--pretend
flag for easier development of extensions - Added a
--verbose
flag for more output what PyScaffold is doing - Use pytest-runner 3.0 as contrib package
- Added a
--no-skeleton
flag to omit the creation ofskeleton.py
- Save parameters used to create project scaffold in
setup.cfg
for later updating
A special thanks goes to Anderson Bravalheri for his awesome support and inovex for sponsoring this release.
Version 2.5.8, 2017-09-10¶
- Use
sphinx.ext.imgmath
instead ofsphinx.ext.mathjax
- Added
--with-gitlab-ci
flag for GitLab CI support - Fix Travis install template dirties git repo, issue #107
- Updated setuptools_scm to version 1.15.6
- Updated pbr to version 3.1.1
Version 2.5.7, 2016-10-11¶
- Added encoding to __init__.py
- Few doc corrections in setup.cfg
- [tool:pytest] instead of [pytest] in setup.cfg
- Updated skeleton
- Switch to Google Sphinx style
- Updated setuptools_scm to version 1.13.1
- Updated pbr to version 1.10.0
Version 2.5.6, 2016-05-01¶
- Prefix error message with ERROR:
- Suffix of untagged commits changed from {version}-{hash} to {version}-n{hash}
- Check if package identifier is valid
- Added log level command line flags to the skeleton
- Updated pbr to version 1.9.1
- Updated setuptools_scm to version 1.11.0
Version 2.5.5, 2016-02-26¶
- Updated pbr to master at 2016-01-20
- Fix sdist installation bug when no git is installed, issue #90
Version 2.5.4, 2016-02-10¶
- Fix problem with
fibonacci
terminal example - Update setuptools_scm to v1.10.1
Version 2.5.3, 2016-01-16¶
- Fix classifier metadata (
classifiers
toclassifier
insetup.cfg
)
Version 2.5.2, 2016-01-02¶
- Fix
is_git_installed
Version 2.5.1, 2016-01-01¶
- Fix: Do some sanity checks first before gathering default options
- Updated setuptools_scm to version 1.10.0
Version 2.5, 2015-12-09¶
- Usage of
test-requirements.txt
instead oftests_require
insetup.py
, issue #71 - Removed
--with-numpydoc
flag since this is now included by default withsphinx.ext.napoleon
in Sphinx 1.3 and above - Added small template for unittest
- Fix for the example skeleton file when using namespace packages
- Fix typo in devpi:upload section, issue #82
- Include
pbr
andsetuptools_scm
in PyScaffold to avoid dependency problems, issue #71 and #72 - Cool logo was designed by Eva Schmücker, issue #66
Version 2.4.4, 2015-10-29¶
- Fix problem with bad upload of version 2.4.3 to PyPI, issue #80
Version 2.4.3, 2015-10-27¶
- Fix problem with version numbering if setup.py is not in the root directory, issue #76
Version 2.4.2, 2015-09-16¶
- Fix version conflicts due to too tight pinning, issue #69
Version 2.4.1, 2015-09-09¶
- Fix installation with additional requirements
pyscaffold[ALL]
- Updated pbr version to 1.7
Version 2.4, 2015-09-02¶
- Allow different py.test options when invoking with
py.test
orpython setup.py test
- Check if Sphinx is needed and add it to setup_requires
- Updated pre-commit plugins
- Replaced pytest-runner by an improved version
- Let pbr do
sphinx-apidoc
, removed fromconf.py
, issue #65
Note
Due to the switch to a modified pytest-runner version it is necessary
to update setup.cfg
. Please check the example.
Version 2.3, 2015-08-26¶
- Format of setup.cfg changed due to usage of pbr, issue #59
- Much cleaner setup.py due to usage of pbr, issue #59
- PyScaffold can be easily called from another script, issue #58
- Internally dictionaries instead of namespace objects are used for options, issue #57
- Added a section for devpi in setup.cfg, issue #62
Note
Due to the switch to pbr, it
is necessary to update setup.cfg
according to the new syntax.
Version 2.2.1, 2015-06-18¶
- FIX: Removed putup console script in setup.cfg template
Version 2.2, 2015-06-01¶
- Allow recursive inclusion of data files in setup.cfg, issue #49
- Replaced hand-written PyTest runner by pytest-runner, issue #47
- Improved default README.rst, issue #51
- Use tests/conftest.py instead of tests/__init__.py, issue #52
- Use setuptools_scm for versioning, issue #43
- Require setuptools>=9.0, issue #56
- Do not create skeleton.py during an update, issue #55
Note
Due to the switch to setuptools_scm the following changes apply:
- use
python setup.py --version
instead ofpython setup.py version
git archive
can no longer be used for packaging (and was never meant for it anyway)- initial tag
v0.0
is no longer necessary and thus not created in new projects - tags do no longer need to start with v
Version 2.1, 2015-04-16¶
- Use alabaster as default Sphinx theme
- Parameter data_files is now a section in setup.cfg
- Allow definition of extras_require in setup.cfg
- Added a CHANGES.rst file for logging changes
- Added support for cookiecutter
- FIX: Handle an empty Git repository if necessary
Version 2.0.4, 2015-03-17¶
- Typo and wrong Sphinx usage in the RTD documentation
Version 2.0.3, 2015-03-17¶
- FIX: Removed misleading include_package_data option in setup.cfg
- Allow selection of a proprietary license
- Updated some documentations
- Added -U as short parameter for –update
Version 2.0.2, 2015-03-04¶
- FIX: Version retrieval with setup.py install
- argparse example for version retrieval in skeleton.py
- FIX: import my_package should be quiet (verbose=False)
Version 2.0.1, 2015-02-27¶
- FIX: Installation bug under Windows 7
Version 2.0, 2015-02-25¶
- Split configuration and logic into setup.cfg and setup.py
- Removed .pre from version string (newer PEP 440)
- FIX: Sphinx now works if package name does not equal project name
- Allow namespace packages with –with-namespace
- Added a skeleton.py as a console_script template
- Set v0.0 as initial tag to support PEP440 version inference
- Integration of the Versioneer functionality into setup.py
- Usage of data_files configuration instead of MANIFEST.in
- Allow configuration of package_data in setup.cfg
- Link from Sphinx docs to AUTHORS.rst
Version 1.4, 2014-12-16¶
- Added numpydoc flag –with-numpydoc
- Fix: Add django to requirements if –with-django
- Fix: Don’t overwrite index.rst during update
Version 1.3.2, 2014-12-02¶
- Fix: path of Travis install script
Version 1.3.1, 2014-11-24¶
- Fix: –with-tox tuple bug #28
Version 1.3, 2014-11-17¶
- Support for Tox (https://tox.readthedocs.org/)
- flake8: exclude some files
- Usage of UTF8 as file encoding
- Fix: create non-existent files during update
- Fix: unit tests on MacOS
- Fix: unit tests on Windows
- Fix: Correct version when doing setup.py install
Version 1.2, 2014-10-13¶
- Support pre-commit hooks (http://pre-commit.com/)
Version 1.1, 2014-09-29¶
- Changed COPYING to LICENSE
- Support for all licenses from http://choosealicense.com/
- Fix: Allow update of license again
- Update to Versioneer 0.12
Version 1.0, 2014-09-05¶
- Fix when overwritten project has a git repository
- Documentation updates
- License section in Sphinx
- Django project support with –with-django flag
- Travis project support with –with-travis flag
- Replaced sh with own implementation
- Fix: new git describe version to PEP440 conversion
- conf.py improvements
- Added source code documentation
- Fix: Some Python 2/3 compatibility issues
- Support for Windows
- Dropped Python 2.6 support
- Some classifier updates
Version 0.9, 2014-07-27¶
- Documentation updates due to RTD
- Added a –force flag
- Some cleanups in setup.py
Version 0.8, 2014-07-25¶
- Update to Versioneer 0.10
- Moved sphinx-apidoc from setup.py to conf.py
- Better support for make html
Version 0.7, 2014-06-05¶
- Added Python 3.4 tests and support
- Flag –update updates only some files now
- Usage of setup_requires instead of six code
Version 0.6.1, 2014-05-15¶
- Fix: Removed six dependency in setup.py
Version 0.6, 2014-05-14¶
- Better usage of six
- Return non-zero exit status when doctests fail
- Updated README
- Fixes in Sphinx Makefile
Version 0.5, 2014-05-02¶
- Simplified some Travis tests
- Nicer output in case of errors
- Updated PyScaffold’s own setup.py
- Added –junit_xml and –coverage_xml/html option
- Updated .gitignore file
Version 0.4.1, 2014-04-27¶
- Problem fixed with pytest-cov installation
Version 0.4, 2014-04-23¶
- PEP8 and PyFlakes fixes
- Added –version flag
- Small fixes and cleanups
Version 0.3, 2014-04-18¶
- PEP8 fixes
- More documentation
- Added update feature
- Fixes in setup.py
Version 0.2, 2014-04-15¶
- Checks when creating the project
- Fixes in COPYING
- Usage of sh instead of GitPython
- PEP8 fixes
- Python 3 compatibility
- Coverage with Coverall.io
- Some more unittests
Version 0.1.2, 2014-04-10¶
- Bugfix in Manifest.in
- Python 2.6 problems fixed
Version 0.1.1, 2014-04-10¶
- Unittesting with Travis
- Switch to string.Template
- Minor bugfixes
Version 0.1, 2014-04-03¶
- First release
pyscaffold¶
pyscaffold package¶
Subpackages¶
pyscaffold.api package¶
Submodules¶
pyscaffold.api.helpers module¶
Useful functions for manipulating the action list and project structure.
-
pyscaffold.api.helpers.
NO_CREATE
= 1¶ Do not create the file during an update
-
pyscaffold.api.helpers.
NO_OVERWRITE
= 0¶ Do not overwrite an existing file during update (still created if not exists)
-
pyscaffold.api.helpers.
ensure
(struct, path, content=None, update_rule=None)[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 (dict) – project representation as (possibly) nested
dict
. Seemerge
. - path (str or list) –
file path relative to the structure root. The directory separator should be
/
(forward slash) if present. Alternatively, a list with the parts of the path can be provided, ordered from the structure root to the file itself. The following examples are equivalent:'docs/api/index.html' ['docs', 'api', 'index.html']
- content (str) – file text contents
- update_rule – see
FileOp
,None
by default
Returns: updated project tree representation
Return type: Note
Use an empty string as content to ensure a file is created empty.
- struct (dict) – project representation as (possibly) nested
-
pyscaffold.api.helpers.
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 Returns: identifier Return type: str
-
pyscaffold.api.helpers.
logger
= <pyscaffold.log.ReportLogger object>¶ Logger wrapper, that provides methods like
report
. SeeReportLogger
.
-
pyscaffold.api.helpers.
merge
(old, new)[source]¶ Merge two dict representations for the directory structure.
Basically a deep dictionary merge, except from the leaf update method.
Parameters: The directory tree is represented as a (possibly nested) dictionary. The keys indicate the path where a file will be generated, while the value indicates the content. Additionally, tuple values are allowed in order to specify the rule that will be followed during an
update
operation (seeFileOp
). In this case, the first element is the file content and the second element is the update rule. For example, the dictionary:{'project': { 'namespace': { 'module.py': ('print("Hello World!")', helpers.NO_OVERWRITE)}}
represents a
project/namespace/module.py
file with contentprint("Hello World!")
, that will be created only if not present.Returns: resulting merged directory representation Return type: dict Note
Use an empty string as content to ensure a file is created empty.
-
pyscaffold.api.helpers.
register
(actions, action, before=None, after=None)[source]¶ Register a new action to be performed during scaffold.
Parameters: - actions (list) – previous action list.
- action (callable) –
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:helpers.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. helpers.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:
helpers.register(actions, do_nothing) # The action will take place after # `pyscaffold.structure:define_structure`
Returns: modified action list.
Return type:
-
pyscaffold.api.helpers.
reject
(struct, path)[source]¶ Remove a file from the project tree representation if existent.
Parameters: - struct (dict) – project representation as (possibly) nested
dict
. Seemerge
. - path (str or list) –
file path relative to the structure root. The directory separator should be
/
(forward slash) if present. Alternatively, a list with the parts of the path can be provided, ordered from the structure root to the file itself. The following examples are equivalent:'docs/api/index.html' ['docs', 'api', 'index.html']
Returns: modified project tree representation
Return type: - struct (dict) – project representation as (possibly) nested
Module contents¶
Exposed API for accessing PyScaffold via Python.
-
class
pyscaffold.api.
Extension
(name)[source]¶ Bases:
object
Base class for PyScaffold’s extensions
-
activate
(actions)[source]¶ Activates the extension by registering its functionality
Parameters: actions (list) – list of action to perform Returns: updated list of actions Return type: list
-
augment_cli
(parser)[source]¶ Augments the command-line interface parser
A command line argument
--FLAG
where FLAG=``self.name`` is added which appendsself.activate
to the list of extensions. As help text the docstring of the extension class is used. In most cases this method does not need to be overwritten.Parameters: parser – current parser object
-
flag
¶
-
mutually_exclusive
= False¶
-
static
register
(*args, **kwargs)[source]¶ Shortcut for
helpers.register
-
static
unregister
(*args, **kwargs)[source]¶ Shortcut for
helpers.unregister
-
-
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: list of actions
Return type: Valid options include:
Naming: - project (str)
- package (str)
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)
Some of these options are equivalent to the command line options, others are used for creating the basic python package meta information, but the last tree can change the way PyScaffold 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.Finally, the extensions list may contain any function that follows the extension API. Note that some PyScaffold features, such as travis, tox and pre-commit support, are implemented as built-in extensions. In order to use these features it is necessary to include the respective functions in the extension list. All built-in extensions are accessible via
pyscaffold.extensions
submodule.Note that extensions may define extra options. For example, built-in cookiecutter extension define a
cookiecutter
option that should be the address to the git repository used as template.
-
pyscaffold.api.
discover_actions
(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) – list of functions responsible for activating the
- extensions. –
Returns: scaffold actions.
Return type:
-
pyscaffold.api.
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 (dict) – project representation as (possibly) nested
dict
. - opts (dict) – given options, see
create_project
for an extensive list.
Returns: project representation and options with default values set
Return type: Raises: DirectoryDoesNotExist
– when PyScaffold is told to update an nonexistent directoryGitNotInstalled
– when git command is not availableGitNotConfigured
– when git does not know user information
Note
This function uses git to determine some options, such as author name and email.
- struct (dict) – project representation as (possibly) nested
-
pyscaffold.api.
init_git
(struct, opts)[source]¶ Add revision control to the generated files.
Parameters: - struct (dict) – project representation as (possibly) nested
dict
. - opts (dict) – given options, see
create_project
for an extensive list.
Returns: updated project representation and options
Return type: - struct (dict) – project representation as (possibly) nested
-
pyscaffold.api.
verify_options_consistency
(struct, opts)[source]¶ Perform some sanity checks about the given options.
Parameters: - struct (dict) – project representation as (possibly) nested
dict
. - opts (dict) – given options, see
create_project
for an extensive list.
Returns: updated project representation and options
Return type: - struct (dict) – project representation as (possibly) nested
pyscaffold.contrib package¶
Subpackages¶
-
class
pyscaffold.contrib.setuptools_scm.git.
GitWorkdir
(path)[source]¶ Bases:
object
experimental, may change at any time
-
pyscaffold.contrib.setuptools_scm.git.
fail_on_shallow
(wd)[source]¶ experimental, may change at any time
-
pyscaffold.contrib.setuptools_scm.git.
fetch_on_shallow
(wd)[source]¶ experimental, may change at any time
-
pyscaffold.contrib.setuptools_scm.git.
list_files_in_archive
(path)[source]¶ List the files that ‘git archive’ generates.
utils
-
class
pyscaffold.contrib.setuptools_scm.version.
ScmVersion
(tag_version, distance=None, node=None, dirty=False, preformatted=False, **kw)[source]¶ Bases:
object
-
exact
¶
-
-
pyscaffold.contrib.setuptools_scm.version.
get_local_node_and_timestamp
(version, fmt='%Y%m%d%H%M%S')[source]¶
-
pyscaffold.contrib.setuptools_scm.version.
meta
(tag, distance=None, dirty=False, node=None, preformatted=False, **kw)[source]¶
copyright: | 2010-2015 by Ronny Pfannschmidt |
---|---|
license: | MIT |
-
pyscaffold.contrib.setuptools_scm.
get_version
(root='.', version_scheme='guess-next-dev', local_scheme='node-and-date', write_to=None, write_to_template=None, relative_to=None, parse=None)[source]¶ If supplied, relative_to should be a file from which root may be resolved. Typically called by a script or module that is not in the root of the repository to direct setuptools_scm to the root of the repository by supplying
__file__
.
Submodules¶
pyscaffold.contrib.ptr module¶
Copyright Jason R. Coombs
MIT-licenced
Implementation
-
class
pyscaffold.contrib.ptr.
CustomizedDist
(attrs=None)[source]¶ Bases:
setuptools.dist.Distribution
-
allow_hosts
= None¶
-
fetch_build_egg
(req)[source]¶ Specialized version of Distribution.fetch_build_egg that respects respects allow_hosts and index_url.
-
index_url
= None¶
-
-
class
pyscaffold.contrib.ptr.
PyTest
(dist, **kw)[source]¶ Bases:
setuptools.command.test.test
>>> import setuptools >>> dist = setuptools.Distribution() >>> cmd = PyTest(dist)
-
finalize_options
()[source]¶ Set final values for all the options that this command supports. This is always called as late as possible, ie. after any option assignments from the command-line or from other commands have been done. Thus, this is the place to code option dependencies: if ‘foo’ depends on ‘bar’, then it is safe to set ‘foo’ from ‘bar’ as long as ‘foo’ still has the same value it was assigned in ‘initialize_options()’.
This method must be implemented by all command classes.
-
initialize_options
()[source]¶ Set default values for all the options that this command supports. Note that these defaults may be overridden by other commands, by the setup script, by config files, or by the command-line. Thus, this is not the place to code dependencies between options; generally, ‘initialize_options()’ implementations are just a bunch of “self.foo = None” assignments.
This method must be implemented by all command classes.
-
install_extra_dists
(dist)[source]¶ Install extras that are indicated by markers or install all extras if ‘–extras’ is indicated.
-
static
marker_passes
(marker)[source]¶ Given an environment marker, return True if the marker is valid and matches this environment.
-
static
paths_on_pythonpath
(paths)[source]¶ Backward compatibility for paths_on_pythonpath; Returns a null context if paths_on_pythonpath is not implemented in orig.test. Note that this also means that the paths iterable is never consumed, which incidentally means that the None values from dist.fetch_build_eggs in older Setuptools will be disregarded.
-
run
()[source]¶ Override run to ensure requirements are available in this session (but don’t install them anywhere).
-
user_options
= [('extras', None, 'Install (all) setuptools extras when running tests'), ('index-url=', None, 'Specify an index url from which to retrieve dependencies'), ('allow-hosts=', None, 'Whitelist of comma-separated hosts to allow when retrieving dependencies'), ('addopts=', None, 'Additional options to be passed verbatim to the pytest runner')]¶
-
pyscaffold.contrib.six module¶
Utilities for writing code that runs on Python 2 and 3
-
class
pyscaffold.contrib.six.
Module_six_moves_urllib
[source]¶ Bases:
module
Create a six.moves.urllib namespace that resembles the Python 3 namespace
-
error
= <module 'pyscaffold.contrib.six.moves.urllib.error'>¶
-
parse
= <module 'pyscaffold.contrib.six.moves.urllib_parse'>¶
-
request
= <module 'pyscaffold.contrib.six.moves.urllib.request'>¶
-
response
= <module 'pyscaffold.contrib.six.moves.urllib.response'>¶
-
robotparser
= <module 'pyscaffold.contrib.six.moves.urllib.robotparser'>¶
-
-
class
pyscaffold.contrib.six.
Module_six_moves_urllib_error
(name)[source]¶ Bases:
pyscaffold.contrib.six._LazyModule
Lazy loading of moved objects in six.moves.urllib_error
-
ContentTooShortError
¶
-
HTTPError
¶
-
URLError
¶
-
-
class
pyscaffold.contrib.six.
Module_six_moves_urllib_parse
(name)[source]¶ Bases:
pyscaffold.contrib.six._LazyModule
Lazy loading of moved objects in six.moves.urllib_parse
-
ParseResult
¶
-
SplitResult
¶
-
parse_qs
¶
-
parse_qsl
¶
-
quote
¶
-
quote_plus
¶
-
splitquery
¶
-
splittag
¶
-
splituser
¶
-
splitvalue
¶
-
unquote
¶
-
unquote_plus
¶
-
unquote_to_bytes
¶
-
urldefrag
¶
-
urlencode
¶
-
urljoin
¶
-
urlparse
¶
-
urlsplit
¶
-
urlunparse
¶
-
urlunsplit
¶
-
uses_fragment
¶
-
uses_netloc
¶
-
uses_params
¶
-
uses_query
¶
-
uses_relative
¶
-
-
class
pyscaffold.contrib.six.
Module_six_moves_urllib_request
(name)[source]¶ Bases:
pyscaffold.contrib.six._LazyModule
Lazy loading of moved objects in six.moves.urllib_request
-
AbstractBasicAuthHandler
¶
-
AbstractDigestAuthHandler
¶
-
BaseHandler
¶
-
CacheFTPHandler
¶
-
FTPHandler
¶
-
FancyURLopener
¶
-
FileHandler
¶
-
HTTPBasicAuthHandler
¶
-
HTTPCookieProcessor
¶
-
HTTPDefaultErrorHandler
¶
-
HTTPDigestAuthHandler
¶
-
HTTPErrorProcessor
¶
-
HTTPHandler
¶
-
HTTPPasswordMgr
¶
-
HTTPPasswordMgrWithDefaultRealm
¶
-
HTTPRedirectHandler
¶
-
HTTPSHandler
¶
-
OpenerDirector
¶
-
ProxyBasicAuthHandler
¶
-
ProxyDigestAuthHandler
¶
-
ProxyHandler
¶
-
Request
¶
-
URLopener
¶
-
UnknownHandler
¶
-
build_opener
¶
-
getproxies
¶
-
install_opener
¶
-
parse_http_list
¶
-
parse_keqv_list
¶
-
pathname2url
¶
-
proxy_bypass
¶
-
url2pathname
¶
-
urlcleanup
¶
-
urlopen
¶
-
urlretrieve
¶
-
-
class
pyscaffold.contrib.six.
Module_six_moves_urllib_response
(name)[source]¶ Bases:
pyscaffold.contrib.six._LazyModule
Lazy loading of moved objects in six.moves.urllib_response
-
addbase
¶
-
addclosehook
¶
-
addinfo
¶
-
addinfourl
¶
-
-
class
pyscaffold.contrib.six.
Module_six_moves_urllib_robotparser
(name)[source]¶ Bases:
pyscaffold.contrib.six._LazyModule
Lazy loading of moved objects in six.moves.urllib_robotparser
-
RobotFileParser
¶
-
-
class
pyscaffold.contrib.six.
MovedAttribute
(name, old_mod, new_mod, old_attr=None, new_attr=None)[source]¶ Bases:
pyscaffold.contrib.six._LazyDescr
-
class
pyscaffold.contrib.six.
MovedModule
(name, old, new=None)[source]¶ Bases:
pyscaffold.contrib.six._LazyDescr
-
pyscaffold.contrib.six.
add_metaclass
(metaclass)[source]¶ Class decorator for creating a class with a metaclass.
-
pyscaffold.contrib.six.
get_unbound_function
(unbound)[source]¶ Get the function out of a possibly unbound function
-
pyscaffold.contrib.six.
int2byte
()¶ S.pack(v1, v2, …) -> bytes
Return a bytes object containing values v1, v2, … packed according to the format string S.format. See help(struct) for more on format strings.
-
pyscaffold.contrib.six.
iteritems
(d, **kw)[source]¶ Return an iterator over the (key, value) pairs of a dictionary.
-
pyscaffold.contrib.six.
iterlists
(d, **kw)[source]¶ Return an iterator over the (key, [values]) pairs of a dictionary.
-
pyscaffold.contrib.six.
itervalues
(d, **kw)[source]¶ Return an iterator over the values of a dictionary.
-
pyscaffold.contrib.six.
python_2_unicode_compatible
(klass)[source]¶ A decorator that defines __unicode__ and __str__ methods under Python 2. Under Python 3 it does nothing.
To support Python 2 and 3 with a single code base, define a __str__ method returning text and apply this decorator to the class.
Module contents¶
Contribution packages used by PyScaffold
All packages inside contrib
are external packages that come with their
own licences and are not part of the PyScaffold source code itself.
The reason for shipping these dependencies directly is to avoid problems in
the resolution of setup_requires
dependencies that occurred more often
than not, see issues #71 and #72.
Currently the contrib packages are:
- setuptools_scm v1.17.0
- six 1.11.0
- pytest-runner 3.0
The packages/modules were just copied over.
pyscaffold.extensions package¶
Submodules¶
pyscaffold.extensions.cookiecutter module¶
Extension that integrates cookiecutter templates into PyScaffold.
Bases:
pyscaffold.api.Extension
Additionally apply a Cookiecutter template
Register before_create hooks to generate project using Cookiecutter
Parameters: actions (list) – list of actions to perform Returns: updated list of actions Return type: list
Add an option to parser that enables the Cookiecutter extension
Parameters: parser (argparse.ArgumentParser) – CLI parser object
Bases:
RuntimeError
A cookiecutter template (git url) is required.
Bases:
RuntimeError
This extension depends on the
cookiecutter
package.
Create a cookie cutter template
Parameters: Returns: updated project representation and options
Return type: struct, opts
Create a Cookiecutter parser.
Parameters: obj_ref (Extension) – object reference to the actual extension Returns: parser for namespace cli argument Return type: NamespaceParser
pyscaffold.extensions.django module¶
Extension that creates a base structure for the project using django-admin.py.
-
class
pyscaffold.extensions.django.
Django
(name)[source]¶ Bases:
pyscaffold.api.Extension
Generate Django project files
-
activate
(actions)[source]¶ Register hooks to generate project using django-admin.
Parameters: actions (list) – list of actions to perform Returns: updated list of actions Return type: list
-
mutually_exclusive
= True¶
-
-
exception
pyscaffold.extensions.django.
DjangoAdminNotInstalled
(message='django-admin.py is not installed, run: pip install django', *args, **kwargs)[source]¶ Bases:
RuntimeError
This extension depends on the
django-admin.py
cli script.-
DEFAULT_MESSAGE
= 'django-admin.py is not installed, run: pip install django'¶
-
-
pyscaffold.extensions.django.
create_django_proj
(struct, opts)[source]¶ Creates a standard Django project with django-admin.py
Parameters: Returns: updated project representation and options
Return type: struct, opts
Raises: RuntimeError
– raised if django-admin.py is not installed
pyscaffold.extensions.gitlab_ci module¶
Extension that generates configuration and script files for GitLab CI.
pyscaffold.extensions.namespace module¶
Extension that adjust project file tree to include a namespace package.
This extension adds a namespace option to
create_project
and provides correct values for the
options root_pkg and namespace_pkg to the following functions in the
action list.
-
class
pyscaffold.extensions.namespace.
Namespace
(name)[source]¶ Bases:
pyscaffold.api.Extension
Omit creation of skeleton.py
-
activate
(actions)[source]¶ Register an action responsible for adding namespace to the package.
Parameters: actions (list) – list of actions to perform Returns: updated list of actions Return type: list
-
augment_cli
(parser)[source]¶ Add an option to parser that enables the namespace extension.
Parameters: parser (argparse.ArgumentParser) – CLI parser object
-
-
pyscaffold.extensions.namespace.
add_namespace
(struct, opts)[source]¶ Prepend the namespace to a given file structure
Parameters: Returns: directory structure as dictionary of dictionaries and input options
Return type:
-
pyscaffold.extensions.namespace.
create_namespace_parser
(obj_ref)[source]¶ Create a namespace parser.
Parameters: obj_ref (Extension) – object reference to the actual extension Returns: parser for namespace cli argument Return type: NamespaceParser
-
pyscaffold.extensions.namespace.
enforce_namespace_options
(struct, opts)[source]¶ Make sure options reflect the namespace usage.
pyscaffold.extensions.no_skeleton module¶
Extension that omits the creation of file skeleton.py
-
class
pyscaffold.extensions.no_skeleton.
NoSkeleton
(name)[source]¶ Bases:
pyscaffold.api.Extension
Omit creation of skeleton.py and test_skeleton.py
-
activate
(actions)[source]¶ Activate extension
Parameters: actions (list) – list of actions to perform Returns: updated list of actions Return type: list
-
pyscaffold.extensions.pre_commit module¶
Extension that generates configuration files for Yelp pre-commit.
-
class
pyscaffold.extensions.pre_commit.
PreCommit
(name)[source]¶ Bases:
pyscaffold.api.Extension
Generate pre-commit configuration file
-
activate
(actions)[source]¶ Activate extension
Parameters: actions (list) – list of actions to perform Returns: updated list of actions Return type: list
-
pyscaffold.extensions.tox module¶
Extension that generates configuration files for the Tox test automation tool.
pyscaffold.extensions.travis module¶
Extension that generates configuration and script files for Travis CI.
Module contents¶
Built-in extensions for PyScaffold.
pyscaffold.templates package¶
Module contents¶
Templates for all files of a project’s scaffold
Template of AUTHORS.rst
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
changelog
(opts)[source]¶ Template of CHANGELOG.rst
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
conftest_py
(opts)[source]¶ Template of conftest.py
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
coveragerc
(opts)[source]¶ Template of .coveragerc
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
get_template
(name)[source]¶ Retrieve the template by name
Parameters: name – name of template Returns: template Return type: string.Template
-
pyscaffold.templates.
gitignore
(opts)[source]¶ Template of .gitignore
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
gitignore_empty
(opts)[source]¶ Template of empty .gitignore
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
gitlab_ci
(opts)[source]¶ Template of .gitlab-ci.yml
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
init
(opts)[source]¶ Template of __init__.py
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
license
(opts)[source]¶ Template of LICENSE.txt
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
namespace
(opts)[source]¶ Template of __init__.py defining a namespace package
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
pre_commit_config
(opts)[source]¶ Template of .pre-commit-config.yaml
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
readme
(opts)[source]¶ Template of README.rst
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
requirements
(opts)[source]¶ Template of requirements.txt
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
setup_cfg
(opts)[source]¶ Template of setup.cfg
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
setup_py
(opts)[source]¶ Template of setup.py
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
skeleton
(opts)[source]¶ Template of skeleton.py defining a basic console script
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
Template of authors.rst
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
sphinx_changelog
(opts)[source]¶ Template of changelog.rst
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
sphinx_conf
(opts)[source]¶ Template of conf.py
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
sphinx_index
(opts)[source]¶ Template of index.rst
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
sphinx_license
(opts)[source]¶ Template of license.rst
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
sphinx_makefile
(opts)[source]¶ Template of Sphinx’s Makefile
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
test_skeleton
(opts)[source]¶ Template of unittest for skeleton.py
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
-
pyscaffold.templates.
tox
(opts)[source]¶ Template of tox.ini
Parameters: opts – mapping parameters as dictionary Returns: file content as string Return type: str
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.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
orforce
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: GitNotInstalled
– when git command is not availableGitNotConfigured
– when git does not know user information
-
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: Raises: PyScaffoldTooOld
– when PyScaffold is to old to update fromNoPyScaffoldProject
– when project was not generated with PyScaffold
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.
-
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 objectReturns: local version 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'¶
-
-
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'¶
-
-
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.
-
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
. 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')
- activity (str) – usually a verb or command, e.g.
-
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: 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: Additional keyword arguments are passed to the
git
callable object.
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: 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.
- log (bool): log activity when true.
-
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.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: 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: - opts (dict) –
-
pyscaffold.structure.
create_structure
(struct, opts, prefix=None)[source]¶ Manifests a directory structure in the filesystem
Parameters: Returns: directory structure as dictionary of dictionaries (similar to input, but only containing the files that actually changed) and input options
Return type: Raises: RuntimeError
– raised if content type in struct is unknown
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: Returns: styled and formatted message
Return type:
-
pyscaffold.termui.
init_colorama
()[source]¶ Initialize colorama if it is available.
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:
-
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:
-
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:
-
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: Returns: distance between s1 and s2
Return type:
-
pyscaffold.utils.
list2str
(lst, indent=0, brackets=True, quotes=True, sep=', ')[source]¶ Generate a Python syntax list string with an indention
Parameters: Returns: string representation of the list
Return type:
-
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:
-
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