Skip to main content

cur-athena-lint

PyPI

Check AWS Cost and Usage Report Athena SQL for the mistakes that inflate your query bill and silently produce wrong numbers — without an AWS account.

pip install cur-athena-lint     # from PyPI, Python 3.9+
cur-athena-lint                 # run the 16 checks over the SQL that ships with it

Or from a clone — the same code either way:

git clone https://github.com/duke5am/cur-athena-lint
cd cur-athena-lint
python3 verify_pack.py          # the 16 structural checks
python3 parse_all_sql.py        # the grammar sweep on its own

The seventeen SQL files ship inside the package, so the installed checker verifies them with no checkout and no extra download.

$ cur-athena-lint
sqlglot      : 26.16.4   dialect: athena
Verified cols: 80 names on the allow-list

[PASS] P02 every .sql file parses as Athena dialect          17/17 parsed; no errors
[PASS] P03 no query uses SELECT *                     10 COUNT(*) aggregates, all fine
[PASS] P04 every statement reading the CUR table filters on year AND month
[PASS] P04b no CTE or subquery reads the CUR table without a partition filter either
[PASS] P06 every column reference is on the verified column allow-list
[PASS] P07 every column the queries use is also declared in setup/create_table.sql
RESULT: 15/15 structural checks passed, 0 failed

Exit codes: 0 every check passed · 1 at least one check failed · 2 nothing was checked (CUR_CONTENT does not exist) · 3 internal failure.

To point the checker at a different tree, set CUR_CONTENT. Note that the two pack-integrity checks (P12 manifest, P15 README counts) then fail unless that tree also ships a REQUIRED_FILES.txt and the pack README.

Why CUR SQL goes wrong

The CUR table is a 100+ column monster where cost is split across many columns and the obvious one is usually the wrong one. Three failures are common:

You scan a year of data to answer a question about one month. The table is partitioned by year/month, and a missing predicate means Athena reads everything. This checker requires both predicates on every CUR-reading statement — including inside CTEs, because a subquery that scans unpruned is just as expensive.

You use the wrong cost column. line_item_unblended_cost is not the number you want for most questions, and for EC2/RDS line items with a reservation applied it is 0 — the cost lives in reservation_effective_cost. Summing the wrong column gives you a confident, wrong total.

You double-count a discount. Savings Plan covered usage is recorded at on-demand list price and offset by a separate SavingsPlanNegation line. Count one without the other and your January total is inflated — by exactly the negation amount, which can be substantial.

What the checker enforces

  • every .sql file parsed with sqlglot's athena dialect — a real grammar, not a regex
  • no SELECT * (with COUNT(*) correctly allowed — it reads no columns)
  • year AND month on every CUR-reading statement, including CTEs and subqueries
  • no function wrapping a partition column in WHERE (that defeats pruning)
  • every column reference against an 80-name verified allow-list
  • internal consistency between the queries and the shipped CREATE EXTERNAL TABLE
  • a header comment with a bytes-scanned warning on every query

What it does NOT check

Stated by the tool itself, not buried: no query here was executed against Athena, no CUR data was read from S3, and no output was compared to Cost Explorer. Column existence is asserted from AWS documentation, not from a live DESCRIBE. Bytes scanned and cost are not measured.

Only your own INFORMATION_SCHEMA can tell you a column exists in your dataset.

The queries

Fifteen analysis queries answering one question each — cost by service, account, resource and tag; month-over-month movers with contribution to change; anomaly detection against a trailing baseline; RI/SP coverage and unused commitment; data transfer; S3 storage and requests; and a partition-pruned variant that proves pruning changes cost, not answers.

CUR-SCHEMA.md explains the line_item_* cost columns and the line_item_line_item_type values that decide whether you double-count.

Setup

pip install cur-athena-lint        # pulls sqlglot, the only dependency
cur-athena-lint

From a clone without installing anything:

apt install python3-sqlglot        # or: pip install sqlglot
python3 verify_pack.py

Requires sqlglot only. Refresh the DDL with cur_athena_lint/setup/create_table.sql.

The full pack

The paid pack adds COST-CONTROL-ATHENA.md, VALIDATION.md (how to prove a query against Cost Explorer before trusting it), the reconciliation query, and the synthetic-CUR validation harness.

  • bank-csv-reconcile — Turn a bank CSV or Excel export into one clean table and reconcile the running balance, so a dropped row shows up instead of silently changing totals. (if you were searching for "bank statement csv to excel")
  • ga4-bigquery-lint — Lint GA4 BigQuery SQL for the session, event_params and cost mistakes that quietly give you wrong numbers, using sqlglot's real BigQuery grammar. (if you were searching for "ga4 bigquery queries")

All 28 tools in this set, grouped by what they check: dev-tools-index

If you arrived here searching for one of these, this is the tool: aws cur athena query · cost and usage report sql · athena partition pruning cost · aws cost anomaly query

→ More developer tooling like this: duke5am.gumroad.com

Release files for cur-athena-lint 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cur-athena-lint 0.1.0
File Size Uploaded
cur_athena_lint-0.1.0.tar.gz 66.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cur-athena-lint 0.1.0
File Interpreter ABI Platform
cur_athena_lint-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 129.0 kB

Release files / cur_athena_lint-0.1.0.tar.gz

Download URL cur_athena_lint-0.1.0.tar.gz
Size 66.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ebcebf5a51555e23795bd0ae83b671b1ef32c595c1062e8848e16fe971164870
BLAKE2b-256 checksum
How to use checksums
a4f40799537b75bd9e72ba898a81a034e1e002cf55abb93e61086a84e6825076
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / cur_athena_lint-0.1.0-py3-none-any.whl

Download URL cur_athena_lint-0.1.0-py3-none-any.whl
Size 62.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
152dbc67f1342d1904c66f7c1c912a6b77f4e17947d91289cd379b147ce04c54
BLAKE2b-256 checksum
How to use checksums
1c4da12412ca799181afe448c91f3990be091f2dee76218e3c79b95e755c85b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page