Is it possible to have a Python docstring calculated? I have a lot of repetitive things in my docstrings, so I'd like to either use f-strings or a %-style format expression.
When I use an f-string at the place of a docstring
importing the module invokes the processing
but when I check the __doc__ of such a function it is empty
sphinx barfs when the docstring is an f-string
I do know how to process the docstrings after the import, but that doesn't work for object 'doc' strings which is recognized by sphinx but is not a real __doc__'s of the object.
Docstrings in Python must be regular string literals.
This is pretty easy to test - the following program does not show the docstring:
BAR = "Hello world!"
def foo():
f"""This is {BAR}"""
pass
assert foo.__doc__ is None
help(foo)
The Python syntax docs say that the docstring must be a "string literal", and the tail end of the f-string reference says they "cannot be used as docstrings".
So unfortunately you must use the __doc__ attribute.
However, you should be able to use a decorator to read the __doc__ attribute and replace it with whatever you want.
Related
I've just started getting into adding docstrings to my classes/methods and I'm having difficulty in formatting them such that they are easily readable when printed. Some of the lines within the docstrings are long enough to wrap around on my IDE, and when I print the docstring in the console there are large gaps of whitespace in these breaks. Additionally, I would like to maintain a consistent indent scheme throughout the docstring, but these linebreaks violate it by forcing lines to print with not indent.
Are there certain best practices to docstring writing that I'm ignoring? Are there ways to print large strings such that formatting is respected?
Hope this makes sense, thanks.
Normally you use the help utility for viewing docstrings, it deals with inconsistency in whitespace:
>>> def test():
""" first line
HELLO THERE#
ME TOO
DOC STRING HERE
"""
return 1
>>> help(test)
Help on function test in module __main__:
test()
first line
HELLO THERE#
ME TOO
DOC STRING HERE
>>> def test2():
"""
DOC string
text here"""
return 5
>>> help(test2)
Help on function test2 in module __main__:
test2()
DOC string
text here
So while you can refer to PEP 8 for usual conventions, you can also just decide what format you like and just try to be consistent within your application.
I have a function that starts like this:
def apply_weighting(self, weighting):
"""
Available functions: {}
""".format(weightings)
What I want is for the docstring to print the dictionary of available weighting functions. But when inspecting the function it states that there are no docstring available:
In [69]: d.apply_weighting?
Type: instancemethod
String Form:<bound method DissectSpace.apply_weighting of <dissect.DissectSpace instance at 0x106b74dd0>>
File: [...]/dissect.py
Definition: d.apply_weighting(self, weighting)
Docstring: <no docstring>
How come? Is it not possible to format a docstring?
The Python interpreter looks for string literals only. Adding a .format() method call is not supported, not for the function definition syntax. It is the compiler that parses out the docstring, not the interpreter, and any variables like weightings are not available at that time; no code execution takes place at this time.
You can always update a docstring after the fact:
def apply_weighting(self, weighting):
"""
Available functions: {}
"""
apply_weighting.__doc__ = apply_weighting.__doc__.format(weightings)
I have a module, errors.py in which several global constants are defined (note: I understand that Python doesn't have constants, but I've defined them by convention using UPPERCASE).
"""Indicates some unknown error."""
API_ERROR = 1
"""Indicates that the request was bad in some way."""
BAD_REQUEST = 2
"""Indicates that the request is missing required parameters."""
MISSING_PARAMS = 3
Using reStructuredText how can I document these constants? As you can see I've listed a docstring above them, but I haven't found any documentation that indicates to do that, I've just done it as a guess.
Unfortunately, variables (and constants) do not have docstrings. After all, the variable is just a name for an integer, and you wouldn't want to attach a docstring to the number 1 the way you would to a function or class object.
If you look at almost any module in the stdlib, like pickle, you will see that the only documentation they use is comments. And yes, that means that help(pickle) only shows this:
DATA
APPEND = b'a'
APPENDS = b'e'
…
… completely ignoring the comments. If you want your docs to show up in the built-in help, you have to add them to the module's docstring, which is not exactly ideal.
But Sphinx can do more than the built-in help can. You can configure it to extract the comments on the constants, or use autodata to do it semi-automatically. For example:
#: Indicates some unknown error.
API_ERROR = 1
Multiple #: lines before any assignment statement, or a single #: comment to the right of the statement, work effectively the same as docstrings on objects picked up by autodoc. Which includes handling inline rST, and auto-generating an rST header for the variable name; there's nothing extra you have to do to make that work.
As a side note, you may want to consider using an enum instead of separate constants like this. If you're not using Python 3.4 (which you probably aren't yet…), there's a backport.enum package for 3.2+, or flufl.enum (which is not identical, but it is similar, as it was the main inspiration for the stdlib module) for 2.6+.
Enum instances (not flufl.enum, but the stdlib/backport version) can even have docstrings:
class MyErrors(enum.Enum):
"""Indicates some unknown error."""
API_ERROR = 1
"""Indicates that the request was bad in some way."""
BAD_REQUEST = 2
"""Indicates that the request is missing required parameters."""
MISSING_PARAMS = 3
Although they unfortunately don't show up in help(MyErrors.MISSING_PARAMS), they are docstrings that Sphinx autodoc can pick up.
If you put a string after the variable, then sphinx will pick it up as the variable's documentation. I know it works because I do it all over the place. Like this:
FOO = 1
"""
Constant signifying foo.
Blah blah blah...
""" # pylint: disable=W0105
The pylint directive tells pylint to avoid flagging the documentation as being a statement with no effect.
This is an older question, but I noted that a relevant answer was missing.
Or you can just include a description of the constants in the docstring of the module via .. py:data::. That way the documentation is also made available via the interactive help. Sphinx will render this nicely.
"""
Docstring for my module.
.. data:: API_ERROR
Indicates some unknown error.
.. data:: BAD_REQUEST
Indicates that the request was bad in some way.
.. data:: MISSING_PARAMS
Indicates that the request is missing required parameters.
"""
You can use hash + colon to document attributes (class or module level).
#: Use this content as input for moo to do bar
MY_CONSTANT = "foo"
This will be picked up by some document generators.
An example here, could not find a better one: Sphinx document module properties
the following worked for me with Sphinx 2.4.4:
in foo.py :
API_ERROR = 1
"""int: Indicates some unknown error."""
then to document it:
.. automodule:: foo.py
:members:
I think you're out of luck here.
Python don't support directly docstrings on variables: there is no attribute that can be attached to variables and retrieved interactively like the __doc__ attribute on modules, classes and functions.
Source.
The Sphinx Napoleon Python documentation extension allows to document module-level variables in an Attributes section.
Per https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html :
Attributes
----------
module_level_variable1 : int
Module level variables may be documented in either the ``Attributes``
section of the module docstring, or in an inline docstring immediately
following the variable.
Either form is acceptable, but the two should not be mixed. Choose
one convention to document module level variables and be consistent
with it.
Writing only because I haven't seen this option in the answers so far:
You can also define your constants as functions that simply return the desired constant value when called, so for example:
def get_const_my_const() -> str:
"""Returns 'my_const'."""
return "my_const"
This way they'll be a bit "more constant" on one hand (less worrying about reassignment) and they'll also provide the opportunity for regular documentation, as with any other function.
I am using Python's dir() function to determine what attributes and methods a class has.
For example to determine the methods in wx.Frame, I use dir(wx.Frame)
Is there any command to determine the list of arguments for each method? For example, if I want to know what arguments belong to wx.Frame.CreateToolBar().
As mentioned in the comments, you can use help(fun) to enter the help editor with the function's signature and docstring. You can also simply use print fun.__doc__ and for most mature libraries you should get reasonable documentation about the parameters and the function signature.
If you're talking about interactive help, consider using IPython which has some useful extras. For instance you could type %psource fun to get a printout of the source code for the function fun, and with tab completion you could just type wx.Frame. and then hit TAB to see a list of all of the methods and attributes available within wx.Frame.
Even though GP89 seems to have already answered this question, I thought I'd jump in with a little more detail.
First, GP89's suggestion was the use Python's built-in help() method. This is a method you can use in the interactive console. For methods, it will print the method's declaration line along with the class' docstring, if it is defined. You can also access this with <object>.__doc__ For example:
>>> def testHelp(arg1, arg2=0):
... """This is the docstring that will print when you
... call help(testHelp). testHelp.__doc__ will also
... return this string. Here is where you should
... describe your method and all its arguments."""
...
>>> help(testHelp)
Help on function testHelp in module __main__:
testHelp(arg1, arg2=0)
This is the docstring that will print when you
call help(testHelp). testHelp.__doc__ will also
return this string. Here is where you should
describe your method and all its arguments.
>>>
However, another extremely important tool for understanding methods, classes and functions is the toolkit's API. For built-in Python functions, you should check the Python Doc Library. That's where I found the documentation for the help() function. You're using wxPython, whose API can be found here, so a quick search for "wx.Frame api" and you can find this page describing all of wx.Frame's methods and variables. Unfortunately, CreatteToolBar() isn't particularly well documented but you can still see it's arguments:
CreateToolBar(self, style, winid, name)
Happy coding!
From the 2.7.2 docs, Section 6, Modules:
Passing two -O flags to the Python interpreter (-OO) will cause the bytecode compiler to perform optimizations that could in some rare cases result in malfunctioning programs. Currently only __doc__ strings are removed from the bytecode, resulting in more compact .pyo files.
This got my attention:
Since some programs may rely on having these available, you should only use this option if you know what you’re doing.
Are there any cases where removing a script's docstrings might logically break some dependency or other aspect of a code's functionality, disregarding any syntactic errors?
EDIT
Why would removing comments break a help statement? It doesnt seem to do so in the interpreter.
>>> help('import_pi')
Help on module import_pi:
NAME
import_pi
FILE
/home/droogans/py/import_pi.py
FUNCTIONS
print_pi()
DATA
pi = 3.1415926535897931
>>> import import_pi()
>>> import_pi.__doc__
>>>
>>> print import_pi.print_pi.__doc__
Convert a string or number to a floating point number, if possible.
For example ply is a module that does lexing and parsing which uses docstrings to describe the grammar. Stripping docstrings would break the code.
The -OO option only affects whether a doc string is stored -- it does not affect parsing. For example the following code works with and without optimizations enabled:
def f():
'Empty docstring'
assert f() is None
The programs that will break with the docstring optimization enabled are ones that rely on the contents of the docstring. Paul Hankin mentioned Ply which is tool that uses docstrings for its dispatch logic. Another example is the doctest module which uses the contents of docstrings for tests.
Here's a simple example of code that won't work with the -OO optimization enabled:
def f():
'30 + 40'
return eval(f.__doc__)
print f()
Note help() will still work with the -OO optimization enabled, but it will only find the function name, arguments, and module, but not the docstring:
>>> help(f)
Help on function f in module __main__:
f()