formate¶
Python formatting mate.
formate
runs a series of user-selected hooks which reformat Python source files.
This can include changing quote characters,
rewriting imports, and calling tools such as
isort and yapf.
Definitions¶
for·mate
Installation¶
python3 -m pip install formate --user
First add the required channels
conda config --add channels https://conda.anaconda.org/conda-forge
conda config --add channels https://conda.anaconda.org/domdfcoding
Then install
conda install formate
python3 -m pip install git+https://github.com/python-formate/formate@master --user
Contents¶
Usage¶
Command Line¶
Reformat the given Python source files.
formate [OPTIONS] [FILENAME]...
Options
-
-c
,
--config-file
<config_file>
¶ The path or filename of the TOML configuration file to use. If a filename is given it is searched for in the current and parent directories.
- Default
formate.toml
-
-e
,
--exclude
<PATTERN>
¶ Patterns for files to exclude from formatting.
-
-v
,
--verbose
¶
Show verbose output.
-
--colour
,
--no-colour
¶
Whether to use coloured output.
-
-T
,
--traceback
¶
Show the complete traceback on error.
-
--diff
¶
Show a diff of changes made
-
--version
¶
Show the version and exit.
Arguments
-
FILENAME
¶
Optional argument(s). Default
None
As a pre-commit
hook¶
formate
can also be used as a pre-commit hook.
To do so, add the following to your
.pre-commit-config.yaml file:
- repo: https://github.com/python-formate/formate
rev: 0.7.0
hooks:
- id: formate
args:
- --verbose
The args
option can be used to provide the command line arguments shown above.
By default formate
is run with --verbose --diff
Configuration¶
formate
is configured using the formate.toml
file in the root of your project
(alongside setup.py
, tox.ini
etc.).
The file uses the TOML syntax, built around a top-level mapping of two keys.
The -c / --config-file
option can be used to point to a file with a different name,
but at this time the file must be TOML and must have the same layout.
The two top-level keys are hooks and config.
hooks
¶
This is a mapping of hook names to their settings. The values can be either:
an integer, representing the priority of the hook.
a mapping of the following:
priority
– an integer, representing the priority of the hook.args
– a list of positional arguments to pass to the hook function. Optional. Default()
.kwargs
– a mapping of keyword arguments to pass to the hook. Optional. Default{}
.
The TOML syntax allows for the mapping to spread over multiple tables, like so:
[hooks]
reformat-generics = 40
collections-import-rewrite = 20
noqa-reformat = 60
ellipsis-reformat = 70
[hooks.isort]
priority = 50
[hooks.isort.kwargs]
multi_line_output = 8
use_parentheses = true
remove_redundant_aliases = true
config
¶
This is a mapping of general configuration settings, which hooks can use as they please.
Common keys include indent
, indicating the type of indent to use, and line_length
,
indicating how long lines may be.
Example:
[config]
indent = "\t"
line_length = 115
Alternatively the configuration may be placed in the pyproject.toml
file defined in PEP 518.
The only difference is that hooks
and config
become tool.formate.hooks
and tool.formate.config
.
You must also pass --config-file pyproject.toml
on the command line.
Built-in Hooks¶
formate
ships with several hooks out of the box:
dynamic_quotes
¶
Reformats quotes in the given source, and returns the reformatted source.
This hook takes no arguments.
collections-import-rewrite
¶
Identify deprecated from collections import <abc>
imports,
and rewrite them as from collections.abc import <abc>
.
This hook takes no arguments.
noqa_reformat
¶
Pull # noqa: ...
comments that immediately follow docstrings back up to the end of the correct line.
This hook takes no arguments.
check_ast
¶
Check the source can be parsed as a Python Abstract Syntax Tree. This could be called early in the execution – to check the file is valid before starting reformatting – and again at the end to ensure no errors were introduced by the reformatting.
This hook takes no arguments.
ellipsis_reformat
¶
Move ellipses (...
) for type stubs onto the end of the stub definition.
Before:
def foo(value: str) -> int: ...After:
def foo(value: str) -> int: ...
This hook takes no arguments.
reformat-generics
¶
Reformats generics (typing.Generic
, typing.Union
, typing.Callable
etc.).
This hook takes a single keyword argument: indent
.
The indent can also be configured via the indent
key in the config table.
Creating your own hooks¶
It is easy to create your own hooks to extend formate
. A basic hook looks like this:
def make_upper(source: str) -> str:
"""
Make all the source uppercase.
:param source: The source to reformat.
:return: The reformatted source.
"""
return source.upper()
An entry point must be configured for the hook. For setuptools:
[options.entry_points]
formate_hooks =
make_upper=<import path>:make_upper
or in pyproject.toml
with PEP 621:
[project.entry-points.formate_hooks]
make_upper = "<import path>:make_upper"
Hooks may also accept positional and/or keyword arguments, either named or with *args
and **kwargs
:
def change_case(source: str, upper: bool = True) -> str:
"""
Change the case of the source.
:param source: The source to reformat.
:param upper: Makes the source uppercase.
:return: The reformatted source.
"""
if upper:
return source.upper()
else:
return source.lower()
Some hooks may require access the the global configuration dict
(the [config] table in formate.toml
).
Hooks can request this by using the @formate.config.wants_global_config
decorator,
which provides the configuration as the formate_global_config
keyword argument:
def change_indents(
source: str,
formate_global_config: Optional[Mapping] = None,
) -> str:
"""
Change the indents of the source.
:param source: The source to reformat.
:param formate_global_config: The global configuration dictionary. Optional.
:return: The reformatted source.
"""
if formate_global_config is None:
formate_global_config = {}
indent = formate_global_config.get("indent", '\t')
return re.sub("( |\t)", indent, source)
Similarly, some hooks may want to know which filename is being reformatted.
They can request this using the @formate.config.wants_filename
decorator
(new in version 0.2.0), which provides the configuration as the formate_filename
keyword argument:
def lint_stubs(source: str, formate_filename: PathLike) -> str:
"""
Lint Python stub files.
:param source: The source to check.
:param formate_filename: The name of the source file,
to ensure this hook only runs on type stubs.
:return: The reformatted source.
"""
if os.path.splitext(formate_filename)[1] != ".pyi":
return source
...
return reformatted_source
See repo-helper/formate-blackrepo-helper/formate-black for an example extension.
Changelog¶
0.4.9¶
Bugs Fixed¶
formate.dynamic_quotes()
– Preserve surrogates in strings. This prevents a crash when attempting to write the resulting file.
0.4.8¶
Bugs Fixed¶
formate.reformat_file()
– Only write to the file if there have been any changes. This avoids unnecessary changes to the mtime.formate.reformat_generics
– Don’t crash if a generic’s name contains a.
.
0.4.7¶
Bugs Fixed¶
formate.reformat_generics
– Correctly handle boolean values in Literals.
0.4.6¶
Bugs Fixed¶
formate.dynamic_quotes
– Preserve quote style in docstrings.
0.4.5¶
Bugs Fixed¶
formate.config
– The decorators now use a type variable to indicate to type checkers the returned object has the same type as the decorated object.formate.isort_hook()
andformate.yapf_hook()
– Don’t crash when keys are missing fromformate_global_config
and aren’t in**kwargs
.
0.4.4¶
0.4.2¶
Bugs Fixed¶
formate.mini_hooks.squish_stubs()
– Ensure space between classes and functions is preserved in cases where there would be no space between the class and a method.
0.4.1¶
Bugs Fixed¶
formate.mini_hooks.squish_stubs()
– Don’t crash due to accessing an out-of-range value from a list.
0.4.0¶
Enhancements¶
formate.mini_hooks.squish_stubs()
– Remove whitespace between the class definition and first single-line function.
0.3.2¶
Bugs Fixed¶
formate.mini_hooks.squish_stubs()
– Don’t crash due to accessing an out-of-range value from a list.
0.3.1¶
Bugs Fixed¶
formate.isort_hook()
– Preserve aliases / re-exports (e.g. import foo as foo) in stub files, as these are necessary for type checkers to understand re-exports.
0.3.0¶
Enhancements¶
Add support for reading the configuration from a
[tool.formate]
table inpyproject.toml
.
0.2.5¶
Bugs Fixed¶
formate.mini_hooks.squish_stubs()
– Improve handling of stubs with multiple decorators and keyword-only arguments.
0.2.4¶
Bugs Fixed¶
formate.isort_hook()
– Correctly handle isort options which may be either a single value or a sequence of values.
0.2.3¶
Bugs Fixed¶
formate.mini_hooks.squish_stubs()
– Correctly handle comments and docstrings at the very top of stub files.
0.2.0¶
0.1.0¶
Initial release.
Downloading source code¶
The formate
source code is available on GitHub,
and can be accessed from the following URL: https://github.com/python-formate/formate
If you have git
installed, you can clone the repository with the following command:
git clone https://github.com/python-formate/formate
Cloning into 'formate'...
remote: Enumerating objects: 47, done.
remote: Counting objects: 100% (47/47), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 173 (delta 16), reused 17 (delta 6), pack-reused 126
Receiving objects: 100% (173/173), 126.56 KiB | 678.00 KiB/s, done.
Resolving deltas: 100% (66/66), done.

