Black, the uncompromising Python code formatter, is stable
pypi.org
pypi.org
Change log: https://black.readthedocs.io/en/latest/change_log.html
Going forward we'll follow our stability policy (https://black.readthedocs.io/en/latest/the_black_code_style/...).
Work continues as usual with bugfixes and enhancements, but style changes are now introduced under our new `--preview` CLI switch. This allows us to evolve Black's style without too much disruption to users that want consistency. The default style is updated yearly.
Thanks to our maintainers for orchestrating the efforts, especially to our most recent reinforcement Batuhan (@isidentical) who was responsible for our match statement support! A hearty thank you to all of our contributors for pushing Black forward, and to our users for being the reason we do it!
That said, I'm a little sad to see it's gone stable without adding support for tabs, which would be extremely simple to add at this point (cf. https://github.com/jleclanche/tan/commit/e23c038167528bdacdd...). I have a lot of people using this tab-capable fork, that I did not advertise anywhere.
Łukasz seems to have a personal grudge against tabs which may be why the issue for tab support was closed early on, but there's a plethora of good reasons to support it behind a flag. I don't want to rehash those arguments here on HN but you think you could re-think the approach a bit?
I'd be happy to do a PR if it's not getting rejected right away with "no discussion allowed" like the last one was (before Black was moved to PSF maintainership).
Prettier works the exact same way and does have --use-tabs as a parameter. Nobody died. No codebase ended up with mixed tabs and spaces from it. Codebases either do --use-tabs or don't.
Like I said, there are a lot of reasons to allow for this. For one thing, tabs are an accessibility feature, but also it's impossible to use Black in an environment that prefers tabs.
Whereas there's no such thing as "an environment that prefers exactly two spaces after every comma inside tuples", thus you don't need an option for this.
>Yet the more options Prettier has, the further from the above goal it gets. The debates over styles just turn into debates over which Prettier options to use. Formatting wars break out with renewed vigour: “Which option values are better? Why? Did we make the right choices?”
>And it’s not the only cost options have. To learn more about their downsides, see the issue about resisting adding configuration, which has more s than any option request issue.
>So why are there any options at all?
>A few were added during Prettier’s infancy to make it take off at all. >A couple were added after “great demand.” >Some were added for compatibility reasons.
To be sure, I personally would have preferred that 2-spaces win out for compatibility with the Javascript ecosystem (so I am perhaps the furthest from the parent poster on the tabs-spaces spectrum!) but I abandoned my preference in favor of PEP-8 years ago, and doing so has opened far more doors for team productivity than it's closed.
It's not useful to the ecosystem because those projects not actually using Black and unable to make the switch end up in a worse scenario (hence the fork which at least fixes this). Nobody wins, here; at best, you're unaffected.
Again I invite you to look at Prettier which has had as much of an impact (if not more) on the JS ecosystem as Black did on Python, but does support tab indent (and is opinionated regardless).
Key quote: --arrow-parens, --jsx-single-quote, --bracket-same-line and --no-bracket-spacing are not the type of options we’re happy to have.
That's because these are entirely stylistic choices. Tab support is a mechanical one. Worth mentioning as well that Prettier supports multiple languages and tab/spaces is a global option, whereas all of these are very language-specific.
My personal preference is tabs for indentation, spaces for alignment. The reason for this is the customizability that comes with tabs instead of spaces. Any editor worth using for coding has an easily configurable tab stop that you can set to your desired space count. With tabs and proper editor configs, everyone can be happy with how their code looks while remaining absolutely identical with no tools reformatting on checkout or commit (as I've sometimes seen).
For a long time, I was in the 4-space indentation camp. These days, I prefer 2. The reality is, though, I use whatever the codebase I'm working on has as "standard".
An editor plugin for this wouldn't even have to be syntax-aware, except for some rare cases where you are using spaces to nicely align a multiline string.
I know it’s very far from the biggest problem in the world but this does make me chuckle a little.
In the olden days, with fixed width fonts on an 80x24 terminal, I think I read somewhere that 3 spaces was optimal (fewest bugs); but that programmers have an aversion to non-multiples of 2. That is why you see 2- or 4-spaces, but not 3. (I think...)
It's nice the broader Python community generally agrees with PEP 8 but it's always a little weird to see it referenced as an authority on styling user code when it is not it's intention and does not claim to be.
And pylint seems to keep adding style checks that I don't like and have to disable.
But the main principle I do agree with is to strive for consistent style within a code base.
In the spirit of dev/user freedom, the creator has every right to enforce a standard, regardless of its basis - even if arbitrary - but I find it a little creepy. Then again, the prevailing usage of “opinionated” in dev circles was new to me, as well. What ever happened to design around maximum flexibility AND feature coverage?
Are developers more likely to be “opinionated” in their work if the predominant digital culture of their early career was rewarding of evangelism via self-promotion? Or grew up in an educational era that promoted activism? Are these sorts of issues more common in smaller / person-driven teams vs. corporate behemoths?
e.g., if VS Code were a one-person show vs. a corporate effort, would we risk seeing changelogs like “Insiders 2.20 - lead Architect and Face of the Product removes plug-ins starting with vowels, “because they lacked cohesion and product-centered aesthetics. They looked poopy in list format with most fonts.”
Absurd, to be sure, but what if these decisions don’t step on obvious toes? The average supporter is more likely to tolerate slightly warmer water than hop into another pot, right? And if you stayed in the pot through several degree increases, you’ll feel a sense of Boiling Frog Belonging (TM).
And if you credited the original dictatorial decision for this emergent sense of community, you’d be very much correct.
I’ve been writing Python code for two decades. I know all the arguments for tabs vs spaces.
Down the path of tabs lies madness.
If you want them that badly, please see git’s smudge/clean filters.
https://stackoverflow.com/questions/2316677/can-git-automati...
There. Now the Python world has a single standard while you are free to use tabs in your checkout. See, you can make all the people happy all the time. :-)
There's extremely clear demand, I didn't just add a random flag to control how much space should be around parentheses. Switching an existing codebase using tabs to spaces is not always feasible.
That said, TIL about a lot of what's in your link, but it looks like a completely inappropriate solution, I think you can agree.
Black encourages the Python ecosystem to settle on spaces. There should be some friction involved (more than a switch) to use tabs, otherwise we're likely to see new code using tabs too.
$0.02 and all that.
Tab codebases are PEP8 compliant. It merely says spaces are "preferred". What it disallows is mixing the two. What it also says is to use tabs if the codebase uses tabs, which I can't do with Black; how about that.
Incidentally, PEP8 takes a much stronger stance on line length, says they should be no more than 79 characters, and Black has enough sense not to respect that by default (and... offer an option, because line length, much like tabs for indent, is an accessibility feature).
Wait I’m not. As much as I dislike double quotes, if they add an option every time someone is a little sad, we’re just going back to square one. I don’t want to debate styles anymore, ever, and I’m willing to give up my own aesthetics for that.
These 'opinionated' formatters are great as long as you agree with the opinions they have. But the inflexibility makes them useless, otherwise.
Tabs are not PEP 8 compliant except for consistency with existing code:
https://www.python.org/dev/peps/pep-0008/#tabs-or-spaces
But if you're going to use a tool like Black in the first place, you're already committed to not preserving different formatting styles in existing code. You want to enforce one consistent style everywhere in the code base. And PEP 8 says that means no tabs.
> a personal grudge against tabs
I don't see why there would have to be any personal grudge given the above.
I'm hoping there will be minimal or even zero style based commits, excepting those related to new Python features. It wouldn't be very Black-like to force a commit of a potentially enormous size on users of the library every year. Probably something you're already thinking about.
I was apprehensive about taking our legacy codebase Black, but zero regrets. Thanks for your work!
Our Livegrep instance with a custom Git blame implementation always crashed at the commit made to do the migration :-) We had to pause our merge queue because we didn't want to run into conflicts, and I remember the `git push` ended up taking a while.
There was only one change that we had to make to Black to get it working on our codebase - https://github.com/psf/black/commit/024c9cab55da7bd3236fd887...
Glad to see it's now stable.
[1]: https://git-scm.com/docs/git-blame#Documentation/git-blame.t...
Because the only thing worse than a slightly wonk formatting convention is spending any time at all implementing, arguing about, or otherwise worrying about formatting conventions.
I think gofmt's brilliance comes down to it not being overly pedantic, it doesn't have an opinion on how all code should be formatted, it only fixes what it sees as clear mistakes.
x = [ 1, 2, 3 ]
y = { 'a': 1, 'b': 2 }
Whereas these are not: x = [1, 2, 3]
y = {'a': 1, 'b': 2}
To me, declaring inline lists and dicts without the leading and trailing space makes it more difficult to see what the data structure is, and what it contains. This is especially true when you have lists or dicts declared inline as arguments to functions, e.g.: my_function_call([ 1, 2, 3 ])
versus: my_function_call([1, 2, 3])
While it's generally not good style to declare data structures inside function calls, at least with the space it's still somewhat apparent what's happening, whereas without the space it just looks like three positional arguments. I love the idea of black, but in practice I'm not going to use something that changes my own code into something that's more difficult for me to read.I used to think 2 space tabs made code harder to read than 4. Now I used 2 spaces and I’ve gotten used to it and can read it fine. And I have no doubt you could learn to read the black formatted code just as easily. I can, since that is how I format my code anyway.
Read a lot of different code and programming languages. They all look pretty much the same after awhile, formatting and syntax.
I might be in the minority, but it's an empirically testable proposition. Given the thousands of people taking Python quizzes for toptal, triplebyte, etc., it should be possible to see which version results in a lower time to answer or a higher accuracy rate.
If anything I’m seeing the opposite trend with a few devs writing “[1,2,3]” so that large constant literals don’t overflow the line.
Foo<Bar,Baz> value = some.method (1, 2, 3 + 4) ;
// or with no parameters:
value = some.method() ;
I've never seen it anywhere else, and it took me a good week to get used to it.This would be more readable -- put the space around the structure, not inside it:
my_function_call( [1, 2, 3] )
Now we can clearly see the separation of the argument from the function call. But I wouldn't bother switching code formatters just to have this.Other than that, enforce it in CI: patches that don’t match the code style can’t be merged
When introducing it there was some resistance. There's always that one guy who tried it once and it reformatted that perfectly hand-formatted function. My answer to them was suck it up. In a tiny fraction of cases Black might make a suboptimal choice, but the rest of your code is so shit it outweighs this negative by 100x.
As PEP8 already says: "A Foolish Consistency is the Hobgoblin of Little Minds". An automatic code formatter is the epitome of consistency, as it applies the rules everywhere the same way. In many places it might give some benefits, but in others it will ruin the original code formatting. I am experienced enough to format my code in a readable way and I don't need it reformatted, just because someone has to try out some tool. Especially log calls. Those are a pet peave of mine.
Yes. I do not understand what’s wrong with it.
Code formatting is a political stance. It’s so much easier to adopt that than have everyone have slightly different opinions on how things should be formatted.
You should be able to scan is as fast because ignoring the 3 lines with additional spacing is easy.
Cant this be done with just a linter to enforce some rules without forcing an auto format. I really liked just working with a linter to enforce style, as long it passed everything was fine. But still left some room for the coder to make things readable
You are mistaking your own habits for your rationality
If no one is automatically code formatting, then no such noise is created. You could even get a linter telling you about PEP8 violations by underlining stuff for example and configure an exception list for the linter, which is company wide, but not have any automatic change happening. The worst offender is automatic code formatting at commit time. You think you commit one thing, but the formatter commits another.
Wow, I wish I lived in your world. I've never see a team larger than 3 people have a consensus on code formatting.
It's not a tradeoff between "good manual formatting" and "mediocre automated formatting".
It's a tradeoff between "random formatting" and "consistent formatting".
Manual formatting only works when a dictator spends their time enforcing a consistent style. Once projects get large, the value of this is marginal.
Its fast enough, can be made to run incrementally, has enough configuration options, and accepts a project-specific configuration file. There is room for a solution in-between laissez-faire and black's strictness.
And not having to think about it at all is just an additional bonus.
I used to have to make style passes before I would commit code. And get style comments in code reviews. I don't miss those days.
> If you are adopting Black in a large project with pre-existing string conventions (like the popular “single quotes for data, double quotes for human-readable strings”), you can pass --skip-string-normalization on the command line. This is meant as an adoption helper, avoid using this for new projects.
Where you think a long call should be allowed somebody else will think it should be split.
Pick a code formatter, and fuck opinions, we'll do whatever the formatter says we have to do. Done. It is not that important if you put semicolons here or there as long as it is consistent.
With Black, I don't spend a single moment thinking about that at all. I estimate I've got a 5-10% productivity boost in my time-spent-writing-code from this!
It was revolutionary. I went from formatting as I went, even for prototyping to throwing code at my editor and letting rustfmt fix it. Big difference in productivity.
to_add = [item for item in data.new_items if item not in data.old_items]
to_remove = [
item for item in data.old_items if item not in data.new_items
]
Although the constructs are nearly structurally identical, they can be formatted very differently, which sometimes hinders understanding them.A different approach would be to instead normalize all words to a certain fixed width. So, "to_add" and "to_remove" would have the same virtual width.
A related issue is that leading indentation counts towards the width limit. This causes refactorings which simply move code around (changing its indentation level) to change the code's shape, even when the code hasn't otherwise changed. This is exacerbated by that one often needs to mold code in such a way that Black formats it in an agreeable way, but this is generally not done during refactorings, so the readability of the code suffers.
I had the opportunity to write a formatter (for SQL, also unconfigurable/opinionated); it seems to successfully avoid these problems: https://github.com/CyberShadow/squelch
Ultimately there has to be a hard limit and it's silly to argue over special cases that should exceed it (because that's just another thing to bikeshed over in code reviews). Black sets a hard limit and enforces it--done, no more discussion.
IMHO it's a code smell to have a bunch of long lines of code that are all visually similar but vary in a tiny and easy to miss way. Here's another way to think about the code you wrote that boils it down to an even smaller and more focused intent:
new = set(data.new_items)
old = set(data.old_items)
to_add = new - old
to_remove = old - new
It's not exactly the same as what you wrote but you get the idea, and it can be made simpler if you're using set types to start with. It's kind of a nudge that if your intent is to do set-like operations like difference, intersection, etc. then you might want to use the right tools for the job instead of banging out more procedural code.Regarding the hard line width, "fit everything on the screen" is a poor goal to aim for; a more useful goal is to make the best use of the two dimensions you have at your disposal. Squishing things across either axis will make for a poorer experience than occasionally requiring some scrolling for some setups.
You may also find it interesting that Prettier does not interpret it as a hard limit as well: https://prettier.io/docs/en/options.html#print-width
If a line is longer than that it's most of the time either something which should be wrapped into multiple lines anyway (like a dictionary with multiple keys) or a sign for code smell.
One of the most common code smells I see leading to longer than necessary lines (and which might make the code harder than necessary to read) is not using early returns.
Also using a trivialized example:
to_add = []
for item in data.new_items:
if item not in data.old_items:
# code spanning multiple lines with further indentation levels
…
to_add = []
for item in data.new_items:
if item in data.old_items:
continue
# code spanning multiple lines with further indentation levels
…Black – Uncompromising Python code formatter - https://news.ycombinator.com/item?id=19939806 - May 2019 (244 comments)
Linting 400kLOC of Python Code with Black - https://news.ycombinator.com/item?id=18536731 - Nov 2018 (1 comment)
Black: An uncompromising Python code formatter - https://news.ycombinator.com/item?id=17151813 - May 2018 (255 comments)
I think you can convey meaning with subtle code style differences. Empty lines to delineate blocks. Single quotes if the string is a keyword, double quotes if it is for the user. Spaces around operators to make an expression clearer. I spend a minute or two before I commit to make the code tidy (linter and then manual tweaking) and would expect that from everybody on my team - it takes often less time than rebasing and picking good commit names, for example.
But even though it annoys me slightly when I encounter Black (or god forbid, Go) used in a project, I know a lot of people like it a lot, and it is good to have the choice. So congrats to the release! :-)
I'm personally glad to see Python development come to the same conclusion enforced by Go's opinionated tooling.
That is: style questions are almost always unimportant to producing value, but teams still waste excessive time on them because of the engineering tendency to bikeshed triviata.
The problem with most things that have to be applied manually is that they're also applied inconsistently. It's like Hungarian notation. Over time, it becomes pure noise: you can't rely on it, especially when reading someone else's code, so it's safer to just ignore it. At which point, the convention's cost/benefit is approaching infinity, because its denominator nearly zero. So I'm not sure I care if the absolute cost is small. It's still an almost complete waste of effort.
The only place I've ever seen manual conventions applied consistently enough to be useful in a sustainable way is when someone's carved out their own private silo of code that is mostly only touched by them.
Exactly, it doesn't matter what option you pick, as long as everybody picks the same option. Enter opinionated code formatters, because otherwise how do you do it?
Only reject obviously quite messy code, and only rarely allow formatting rewrites. Learn that anybody’s strong preferences for a specific style or discussion of such aren’t demonstrably beneficial for the bottom line of the business or customers.
Some programmers are zealots who have a hard time working with others, the solution isn't always to force the matter or acquiesce to the squeakiest wheel. A strong organization should be able to enable people do have their style and disable people from forcing their opinions on everybody or wasting everybody's time with low-value debate.
Code with style changes, especially within a file, is harder to follow than almost any reasonable consistent style. And adopting a common formatter with common settings is a lot less work than “reject changes on lines where code isn't changed, and coach the style zealots to calm down” even if it was neutral in readability.
This is exactly the type of arguably useless effort we don't want to spend any time on. Having to think about what is "reasonable", "allowed", or "best" is non-negligible cognitive burden for both the writer and reviewer/reader.
I often then tweak the code in a way that is not necessarily better, it's merely rendered better by black.
It just feels like I'm fighting against the tool half of the time.
I think the appeal is that it avoids the discussions entirely (i.e. if it doesn't matter what option you pick, why even have the option? Particularly if these options will mean you divert away from the standard python style guide, which has been trying to standardize these choices for years so that codebases have similar rules.)
i.e. if your org has inconsistent python formatting between different independently-operating teams, it's easier to enforce PEP 8 than start a load of pointless arguments about what good looks like.
Yes that's very true, but, and now comes the big but - if you're working in a project with dozens and dozens of other devs, you will necessarily see all kinds of weird formatting. And this is where an opinionated formatter shines. It doesn't matter how many people work on your project, what the churn-rate is or if the guy that just started yesterday already read the code-formatting guidelines or not - the formatter will just take care of it and remove all hassles surrounding that topic. And this only at the price of opinionated formatting which I may or may not like - a price that I likely have to pay either way, because there's no way that everybody shares the same opinion about formatting in the first place.
I recommend to give opinionated formatters a try, if you haven't already. I know plenty of folks who were initially against it but eventually came around it because it made life a lot easier: No more discussions about formatting on PRs, no more tabs vs space wars, everything's already settled and automatically taken care of.
Opinionated code formatters mean that opinionated coders with different preferences on a team don't produce (or at least produce less) noise in diffs.
You see that here.
Things like a = [ 1, 2, 3 ] when 90% of the world is a = [1, 2, 3]
These folks will spend hours / days try to force weird approaches.
Sometimes they are obviously wrong. But it's annoying to have to fight over it. Something like black saves you the hassle and the WEIRD local coding rules someone comes up with if you are on a project with them.
First step was to run an autoformatter. I used stock presets so neither of the two would think the other was favoured in the cleanup.
However, if another person ALSO has a strong opinion about this - nightmare.
Why? This is exactly why we need autoformatters :-) if you're on a team, you should be conveying meaning with variable names, comments, and structure. If it doesn't show up in the syntax tree, it doesn't have meaning. Consistency always wins because it elevates everyone's ability to read the code.
There's more to it than the social aspect though: putting effort into manually moving around characters in a text editor is not the best use of mental bandwidth. My experience (and that of many I know) is that formatters help you code faster with less bugs by letting you focus on the higher-level structure of the problem NOT on the minutiae of where each punctuation mark should live. If your code is syntactically correct, the autoformatter will make it look "right" and you don't have to think about consistent formatting at all. If it's not syntactically correct, you set your editor to autoformat on save and you get immediate feedback. So it's not just about consistency, it's also a productivity aid.
I understand having strong opinions about the "right" code style. Personally, I dislike the double quotes in black. So I type single quotes and let black do its thing on save. What I type does not need to be what I commit (so long as they both compile to the same AST)! I don't want to waste time debating formatting details in a PR, and I certainly don't want to interrupt my coding flow to manually perform the labor of shuffling ascii chars around when there is fully automated solution. I can't think of a single scenario where my personal style preference would outweigh the significant advantages I've seen from autoformatters.
Why did you use paragraphs to write your comment then? People read the code thats written.
Also, single functions that are long enough to contain something analogous to paragraphs are arguably not Pythonic in the first place.
If that part of the code is special for whatever reason, add a comment saying why.
Spend some time considering the language standards, but then ship it for god's sake.
See also from Peter Norvig[0]:
* Get involved in a language standardization effort. It could be the ANSI C++ committee, or it could be deciding if your local coding style will have 2 or 4 space indentation levels. Either way, you learn about what other people like in a language, how deeply they feel so, and perhaps even a little about why they feel so.
* Have the good sense to get off the language standardization effort as quickly as possible.
It is the one small grip, I have with black. C&P for example some string-indexed dict element as argument into a f-string sometimes produces duplicate double quotes if it gets into black's hands beforehand. But in the end, black outweights all these minor things. This particular issue also is probably better considered as a tooling task for editors, IDEs etc.
Use comments to describe those blocks and their meaning, don't just assume everyone is thinking exactly the same as you are about the code organization (hint, they probably aren't). Where you see a bunch of logically separated blocks of operations I might be new to the codebase and just see a bunch of unnecessary whitespace. Describe what's being organized and why in comments.
def foo(a,b,c):
var x = 40
var y = None
bar()
return x * b
I think the blocks of code make it more readable, some variables are set up, some work is done, then it returns somethingCode is meant to be read by humans. Compilers don't have wetware eyes. Homogenizing code that was hand-formatted for the situation ignores the art and craft of writing software.
I think formatters do have use as a "base" (e.g. Allman or K&R curlies?), especially for junior devs, but experienced developers that care about their software that has their name on it normally put their best foot forward. They would strive to present the most readable software they can put forth.
I've been writing software since 1981 and have yet to meet a code formatter that I like. `// @formatter:off` !
The only way to avoid it is to have the political power to call out the team member that's annoying. Easy enough to do if you're the lead and nobody will question your decisions.
The worst and dumbest fights I've encountered is with people with 30 years of experience who have diametrically opposed opinions. I _especially_ despise having to call out very senior engineers when their own code misbehaves.
Since code is skewed heavily to the left of "read:write", the primary issues that formatting should address are [1] muscular eye fatigue induced by "formatting" or non-formatting that leads to excessive eye saccades (i.e. eyes "jumping" from point to point, or obliquely) [2] formatting that obscures logic leading to cognitive fatigue.
Another thought experiment I've used is: Imagine that you replaced [A-Za-z0-9] with squares and made it black and white. Leave the language's keywords alone. Does the shape of the code suggest the logic and flow? etc. That's more in the zone of cognitive load.
That's why it's an art and craft, to me. My thinking is also colored by smaller shops, since a stint as a cog in some large orgs burned up my soul.
And yes, I've been in a few dumb fights ;)
Black is not ideal but one can live with its output and in time the style becomes familiar to everyone.
Python has significant whitespace, so you can't just click "ignore whitespace changes" in Github diffs and it doesn't matter. You have to put up with every silly whitespace change.
Until Black.
I wrote a blog post on how to use Black in Jupyter Lab notebooks if anyone is interested: https://coiled.io/blog/code-formatting-jupyter-notebooks-wit...
It's really nice to format a notebook with the click of a button.
— Matthias Bussonnier, https://github.com/ipython/ipython/issues/13463#issuecomment...
R. Hettinger needed to learn to always be graceful when commenting or criticizing the work of others, especially volunteers.
And we all saw how wild the difference is in engagement for a project like ipython between the "normal" level and the "viral" level. Users are just using it and depending on it, never interacting with the project, but if something attracts attention it can be like a thousand flies flocking to it. Often when something gets negative attention..
1) People who easily get passionate but are gentlemen when it counts. R. Hettinger is one of these.
2) People who get passionate and are politicians. GvR is one of those and he is above the CoC.
3) Vicious politicians who always remain calm. These are the most dangerous, are often mediocre and climb the ladder at various large corporations. Some of these have not contributed much.
4) Some really nice people. You generally won't see much of them in discussions.
R. Hettinger is independent and honest, unlike the snake pit that runs Python.
https://black.readthedocs.io/en/stable/the_black_code_style/...
But the whole idea is that you should learn to suppress your ego and let the tool be the one dictating stylistic choices...
Like the sibling comment mentions:
Dusty Phillips, writer:
"Black is opinionated so you don’t have to be."
- Author of some tool
- advocates of code formatters
https://black.readthedocs.io/en/latest/the_black_code_style/...
Seen from outside, I think the double quotes are just the natural form of strings in lots of other places, at least in those that come from the same family than C (C++, Java, C#, Rust, just to name a few)
Also Prettier.js (which I'd call the "Black of JavaScript") also settled on double quotes. So we're left with a de facto consensus across programming languages as a whole, which kind of feels nice.
Using Flake8 with Black requires only two configuration options [1], while Pylint requires three [2]. If you prefer to use Black with --line-length 79, then it's down to a single configuration option for Flake8 or two for Pylint.
[1]: https://black.readthedocs.io/en/latest/guides/using_black_wi...
[2]: https://black.readthedocs.io/en/latest/guides/using_black_wi...
Another coworker and I have created an import sorter that fits well alongside Black, called µsort. It is designed from the ground up to be a safe, stable import sorter that won't move imports in ways that potentially change behavior of the codebase, and without needing developers to litter their code with "skip" directives. We use it in our daily formatting codemods on tens of thousands of source files every day, and just finished our 1.0 release in December.
Going further, if you like enforcing both formatting and import order in your CI pipeline, I also created the project µfmt, which combines both Black and µsort into a single, atomic formatting step. This ensures there's never any conflict of opinion between the two tools, and any formatting changes are presented as a single diff result.
How can that be the case? Can't Python imports have behaviour that varies on the time of the day if they want?
An import could monkey patch a basic operation one day but not the next.
https://usort.readthedocs.io/en/stable/guide.html#side-effec...
The biggest reason is µsort's detection of sortable "blocks" of imports, and only sorting within those blocks to limit breaking changes, combined with use of proper parsing and CST manipulation to guarantee valid syntax after sorting.
Ever since then, I am not opinionated about coding standards. The benefits do not match the costs.
Although I do like the approach of "use something like black on precommit", and if you don't like it, you can reformat to your standards on check out, and be happy. It will get fixed on check in.
If you're coders can code it doesn't matter, and if they can't formatting their poor code isn't going to fix it.
It leads to the question “then what is the ultimate bike shedding issue?”
Whenever you have one of these bike shed issues in a meeting, do this: Give everyone 5 minutes to say their piece, give everyone an opportunity to ask 2 follow up questions to anyone, and a 2 minute response. Go through everyones opinion, take a vote and move on. Then set a date 1 year in the future to review/change the policy.
A nice bonus is that you end up having uniformly readable code.
Can someone explain this to me? Why would you ever prefer " over ' in a language where both can be used equally?
print("\"Hello\" he said")
to print('"Hello" he said')
I think pretty much all formatters for languages that let you use either quote do this. It makes sense.EDIT: I misinterpreted that single quote as a backtick. In any case, both single and double quotes are common in SQL, but single quotes are a bit more common.
If you’re on a Mac, Option-Shift-] will type it.
* Double quotes are more visible, especially for triple quotes.
* It makes it easier to have text without having to manually escape apostrophes.
However, does not Python and standard SQL using different quote characters make it easier? I.e.
query = "SELECT column_a FROM a_table WHERE column_b = 'foo';"
compared to this, if single quotes were enforced: query = 'SELECT column_a FROM a_table WHERE column_b = \'foo\';'On the other hand, if it's useful to have minimum need of escaping, then single quote is still better, because in SQL it's much more common to quote identifier names than to have literal strings.
query = 'SELECT "columnA" FROM "aTable" WHERE "columnB" = \'foo\';'
compared to query = "SELECT \"columnA\" FROM \"aTable\" WHERE \"columnB\" = 'foo';"Why? It’s obvious that it causes issues as I showed, and yet you simplay claim the opposite without argument? The difference between other programming languages and SQL is, of course, that it’s very common to have embedded SQL code in your program, but not common to have embedded strings of code in another programming language.
> in SQL it's much more common to quote identifier names than to have literal strings.
That is certainly not true. The kind of SQL you quote is only found in auto-generated SQL by ORMs and the like, and those are not likely to exist as strings in code. To use your example, this is the normal SQL way to write that:
query = "SELECT columnA FROM aTable WHERE columnB = 'foo';"
I.e. no double quotes needed; no need to escape anything.But to be fair I think it's because 1. Double quotes are ""universally"" strings in other languages 2. Having apostrophes gets annoying.
The great benefit really is that I can write single word strings just fine, and black will adjust it for me. I get my cake, and so do the others.
Edit: I suppose the question is superfluous seeing how many replies there are just here.
The whole point is that they’re all arbitrary so just let the defaults win, and adjust yourself instead.
To elaborate a bit, sure, there are arguments for everything talked about here, and they're valid, but the marginal utility of any one choice is dwarfed by opting out of the arguments entirely, and just going with whatever Black has selected as a default.
And while it’s still kind of strange that `a = “foo”` looks different than `repr(a)`, after a while of using Black I don’t notice it anymore.
Personally, I still type single quotes in almost all cases, and just let Black reformat to double quotes to save shift key presses.
>>> "string"
'string'
I sense a bloated ego of the author in Black's decisions -- to contradict with the language's preferred formatting style.Then put that commit's (full) sha in a file named something like .git-blame-ignore-revs
Then `$ git config blame.ignoreRevsFile .git-blame-ignore-revs`
That being said, my biggest gripe with it is that it has at some point started reformatting docstrings [0] in addition to the code -- strictly following PEP 257 [1] -- without any way to disable that behaviour. While I understand the desire to standardise, docstrings are not executable code, and should be allowed more flexibility when it comes to formatting.
I know, I know consistency. I've heard that for years. I disagree that it matters. Where I work, one codebase is formatted with black, another is not. The un-blackened codebase is rife with all sorts of style inconsistencies. This does not make it more taxing to read.
The only downside is the useless PR nits from folks who randomly decide you ought to format something a bit differently. If it were up to me, I would just ban all style related comments and move on with life. But adopting Black seems politically feasible, so I advocate for that.
Because easily 98% of the work of any developer is being a "wetware compiler" since "code is written for other people."
So the faster the human can mentally run the code, the faster they can then decide what action to take next
> This does not make it more taxing to read.
Ah, spoken like someone who has not yet worked in a "foreign language" shop, where the developers are new to the language at hand and bring their old "best practices" to the current language
People always say this. But they fail to provide any evidence that consistency helps, and if so if by how much. All they have is personal experience, which is all I have as well. And my personal experience says it just doesn't matter.
> Ah, spoken like someone who has not yet worked in a "foreign language" shop, where the developers are new to the language at hand and bring their old "best practices" to the current language
Quite the assumption. That's where many of the inconsistencies come from. And Black isn't going to help with different language idioms. That matters a lot more than whether or not you use a trailing comma for the last item of a multi-line list or not.
Honestly every language needs something like this. Black is literally the first tool I install when I write Python and it's sorely missed when I move to a language without an opinionated formatter.
I also always hated single quote docstrings even in single quote code bases.
This is a very nice quote and sums up my own view on black (and code formatters in general) nicely. Thera are things you don´t really want to have an opinion about.
I typed a hundred tabs
You go back to space and I go back to black
awesome reference!
[1] https://prettier.io/ [2] https://github.com/google/google-java-format
Don't @ me.
Loosely related - This is Python pip. Trail of Bits has a tool pip-audit that audits Python environments and dependency trees for known vulnerabilities.