X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/dafa12f10b8ee71f6676d06a2c155f6c4a55cef2..65f0ea61599dc6d2be95ee961c42a55247130c49:/README.md?ds=inline diff --git a/README.md b/README.md index 475954f..ed9f105 100644 --- a/README.md +++ b/README.md @@ -1,586 +1,481 @@ -![Black Logo](https://raw.githubusercontent.com/ambv/black/master/docs/_static/logo2-readme.png) +![Black Logo](https://raw.githubusercontent.com/psf/black/master/docs/_static/logo2-readme.png) +
- - - - - - + + + + + + + + + +
> âAny color you like.â +_Black_ is the uncompromising Python code formatter. By using it, you agree to cede +control over minutiae of hand-formatting. In return, _Black_ gives you speed, +determinism, and freedom from `pycodestyle` nagging about formatting. You will save time +and mental energy for more important matters. + +Blackened code looks the same regardless of the project you're reading. Formatting +becomes transparent after a while and you can focus on the content instead. + +_Black_ makes code review faster by producing the smallest diffs possible. -*Black* is the uncompromising Python code formatter. By using it, you -agree to cede control over minutiae of hand-formatting. In return, -*Black* gives you speed, determinism, and freedom from `pycodestyle` -nagging about formatting. You will save time and mental energy for -more important matters. +Try it out now using the [Black Playground](https://black.now.sh). Watch the +[PyCon 2019 talk](https://youtu.be/esZLCuWs_2Y) to learn more. -Blackened code looks the same regardless of the project you're reading. -Formatting becomes transparent after a while and you can focus on the -content instead. +--- -*Black* makes code review faster by producing the smallest diffs -possible. +_Contents:_ **[Installation and usage](#installation-and-usage)** | +**[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)** | +**[GitHub Actions](#github-actions)** | +**[Ignoring unmodified files](#ignoring-unmodified-files)** | **[Used by](#used-by)** | +**[Testimonials](#testimonials)** | **[Show your style](#show-your-style)** | +**[Contributing](#contributing-to-black)** | **[Change log](#change-log)** | +**[Authors](#authors)** +--- -## Installation and Usage +## Installation and usage ### Installation -*Black* can be installed by running `pip install black`. It requires -Python 3.6.0+ to run but you can reformat Python 2 code with it, too. +_Black_ can be installed by running `pip install black`. It requires Python 3.6.2+ to +run. If you want to format Python 2 code as well, install with +`pip install black[python2]`. + +#### Install from GitHub + +If you can't wait for the latest _hotness_ and want to install from GitHub, use: +`pip install git+git://github.com/psf/black` ### Usage To get started right away with sensible defaults: -``` +```sh black {source_file_or_directory} ``` -### Command line options - -Black doesn't provide many options. You can list them by running -`black --help`: - -```text -black [OPTIONS] [SRC]... +You can run _Black_ as a package if running it as a script doesn't work: -Options: - -l, --line-length INTEGER Where to wrap around. [default: 88] - --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 there was an - internal error. - --diff Don't write the files back, just output a diff - for each file on stdout. - --fast / --safe If --fast given, skip temporary sanity checks. - [default: --safe] - -q, --quiet Don't emit non-error messages to stderr. Errors - are still emitted, silence those with - 2>/dev/null. - --version Show the version and exit. - --help Show this message and exit. +```sh +python -m black {source_file_or_directory} ``` -*Black* is a well-behaved Unix-style command-line tool: -* it does nothing if no sources are passed to it; -* it will read from standard input and write to standard output if `-` - is used as the filename; -* it only outputs messages to users on standard error; -* exits with code 0 unless an internal error occurred (or `--check` was - used). - +### Command line options -### NOTE: This is an early pre-release +_Black_ doesn't provide many options. You can list them by running `black --help`: -*Black* can already successfully format itself and the standard library. -It also sports a decent test suite. However, it is still very new. -Things will probably be wonky for a while. This is made explicit by the -"Alpha" trove classifier, as well as by the "a" in the version number. -What this means for you is that **until the formatter becomes stable, -you should expect some formatting to change in the future**. +```text +Usage: black [OPTIONS] [SRC]... -Also, as a temporary safety measure, *Black* will check that the -reformatted code still produces a valid AST that is equivalent to the -original. This slows it down. If you're feeling confident, use -``--fast``. + 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] + + -t, --target-version [py27|py33|py34|py35|py36|py37|py38|py39] + Python versions that should be supported by + Black's output. [default: per-file auto- + detection] + + --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. + -C, --skip-magic-trailing-comma + Don't use trailing commas as a reason to + split lines. + + --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 + there was an internal error. + + --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] + + --include TEXT A regular expression that matches files and + directories that should be included on + recursive searches. An empty value means + all files are included regardless of the + name. Use forward slashes for directories + 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 + paths are excluded. Use forward slashes for + directories on all platforms (Windows, too). + Exclusions are calculated first, inclusions + later. [default: /(\.direnv|\.eggs|\.git|\. + hg|\.mypy_cache|\.nox|\.tox|\.venv|venv|\.sv + n|_build|buck-out|build|dist)/] + + --extend-exclude TEXT Like --exclude, but adds additional files + and directories on top of the excluded + ones (useful if you simply want to add to + the default). + + --force-exclude TEXT Like --exclude, but files and directories + matching this regex will be excluded even + when they are passed explicitly as + arguments. + + + --stdin-filename TEXT The name of the file when passing it through + stdin. Useful to make sure Black will + respect --force-exclude option on some + editors that rely on using stdin. + + -q, --quiet Don't emit non-error messages to stderr. + Errors are still emitted; silence those with + 2>/dev/null. + + -v, --verbose Also emit messages to stderr about files + that were not changed or were ignored due to + exclusion patterns. + + --version Show the version and exit. + --config FILE Read configuration from FILE path. + -h, --help Show this message and exit. +``` -## The *Black* code style +_Black_ is a well-behaved Unix-style command-line tool: -*Black* reformats entire files in place. It is not configurable. It -doesn't take previous formatting into account. It doesn't reformat -blocks that start with `# fmt: off` and end with `# fmt: on`. It also -recognizes [YAPF](https://github.com/google/yapf)'s block comments to -the same effect, as a courtesy for straddling code. +- it does nothing if no sources are passed to it; +- it will read from standard input and write to standard output if `-` is used as the + filename; +- 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 -### How *Black* wraps lines +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. -*Black* ignores previous formatting and applies uniform horizontal -and vertical whitespace to your code. The rules for horizontal -whitespace can be summarized as: do whatever makes `pycodestyle` happy. -The coding style used by *Black* can be viewed as a strict subset of -PEP 8. +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#black-compatible-configurations). -As for vertical whitespace, *Black* tries to render one full expression -or simple statement per line. If this fits the allotted line length, -great. -```py3 -# in: +### Migrating your code style without ruining git blame -l = [1, - 2, - 3, -] +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. -# out: +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. -l = [1, 2, 3] ``` - -If not, *Black* will look at the contents of the first outer matching -brackets and put that in a separate indented line. -```py3 -# in: - -l = [[n for n in list_bosses()], [n for n in list_employees()]] - -# out: - -l = [ - [n for n in list_bosses()], [n for n in list_employees()] -] +# Migrate code style to Black +5b4ab991dede475d393e9d69ec388fd6bd949699 ``` -If that still doesn't fit the bill, it will decompose the internal -expression further using the same rule, indenting matching brackets -every time. If the contents of the matching brackets pair are -comma-separated (like an argument list, or a dict literal, and so on) -then *Black* will first try to keep them on the same line with the -matching brackets. If that doesn't work, it will put all of them in -separate lines. -```py3 -# in: - -def very_important_function(template: str, *variables, file: os.PathLike, debug: bool = False): - """Applies `variables` to the `template` and writes to `file`.""" - with open(file, 'w') as f: - ... - -# out: - -def very_important_function( - template: str, - *variables, - file: os.PathLike, - debug: bool = False, -): - """Applies `variables` to the `template` and writes to `file`.""" - with open(file, "w") as f: - ... -``` +Afterwards, you can pass that file to `git blame` and see clean and meaningful blame +information. -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 clear delimiter -between two distinct sections of the code that otherwise share the same -indentation level (like the arguments list and the docstring in the -example above). - -If a line of "from" imports cannot fit in the allotted length, it's always split -into one per line. Imports tend to change often and this minimizes diffs, as well -as enables readers of code to easily find which commit introduced a particular -import. This exception also makes *Black* compatible with -[isort](https://pypi.org/p/isort/). Use `multi_line_output=3`, -`include_trailing_comma=True`, `force_grid_wrap=0`, and `line_length=88` in your -isort config. - - -### Line length - -You probably noticed the peculiar default line length. *Black* defaults -to 88 characters per line, which happens to be 10% over 80. This number -was found to produce significantly shorter files than sticking with 80 -(the most popular), or even 79 (used by the standard library). In -general, [90-ish seems like the wise choice](https://youtu.be/wf-BqAjZb8M?t=260). - -If you're paid by the line of code you write, you can pass -`--line-length` with a lower number. *Black* will try to respect that. -However, sometimes it won't be able to without breaking other rules. In -those rare cases, auto-formatted code will exceed your allotted limit. - -You can also increase it, but remember that people with sight disabilities -find it harder to work with line lengths exceeding 100 characters. -It also adversely affects side-by-side diff review on typical screen -resolutions. Long lines also make it harder to present code neatly -in documentation or talk slides. - -If you're using Flake8, you can bump `max-line-length` to 88 and forget -about it. Alternatively, use [Bugbear](https://github.com/PyCQA/flake8-bugbear)'s -B950 warning instead of E501 and keep the max line length at 80 which -you are probably already using. You'd do it like this: -```ini -[flake8] -max-line-length = 80 -... -select = C,E,F,W,B,B950 -ignore = E501 +```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'll find *Black*'s own .flake8 config file is configured like this. -If you're curious about the reasoning behind B950, Bugbear's documentation -explains it. The tl;dr is "it's like highway speed limits, we won't -bother you if you overdo it by a few km/h". - - -### Empty lines - -*Black* avoids spurious vertical whitespace. This is in the spirit of -PEP 8 which says that in-function vertical whitespace should only be -used sparingly. - -*Black* will allow single empty lines inside functions, and single and -double empty lines on module level left by the original editors, except -when they're within parenthesized expressions. Since such expressions -are always reformatted to fit minimal space, this whitespace is lost. +You can even configure `git` to automatically ignore revisions listed in a file on every +call to `git blame`. -It will also insert proper spacing before and after function definitions. -It's one line before and after inner functions and two lines before and -after module-level functions. *Black* will not put empty lines between -function/class definitions and standalone comments that immediately precede -the given function/class. +```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!) -### Trailing commas +### NOTE: This is a beta product -*Black* will add trailing commas to expressions that are split -by comma where each element is on its own line. This includes function -signatures. +_Black_ is already [successfully used](https://github.com/psf/black#used-by) by many +projects, small and big. It also sports a decent test suite. However, it is still very +new. Things will probably be wonky for a while. This is made explicit by the "Beta" +trove classifier, as well as by the "b" in the version number. What this means for you +is that **until the formatter becomes stable, you should expect some formatting to +change in the future**. That being said, no drastic stylistic changes are planned, +mostly responses to bug reports. -Unnecessary trailing commas are removed if an expression fits in one -line. This makes it 1% more likely that your line won't exceed the -allotted line length limit. Moreover, in this scenario, if you added -another argument to your call, you'd probably fit it in the same line -anyway. That doesn't make diffs any larger. - -One exception to removing trailing commas is tuple expressions with -just one element. In this case *Black* won't touch the single trailing -comma as this would unexpectedly change the underlying data type. Note -that this is also the case when commas are used while indexing. This is -a tuple in disguise: ```numpy_array[3, ]```. - -One exception to adding trailing commas is function signatures -containing `*`, `*args`, or `**kwargs`. In this case a trailing comma -is only safe to use on Python 3.6. *Black* will detect if your file is -already 3.6+ only and use trailing commas in this situation. If you -wonder how it knows, it looks for f-strings and existing use of trailing -commas in function signatures that have stars in them. In other words, -if you'd like a trailing comma in this situation and *Black* didn't -recognize it was safe to do so, put it there manually and *Black* will -keep it. - - -### Strings - -*Black* prefers double quotes (`"` and `"""`) over single quotes (`'` -and `'''`). It will replace the latter with the former as long as it -does not result in more backslash escapes than before. - -*Black* also standardizes string prefixes, making them always lowercase. -On top of that, if your code is already Python 3.6+ only or it's using -the `unicode_literals` future import, *Black* will remove `u` from the -string prefix as it is meaningless in those scenarios. - -The main reason to standardize on a single form of quotes is aesthetics. -Having one kind of quotes everywhere reduces reader distraction. -It will also enable a future version of *Black* to merge consecutive -string literals that ended up on the same line (see -[#26](https://github.com/ambv/black/issues/26) for details). - -Why settle on double quotes? They anticipate apostrophes in English -text. They match the docstring standard described in PEP 257. An -empty string in double quotes (`""`) is impossible to confuse with -a one double-quote regardless of fonts and syntax highlighting used. -On top of this, double quotes for strings are consistent with C which -Python interacts a lot with. - -On certain keyboard layouts like US English, typing single quotes is -a bit easier than double quotes. The latter requires use of the Shift -key. My recommendation here is to keep using whatever is faster to type -and let *Black* handle the transformation. - - -### Line Breaks & Binary Operators - -*Black* will break a line before a binary operator when splitting a block -of code over multiple lines. This is so that *Black* is compliant with the -recent changes in the [PEP 8](https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator) -style guide, which emphasizes that this approach improves readability. - -This behaviour may raise ``W503 line break before binary operator`` warnings in -style guide enforcement tools like Flake8. Since ``W503`` is not PEP 8 compliant, -you should tell Flake8 to ignore these warnings. - - -### Slices - -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. ``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. - -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 Flake8 to ignore these warnings. - - -### Parentheses - -Some parentheses are optional in the Python grammar. Any expression can -be wrapped in a pair of parentheses to form an atom. There are a few -interesting cases: - -- `if (...):` -- `while (...):` -- `for (...) in (...):` -- `assert (...), (...)` -- `from X import (...)` -- assignments like: - - `target = (...)` - - `target: type = (...)` - - `some, *un, packing = (...)` - - `augmented += (...)` - -In those cases, parentheses are removed when the entire statement fits -in one line, or if the inner expression doesn't have any delimiters to -further split on. If there is only a single delimiter and the expression -starts or ends with a bracket, the parenthesis can also be successfully -omitted since the existing bracket pair will organize the expression -neatly anyway. Otherwise, the parentheses are added. - -Please note that *Black* does not add or remove any additional nested -parentheses that you might want to have for clarity or further -code organization. For example those parentheses are not going to be -removed: -```py3 -return not (this or that) -decision = (maybe.this() and values > 0) or (maybe.that() and values < 0) -``` +Also, as a temporary safety measure, _Black_ will check that the reformatted code still +produces a valid AST that is equivalent to the original. This slows it down. If you're +feeling confident, use `--fast`. +## The _Black_ code style -### Call chains - -Some popular APIs, like ORMs, use call chaining. This API style is known -as a [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface). -*Black* formats those treating dots that follow a call or an indexing -operation like a very low priority delimiter. It's easier to show the -behavior than to explain it. Look at the example: -```py3 -def example(session): - result = ( - session.query(models.Customer.id) - .filter( - models.Customer.account_id == account_id, - models.Customer.email == email_address, - ) - .order_by(models.Customer.id.asc()) - .all() - ) -``` +_Black_ is a PEP 8 compliant opinionated formatter. _Black_ reformats entire files in +place. It is not configurable. It doesn't take previous formatting into account. Your +main option of configuring _Black_ is that it doesn't reformat blocks that start with +`# fmt: off` and end with `# fmt: on`, or lines that ends with `# fmt: skip`. Pay +attention that `# fmt: on/off` have to be on the same level of indentation. To learn +more about _Black_'s opinions, to go +[the_black_code_style](https://github.com/psf/black/blob/master/docs/the_black_code_style.md). +Please refer to this document before submitting an issue. What seems like a bug might be +intended behaviour. -### Typing stub files - -PEP 484 describes the syntax for type hints in Python. One of the -use cases for typing is providing type annotations for modules which -cannot contain them directly (they might be written in C, or they might -be third-party, or their implementation may be overly dynamic, and so on). - -To solve this, [stub files with the `.pyi` file -extension](https://www.python.org/dev/peps/pep-0484/#stub-files) can be -used to describe typing information for an external module. Those stub -files omit the implementation of classes and functions they -describe, instead they only contain the structure of the file (listing -globals, functions, and classes with their members). The recommended -code style for those files is more terse than PEP 8: - -* prefer `...` on the same line as the class/function signature; -* avoid vertical whitespace between consecutive module-level functions, - names, or methods and fields within a single class; -* use a single blank line between top-level class definitions, or none - if the classes are very small. - -*Black* enforces the above rules. There are additional guidelines for -formatting `.pyi` file that are not enforced yet but might be in -a future version of the formatter: - -* all function bodies should be empty (contain `...` instead of the body); -* do not use docstrings; -* prefer `...` over `pass`; -* for arguments with a default, use `...` instead of the actual default; -* avoid using string literals in type annotations, stub files support - forward references natively (like Python 3.7 code with `from __future__ - import annotations`); -* use variable annotations instead of type comments, even for stubs that - target older versions of Python; -* 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](https://github.com/psf/black/blob/master/docs/the_black_code_style.md#pragmatism) +of `the_black_code_style` describes what those exceptions are and why this is the case. -## Editor integration - -### Emacs +Please refer to this document before submitting an issue just like with the document +above. What seems like a bug might be intended behaviour. -Use [proofit404/blacken](https://github.com/proofit404/blacken). +## pyproject.toml +_Black_ is able to read project-specific default values for its command line options +from a `pyproject.toml` file. This is especially useful for specifying custom +`--include` and `--exclude`/`--extend-exclude` patterns for your project. -### PyCharm +**Pro-tip**: If you're asking yourself "Do I need to configure anything?" the answer is +"No". _Black_ is all about sensible defaults. -1. Install `black`. +### What on Earth is a `pyproject.toml` file? - $ pip install black +[PEP 518](https://www.python.org/dev/peps/pep-0518/) defines `pyproject.toml` as a +configuration file to store build system requirements for Python projects. With the help +of tools like [Poetry](https://python-poetry.org/) or +[Flit](https://flit.readthedocs.io/en/latest/) it can fully replace the need for +`setup.py` and `setup.cfg` files. -2. Locate your `black` installation folder. +### Where _Black_ looks for the file - On MacOS / Linux / BSD: +By default _Black_ looks for `pyproject.toml` starting from the common base directory of +all files and directories passed on the command line. If it's not there, it looks in +parent directories. It stops looking when it finds the file, or a `.git` directory, or a +`.hg` directory, or the root of the file system, whichever comes first. - $ which black - /usr/local/bin/black # possible location +If you're formatting standard input, _Black_ will look for configuration starting from +the current working directory. - On Windows: +You can use a "global" configuration, stored in a specific location in your home +directory. This will be used as a fallback configuration, that is, it will be used if +and only if _Black_ doesn't find any configuration as mentioned above. Depending on your +operating system, this configuration file should be stored as: - $ where black - %LocalAppData%\Programs\Python\Python36-32\Scripts\black.exe # possible location +- Windows: `~\.black` +- Unix-like (Linux, MacOS, etc.): `$XDG_CONFIG_HOME/black` (`~/.config/black` if the + `XDG_CONFIG_HOME` environment variable is not set) -3. Open External tools in PyCharm with `File -> Settings -> Tools -> External Tools`. +Note that these are paths to the TOML file itself (meaning that they shouldn't be named +as `pyproject.toml`), not directories where you store the configuration. Here, `~` +refers to the path to your home directory. On Windows, this will be something like +`C:\\Users\UserName`. -4. Click the + icon to add a new external tool with the following values: - - Name: Black - - Description: Black is the uncompromising Python code formatter. - - Program:pyproject.toml