Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single quotes option #118

Closed
bofm opened this issue Apr 9, 2018 · 72 comments
Closed

Single quotes option #118

bofm opened this issue Apr 9, 2018 · 72 comments
Labels
T: style What do we want Blackened code to look like?

Comments

@bofm
Copy link

bofm commented Apr 9, 2018

Hi! Although Black now prefers doubles, can we have an option to keep single quotes? Forcing double quotes would make this great project unusable for many users who picked the rule of using single quotes.

Operating system: MacOS
Python version: 3.6
Black version: 18.4a0
Does also happen on master: yes

@gaggle
Copy link

gaggle commented Apr 9, 2018

I'm not a maintainer just an interested user, I respectfully voted down because I think black's power is to annihilate all these small discussions forever. Out of curiosity are there objective reasons that you need to stick with single-quotes?

@bofm
Copy link
Author

bofm commented Apr 9, 2018

are there objective reasons that you need to stick with single-quotes?

It is an approved code style I have to use at work. There are millions of lines of code with single quotes in the existing code base which are not going to be reformatted. I believe this is also the case for other people.

@ambv
Copy link
Collaborator

ambv commented Apr 9, 2018

Please discuss the approved code style at work, Black's documentation is using several arguments as to why double quotes are preferred.

If you have strong reasons to prefer single quotes, list them here. "Approved code style" is not a reason alone.

@bofm
Copy link
Author

bofm commented Apr 9, 2018

The reasons to add single quotes options:

  • Black is unusable when contributing to an existing project written with single quotes
  • Python official documentation uses single quotes in code examples
  • default repr() produces single-quoted string literals for most standard types (dict, list, tuple, str, bytes, namedtuple, etc)
  • many popular projects and their docs use single quotes
  • PEP proposals mostly use single quotes in code examples
  • Guido used single quotes in his latest commits on Github

Let me emphasize - the point is that restricting the quotes variants to only double quotes makes this cool project unusable for a big part of Python programmers.

@ambv
Copy link
Collaborator

ambv commented Apr 9, 2018

All your reasons can be summarized like this: "Black shouldn't have an opinion because other projects don't have an opinion."

This is an appeal to authority and as such doesn't give us anything actionable to discuss.

I also don't buy the argument that this makes it "unusable for a big part of Python programmers". Why? The code is going to still work, programmers may even continue writing their code with single quotes (and let Black convert it as needed).

Note that Black is using a variant of wrapping lines with brackets that isn't even covered as an option in PEP 8. Does this make Black unusable?

@bofm
Copy link
Author

bofm commented Apr 9, 2018

What if a project has an opinion but a different one? Is Black’s intention to change opinions or to be a helpful tool?

@gaggle
Copy link

gaggle commented Apr 9, 2018

That is a false equivalence @bofm, projects can obviously be opinionated and be helpful. But it may be black isn't for you, no big harm in that right?

For what its worth I don't agree with all black does, but honestly, formatting is such a small pain that I'm 100% ready to outsource the entire concept and accept whatever the community comes up with. It beats hours of bikeshedding. StandardJS has a lot of the same forces acting on it in the Javascript world and they've also had to stick to their guns against many who disagree. I use both, and honestly, it's like an hour and its formatting becomes second nature. My pairing-partner and I spent last week with black (I've just activated it as part of CI), and it's fine. Everything is fine. The maintainers of this project listen to reason but not opinions when deciding a direction, what better principles can we really ask for?

As a matter of practicality, if you do want to use black, have you considered not running it against the entire codebase but limit it to specific folders? With a tiered rollout, you can slowly subsume folders instead of having to orchestrate a big all-or-nothing effort.

@kalekseev
Copy link
Contributor

Option for quotes looks like a simple thing to add to black, if a lot of people argue about that why don't? Why we can have width size option but can't have quote option? Even if you look at the pr it was originally with single quotes by default with argument - it's simpler to type and then switched to double quotes because ' char can be added and quotes will be swapped to " (though now if " char added to the string the opposite will happen). Tab width, line width and quotes where the first options that were added to prettier https://prettier.io/docs/en/options.html (though authors claim that it's opinionated code formatter with minimal set of options as black do).

@bofm overall even if black won't accept option and it crucial for your project you can fork black and apply code from #75 when it was using single quote, it shouldn't be hard to maintain at least at this point.

