classification
Title: PEP 498: docstrings as f-strings
Type: behavior Stage: resolved
Components: Documentation Versions: Python 3.7, Python 3.6
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: docs@python Nosy List: JockeTF, Mariatta, docs@python, eric.smith, gvanrossum, martin.panter, ned.deily, python-dev, rhettinger, serhiy.storchaka, terry.reedy, yselivanov
Priority: normal Keywords:

Created on 2016-11-18 20:43 by yselivanov, last changed 2017-03-31 16:36 by dstufft. This issue is now closed.

Files
File name Uploaded Description Edit
fstring-no-docstring.patch serhiy.storchaka, 2016-11-26 20:46 review
Pull Requests
URL Status Linked Edit
PR 592 merged Mariatta, 2017-03-10 07:02
PR 600 merged Mariatta, 2017-03-10 16:59
PR 552 closed dstufft, 2017-03-31 16:36
Messages (28)
msg281166 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2016-11-18 20:43
Can f-strings be used as docstrings?

Right now:

    class Foo:
       f'spam'
    Foo.__doc__ is None

I couldn't find that f-strings cannot be used as docstrings in neither PEP 498 not in the 3.6 documentation, so I suppose this is a bug.
msg281167 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2016-11-18 20:58
As you've seen, the answer is "no"!

We'd need to add logic to evaluate them at function definition time. That would be a slight noticeable change, if the expressions had side effects.
msg281168 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-11-18 21:23
There was a bit of discussion at the top of <https://bugs.python.org/issue25179#msg254298>.

IMO it would be simpler do disallow all f-strings as docstrings. Otherwise, what would the result of this be:

name = "module level"
class C:
    name = "class level"
    def m(self, name="default param"):
        f"{name}"
msg281172 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2016-11-18 21:41
> IMO it would be simpler do disallow all f-strings as docstrings.

How exactly you want to disallow them?  Raise SyntaxError?  If you don't raise anything, then the behaviour is just confusing -- the interpreter parses them, but __doc__ is None.

I think this needs to be fixed.  Eric, can we still fix this in 3.6?  If not, then we need to update the PEP and the docs.
msg281174 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-11-18 22:14
Actually, testing your code fragment, it seems you do get a doc string when the f-string has no substitutions in curly brackets, otherwise you don’t get any doc string. Maybe this is due to how different forms of string are compiled.

>>> class Foo:
...    f'spam'  # Compiled as plain 'spam'
... 
>>> Foo.__doc__
'spam'
>>> class Foo:
...     'spam' f'{"MMM"}'  # Compiled as f'spam{"MMM"}'
... 
>>> Foo.__doc__ is None
True
msg281175 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2016-11-18 22:19
Having an unassigned f-string as the first statement is still valid syntax, so could at most be a warning, not a SyntaxError.
msg281182 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2016-11-19 00:16
It's Ned's call, but I wouldn't recommend changing this in 3.6, at least not 3.6.0.

As Martin points out, the reason f'foo' is a "normal" string has to do with how strings and f-strings are assembled and concatenated.

Similarly:
'foo' f'bar' 'baz'
is a normal string, 'foobarbaz'.

I can't think of another place that requires a "normal" string, but if they exist, they'd be affected by this, too.
msg281186 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2016-11-19 00:57
Might I point out the precedent of b-strings? Those also don't contribute
to __doc__.
msg281188 - (view) Author: Ned Deily (ned.deily) * (Python committer) Date: 2016-11-19 01:11
Since this was previously discussed and rejected (in Issue25179), I don't think we should revisit this now for 3.6, other than potentially a documentation tweak.
msg281740 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-11-25 22:00
Much of this discussion seems to duplicate and effectively re-open of #25179, wherein it was decided/accepted that true, non-degenerate, non-trivial, non-constant, f-strings that actually do formatting are not constants and do not and should not become docstrings.  I agree.  I think this issue should either be closed as 'not a bug' or redefined as a doc issue.

It was noted by Martin P. in #25179 that "a constant f-string without any interpolations does become a doc string."  That is because such is really a string literal and not really an f-string, in the same sense that 'circle of radius 0' is really a point and not a circle.

The current glossary entry is

"docstring
    A string literal which appears as the first expression in a class, function or module. While ignored when the suite is executed, it is recognized by the compiler and put into the __doc__ attribute of the enclosing class, function or module. Since it is available via introspection, it is the canonical place for documentation of the object."

