diff --git a/sphinx_gallery/py_source_parser.py b/sphinx_gallery/py_source_parser.py index d397087f9..6d072e735 100644 --- a/sphinx_gallery/py_source_parser.py +++ b/sphinx_gallery/py_source_parser.py @@ -47,20 +47,41 @@ def get_docstring_and_rest(filename): if not isinstance(node, ast.Module): raise TypeError("This function only supports modules. " "You provided {0}".format(node.__class__.__name__)) - if node.body and isinstance(node.body[0], ast.Expr) and \ - isinstance(node.body[0].value, ast.Str): - docstring_node = node.body[0] - docstring = docstring_node.value.s - if hasattr(docstring, 'decode'): # python2.7 - docstring = docstring.decode('utf-8') - # This get the content of the file after the docstring last line - # Note: 'maxsplit' argument is not a keyword argument in python2 - rest = content.decode('utf-8').split('\n', docstring_node.lineno)[-1] - return docstring, rest - else: + try: + # in python 3.7 module knows it's docstring + docstring = node.docstring + # grab the rest of the file + # in python 3.7 module knows it's docstring + docstring = node.docstring + # count the lines in the docstring. We have to do it this way instead + # of looking at the line of the first element of the AST because there may + # be comments before the first code that SG needs to capture. + ds_lines = len(docstring.split('\n')) + # if there is a coding line, this will be off by one + if content.startswith(b'# -*- coding:'): + ds_lines += 1 + # grab the rest of the file + rest = '\n'.join(content.decode('utf-8').split('\n')[ds_lines:]) + + except AttributeError: + # this block can be removed when python 3.6 support is dropped + if node.body and isinstance(node.body[0], ast.Expr) and \ + isinstance(node.body[0].value, ast.Str): + docstring_node = node.body[0] + docstring = docstring_node.value.s + if hasattr(docstring, 'decode'): # python2.7 + docstring = docstring.decode('utf-8') + # This get the content of the file after the docstring last line + # Note: 'maxsplit' argument is not a keyword argument in python2 + rest = content.decode('utf-8').split('\n', docstring_node.lineno)[-1] + else: + docstring, rest = '', '' + + if not docstring : raise ValueError(('Could not find docstring in file "{0}". ' 'A docstring is required by sphinx-gallery') .format(filename)) + return docstring, rest def split_code_and_text_blocks(source_file):