]> git.madduck.net Git - etc/vim.git/blobdiff - README.md

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Scrollable sidebar (#1457)
[etc/vim.git] / README.md
index 04905e2c73ee3b985334c7007cfa818e6a737ea4..3c63cb5e51aa376ffa8263012b4be92bc756c7c0 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
 <p align="center">
 <a href="https://travis-ci.com/psf/black"><img alt="Build Status" src="https://travis-ci.com/psf/black.svg?branch=master"></a>
 <a href="https://github.com/psf/black/actions"><img alt="Actions Status" src="https://github.com/psf/black/workflows/Test/badge.svg"></a>
 <p align="center">
 <a href="https://travis-ci.com/psf/black"><img alt="Build Status" src="https://travis-ci.com/psf/black.svg?branch=master"></a>
 <a href="https://github.com/psf/black/actions"><img alt="Actions Status" src="https://github.com/psf/black/workflows/Test/badge.svg"></a>
+<a href="https://github.com/psf/black/actions"><img alt="Actions Status" src="https://github.com/psf/black/workflows/Primer/badge.svg"></a>
 <a href="https://black.readthedocs.io/en/stable/?badge=stable"><img alt="Documentation Status" src="https://readthedocs.org/projects/black/badge/?version=stable"></a>
 <a href="https://coveralls.io/github/psf/black?branch=master"><img alt="Coverage Status" src="https://coveralls.io/repos/github/psf/black/badge.svg?branch=master"></a>
 <a href="https://github.com/psf/black/blob/master/LICENSE"><img alt="License: MIT" src="https://black.readthedocs.io/en/stable/_static/license.svg"></a>
 <a href="https://black.readthedocs.io/en/stable/?badge=stable"><img alt="Documentation Status" src="https://readthedocs.org/projects/black/badge/?version=stable"></a>
 <a href="https://coveralls.io/github/psf/black?branch=master"><img alt="Coverage Status" src="https://coveralls.io/repos/github/psf/black/badge.svg?branch=master"></a>
 <a href="https://github.com/psf/black/blob/master/LICENSE"><img alt="License: MIT" src="https://black.readthedocs.io/en/stable/_static/license.svg"></a>
@@ -31,8 +32,9 @@ Try it out now using the [Black Playground](https://black.now.sh). Watch the
 ---
 
 _Contents:_ **[Installation and usage](#installation-and-usage)** |
 ---
 
 _Contents:_ **[Installation and usage](#installation-and-usage)** |
-**[Code style](#the-black-code-style)** | **[pyproject.toml](#pyprojecttoml)** |
-**[Editor integration](#editor-integration)** | **[blackd](#blackd)** |
+**[Code style](#the-black-code-style)** | **[Pragmatism](#pragmatism)** |
+**[pyproject.toml](#pyprojecttoml)** | **[Editor integration](#editor-integration)** |
+**[blackd](#blackd)** | **[black-primer](#black-primer)** |
 **[Version control integration](#version-control-integration)** |
 **[Ignoring unmodified files](#ignoring-unmodified-files)** | **[Used by](#used-by)** |
 **[Testimonials](#testimonials)** | **[Show your style](#show-your-style)** |
 **[Version control integration](#version-control-integration)** |
 **[Ignoring unmodified files](#ignoring-unmodified-files)** | **[Used by](#used-by)** |
 **[Testimonials](#testimonials)** | **[Show your style](#show-your-style)** |
@@ -52,7 +54,7 @@ run but you can reformat Python 2 code with it, too.
 
 To get started right away with sensible defaults:
 
 
 To get started right away with sensible defaults:
 
-```
+```sh
 black {source_file_or_directory}
 ```
 
 black {source_file_or_directory}
 ```
 
@@ -61,36 +63,41 @@ black {source_file_or_directory}
 _Black_ doesn't provide many options. You can list them by running `black --help`:
 
 ```text
 _Black_ doesn't provide many options. You can list them by running `black --help`:
 
 ```text
-black [OPTIONS] [SRC]...
+Usage: black [OPTIONS] [SRC]...
+
+  The uncompromising code formatter.
 
 Options:
   -c, --code TEXT                 Format the code passed in as a string.
   -l, --line-length INTEGER       How many characters per line to allow.
                                   [default: 88]
 
 Options:
   -c, --code TEXT                 Format the code passed in as a string.
   -l, --line-length INTEGER       How many characters per line to allow.
                                   [default: 88]
+
   -t, --target-version [py27|py33|py34|py35|py36|py37|py38]
                                   Python versions that should be supported by
                                   Black's output. [default: per-file auto-
                                   detection]
   -t, --target-version [py27|py33|py34|py35|py36|py37|py38]
                                   Python versions that should be supported by
                                   Black's output. [default: per-file auto-
                                   detection]
-  --py36                          Allow using Python 3.6-only syntax on all
-                                  input files.  This will put trailing commas
-                                  in function signatures and calls also after
-                                  *args and **kwargs. Deprecated; use
-                                  --target-version instead. [default: per-file
-                                  auto-detection]
+
   --pyi                           Format all input files like typing stubs
                                   regardless of file extension (useful when
                                   piping source on standard input).
   --pyi                           Format all input files like typing stubs
                                   regardless of file extension (useful when
                                   piping source on standard input).
+
   -S, --skip-string-normalization
                                   Don't normalize string quotes or prefixes.
   --check                         Don't write the files back, just return the
                                   status.  Return code 0 means nothing would
                                   change.  Return code 1 means some files
   -S, --skip-string-normalization
                                   Don't normalize string quotes or prefixes.
   --check                         Don't write the files back, just return the
                                   status.  Return code 0 means nothing would
                                   change.  Return code 1 means some files
-                                  would be reformatted.  Return code 123 means
+                                  would be reformatted. Return code 123 means
                                   there was an internal error.
                                   there was an internal error.
+
   --diff                          Don't write the files back, just output a
                                   diff for each file on stdout.
   --diff                          Don't write the files back, just output a
                                   diff for each file on stdout.
+
+  --color / --no-color            Show colored diff. Only applies when
+                                  `--diff` is given.
+
   --fast / --safe                 If --fast given, skip temporary sanity
                                   checks. [default: --safe]
   --fast / --safe                 If --fast given, skip temporary sanity
                                   checks. [default: --safe]
+
   --include TEXT                  A regular expression that matches files and
                                   directories that should be included on
                                   recursive searches.  An empty value means
   --include TEXT                  A regular expression that matches files and
                                   directories that should be included on
                                   recursive searches.  An empty value means
@@ -99,6 +106,7 @@ Options:
                                   on all platforms (Windows, too).  Exclusions
                                   are calculated first, inclusions later.
                                   [default: \.pyi?$]
                                   on all platforms (Windows, too).  Exclusions
                                   are calculated first, inclusions later.
                                   [default: \.pyi?$]
+
   --exclude TEXT                  A regular expression that matches files and
                                   directories that should be excluded on
                                   recursive searches.  An empty value means no
   --exclude TEXT                  A regular expression that matches files and
                                   directories that should be excluded on
                                   recursive searches.  An empty value means no
@@ -106,16 +114,23 @@ Options:
                                   directories on all platforms (Windows, too).
                                   Exclusions are calculated first, inclusions
                                   later.  [default: /(\.eggs|\.git|\.hg|\.mypy
                                   directories on all platforms (Windows, too).
                                   Exclusions are calculated first, inclusions
                                   later.  [default: /(\.eggs|\.git|\.hg|\.mypy
-                                  _cache|\.nox|\.tox|\.venv|_build|buck-
+                                  _cache|\.nox|\.tox|\.venv|\.svn|_build|buck-
                                   out|build|dist)/]
                                   out|build|dist)/]
+
+  --force-exclude TEXT            Like --exclude, but files and directories
+                                  matching this regex will be excluded even
+                                  when they are passed explicitly as arguments
+
   -q, --quiet                     Don't emit non-error messages to stderr.
   -q, --quiet                     Don't emit non-error messages to stderr.
-                                  Errors are still emitted, silence those with
+                                  Errors are still emitted; silence those with
                                   2>/dev/null.
                                   2>/dev/null.
+
   -v, --verbose                   Also emit messages to stderr about files
                                   that were not changed or were ignored due to
                                   --exclude=.
   -v, --verbose                   Also emit messages to stderr about files
                                   that were not changed or were ignored due to
                                   --exclude=.
+
   --version                       Show the version and exit.
   --version                       Show the version and exit.
-  --config PATH                   Read configuration from PATH.
+  --config FILE                   Read configuration from PATH.
   -h, --help                      Show this message and exit.
 ```
 
   -h, --help                      Show this message and exit.
 ```
 
@@ -127,6 +142,60 @@ _Black_ is a well-behaved Unix-style command-line tool:
 - it only outputs messages to users on standard error;
 - exits with code 0 unless an internal error occurred (or `--check` was used).
 
 - it only outputs messages to users on standard error;
 - exits with code 0 unless an internal error occurred (or `--check` was used).
 
+### Using _Black_ with other tools
+
+While _Black_ enforces formatting that conforms to PEP 8, other tools may raise warnings
+about _Black_'s changes or will overwrite _Black_'s changes. A good example of this is
+[isort](https://pypi.org/p/isort). Since _Black_ is barely configurable, these tools
+should be configured to neither warn about nor overwrite _Black_'s changes.
+
+Actual details on _Black_ compatible configurations for various tools can be found in
+[compatible_configs](https://github.com/psf/black/blob/master/docs/compatible_configs.md).
+
+### Migrating your code style without ruining git blame
+
+A long-standing argument against moving to automated code formatters like _Black_ is
+that the migration will clutter up the output of `git blame`. This was a valid argument,
+but since Git version 2.23, Git natively supports
+[ignoring revisions in blame](https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revltrevgt)
+with the `--ignore-rev` option. You can also pass a file listing the revisions to ignore
+using the `--ignore-revs-file` option. The changes made by the revision will be ignored
+when assigning blame. Lines modified by an ignored revision will be blamed on the
+previous revision that modified those lines.
+
+So when migrating your project's code style to _Black_, reformat everything and commit
+the changes (preferably in one massive commit). Then put the full 40 characters commit
+identifier(s) into a file.
+
+```
+# Migrate code style to Black
+5b4ab991dede475d393e9d69ec388fd6bd949699
+```
+
+Afterwards, you can pass that file to `git blame` and see clean and meaningful blame
+information.
+
+```console
+$ git blame important.py --ignore-revs-file .git-blame-ignore-revs
+7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 1) def very_important_function(text, file):
+abdfd8b0 (Alice Doe  2019-09-23 11:39:32 -0400 2)     text = text.lstrip()
+7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 3)     with open(file, "r+") as f:
+7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 4)         f.write(formatted)
+```
+
+You can even configure `git` to automatically ignore revisions listed in a file on every
+call to `git blame`.
+
+```console
+$ git config blame.ignoreRevsFile .git-blame-ignore-revs
+```
+
+**The one caveat is that GitHub and GitLab do not yet support ignoring revisions using
+their native UI of blame.** So blame information will be cluttered with a reformatting
+commit on those platforms. (If you'd like this feature, there's an open issue for
+[GitLab](https://gitlab.com/gitlab-org/gitlab/-/issues/31423) and please let GitHub
+know!)
+
 ### NOTE: This is a beta product
 
 _Black_ is already [successfully used](#used-by) by many projects, small and big. It
 ### NOTE: This is a beta product
 
 _Black_ is already [successfully used](#used-by) by many projects, small and big. It
@@ -215,6 +284,69 @@ def very_important_function(
         ...
 ```
 
         ...
 ```
 
+_Black_ prefers parentheses over backslashes, and will remove backslashes if found.
+
+```py3
+# in:
+
+if some_short_rule1 \
+  and some_short_rule2:
+      ...
+
+# out:
+
+if some_short_rule1 and some_short_rule2:
+  ...
+
+
+# in:
+
+if some_long_rule1 \
+  and some_long_rule2:
+    ...
+
+# out:
+
+if (
+    some_long_rule1
+    and some_long_rule2
+):
+    ...
+
+```
+
+Backslashes and multiline strings are one of the two places in the Python grammar that
+break significant indentation. You never need backslashes, they are used to force the
+grammar to accept breaks that would otherwise be parse errors. That makes them confusing
+to look at and brittle to modify. This is why _Black_ always gets rid of them.
+
+If you're reaching for backslashes, that's a clear signal that you can do better if you
+slightly refactor your code. I hope some of the examples above show you that there are
+many ways in which you can do it.
+
+However there is one exception: `with` statements using multiple context managers.
+Python's grammar does not allow organizing parentheses around the series of context
+managers.
+
+We don't want formatting like:
+
+```py3
+with make_context_manager1() as cm1, make_context_manager2() as cm2, make_context_manager3() as cm3, make_context_manager4() as cm4:
+    ...  # nothing to split on - line too long
+```
+
+So _Black_ will now format it like this:
+
+```py3
+with \
+     make_context_manager(1) as cm1, \
+     make_context_manager(2) as cm2, \
+     make_context_manager(3) as cm3, \
+     make_context_manager(4) as cm4 \
+:
+    ...  # backslashes and an ugly stranded colon
+```
+
 You might have noticed that closing brackets are always dedented and that a trailing
 comma is always added. Such formatting produces smaller diffs; when you add or remove an
 element, it's always just one line. Also, having the closing bracket dedented provides a
 You might have noticed that closing brackets are always dedented and that a trailing
 comma is always added. Such formatting produces smaller diffs; when you add or remove an
 element, it's always just one line. Also, having the closing bracket dedented provides a
@@ -395,9 +527,12 @@ PEP 8
 [recommends](https://www.python.org/dev/peps/pep-0008/#whitespace-in-expressions-and-statements)
 to treat `:` in slices as a binary operator with the lowest priority, and to leave an
 equal amount of space on either side, except if a parameter is omitted (e.g.
 [recommends](https://www.python.org/dev/peps/pep-0008/#whitespace-in-expressions-and-statements)
 to treat `:` in slices as a binary operator with the lowest priority, and to leave an
 equal amount of space on either side, except if a parameter is omitted (e.g.
-`ham[1 + 1 :]`). It also states that for extended slices, both `:` operators have to
-have the same amount of spacing, except if a parameter is omitted (`ham[1 + 1 ::]`).
-_Black_ enforces these rules consistently.
+`ham[1 + 1 :]`). It recommends no spaces around `:` operators for "simple expressions"
+(`ham[lower:upper]`), and extra space for "complex expressions"
+(`ham[lower : upper + offset]`). _Black_ treats anything more than variable names as
+"complex" (`ham[lower : upper + 1]`). It also states that for extended slices, both `:`
+operators have to have the same amount of spacing, except if a parameter is omitted
+(`ham[1 + 1 ::]`). _Black_ enforces these rules consistently.
 
 This behaviour may raise `E203 whitespace before ':'` warnings in style guide
 enforcement tools like Flake8. Since `E203` is not PEP 8 compliant, you should tell
 
 This behaviour may raise `E203 whitespace before ':'` warnings in style guide
 enforcement tools like Flake8. Since `E203` is not PEP 8 compliant, you should tell
@@ -489,6 +624,47 @@ file that are not enforced yet but might be in a future version of the formatter
 - for arguments that default to `None`, use `Optional[]` explicitly;
 - use `float` instead of `Union[int, float]`.
 
 - for arguments that default to `None`, use `Optional[]` explicitly;
 - use `float` instead of `Union[int, float]`.
 
+## Pragmatism
+
+Early versions of _Black_ used to be absolutist in some respects. They took after its
+initial author. This was fine at the time as it made the implementation simpler and
+there were not many users anyway. Not many edge cases were reported. As a mature tool,
+_Black_ does make some exceptions to rules it otherwise holds. This section documents
+what those exceptions are and why this is the case.
+
+### The magic trailing comma
+
+_Black_ in general does not take existing formatting into account.
+
+However, there are cases where you put a short collection or function call in your code
+but you anticipate it will grow in the future.
+
+For example:
+
+```py3
+TRANSLATIONS = {
+    "en_us": "English (US)",
+    "pl_pl": "polski",
+}
+```
+
+Early versions of _Black_ used to ruthlessly collapse those into one line (it fits!).
+Now, you can communicate that you don't want that by putting a trailing comma in the
+collection yourself. When you do, _Black_ will know to always explode your collection
+into one item per line.
+
+How do you make it stop? Just delete that trailing comma and _Black_ will collapse your
+collection into one line if it fits.
+
+### r"strings" and R"strings"
+
+_Black_ normalizes string quotes as well as string prefixes, making them lowercase. One
+exception to this rule is r-strings. It turns out that the very popular
+[MagicPython](https://github.com/MagicStack/MagicPython/) syntax highlighter, used by
+default by (among others) GitHub and Visual Studio Code, differentiates between
+r-strings and R-strings. The former are syntax highlighted as regular expressions while
+the latter are treated as true raw strings with no special semantics.
+
 ## pyproject.toml
 
 _Black_ is able to read project-specific default values for its command line options
 ## pyproject.toml
 
 _Black_ is able to read project-specific default values for its command line options
@@ -580,8 +756,11 @@ file hierarchy.
 
 ### Emacs
 
 
 ### Emacs
 
-Use [proofit404/blacken](https://github.com/proofit404/blacken) or
-[Elpy](https://github.com/jorgenschaefer/elpy).
+Options include the following:
+
+- [purcell/reformatter.el](https://github.com/purcell/reformatter.el)
+- [proofit404/blacken](https://github.com/proofit404/blacken)
+- [Elpy](https://github.com/jorgenschaefer/elpy).
 
 ### PyCharm/IntelliJ IDEA
 
 
 ### PyCharm/IntelliJ IDEA
 
@@ -607,6 +786,9 @@ $ where black
 %LocalAppData%\Programs\Python\Python36-32\Scripts\black.exe  # possible location
 ```
 
 %LocalAppData%\Programs\Python\Python36-32\Scripts\black.exe  # possible location
 ```
 
+Note that if you are using a virtual environment detected by PyCharm, this is an
+unneeded step. In this case the path to `black` is `$PyInterpreterDirectory$/black`.
+
 3. Open External tools in PyCharm/IntelliJ IDEA
 
 On macOS:
 3. Open External tools in PyCharm/IntelliJ IDEA
 
 On macOS:
@@ -632,7 +814,7 @@ On Windows / Linux / BSD:
 6. Optionally, run _Black_ on every file save:
 
    1. Make sure you have the
 6. Optionally, run _Black_ on every file save:
 
    1. Make sure you have the
-      [File Watcher](https://plugins.jetbrains.com/plugin/7177-file-watchers) plugin
+      [File Watchers](https://plugins.jetbrains.com/plugin/7177-file-watchers) plugin
       installed.
    2. Go to `Preferences or Settings -> Tools -> File Watchers` and click `+` to add a
       new watcher:
       installed.
    2. Go to `Preferences or Settings -> Tools -> File Watchers` and click `+` to add a
       new watcher:
@@ -644,7 +826,7 @@ On Windows / Linux / BSD:
       - Output paths to refresh: `$FilePath$`
       - Working directory: `$ProjectFileDir$`
 
       - Output paths to refresh: `$FilePath$`
       - Working directory: `$ProjectFileDir$`
 
-   - Uncheck "Auto-save edited files to trigger the watcher"
+   - Uncheck "Auto-save edited files to trigger the watcher" in Advanced Options
 
 ### Wing IDE
 
 
 ### Wing IDE
 
@@ -697,7 +879,7 @@ Configuration:
 To install with [vim-plug](https://github.com/junegunn/vim-plug):
 
 ```
 To install with [vim-plug](https://github.com/junegunn/vim-plug):
 
 ```
-Plug 'psf/black'
+Plug 'psf/black', { 'branch': 'stable' }
 ```
 
 or with [Vundle](https://github.com/VundleVim/Vundle.vim):
 ```
 
 or with [Vundle](https://github.com/VundleVim/Vundle.vim):
@@ -706,8 +888,15 @@ or with [Vundle](https://github.com/VundleVim/Vundle.vim):
 Plugin 'psf/black'
 ```
 
 Plugin 'psf/black'
 ```
 
+and execute the following in a terminal:
+
+```console
+$ cd ~/.vim/bundle/black
+$ git checkout origin/stable -b stable
+```
+
 or you can copy the plugin from
 or you can copy the plugin from
-[plugin/black.vim](https://github.com/psf/black/tree/master/plugin/black.vim).
+[plugin/black.vim](https://github.com/psf/black/blob/stable/plugin/black.vim).
 
 ```
 mkdir -p ~/.vim/pack/python/start/black/plugin
 
 ```
 mkdir -p ~/.vim/pack/python/start/black/plugin
@@ -746,6 +935,55 @@ default. On macOS with Homebrew run: `brew install vim`. When building Vim from
 use: `./configure --enable-python3interp=yes`. There's many guides online how to do
 this.
 
 use: `./configure --enable-python3interp=yes`. There's many guides online how to do
 this.
 
+**I get an import error when using _Black_ from a virtual environment**: If you get an
+error message like this:
+
+```text
+Traceback (most recent call last):
+  File "<string>", line 63, in <module>
+  File "/home/gui/.vim/black/lib/python3.7/site-packages/black.py", line 45, in <module>
+    from typed_ast import ast3, ast27
+  File "/home/gui/.vim/black/lib/python3.7/site-packages/typed_ast/ast3.py", line 40, in <module>
+    from typed_ast import _ast3
+ImportError: /home/gui/.vim/black/lib/python3.7/site-packages/typed_ast/_ast3.cpython-37m-x86_64-linux-gnu.so: undefined symbool: PyExc_KeyboardInterrupt
+```
+
+Then you need to install `typed_ast` and `regex` directly from the source code. The
+error happens because `pip` will download [Python wheels](https://pythonwheels.com/) if
+they are available. Python wheels are a new standard of distributing Python packages and
+packages that have Cython and extensions written in C are already compiled, so the
+installation is much more faster. The problem here is that somehow the Python
+environment inside Vim does not match with those already compiled C extensions and these
+kind of errors are the result. Luckily there is an easy fix: installing the packages
+from the source code.
+
+The two packages that cause the problem are:
+
+- [regex](https://pypi.org/project/regex/)
+- [typed-ast](https://pypi.org/project/typed-ast/)
+
+Now remove those two packages:
+
+```console
+$ pip uninstall regex typed-ast -y
+```
+
+And now you can install them with:
+
+```console
+$ pip install --no-binary :all: regex typed-ast
+```
+
+The C extensions will be compiled and now Vim's Python environment will match. Note that
+you need to have the GCC compiler and the Python development files installed (on
+Ubuntu/Debian do `sudo apt-get install build-essential python3-dev`).
+
+If you later want to update _Black_, you should do it like this:
+
+```console
+$ pip install -U black --no-binary regex,typed-ast
+```
+
 ### Visual Studio Code
 
 Use the
 ### Visual Studio Code
 
 Use the
@@ -773,7 +1011,7 @@ Use [python-black](https://atom.io/packages/python-black).
 
 ### Kakoune
 
 
 ### Kakoune
 
-Add the following hook to your kakrc, then run black with `:format`.
+Add the following hook to your kakrc, then run _Black_ with `:format`.
 
 ```
 hook global WinSetOption filetype=python %{
 
 ```
 hook global WinSetOption filetype=python %{
@@ -832,7 +1070,7 @@ Options:
 There is no official blackd client tool (yet!). You can test that blackd is working
 using `curl`:
 
 There is no official blackd client tool (yet!). You can test that blackd is working
 using `curl`:
 
-```
+```sh
 blackd --bind-port 9090 &  # or let blackd choose a port
 curl -s -XPOST "localhost:9090" -d "print('valid')"
 ```
 blackd --bind-port 9090 &  # or let blackd choose a port
 curl -s -XPOST "localhost:9090" -d "print('valid')"
 ```
@@ -881,6 +1119,124 @@ Apart from the above, `blackd` can produce the following response codes:
 The response headers include a `X-Black-Version` header containing the version of
 _Black_.
 
 The response headers include a `X-Black-Version` header containing the version of
 _Black_.
 
+## black-primer
+
+`black-primer` is a tool built for CI (and huumans) to have _Black_ `--check` a number
+of (configured in `primer.json`) Git accessible projects in parallel. _(A PR will be
+accepted to add Mercurial support.)_
+
+### Run flow
+
+- Ensure we have a `black` + `git` in PATH
+- Load projects from `primer.json`
+- Run projects in parallel with `--worker` workers (defaults to CPU count / 2)
+  - Checkout projects
+  - Run black and record result
+  - Clean up repository checkout _(can optionally be disabled via `--keep`)_
+- Display results summary to screen
+- Default to cleaning up `--work-dir` (which defaults to tempfile schemantics)
+- Return
+  - 0 for successful run
+  - < 0 for environment / internal error
+  - > 0 for each project with an error
+
+### Speed up Runs 🏎
+
+If you're running locally yourself to test black on lots of code try:
+
+- Using `-k` / `--keep` + `-w` / `--work-dir` so you don't have to re-checkout the repo
+  each run
+
+### CLI Arguments
+
+```text
+Usage: black-primer [OPTIONS]
+
+  primer - prime projects for blackening... 🏴
+
+Options:
+  -c, --config PATH      JSON config file path  [default: /Users/cooper/repos/
+                         black/src/black_primer/primer.json]
+
+  --debug                Turn on debug logging  [default: False]
+  -k, --keep             Keep workdir + repos post run  [default: False]
+  -L, --long-checkouts   Pull big projects to test  [default: False]
+  -R, --rebase           Rebase project if already checked out  [default:
+                         False]
+
+  -w, --workdir PATH     Directory Path for repo checkouts  [default: /var/fol
+                         ders/tc/hbwxh76j1hn6gqjd2n2sjn4j9k1glp/T/primer.20200
+                         517125229]
+
+  -W, --workers INTEGER  Number of parallel worker coroutines  [default: 69]
+  -h, --help             Show this message and exit.
+```
+
+### primer config file
+
+The config is JSON format. Its main element is the `"projects"` dictionary. Below
+explains each parameter:
+
+```json
+{
+  "projects": {
+    "00_Example": {
+      "cli_arguments": "List of extra CLI arguments to pass Black for this project",
+      "expect_formatting_changes": "Boolean to indicate that the version of Black is expected to cause changes",
+      "git_clone_url": "URL you would pass `git clone` to check out this repo",
+      "long_checkout": "Boolean to have repo skipped by defauult unless `--long-checkouts` is specified",
+      "py_versions": "List of major Python versions to run this project with - all will do as you'd expect - run on ALL versions"
+    },
+    "aioexabgp": {
+      "cli_arguments": [],
+      "expect_formatting_changes": true,
+      "git_clone_url": "https://github.com/cooperlees/aioexabgp.git",
+      "long_checkout": false,
+      "py_versions": ["all", "3.8"] // "all" ignores all other versions
+    }
+  }
+}
+```
+
+### Example run
+
+```console
+cooper-mbp:black cooper$ ~/venvs/b/bin/black-primer
+[2020-05-17 13:06:40,830] INFO: 4 projects to run Black over (lib.py:270)
+[2020-05-17 13:06:44,215] INFO: Analyzing results (lib.py:285)
+-- primer results 📊 --
+
+3 / 4 succeeded (75.0%) ✅
+1 / 4 FAILED (25.0%) 💩
+ - 0 projects disabled by config
+ - 0 projects skipped due to Python version
+ - 0 skipped due to long checkout
+
+Failed projects:
+
+### flake8-bugbear:
+ - Returned 1
+ - stdout:
+--- tests/b303_b304.py 2020-05-17 20:04:09.991227 +0000
++++ tests/b303_b304.py 2020-05-17 20:06:42.753851 +0000
+@@ -26,11 +26,11 @@
+     maxint = 5  # this is okay
+     # the following shouldn't crash
+     (a, b, c) = list(range(3))
+     # it's different than this
+     a, b, c = list(range(3))
+-    a, b, c, = list(range(3))
++    a, b, c = list(range(3))
+     # and different than this
+     (a, b), c = list(range(3))
+     a, *b, c = [1, 2, 3, 4, 5]
+     b[1:3] = [0, 0]
+
+would reformat tests/b303_b304.py
+Oh no! 💥 💔 💥
+1 file would be reformatted, 22 files would be left unchanged.
+```
+
 ## Version control integration
 
 Use [pre-commit](https://pre-commit.com/). Once you
 ## Version control integration
 
 Use [pre-commit](https://pre-commit.com/). Once you
@@ -905,7 +1261,7 @@ for your project. See _Black_'s own
 example.
 
 If you're already using Python 3.7, switch the `language_version` accordingly. Finally,
 example.
 
 If you're already using Python 3.7, switch the `language_version` accordingly. Finally,
-`stable` is a tag that is pinned to the latest release on PyPI. If you'd rather run on
+`stable` is a branch that tracks the latest release on PyPI. If you'd rather run on
 master, this is also an option.
 
 ## Ignoring unmodified files
 master, this is also an option.
 
 ## Ignoring unmodified files
@@ -934,8 +1290,10 @@ then write the above files to `.cache/black/<version>/`.
 
 The following notable open-source projects trust _Black_ with enforcing a consistent
 code style: pytest, tox, Pyramid, Django Channels, Hypothesis, attrs, SQLAlchemy,
 
 The following notable open-source projects trust _Black_ with enforcing a consistent
 code style: pytest, tox, Pyramid, Django Channels, Hypothesis, attrs, SQLAlchemy,
-Poetry, PyPA applications (Warehouse, Pipenv, virtualenv), pandas, Pillow, every Datadog
-Agent Integration, Home Assistant.
+Poetry, PyPA applications (Warehouse, Bandersnatch, Pipenv, virtualenv), pandas, Pillow,
+every Datadog Agent Integration, Home Assistant.
+
+The following organizations use _Black_: Facebook, Dropbox.
 
 Are we missing anyone? Let us know.
 
 
 Are we missing anyone? Let us know.
 
@@ -994,7 +1352,14 @@ other hand, if your answer is "because I don't like a particular formatting" the
 not ready to embrace _Black_ yet. Such changes are unlikely to get accepted. You can
 still try but prepare to be disappointed.
 
 not ready to embrace _Black_ yet. Such changes are unlikely to get accepted. You can
 still try but prepare to be disappointed.
 
-More details can be found in [CONTRIBUTING](CONTRIBUTING.md).
+More details can be found in
+[CONTRIBUTING](https://github.com/psf/black/blob/master/CONTRIBUTING.md).
+
+## Change Log
+
+The log's become rather long. It moved to its own file.
+
+See [CHANGES](https://github.com/psf/black/blob/master/CHANGES.md).
 
 ## Authors
 
 
 ## Authors
 
@@ -1003,12 +1368,13 @@ Glued together by [Łukasz Langa](mailto:lukasz@langa.pl).
 Maintained with [Carol Willing](mailto:carolcode@willingconsulting.com),
 [Carl Meyer](mailto:carl@oddbird.net),
 [Jelle Zijlstra](mailto:jelle.zijlstra@gmail.com),
 Maintained with [Carol Willing](mailto:carolcode@willingconsulting.com),
 [Carl Meyer](mailto:carl@oddbird.net),
 [Jelle Zijlstra](mailto:jelle.zijlstra@gmail.com),
-[Mika Naylor](mailto:mail@autophagy.io), and
-[Zsolt Dollenstein](mailto:zsol.zsol@gmail.com).
+[Mika Naylor](mailto:mail@autophagy.io),
+[Zsolt Dollenstein](mailto:zsol.zsol@gmail.com), and
+[Cooper Lees](mailto:me@cooperlees.com).
 
 Multiple contributions by:
 
 
 Multiple contributions by:
 
-- [Abdur-Rahmaan Janhangeer](mailto:cryptolabour@gmail.com)
+- [Abdur-Rahmaan Janhangeer](mailto:arj.python@gmail.com)
 - [Adam Johnson](mailto:me@adamj.eu)
 - [Alexander Huynh](mailto:github@grande.coffee)
 - [Andrew Thorp](mailto:andrew.thorp.dev@gmail.com)
 - [Adam Johnson](mailto:me@adamj.eu)
 - [Alexander Huynh](mailto:github@grande.coffee)
 - [Andrew Thorp](mailto:andrew.thorp.dev@gmail.com)