Downloading a ‘zip’ file of the source code¶
Building from source¶
The recommended way to build formate
is to use tox:
tox -e build
The source and wheel distributions will be in the directory dist
.
If you wish, you may also use pep517.build or another PEP 517-compatible build tool.
License¶
formate
is licensed under the MIT License
A short and simple permissive license with conditions only requiring preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code.
Permissions | Conditions | Limitations |
---|---|---|
|
|
Copyright (c) 2021-2022 Dominic Davis-Foster
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.
formate
¶
Python formatting mate.
Functions:
|
Given a list of hooks (in order), call them in turn to reformat the source. |
|
Reformat the given file, and show the diff if changes were made. |
|
Call isort, using the given keyword arguments as its configuration. |
|
Call yapf, using the given keyword arguments as its configuration. |
Classes:
|
Reformat a Python source file. |
-
call_hooks
(hooks, source, filename)[source]¶ Given a list of hooks (in order), call them in turn to reformat the source.
- Parameters
- Return type
- Returns
The reformatted source.
Changed in version 0.4.3: Added the
filename
argument.
-
reformat_file
(filename, config, colour=None)[source]¶ Reformat the given file, and show the diff if changes were made.
- Parameters
- Return type
-
class
Reformatter
(filename, config)[source]¶ Bases:
object
Reformat a Python source file.
- Parameters
filename (
Union
[str
,Path
,PathLike
]) – The filename to reformat.config (
FormateConfigDict
) – Theformate
configuration, parsed from a TOML file (or similar).
Attributes:
The filename being reformatted, as a POSIX-style path.
The filename being reformatted.
The
formate
configuration, parsed from a TOML file (or similar).Methods:
run
()Run the reformatter.
get_diff
()Returns the diff between the original and reformatted file content.
Return the reformatted file as a string.
to_file
()Write the reformatted source to the original file.
-
config
¶ Type:
FormateConfigDict
The
formate
configuration, parsed from a TOML file (or similar).
-
isort_hook
(source, formate_filename, formate_global_config=None, **kwargs)[source]¶ Call isort, using the given keyword arguments as its configuration.
-
yapf_hook
(source, formate_global_config=None, **kwargs)[source]¶ Call yapf, using the given keyword arguments as its configuration.
- Parameters
If
yapf_style
is given as a keyword argument, use that style. If a filename is given as the style it is searched for in the current and parent directories, and the style taken from the configuration in that file.- Return type
- Returns
The reformatted source.
formate.classes
¶
Core classes.
Classes:
|
|
|
|
|
Represents an entry point for a hook. |
|
Represents a |
Data:
Type hint for the |
-
typeddict
FormateConfigDict
[source]¶ Bases:
TypedDict
typing.TypedDict
representing the configuration mapping parsed fromformate.toml
or similar.- Optional Keys
hooks (
Mapping
[str
,Union
[int
,ExpandedHookDict
]]) – Mapping defining the hooks to run. Each value can either be an integer (the priority) or aExpandedHookDict
.config (
Mapping
[str
,Any
]) – Mapping defining the global configuration forformate
.
-
typeddict
ExpandedHookDict
[source]¶ Bases:
TypedDict
typing.TypedDict
representing the expanded form of a hook in the mapping parsed from the config file.
-
HooksMapping
¶ Type hint for the
hooks
key of theformate
configuration mapping.Alias of
Mapping
[str
,Union
[int
,ExpandedHookDict
]]
-
class
EntryPoint
(name, obj)[source]¶ Bases:
object
Represents an entry point for a hook.
- Parameters
Attributes:
Methods:
__repr__
()Return a string representation of the
EntryPoint
.from_dict
(d)Construct an instance of
EntryPoint
from a dictionary.to_dict
([convert_values])Returns a dictionary containing the contents of the
EntryPoint
object.-
name
¶ Type:
str
The name of the entry point. The name is normalized into lowercase, with underscores replaced by hyphens.
-
__repr__
()¶ Return a string representation of the
EntryPoint
.- Return type
-
classmethod
from_dict
(d)¶ Construct an instance of
EntryPoint
from a dictionary.
-
to_dict
(convert_values=False)¶ Returns a dictionary containing the contents of the
EntryPoint
object.
-
class
Hook
(name, priority=10, args=(), kwargs={}, entry_point=None, global_config={})[source]¶ Bases:
object
Represents a
formate
reformatting hook.- Parameters
name (
str
) – The name of the entry point. The name is normalized into lowercase, with underscores replaced by hyphens.priority (
int
) – The priority of the hook. Default10
.args – The positional arguments passed to the hook function. Default
()
.kwargs (
Dict
[str
,Any
]) – The keyword arguments passed to the hook function. Default{}
.entry_point (
Optional
[EntryPoint
]) – DefaultNone
.global_config (
Mapping
[str
,Any
]) – A read-only view on the global configuration mapping, for hooks to do with as they wish. Default{}
.
Attributes:
The name of the hook.
The priority of the hook.
The positional arguments passed to the hook function.
The keyword arguments passed to the hook function.
A read-only view on the global configuration mapping, for hooks to do with as they wish.
Methods:
parse
(data)Parse the given mapping into
Hook
s.__call__
(source, filename)Call the hook.
__repr__
()Return a string representation of the
Hook
.from_dict
(d)Construct an instance of
Hook
from a dictionary.to_dict
([convert_values])Returns a dictionary containing the contents of the
Hook
object.-
name
¶ Type:
str
The name of the hook. The name is normalized into lowercase, with underscores replaced by hyphens.
-
global_config
¶ -
A read-only view on the global configuration mapping, for hooks to do with as they wish.
-
__call__
(source, filename)[source]¶ Call the hook.
- Parameters
- Return type
- Returns
The reformatted source.
- Raises
TypeError
ifentry_point
has not been set.
Changed in version 0.2.0: Added the
filename
argument.
formate.config
¶
Read and parse formate configuration.
Data:
Invariant |
Functions:
|
Load the |
|
Returns a read-only view on the global configuration mapping, for hooks to do with as they wish. |
|
Given a mapping parsed from a TOML file (or similar), return a list of hooks selected by the user. |
|
Decorator to indicate to |
|
Decorator to indicate to |
-
_C_str
= TypeVar(_C_str, bound=typing.Callable[..., str])¶ Type:
TypeVar
Invariant
TypeVar
bound totyping.Callable
[…,str
].
-
load_toml
(filename)[source]¶ Load the
formate
configuration mapping from the given TOML file.- Parameters
- Return type
-
parse_global_config
(config)[source]¶ Returns a read-only view on the global configuration mapping, for hooks to do with as they wish.
- Parameters
config (
Mapping
) – Theformate
configuration, parsed from a TOML file (or similar).- Return type
-
parse_hooks
(config)[source]¶ Given a mapping parsed from a TOML file (or similar), return a list of hooks selected by the user.
formate.dynamic_quotes
¶
Applies “dynamic quotes” to Python source code.
The rules are:
Use double quotes
"
where possible.Use single quotes
'
for empty strings and single characters (a
,\n
etc.).Leave the quotes unchanged for multiline strings, f strings and raw strings.
formate.ellipses
¶
Move ellipses (...
) for type stubs onto the end of the stub definition.
Before:
def foo(value: str) -> int: ...After:
def foo(value: str) -> int: ...
formate.exceptions
¶
Exception classes.
-
exception
HookNotFoundError
(hook)[source]¶ Bases:
ValueError
Exception to indicate the specified hook could not be found.
formate.imports
¶
Converts import statements.
Classes:
|
Identify deprecated |
Functions:
|
Identify deprecated |
formate.mini_hooks
¶
Small but mighty hooks.
Functions:
|
Check the source can be parsed as a Python Abstract Syntax Tree. |
|
Pull |
|
Squash type stubs by removing unnecessary blank lines. |
-
check_ast
(source)[source]¶ Check the source can be parsed as a Python Abstract Syntax Tree.
- Parameters
source (
str
) – The source to check.- Raises
SyntaxError – If the source is not valid Python.
- Return type
- Returns
The source unchanged.
-
noqa_reformat
(source)[source]¶ Pull
# noqa: ...
comments that immediately follow docstrings back up to the end of the correct line.
formate.reformat_generics
¶
Formats generics (List[...]
, Union[...]
etc.) at the module and class level.
Example output, with a line length of 100
:
ParamsMappingValueType = Union[str, bytes, int, float, Iterable[Union[str, bytes, int, float]]]
Data = Union[None, str, bytes, MutableMapping[str, Any], Iterable[Tuple[str, Optional[str]]], IO]
ParamsType = Union[
Mapping[Union[str, bytes, int, float], ParamsMappingValueType],
Union[str, bytes],
Tuple[Union[str, bytes, int, float], ParamsMappingValueType],
None
]
Functions:
|
Reformats generics ( |
Classes:
|
Represents a |
|
Represents a list of elements, most often used within a |
-
reformat_generics
(source, formate_global_config=None, **kwargs)[source]¶ Reformats generics (
typing.Generic
,typing.Union
,typing.Callable
etc.) in the given source, and returns the reformatted source.
-
class
Generic
(name, elements)[source]¶ Bases:
object
Represents a
typing.Generic
,typing.Union
,typing.Callable
etc.- Parameters
Methods:
formate.utils
¶
Utility functions.
Functions:
|
Given a list of hooks, import the corresponding entry point and return a mapping of entry point names to |
|
Normalize the given name into lowercase, with underscores replaced by hyphens. |
|
Context manager to catch |
Classes:
|
ABC for rewriting Python source files from an AST and a token stream. |
|
Subclass of |
-
import_entry_points
(hooks)[source]¶ Given a list of hooks, import the corresponding entry point and return a mapping of entry point names to
EntryPoint
objects.- Parameters
- Raises
HookNotFoundError
if no entry point can be found for a hook.- Return type
-
normalize
(name)[source]¶ Normalize the given name into lowercase, with underscores replaced by hyphens.
-
syntaxerror_for_file
(filename)[source]¶ Context manager to catch
SyntaxError
and set its filename tofilename
if the current filename is<unknown>
.This is useful for syntax errors raised when parsing source into an AST.
- Return type
-
class
Rewriter
(source)[source]¶ Bases:
NodeVisitor
ABC for rewriting Python source files from an AST and a token stream.
Attributes:
The original source.
The tokenized source.
The parts of code to replace.
Methods:
rewrite
()Rewrite the source and return the new source.
record_replacement
(text_range, new_source)Record a region of text to be replaced.
-
tokens
¶ Type:
ASTTokens
The tokenized source.
-
replacements
¶ Type:
List
[Tuple
[Tuple
[int
,int
],str
]]The parts of code to replace.
Each element comprises a tuple of
(start char, end char)
insource
, and the new text to insert between these positions.
-
-
class
SyntaxTracebackHandler
(exception=Abort())[source]¶ Bases:
TracebackHandler
Subclass of
consolekit.tracebacks.TracebackHandler
to additionally handleSyntaxError
.
View the Function Index or browse the Source Code.