yapf icon indicating copy to clipboard operation
yapf copied to clipboard

Settings for forcing/prefering single/double quotes for strings

Open ghost opened this issue 7 years ago • 29 comments

Just a setting so quoting style can be unified across a codebase.

e.g.

for the three strings abc, a'c, a"c

prefer_single_quotes -> 'abc', "a'c", 'a"c' prefer_double_quotes -> "abc", "a'c", 'a"c'

force_single_quotes -> 'abc', 'a\'c', 'a"c' force_double_quotes -> "abc", "a'c", "a\"c"

ghost avatar Apr 28 '17 10:04 ghost

As a useful reference, I use this tool for exactly this: https://github.com/myint/unify

humitos avatar Jun 09 '17 02:06 humitos

I'm always preferring single quote while writing JavaScript, and eslint works well with it.

kxxoling avatar Jun 27 '18 03:06 kxxoling

YAPF doesn't seem to replace triple single quotes with triple double quotes, even though PEP 8 specifies triple double quotes: https://www.python.org/dev/peps/pep-0008/#string-quotes

mscheper avatar Oct 11 '18 19:10 mscheper

Is this feature on the roadmap at all? This really seems like a huge source of inconsistency. Even google internally forces quote symbol rules.

samuela avatar Mar 14 '19 06:03 samuela

Would be really useful. Any progress on this?

radude avatar Jun 30 '19 22:06 radude

Hello!

I would like to communicate that this is also relevant to my interests!

Please implement this!

loganknecht avatar Aug 09 '19 21:08 loganknecht

Thanks for opening this thread. I'm also looking forward to this being implemented.

ianyepan avatar Jan 19 '20 09:01 ianyepan

Bump

willfish avatar Jun 14 '20 17:06 willfish

This is one aspect in which black is superior to yapf. From the relevant portion of the docs:

Black prefers double quotes (" and """) over single quotes (' and '''). It will replace the latter with the former as long as it does not result in more backslash escapes than before. (emphasis added)

It goes further:

Black also standardizes string prefixes, making them always lowercase. On top of that, if your code is already Python 3.6+ only or it's using the unicode_literals future import, Black will remove u from the string prefix as it is meaningless in those scenarios.

fanninpm avatar Jun 17 '20 15:06 fanninpm

Yapf has a philosophy of not changing the source at all, except for whitespace.

You could always format your code with black, then re-format it with yapf. ;) This would also change some backslashes to parenthesized expressions, I think.

PS: pylint looks for the most common type of quotes and then complains when the other is used (except for cases like "'" and '"' which would otherwise be '\'' or "\"").

kamahen avatar Jun 18 '20 17:06 kamahen

You could always format your code with black, then re-format it with yapf. ;)

Well, to be fair that's not at all a bad idea.

ianyepan avatar Jun 19 '20 05:06 ianyepan

Yapf has a philosophy of not changing the source at all

[YAPF] takes the code and reformats it to the best formatting that conforms to the style guide, even if the original code didn't violate the style guide. (from the README)

@kamahen How are these two statements in concord? Does the README need to be changed?

Anyway, I normally use black instead of yapf, but one certain project I'm looking at contributing to has a style guide that dictates the usage of "single quotes for strings, or a double quote if the the string contains a single quote." This is where YAPF can help — by providing a means to specify a certain quote style in a project and to have that style automatically be applied.

fanninpm avatar Jun 19 '20 14:06 fanninpm

From my experiences, black is superior. But I really really love 2-space indentation and black for-the-life-of-me refuse to include that option. Sad.

ianyepan avatar Jun 19 '20 15:06 ianyepan

@fanninpm "How are these two statements in concord? Does the README need to be changed?"

No. Yapf only changes whitespace. It doesn't change quotes; it doesn't reformat comments; it doesn't add/remove backslash; it doesn't insert/remove parentheses.

(I would love it if yapf had some options for doing these things; but I don't have time to do any of them, and Emacs will reformat comments for me.)

Black is fine as long as you don't want any options. I've used pretty-printers like that in the past (Plus), and there are worse things (the Plus pretty-printer was great because my input was on punched cards, so minor edits to the code were much easier if I didn't have to worry about reformatting). I think (but can't remember for sure) that someone wrote a reformatter for BNR Protel; I do remember that we all agreed on a standard format and henceforth there was no religious arguing over code layout standards.

kamahen avatar Jun 19 '20 17:06 kamahen

Yapf has a philosophy of not changing the source at all

[YAPF] takes the code and reformats it to the best formatting that conforms to the style guide, even if the original code didn't violate the style guide. (from the README)

@kamahen How are these two statements in concord? Does the README need to be changed?

We don't allow changes to the token stream. So we don't add, remove, or modify the tokens. This is why we don't allow adding a \-newline or rearranging imports, etc.

Anyway, I normally use black instead of yapf, but one certain project I'm looking at contributing to has a style guide that dictates the usage of "single quotes for strings, or a double quote if the the string contains a single quote." This is where YAPF can help — by providing a means to specify a certain quote style in a project and to have that style automatically be applied.

I've considered adding a feature where people could run their own transforms over the code. Similar to how lib2to3 does it with "fixes". (In fact, it would be exactly like that, because that's what we'll use.) That will allow them to use these transforms, but the onus is on the programmer to ensure it's safe to perform the transformations.

bwendling avatar Jun 19 '20 19:06 bwendling

lib2to3 is going away; don't know if any of the potential successors will have a transformation library. All I've seen so far is that there are a couple of potential successors for parsing.

See https://bugs.python.org/issue40360: lib2to3 is now deprecated and may not be able to fully parse Python 3.10+. CPython encourages using https://libcst.readthedocs.io/ or https://parso.readthedocs.io/

https://github.com/pyga/awpa https://github.com/Instagram/LibCST

LibCST builds on parso. Comparing stars on GitHub:

https://github.com/PyCQA/redbaron : 457 LibCST: 423 parso: 296 awpa: 10

https://bugs.python.org/issue40360#msg367726 and https://bugs.python.org/issue40360#msg367730

kamahen avatar Jun 20 '20 00:06 kamahen

See if 521d61770aa51cc362c679bdd08f46699d243713 helps you with the quotes issue.

bwendling avatar Jun 21 '20 04:06 bwendling

When will this be merged into master and released?

you-n-g avatar Oct 30 '20 01:10 you-n-g

Yeah, what's the state of this? This commit doesn't seem to be in master...

You could always format your code with black, then re-format it with yapf. ;)

