<?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: Saurav Gopinath ek</title>
    <description>The latest articles on DEV Community by Saurav Gopinath ek (@saurav_gopinathek_6a0cd7).</description>
    <link>https://dev.to/saurav_gopinathek_6a0cd7</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%2F4114813%2F055d319a-3295-4123-84f9-ea41a0665817.png</url>
      <title>DEV Community: Saurav Gopinath ek</title>
      <link>https://dev.to/saurav_gopinathek_6a0cd7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saurav_gopinathek_6a0cd7"/>
    <language>en</language>
    <item>
      <title>DataLens: The Data Tool That Refused to pip install Anything</title>
      <dc:creator>Saurav Gopinath ek</dc:creator>
      <pubDate>Tue, 08 Sep 2026 03:22:48 +0000</pubDate>
      <link>https://dev.to/saurav_gopinathek_6a0cd7/datalens-a-zero-dependency-tool-for-datasets-4ckj</link>
      <guid>https://dev.to/saurav_gopinathek_6a0cd7/datalens-a-zero-dependency-tool-for-datasets-4ckj</guid>
      <description>&lt;p&gt;&lt;strong&gt;What DataLens actually does&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before the stdlib war stories, here's the tool itself. DataLens is a data quality engine — you point it at a messy CSV/JSONL file and it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Streams the file&lt;/strong&gt; instead of loading it all into memory, so it handles files bigger than your RAM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infers types&lt;/strong&gt; per column — detects 15 types including EMAIL, UUID, IP_ADDRESS, DATE, not just "string vs number"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flags problems&lt;/strong&gt;: missing values, type mismatches, outliers (IQR + Z-score), duplicates, format violations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runs anomaly detection&lt;/strong&gt; through the autoencoder we hand-built (explained below) to catch multi-column issues a simple rule can't&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-cleans&lt;/strong&gt; the data with a confidence score attached to each fix, so nothing gets silently changed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lets you run SQL directly&lt;/strong&gt; on the dataset via an in-memory &lt;code&gt;sqlite3&lt;/code&gt; engine — no separate database setup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compiles to one file&lt;/strong&gt; — &lt;code&gt;datalens_single.py&lt;/code&gt; — that runs anywhere Python 3.14 runs, no &lt;code&gt;pip install&lt;/code&gt; needed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;python datalens.py analyze data.csv
python datalens.py clean data.csv --apply
&lt;/span&gt;&lt;span class="gp"&gt;python datalens.py query data.csv "SELECT * FROM data WHERE age &amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;30&lt;span class="s2"&gt;"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the "what." Now the "how it almost broke us": the anomaly detector needed a neural net, and our rulebook said no third-party packages. No NumPy. No pandas. No scikit-learn. Just Python 3.14's standard library.&lt;/p&gt;

&lt;p&gt;Our first reaction was denial. You cannot build an ANN without a matrix library — everyone knows that. &lt;code&gt;numpy.dot()&lt;/code&gt; is basically load-bearing infrastructure for machine learning in Python. We spent an embarrassing amount of time trying to convince ourselves some obscure &lt;code&gt;math&lt;/code&gt; submodule secretly did vectorized linear algebra. It doesn't. There is no shortcut. If you want matrix multiplication in pure stdlib Python, you write nested &lt;code&gt;for&lt;/code&gt; loops and you like it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we normally would have installed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In any other project, this is a two-second decision: &lt;code&gt;pip install numpy&lt;/code&gt;, import it, move on with your life. Matrix ops, broadcasting, vectorized activation functions — all free. Neither of us had ever really had to think about how &lt;code&gt;A @ B&lt;/code&gt; works under the hood, because neither of us had ever had to write it ourselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it actually took to replace it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quick context if you're not deep in ML: an autoencoder is a neural net that learns to compress data down and rebuild it back — if it can't rebuild something well, that "something" is probably an anomaly. Backprop is just how the network learns from its mistakes, by working backward from the error and adjusting itself.&lt;/p&gt;

