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!
Congratulations. I'm a Python developer of 17+ years and Black is truly a huge blessing in the Python ecosystem.
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).
I think one of the great benefits of Black is that it is opinionated. Giving folks the option to select the type of indentation blunts the benefits. If you have a huge code base which mixes tabs and spaces it’s going to be hard to diff and merge code (or even reuse code snippets).
The point of black is that you run it on the same codebase with the same parameters.
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.
Reading this doc it feels like the Prettier team is saying options like tabs/spaces were only added early on to get initial adoption, if it were up to them now there would be far less options to configure at all.
The options in question are some of the more.. fancy ones, and the "history" in question is things such as cross-compatibility with ESLint. Certainly not "tab support". (And I've contributed to Prettier a great deal, FWIW)
Unfortunately Black goes with PEP8, and PEP8 recommends spaces. Guido made this call arbitrarily years ago for absolutely nonsensical reasoning (basically came down to that some people use shitty editors that don't handle tabs reasonably) and the entire Python community has had to suffer since.
On the contrary, I think it's fundamentally useful to the ecosystem that there be a winner in the tabs-vs-spaces/how-many-spaces debate. Code snippets become portable, developers don't need to adapt when joining a new team, etc. Indeed, https://www.python.org/dev/peps/pep-0008/#indentation has enshrined 4 spaces as the official recommendation. And when the best-in-class formatter enforces this, that's a good thing.
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.
Environments that prefer tabs just use Tan, or otherwise, those environments just didn't use Black at all.
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).
The Prettier team has gone on to say they regret giving people several of the configuration options they did though and have a page dedicated to their option philosophy. https://prettier.io/docs/en/option-philosophy.html
Yes, you'll find no mention of regretting adding tab support to prettier on that page.
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.
I don't want to wade in or start a debate, but just share my experiences with formatting over the years. Lacking autoformatters in the past, I've worked with coworkers that preferred 2, 3, 4 & even 8 spaces for indentation.
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".
Since Black enforces that indents are exactly four spaces, you could configure your editor to render four spaces at the start of a line as two spaces, getting exactly the behaviour you desire from tabs.
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.
The proper number of spaces seems to me to be dependent upon the font size. Smaller font, more spaces.
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...)
While I completely agree with all your other reasoning. It should be pointed out that PEP 8 is not intended to be a styling guide for user code, it's intended to be a styling guide for the standard library: https://www.python.org/dev/peps/pep-0008/#introduction
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.
One thing I liked about Python was that PEP8 existed and was some sort of fairly aged standard for formatting. I’m not sure why people feel under deviation to suit their personal preferences is more valuable than consistency.
Consistency is not in and of itself valuable. What is valuable is when it makes things clearer, or otherwise easier. Tabs vs spaces has absolutely no effect on my comprehension of the code. Being able to use spaces for alignment would actually help in some cases but oh well, that's not allowed in python. The way black splits [] expressions is actually harmful when it's used in a chain with method calls as is not uncommon in pandas.
to anyone with even the slightest levels of OCD,(like say 95%? of software developers) consistency for the sake of consistency has a lot of value. The reason I like Black is not because of the authors opinions, but because it is consistent (due to the absence of configuration/user preferences).
Perhaps my naivete is showing, but I fail to see how an option that allows broader range of use cases suddenly becomes a religious war about spacing.
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.
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. :-)
At the risk of repeating myself, I forked Black into Tan and just added --use-tabs. The alternative was "don't use Black". Others are in my situation as well and use Tan, somehow finding it despite it not being advertised anywhere. Hell I had people bugging me to update it a few weeks back.
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.
I shared that link in good faith, not aware of your specific use case. I still think it's for the better that black does not allow tabs, and that your fork is a good solution for shops that need tabs for an existing code base.
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.
Sorry, I re-read my comment and noticed it sounds way more aggressive than I intended it to be! I love the little hack actually, but it looks like it's really just a hack ;)
PEP-8 is the de-facto standard for python. Why would a formatter for python support anything (such as tabs) that deviates from that? There might be code that does not adhere to PEP-8, but to me this is not a justification, just some people distancing themselves from the python core community.
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).
And I’m a little sad to see it’s gone stable without adding support for single quotes...
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.
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.
Some teams strongly prefer a longer line length. For code maintained exclusively or primarily by a team that can reach agreement on this issue, it is okay to increase the nominal line length from 80 to 100 characters (effectively increasing the maximum length to 99 characters), provided that comments and docstrings are still wrapped at 72 characters.
Congrats to the black team on this release, and thank you scrollaway for your fork. We are in a similar position where we are (for various reasons) stuck on using tabs for an existing project. Luckily it seems like there might be some movement on this front where the maintainer team is at least more receptive to reopening this conversation:
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!
I think that’s only MySQL. Postgres uses double quotes for identifiers and single quotes for literals.
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 use proper apostrophes instead of ASCII apostrophe / single quote, you don’t have to escape anything and you get better typography. "don’t" is easier to read than both.
Because most commonly used languages use double quotes, not single quotes, for string literals. Some languages can use both, either interchangeably or with slightly different semantics, but others either uses single quotes for other purposes, or do not use them for anything at all. Therefore, double quotes for strings look more normal, so to speak, in source code.
Except that in the language you're most likely to mix with Python, SQL, strings are in single quotes (double quotes are for identifiers like column names, especially if they're case sensitive). So it's probably a bad choice on Black's part.
If it's useful to use the same string literal character "as everyone else", it would be useful to use the same as a language you are very likely to see combined - so, single quote.
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';"
> it would be useful to use the same as a language you are very likely to see combined - so, single quote.
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.
The presence and depth of the debate about this formatting choice suggests that it isn't arbitrary. Many have provided solid reasons for why one option should be preferred over the other. They aren't merely articulating their opinions; they are also providing objective reasons for why their opinion is valid.
Everything about formatting is arbitrary, as long as it's consistent in a given codebase to the point of predictability (e.g. 90% consistent, not necessarily 100% consistent).
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.
That was the thing that bugged me at first, but other people on my team loved it. Some things bugged other people on my team, even though I love them. If a tool can manage to annoy everyone about the same amount, but in different areas, it’s doing something right.
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.
Things were factored a few times, wasn’t a consistent patch. Also I didn’t care for a few of the changes so didn’t upgrade yet. However stable should be a good target for automation.
Additionally, standardizing all quotes makes searching for a specific string literal across a codebase easier, since you don't need regex to match against both quote types. Once you've decided to standardize strings, it doesn't matter much which one you pick.
Personally, I still type single quotes in almost all cases, and just let Black reformat to double quotes to save shift key presses.
IIRC, the -S only avoid single quotes to get switched to double quotes. What I meant was allowing Black to switch double-quotes to single quotes automatically.
I understand that. And this is what I like in Black. But the single quotes thing is really up to debate. When you use it with other tools such as flake8 or pylint, you have to disable a bunch of things to make them work together because no one agrees on this point.
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.
> When you use it with other tools such as flake8 or pylint, you have to disable a bunch of things to make them work together
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.
That made me wonder, so I went and tested edge cases, like "abc\"d\"ef", which black quite properly converts to 'abc"d"ef'. So it does use single quotes where appropriate.
You can have some basic configurable stuffs in an opinionated tool though, see Prettier. It allows tab/space, quote style, line length etc., to be modified.
Prettier has some options, but they are not happy about it, it's just how things happened and now cannot be "solved", i.e. remove them, albeit they would love being able to do that:
There’s also “blue” which I’m the author of and looks similar: https://pypi.org/project/blue/ would love to get your help and thoughts in the issue tracker or by email.
Great, I'm sure it will end up with a good solution eventually. Unfortunate that it had to be this heated about this change.
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..
There are several main personalities in the python-dev space:
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.
After this comment the submission dropped from place 25 to place 56 in less than 10 minutes. Suppression of opinion is a standard PSF politician tactic.
Fuck I love Black -- makes working with other developers amazing once you stick it in a precommit. The quote from Dusty Phillips on the homepage is perfect and has stuck with me for years. I don't have to debate with developers about their individual preferences over what's best because we can just use Black and be done with it.
I love it even though I dislike quite a few of its formatting rules.
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.
Exactly, gofmt is actually almost perfect. Ironically, it makes Rob's quote less meaningful.
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.
The problem I have with it is that, to me, these are super readable:
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.
My only response to this would be “get used to it”.
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.
> 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.
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.
I think it just doesn't matter anymore because almost all editors support code folding and visual markers for it, making it MUCH easier regardless of 2 vs. 4.
And that’s the reason everyone should use tabs. You like 2, I like 4, someone else one the team likes 3, 6, 8, whatever? No problem if tabs are used, everyone can set tabstop to their liking!
You might not have been writing JavaScript. For objects, spacing properties from curly brackets is pretty much the norm, Prettier does that by default. For lists I see it rarer but I personally use it instinctively for consistency with objects, especially with things like useState destructuring and ([ complex, ...splatting, ...combinations ]) into function calls (which admittedly becomes uncomfortably terse).
Just learn how to make them readable. I am yet to see a single developer who didn’t manage to learn that. Seriously, the worst types are the ones who think they are experienced enough to think what “is more readable”. It’s all a matter of habit.
I disagree: your style is less readable than Black's. You've moved the data-structure syntax away from the data, and toward the function-call syntax, causing them to blend together.
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.
Before I introduced Black in my workplace, all code reviews were peppered with stuff like "should be indented", "use single quotes" etc. Made it impossible to talk about the stuff that actually matters.
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.
I don't love how Black doesn't let you put some clarificatory parentheses -- for instance, they get wiped from
`eq_balanced = (left_hand_side == right_hand_side)`
But the benefits of never wasting time on discussing inanity outweigh any specific complaints.
Anyone have a foolproof way to reformatting all the code in a repo without screwing up history? I've seen some complicated commands which seem too sketchy to a git novice like myself.
Adopting Black made me realize quite how much of my coding thinking capacity had previously been spent thinking about code formatting - I used to really sweat the details about how to break up a long function call, where to put the line breaks, how to indent my dictionary literals...
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!
To add onto this, I also found that Black works as a nice heuristic indicating to split up code when the formatted output isn't "pretty" into separate lines.
It's been at least a decade since I've not used an autoformatter on every piece of code ever. I didn't realize there were people who worked at places without autoformatters still.
Had a similar experience when I used rustfmt (which led me to trying black). I was used to formatters that over formatted, removing newlines used to dilineate sections of code, etc. I tried rustfmt when learning Rust because I figured id learn adopt standard practices.
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.
I remember we migrated 2+ million LoC to being formatted by Black at Dropbox.
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.
When I switched the company to Black, I reformatted the whole repository history with it. Every developer had to clone the repository again and reapply their local changes to it, but in the end it was a good choice because "blame" still works perfectly since we don't have one big reformatting commit.
An alternative is to use Git's blame.ignoreRevsFile[1] option to ignore specific commits when calculating blames. The downside is that although you can save the list of commits in the repo, you cannot do the same for the config setting itself, so it calls for some light automation at scale.
Still ugly. I hate looking at code mangled by this thing. Single quotes? Fluent interfaces? Go write Go if you want ugly code you don't have to think about.
Pretty sure Black prefers double quotes in the main case, but what are “fluent interfaces”? Go is pretty great though, I completely understand the envy! :)
Does Black inhibit method chaining? In any case, I don’t see the value in fluent interfaces—if I had to choose between an opinionated code formatter and something people do because Martin Fowler told them to do it, I would take the former every time.
Personally, I don't understand the appeal of opinionated code formatters. If you don't want to discuss "taste" questions, then just don't, it doesn't matter what option you pick. If it is an important question, then you should debate it.
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! :-)
> If you don't want to discuss "taste" questions, then just don't, it doesn't matter what option you pick. If it is an important question, then you should debate it.
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.
I think the general consensus of many people, myself included, is that it doesn't matter what the specifics are, as long as they're being applied consistently. Beyond that, it's a question of optimizing the cost/benefit ratio.
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.
> If you don't want to discuss "taste" questions, then just don't, it doesn't matter what option you pick.
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.
My point is you let people have their different styles, reject changes on lines where code isn't changed, and coach the style zealots to calm down. Changing a couple of bytes in a file? Don't change the style. Writing something new? Figure out what's best. Rewriting a big chunk? Make reasonable formatting choices.
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.
> My point is you let people have their different styles, reject changes on lines where code isn't changed, and coach the style zealots to calm down
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.
> Changing a couple of bytes in a file? Don't change the style. Writing something new? Figure out what's best. Rewriting a big chunk? Make reasonable formatting choices.
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.
When I use black or other formatter, I have to exert cognitive effort to anticipate how the formatter will format the code so that I can avoid the inevitable stupid formatting decisions.
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 it's a tell when people get so fussy about style, if you can't get past non functional differences how are you going do on differences of functional differences. "my code is spaghetti and performs poorly, but at least I used a formatter!"
> Personally, I don't understand the appeal of opinionated code formatters. If you don't want to discuss "taste" questions, then just don't, it doesn't matter what option you pick.
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.
I can stop discussing taste issues, but it doesn’t prevent others from debating what the proper style for my PR ought to be, meanwhile I can’t merge my PR.
> I think you can convey meaning with subtle code style differences.
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.
I only reformat code I am rewriting, for that reason. I've never seen a tool that was very good at bending its own rules to minimize these accidental changes (e.g., let a function call go to column 83 to keep it on one line).
The reason I like black is the most opinonated folks have WEIRD opinions.
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.
I think I figured out why: it’s easy for everyone to have an opinion about simple things. Complex things that are worth arguing about take more knowledge/experience and at that point fewer folks are qualified to argue about them.
I once came in on a project where one dev used "func( arg )" and the other used "func (arg)". They would reformat each other's lines when they changed something, so the diff had a lot of whitespace changes. The two were not on speaking terms any longer, so I was tasked with cleaning up the mess.
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.
I just don't see why you would care if this extra space is in there or not. If they want to stick it in there, be my guest. I can read either just fine, even if, gasp, it's not 100% consistent through the whole codebase.
> convey meaning with subtle code style differences
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.
Auto formatters support paragraphs, but they don't support I'm going to give this paragraph 2 blank lines because it's particularly important/complicated/blah.
I think the argument is not that structure should be dispensed, or that it doesn't matter, rather that a given style convention is fungible, and we should probably all just pick something good enough and get on with it, because the code will execute regardless of whether we use " or ' around our strings.
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.
I actually had this formatter thing happen at work. We have code that generates more python code. Now the quotes are changed and we need escapes because a rule it being applied. Escapes are harder to read and look messier.
> So I type single quotes and let black do its thing on save.
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.
Sounds like you actually are very opinionated about your coding style, so it's both totally understandable and yet ironic that you'd begrudge that of others. I've tried hard to internalize that opinions are like assholes, everybody has one and they all stink. My own included.
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.
Ye I don't understand it either. Why would you want some automated Whitespace Hitler telling you what to do. You can't even select between tabs and spaces for indentation.
Huge milestone for the Python community! Very happy for you guys. In Elixir, `mix format` has saved so much time across multiple projects and teams. I can't remember the last time I talked about line breaks and how to divvy up a long multiple line function header.
Loosely related - This is Python pip. Trail of Bits has a tool pip-audit that audits Python environments and dependency trees for known vulnerabilities.
Not that I don't appreciate the shoutout (I'm one of the developers of pip-audit), but what's the connection? Is it because black is installed via pip?
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.
5 upvotes generate a pro tip: have your CI run black --check against the code you want formatted. That way different devs can run the formatting how they like (in tox; in a pre-commit hook; in IDE; on the command line) and CI just enforces that it happened.
Long ago, I worked at a company that decided it needed coding standards. We spend two weeks arguing about coding standards. Nothing else got done.
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.
Sort of why I think Go got it right with gofmt. Its not as strict as it could be but all Go looks more or less the same and it’s because it was built into the language
Too many people have too strong opinions on the subject. Some things are reasonably good ideas, many more are just arbitrary, strict rules prevent doing reasonable exceptions, and an enormous amount of time is wasted discussing the matter.
Just an off topic note on language: penultimate means second to (last, final, biggest, etc), i.e. the one before the ultimate. Perhaps an odd choice of word in context that is often misunderstood.
It leads to the question “then what is the ultimate bike shedding issue?”
yes, ironically the word choice is to avoid bike shedding, if I said it was the ultimate issue there would be all sorts but but no, this issue, where as if it's the 2nd everyone can have their pet issue be most important and we can reach agreement on it and move forward while tabling the discussion of what is the ultimate 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.
To me, the point of using code formatters is that you don't have to think/talk about code formatting much at all. As in, there are never annoying comments about formatting in PRs.
A nice bonus is that you end up having uniformly readable code.
Arguing over coding standards is harmful, but consistency is a good thing. Best to adopt a standard style guide and limit any debate to deviations and even better to have a tool like Black make it automatic.
Yep. Even if I personally hate a coding style, I'll stick to it religiously if it's what my team uses. A good coding style is one that everyone adheres to.
Shameless self-promotion, as a former coworker of Łukasz, Black's creator:
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.
Absolutely! We're hoping that the vast majority of modules are good citizens, but we also know that the reality not perfect. That's why µsort allows you to configure a list of modules with known import-time side effects, and µsort will then treat those are barriers everywhere.
Even better, you can overwrite the default importer to substitute your own with any behavior you want. Used in EVE Online to do their "hide the python code somewhere" scheme.
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.
FWIW, there's one particular use case where the isort behavior is incredibly useful: in eval-as-you-type data science e.g. when using Hydrogen in Atom you type an import whenever you need it but that leads to a lot of duplication and imports scattered across the file, and it's nice that isort just moves that up top on every save.
That's something we're aware of, and something we've considered, but also potentially dangerous from a safety standpoint, due to Python's dynamic nature, and how much moving imports can affect runtime semantics. Any implementation of this would need to be aware of those dangers, and also be able to provide stable and predictable behavior. At the moment, it's not a huge priority given the availability of tooling to automatically add missing imports, or the limited impact of under-sorting in the context of notebooks.
I use black and love it— but only with 120 line lengths. The default of 80 is wayyy to low for the days of 4k monitors. The tricks it uses to split some things up onto new lines actually makes it less readable.
I agree. I've sometimes found Black's output to be on the borderline of unreadable with the default line length of 80. My team settled on a length of 120 (the only Black config item we changed) and it has largely, though not entirely, solved that problem.
As long as you can easily review code side-by-side with line numbers intact, you're good. The default was chosen for lower resolution 13" laptop monitors to be able to display the Phabricator diff page (think: Github PR review page) without having to wrap any lines.
I agree 80 is too low, but it doesn't have anything to do with 4k monitors, it's just that 80 is too short. Any longer than 120 is not readable imo. Luckily Black lets you change the line length so it's not an issue.
297 comments
[ 3.1 ms ] story [ 292 ms ] threadChange 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.
https://github.com/psf/black/issues/2798
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!
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)
Can someone explain this to me? Why would you ever prefer " over ' in a language where both can be used equally?
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.
compared to this, if single quotes were enforced: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.
compared toWhy? 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:
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.
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...
https://prettier.io/docs/en/option-philosophy.html
— 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.
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.
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.
This would be more readable -- put the space around the structure, not inside it:
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.
https://black.readthedocs.io/en/stable/the_black_code_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`
[1] https://prettier.io/ [2] https://github.com/google/google-java-format
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.
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...
Don't @ me.
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.
https://en.m.wikipedia.org/wiki/Law_of_triviality
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.
[0]:https://www.norvig.com/21-days.html
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.
Loosely related - This is Python pip. Trail of Bits has a tool pip-audit that audits Python environments and dependency trees for known vulnerabilities.
https://github.com/trailofbits/pip-audit
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.
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.
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.
https://usort.readthedocs.io
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.
https://ufmt.readthedocs.io
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.
I typed a hundred tabs
You go back to space and I go back to black
awesome reference!