Explain yourself! Interrogate a codebase for docstring coverage.

Overview

Pink Sloth Logo

interrogate: explain yourself

Documentation Coverage Testing Coverage Documentation Status CI Status

Interrogate a codebase for docstring coverage.

Why Do I Need This?

interrogate checks your code base for missing docstrings.

Documentation should be as important as code itself. And it should live within code. Python standardized docstrings, allowing for developers to navigate libraries as simply as calling help() on objects, and with powerful tools like Sphinx, pydoc, and Docutils to automatically generate HTML, LaTeX, PDFs, etc.

Enter: interrogate.

interrogate will tell you which methods, functions, classes, and modules have docstrings, and which do not. Use interrogate to:

  • Get an understanding of how well your code is documented;
  • Add it to CI/CD checks to enforce documentation on newly-added code;
  • Assess a new code base for (one aspect of) code quality and maintainability.

Let's get started.

Requirements

interrogate supports Python 3.6 and above.

Installation

interrogate is available on PyPI and GitHub. The recommended installation method is pip-installing into a virtualenv:

$ pip install interrogate

Usage

Try it out on a Python project:

$ interrogate [PATH]
RESULT: PASSED (minimum: 80.0%, actual: 100.0%)

Add verbosity to see a summary:

$ interrogate -v [PATH]

================== Coverage for /Users/lynn/dev/interrogate/ ====================
------------------------------------ Summary ------------------------------------
| Name                                  |   Total |   Miss |   Cover |   Cover% |
|---------------------------------------|---------|--------|---------|----------|
| src/interrogate/__init__.py           |       1 |      0 |       1 |     100% |
| src/interrogate/__main__.py           |       1 |      0 |       1 |     100% |
| src/interrogate/badge_gen.py          |       5 |      0 |       5 |     100% |
| src/interrogate/cli.py                |       2 |      0 |       2 |     100% |
| src/interrogate/config.py             |       8 |      0 |       8 |     100% |
| src/interrogate/coverage.py           |      25 |      0 |      25 |     100% |
| src/interrogate/utils.py              |      10 |      0 |      10 |     100% |
| src/interrogate/visit.py              |      16 |      0 |      16 |     100% |
| tests/functional/__init__.py          |       1 |      0 |       1 |     100% |
| tests/functional/test_cli.py          |       7 |      0 |       7 |     100% |
| tests/functional/test_coverage.py     |       6 |      0 |       6 |     100% |
| tests/unit/__init__.py                |       1 |      0 |       1 |     100% |
| tests/unit/test_badge_gen.py          |       6 |      0 |       6 |     100% |
| tests/unit/test_config.py             |      10 |      0 |      10 |     100% |
| tests/unit/test_utils.py              |      13 |      0 |      13 |     100% |
|---------------------------------------|---------|--------|---------|----------|
| TOTAL                                 |     112 |      0 |     112 |   100.0% |
---------------- RESULT: PASSED (minimum: 95.0%, actual: 100.0%) ----------------

Add even more verbosity:

$ interrogate -vv [PATH]

