def test_nonstandard_property(): # test discovery of a property that does not satisfy isinstace(.., property) class SpecialProperty(object): def __init__(self, axis=0, doc=""): self.axis = axis self.__doc__ = doc def __get__(self, obj, type): if obj is None: # Only instances have actual _data, not classes return self else: return obj._data.axes[self.axis] def __set__(self, obj, value): obj._set_axis(self.axis, value) class Dummy: attr = SpecialProperty(doc="test attribute") doc = get_doc_object(Dummy) assert "test attribute" in str(doc)
def check_rest(module, names, dots=True): """ Check reStructuredText formatting of docstrings Returns: [(name, success_flag, output), ...] """ try: skip_types = (dict, str, unicode, float, int) except NameError: # python 3 skip_types = (dict, str, float, int) results = [] if module.__name__[6:] not in OTHER_MODULE_DOCS: results += [(module.__name__,) + validate_rst_syntax(inspect.getdoc(module), module.__name__, dots=dots)] for name in names: full_name = module.__name__ + "." + name obj = getattr(module, name, None) if obj is None: results.append((full_name, False, "%s has no docstring" % (full_name,))) continue elif isinstance(obj, skip_types): continue if inspect.ismodule(obj): text = inspect.getdoc(obj) else: try: text = str(get_doc_object(obj)) except: import traceback results.append((full_name, False, "Error in docstring format!\n" + traceback.format_exc())) continue m = re.search("([\x00-\x09\x0b-\x1f])", text) if m: msg = "Docstring contains a non-printable character %r! " 'Maybe forgot r"""?' % (m.group(1),) results.append((full_name, False, msg)) continue try: src_file = short_path(inspect.getsourcefile(obj)) except TypeError: src_file = None if src_file: file_full_name = src_file + ":" + full_name else: file_full_name = full_name results.append((full_name,) + validate_rst_syntax(text, file_full_name, dots=dots)) return results
def autodoc_process_docstring(app, what, name, obj, options, lines): # Don't try to validate the docstrings of modules if what == 'module': return parsed = docscrape_sphinx.get_doc_object(obj, what) if what == 'property': return # Validate the parameters documented_parameters = set() for parameter in parsed.get('Parameters'): documented_parameters.add(parameter.name) assert_standard_sentence(parameter.desc, 'parameter', parameter.name, obj) # Check that the parameters match the signature signature = inspect.signature(obj) available_parameters = set() for i, parameter in enumerate(signature.parameters.values()): if i == 0 and parameter.name == 'self': continue elif parameter.kind == inspect.Parameter.VAR_POSITIONAL: available_parameters.add('*' + parameter.name) elif parameter.kind == inspect.Parameter.VAR_KEYWORD: available_parameters.add('**' + parameter.name) else: available_parameters.add(parameter.name) # Find undocumented parameters undocumented = available_parameters - documented_parameters if undocumented: undocumented = ', '.join(f'`{param}`' for param in undocumented) LOGGER.warn(f"parameters {undocumented} should be documented for {obj.__name__} at " f"{get_code_location(obj)}") # Find parameters that are documented but not available missing = documented_parameters - available_parameters if missing: missing = ', '.join(f'`{param}`' for param in missing) LOGGER.warn(f"parameters {missing} are documented but not defined for {obj.__name__} at " f"{get_code_location(obj)}") # Check if the function could return something if what in ('function', 'method'): source = [line.strip() for line in inspect.getsource(obj).splitlines()] could_return = any(line.startswith('return ') or line.startswith('raise NotImplemented') for line in source) returns = parsed.get('Returns') for parameter in parsed.get('Returns'): assert_standard_sentence(parameter.desc, 'return value', parameter.name, obj) if could_return and not returns: LOGGER.warn(f"return values should be documented for {obj.__name__} at " f"{get_code_location(obj)}") if not could_return and returns: LOGGER.warn(f"return values are documented but not defined for {obj.__name__} at " f"{get_code_location(obj)}")
def check_rest(module, names, dots=True): """ Check reStructuredText formatting of docstrings Returns: [(name, success_flag, output), ...] """ skip_types = (dict, str, unicode, float, int) results = [] if module.__name__[6:] not in OTHER_MODULE_DOCS: results += [(module.__name__, ) + validate_rst_syntax( inspect.getdoc(module), module.__name__, dots=dots)] for name in names: full_name = module.__name__ + '.' + name obj = getattr(module, name, None) if obj is None: results.append( (full_name, False, "%s has no docstring" % (full_name, ))) continue elif isinstance(obj, skip_types): continue if inspect.ismodule(obj): text = inspect.getdoc(obj) else: try: text = str(get_doc_object(obj)) except: import traceback results.append( (full_name, False, "Error in docstring format!\n" + traceback.format_exc())) continue try: src_file = short_path(inspect.getsourcefile(obj)) except TypeError: src_file = None if src_file: file_full_name = src_file + ':' + full_name else: file_full_name = full_name results.append((full_name, ) + validate_rst_syntax(text, file_full_name, dots=dots)) return results
def check_rest(module, names, dots=True): """ Check reStructuredText formatting of docstrings Returns: [(name, success_flag, output), ...] """ skip_types = (dict, str, unicode, float, int) results = [] if module.__name__[6:] not in OTHER_MODULE_DOCS: results += [(module.__name__,) + validate_rst_syntax(inspect.getdoc(module), module.__name__, dots=dots)] for name in names: full_name = module.__name__ + '.' + name obj = getattr(module, name, None) if obj is None: results.append((full_name, False, "%s has no docstring" % (full_name,))) continue elif isinstance(obj, skip_types): continue if inspect.ismodule(obj): text = inspect.getdoc(obj) else: try: text = str(get_doc_object(obj)) except: import traceback results.append((full_name, False, "Error in docstring format!\n" + traceback.format_exc())) continue try: src_file = short_path(inspect.getsourcefile(obj)) except TypeError: src_file = None if src_file: file_full_name = src_file + ':' + full_name else: file_full_name = full_name results.append((full_name,) + validate_rst_syntax(text, file_full_name, dots=dots)) return results
def check_rest(module, names, dots=True): """ Check reStructuredText formatting of docstrings Returns: [(name, success_flag, output), ...] """ try: skip_types = (dict, str, unicode, float, int) except NameError: # python 3 skip_types = (dict, str, float, int) results = [] if module.__name__[6:] not in OTHER_MODULE_DOCS: results += [(module.__name__, ) + validate_rst_syntax( inspect.getdoc(module), module.__name__, dots=dots)] for name in names: full_name = module.__name__ + '.' + name obj = getattr(module, name, None) if obj is None: results.append( (full_name, False, "%s has no docstring" % (full_name, ))) continue elif isinstance(obj, skip_types): continue if inspect.ismodule(obj): text = inspect.getdoc(obj) else: try: text = str(get_doc_object(obj)) except Exception: import traceback results.append( (full_name, False, "Error in docstring format!\n" + traceback.format_exc())) continue m = re.search("([\x00-\x09\x0b-\x1f])", text) if m: msg = ("Docstring contains a non-printable character %r! " "Maybe forgot r\"\"\"?" % (m.group(1), )) results.append((full_name, False, msg)) continue try: src_file = short_path(inspect.getsourcefile(obj)) except TypeError: src_file = None if src_file: file_full_name = src_file + ':' + full_name else: file_full_name = full_name results.append((full_name, ) + validate_rst_syntax(text, file_full_name, dots=dots)) return results