Adding parameters to module docstrings with Python Sphinx - python

I have a docstring in the beginning of every module describing its usage and functionality. Here I also want to add the most relevant parameters - like settings in a parameter file or via command line arguments. It's no classical function parameters since the module might be called as stand-alone as well (via if __name__ == '__main__' capture). But since the ordinary parameter formatting of Sphinx is neat I want to just re-use it.
However, Sphinx seems to handle the "Parameter" section differently when in a module compared to when in a function.
This is how they are formatted differently:
Parameters in function docstring:
Parameters in module docstring:
You see the difference. In functions the keyword "Parameters" is added and then we have a nice bullet list. In modules no title is created, no list, the type is not set in braces but on an additional line etc.
Docstring format is the same (numpydoc):
Parameters
----------
pars : dict
Parameter dictionary.
key : str
Parameter name.
vs.
Parameters
----------
num_axial_segments : int
The number of axial rotor segments.
magnet_segmentation_method : int
The method of magnet segmentation.
0: Uniform segmentation (all magnets same amount of segments).
Does anyone have an idea why it's handled like this? And what I can do about it?
I would like the parameters in modules output in the same way as in functions.

The style used to render the docstring sections is dependent on the HTML theme you are using with Sphinx.
Does anyone have an idea why it's handled like this?
The reason the styles are different for module and function docstrings, is because it's customary to use a command-line syntax style to document scripts that is different from function signature syntax style . Notice the style you showed for the module docstring is similar to a list of command-line arguments.
I would like the parameters in modules output in the same way as in functions.
Different themes may render module docstrings similarly or differently from function and classe docstrings. You would have to choose a different theme or customize the theme's CSS by copying the style used for functions to the style used for module docstrings.
the type is not set in braces but on an additional line etc.
This is noteworthy because you would expect the napoleon-sphinx extension to not render type and name on different lines as if it were using classic reST syntax instead of Google style or Numpy.
I would recommend trying a different HTML theme or setting the napoleon_use_param , napoleon_use_ivar and napoleon_use_rtype explicitly to see if there's a difference.
And what I can do about it?
The examples given for Google style or Numpy style suggest using docstring sections but that's somewhat oversimplified because command-line style syntax is better illustrated and automated by the way argparse implements it. There are a few extensions meant to ease and automate the process of documenting scripts.
As for the difference in style I wouldn't worry about it (admittedly in the HTML theme you are currently using it doesn't look very good). A command-line invocation of a script or a run-time call of a function are different and accordingly themes may and will render those docstrings sections with visual differences.

Related

Parsing Function names, arguments, return value from python file?