================== Coverage for /Users/lynn/dev/interrogate/ ====================
------------------------------- Detailed Coverage -------------------------------
| Name                                                                |  Status |
|---------------------------------------------------------------------|---------|
| src/interrogate/__init__.py (module)                                | COVERED |
|---------------------------------------------------------------------|---------|
| src/interrogate/__main__.py (module)                                | COVERED |
|---------------------------------------------------------------------|---------|
| src/interrogate/badge_gen.py (module)                               | COVERED |
|   save_badge (L33)                                                  | COVERED |
|   get_badge (L50)                                                   | COVERED |
|   get_color (L66)                                                   | COVERED |
|   create (L79)                                                      | COVERED |
|---------------------------------------------------------------------|---------|
| src/interrogate/cli.py (module)                                     | COVERED |
|   main (L218)                                                       | COVERED |
|---------------------------------------------------------------------|---------|
| src/interrogate/config.py (module)                                  | COVERED |
|   InterrogateConfig (L17)                                           | COVERED |
|   find_project_root (L52)                                           | COVERED |
|   find_project_config (L80)                                         | COVERED |
|   parse_pyproject_toml (L91)                                        | COVERED |
|   sanitize_list_values (L107)                                       | COVERED |
|   parse_setup_cfg (L130)                                            | COVERED |
|   read_config_file (L164)                                           | COVERED |
|---------------------------------------------------------------------|---------|
| src/interrogate/coverage.py (module)                                | COVERED |
|   BaseInterrogateResult (L21)                                       | COVERED |
|     BaseInterrogateResult.perc_covered (L35)                        | COVERED |
|   InterrogateFileResult (L49)                                       | COVERED |
|     InterrogateFileResult.combine (L62)                             | COVERED |
|   InterrogateResults (L76)                                          | COVERED |
|     InterrogateResults.combine (L88)                                | COVERED |
|   InterrogateCoverage (L96)                                         | COVERED |
|     InterrogateCoverage._add_common_exclude (L115)                  | COVERED |
|     InterrogateCoverage._filter_files (L122)                        | COVERED |
|     InterrogateCoverage.get_filenames_from_paths (L139)             | COVERED |
|     InterrogateCoverage._filter_nodes (L166)                        | COVERED |
|     InterrogateCoverage._get_file_coverage (L192)                   | COVERED |
|     InterrogateCoverage._get_coverage (L218)                        | COVERED |
|     InterrogateCoverage.get_coverage (L235)                         | COVERED |
|     InterrogateCoverage._get_filename (L240)                        | COVERED |
|     InterrogateCoverage._get_detailed_row (L251)                    | COVERED |
|     InterrogateCoverage._create_detailed_table (L268)               | COVERED |
|       InterrogateCoverage._create_detailed_table._sort_nodes (L275) | COVERED |
|     InterrogateCoverage._print_detailed_table (L297)                | COVERED |
|     InterrogateCoverage._create_summary_table (L315)                | COVERED |
|     InterrogateCoverage._print_summary_table (L349)                 | COVERED |
|     InterrogateCoverage._sort_results (L367)                        | COVERED |
|     InterrogateCoverage._get_header_base (L397)                     | COVERED |
|     InterrogateCoverage.print_results (L406)                        | COVERED |
|---------------------------------------------------------------------|---------|
| src/interrogate/utils.py (module)                                   | COVERED |
|   parse_regex (L22)                                                 | COVERED |
|   smart_open (L41)                                                  | COVERED |
|   get_common_base (L61)                                             | COVERED |
|   OutputFormatter (L81)                                             | COVERED |
|     OutputFormatter.should_markup (L91)                             | COVERED |
|     OutputFormatter.set_detailed_markup (L106)                      | COVERED |
|     OutputFormatter.set_summary_markup (L130)                       | COVERED |
|     OutputFormatter._interrogate_line_formatter (L159)              | COVERED |
|     OutputFormatter.get_table_formatter (L222)                      | COVERED |
|---------------------------------------------------------------------|---------|
| src/interrogate/visit.py (module)                                   | COVERED |
|   CovNode (L15)                                                     | COVERED |
|   CoverageVisitor (L42)                                             | COVERED |
|     CoverageVisitor._has_doc (L56)                                  | COVERED |
|     CoverageVisitor._visit_helper (L63)                             | COVERED |
|     CoverageVisitor._is_nested (L109)                               | COVERED |
|     CoverageVisitor._is_private (L118)                              | COVERED |
|     CoverageVisitor._is_semiprivate (L126)                          | COVERED |
|     CoverageVisitor._is_ignored_common (L136)                       | COVERED |
|     CoverageVisitor._has_property_decorators (L153)                 | COVERED |
|     CoverageVisitor._is_func_ignored (L167)                         | COVERED |
|     CoverageVisitor._is_class_ignored (L188)                        | COVERED |
|     CoverageVisitor.visit_Module (L192)                             | COVERED |
|     CoverageVisitor.visit_ClassDef (L199)                           | COVERED |
|     CoverageVisitor.visit_FunctionDef (L208)                        | COVERED |
|     CoverageVisitor.visit_AsyncFunctionDef (L217)                   | COVERED |
|---------------------------------------------------------------------|---------|
| tests/functional/__init__.py (module)                               | COVERED |
|---------------------------------------------------------------------|---------|
| tests/functional/test_cli.py (module)                               | COVERED |
|   runner (L22)                                                      | COVERED |
|   test_run_no_paths (L30)                                           | COVERED |
|   test_run_shortflags (L71)                                         | COVERED |
|   test_run_longflags (L97)                                          | COVERED |
|   test_run_multiple_flags (L115)                                    | COVERED |
|   test_generate_badge (L126)                                        | COVERED |
|---------------------------------------------------------------------|---------|
| tests/functional/test_coverage.py (module)                          | COVERED |
|   test_coverage_simple (L42)                                        | COVERED |
|   test_coverage_errors (L55)                                        | COVERED |
|   test_print_results (L83)                                          | COVERED |
|   test_print_results_ignore_module (L117)                           | COVERED |
|   test_print_results_single_file (L144)                             | COVERED |
|---------------------------------------------------------------------|---------|
| tests/unit/__init__.py (module)                                     | COVERED |
|---------------------------------------------------------------------|---------|
| tests/unit/test_badge_gen.py (module)                               | COVERED |
|   test_save_badge (L25)                                             | COVERED |
|   test_save_badge_windows (L47)                                     | COVERED |
|   test_get_badge (L61)                                              | COVERED |
|   test_get_color (L85)                                              | COVERED |
|   test_create (L102)                                                | COVERED |
|---------------------------------------------------------------------|---------|
| tests/unit/test_config.py (module)                                  | COVERED |
|   test_find_project_root (L29)                                      | COVERED |
|   test_find_project_config (L45)                                    | COVERED |
|   test_parse_pyproject_toml (L54)                                   | COVERED |
|   test_sanitize_list_values (L84)                                   | COVERED |
|   test_parse_setup_cfg (L89)                                        | COVERED |
|   test_parse_setup_cfg_raises (L114)                                | COVERED |
|   test_read_config_file_none (L125)                                 | COVERED |
|   test_read_config_file (L184)                                      | COVERED |
|   test_read_config_file_raises (L198)                               | COVERED |
|---------------------------------------------------------------------|---------|
| tests/unit/test_utils.py (module)                                   | COVERED |
|   test_parse_regex (L32)                                            | COVERED |
|   test_smart_open (L39)                                             | COVERED |
|   test_get_common_base (L69)                                        | COVERED |
|   test_get_common_base_windows (L100)                               | COVERED |
|   test_output_formatter_should_markup (L132)                        | COVERED |
|   test_output_formatter_set_detailed_markup (L163)                  | COVERED |
|   test_output_formatter_set_summary_markup (L206)                   | COVERED |
|   test_output_formatter_interrogate_line_formatter (L258)           | COVERED |
|   test_output_formatter_interrogate_line_formatter_windows (L319)   | COVERED |
|   test_output_formatter_get_table_formatter (L343)                  | COVERED |
|   test_output_formatter_get_table_formatter_py38 (L381)             | COVERED |
|   test_output_formatter_get_table_formatter_raises (L395)           | COVERED |
|---------------------------------------------------------------------|---------|

