DEV Community

Ahmed Abdeltawab
Ahmed Abdeltawab

Posted on

An adversarial review found 11 real defects in my Python library. Best decision I made.

I built and published a Python library — then put it in front of an adversarial review whose only job was to break it. This is what it found, and what the library looks like now.

What pydextra is

pip install pydextra, then import dextra as dx. It's a small data-analysis library with one obsession: disclosure. Its 63 public functions — plus 5 scikit-learn-compatible wrappers, 68 public callables in all — share one flag vocabulary and:

  • print a one-line Decision: explaining what they did and why,
  • keep an audit trail on the DataFrame,
  • and, wherever statistics are learned from data, return a replayable params plan — fit on train, replay verbatim on test — so train/test leakage becomes hard to commit by accident.

One real call, verbatim from the leakage-safe pipeline notebook:

train_fe, params = dx.featpipe(train, steps=steps, return_params=True)
Enter fullscreen mode Exit fullscreen mode
Decision: Fitted a 3-step featpipe pipeline (handle_missing -> encode -> scale);
33 new column(s) produced; combined params is a versioned, JSON-serialisable
artifact. Apply to held-out data with featpipe(df_test, params=...).
Enter fullscreen mode Exit fullscreen mode

The part I'm most proud of isn't a feature

An adversarial external evaluation found 11 evidence-backed defects in the library. Version 0.6.0 closed all 11 — each one reproduced first by a failing "red" test, then fixed until green, with ~35 permanent regression tests and zero-warning exit gates. The original independent audit had scored an earlier version 82/100; the updated referee evaluation of 0.6.0 passed every agreed gate — 10/10 on a measurable definition fixed before the work started — with the remaining limitations listed openly in the repo.

Since 0.6.0 the API is frozen by policy: no new features, hotfixes only. What you evaluate today is what you run next year.

Three notebooks, real mess

All three are published fully executed on Kaggle:

  1. Rescuing 9,291 invoice numbers from silent coercion — how numeric coercion silently eats identifiers, and how a disclosure-first loader catches it.
  2. Two pipelines, same AUC (0.8465) — one is lying — the wrong protocol and the right one produce identical single-run AUC (0.8465); only 10 repetitions expose the real optimistic bias (+0.0261 ± 0.0210, wrong side higher in 9 of 10 runs). The full write-up: Same AUC, hidden leak, or run it in 5 minutes on Colab.
  3. Egypt food prices 2010–2026: a fully-Arabic EDA — garlic +214.8% in one jump. Deliberately written in Arabic: technical Arabic data-science content is rare, and this is a small contribution against that gap.

Honest scope

It's a personal educational-practical project — not a pandas replacement, and not aimed at production-scale pipelines. pandas is the engine underneath; pydextra adds the disclosure layer.

If the idea of functions that explain themselves appeals to you, a GitHub star helps others find it.

Top comments (5)

Collapse
 
alexshev profile image
Alex Shev

Adversarial review is valuable for data products too. For a Maps/ranking pipeline I would test with moved businesses, duplicate listings, missing coordinates, service-area businesses, and sudden review spikes. Happy-path city/name examples hide most of the bugs.

Collapse
 
ahmedabdeltawab profile image
Ahmed Abdeltawab

Thanks Alex — "happy-path examples hide most of the bugs" is exactly the lesson. The clearest case in the article: on a single train/test split the leaky pipeline and the clean one score an identical AUC (0.8465 vs 0.8465). Only repeating the experiment 10 times exposes the real bias (+0.0261 ± 0.0210, leaky ahead in 9 of 10). One happy run says nothing.

Your Maps list is a good taxonomy, and it splits in two. Duplicate listings, missing coordinates and sudden spikes are generic — dedupe, missing-value and outlier checks can flag them, and that's the part a library can help with. But a moved business or a service-area business is domain semantics: no generic tool knows the shop relocated. That needs your adversarial test set, not a package.

Which of those five broke ranking most often in practice?

Collapse
 
alexshev profile image
Alex Shev

The repeated split example is a clean teaching case. One run can make the leaky and clean pipelines look equivalent; repeated runs expose the bias. For Maps data I would use the same pattern: one location snapshot is anecdote, repeated slices across cities and time are where the bad assumptions show up.

Thread Thread
 
ahmedabdeltawab profile image
Ahmed Abdeltawab

Exactly — and there's an extra trap when you move that pattern to geo/time data: how you repeat matters as much as that you repeat. If the repeated slices are random, rows from the same city or the same week land on both sides, and the repetition just re-averages the same leak with tighter error bars — false confidence instead of a warning. Repeating by group (hold out whole cities) or forward in time (train on earlier slices, test on later ones) is what actually surfaces the bad assumption.

My demo gets to use plain repeated CV only because that dataset has no group or time structure. Yours has both, which makes it the harder case — and the one where a single snapshot is most convincing and most wrong.

Thread Thread
 
alexshev profile image
Alex Shev

Yes, that group boundary is the part people miss. Random repeats can make a leak look statistically stable. Holding out whole cities or future windows is the difference between repeated comfort and a real assumption test.