&lt;p&gt;An autoencoder needs: matrix multiplication, transpose, element-wise activation functions (sigmoid, ReLU), and gradient computation for backprop. Without NumPy, every one of those is a hand-rolled function operating on nested Python lists. Matrix multiply becomes three nested loops instead of one line. A forward pass that would be a single &lt;code&gt;.dot()&lt;/code&gt; call turns into a small file of helper functions: &lt;code&gt;matmul()&lt;/code&gt;, &lt;code&gt;transpose()&lt;/code&gt;, &lt;code&gt;add_bias()&lt;/code&gt;, &lt;code&gt;sigmoid()&lt;/code&gt;, &lt;code&gt;sigmoid_derivative()&lt;/code&gt;. We split it — one of us built the forward pass and activation functions, the other took backprop and the training loop — and then spent a good while debugging the seam where the two met.&lt;/p&gt;

&lt;p&gt;The genuinely hard part wasn't the math — it was performance. Pure Python loops over lists of lists are slow, and profiling a dataset with a few thousand rows through even a small autoencoder made that obvious fast. We ended up leaning hard on Python's &lt;code&gt;array&lt;/code&gt; module instead of plain lists for the weight matrices. In plain terms: a normal Python list stores each number as a separate object scattered in memory, while &lt;code&gt;array&lt;/code&gt; packs numbers back-to-back like a real numeric array in C — less overhead, faster access. It's the closest thing the standard library has to a "no dependency" NumPy array, and neither of us knew it existed until this project forced us to find it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The stdlib corner nobody told us about&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The other surprise was &lt;code&gt;sqlite3&lt;/code&gt;. We'd always thought of it as "the toy database module," something you use for a quick local cache, not real analytics. Turns out it's a fully capable SQL engine sitting in the standard library, in-memory mode and all — &lt;code&gt;sqlite3.connect(":memory:")&lt;/code&gt; gives you a real query engine with joins, aggregates, and indexes, with zero setup. We ended up building DataLens's entire SQL analytics layer on top of it instead of hand-rolling a query parser, which honestly felt like cheating in the best way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The thing that turned out harder than the docs made it look&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The docs for &lt;code&gt;array&lt;/code&gt; make it sound like a drop-in replacement for lists with a type constraint. What they don't emphasize is that &lt;code&gt;array&lt;/code&gt; only holds primitive numeric types — no nested structures — so representing a 2D matrix means either flattening to 1D and doing manual index math (&lt;code&gt;row * width + col&lt;/code&gt;) everywhere, or nesting arrays inside a list and losing some of the contiguous-memory benefit you wanted in the first place. We went with flattening, and every single matrix operation had to be rewritten around that indexing scheme. It works, and it's fast, but it made debugging genuinely painful — a transpose bug three layers into backprop just looks like "the model isn't learning," not "your index math is wrong," and it took the two of us comparing notes line by line to actually find it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why bother&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The constraint felt arbitrary at first — obviously NumPy would make all of this trivial and safe. But writing the matrix ops by hand meant we actually understood, for the first time, what a forward pass and backward pass are doing numerically, instead of trusting a black box. And the deployment story is real: DataLens compiles down to one portable &lt;code&gt;.py&lt;/code&gt; file that runs on any machine with Python 3.14, no &lt;code&gt;pip install&lt;/code&gt;, no dependency resolution, no supply-chain risk. For a data quality tool meant to run in locked-down or air-gapped environments, that's not a nice-to-have — it's the whole point.&lt;/p&gt;

&lt;p&gt;Turns out "zero dependency" isn't a limitation you work around. It's a forcing function that makes you actually learn the thing you'd normally outsource — and a decent excuse to argue with your teammate about whose indexing bug it was.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/Akshith1413/DataLens" rel="noopener noreferrer"&gt;github.com/Akshith1413/DataLens&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've ever hand-rolled something you normally &lt;code&gt;pip install&lt;/code&gt;, drop it in the comments — curious what stdlib corners other people have found.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>data</category>
      <category>datascience</category>
    </item>
  </channel>
</rss>