------------------------------------ Summary ------------------------------------
| Name                                  |   Total |   Miss |   Cover |   Cover% |
|---------------------------------------|---------|--------|---------|----------|
| src/interrogate/__init__.py           |       1 |      0 |       1 |     100% |
| src/interrogate/__main__.py           |       1 |      0 |       1 |     100% |
| src/interrogate/badge_gen.py          |       5 |      0 |       5 |     100% |
| src/interrogate/cli.py                |       2 |      0 |       2 |     100% |
| src/interrogate/config.py             |       8 |      0 |       8 |     100% |
| src/interrogate/coverage.py           |      25 |      0 |      25 |     100% |
| src/interrogate/utils.py              |      10 |      0 |      10 |     100% |
| src/interrogate/visit.py              |      16 |      0 |      16 |     100% |
| tests/functional/__init__.py          |       1 |      0 |       1 |     100% |
| tests/functional/test_cli.py          |       7 |      0 |       7 |     100% |
| tests/functional/test_coverage.py     |       6 |      0 |       6 |     100% |
| tests/unit/__init__.py                |       1 |      0 |       1 |     100% |
| tests/unit/test_badge_gen.py          |       6 |      0 |       6 |     100% |
| tests/unit/test_config.py             |      10 |      0 |      10 |     100% |
| tests/unit/test_utils.py              |      13 |      0 |      13 |     100% |
|---------------------------------------|---------|--------|---------|----------|
| TOTAL                                 |     112 |      0 |     112 |   100.0% |
---------------- RESULT: PASSED (minimum: 95.0%, actual: 100.0%) ----------------

Other Usage

Generate a shields.io badge (like this one! interrogate-badge ):

$ interrogate --generate-badge PATH
RESULT: PASSED (minimum: 80.0%, actual: 100.0%)
Generated badge to /Users/lynn/dev/interrogate/docs/_static/interrogate_badge.svg

Add it to your tox.ini file to enforce a level of coverage:

[testenv:doc]
deps = interrogate
skip_install = true
commands =
    interrogate --quiet --fail-under 95 src tests

Or use it with pre-commit:

repos:
  - repo: https://github.com/econchick/interrogate
    rev: 1.3.2  # or master if you're bold
    hooks:
      - id: interrogate
        args: [--quiet, --fail-under=95]

Use it within your code directly:

>>> from interrogate import coverage
>>> cov = coverage.InterrogateCoverage(paths=["src"])
>>> results = cov.get_coverage()
>>> results
InterrogateResults(total=68, covered=65, missing=3)

