Repository navigation
Pointblank v1.2.0 focuses on correctness, consistency, and safety. Every table-level validation step now has a step report, and many step report layouts have been cleaned up. NaN is now treated as a missing value in every validation method on every backend. AI-powered prompt() steps are much more reliable as they no longer report every row as failing when the model's replies can't be used. Pandas 3 is now supported, and to_code()/to_yaml() now round-trip every validation method.
Breaking Changes
- Python code in YAML configs is opt-in —
python:blocks and theexpr/pre/activeshortcuts in YAML configs now run only withallow_python=True(inyaml_interrogate(),YAMLValidator.build_validation(), andexecute_workflow()) orpb run --allow-python. Declarative calls such aspb.load_dataset(),pb.col(),pb.ref(),pb.seg_group(), and the column selectors are checked without running any code, so they always work.yaml_to_python()no longer runs any code. (#527) data_freshness()now fails when the newest timestamp is later than the reference time. A newallow_future=parameter acceptsTrue(the old behavior) or a duration such as"5m"to allow for clock skew. (#518)Pipeline.run()now raises a newContractViolationErrorfor contracts withon_violation="raise". Itsresultattribute holds thePipelineResult. Before, the error was caught and the run kept going. (#517)
New Features
- Step reports for table-level steps —
get_step_report()now returns a summary report forcol_exists(),row_count_match(),col_count_match(),col_pct_null(),col_pct_missing(),data_freshness(), andspecially(). Before, it returnedNonefor these steps. Each report shows the value measured during interrogation (counts, null and missing percentages, data age, the closest matching column name, and so on) next to the expected value, with a pass/fail mark. (#488) - Pandas 3 support — The
pandas<3pin has been removed. A new CI job runs the test suite with every direct dependency at its minimum declared version.specially()also no longer renames columns in place on Pandas results. (#496)
Enhancements
col_vals_expr()steps are now easier to tell apart in the validation report. TheCOLUMNScell lists the columns the expression uses,STEPshows the expression's name if you set one, and on Python 3.11+ the footer shows the expression as you wrote it. (#492)col_vals_increasing()andcol_vals_decreasing()now support date, datetime, and Decimal columns on every backend and skipMissingSpeccodes the same way they skip nulls. (#532)- The
col_sum_*(),col_avg_*(), andcol_sd_*()methods now work on Decimal columns on every backend and accept aDecimalvalue=. (#529) - Comparison steps now accept
Decimalanddatetime.timevalues. Validation methods also accept ISO datetime strings with a UTC offset (e.g.,"2023-10-01T13:45:30+05:00"). Thanks @DG47! (#511, #528) col_vals_regex(),col_vals_str_len(), andcol_vals_within_spec()now check Polars Categorical and Enum columns. Thanks @pcbeingused333! (#481, #482, #483)col_summary_tbl()andDataScannow choose each column's profile from its dtype class. Decimal columns are summarized as numbers, Enum columns as strings, and Time columns get a min and max. Columns that can't be summarized are listed instead of throwing an error. (#501)emit_otel()gains ameter_version=parameter.OTelExporternow checks its arguments when it's created. (#514)generate_dataset()now gives numeric columns their field's dtype (e.g.,int_field(dtype="Int32")gives anInt32column), andtime_field()columns now hold realtimevalues. (#515)pb runandpb validatenow show steps that are inactive or couldn't be evaluated, along with the reason.pb runaddsNot evaluated:andInactive:counts and anincompletestatus, and--fail-on anynow also fails when a step couldn't be evaluated. (#525)
Bug Fixes
Missing values and NaN
NaNis now treated as a missing value on Polars, PyArrow, and DuckDB, as it already was on pandas. This covers comparison steps on DuckDB tables,col_vals_between(),col_vals_outside(),col_vals_not_in_set(),col_vals_increasing(),col_vals_decreasing(), andMissingSpecchecks. Range bounds given asNaNare now handled too. Thanks @DG47 and @pcbeingused333! (#474, #484, #485, #486, #487, #500, #531)- A missing value that fails
col_vals_in_set()now appears among the failing rows in sundered data and data extracts. Thanks @pcbeingused333! (#480) - When segments are derived from a Pandas column, missing values now form a
Nonesegment instead of causing an evaluation error or being skipped. Thank you @DG47! (#508) - Aggregates that can't be computed (e.g., the standard deviation of one value) are now reported as evaluation errors instead of raising errors or failing silently. (#529)
AI validation (prompt())
- When no model reply can be used (because of a refusal, truncated JSON, an empty result, or a cut-off reply), the step is now marked as not evaluated instead of reporting every row as failing. The step note quotes the unusable reply. Thanks @pcbeingused333! (#475, #503)
- Results in a reply are only accepted for that batch's own rows. (#503)
- Each batch now starts a new conversation, so requests no longer grow with every batch and earlier verdicts can't influence later ones. Thanks @pcbeingused333! (#479)
- The JSON array is now found when the reply has square brackets before it. Thanks @pcbeingused333! (#471)
- Row verdicts are now matched to pandas rows by position, so frames with a non-default index get the right results. Thanks @pcbeingused333! (#477)
- The batch schema is now inferred from every unique row, so sparse text columns no longer cause an error. Thanks @pcbeingused333! (#478)
- The reply-token limit for Anthropic and Bedrock models has been raised to 16,000.
DraftValidationandEditValidationnow raise a clear error when a reply is cut off. (#493) - The
draft_validation_planMCP tool now usesanthropic:claude-sonnet-5-5by default, replacing a model that's being retired. Thanks @pcbeingused333! (#470)
Step reports
col_schema_match()step reports now agree with the validation result for every combination ofcomplete=andin_order=, and they're easier to read! (#491)- Step report headers, assertion boxes, pass/fail marks, and widths are now consistent across report types. (#489)
- Awkward and ungrammatical text in step reports has been fixed.
conjointly()andspecially()reports now name their expressions instead of showing<lambda>. (#490) get_dataframe_report()no longer fails on segmented steps, and checksum specs incol_vals_within_spec()no longer stopinterrogate()on Polars LazyFrames. (#495)
Column summaries (col_summary_tbl() and DataScan)
col_summary_tbl()now explains why it fails when no column can be profiled, instead of raising a bareAssertionError. Thanks @cristianchiriac! (#469)- List and array columns are now skipped instead of resulting in an error. Thanks @DG47! (#499)
- Empty cells now show
-on every backend, HTML is no longer shown as text, and string-length statistics now ignore missing values. (#495, #502, #506)
Serialization (to_code(), to_yaml(), yaml_to_python())
to_code()andto_yaml()now write out every validation method, and the output gives the same results as the original plan. (#494)Validate(reference=...)is now written out when the reference is a file path or connection string, so plans that usepb.ref()can be rebuilt. (#504)- Decimal, time, and timezone-aware datetime values are now written out with the imports they need. (#528)
- The original
active=value is now kept when a plan is serialized after interrogation. (#521) yaml_to_python()now writes working code for file paths and connection strings. (#505)
Validation workflow
- Calling
interrogate()again now starts over from the steps as they were defined, andbrieftemplates are kept. (#524) get_sundered_data()now returns the right rows for segmented steps and leaves out steps that usepre=. (#495, #497)- Segmented steps are now kept when no segments are found, instead of being dropped from the validation. (#516)
add_steps()now works when copying steps from aValidateobject for methods that don't takevalue=. (#523)emit_otel()now sends traces and log records, the same asOTelExporter.export(). (#514)
Data generation
- With
seed=, each generated column now gets its own random sequence, so columns are no longer identical or correlated. Seeded multi-country data is now the same in every session. (#526) - Prefixed
profile_fields()profiles now each get their own person, location, and employer. (#519) - The postcode in a generated
addressnow matches the row'spostcodecolumn. (#522) get_data_path()no longer leaves temporary files behind. (#520)
Documentation
- The User Guide sections are now ordered to follow how people might use Pointblank: the core validation workflow first, then data tools, production use, and other interfaces. (#509)
- Retired OpenAI and Claude models have been replaced in the AI examples. Thanks @pcbeingused333! (#472, #493)
- Several small documentation fixes, including clearer report terminology and customization guidance. (#512)
Maintenance
- The
duckdbextra now requiresibis-framework>=11.0.0andnarwhals>=2.8.0, which fixes queries on ibis 10.x with DuckDB 1.4+. DuckDB is temporarily capped at<2until ibis and Narwhals support it. (#476) - The minimum versions are now
narwhals>=2.8.0andgreat-tables>=1.1.0, and thegenerateextra now requireschatlas>=0.10.0. (#496, #513)