for my project documentation I use the intersphinx mapping to the wxpython documentation. That works fine so far but I don't succeed to get a link to wx.CheckBoxState. I tried to find information about that here and in other forums, but didn't find anything.
Here my code:
def my_meth( self, value, aStr ):
"""
:param int value: This is my value
:param str aStr: This is another value
Description using
- :py:class:`wx.CheckBoxState`
- :py:class:`wx.CheckBoxState.enumeration`
- :py:class:`wx.Validator`
"""
self.my_var = value
self.my_str = aStr
Running Sphinx produces
As you see links to "int", "str", "wx.Validator" work fine, but both attempts to find a link to wx.CheckBoxState didn't succeed.
There is still the hard coded way (a direct link to the page), but I would prefer the smart one (:py:class:...).
Can anybody help?
Thanks in advance
Humbalan
By the way: I work with sphinx 1.7.5, python 3.7 and wxpython 4.0.1
Depending on your intersphinx mapping configuration, you might need to adjust it. Assuming it looks like this:
intersphinx_mapping = {
'wx': ('https://docs.wxpython.org/', None),
}
You would then do this:
def my_meth( self, value, aStr ):
"""
:param int value: This is my value
:param str aStr: This is another value
Description using
- :ref:`wx.CheckBoxState`
- :py:class:`wx.Validator`
"""
self.my_var = value
self.my_str = aStr
I assumed that :py:obj: would work as an object of unspecified type for wx.CheckBoxState and wx.CheckBoxState.enumeration, but it didn't. I fell back to using :ref:, which worked for wx.CheckBoxState but not wx.CheckBoxState.enumeration, so I removed the latter. They seem to be the same target in the docs to me.
The style may be different, but I think that's the best you can hope for with the wxPython documentation out of the box.
You could try modifying your checkout of wxPython, modify the docs and possibly their source code until you get it to generate the link you want, then submit a pull request to them.
Related
In JetBrain's example for docstring in Pycharm, it is mentioned that:
Note that for reStructuredText it's possible to specify types in two formats:
:param param_type param_name: parameter description (type description is on the same line as the parameter description).
:type param_name: param_type (type description is on a separate line)
I want to make my pycharm autogenerate the second variant, not the first one?
Currently, it is even not even adding the type
def foo(a: str, b: int = 1) -> str:
"""
:param a:
:param b:
:return:
"""
return a + str(b)
a related question is: How to customize docstring generation in pycharm and share the template through git?
Currently, in spite of the documentation mentioning both formats, it appears it is not possible to switch between the two styles. https://youtrack.jetbrains.com/issue/PY-12327
You can enable the second style (which I think you want) by checking the following option:
Editor - General - Smart Keys - Python check Insert type placeholders in the documentation comment stub. (or use the Settings search and search for comment stub)
Very unintuitive and many people have been requesting improvements to this functionality in PyCharm. Ideally, you'd want to be able to provide a custom sphinx.mustache docstring template of this style:
{{! Sphinx Docstring Template }}
{{summaryPlaceholder}}
{{extendedSummaryPlaceholder}}
{{#args}}
:param {{var}}: {{descriptionPlaceholder}}
{{/args}}
{{#kwargs}}
:param {{var}}: {{descriptionPlaceholder}}
{{/kwargs}}
{{#exceptions}}
:raises {{type}}: {{descriptionPlaceholder}}
{{/exceptions}}
{{#returns}}
:return: {{descriptionPlaceholder}}
{{/returns}}
{{#yields}}
:yield: {{descriptionPlaceholder}}
{{/yields}}
(example taken from here https://github.com/executablebooks/markdown-it-py/blob/master/docstring.fmt.mustache)
But again, that is currently not supported in PyCharm - feel free to comment and vote on the linked issue, and perhaps it gets some attention.
I am trying to figure out how can I provide type hints for a dictionary argument being passed to a function without using Dict[str, str] as that doesnt provide what the keys will be.
I have tried two approaches so far, one with using typing_extensions so that I can have compatibility with 3.6, and also with pydantic, but I cant get the hits to show.
Consider this example code:
from typing_extensions import TypedDict
from pydantic import BaseModel
class Some(TypedDict):
"""keya is some key"""
keya: str
"""another_key is another key"""
another_key: str
def some(a: Some) -> None:
print(a.get('keya'))
return None
some({'keya': 'key', 'another_key': 'nonething'})
As expected, the type hints for the some function shows the type Some, but not its keys.
What I am trying to accomplish is 2 things.
Provide key hints when the function argument is a dict (most important)
Generate documentation with sphinx so that the keys reflect in the documentation.
Edit
As on of the comments pointed out, I can accomplish this with **kwargs to some extent, but that is not the intention. Setting **kwargs does not give me type hints either.
I think in this case, it might actually be better to file a feature request/submit a pull request to your editor improving the quality of its type hinting. Similarly, with sphinx, you could submit a pull request that ensures that the docs either properly link to the definition of Some or include a more detailed description within the function signature itself.
After all, the problem you're facing is a limitation of your editor/sphinx, not with Python or type hints, and you might get better long-term results if you tackle the problem at the source.
You may also get better results if you use the "constructor" of Some instead of passing in a dict literal. At least for me, doing this gets me full key hints for Some when using PyCharm. Not sure if that'll also be the case for your editor:
some(Some(keya='key', another_key='nonething'))
Note that doing Some(...) will actually just return a plain old regular dict at runtime, so this shouldn't lead to any difference in behavior.
It could also be worth trying to do:
x: Some = {
"keya": "key",
"another_key": "nonething",
}
some(x)
...to see if your editor might give better hints with that form.
I have somewhat narrowed down to a possible solution using the following code. It meets most of the requirements:
mypy type checks passes
shows keys
documentation also shows keys and types
The main caviate to this solution is that mypy thinks the value is optional because of a default value so the solution is not quite complete.
Using the validate_items function, I can validate that the values are there. Please see the comments on the code snippet and offer suggestions.
from typing_extensions import TypedDict
from typing import Union
class Some(TypedDict):
keya: str
another_key: str
def validate_items(v: dict) -> None:
for key, value in v.items():
assert isinstance(value,str), '{} is required'.format(key)
# Would love to pull the type of a key from the Some class here or
# would love to put the validation in the Some class itself
def some(a: Some={'keya': '', 'another_key': ''}) -> None:
"""[summary]
Args:
a (Some, optional): [description]. Defaults to {'keya': '', 'another_key': ''}.
Returns:
[type]: [description]
"""
validate_items(dict(a))
print(a.get('keya'))
return None
In the screenshot, I can see that mypy is complaining about the None value which is expected, and in the popup help, we can also see the keys that are required in the dictionary being passed along with the type that is being set to it.
The solution feels quite hacky, and would appreciate any corrections to make it more pythonic.
I'm trying to use the typing module to document my Python package, and I have a number of situations where several different types are allowable for a function parameter. For instance, you can either pass a number, an Envelope object (one of the classes in my package), or a list of numbers from which an Envelope is constructed, or a list of lists of numbers from which an envelope is constructed. So I make an alias type as follows:
NumberOrEnvelope = Union[Sequence[Real], Sequence[Sequence[Real]], Real, Envelope]
Then I write the function:
def example_function(parameter: NumberOrEnvelope):
...
And that looks great to me. However, when I create the documentation using Sphinx, I end up with this horrifically unreadable function signature:
example_function(parameter: Union[Sequence[numbers.Real], Sequence[Sequence[numbers.Real]], numbers.Real, expenvelope.envelope.Envelope])
Same thing also with the hints that pop up when I start to try to use the function in PyCharm.
Is there some way I can have it just leave it as "NumberOrEnvelope". Ideally that would also link in the documentation to a clarification of what "NumberOrEnvelope" is, though even if it didn't it would be way better than what's appearing now.
I had the same issue and used https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_type_aliases, introduced in version 3.3.
In your sphinx conf.py, insert this section. It does not seem to make much sense at the first sight, but does the trick:
autodoc_type_aliases = dict(NumberOrEnvelope='NumberOrEnvelope')
Warning: It only works in modules that start with from __future__ import annotation
Note: If there is a target in the documentation, type references even have a hyperlink to the definition. I have classes, documented elsewhere with autoclass, which are used as types of function parameters, and the docs show the nice names of the types with links.
Support for this appears to be in the works.
See Issue #6518.
That issue can be closed by the recent updates to Pull Request #8007 (under review).
If you want the fix ASAP, you can perhaps try using that build.
EDIT: This doesn't quite work, sadly.
Turns out after a little more searching, I found what I was looking for. Instead of:
NumberOrEnvelope = Union[Sequence[Real], Sequence[Sequence[Real]], Real, Envelope]
I found that you can create your own compound type that does the same thing:
NumberOrEnvelope = TypeVar("NumberOrEnvelope", Sequence[Real], Sequence[Sequence[Real]], Real, Envelope)
This displays in documentation as "NumberOrEnvelope", just as I wanted.
When I write a function in Python (v2.7), I very often have a type in mind for one of the arguments. I'm working with the unbelievably brilliant pandas library at the movemement, so my arguments are often 'intended' to be pandas.DataFrames.
In my favorite IDE (Spyder), when you type a period . a list of methods appear. Also, when you type the opening parenthesis of a method, the docstring appears in a little window.
But for these things to work, the IDE has to know what type a variable is. But of course, it never does. Am I missing something obvious about how to write Pythonic code (I've read Python Is Not Java but it doesn't mention this IDE autocomplete issue.
Any thoughts?
I don't know if it works in Spyder, but many completion engines (e.g. Jedi) also support assertions to tell them what type a variable is. For example:
def foo(param):
assert isinstance(param, str)
# now param will be considered a str
param.|capitalize
center
count
decode
...
Actually I use IntelliJ idea ( aka pyCharm ) and they offer multiple ways to specify variable types:
1. Specify Simple Variable
Very simple: Just add a comment with the type information behind the definition. From now on Pycharm supports autcompletition! e.g.:
def route():
json = request.get_json() # type: dict
Source: https://www.jetbrains.com/help/pycharm/type-hinting-in-pycharm.html
2. Specify Parameter:
Add three quote signs after the beginning of a method and the idea will autocomplete a docstring, as in the following example:
Source: https://www.jetbrains.com/help/pycharm/using-docstrings-to-specify-types.html
(Currently on my mobile, going to make it pretty later)
If you're using Python 3, you can use function annotations. As an example:
#typechecked
def greet(name: str, age: int) -> str:
print("Hello {0}, you are {1} years old".format(name, age))
I don't use Spyder, but I would assume there's a way for it to read the annotations and act appropriately.
I don't know whether Spyder reads docstrings, but PyDev does:
http://pydev.org/manual_adv_type_hints.html
So you can document the expected type in the docstring, e.g. as in:
def test(arg):
'type arg: str'
arg.<hit tab>
And you'll get the according string tab completion.
Similarly you can document the return-type of your functions, so that you can get tab-completion on foo for foo = someFunction().
At the same time, docstrings make auto-generated documention much more helpful.
The problem is with the dynamic features of Python, I use Spyder and I've used a lot more of python IDEs (PyCharm, IDLE, WingIDE, PyDev, ...) and ALL of them have the problem you stated here. So, when I want code completion for help I just instantiate the variable to the type I want and then type ".", for example: suppose you know your var df will be a DataFrame in some piece of code, you can do this df = DataFrame() and for now on the code completion should work for you just do not forget to delete (or comment) the line df = DataFrame() when you finish editing the code.
When it comes to constructors, and assignments, and method calls, the PyCharm IDE is pretty good at analyzing my source code and figuring out what type each variable should be. I like it when it's right, because it gives me good code-completion and parameter info, and it gives me warnings if I try to access an attribute that doesn't exist.
But when it comes to parameters, it knows nothing. The code-completion dropdowns can't show anything, because they don't know what type the parameter will be. The code analysis can't look for warnings.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
peasant = Person("Dennis", 37)
# PyCharm knows that the "peasant" variable is of type Person
peasant.dig_filth() # shows warning -- Person doesn't have a dig_filth method
class King:
def repress(self, peasant):
# PyCharm has no idea what type the "peasant" parameter should be
peasant.knock_over() # no warning even though knock_over doesn't exist
King().repress(peasant)
# Even if I call the method once with a Person instance, PyCharm doesn't
# consider that to mean that the "peasant" parameter should always be a Person
This makes a certain amount of sense. Other call sites could pass anything for that parameter. But if my method expects a parameter to be of type, say, pygame.Surface, I'd like to be able to indicate that to PyCharm somehow, so it can show me all of Surface's attributes in its code-completion dropdown, and highlight warnings if I call the wrong method, and so on.
Is there a way I can give PyCharm a hint, and say "psst, this parameter is supposed to be of type X"? (Or perhaps, in the spirit of dynamic languages, "this parameter is supposed to quack like an X"? I'd be fine with that.)
EDIT: CrazyCoder's answer, below, does the trick. For any newcomers like me who want the quick summary, here it is:
class King:
def repress(self, peasant):
"""
Exploit the workers by hanging on to outdated imperialist dogma which
perpetuates the economic and social differences in our society.
#type peasant: Person
#param peasant: Person to repress.
"""
peasant.knock_over() # Shows a warning. And there was much rejoicing.
The relevant part is the #type peasant: Person line of the docstring.
If you also go to File > Settings > Python Integrated Tools and set "Docstring format" to "Epytext", then PyCharm's View > Quick Documentation Lookup will pretty-print the parameter information instead of just printing all the #-lines as-is.
Yes, you can use special documentation format for methods and their parameters so that PyCharm can know the type. Recent PyCharm version supports most common doc formats.
For example, PyCharm extracts types from #param style comments.
See also reStructuredText and docstring conventions (PEP 257).
Another option is Python 3 annotations.
Please refer to the PyCharm documentation section for more details and samples.
If you are using Python 3.0 or later, you can also use annotations on functions and parameters. PyCharm will interpret these as the type the arguments or return values are expected to have:
class King:
def repress(self, peasant: Person) -> bool:
peasant.knock_over() # Shows a warning. And there was much rejoicing.
return peasant.badly_hurt() # Lets say, its not known from here that this method will always return a bool
Sometimes this is useful for non-public methods, that do not need a docstring. As an added benefit, those annotations can be accessed by code:
>>> King.repress.__annotations__
{'peasant': <class '__main__.Person'>, 'return': <class 'bool'>}
Update: As of PEP 484, which has been accepted for Python 3.5, it is also the official convention to specify argument and return types using annotations.
PyCharm extracts types from a #type pydoc string. See PyCharm docs here and here, and Epydoc docs. It's in the 'legacy' section of PyCharm, perhaps it lacks some functionality.
class King:
def repress(self, peasant):
"""
Exploit the workers by hanging on to outdated imperialist dogma which
perpetuates the economic and social differences in our society.
#type peasant: Person
#param peasant: Person to repress.
"""
peasant.knock_over() # Shows a warning. And there was much rejoicing.
The relevant part is the #type peasant: Person line of the docstring.
My intention is not to steal points from CrazyCoder or the original questioner, by all means give them their points. I just thought the simple answer should be in an 'answer' slot.
I'm using PyCharm Professional 2016.1 writing py2.6-2.7 code, and I found that using reStructuredText I can express types in a more succint way:
class Replicant(object):
pass
class Hunter(object):
def retire(self, replicant):
""" Retire the rogue or non-functional replicant.
:param Replicant replicant: the replicant to retire.
"""
replicant.knock_over() # Shows a warning.
See: https://www.jetbrains.com/help/pycharm/2016.1/type-hinting-in-pycharm.html#legacy
You can also assert for a type and Pycharm will infer it:
def my_function(an_int):
assert isinstance(an_int, int)
# Pycharm now knows that an_int is of type int
pass