Use interrogate with GitHub Actions. Check out the action written & maintained by Jack McKew (thank you, Jack!).

Configuration

Configure within your pyproject.toml (interrogate will automatically detect a pyproject.toml file and pick up default values for the command line options):

$ interrogate -c pyproject.toml [OPTIONS] [PATHS]...
[tool.interrogate]
ignore-init-method = true
ignore-init-module = false
ignore-magic = false
ignore-semiprivate = false
ignore-private = false
ignore-property-decorators = false
ignore-module = false
fail-under = 95
exclude = ["setup.py", "docs", "build"]
ignore-regex = ["^get$", "^mock_.*", ".*BaseClass.*"]
verbose = 0
quiet = false
whitelist-regex = []
color = true

Or configure within your setup.cfg (interrogate will automatically detect a setup.cfg file and pick up default values for the command line options):

$ interrogate -c setup.cfg [OPTIONS] [PATHS]...
[tool:interrogate]
ignore-init-method = true
ignore-init-module = false
ignore-magic = false
ignore-semiprivate = false
ignore-private = false
ignore-property-decorators = false
ignore-module = false
fail-under = 95
exclude = setup.py,docs,build
ignore-regex = ^get$,^mock_.*,.*BaseClass.*
verbose = 0
quiet = false
whitelist-regex =
color = true

Warning

The use of setup.cfg is not recommended unless for very simple use cases. .cfg files use a different parser than pyproject.toml which might cause hard to track down problems. When possible, it is recommended to use pyproject.toml to define your interrogate configuration.

To view all options available, run interrogate --help:

interrogate -h
Usage: interrogate [OPTIONS] [PATHS]...

  Measure and report on documentation coverage in Python modules.

Options:
  --version                       Show the version and exit.
  -v, --verbose                   Level of verbosity  [default: 0]
  -q, --quiet                     Do not print output  [default: False]
  -f, --fail-under INT | FLOAT    Fail when coverage % is less than a given
                                  amount.  [default: 80.0]

  -e, --exclude PATH              Exclude PATHs of files and/or directories.
                                  Multiple `-e/--exclude` invocations
                                  supported.

  -i, --ignore-init-method        Ignore `__init__` method of classes.
                                  [default: False]

  -I, --ignore-init-module        Ignore `__init__.py` modules.  [default:
                                  False]

  -m, --ignore-magic              Ignore all magic methods of classes.
                                  [default: False]

                                  NOTE: This does not include the `__init__`
                                  method. To ignore `__init__` methods, use
                                  `--ignore-init-method`.

  -M, --ignore-module             Ignore module-level docstrings.  [default:
                                  False]

  -n, --ignore-nested-functions   Ignore nested functions and methods.
                                  [default: False]

  -p, --ignore-private            Ignore private classes, methods, and
                                  functions starting with two underscores.
                                  [default: False]

                                  NOTE: This does not include magic methods;
                                  use `--ignore-magic` and/or `--ignore-init-
                                  method` instead.

  -P, --ignore-property-decorators
                                  Ignore methods with property setter/getter
                                  decorators.  [default: False]

  -s, --ignore-semiprivate        Ignore semiprivate classes, methods, and
                                  functions starting with a single underscore.
                                  [default: False]

  -r, --ignore-regex STR          Regex identifying class, method, and
                                  function names to ignore. Multiple
                                  `-r/--ignore-regex` invocations supported.

  -w, --whitelist-regex STR       Regex identifying class, method, and
                                  function names to include. Multiple
                                  `-w/--whitelist-regex` invocations
                                  supported.

  -o, --output FILE               Write output to a given FILE.  [default:
                                  stdout]

  --color / --no-color            Toggle color output on/off when printing to
                                  stdout.  [default: True]

  -g, --generate-badge PATH       Generate a 'shields.io' status badge (an SVG
                                  image) in at a given file or directory. Will
                                  not generate a badge if results did not
                                  change from an existing badge of the same
                                  path.

  -h, --help                      Show this message and exit.
  -c, --config FILE               Read configuration from `pyproject.toml` or
                                  `setup.cfg`.

Credits

interrogate was inspired by docstr-coverage, which was forked from Alexey "DataGreed" Strelkov's docstring-coverage, which was inspired by a 2004 recipe from James Harlow (turtles...).

The cute sloth logo is by JustineW purchased via the Noun Project (but also available under the Creative Commons License with attribution).

Owner
Lynn Root
Staff Engineer @spotify, @pyladies leader; @roguelynn on Twitter.
Lynn Root
Python For Finance Cookbook - Code Repository