Im trying to get all the function names, with their arguments, and return's of a python file, using python script.
Tried to use AST library with FunctionDef class but couldn't able to extract the information I'm looking for.
Thanks.
This answer recommends the inspect module for getting a list of functions; it can be used (but isn't required) for accessing function parameter names. To the best of my knowledge, Python's design doesn't really allow getting this information about a function's return values; so you might have to annotate those yourself, be it with a docstring, custom attribute, type hint, etc.

Do I need to do type checking when preparing library for open source?

I have I small module that I use inside one of my projects. Now I decided to place it on github so now I am writing some docstrings and cleaning the code.
I have a composition of 2 classes so the initialization looks like this:
foo = Class_1()
bar = Class_2(param1=foo)
I know that the first argument to the Class_2 has to be an instance of Class_1 or the code won't work. But it may be clear only for me as I wrote code of Class_2, but when using module as API it may be unclear for a user that param1 has to be an instance of Class_1. If someone will use bar = Class_2(param1='foo'). The trackback will be bad and it will be impossible to understand what happened. So the question is: do I need to check in my __init__ that isinstance(param1, Class_1) and if no raise an excaption with an appropriate message, or writing good documentation is enough?
This is very opinion-based (not great for StackOverflow in particular) - but in my opinion, you should do both.
On the one hand, using isinstance() and exception-handling are both good defensive-coding practices.
On the other hand, inline documentation is nice. Per the Python developer guide:
The markup used for the Python documentation is reStructuredText, developed by the docutils project, amended by custom directives and using a toolset named Sphinx to post-process the HTML output.
Some IDEs, such as JetBrains PyCharm, are configured to automatically pick up well-formed reST docstrings and perform automated type-checking based on those conventions (which I've found to be really useful). See also: PEP 257 and What is the standard Python docstring format? for details.

Python Docstring: What do these docstring parameters mean exactly?

Can someone tell me the differences between the following docstring parameters?
:type and :param
I've seen both being used to specify the type of method arguments, but I don't think they do exactly the same. Is one of them for the programmer and the other for the IDE or something like that?
:rtype, :return and :returns
Especially :return and :returns seem very similar, so which are to use in which situation?
These conventions are used by the Sphinx documentation tool, which was originally designed for processing Python docs. Its popularity has, however, led it to be extended into other domains, defined in the Sphinx documentation as "a collection of markup (reStructuredText directives and roles) to describe and link to objects belonging together".
According to the linked page :return comes from the Python domain, :returns from the JavaScript domain, and they both appear to be used for the same thing (i.e. documenting the return value of a function or method). In practice :returns appears so infrequently one wonders whether it's a documentation typo.
:rtype specifies the return type, and will create a link to the type definition if that's possible (i.e. if Sphinx can find the definition in the code you are documenting).
None of them mean anything by themselves. Various programs will scan a docstring and interpret certain pieces (or tags) specially for formatting, linking, etc. By convention (starting with javadoc?), such tags often begin with :. Beyond that, the specific meaning depends on the program parsing the docstring, and there is no defined standard for what tags should be used. Some programs use :return to document the return value of a function, others use :rtype.
The only real answer to your question is, consult the documentation for the program you expect to process your docstrings.

enforcing python function parameters types from docstring

Both epydoc and Sphinx document generators permit the coder to annotate what the types should be of any/all function parameter.
My question is: Is there a way (or module) that enforces these types (at run-time) when documented in the docstring. This wouldn't be strong-typing (compile-time checking), but (more likely) might be called firm-typing (run-time checking). Maybe raising a "ValueError", or even better still... raising a "SemanticError"
Ideally there would already be something (like a module) similar to the "import antigravity" module as per xkcd, and this "firm_type_check" module would already exist somewhere handy for download.
FYI: The docstring for epydoc and sphinz are as follows:
epydoc:
Functions and Methods parameters:
#param p: ... # A description of the parameter p for a function or method.
#type p: ... # The expected type for the parameter p.
#return: ... # The return value for a function or method.
#rtype: ... # The type of the return value for a function or method.
#keyword p: ... # A description of the keyword parameter p.
#raise e: ... # A description of the circumstances under which a function or method
raises exception e.
Sphinx: Inside Python object description directives, reST field lists with these fields are recognized and formatted nicely:
param, parameter, arg, argument, key, keyword: Description of a parameter.
type: Type of a parameter.
raises, raise, except, exception: That (and when) a specific exception is raised.
var, ivar, cvar: Description of a variable.
returns, return: Description of the return value.
rtype: Return type.
The closest I could find was a mention by Guido in mail.python.org and created by Jukka Lehtosalo at Mypy Examples. CMIIW: mypy cannot be imported as a py3 module.
Similar stackoverflow questions that do not use the docstring per se:
Pythonic Way To Check for A Parameter Type
What's the canonical way to check for type in python?
To my knowledge, nothing of the sort exists, for a few important reasons:
First, docstrings are documentation, just like comments. And just like comments, people will expect them to have no effect on the way your program works. Making your program's behavior depend on its documentation is a major antipattern, and a horrible idea all around.
Second, docstrings aren't guaranteed to be preserved. If you run python with -OO, for example, all docstrings are removed. What then?
Finally, Python 3 introduced optional function annotations, which would serve that purpose much better: http://legacy.python.org/dev/peps/pep-3107/ . Python currently does nothing with them (they're documentation), but if I were to write such a module, I'd use those, not docstrings.
My honest opinion is this: if you're gonna go through the (considerable) trouble of writing a (necessarily half-baked) static type system for Python, all the time it will take you would be put to better use by learning another programming language that supports static typing in a less insane way:
Clojure (http://clojure.org/) is incredibly dynamic and powerful (due to its nature as a Lisp) and supports optional static typing through core.typed (https://github.com/clojure/core.typed). It is geared towards concurrency and networking (it has STM and persistent data structures <3 ), has a great community, and is one of the most elegantly-designed languages I've seen. That said, it runs on the JVM, which is both a good and a bad thing.
Golang (http://golang.org/) feels sort-of Pythonic (or at least, it's attracting a lot of refugees from Python), is statically typed and compiles to native code.
Rust (http://www.rust-lang.org/) is lower-level than that, but it has one of the best type systems I've seen (type inference, pattern matching, traits, generics, zero-sized types...) and enforces memory and resource safety at compile time. It is being developed by Mozilla as a language to write their next browser (Servo) in, so performance and safety are its main goals. You can think of it as a modern take on C++. It compiles to native code, but hasn't hit 1.0 yet and as such, the language itself is still subject to change. Which is why I wouldn't recommend writing production code in it yet.

How to document and test interfaces required of formal parameters in Python 2?

To ask my very specific question I find I need quite a long introduction to motivate and explain it -- I promise there's a proper question at the end!
While reading part of a large Python codebase, sometimes one comes across code where the interface required of an argument is not obvious from "nearby" code in the same module or package. As an example:
def make_factory(schema):
entity = schema.get_entity()
...
There might be many "schemas" and "factories" that the code deals with, and "def get_entity()" might be quite common too (or perhaps the function doesn't call any methods on schema, but just passes it to another function). So a quick grep isn't always helpful to find out more about what "schema" is (and the same goes for the return type). Though "duck typing" is a nice feature of Python, sometimes the uncertainty in a reader's mind about the interface of arguments passed in as the "schema" gets in the way of quickly understanding the code (and the same goes for uncertainty about typical concrete classes that implement the interface). Looking at the automated tests can help, but explicit documentation can be better because it's quicker to read. Any such documentation is best when it can itself be tested so that it doesn't get out of date.
Doctests are one possible approach to solving this problem, but that's not what this question is about.
Python 3 has a "parameter annotations" feature (part of the function annotations feature, defined in PEP 3107). The uses to which that feature might be put aren't defined by the language, but it can be used for this purpose. That might look like this:
def make_factory(schema: "xml_schema"):
...
Here, "xml_schema" identifies a Python interface that the argument passed to this function should support. Elsewhere there would be code that defines that interface in terms of attributes, methods & their argument signatures, etc. and code that allows introspection to verify whether particular objects provide an interface (perhaps implemented using something like zope.interface / zope.schema). Note that this doesn't necessarily mean that the interface gets checked every time an argument is passed, nor that static analysis is done. Rather, the motivation of defining the interface is to provide ways to write automated tests that verify that this documentation isn't out of date (they might be fairly generic tests so that you don't have to write a new test for each function that uses the parameters, or you might turn on run-time interface checking but only when you run your unit tests). You can go further and annotate the interface of the return value, which I won't illustrate.
So, the question:
I want to do exactly that, but using Python 2 instead of Python 3. Python 2 doesn't have the function annotations feature. What's the "closest thing" in Python 2? Clearly there is more than one way to do it, but I suspect there is one (relatively) obvious way to do it.
For extra points: name a library that implements the one obvious way.
Take a look at plac that uses annotations to define a command-line interface for a script. On Python 2.x it uses plac.annotations() decorator.
The closest thing is, I believe, an annotation library called PyAnno.
From the project webpage:
"The Pyanno annotations have two functions:
Provide a structured way to document Python code
Perform limited run-time checking "

Categories