I suggest adding "Bytestring literals and non-trivial f-strings do not become docstrings." as the second sentence.
msg281755 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2016-11-26 06:10
[TJR]
> I think this issue should either be closed as 'not a bug' 
> or redefined as a doc issue.

I concur.  

FWIW, here are some comparisons.  
Not allowed:

   'Not counted as' + ' a docstring'
   'Not a docstring ' * 10
   b'Also not a docstring'

Allowed:

   'This is a ' 'docstring'
   r'This is a docstring'
msg281756 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2016-11-26 06:24
I don't really care that much, but I personally think that it would be more consistent (and a simpler rule) if *no* f-string (not even ones without substitutions) were to be allowed as docstrings.

In all other examples that Raymond shows it's the syntactic form that matters -- no on b-strings, yes on r-strings, yes on concatenation (using space), no on +, etc.

The language reference clearly defines f-strings as all strings with an f-prefix, and says that they *may* contain replacement fields.  So it's clear that an f-string without replacements is still an f-string, and it is still distinguished from other strings.  Hence I think it should not be allowed as a docstring.

(Also, what purpose could using the f-prefix for a docstring possibly have?  All the other allowable combinations do have a use.)
msg281759 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-11-26 08:23
Adding more confusion, the expression ``('This is a docstring')`` is accepted as a docstring despite the fact that it is not a string literal.

The cases f'string' and ('string') looks similar to me. Both are simple expressions that become indistinguishable from string literals due to some optimization at parser level. It would be nice to disallow them as docstrings, but it may be not easy to do.
msg281786 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2016-11-26 17:47
OK, clearly the code that sets __doc__ is too closely tied to the generated
code (or to the reduced AST used to generate code). I still think code that
uses any of these is on thin ice and should expect to be broken in the
future.
msg281799 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-11-26 20:33
I withdraw my previously suggested addition to the Docstring glossary entry (msg281740).  It implies that trivial f-strings are acceptable and I agree that other implementations and future Cpython should be free to strictly follow the literal meaning of the first sentence: docstring = initial string literal expression.

I suggest instead that 'string literal' in the first sentence link to https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals.  This would make it clearer that 'string literal' is being used the the Python technical sense rather than in any more informal English sense.

We could possibly add a version of what Guido said above, such as: "(Acceptance of anything other than a string literal as a docstring is an implementation accident and should not be relied upon.)"
msg281800 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-11-26 20:46
Proposed patch makes f-strings not be accepted as docstrings. It also disallow f-strings in ast.literal_eval().
msg281801 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2016-11-26 21:00
I think such a patch is fine -- for 3.6.1.

Also note that linking to the definition of "string literal" is
insufficient, assuming we will want to continue supporting literal
concatenation (
https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation).
(And I want to, because I can see a use case.)
msg281808 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-11-27 01:22
I considered concatenated string literals to be included in 'string literal'.  If that is not obvious, then it should be made so.  Replace 'string literal' with 'string literal or concatenated strings literals' and link each part to their respective (and successive) sections.
msg281810 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2016-11-27 05:19
I was just noticing that the formal grammar in the reference manual first
defines a single string literal and then separately describes concatenation.
msg282910 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2016-12-11 07:54
Eric, could you please make a review of the patch?
msg282924 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2016-12-11 15:20
It looks good to me, save for one tiny issue. I left a review comment.
msg282934 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2016-12-11 17:39
New changeset 30341d5c1423 by Serhiy Storchaka in branch '3.6':
Issue #28739: f-string expressions no longer accepted as docstrings and
https://hg.python.org/cpython/rev/30341d5c1423

New changeset 8e0f147dfa3d by Serhiy Storchaka in branch 'default':
Issue #28739: f-string expressions no longer accepted as docstrings and
https://hg.python.org/cpython/rev/8e0f147dfa3d
msg287628 - (view) Author: Joakim Soderlund (JockeTF) Date: 2017-02-12 00:40
I got slightly confused here while playing around.

Python 3.6.0 (default, Jan 31 2017, 11:39:39) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class Huacaya:
...   f"""Huacaya!"""
... 
>>> class Suri:
...   f"""{'Suri!'}"""
... 
>>> Huacaya.__doc__ is None
False
>>> Suri.__doc__ is None
True

