Changelog
Unreleased
v0.3.1 — 2026-06-03
Added
-
MetricCompute.scan()— pre-flight compatibility scan that introspects source table schemas and returns aScanResultwith oneCompatibilityResultper metric × slice and per metric × segment pair. Schema introspection is batched by unique source URI. -
CompatibilityResult— frozen dataclass carrying the compatibility verdict for a single metric × spec pair:compatible,valid_join_keys,missing_columns, andreason. -
ScanResult— container for the full compatibility matrix with query helpers:compatible_slices(),compatible_segments(),compatible_metrics(),for_metric(), andfor_spec().
v0.3.0 — 2026-06-03
Added
-
SegmentSpec.entity_id— required field identifying the primary key column on the DIM table. Used as the right-hand side of the generated JOIN ON condition (_dim.<entity_id>). -
SegmentSpec.join_keys— optional whitelist of fact-table FK columns that may be used as join keys for this segment. When non-empty, the join key supplied atcompute()time must appear in this list; otherwise aQueryBuildErroris raised. -
segmentsdict form inMetricCompute.compute()—segmentsnow acceptsdict[str, str] | str | None. The dict form maps exactly one segment name to an explicit fact-table FK column, enabling the same segment spec to be joined via different columns (e.g.,buyer_idvsseller_idon a transactions table). -
DIM-table JOIN in generated SQL — when a segment has
entity_idset, aitaem generates a proper JOIN from the fact table to the DIM table rather than applying segment predicates inline against the fact table. Unqualified column references invalues[].whereexpressions are automatically qualified with_dim.via sqlglot AST rewriting. -
referenced_columnsfor segment specs —ValidationResult.referenced_columnsnow includes"entity_id","join_keys"(when non-empty), and"values[i].where"keys for segment specs.
Changed (Breaking)
-
SegmentSpec.entity_idis now required. Existing segment specs without this field will fail validation with aSpecValidationError. Addentity_id: <dim_pk_column>to every segment spec YAML file. -
SegmentSpec.sourceis now used. Previously parsed but ignored,sourceis now the URI of the DIM table that will be joined at query time. Ensure it points to the correct DIM table, not the fact table. -
segmentsincompute()no longer acceptslist[str]. The parameter type changed fromstr | list[str] | Nonetodict[str, str] | str | None. Multi-segment calls are no longer supported in a singlecompute()call; callcompute()once per segment instead.
v0.2.2 — 2026-06-01
Added
ValidationResult.referenced_columns— populated on successful spec validation; adict[str, list[str]]mapping each spec field to the unqualified column names it references.Nonewhen the spec is invalid. Intended for downstream consumers who hold a warehouse connection and want to verify that every referenced column is present in the source table before computing metrics. See Column introspection for usage.
v0.2.1 — 2026-05-28
Added
-
MetricSpec.format— optional metadata field for metric value interpretation. Allowed values:percentage,absolute,ratio,currency, andcurrency:<CODE>where<CODE>is a 3-letter uppercase ISO 4217 currency code (e.g.currency:USD). Plain"currency"is valid for monetary metrics with mixed or unspecified currency. Validated at spec load time; invalid values raiseSpecValidationError. -
metric_formatoutput column — everycompute()result now includes ametric_formatcolumn (inserted aftermetric_name) carrying the spec'sformatvalue, orNonewhenformatis not set. The output schema now has 11 columns. -
hourlyperiod type —period_type="hourly"produces one output row per clock hour.time_windownow accepts full ISO datetime strings (e.g."2024-01-15T08:00:00") when using hourly granularity; plain date strings fall back to midnight. Sub-hour precision in the start value is silently truncated to the nearest full hour. -
METRIC_FORMAT_VALUES— new constant exported fromaitaem, afrozensetof the simple format values:{"percentage", "absolute", "ratio", "currency"}.
Changed (Breaking)
STANDARD_COLUMNSnow has 11 entries. Themetric_formatcolumn is inserted at index 5 (aftermetric_name). Code that relies on column position or count (e.g.df.iloc[:, 9]) must be updated.
v0.2.0 — 2026-05-27
Changed (Breaking)
MetricSpec,SliceSpec,SegmentSpec: thenamefield is now validated as a SQL identifier at load time. Names must match^[A-Za-z_][A-Za-z0-9_]*$— letters, digits, and underscores only, starting with a letter or underscore. Specs whose names contain spaces, hyphens, dots, or other characters will raiseSpecValidationErrorat load time rather than failing silently or raisingQueryExecutionErrorat compute time.
Migration: rename any affected specs.
For example: "English speaking countries" → "english_speaking_countries",
"revenue-2024" → "revenue_2024". The validation error message includes a
suggested replacement name.
SpecCache.from_yaml(),SpecCache.from_string(),SpecCache.add(): now raiseSpecValidationErrorwhen a spec with a duplicate name is loaded. Previouslyfrom_yaml()logged a warning and overwrote the earlier spec;from_string()andadd()silently kept the first. Uniqueness is enforced per spec type (metrics, slices, and segments have independent namespaces).
Migration: ensure all spec files have unique names per type. If you were relying on
the overwrite behaviour to update a spec at runtime, use cache.clear() followed by a
fresh load instead.
ConnectionErrorrenamed toAitaemConnectionErrorthroughout the library to avoid shadowing Python's built-inConnectionError.
Migration: replace any except ConnectionError or from aitaem... import ConnectionError
with AitaemConnectionError, which is now importable directly from aitaem.
Added
STANDARD_COLUMNS: list[str]is now importable directly fromaitaem. Contains the ordered list of column names thatMetricCompute.compute()always returns:period_type,period_start_date,period_end_date,entity_id,metric_name,slice_type,slice_value,segment_name,segment_value,metric_value.- Spec types (
MetricSpec,SliceSpec,SliceValue,SegmentSpec,SegmentValue) are now importable directly fromaitaem(previously only fromaitaem.specs). IbisConnectoris now importable directly fromaitaem(previously only fromaitaem.connectorsoraitaem.connectors.ibis_connector).- All exception classes are now importable directly from
aitaem(previously required internal import paths such asaitaem.utils.exceptions). PeriodType— aLiteraltype alias for validperiod_typevalues; importable fromaitaem. Use in Pydantic models or type annotations.VALID_PERIOD_TYPES— afrozenset[str]of validperiod_typevalues; importable fromaitaem. Derived fromPeriodTypeso both are always in sync.MetricCompute.compute():period_typeparameter is now annotated asPeriodType(previously barestr), enabling IDE completions and static analysis warnings.SpecCache.metrics,SpecCache.slices,SpecCache.segments— read-onlyMappingproperties for iterating over all loaded specs without individualget_*lookups.
v0.1.5 — 2026-04-22
Added
SliceSpec: new wildcard variant — setwhere: <column_name>at the spec level (instead of listingvalues) to auto-populate slice values from the column's distinct values at query time. Supports simple and dot-qualified column names.
Fixed
MetricSpec.from_yaml(),SliceSpec.from_yaml(),SegmentSpec.from_yaml(): no longer raise an unhandledOSErrorwhen a YAML string longer than the OSPATH_MAXvalue is passed. The path-existence check now wrapspath.is_file()intry/except OSErrorand falls back to treating the input as YAML content.
v0.1.4 — 2026-03-23
Changed
MetricSpec: removedaggregationfield. Aggregation type is now inferred from the SQL function embedded innumerator(anddenominator). Ratio is implied whendenominatoris present. Validation enforces that bothnumeratoranddenominator(when present) contain a recognised aggregate function call (SUM,AVG,COUNT,MIN,MAX).
Migration guide
- Remove
aggregation:from all metric YAML specs. - Ensure
numerator(anddenominatorwhen present) contain an explicit aggregate function call such asSUM(col),AVG(col),COUNT(*),MIN(col), orMAX(col).
Added
MetricSpec: new optionalentitiesfield — declares which entity columns the metric supports for disaggregation (e.g.entities: [user_id, device_id]). Must be a non-empty list if provided.MetricCompute.compute(): newby_entityparameter — groups results by an entity column declared in each metric'sentitieslist; raisesQueryBuildErrorif any metric does not support the requested entity column.- Standard output schema gains an
entity_idcolumn (position 4, betweenperiod_end_dateandmetric_name);Nonewhenby_entityis not set. - Added PostgreSQL backend support via
ibis-framework[postgres](pip install "aitaem[postgres]") - New
aitaem.connectors.backend_specsmodule withDuckDBConfig,BigQueryConfig, andPostgresConfigdataclasses — centralizes backend field validation for all connectors - PostgreSQL source URI format:
postgres://schema/table(e.g.postgres://public/orders)
v0.1.3 — 2026-03-17
- New
aitaem.helpersmodule for user-facing convenience functions - New
load_csvs_to_duckdb(csv_path, db_path, overwrite=True)helper — loads a single CSV or all top-level CSVs in a folder into a DuckDB file and returns a connectedIbisConnector MetricSpec: unknown-fields check now usesdataclasses.fields()instead of a hard-coded set- README: updated CSV loading example to use
load_csvs_to_duckdb
v0.1.2 — 2026-03-14
- Updated installation instructions to use PyPI
- Added CI, PyPI version, and Python version badges to README
v0.1.1
- Bug fixes and internal improvements
v0.1.0 — Initial release
MetricSpec,SliceSpec,SegmentSpecwith YAML parsing and validationSpecCachewith eager loading from files, directories, or stringsConnectionManagerwith DuckDB and BigQuery supportMetricCompute— primary user interface for computing metrics- Cross-product (composite) slice support
- Standard 9-column output DataFrame
- Example ad campaigns dataset with sample YAML specs
For full release diffs, see GitHub Releases.