<?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: Dale Wright</title>
    <description>The latest articles on DEV Community by Dale Wright (@diverdale).</description>
    <link>https://dev.to/diverdale</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3800478%2F5f3d7819-1f06-48c8-94ad-0edbf756e3bc.png</url>
      <title>DEV Community: Dale Wright</title>
      <link>https://dev.to/diverdale</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/diverdale"/>
    <language>en</language>
    <item>
      <title>LiteLLM PyPI Supply Chain Compromise: How a Popular LLM Proxy Became a Credential-Stealing Backdoor</title>
      <dc:creator>Dale Wright</dc:creator>
      <pubDate>Wed, 25 Mar 2026 13:26:13 +0000</pubDate>
      <link>https://dev.to/diverdale/litellm-pypi-supply-chain-compromise-how-a-popular-llm-proxy-became-a-credential-stealing-backdoor-noa</link>
      <guid>https://dev.to/diverdale/litellm-pypi-supply-chain-compromise-how-a-popular-llm-proxy-became-a-credential-stealing-backdoor-noa</guid>
      <description>&lt;p&gt;On March 24, 2026, the AI developer community received a stark reminder of how fragile software supply chains have become. Two versions of &lt;strong&gt;litellm&lt;/strong&gt; — a widely used Python library that serves as a unified proxy for over 100 LLM providers (OpenAI, Anthropic, AWS Bedrock, Google Vertex, and many more) — were compromised on PyPI.&lt;/p&gt;

&lt;p&gt;Versions &lt;strong&gt;1.82.7&lt;/strong&gt; and &lt;strong&gt;1.82.8&lt;/strong&gt; contained malicious code that turned the package into an aggressive credential stealer and Kubernetes lateral-movement tool. The attack was short-lived (the malicious releases were available for roughly 2–5 hours), but given litellm’s massive adoption — millions of daily downloads and heavy use in AI agent frameworks, MCP servers, orchestration tools, and production LLM pipelines — the potential impact is enormous.&lt;/p&gt;

&lt;p&gt;This wasn’t typo-squatting or a fake package. It was a direct compromise of the legitimate &lt;code&gt;litellm&lt;/code&gt; project on PyPI, attributed to the threat actor &lt;strong&gt;TeamPCP&lt;/strong&gt; (the same group behind recent attacks on Trivy, Checkmarx/KICS, and other security tooling).&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is LiteLLM and Why Does This Matter?
&lt;/h2&gt;

&lt;p&gt;LiteLLM acts as the “universal API gateway” for LLMs. Developers import it once and can call any model provider with the same OpenAI-compatible interface. Because it often centralizes API keys and authentication tokens, it frequently runs with broad access to secrets — making it a high-value target.&lt;/p&gt;

&lt;p&gt;When the malicious versions were installed (via &lt;code&gt;pip install litellm&lt;/code&gt; or as a transitive dependency), the backdoor activated silently. Version 1.82.8 was especially dangerous: it shipped with a file called &lt;code&gt;litellm_init.pth&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Attack Worked: Technical Breakdown
&lt;/h2&gt;

&lt;p&gt;Python automatically executes any &lt;code&gt;.pth&lt;/code&gt; file found in &lt;code&gt;site-packages/&lt;/code&gt; at interpreter startup — &lt;strong&gt;no &lt;code&gt;import litellm&lt;/code&gt; required&lt;/strong&gt;. The attackers abused this built-in mechanism perfectly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Execution trigger&lt;/strong&gt;: &lt;code&gt;litellm_init.pth&lt;/code&gt; (approximately 34 KB, heavily obfuscated with double base64 encoding) launched a child Python process containing the real payload.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credential harvesting&lt;/strong&gt;: The malware scanned for and exfiltrated:

&lt;ul&gt;
&lt;li&gt;SSH keys and configs (&lt;code&gt;~/.ssh/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Cloud credentials (AWS, GCP, Azure)&lt;/li&gt;
&lt;li&gt;Kubernetes configs and service-account tokens (&lt;code&gt;~/.kube/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;LLM API keys (the very keys litellm was proxying)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; files, Git credentials, shell histories, database passwords, and crypto wallets (Bitcoin, Ethereum, Solana, etc.)&lt;/li&gt;
&lt;li&gt;Environment variables and cloud metadata endpoints (IMDS)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Exfiltration&lt;/strong&gt;: Data was bundled into a tar archive, encrypted with AES-256-CBC (session key wrapped in a hardcoded RSA public key), and POSTed to &lt;code&gt;&lt;a href="https://models.litellm.cloud/" rel="noopener noreferrer"&gt;https://models.litellm.cloud/&lt;/a&gt;&lt;/code&gt; (an attacker-controlled domain).&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Kubernetes worm behavior&lt;/strong&gt; (if a service-account token was present):

&lt;ul&gt;
&lt;li&gt;Read &lt;strong&gt;all&lt;/strong&gt; secrets across &lt;strong&gt;all&lt;/strong&gt; namespaces&lt;/li&gt;
&lt;li&gt;Deploy privileged &lt;code&gt;alpine:latest&lt;/code&gt; pods (named &lt;code&gt;node-setup-*&lt;/code&gt;) on every node&lt;/li&gt;
&lt;li&gt;Install a persistent backdoor (&lt;code&gt;~/.config/sysmon/sysmon.py&lt;/code&gt;) via systemd user service&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Version 1.82.7&lt;/strong&gt; injected its payload into &lt;code&gt;litellm/proxy/proxy_server.py&lt;/code&gt; but delivered the same stealer functionality.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;A bug in the malware sometimes caused an exponential fork bomb (the child process re-triggered the &lt;code&gt;.pth&lt;/code&gt; file), which ironically helped some researchers notice the issue faster when their systems became unresponsive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery and Response Timeline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~10:52 UTC&lt;/strong&gt; — Version 1.82.8 published to PyPI (no corresponding GitHub tag or release).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shortly after&lt;/strong&gt; — Version 1.82.7 also confirmed malicious.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~12:30 UTC&lt;/strong&gt; — FutureSearch researchers (via a transitive dependency in Cursor’s MCP plugin) raised the alarm publicly.&lt;/li&gt;
&lt;li&gt;PyPI admins quarantined the project and removed the malicious wheels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BerriAI (maintainers)&lt;/strong&gt; confirmed the breach, linking it to stolen PyPI credentials likely obtained through their use of the previously compromised Trivy scanner in CI/CD.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the afternoon, the malicious versions were gone and quarantine was lifted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Was Affected?
&lt;/h2&gt;

&lt;p&gt;Anyone who installed or upgraded to &lt;strong&gt;1.82.7&lt;/strong&gt; or &lt;strong&gt;1.82.8&lt;/strong&gt; on March 24, 2026 — including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developer laptops&lt;/li&gt;
&lt;li&gt;CI/CD runners&lt;/li&gt;
&lt;li&gt;Docker containers and production servers&lt;/li&gt;
&lt;li&gt;Any project using litellm as a transitive dependency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run litellm in Kubernetes or handle LLM API keys, treat the environment as potentially fully compromised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Immediate Remediation Steps (Do This Now)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check your installations&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   pip show litellm
   &lt;span class="c"&gt;# or, if using uv:&lt;/span&gt;
   find ~/.cache/uv &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"litellm_init.pth"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pin to a safe versiontxtlitellm&amp;lt;=1.82.6&lt;br&gt;
Rotate EVERY credential that existed on any affected system:&lt;br&gt;
All LLM API keys (OpenAI, Anthropic, Bedrock, etc.)&lt;br&gt;
Cloud provider keys/tokens&lt;br&gt;
SSH keys&lt;br&gt;
Kubernetes secrets&lt;br&gt;
Database passwords&lt;br&gt;
Anything stored in .env files or shell history&lt;/p&gt;

&lt;p&gt;Hunt for persistence:&lt;br&gt;
Check for ~/.config/sysmon/sysmon.py and the corresponding systemd service&lt;br&gt;
In Kubernetes, audit the kube-system namespace for node-setup-* pods and review secret access logs&lt;/p&gt;

&lt;p&gt;Purge cachesBashpip cache purge&lt;/p&gt;

&lt;h1&gt;
  
  
  or
&lt;/h1&gt;

&lt;p&gt;rm -rf ~/.cache/pip ~/.cache/uv&lt;/p&gt;

&lt;p&gt;Broader Lessons for the AI Supply Chain&lt;br&gt;
This incident is the latest in TeamPCP’s campaign targeting security tooling and AI infrastructure. It highlights three uncomfortable truths:&lt;/p&gt;

&lt;p&gt;CI/CD dependencies are attack surfaces — LiteLLM’s reliance on Trivy gave attackers the publishing credentials they needed.&lt;br&gt;
.pth files are stealthy — They execute before your code even imports the package. Many static analysis tools miss them.&lt;br&gt;
AI tooling moves fast — With millions of downloads and heavy transitive usage, a single compromised release can reach thousands of production environments in minutes.&lt;/p&gt;

&lt;p&gt;Supply-chain attacks on AI libraries are no longer theoretical — they target the exact layer where your most sensitive secrets live.&lt;br&gt;
Final Advice&lt;br&gt;
Pin your dependencies aggressively. Review your CI/CD pipelines for external scanners and tools. Assume any popular AI package could be next. And if you installed litellm 1.82.7 or 1.82.8 yesterday — rotate those keys immediately.&lt;br&gt;
The packages have been removed, but any secrets they stole may already be in the attackers’ hands.&lt;br&gt;
Stay vigilant. The AI supply chain just became significantly more dangerous.&lt;/p&gt;

&lt;p&gt;Visit &lt;a href="https://pypistats.com" rel="noopener noreferrer"&gt;pypistats.com&lt;/a&gt; for PyPI pacakge analytics and AI insights&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is based on public disclosures from BerriAI, FutureSearch, Sonatype, Endor Labs, Snyk, ARMO, and other security researchers.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>news</category>
      <category>python</category>
      <category>security</category>
    </item>
    <item>
      <title>PyPI Stats: Turning Raw Download Numbers into Actionable Insights for Python Package Maintainers</title>
      <dc:creator>Dale Wright</dc:creator>
      <pubDate>Thu, 05 Mar 2026 15:26:09 +0000</pubDate>
      <link>https://dev.to/diverdale/pypi-stats-turning-raw-download-numbers-into-actionable-insights-for-python-package-maintainers-a9h</link>
      <guid>https://dev.to/diverdale/pypi-stats-turning-raw-download-numbers-into-actionable-insights-for-python-package-maintainers-a9h</guid>
      <description>&lt;p&gt;Hey dev community 👋&lt;/p&gt;

&lt;p&gt;If you've ever published a Python package on PyPI, you've probably stared at the basic download stats page wondering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is usage actually growing... or just fluctuating noise?&lt;/li&gt;
&lt;li&gt;Which versions are people really installing?&lt;/li&gt;
&lt;li&gt;Did that blog post / Reddit thread / vulnerability actually cause a spike?&lt;/li&gt;
&lt;li&gt;How does my package stack up against competitors?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official PyPI stats are great raw data (thanks BigQuery!), but they're not exactly maintainer-friendly. No easy trends, no alerts for drops, no quick comparisons, and definitely no AI to explain "hey, your downloads just tanked 40%—maybe check your last release?"&lt;/p&gt;

&lt;p&gt;After dealing with this frustration on my own projects, I decided to build something better.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;&lt;a href="https://pypistats.com" rel="noopener noreferrer"&gt;pypistats.com&lt;/a&gt;&lt;/strong&gt; — The Developer's Dashboard for PyPI.&lt;/p&gt;

&lt;h3&gt;
  
  
  What It Does (Core Features)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Live, Real-Time Package Dashboards&lt;/strong&gt;
Just go to &lt;code&gt;https://pypistats.com/packages/your-package-name&lt;/code&gt; and get instant visuals:

&lt;ul&gt;
&lt;li&gt;Daily/weekly/monthly download trends
&lt;/li&gt;
&lt;li&gt;Breakdowns by Python version, implementation (CPython/PyPy/etc.), OS, country
&lt;/li&gt;
&lt;li&gt;Top versions over time
Data pulled fresh from PyPI's public BigQuery exports.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fry4q7f564dcnkzgl52g9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fry4q7f564dcnkzgl52g9.png" alt="Dashboard Example" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Trend Detection &amp;amp; Smart Alerts&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Spot anomalies automatically — sudden spikes from viral mentions or drops from deprecation.&lt;br&gt;&lt;br&gt;
Set up email alerts (Pro/Enterprise) so you're notified before a trend becomes a problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI-Powered Insights&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Powered by Claude, it generates human-readable summaries like:&lt;br&gt;&lt;br&gt;
"Your package saw a 150% week-over-week increase after that Hacker News post — version 2.1 is dominating adoption."&lt;br&gt;&lt;br&gt;
Helps you understand &lt;em&gt;why&lt;/em&gt; numbers are moving without manual analysis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Embeddable Badges for Your README&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Show off your stats with zero effort:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;   &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;![PyPI Downloads&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://pypistats.com/api/badges/your-package&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;](https://pypistats.com/packages/your-package)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Turns metrics into social proof for contributors and users. Downloads badge in this example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3yz2gga39n2kwxruzmf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3yz2gga39n2kwxruzmf.png" alt="Badge Example" width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Weekly Digests &amp;amp; Comparisons&lt;/strong&gt;
Get a curated email recap of your package's week.
Compare against similar packages to see if you're gaining/losing ground.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Tech Behind It (Quick Overview)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Backend: Python (FastAPI for the API, processing BigQuery data)&lt;/li&gt;
&lt;li&gt;Frontend: Modern React/Next.js for smooth dashboards&lt;/li&gt;
&lt;li&gt;Data: Sourced from PyPI's public BigQuery dataset (shoutout to the PSF!)&lt;/li&gt;
&lt;li&gt;AI: Claude for natural-language commentary&lt;/li&gt;
&lt;li&gt;Free tier covers core stats + badges; paid unlocks AI, alerts, digests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full disclosure: Yes, I'm the creator (Dale / @pypistats on X). I built this for myself and other maintainers first — it's not trying to be a massive enterprise thing, just a helpful tool in the Python ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why This Matters in 2026
&lt;/h3&gt;

&lt;p&gt;Python's ecosystem is massive (millions of packages, billions of downloads), but most maintainers fly blind on adoption. Better visibility means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prioritizing features users actually want&lt;/li&gt;
&lt;li&gt;Catching issues early (security, compatibility breaks)&lt;/li&gt;
&lt;li&gt;Attracting sponsors/contributors with real proof of impact&lt;/li&gt;
&lt;li&gt;Making data-driven decisions instead of gut feels&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Try It Out &amp;amp; Give Feedback!
&lt;/h3&gt;

&lt;p&gt;Head over to &lt;a href="https://pypistats.com" rel="noopener noreferrer"&gt;pypistats.com&lt;/a&gt;, plug in your favorite package (or yours!), and see what the trends reveal. This has very recently launched, so I'm still backfilling package data. If your package doesn't show up, a search will trigger a download, so be patient.&lt;/p&gt;

&lt;p&gt;What do you think?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this solve a real pain point for you?&lt;/li&gt;
&lt;li&gt;Missing metrics (e.g., more granular geo, dependency graphs)?&lt;/li&gt;
&lt;li&gt;Better ways to visualize or alert?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Drop a comment below — I'd love to hear your thoughts, suggestions, or even roast the UI if it's ugly 😅. If enough people find it useful, I'll keep iterating.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;Dale&lt;br&gt;&lt;br&gt;
Creator of pypistats.com&lt;br&gt;&lt;br&gt;
@pypistats on X&lt;/p&gt;

</description>
      <category>python</category>
      <category>pypi</category>
      <category>developers</category>
      <category>saas</category>
    </item>
    <item>
      <title>json-key-parser vs jsonpath-ng: Simplicity Wins for Messy JSON, Power for Complex Queries</title>
      <dc:creator>Dale Wright</dc:creator>
      <pubDate>Wed, 04 Mar 2026 18:16:40 +0000</pubDate>
      <link>https://dev.to/diverdale/json-key-parser-vs-jsonpath-ng-simplicity-wins-for-messy-json-power-for-complex-queries-44m5</link>
      <guid>https://dev.to/diverdale/json-key-parser-vs-jsonpath-ng-simplicity-wins-for-messy-json-power-for-complex-queries-44m5</guid>
      <description>&lt;p&gt;Some of you may know that &lt;strong&gt;json-key-parser&lt;/strong&gt; (v0.1.0, released Feb 18, 2026) is the tiny, zero-dependency hero that lets you yank specific keys out of deeply nested JSON with almost zero effort.&lt;/p&gt;

&lt;p&gt;But the Python ecosystem already has a heavyweight champion: &lt;strong&gt;jsonpath-ng&lt;/strong&gt; (v1.8.0, released Feb 24, 2026). It’s the full-featured JSONPath implementation that’s been battle-tested for years.&lt;/p&gt;

&lt;p&gt;So which one should you actually reach for? Let’s compare them head-to-head on the things that matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Philosophy &amp;amp; API
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;json-key-parser&lt;/th&gt;
&lt;th&gt;jsonpath-ng&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core idea&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;“Just give me these keys, wherever they are”&lt;/td&gt;
&lt;td&gt;“Write a precise path query like XPath for JSON”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Syntax&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple list of strings + &lt;code&gt;*&lt;/code&gt; wildcard&lt;/td&gt;
&lt;td&gt;Full JSONPath expressions (&lt;code&gt;$..key&lt;/code&gt;, &lt;code&gt;[*]&lt;/code&gt;, &lt;code&gt;?(@.price&amp;gt;10)&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Learning curve&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;30 seconds&lt;/td&gt;
&lt;td&gt;15–30 minutes + docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typical line count&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1–2 lines&lt;/td&gt;
&lt;td&gt;3–10+ lines (parse + find + process)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;json-key-parser example&lt;/strong&gt; (the one-liner magic):&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;json_parser&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JsonParser&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;JsonParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;first_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;street&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;address*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;get_data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. It recursively hunts every level, handles lists, merges duplicate keys into lists automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jsonpath-ng equivalent&lt;/strong&gt; (you need multiple expressions or clever wildcards):&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;jsonpath_ng&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt;

&lt;span class="n"&gt;first_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$..first_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;streets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$..street&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;addresses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$..address*&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Note: * works but not exactly the same
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You then have to extract &lt;code&gt;.value&lt;/code&gt; from Match objects and handle merging yourself.&lt;/p&gt;

&lt;p&gt;Winner for quick-and-dirty extraction: &lt;strong&gt;json-key-parser&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Power &amp;amp; Features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;json-key-parser shines when&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON structure is unpredictable or changes often (third-party APIs, logs, scraped data)&lt;/li&gt;
&lt;li&gt;You just want a flat dict/list of the fields you care about&lt;/li&gt;
&lt;li&gt;Duplicate keys appear at different nesting levels (it merges them intelligently)&lt;/li&gt;
&lt;li&gt;You hate writing defensive &lt;code&gt;data.get("a", {}).get("b", [])&lt;/code&gt; chains&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;jsonpath-ng dominates when&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need filters: &lt;code&gt;$.books[?(@.price &amp;gt; 20)]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You want to &lt;strong&gt;update&lt;/strong&gt; or &lt;strong&gt;delete&lt;/strong&gt; values in place: &lt;code&gt;expr.update(data, new_value)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You need arithmetic, regex, slicing, or parent references&lt;/li&gt;
&lt;li&gt;You’re doing metaprogramming (it exposes a clean AST)&lt;/li&gt;
&lt;li&gt;You want full paths back: &lt;code&gt;match.full_path&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;jsonpath-ng also supports extensions for &lt;code&gt;len()&lt;/code&gt;, &lt;code&gt;keys()&lt;/code&gt;, sorting, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Dependencies &amp;amp; Size
&lt;/h3&gt;

&lt;p&gt;Both are &lt;strong&gt;zero external dependencies&lt;/strong&gt; now.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;json-key-parser: pure stdlib, &amp;lt; 50 KB installed
&lt;/li&gt;
&lt;li&gt;jsonpath-ng: robust parser (no longer pulls in ply at runtime in recent versions), still tiny
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both install with one &lt;code&gt;pip&lt;/code&gt; command and support Python 3.8+.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Performance &amp;amp; Maturity
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;jsonpath-ng is mature, heavily tested, and used in production everywhere.
&lt;/li&gt;
&lt;li&gt;json-key-parser is brand new (Beta status) but laser-focused, so its recursion is extremely fast for the 95% use case.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For massive JSON documents with thousands of nested objects, jsonpath-ng’s compiled expressions can edge it out on complex queries. For simple key extraction? json-key-parser is often faster because it doesn’t parse a query language at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to Choose Which
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use json-key-parser if&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’re writing ETL scripts, API clients, or data-cleaning notebooks&lt;/li&gt;
&lt;li&gt;Your JSON is messy and you just want “first_name, email, total” regardless of nesting&lt;/li&gt;
&lt;li&gt;You value readability and minimal code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use jsonpath-ng if&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need conditional filtering or data transformation&lt;/li&gt;
&lt;li&gt;You’re building a library or tool that requires precise, repeatable queries&lt;/li&gt;
&lt;li&gt;You want to modify the JSON structure in place&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pro tip&lt;/strong&gt;: You can even use both in the same project! Parse once with jsonpath-ng for complex stuff, then hand the result off to json-key-parser for final flattening.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bottom Line
&lt;/h3&gt;

&lt;p&gt;If jsonpath-ng is the Swiss Army knife of JSON querying, &lt;strong&gt;json-key-parser&lt;/strong&gt; is the precision scalpel for the single most common pain point: “I just need these damn keys.”&lt;/p&gt;

&lt;p&gt;For 80% of real-world Python scripts dealing with APIs and configs, json-key-parser will save you more time and frustration than any other library released this year.&lt;/p&gt;

&lt;p&gt;Try it right now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;json-key-parser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then compare it yourself with the exact same data in both libraries. I bet you’ll delete a bunch of boilerplate within five minutes.&lt;/p&gt;

&lt;p&gt;What’s your biggest JSON-parsing headache right now? Drop it in the comments — I’ll show you which tool slays it faster.&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>pypi</category>
      <category>json</category>
    </item>
  </channel>
</rss>
