| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e650fd3 commit ec5569b
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,7 @@ | |||
| 2 | 2 | ||
| 3 | 3 | import os | |
| 4 | 4 | import unittest | |
| 5 | + import textwrap | ||
| 5 | 6 | ||
| 6 | 7 | from test.support.script_helper import assert_python_ok | |
| 7 | 8 | from test.test_tools import skip_if_missing, toolsdir | |
@@ -27,6 +28,41 @@ def get_header(self, data): | |||
| 27 | 28 | headers[key] = val.strip() | |
| 28 | 29 | return headers | |
| 29 | 30 | ||
| 31 | + def get_msgids(self, data): | ||
| 32 | + """ utility: return all msgids in .po file as a list of strings """ | ||
| 33 | + msgids = [] | ||
| 34 | + reading_msgid = False | ||
| 35 | + cur_msgid = [] | ||
| 36 | + for line in data.split('\n'): | ||
| 37 | + if reading_msgid: | ||
| 38 | + if line.startswith('"'): | ||
| 39 | + cur_msgid.append(line.strip('"')) | ||
| 40 | + else: | ||
| 41 | + msgids.append('\n'.join(cur_msgid)) | ||
| 42 | + cur_msgid = [] | ||
| 43 | + reading_msgid = False | ||
| 44 | + continue | ||
| 45 | + if line.startswith('msgid '): | ||
| 46 | + line = line[len('msgid '):] | ||
| 47 | + cur_msgid.append(line.strip('"')) | ||
| 48 | + reading_msgid = True | ||
| 49 | + else: | ||
| 50 | + if reading_msgid: | ||
| 51 | + msgids.append('\n'.join(cur_msgid)) | ||
| 52 | + | ||
| 53 | + return msgids | ||
| 54 | + | ||
| 55 | + def extract_docstrings_from_str(self, module_content): | ||
| 56 | + """ utility: return all msgids extracted from module_content """ | ||
| 57 | + filename = 'test_docstrings.py' | ||
| 58 | + with temp_cwd(None) as cwd: | ||
| 59 | + with open(filename, 'w') as fp: | ||
| 60 | + fp.write(module_content) | ||
| 61 | + assert_python_ok(self.script, '-D', filename) | ||
| 62 | + with open('messages.pot') as fp: | ||
| 63 | + data = fp.read() | ||
| 64 | + return self.get_msgids(data) | ||
| 65 | + | ||
| 30 | 66 | def test_header(self): | |
| 31 | 67 | """Make sure the required fields are in the header, according to: | |
| 32 | 68 | http://www.gnu.org/software/gettext/manual/gettext.html#Header-Entry | |
@@ -70,3 +106,55 @@ def test_POT_Creation_Date(self): | |||
| 70 | 106 | ||
| 71 | 107 | # This will raise if the date format does not exactly match. | |
| 72 | 108 | datetime.strptime(creationDate, '%Y-%m-%d %H:%M%z') | |
| 109 | + | ||
| 110 | + def test_funcdocstring_annotated_args(self): | ||
| 111 | + """ Test docstrings for functions with annotated args """ | ||
| 112 | + msgids = self.extract_docstrings_from_str(textwrap.dedent('''\ | ||
| 113 | + def foo(bar: str): | ||
| 114 | + """doc""" | ||
| 115 | + ''')) | ||
| 116 | + self.assertIn('doc', msgids) | ||
| 117 | + | ||
| 118 | + def test_funcdocstring_annotated_return(self): | ||
| 119 | + """ Test docstrings for functions with annotated return type """ | ||
| 120 | + msgids = self.extract_docstrings_from_str(textwrap.dedent('''\ | ||
| 121 | + def foo(bar) -> str: | ||
| 122 | + """doc""" | ||
| 123 | + ''')) | ||
| 124 | + self.assertIn('doc', msgids) | ||
| 125 | + | ||
| 126 | + def test_funcdocstring_defvalue_args(self): | ||
| 127 | + """ Test docstring for functions with default arg values """ | ||
| 128 | + msgids = self.extract_docstrings_from_str(textwrap.dedent('''\ | ||
| 129 | + def foo(bar=()): | ||
| 130 | + """doc""" | ||
| 131 | + ''')) | ||
| 132 | + self.assertIn('doc', msgids) | ||
| 133 | + | ||
| 134 | + def test_funcdocstring_multiple_funcs(self): | ||
| 135 | + """ Test docstring extraction for multiple functions combining | ||
| 136 | + annotated args, annotated return types and default arg values | ||
| 137 | + """ | ||
| 138 | + msgids = self.extract_docstrings_from_str(textwrap.dedent('''\ | ||
| 139 | + def foo1(bar: tuple=()) -> str: | ||
| 140 | + """doc1""" | ||
| 141 | + | ||
| 142 | + def foo2(bar: List[1:2]) -> (lambda x: x): | ||
| 143 | + """doc2""" | ||
| 144 | + | ||
| 145 | + def foo3(bar: 'func'=lambda x: x) -> {1: 2}: | ||
| 146 | + """doc3""" | ||
| 147 | + ''')) | ||
| 148 | + self.assertIn('doc1', msgids) | ||
| 149 | + self.assertIn('doc2', msgids) | ||
| 150 | + self.assertIn('doc3', msgids) | ||
| 151 | + | ||
| 152 | + def test_classdocstring_early_colon(self): | ||
| 153 | + """ Test docstring extraction for a class with colons occuring within | ||
| 154 | + the parentheses. | ||
| 155 | + """ | ||
| 156 | + msgids = self.extract_docstrings_from_str(textwrap.dedent('''\ | ||
| 157 | + class D(L[1:2], F({1: 2}), metaclass=M(lambda x: x)): | ||
| 158 | + """doc""" | ||
| 159 | + ''')) | ||
| 160 | + self.assertIn('doc', msgids) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + Fix pygettext not extracting docstrings for functions with type annotated | ||
| 2 | + arguments. | ||
| 3 | + Patch by Toby Harradine. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -320,6 +320,7 @@ def __init__(self, options): | |||
| 320 | 320 | self.__lineno = -1 | |
| 321 | 321 | self.__freshmodule = 1 | |
| 322 | 322 | self.__curfile = None | |
| 323 | + self.__enclosurecount = 0 | ||
| 323 | 324 | ||
| 324 | 325 | def __call__(self, ttype, tstring, stup, etup, line): | |
| 325 | 326 | # dispatch | |
@@ -340,17 +341,23 @@ def __waiting(self, ttype, tstring, lineno): | |||
| 340 | 341 | elif ttype not in (tokenize.COMMENT, tokenize.NL): | |
| 341 | 342 | self.__freshmodule = 0 | |
| 342 | 343 | return | |
| 343 | - # class docstring? | ||
| 344 | + # class or func/method docstring? | ||
| 344 | 345 | if ttype == tokenize.NAME and tstring in ('class', 'def'): | |
| 345 | 346 | self.__state = self.__suiteseen | |
| 346 | 347 | return | |
| 347 | 348 | if ttype == tokenize.NAME and tstring in opts.keywords: | |
| 348 | 349 | self.__state = self.__keywordseen | |
| 349 | 350 | ||
| 350 | 351 | def __suiteseen(self, ttype, tstring, lineno): | |
| 351 | - # ignore anything until we see the colon | ||
| 352 | - if ttype == tokenize.OP and tstring == ':': | ||
| 353 | - self.__state = self.__suitedocstring | ||
| 352 | + # skip over any enclosure pairs until we see the colon | ||
| 353 | + if ttype == tokenize.OP: | ||
| 354 | + if tstring == ':' and self.__enclosurecount == 0: | ||
| 355 | + # we see a colon and we're not in an enclosure: end of def | ||
| 356 | + self.__state = self.__suitedocstring | ||
| 357 | + elif tstring in '([{': | ||
| 358 | + self.__enclosurecount += 1 | ||
| 359 | + elif tstring in ')]}': | ||
| 360 | + self.__enclosurecount -= 1 | ||
| 354 | 361 | ||
| 355 | 362 | def __suitedocstring(self, ttype, tstring, lineno): | |
| 356 | 363 | # ignore any intervening noise | |
| Back | FazBrowse Home | New Git URL |
0 commit comments