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

Using a colon in the property's description, treats the leading text as return type #9273

Open
DevilXD opened this issue May 26, 2021 · 13 comments

Comments

@DevilXD
Copy link

DevilXD commented May 26, 2021

Describe the bug

Using a colon in the property's description, treats the leading text as the return type, breaking documentation.

To Reproduce

import random

class Test:
    @property
    def test(self) -> str:
        """
        Returns one of: ``"Yes"`` or ``No``.
        """
        return random.choice(["Yes", "No"])

Current behavior

https://i.imgur.com/9j01Hu2.png

Expected behavior

https://i.imgur.com/ea0PYae.png
(Note: I've modified the HTML file manually to include the colon here, just to show how I imagined it should look like)

Test project

Test.zip

Environment info

  • OS: Win7x64
  • Python version: 3.8.8x64
  • Sphinx version: Originally discovered in 3.5.4, still persists after upgrading to 4.0.2
  • Sphinx extensions: autodoc and napoleon
  • Extra tools: None
@tk0miya
Copy link
Member

tk0miya commented May 29, 2021

It seems you're using the napoleon module. So you should use numpydoc style or google style docstring. But your docstring does not match either.

@DevilXD
Copy link
Author

DevilXD commented May 29, 2021

I don't get it. I know I'm using napoleon, but even then, each docstring starts with a description - what do you mean "does not match either"? Are the headers like Returns or Parameters or Arguments required?

This issue appears only for properties, functions and class description work fine:

Code
Documentation

This is a bug in the napoleon module, which incorrectly considers everything before the colon as the return type.

@tk0miya
Copy link
Member

tk0miya commented May 30, 2021

If my understanding correct, Google style recommends to describe the attributes and properties of the class at the "Attribute" section of the class docstring: https://numpydoc.readthedocs.io/en/latest/format.html#documenting-classes

Note: Numpydoc style is also: https://numpydoc.readthedocs.io/en/latest/format.html#documenting-classes

BTW, I found the reason why the napoleon extension considers the leading text before colon as a type.
Since Sphinx-1.4, it supports docstrings for the attributes and properties containing type definitions. It expects the docstring can starts with type and colon.
https://www.sphinx-doc.org/ja/master/usage/extensions/example_google.html#example-google (Please search this page by "@Property")

I guess this is an originated behavior of napoleon, not a bug. (But I feel this is against the style...)

@DevilXD
Copy link
Author

DevilXD commented May 30, 2021

Well, this is quite a bit inconsistent then, as you can see. Also impossible to avoid too, it seems - I tried "escaping" the colon character, but nothing worked. How do I add a description containing a colon to a property now?

@DevilXD
Copy link
Author

DevilXD commented Jun 2, 2021

I thought about using napoleon_google_docstring = False in conf.py, but it didn't appear to work, so I've figured out "a solution" to this - just plug in the return type first, then add description:

str: Returns one of: `"Yes"` or `"No"`.

Still, I feel it's quite inconsistent. It'd be nice to have a way to escape the colon, or some other way of telling napoleon that this is part of a description, not documentation syntax.

@ailin-nemui
Copy link

I'm having the same issue. Example code 1:

    def is_thing(self) -> bool:
        """Determines if this expression is the built in class owl:Thing.

        Returns:
            True if this expression is owl:Thing
        """

The result looks like:

Returns
Thing
Return type
True if this expression is owl

Since I'm using type annotations, I do not want to specify the type.

Example code 2:

Thing: Final = make_thing()  #: The OWL Class corresponding to owl:Thing

The result looks like

Thing

Type
The OWL Class corresponding to owl

Can I escape the colon somehow?

@DevilXD
Copy link
Author

DevilXD commented Jul 2, 2021

@ailin-nemui Your best bet is to use bool: before the description. Yes, documentation needs to be kept up to date with type annotations anyway, so that's the only working, non-hacky solution I've found.

@tristanlatr
Copy link

tristanlatr commented Sep 29, 2021

Hello,

I share your point of view in the sense that we should be able to use a commas in the first line of a free form description of an attribute/property. It’s currently impossible because the Napoleon (this version) do not have the concept of what’s a valid type specification and what’s not.

My proposal to solve this issue is similar to what I proposed in #7077, meaning, checking if the string before the column is a valid type, if so, then we consider it as the type, if not, it’s simply part of the description.

For the implementation part, I link here a version of Napoleon extension that wraps the type specification inside a new object: TypeDocstring and provides a manner to check wether a string is a valid type: https://github.com/tristanlatr/pydoctor/blob/6b3f23b791704ef2639bfa0b2d9d9efb0e621c78/pydoctor/napoleon/docstring.py#L91

Review the tests for the type specification here: https://github.com/tristanlatr/pydoctor/blob/6b3f23b791704ef2639bfa0b2d9d9efb0e621c78/pydoctor/test/test_napoleon_docstring.py#L84

Tell me what you think. Thanks

@hamidomar000m
Copy link

@DevilXD and @ailin-nemui i had the same problem and fixed it by adding : before the description as below:
"""Determines if this expression is the built in class owl:Thing.

    Returns:
        :True if this expression is owl:Thing
    """

@bbrk24
Copy link

bbrk24 commented Jul 28, 2023

I ran into this in a way that I didn't expect at all. The docstring is

"""Date and time of the collection in UTC (YYYY-MM-DDTHH:MM:SS)"""

and it rendered this:

image

Beyond the fact that this is obviously wrong, I didn't know something could have multiple types. Because it has multiple types, adding the type annotation to the docstring doesn't fix anything, it just adds the correct type to the top of the list.

There are two workarounds that I've found.

  1. Add : : to the beginning of the docstring, as
    """: :Date and time of the collection in UTC (YYYY-MM-DDTHH:MM:SS)"""
    This is completely unintuitive and looks bizarre in the source.
  2. Mark the date format as code, i.e.
    """Date and time of the collection in UTC (``YYYY-MM-DDTHH:MM:SS``)"""
    The date format is now rendered as monospace text on a gray background, but at least the description is readable.

@picnixz
Copy link
Member

picnixz commented Jul 29, 2023

I'm confused because I cannot reproduce your issue @bbrk24. Can you provide me the whole docstring together with its context please?

Nevermind, I checked the docstring outside of a @property.

EDIT:

With this minimal example:

class HH: pass
class MM: pass
class SS: pass

class A:
   @property
   def a(self):
       """List of HH:MM:SS strings."
       return []

we have no way to understand that List of HH does not refer to the type List[HH]. The best approach is to allow users to explicitly escape colons to avoid such situations and we would just ignore escaped colons, namely:

class A:
   @property
   def a(self):
       """List of HH\:MM\:SS strings."
       return []

would render without a type.

@bbrk24
Copy link

bbrk24 commented Jul 29, 2023

The best approach is to allow users to explicitly escape colons to avoid such situations and we would just ignore escaped colons, namely:

class A:
   @property
   def a(self):
       """List of HH\:MM\:SS strings."
       return []

Yeah, I tried something like that at first, but using r""" instead of """ -- that way, the backslashes are preserved. I didn't record the error message but I think I did get a warning about unexpected backslashes.

@picnixz
Copy link
Member

picnixz commented Jul 29, 2023

Actually, it was not a fix for you. It was an example of what would be ideal in the best world xD

rv-jenkins pushed a commit to runtimeverification/k that referenced this issue Jul 19, 2024
…perly (#4535)

Fix: Pi-Squared-Inc/pi2#1644

Unfortunately, Napoleon extensions can't escape `:` and treat everything
before it as a type thus, the rendering of this example was outputting a
wrong and malformed description of the function as shown below:
![Captura de Tela 2024-07-19 às 10 01
18](https://github.com/user-attachments/assets/2091230d-dd0f-4575-9308-515ffbf12041)

As this isn't a key feature description, we chose to remove it to get
cleaner documentation:
![Captura de Tela 2024-07-19 às 10 04
41](https://github.com/user-attachments/assets/d203151b-38d9-45db-8e57-3993e8b7d1ee)


This is a known issue discussed here:
sphinx-doc/sphinx#9273
@AA-Turner AA-Turner modified the milestones: 7.x, 8.x Jul 20, 2024
@AA-Turner AA-Turner removed this from the 8.x milestone Jan 12, 2025
@AA-Turner AA-Turner added this to the some future version milestone Jan 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants