<?xml version='1.0' encoding='utf-8'?>
<rss version="2.0"><channel><title>Bug Casebook</title><link>https://bug-casebook.pages.dev/en/</link><description>Investigating the root causes and fixes behind real development problems, plus guides and ideas</description><language>en</language><item><title>If a Python import reads your own file instead of the standard library, check whether the file is named inspect.py</title><link>https://bug-casebook.pages.dev/en/posts/python-file-named-inspect-shadows-stdlib-en/</link><guid>https://bug-casebook.pages.dev/en/posts/python-file-named-inspect-shadows-stdlib-en/</guid><description>&lt;p&gt;While scoring kept failing in an automated content pipeline (content-loop-mvp), I was writing a small diagnostic script to print per-criterion scores. The script wouldn&amp;#x27;t run on Windows 11, and a file named &lt;code&gt;inspect.py&lt;/code&gt; was blamed.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;When Python resolves a module, it searches the folder the running script lives in *before* it searches the standard library (the modules that ship with Python itself). So if &lt;code&gt;inspect.py&lt;/code&gt; sits in that same folder, &lt;code&gt;import inspect&lt;/code&gt; reads that file instead of the standard library&amp;#x27;s &lt;code&gt;inspect&lt;/code&gt;. One line confirms it either way:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python -c &amp;quot;import inspect; print(inspect.__file__)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the printed path points inside your own project folder, the standard library has been shadowed.&lt;/p&gt;
&lt;p&gt;In this session, that one line was never actually run. The script was renamed and re-run, but an old &lt;code&gt;inspect.py&lt;/code&gt; left over in a scratch folder was still being picked up from the same spot , and the record cuts off right there once the session hit its turn limit .&lt;/p&gt;
&lt;p&gt;If renaming doesn&amp;#x27;t fix it and the same error keeps showing up in the same place, do these three things:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;Delete the old &lt;code&gt;inspect.py&lt;/code&gt;. If you don&amp;#x27;t want to delete it, move it to a different folder.&lt;/li&gt;&lt;li&gt;In the folder you&amp;#x27;re running from, list &lt;code&gt;*.py&lt;/code&gt; (&lt;code&gt;dir *.py&lt;/code&gt; on Windows, &lt;code&gt;ls *.py&lt;/code&gt; on Mac/Linux) and check whether any other file shares a name with a standard library module.&lt;/li&gt;&lt;li&gt;Re-run the one-liner above and confirm &lt;code&gt;inspect.__file__&lt;/code&gt; now points at the standard library path.&lt;/li&gt;&lt;/ol&gt;
&lt;h2&gt;Situation&lt;/h2&gt;
&lt;p&gt;content-loop-mvp is a Korean-language content pipeline: it generates topic candidates, gathers and cross-checks evidence from the web, writes the article, then has a separate model screen it — only articles that pass get saved. Originally all four stages required an OpenAI or Gemini API key to run . In this session, the decision was made to skip API keys entirely and shell out to the Claude and Codex CLIs as subprocesses to stand in for the model calls . All four stages actually running on Claude came after that . The condition was that the bar (minimum topic score of 75) would not be lowered .&lt;/p&gt;
&lt;p&gt;The problem: even with the bar unchanged, five runs in a row produced zero articles. The highest topic score stayed at 74 . Adding per-criterion grading instructions to the scoring prompt and re-running still capped out at 72–74 . So the plan became: write a one-off diagnostic script to print one candidate&amp;#x27;s score, broken down by criterion .&lt;/p&gt;
&lt;h2&gt;Symptom&lt;/h2&gt;
&lt;p&gt;Running the diagnostic script failed. The AI concluded &amp;quot;the file is named &lt;code&gt;inspect.py&lt;/code&gt;, which conflicts with the standard library&amp;#x27;s &lt;code&gt;inspect&lt;/code&gt;&amp;quot; and decided to rename it and re-run . But the record doesn&amp;#x27;t contain the actual error message — there&amp;#x27;s no line confirming what the error actually was, or that it was really caused by the &lt;code&gt;inspect&lt;/code&gt; shadowing.&lt;/p&gt;
&lt;h2&gt;Cause&lt;/h2&gt;
&lt;p&gt;The only cause on record is &amp;quot;because the file is named &lt;code&gt;inspect.py&lt;/code&gt;.&amp;quot; The name does collide with a standard library module, and the one-liner above would confirm the shadowing immediately — but in this session, that confirmation never happened. So this can&amp;#x27;t be written up as a confirmed cause for this session.&lt;/p&gt;
&lt;h2&gt;Fix&lt;/h2&gt;
&lt;p&gt;The plan was to rename the file and re-run, but the old &lt;code&gt;inspect.py&lt;/code&gt; left behind in the scratch folder was still being picked up from the same location . Right as the old file was about to be deleted and re-run, the session hit its turn limit . So this article can&amp;#x27;t claim &amp;quot;fixed.&amp;quot; The fix only counts as done once the old file is removed and the one-liner confirms which file is actually being read.&lt;/p&gt;
&lt;h2&gt;Bonus — renaming the file and removing the old one are not the same thing&lt;/h2&gt;
&lt;p&gt;Renaming avoids the new file being shadowed, but an old file left in the same folder keeps getting picked up regardless of what you rename the new one to. After renaming, list the folder again and check there isn&amp;#x27;t another &lt;code&gt;.py&lt;/code&gt; file sharing a name with a standard library module. Putting a diagnostic script in a scratch/temp folder sets the same trap.&lt;/p&gt;
&lt;h2&gt;Reporter&amp;#x27;s Notes — thought renaming one file would be the end of it&lt;/h2&gt;
&lt;p class="narration"&gt;A diagnostic script meant to print per-criterion topic scores won&amp;#x27;t run. There&amp;#x27;s no note quoting the actual error message.&lt;/p&gt;
&lt;div class="dialogue right" data-speaker="Jung Bada"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-bada.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Bada&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;The diagnostic script won&amp;#x27;t run. I built it to see why the topic score is stuck at 74, but I think the problem is the filename &lt;code&gt;inspect.py&lt;/code&gt; — it collides with the standard library&amp;#x27;s &lt;code&gt;inspect&lt;/code&gt; &lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue left" data-speaker="Jung Haneul"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-haneul.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Haneul&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;How did you confirm the error is actually about &lt;code&gt;inspect&lt;/code&gt;? Same name is a guess — have you actually seen which file got read?&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue right" data-speaker="Jung Bada"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-bada.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Bada&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;I know Python searches the folder you ran from first. Same name means it obviously reads my file&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue right" data-speaker="Park Doeun"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/park-doeun.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Park Doeun&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;Wait, what does &amp;quot;searches first&amp;quot; even mean? I thought Python just finds things automatically when you import&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue right" data-speaker="Jung Bada"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-bada.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Bada&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;There&amp;#x27;s a search path list. The first entry is the folder you ran from, so if &lt;code&gt;inspect.py&lt;/code&gt; is there, it gets picked up before the standard library. So renaming it should be the end of it&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue left" data-speaker="Park Dohyun"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/park-dohyun.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Park Dohyun&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;&amp;quot;Renaming is the end of it&amp;quot; is the most expensive assumption here. How do you tell &amp;quot;fixed&amp;quot; apart from &amp;quot;just hidden&amp;quot;?&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue left" data-speaker="Jung Haneul"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-haneul.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Haneul&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;If Bada&amp;#x27;s right, &lt;code&gt;inspect.__file__&lt;/code&gt; should print our folder&amp;#x27;s path. Until you print it, it&amp;#x27;s just a hypothesis&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue right" data-speaker="Jung Bada"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-bada.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Bada&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;Printing it can wait. I&amp;#x27;ll rename it first and re-run &lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue right" data-speaker="Park Doeun"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/park-doeun.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Park Doeun&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;You renamed it and it&amp;#x27;s still hitting the same spot? The old &lt;code&gt;inspect.py&lt;/code&gt; was still sitting in the scratch folder &lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue right" data-speaker="Jung Bada"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-bada.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Bada&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;Oh — the renamed one is a new file, but the old one was still there. As long as that file exists, it gets picked up no matter what you rename the new one to&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue left" data-speaker="Park Dohyun"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/park-dohyun.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Park Dohyun&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;So what&amp;#x27;s the actual state right now? Fixed, or just hidden?&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue left" data-speaker="Jung Haneul"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-haneul.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Haneul&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;Neither. Deleting the old file and printing the result was supposed to be next, but the day&amp;#x27;s turn budget ran out right there &lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue right" data-speaker="Park Doeun"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/park-doeun.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Park Doeun&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;So we still don&amp;#x27;t know the outcome?&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue right" data-speaker="Jung Bada"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/jung-bada.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Jung Bada&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;Right, nobody knows yet. Until we print it, even the cause is just a hypothesis&lt;/div&gt;&lt;/div&gt;
&lt;div class="dialogue left" data-speaker="Park Dohyun"&gt;&lt;div class="speaker"&gt;&lt;img class="avatar" src="../../assets/characters/park-dohyun.webp" alt="" width="48" height="48" loading="lazy"&gt;&lt;span&gt;Park Dohyun&lt;/span&gt;&lt;/div&gt;&lt;div class="speech"&gt;Then there&amp;#x27;s one lesson left: grab the actual error message first, confirm the hypothesis in one line, and only then rename anything&lt;/div&gt;&lt;/div&gt;</description></item></channel></rss>