Black: Is --target-version the minimum or should all be explicitly listed?

Created on 14 Mar 2019  路  8Comments  路  Source: psf/black

With old Black 18.9b0, I had this in pyproject.toml:

[tool.black]
py36 = true

The new Black 19.3b0 warns:

--py36 is deprecated and will be removed in a future version. Use --target-version py36 instead.

The docs say:

  -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]

I see Black's own pyproject.toml includes:

toml [tool.black] target_version = ['py36', 'py37', 'py38']

If I target just py36, does it treat that as a minimum?

Is that the same as ['py36', 'py37', 'py38']?

It recommended to explicitly list all the targetted versions?

command line

Most helpful comment

I'm also curious why we need the upper bound. In practice, 3.5-3.8 is currently the same as just 3.5. What sort of theoretical cases are there where it'd be different?

In theory, a new version of Python could change the syntax such that a kind of formatting that Black thinks is ideal is no longer supported. As a hypothetical example, maybe Python 3.9 will decide that all string prefixes have to be uppercase, so f"{x}" will be SyntaxError and only F"{x}" will be legal. In that case, if you set target_version to 3.5-3.8, we'd still emit f"{x}" (because Black's style prefers lowercase string prefixes), but with 3.5-3.9 we'd have to emit F"{x}".

In practice that sort of scenario doesn't seem terribly likely, so I'd be OK with making target_version just a minimum requirement.

All 8 comments

You should include all Python versions that you want your code to run under. In practice, though, 3.6 through 3.8 are currently the same as far as Black is concerned, so either variant will do the same.

Let us know if you think the docs can be improved.

Jelle, I get that certain edge cases in the grammar are only available in the newer versions, so we need the lower bound. Why do we need the upper bound, too?

FWIW I just had to look into black's source cod too, to figure out how to set target-version.

From the docs it's unclear that it takes multiple versions and reusing --target-version=py36 as target-version=py36 fails with confusing errors.

I think it's fine to allow supplying a range (although I'd prefer something like py27...py38 or py37... that conveys the meaning better), but the docs don't reflect that currently.

Another confusion.

Let's say I support Python 3.5-3.8 so have this in pyproject.toml:

[tool.black]
target_version = ['py35', 'py36', 'py37', 'py38']

If I don't have this config file and want to do the same thing directly on the command line, do I need to repeat each argument?

$ black --target-version py35 --target-version py36 --target-version py37 --target-version py38 .

And then would .pre-commit.yaml need to look like this?

repos:
  - repo: https://github.com/psf/black
    rev: 19.10b0
    hooks:
      - id: black
        args: ["--target-version", "py35", "--target-version", "py36", "--target-version", "py37", "--target-version", "py38"]

These are pretty long, and it'd be nice to have a shorter range argument (or just a single lower bound).


I'm also curious why we need the upper bound. In practice, 3.5-3.8 is currently the same as just 3.5. What sort of theoretical cases are there where it'd be different?

Thanks!

I'm also curious why we need the upper bound. In practice, 3.5-3.8 is currently the same as just 3.5. What sort of theoretical cases are there where it'd be different?

In theory, a new version of Python could change the syntax such that a kind of formatting that Black thinks is ideal is no longer supported. As a hypothetical example, maybe Python 3.9 will decide that all string prefixes have to be uppercase, so f"{x}" will be SyntaxError and only F"{x}" will be legal. In that case, if you set target_version to 3.5-3.8, we'd still emit f"{x}" (because Black's style prefers lowercase string prefixes), but with 3.5-3.9 we'd have to emit F"{x}".

In practice that sort of scenario doesn't seem terribly likely, so I'd be OK with making target_version just a minimum requirement.

In practice that sort of scenario doesn't seem terribly likely, so I'd be OK with making target_version just a minimum requirement.

I was very surprised to discover it wasn't already a minimum requirement, and that only happened when I stumbled across this issue!

FWIW I think making forward-compatibilty the easy option is also better for the ecosystem :smile:

At the same time I agree that it should almost certainly be 3.6+, 3.7+, 3.8+, and so on. But Jelle's got a point about possible syntax breaking changes in the future. I'm not sure if we should make this change.

I'd hope the answer is "Python 2 taught us not to make breaking changes to the syntax" - and if we do, adding an optional --maximum-version argument will be the least of the problems dumped on the library ecosystem.

Was this page helpful?
0 / 5 - 0 ratings