At first I thought f-strings *did* work as docstrings since it worked  just fine for the first class. But, the docstring suddenly vanished when putting an actual expression into it.
msg289338 - (view) Author: Mariatta (Mariatta) * (Python committer) Date: 2017-03-10 07:07
Hi, I updated the documentation mentioning that f-strings cannot be used as docstring. Please review it.
Thanks.
msg289397 - (view) Author: Mariatta (Mariatta) * (Python committer) Date: 2017-03-10 17:58
Thanks for reviewing, Serhiy and Eric. Documentation has been updated and backported to 3.6.

OK to close this issue?
msg289398 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2017-03-10 18:08
Yes, I think it can be closed. Thanks!
msg290241 - (view) Author: Mariatta (Mariatta) * (Python committer) Date: 2017-03-24 22:36
New changeset ff6f3716279e75b2519133a82b9de0c3601963d9 by Mariatta in branch '3.6':
bpo-28739: Document that f-strings cannot be used as docstring (GH-592) (GH-600)
https://github.com/python/cpython/commit/ff6f3716279e75b2519133a82b9de0c3601963d9
msg290242 - (view) Author: Mariatta (Mariatta) * (Python committer) Date: 2017-03-24 22:37
New changeset d4e89287b397c7382c12d3f3d9fd901fd8243b3c by Mariatta in branch 'master':
bpo-28739: Document that f-strings cannot be used as docstring (GH-592)
https://github.com/python/cpython/commit/d4e89287b397c7382c12d3f3d9fd901fd8243b3c
History
Date User Action Args
2017-03-31 16:36:13dstufftsetpull_requests: + pull_request885
2017-03-24 22:37:02Mariattasetmessages: + msg290242
2017-03-24 22:36:50Mariattasetmessages: + msg290241
2017-03-10 18:12:56Mariattasetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2017-03-10 18:08:55eric.smithsetmessages: + msg289398
2017-03-10 17:58:02Mariattasetmessages: + msg289397
2017-03-10 16:59:50Mariattasetpull_requests: + pull_request494
2017-03-10 07:07:48Mariattasetstage: needs patch -> patch review
2017-03-10 07:07:17Mariattasetnosy: + Mariatta
messages: + msg289338
2017-03-10 07:02:39Mariattasetpull_requests: + pull_request487
2017-02-12 00:40:00JockeTFsetnosy: + JockeTF
messages: + msg287628
2016-12-11 17:41:59serhiy.storchakasetnosy: + docs@python
assignee: docs@python
components: + Documentation, - Interpreter Core
keywords: - patch
stage: patch review -> needs patch
2016-12-11 17:39:56python-devsetnosy: + python-dev
messages: + msg282934
2016-12-11 15:20:02eric.smithsetmessages: + msg282924
2016-12-11 07:54:15serhiy.storchakasettype: behavior
stage: patch review
messages: + msg282910
versions: + Python 3.6
2016-11-27 05:19:38gvanrossumsetmessages: + msg281810
2016-11-27 01:22:46terry.reedysetmessages: + msg281808
2016-11-26 21:00:10gvanrossumsetmessages: + msg281801
2016-11-26 20:46:26serhiy.storchakasetfiles: + fstring-no-docstring.patch
keywords: + patch
messages: + msg281800
2016-11-26 20:33:54terry.reedysetmessages: + msg281799
2016-11-26 17:47:45gvanrossumsetmessages: + msg281786
2016-11-26 08:23:21serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg281759
2016-11-26 06:24:28gvanrossumsetmessages: + msg281756
2016-11-26 06:10:03rhettingersetnosy: + rhettinger
messages: + msg281755
2016-11-25 22:00:36terry.reedysetnosy: + terry.reedy
messages: + msg281740
2016-11-19 01:11:30ned.deilysetnosy: + ned.deily

messages: + msg281188
versions: - Python 3.6
2016-11-19 00:57:10gvanrossumsetmessages: + msg281186
2016-11-19 00:16:11eric.smithsetmessages: + msg281182
2016-11-18 22:19:45martin.pantersetmessages: + msg281175
2016-11-18 22:14:12martin.pantersetmessages: + msg281174
2016-11-18 21:41:08yselivanovsetmessages: + msg281172
2016-11-18 21:23:44martin.pantersetmessages: + msg281168
2016-11-18 20:58:25eric.smithsetmessages: + msg281167
2016-11-18 20:43:51yselivanovcreate