@ambv
Copy link
Collaborator

ambv commented Apr 10, 2018

Black is both a formatter and a code style. One of the core tenets of this project is that all blackened code looks the same. This is why I will never add configurable soft tab width, or identation with hard tabs.

Having options is a burden to the user and a slippery slope to introduce more and more. Case in point: you're already using --line-length as an argument to add something else. The more options, the bigger the need for a configuration file.

We chose to standardize on double quotes because:

  • standardizing on one makes sense; and
  • standardizing on double quotes makes more sense than single quotes.

I mostly wanted the former and didn't care much which quote is going to be the one we choose. Over the course of designing this with @carljm and @zsol, they convinced me that double quotes are a better option. So this is what Black does now. Shouldn't it be reassuring to users to know that what Black does is informed by rational arguments?

I didn't hear any arguments here that would tell me why single quotes are preferable. "This is what we used to do" doesn't work, Black is bound to be disruptive when adopted. "It's easier to type" is something that I myself said and this was debunked (it's not easier on all keyboard layouts, and more importantly you can keep typing whatever you want and Black will convert it for you).

I'll keep this open because maybe somebody will appear and communicate clearly why an option for this is required. Unless it's strictly necessary, Black won't introduce it.

PS. While forking is always an option in a MIT-licensed project, I felt like suggesting this on my issue tracker was hostile. I would appreciate you not doing that again.

@kalekseev
Copy link
Contributor

PS. While forking is always an option in a MIT-licensed project, I felt like suggesting this on my issue tracker was hostile. I would appreciate you not doing that again.

Sorry, your project is great, I appreciate your work and didn't want to harm anyone with my comments.

@ambv ambv added the T: style What do we want Blackened code to look like? label Apr 12, 2018
@ambv
Copy link
Collaborator

ambv commented Apr 12, 2018

Will close this for now. If there's any new evidence of single quotes being preferable over double quotes, we can reopen this and resume discussion.

@ambv ambv closed this as completed Apr 12, 2018
@lordmauve
Copy link

I use single-quoted strings to indicate internal identifiers (eg. dict keys) and double-quoted strings to indicate human-readable text (exception messages and IO).

Roughly if the string matches ^\w+$ I would not enforce double quotes.

@audiolion
Copy link

I think this is a really cool project, I hate double quotes though, and more than just typing double quotes, I don't like reading double quotes, quotes are just noise, and I actually really like javascript where you don't have to use quotes at all for dict keys e.g.

const dict = {
    fruits: ['apple', 'orange'],
    veggies: ['carrot', 'turnip'],
}

so single quote is the closest I can get in python to minimizing that noise. When your editor does syntax highlighting, you can easily see what is a string and what isn't.

I read the entire discussion and know you are highly unlikely to change your mind on this, but I want to still voice my opinion.

@Kristinita
Copy link

1. Another argument

Coupled with @bofl arguments.

Syntax highlighting is corrupted for some text editor syntaxes.

2. Example

I use PythonImproved syntax for Sublime Text.

Part of my SashaPythonImproved.py file:

SITEMAP = {
    'format': 'xml',
    'priorities': {
        'articles': 1,
        'indexes': 0.5,
        'pages': 0.5
    },
    'changefreqs': {
        'articles': 'always',
        'indexes': 'weekly',
        'pages': 'always'
    }
}

Expected

Black format this code to:

SITEMAP = {
    "format": "xml",
    "priorities": {"articles": 1, "indexes": 0.5, "pages": 0.5},
    "changefreqs": {"articles": "always", "indexes": "weekly", "pages": "always"},
}

Actual

Thanks.

@kennethreitz
Copy link

this makes me sad :(

@roganov
Copy link

roganov commented May 17, 2018

Could we please have more discussion about this? This the single pain point that prevents us of adopting black at work :(

@kennethreitz
Copy link

kennethreitz commented May 17, 2018

I'd rather have all the quotes be unified than have them be single quotes. I think this is a reasonable default.

@roganov this is not a reason to not use Black.

@roganov
Copy link

roganov commented May 17, 2018

@kennethreitz For new projects, yes. For existing ones that use single quotes, converting all quotes to double quotes is sometimes is not an option.

@alanhamlett
Copy link

@zsol, why are double quotes better than single quotes?

@ambv
Copy link
Collaborator

ambv commented May 25, 2018

@alanhamlett, is the explanation in the README insufficient?

@alanhamlett
Copy link

Yes, it's insufficient. You should follow Prettier's example and allow configuring this tiny little quote thing instead of blocking massive amounts of teams from using it.

@alanhamlett
Copy link

alanhamlett commented May 25, 2018

I'd rather have all the quotes be unified than have them be single quotes.

I agree, but only within the scope of a project or organization.

Overall, this conversation is bikeshedding and @ambv should just allow configuring quote style.

@ranjanashish
Copy link

Hi @ambv! I totally love black. Thank you so much for this! I, personally, would love it more if using single quotes was configurable (just like line length).

I had wanted to voice my opinion here before as well but didn't really know how to articulate it and provide a reasoning for my choice. But today someone on HN explained it the way I think about using single quotes:

A double-quote is more noisy than a single-quote, and W is more noisy than V.
The difference is that " and ' are equally usable options in the context we're talking about. Quotes are very common, so the visual noise adds up when your screen is full of quote marks. Given that they mean the same thing, and one is both harder to type and harder to read, it makes sense to prefer the other.

Link to the HN comment: https://news.ycombinator.com/item?id=17158110

@bmedicke
Copy link

bmedicke commented May 26, 2018

Double quotes are needlessly noisy. That's easy enough to see when you take a look at two ways to write an empty string: '' vs "".

Plus the python interpreter seems to prefer single quotes:

>>> "string"
'string'

@ambv
Copy link
Collaborator

ambv commented May 26, 2018

To everybody that respectfully voiced their opinion here and voted for some of the existing comments, thank you.

@alanhamlett, please revisit your language choices. Even if you were right in your opinion, the way you voice it makes it hard for others to treat you seriously.

Calling a conversation childish because you disagree with the other side of the argument is unnecessarily escalating the situation. Accusations of "blocking massive amounts of teams" is hyperbole and unfair. Telling unpaid maintainers of an open source project what they "should" do is arrogant. You have no skin in this game and are in no position to demand any action.

With this out of the way, let me summarize my position.

Black as a code style is an attempt at a strict subset of PEP 8 which doesn't leave much up to debate. A "code style: black" badge on a repo should be enough to tell the reader exactly what they can expect from the code inside. The first configurable styling option would be the foot in the door that would be used to demand more configurability. This is why Black will never have an option to choose single quotes over double quotes.

What I'm still pondering is if Black should have an option to omit enforcement of styling of string quotes. That would allow projects to adopt it a bit more incrementally. I'm open to arguments in support of this idea. I mostly worry about getting more requests for options to disable other parts of Black in the future.

@gaggle
Copy link

gaggle commented May 26, 2018

I’m confused by the “double quotes means I can’t use it” statements, if there are concrete arguments (not opinions) or specific use-cases that exemplify this problem I think that’s valuable to bring up in this thread. But, honestly and with respect, I’m not at all persuaded by opinion pieces. “Because it’s our standard”, “I hate double quotes”, “double quotes hurts many teams”, these aren’t arguments. We must be rigorous in our thinking!

My experience with black is that we rolled it out piecemeal, targeting certain folders in one project. After some experimenting the entire project ended up included. And it was fine. I don’t agree to all black’s decisions, none of us at the office did, but we DID agree it’s so much easier to not have bikesheddy formatting discussions.

I respect ambv’s commitment to his original vision of a no-nonsense linter. The javascript community has StandardJS (which also draws ire over its quote choice), I’m above all else happy to see a strong voice emerging for Python and will support that over specific quote style. Thank you for your work, whatever decision you feel is best going forward👌

@ariddell
Copy link

I would love to replace my use of yapf with black. Python is missing a standard code formatter.

I'd like to add a specific argument in favor permitting configuration here (see also @bofm's list above and @kennethreitz 's widely-adopted PEP8 amendment): typing a single quote takes fewer keystrokes when using the standard keyboard layouts in the US, UK, and China. It takes the same number of keystrokes on standard layouts in Germany and France. I know of no keyboard layouts which make it easier to type double quotes.

This is an excellent project. I look forward to seeing it develop.

@zsol
Copy link
Collaborator

zsol commented May 26, 2018

@ariddell that's definitely a reasonable concern that has come up during development. We realized that we can just keep typing single quotes and let black correct it automatically. Would you agree this is a reasonable workflow?

@ambv
Copy link
Collaborator

ambv commented May 29, 2018

@kadrach, this is interesting. Your counting method is invalid though, it counts apostrophes within other strings and comments. Please use an AST.

Could we do Top 1000 instead and only count within unique files?

@kadrach
Copy link

kadrach commented May 29, 2018

@ambv Agreed, I was trying to avoid the work of doing this via an AST. I do wonder how much quotes contained within quotes would affect the outcome. I did deliberately want to include comments as "part of the code".

I'm not sure I understand counting within unique files. I would like to exclude vendored code, but then the problem of how to identify vendored code arises.

@sethmlarson
Copy link
Member

@kadrach Counting only unique files would solve the vendoring problem for the most part as vendored code is usually copied in-place.

@kadrach
Copy link

kadrach commented May 29, 2018

@SethMichaelLarson I'm not quite clear on how to achieve this. How do you determine which project a file is attributed to? Has someproject vendored pip, or has pip vendored someproject? Counting only files unique across all projects would weight the counts heavily, disregarding packages that are more commonly vendored (perhaps pip as an example?).

@sethmlarson
Copy link
Member

sethmlarson commented May 29, 2018

I'm not sure this needs that level of detail, more to protect over-accounting for packages like urllib3 which is commonly vendored and which is also previously vendored by requests which is ALSO commonly vendored. :P

@kadrach
Copy link

kadrach commented May 29, 2018

That's true, but we do need to count e.g. requests individually. If we only use unique files, choices that requests has made will be discounted (given most of the "requests" files will be non-unique and ignored); and requests is likely to be among the top packages.

@ambv
Copy link
Collaborator

ambv commented May 29, 2018

Create a dict where the key is the sha1 of the file content and the value is the file content. Download all packages first while building this dictionary. Later you can use black.lib2to3_parse() to get the CST of the content, subclass black.Visitor to pluck out all strings and check the opening few characters to classify the string.

It doesn't matter which package a file comes from. It's super unlikely for unrelated files to match hash-wise so you're not "discounting" requests, you're just counting it once. In fact, you'll count it more than once since some vendored libs will be outdated. But that's a way better approximation than your first attempt.

@kadrach
Copy link

kadrach commented May 29, 2018

I think I still need to retain a project to file association, to determine a "quote style choice" at project level.

@ambv
Copy link
Collaborator

ambv commented May 29, 2018

No, that would unreasonably bump the value of a "style choice" for projects with small codebases compared to projects with many files. We don't care what a "project" chose, we care what all of the unique source code in the top 1,000 projects is using.

@kadrach
Copy link

kadrach commented May 29, 2018

Weighting by number of files would bump projects with many little files over projects that opted for a smaller number of larger files. That seems unreasonable. Perhaps by number of lines?

My original intent was to figure out what the "unspoken standard" choices of the topmost projects are, not what all of the unique source code is using - I'm not convinced of that measure.

@landtuna
Copy link

The biggest issue for me is that, for the people who use single quotes only as identifiers, running Black on a codebase actually loses information. It's not AST information, but it's information in the sense that a code comment is information.

@ambv
Copy link
Collaborator

ambv commented May 29, 2018

For the people who use single quotes only as identifiers, running Black on a codebase actually loses information.

@landtuna, while I am skeptical if such scheme can be rolled out consistently, I acknowledge this is a problem.

@kbd
Copy link

kbd commented May 30, 2018

The strongest argument in this thread for providing an option to not change quotes for strings (except for docstrings, which should always be """ per PEP 257) is that many people (including Guido) use quote style as a "extra-terse comment" to convey meaning, with single quotes meaning "data" and double quotes meaning "human-readable string".

I checked through my code and found I do the same thing without ever consciously deciding on that. I suspect this is common. I think this is actually why standardizing on double quotes bugged me (and perhaps other people?) so much and I couldn't explain why.

@ambv
Copy link
Collaborator

ambv commented May 30, 2018

@kbd, agreed, this is the most convincing argument for allowing Black to optionally skip normalizing quotes as I suggested a few days back. That would cover all people unhappy with double quote enforcement.

@jgirardet
Copy link
Contributor

you mean something like that ?

['my_key'] = "my string"

instead of

["my_key"] = "my string"

@lig
Copy link

lig commented May 30, 2018

@ambv I'm strongly voting for single quotes as approved code style. I've seen this at a lot of companies and discussed several times at different meetups. It is a widely spread practice to use single quotes for everything that is a code and double quotes for doc strings.

In fact, this is very useful in IDEs and editors where one could differentiate in-code strings and doc strings between each other via defining different coloring for them.

Honestly, I was a bit shocked after black converted all single quotes to double quotes resulting in much less readable code in an IDE.

@kbd
Copy link

kbd commented May 30, 2018

@ambv What do you think about an enforced quote style of "strings containing no whitespace are single-quoted while strings with whitespace get double quotes"? That would be a consistent style (i.e. the same file would always have the same output) that may produce the smallest delta from how many people actually prefer to write Python.

I could definitely see adopting that enforced style, whereas I would personally never want to use forced double-quotes.

@lig
Copy link

lig commented May 30, 2018

@kbd sounds like something that is the best from different worlds. This should work for the case with ' for code, "" for docs and also ' for data, "" for human-readable values most of the time. A nice trick as for me.

@harveyr
Copy link

harveyr commented May 30, 2018

For another data point: My team is about to reformat all our code with black. We've always used single quotes. We've got some very experienced Python folks. Everyone is fine with it.

@gaggle
Copy link

gaggle commented May 30, 2018

@harveyr yeah us too.

I’m fine w. whatever, including a toggle-option that we as a community can possibly discuss and revisit in due time. Perhaps a toggle option really is the suitable solution to not fracture whatever community this project is accumulating.

Still not sure what makes us so different from StandardJS that does insist on a unified quote style 🤷‍♂️ But I also don’t subscribe to the “public strings as double-quotes” strategy, it’s much too fragile for my tastes (I’d push public strings through a translation function before using semantically meaningless quotes)

@ambv
Copy link
Collaborator

ambv commented May 30, 2018

What do you think about an enforced quote style of "strings containing no whitespace are single-quoted while strings with whitespace get double quotes"?

@kbd, I find this curious but too magical :)

@kbd
Copy link

kbd commented May 30, 2018

But I also don’t subscribe to the “public strings as double-quotes” strategy, it’s much too fragile for my tastes (I’d push public strings through a translation function before using semantically meaningless quotes)

The discussion hasn't been about "public" strings, but "human-readable" strings (i.e. natural language vs code). It's not necessarily about user-facing strings. For example, the vast majority of all (non-docstring) quotes in my code are single quotes because most strings in code are data (dictionary keys, names of things, shell values, filenames, etc.), but things like log messages and exception strings get double quotes. As far as "semantically meaningless" goes, many people in this thread have already explained the meaning they assign to different quotes.

I find this curious but too magical :)

Not arguing with you (since that's not an argument ;) but what if that small heuristic corresponds to what most people actually do and expect when reading Python code? What if in practice that results in the least disruption on existing codebases? What if it allows a fully-automated/consistent style that can be used by people who would otherwise reject double quotes everywhere? Would it be worth consideration?

Edit: I'd imagine this formatting would even catch bugs. "Why did this dictionary key / filename get double quotes? Oops there's a space".

@psf psf deleted a comment from razzius May 30, 2018
@ikatson
Copy link

ikatson commented May 30, 2018

One more argument to make it more configurable than it is now, is that "git blame" becomes of less use for older commits, as the majority of the changes black does on our code is changing quote style from single to double

@ambv
Copy link
Collaborator

ambv commented May 30, 2018

@ikatson, agreed. In general, I should add this to the README:

  • you can use git hyper-blame and/or git blame $BLACK_REV^ -- $FILE to skip over the formatting commit

That is useful beyond the string quotes.

@ambv ambv closed this as completed in 8ebbd26 May 30, 2018
@ambv
Copy link
Collaborator

ambv commented May 30, 2018

Resolution: 18.6b0 has --skip-string-normalization, or -S for short. This allows existing projects to adopt Black with less friction and works for all alternative string quotes policies.

Black still defaults to and recommends normalizing string quotes to double quotes everywhere as we believe this is a better default than single quotes, and is enforceable unlike the "single quotes for data, double quotes for human-readable strings" policy.

I hope this resolves to your satisfaction what's been the most controversial issue in Black's history.

@psf psf locked as resolved and limited conversation to collaborators May 30, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
T: style What do we want Blackened code to look like?
Projects
None yet
Development

No branches or pull requests