Skip to content

Commit 5532f8c

Browse files
authored
Merge pull request #19 from pixelneo/hints
Support type hints
2 parents 8dcf0ee + 6f184d7 commit 5532f8c

10 files changed

+48
-36
lines changed

README.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# vim-python-docstring
2-
This is a plugin to Vim for creating of docstrings.
2+
This is a plugin to Vim and NeoVim for creating of docstrings.
33

4-
Works also with neovim.
4+
**New**: Support for type hints and async functions.
55

66
## What it does
7-
Docstrings for methods will contain a **list of arguments**, **list of raised exceptions** and whether the method **yields** or **raises**.
7+
Docstrings for methods will contain a **list of parameters and their type hints**, **list of raised exceptions** and whether the method **yields** or **raises**.
88

99
Class docstring will have a **list of atributes**.
1010

@@ -39,6 +39,7 @@ The plugin uses these commands:
3939
| Command | Description |
4040
|---------------|-------------|
4141
| Docstring | Create full docstring
42+
| DocstringTypes| Just like `:Docstring` but includes type hints
4243
| DocstringLine | Create empty one-line docstring
4344

4445
## Options:
@@ -64,7 +65,7 @@ Possible values = [`'google'`, `'numpy'`, `'rest'`, `'epytext'`]
6465
let g:python_style = 'google'
6566
~~~
6667

67-
## Work in progress
68+
## Development
6869
Pull requests are welcome as are feature request and issue reports.
6970

7071
You can encounter some situations in which the plugin may not work as expected.

autoload/vimpythondocstring.vim

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ function! vimpythondocstring#Full()
1616
python3 pydocstring.Docstring().full_docstring()
1717
endfunction
1818

19+
function! vimpythondocstring#FullTypes()
20+
python3 pydocstring.Docstring().full_docstring(print_hints=True)
21+
endfunction
22+
1923
function! vimpythondocstring#Oneline()
2024
python3 pydocstring.Docstring().oneline_docstring()
2125
endfunction

plugin/vim-python-docstring.vim

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
command! -nargs=0 Docstring call vimpythondocstring#Full()
2+
command! -nargs=0 DocstringTypes call vimpythondocstring#FullTypes()
23
command! -nargs=0 DocstringLine call vimpythondocstring#Oneline()

python/asthelper.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,16 @@ def _handle_functions(self, node):
8484

8585
if self.parent:
8686
for arg in node.args.args:
87-
self.arguments.append(arg.arg)
87+
type_hint = None
88+
if arg.annotation is not None:
89+
type_hint = ast.unparse(arg.annotation)
90+
self.arguments.append({'arg': arg.arg, 'type': type_hint})
8891
if len(self.arguments) > 0 and (self.arguments[0] == 'self' or self.arguments[0] == 'cls'):
8992
self.arguments.pop(0)
9093

9194
self.returns = new_visitor.returns
9295
self.yields = new_visitor.yields
96+
print(self.arguments)
9397

9498
def visit_Raise(self, node):
9599
r = RaiseNameCollector()

python/pydocstring.py

+24-23
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ def _docstring_helper(self, obj_indent, docstring):
4747

4848
return '\n'.join(lines)
4949

