<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jazzy JJ</title>
    <description>The latest articles on DEV Community by Jazzy JJ (@jazzyjj0601).</description>
    <link>https://dev.to/jazzyjj0601</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4153074%2F43274411-0a96-4c10-a276-5955962010fd.jpg</url>
      <title>DEV Community: Jazzy JJ</title>
      <link>https://dev.to/jazzyjj0601</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jazzyjj0601"/>
    <language>en</language>
    <item>
      <title>I audited marshmallow's docs: 184 missing docstrings, 65 stale. Here's the tool I built to fix that</title>
      <dc:creator>Jazzy JJ</dc:creator>
      <pubDate>Fri, 02 Oct 2026 20:18:14 +0000</pubDate>
      <link>https://dev.to/jazzyjj0601/i-audited-marshmallows-docs-184-missing-docstrings-65-stale-heres-the-tool-i-built-to-fix-that-455b</link>
      <guid>https://dev.to/jazzyjj0601/i-audited-marshmallows-docs-184-missing-docstrings-65-stale-heres-the-tool-i-built-to-fix-that-455b</guid>
      <description>&lt;p&gt;Most teams have one repo nobody wants to touch. It works, it matters, and the people who understood it have moved on. Half the functions have no docstring, and the ones that do often describe a signature that changed years ago.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Legacy Doc-AI&lt;/strong&gt; to deal with that repo. It's a small CLI that does two jobs: it tells you exactly where the documentation is missing or out of date, and it drafts docstrings and a README for you to review.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it found in marshmallow
&lt;/h2&gt;

&lt;p&gt;To test it on real code, I pointed it at the source of &lt;a href="https://github.com/marshmallow-code/marshmallow" rel="noopener noreferrer"&gt;marshmallow&lt;/a&gt;, a well-maintained, widely used Python library. &lt;code&gt;legacy-doc-ai check&lt;/code&gt; reported:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Files analysed&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Functions and methods&lt;/td&gt;
&lt;td&gt;236&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Classes&lt;/td&gt;
&lt;td&gt;63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Functions with a docstring&lt;/td&gt;
&lt;td&gt;59 of 236&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Missing docstrings (functions + classes)&lt;/td&gt;
&lt;td&gt;184&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stale docstrings&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;"Stale" here means something specific and checkable: the function takes a parameter that its docstring never mentions. All 65 flags are of that kind. If a well-kept library has gaps like this, your 2014 internal service probably has more.&lt;/p&gt;