Python For Finance Cookbook - Code Repository

Packt 544 Dec 25, 2022
A collection of lecture notes, drawings, flash cards, mind maps, scripts

Neuroanatomy A collection of lecture notes, drawings, flash cards, mind maps, scripts and other helpful resources for the course "Functional Organizat

Georg Reich 3 Sep 21, 2022
✨ Real-life Data Analysis and Model Training Workshop by Global AI Hub.

🎓 Data Analysis and Model Training Course by Global AI Hub Syllabus: Day 1 What is Data? Multimedia Structured and Unstructured Data Data Types Data

Global AI Hub 71 Oct 28, 2022
Visualizacao-dados-dell - Repositório com as atividades desenvolvidas no curso de Visualização de Dados

📚 Descrição Neste curso da Dell trabalhamos com a visualização de dados. 🖥️ Aulas 1.1 - Explorando conjuntos de dados 1.2 - Fundamentos de visualiza

Claudia dos Anjos 1 Dec 28, 2021
PythonCoding Tutorials - Small functions that would summarize what is needed for python coding

PythonCoding_Tutorials Small functions that would summarize what is needed for p

Hosna Hamdieh 2 Jan 03, 2022
Anomaly Detection via Reverse Distillation from One-Class Embedding

Anomaly Detection via Reverse Distillation from One-Class Embedding Implementation (Official Code ⭐️ ⭐️ ⭐️ ) Environment pytorch == 1.91 torchvision =

73 Dec 19, 2022
Reproducible Data Science at Scale!

Pachyderm: The Data Foundation for Machine Learning Pachyderm provides the data layer that allows machine learning teams to productionize and scale th

Pachyderm 5.7k Dec 29, 2022
A Python validator for SHACL

pySHACL A Python validator for SHACL. This is a pure Python module which allows for the validation of RDF graphs against Shapes Constraint Language (S

RDFLib 187 Dec 29, 2022
Exercism exercises in Python.

Exercism exercises in Python.

Exercism 1.3k Jan 04, 2023
LotteryBuyPredictionWebApp - Lottery Purchase Prediction Model

Lottery Purchase Prediction Model Objective and Goal Predict the lottery type th

Wanxuan Zhang 2 Feb 14, 2022
Course materials and handouts for #100DaysOfCode in Python course

#100DaysOfCode with Python course Course details page: talkpython.fm/100days Course Summary #100DaysOfCode in Python is your perfect companion to take

Talk Python 1.9k Dec 31, 2022
Plugins for MkDocs.

Plugins for MkDocs and Python Markdown pip install neoteroi-mkdocs This package includes the following plugins and extensions: Name Description Type m

35 Dec 23, 2022
Contains the assignments from the course Building a Modern Computer from First Principles: From Nand to Tetris.

Contains the assignments from the course Building a Modern Computer from First Principles: From Nand to Tetris.

Matheus Rodrigues 1 Jan 20, 2022
🌱 Complete API wrapper of Seedr.cc

Python API Wrapper of Seedr.cc Table of Contents Installation How I got the API endpoints? Start Guide Getting Token Logging with Username and Passwor

Hemanta Pokharel 43 Dec 26, 2022
A hack to run custom shell commands when building documentation on Read the Docs.

readthedocs-custom-steps A hack to run custom steps when building documentation on Read the Docs. Important: This module should not be installed outsi

Niklas Rosenstein 5 Feb 22, 2022
Get link preview of a website.

Preview Link You may have seen a preview of a link with a title, image, domain, and description when you share a link on social media. This preview ha

SREEHARI K.V 8 Jan 08, 2023
Easy OpenAPI specs and Swagger UI for your Flask API

Flasgger Easy Swagger UI for your Flask API Flasgger is a Flask extension to extract OpenAPI-Specification from all Flask views registered in your API

Flasgger 3.1k Dec 24, 2022
Some code that takes a pipe-separated input and converts that into a table!

tablemaker A program that takes an input: a | b | c # With comments as well. e | f | g h | i |jk And converts it to a table: ┌───┬───┬────┐ │ a │ b │

CodingSoda 2 Aug 30, 2022
Parser manager for parsing DOC, DOCX, PDF or HTML files

Parser manager Description Parser gets PDF, DOC, DOCX or HTML file via API and saves parsed data to the database. Implemented in Ruby 3.0.1 using Acti

Эдем 4 Dec 04, 2021
30 Days of google cloud leaderboard website

30 Days of Cloud Leaderboard This is a leaderboard for the students of Thapar, Patiala who are participating in the 2021 30 days of Google Cloud Platf

Developer Student Clubs TIET 13 Aug 25, 2022