Well, to be fair that's not at all a bad idea.

It is a bad idea: Editors can usually call black or yapf for formatting, but not both...

ThiefMaster avatar Mar 17 '21 15:03 ThiefMaster

It is a bad idea: Editors can usually call black or yapf for formatting, but not both...

I beg to differ. I believe it's not impossible to set up a sequence of formatters with specific orders -- I know for a fact Emacs can do this in a breeze.

ianyepan avatar Mar 17 '21 17:03 ianyepan

Yapf has a philosophy of not changing the source at all

This is a well-intentioned philosophy, but YAPF would be a far more useful tool if the philosophy was for this to merely be the default behaviour. I've seen hundreds of hours wasted by devs not being able to find code because of these things, and the resulting formatting arguments. The more that can be enforced by code, saving devs from having to worry about it, the better, IMHO.

mscheper avatar Mar 24 '21 14:03 mscheper

There just needs to be a simple script that follows these rules:

  • Docstrings that will be assigned to a __doc__ attribute should be triple double quoted: e.g.
def func():
    """
    I want my docstrings to look like this
    """
   ...
  • Existing triple quotes that are assigned to a variable or passed to a function as an argument should be converted to triple single quotes. e.g.
import ubelt
text = ubelt.codeblock(
    '''
    This text is meant to be used problematically, so distinguish it from documentation
    ''')
  • Unless the text has a quote character embedded inside it. In that case leave it be. The programmer probably knows what they are doing there.
import ubelt
text = ubelt.codeblock(
    """
    I know what I'm doing here. Please don't escape my single quotes. It would make this ugly!
    """)
  • For regular quotes, similar rules apply. If it is assigned or used it should be single quoted unless there are already quotes in the string.
x = 'mode1'                          # Due to my RSA, it can hurt to type. Single quotes are easier on my hands. I know its a small thing, but I do use them a lot. Extra shift presses add up. 
y = f'"{string_payload}"'  # please don't reformat these
  • For string that are not docstrings, but also not assigned to an attribute or used, double quotes is probably better.

def foo(): """ my docstring # note - single lines are ok for short docstrings """ x = 1 """ This is a multi-line comment, probably containing some sort of ascii drawing, but not a docstring. Use double quotes to indicate it is a comment. """ return x + 1

Anyway, if anyone writes that tool let me know. I'll just run it after yapf. I really don't care if it is a part of it. I just want a configurable quote normalizing script. If someone writes it I can put it on pypi if they need help with that part. (I might write it if nobody else does, I imagine you can at least get 90% of the way there with a Concrete Syntax Tree, or a tool like redbaron, or even ast and some hueristics)

/rant

EDIT: I did write it myself: https://gist.github.com/Erotemic/75618ea970a2af49cd43db1bf61a8ac6

It's not the exact spec I wroteup, but its close, and it got the job done.

Erotemic avatar Sep 08 '21 02:09 Erotemic

Instead of text = ubelt.codeblock(...) why not use the standard Python library's textwrap.dedent()?

Anyway, you can run black or black -S (https://github.com/psf/black) to do some of the transformations that you want, and then run yapf to allow control over the the formatting that black doesn't allow.

kamahen avatar Sep 08 '21 06:09 kamahen

@kamahen because I don't want to have to write .strip('\n') after it every time.

Erotemic avatar Sep 08 '21 21:09 Erotemic

@kamahen: Does your comment have anything to do with quotation marks?

mscheper avatar Dec 02 '21 18:12 mscheper

@mscheper - My comment has to do with transformation libraries - and changing between single and double quotes would be an example of a transformation. As noted elsewhere, yapf only changes whitespace and leaves everything else alone. Other tools, such as black can do other changes, such as changing the quotes or adding/removing backslashes/parentheses.

Any tool that depends on lib2to3 (both yapf and black currently depend on it) is subject to breakage with future changes to Python syntax. (Already we've seen problems with the "walrus" operator, for example)

kamahen avatar Dec 02 '21 19:12 kamahen

Please, just implement this, and make the default adhere to your philosophy. This way we can have amazing Yapf, but with double quotes.

The way I see it:

  • black does it, but is too opinionated
  • yapf is very nice, configurable, but doesn't want to touch the token stream, so no double quotes among others. IMO this is also an opinion. Which is fine, but make it configurable with a default conforming to your philosophy.

So can we ever have a formatter do exactly what we want?

dhensen avatar Jan 16 '23 16:01 dhensen

It seems to me that this is a fair bit of work (which nobody seems to be volunteering to do) and there's a simple work-around: use black to change the quote and then use yapf to make it format the way you want.

kamahen avatar Jan 16 '23 16:01 kamahen

I prefer to use single quotes, and you can use Eslint to configure whether to use single or double quotes by default during front-end development. But there doesn't seem to be a python formatter that can do that yet. Maybe it's a difference in philosophy, which is frustrating.

seele-vollerei-ai avatar Dec 31 '23 15:12 seele-vollerei-ai