&lt;p&gt;The full report is here: &lt;a href="https://legacy-doc-ai.pages.dev/sample-audit.html" rel="noopener noreferrer"&gt;sample audit of marshmallow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parse, don't guess.&lt;/strong&gt; It walks the code's syntax tree (Python's &lt;code&gt;ast&lt;/code&gt;) to list every function, class, parameter and existing docstring. That's what powers the coverage numbers and the stale-parameter check: no AI involved, so those numbers are exact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Draft with a language model.&lt;/strong&gt; For each undocumented function it sends the function's code to a model and asks for a docstring in a consistent style. It works with OpenAI or Anthropic models, or any OpenAI-compatible endpoint, including a model running on your own machine, so the code doesn't have to leave it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review before anything changes.&lt;/strong&gt; &lt;code&gt;--dry-run&lt;/code&gt; prints every proposed docstring without touching a file.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A real before and after
&lt;/h2&gt;

&lt;p&gt;This is from the marshmallow run, using a small local model (Qwen2.5-3B), copied verbatim from the log.&lt;/p&gt;

&lt;p&gt;Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not a valid POSIX timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not a valid POSIX timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;from_timestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Convert a value to a datetime object based on a POSIX timestamp.

    Args:
        value (Any): The value to convert. If a boolean, raises a ValueError.

    Returns:
        datetime.datetime: The datetime object corresponding to the timestamp.

    Raises:
        ValueError: If the value is a boolean, or if the value is less than 0.
        ValueError: If there is an overflow error during conversion.
        ValueError: If there is an OSError during conversion.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It picked up the edge cases from the code itself: booleans, negatives, overflow. One honest caveat: a 3B model occasionally rewrites a type name (&lt;code&gt;dt.datetime&lt;/code&gt; became &lt;code&gt;datetime.datetime&lt;/code&gt; in the text), which is exactly why every change goes through review.&lt;/p&gt;

&lt;h2&gt;
  
  
  The commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;legacy-doc-ai check path/to/repo                  &lt;span class="c"&gt;# coverage + stale docstrings&lt;/span&gt;
legacy-doc-ai docstrings &lt;span class="nt"&gt;--dry-run&lt;/span&gt; path/to/repo   &lt;span class="c"&gt;# proposed docstrings, nothing written&lt;/span&gt;
legacy-doc-ai readme &lt;span class="nt"&gt;--dry-run&lt;/span&gt; path/to/repo       &lt;span class="c"&gt;# a README drafted from the code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why not Sphinx, Doxygen or Copilot?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sphinx and Doxygen&lt;/strong&gt; publish the docstrings you already have. With 184 missing, there isn't much to publish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copilot&lt;/strong&gt; will write a docstring for the function in front of you. It won't tell you which 184 are missing or which 65 have drifted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Legacy Doc-AI is the step before those tools: find the gaps across the whole repo, fill them, and keep them from drifting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it on your repo
&lt;/h2&gt;

&lt;p&gt;I'm running free audits while I get this in front of people. Send me a public repo URL and I'll send back the same report you saw for marshmallow, plus sample docstrings for a few of its worst-documented functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site: &lt;a href="https://legacy-doc-ai.pages.dev" rel="noopener noreferrer"&gt;legacy-doc-ai.pages.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Email: &lt;a href="mailto:jasperjensen8888@gmail.com"&gt;jasperjensen8888@gmail.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the free first run it's £39 per repo per month. I'd especially like to hear from anyone looking after a codebase older than its current team.&lt;/p&gt;

</description>
      <category>python</category>
      <category>documentation</category>
      <category>devtools</category>
      <category>legacycode</category>
    </item>
    <item>
      <title>I scanned four popular Python libraries for missing docstrings</title>
      <dc:creator>Jazzy JJ</dc:creator>
      <pubDate>Wed, 30 Sep 2026 20:31:33 +0000</pubDate>
      <link>https://dev.to/jazzyjj0601/i-scanned-four-popular-python-libraries-for-missing-docstrings-5c65</link>
      <guid>https://dev.to/jazzyjj0601/i-scanned-four-popular-python-libraries-for-missing-docstrings-5c65</guid>
      <description>&lt;p&gt;Old Python projects rot in a quiet way. Functions get new parameters and the docstring above them stays frozen. I've been building a command-line tool, Legacy Doc-AI, that finds those gaps and drafts fixes. To see if the problem is real, I pointed its scanner at four well-known libraries.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the scan found
&lt;/h2&gt;

&lt;p&gt;Functions with no docstring at all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;marshmallow: 177 of 236 (75%)&lt;/li&gt;
&lt;li&gt;flask: 596 of 856 (70%)&lt;/li&gt;
&lt;li&gt;requests: 392 of 635 (62%)&lt;/li&gt;
&lt;li&gt;urllib3: 1293 of 1634 (79%)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are raw counts. The scanner counts every function and method it finds, including private helpers and tests, and many of those are fine without docs. So read them as "how much is uncovered", not "how badly these projects are run".&lt;/p&gt;

&lt;h2&gt;
  
  
  What the tool does
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;It reads your code and lists every function and class.&lt;/li&gt;
&lt;li&gt;It flags the ones with no docstring, or whose documented parameters differ from the real ones.&lt;/li&gt;
&lt;li&gt;It sends each function and its surrounding code to an AI model, which drafts a docstring.&lt;/li&gt;
&lt;li&gt;It shows you the changes, and nothing is written until you accept them.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where it's at
&lt;/h2&gt;

&lt;p&gt;It's early. I'm not claiming it writes perfect docs, and I haven't measured how accurate the drafts are. I want honest feedback from people who maintain older Python code.&lt;/p&gt;

&lt;p&gt;There's a free audit: send me a public repo and I'll send back the coverage report. Sign-up is at &lt;a href="https://legacy-doc-ai.pages.dev" rel="noopener noreferrer"&gt;https://legacy-doc-ai.pages.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The planned price is £39 per repo per month. Does that sound sensible? And what would make you trust generated docstrings in your repo?&lt;/p&gt;

</description>
      <category>python</category>
      <category>documentation</category>
      <category>opensource</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