50-
def get_method_docstring(self, method_indent, args, returns, yields, raises):
50+
def get_method_docstring(self, method_indent, args, returns, yields, raises, print_hints=False):
5151
with open(os.path.join(self.location, '..', 'styles/{}-{}.txt'.format(self.style, 'method')), 'r') as f:
5252
self.template = ibis.Template(f.read())
53-
docstring = self.template.render(indent=self.indent, args=args,
53+
docstring = self.template.render(indent=self.indent, args=args, hints=print_hints,
5454
raises=raises, returns=returns, yields=yields)
5555
return self._docstring_helper(method_indent, docstring)
5656

@@ -71,13 +71,13 @@ class ObjectWithDocstring(abc.ABC):
7171
7272
"""
7373

74-
def __init__(self, env, templater, style='google'):
74+
def __init__(self, env, templater):
7575
self.starting_line = env.current_line_nr
7676
self.env = env
7777
self.templater = templater
7878

7979
@abc.abstractmethod
80-
def write_docstring(self):
80+
def write_docstring(self, *args, **kwargs):
8181
""" Method to create a docstring for appropriate object
8282
8383
Writes the docstring to correct lines in `self.env` object.
@@ -88,7 +88,7 @@ def _get_sig(self):
8888
lines = []
8989
lines_it = self.env.lines_following_cursor()
9090
sig_line, first_line = next(lines_it)
91-
indent = re.findall('^(\s*)', first_line)[0]
91+
indent = re.findall(r'^(\s*)', first_line)[0]
9292

9393
lines.append(first_line)
9494

@@ -108,7 +108,7 @@ def _object_tree(self):
108108

109109
lines.append(first_line)
110110

111-
obj_indent = re.findall('^(\s*)', first_line)[0]
111+
obj_indent = re.findall(r'^(\s*)', first_line)[0]
112112
expected_indent = concat_(obj_indent, self.env.python_indent)
113113

114114
valid_sig, _ = self._is_valid(first_line)
@@ -182,8 +182,8 @@ def write_simple_docstring(self):
182182

183183
class MethodController(ObjectWithDocstring):
184184

185-
def __init__(self, env, templater, style='google'):
186-
super().__init__(env, templater, style)
185+
def __init__(self, env, templater):
186+
super().__init__(env, templater)
187187

188188
def _process_tree(self, tree):
189189
v = MethodVisitor()
@@ -193,11 +193,11 @@ def _process_tree(self, tree):
193193
return args, v.returns, v.yields, raises
194194

195195
# TODO: set cursor on appropriate position to fill the docstring
196-
def write_docstring(self):
196+
def write_docstring(self, print_hints=False):
197197
sig_line, method_indent, tree = self._object_tree()
198198
args, returns, yields, raises = self._process_tree(tree)
199199
docstring = self.templater.get_method_docstring(
200-
method_indent, args, returns, yields, raises)
200+
method_indent, args, returns, yields, raises, print_hints)
201201
self.env.append_after_line(sig_line, docstring)
202202

203203
def _arguments(self, tree):
@@ -214,8 +214,8 @@ def _arguments(self, tree):
214214

215215
class ClassController(ObjectWithDocstring):
216216

217-
def __init__(self, env, templater, style='google'):
218-
super().__init__(env, templater, style)
217+
def __init__(self, env, templater):
218+
super().__init__(env, templater)
219219

220220
def _process_tree(self, tree):
221221
x = ClassInstanceNameExtractor()
@@ -225,7 +225,7 @@ def _process_tree(self, tree):
225225
att = list(v.attributes)
226226
return att
227227

228-
def write_docstring(self):
228+
def write_docstring(self, *args, **kwargs):
229229
sig_line, class_indent, tree = self._object_tree()
230230
attr = self._process_tree(tree)
231231
docstring = self.templater.get_class_docstring(class_indent, attr)
@@ -240,33 +240,34 @@ def __init__(self):
240240
style = env.python_style
241241
indent = env.python_indent
242242
location = env.plugin_root_dir
243-
templater = Templater(location, indent, style)
243+
templater = Templater(location, indent=indent, style=style)
244244

245-
self.obj_controller = self._controller_factory(env, templater, style)
245+
self.obj_controller = self._controller_factory(env, templater)
246246

247-
def _controller_factory(self, env, templater, style):
247+
def _controller_factory(self, env, templater):
248248
line = env.current_line
249-
first_word = re.match('^\s*(\w+).*', line).groups()[0]
249+
first_word = re.match(r'^\s*(\w+).*', line).groups()[0]
250250
if first_word == 'def':
251-
return MethodController(env, templater, style=style)
251+
return MethodController(env, templater)
252252
elif first_word == 'class':
253-
return ClassController(env, templater, style=style)
253+
return ClassController(env, templater)
254254
elif first_word == 'async':
255-
second_word_catch = re.match('^\s*\w+\s+(\w+).*', line)
255+
second_word_catch = re.match(r'^\s*\w+\s+(\w+).*', line)
256256
if second_word_catch:
257257
second_word = second_word_catch.groups()[0]
258258
if second_word == 'def':
259-
return MethodController(env, templater, style=style)
259+
return MethodController(env, templater)
260260

261261
raise DocstringUnavailable(
262262
'Docstring cannot be created for selected object')
263263

264-
def full_docstring(self):
264+
def full_docstring(self, print_hints=False):
265265
""" Writes docstring containing arguments, returns, raises, ... """
266266
try:
267-
self.obj_controller.write_docstring()
267+
self.obj_controller.write_docstring(print_hints=print_hints)
268268
except Exception as e:
269269
print(concat_('Doctring ERROR: ', e))
270+
raise e
270271

271272
def oneline_docstring(self):
272273
""" Writes only a one-line empty docstring """

python/vimenv.py

-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ def append_after_line(self, line_nr, text):
9797

9898
def lines_following_cursor(self):
9999
import vim
100-
lines = []
101100
buffer = vim.current.buffer
102101
cursor_row = vim.current.window.cursor[0] - 1
103102
current_row = cursor_row

styles/epytext-method.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
2-
{% if args|len > 0 %}{% for a in args %}@param {{a}}:
3-
{% endfor %}{% endif %}{% if returns %}@return:
2+
{% if args|len > 0 %}{% for a in args %}@param {{a.arg}}:
3+
{% endfor %}{% if hints %}{% for a in args %}{% if a.type %}@type {{a.arg}}: {{a.type}}
4+
{% endif %}{% endfor %}{% endif %}{% endif %}{% if returns %}@return:
45
{% endif %}{% if yields %}@yield:
56
{% endif %}{% if raises|len > 0 %}{% for a in raises %}@raise {{a}}:
67
{% endfor %}{% endif %}"""

styles/google-method.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""
22
{% if args|len > 0 %}
33
Args:
4-
{% for a in args %}{{indent}}{{a}}:
4+
{% for a in args %}{{indent}}{{a.arg}}{% if hints and a.type %} ({{a.type}}){% endif %}:
55
{% endfor %}{% endif %}{% if returns %}
66
Returns:
77
{{indent}}
@@ -10,6 +10,6 @@ Yields:
1010
{{indent}}
1111
{% endif %}{% if raises|len > 0 %}
1212
Raises:
13-
{% for a in raises %}{{indent}}{{a}}:
13+
{% for r in raises %}{{indent}}{{r}}:
1414
{% endfor %}{% endif %}
1515
"""

styles/numpy-method.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{% if args|len > 0 %}
33
Parameters
44
----------
5-
{% for a in args %}{{indent}}{{a}} :
5+
{% for a in args %}{{indent}}{{a.arg}} :{% if hints and a.type %} {{a.type}}{% endif %}
66
{% endfor %}{% endif %}{% if returns %}
77
Returns
88
-------

styles/rest-method.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
2-
{% if args|len > 0 %}{% for a in args %}:param {{a}}:
3-
{% endfor %}{% endif %}{% if returns %}:returns:
2+
{% if args|len > 0 %}{% for a in args %}:param {{a.arg}}:
3+
{% endfor %}{% if hints %}{% for a in args %}{% if a.type %}:type {{a.arg}}: {{a.type}}
4+
{% endif %}{% endfor %}{% endif %}{% endif %}{% if returns %}:returns:
45
{% endif %}{% if yields %}:yields:
56
{% endif %}{% if raises|len > 0 %}{% for a in raises %}:raises {{a}}:
67
{% endfor %}{% endif %}"""

0 commit comments

Comments
 (0)