Metadata-Version: 2.4
Name: iplytics
Version: 1.0.0
Summary: IPL Cricket Analytics Platform - Query IPL data with SQL, semantic metrics and instant visualizations
Author: ch04niverse
License: MIT
Project-URL: Homepage, https://github.com/charan0318/iplytics
Project-URL: Repository, https://github.com/charan0318/iplytics
Project-URL: Issues, https://github.com/charan0318/iplytics/issues
Project-URL: Documentation, https://iplytics.readthedocs.io
Keywords: cricket,ipl,analytics,sql,duckdb,data-science
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Database
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: polars>=1.0.0
Requires-Dist: duckdb>=1.0.0
Requires-Dist: dbt-duckdb>=1.8.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: fastapi>=0.115.0
Requires-Dist: uvicorn[standard]>=0.32.0
Requires-Dist: sqlglot>=25.0.0
Requires-Dist: sqlparse>=0.5.0
Requires-Dist: psutil>=6.0.0
Requires-Dist: pyarrow>=18.0.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: typer>=0.12.0
Requires-Dist: rich>=13.0.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
Requires-Dist: httpx>=0.27.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: ruff>=0.5.0; extra == "dev"
Requires-Dist: mypy>=1.10.0; extra == "dev"
Provides-Extra: sdk
Requires-Dist: httpx>=0.27.0; extra == "sdk"
Provides-Extra: server
Requires-Dist: fastapi>=0.115.0; extra == "server"
Requires-Dist: uvicorn[standard]>=0.32.0; extra == "server"
Provides-Extra: etl
Requires-Dist: polars>=1.0.0; extra == "etl"
Requires-Dist: pyyaml>=6.0; extra == "etl"
Dynamic: license-file

# IPLytics

[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Status: Experimental](https://img.shields.io/badge/status-experimental-orange.svg)](https://github.com/charan0318/iplytics)
[![PyPI](https://img.shields.io/badge/PyPI-available-brightgreen.svg)](https://pypi.org/project/iplytics/)
[![GitHub stars](https://img.shields.io/github/stars/charan0318/iplytics?style=social)](https://github.com/charan0318/iplytics)

**A self-service analytics platform for IPL cricket data**

---

## What is IPLytics?

IPLytics is an open-source analytics platform that lets you query IPL cricket data using SQL.

You write SQL. IPLytics handles the rest — data ingestion, modeling, semantic metrics, caching, visualization recommendations.

## Why IPLytics?

| Problem | Traditional Approach | IPLytics |
|---------|---------------------|----------|
| **Data access** | Scrape Cricbuzz/ESPN, parse HTML | Clean Parquet + SQL |
| **Metrics** | Recalculate strike rate every query | Semantic metrics (strike_rate, economy, batting_average) |
| **Context** | Raw numbers | Phase-aware (powerplay/middle/death), venue-adjusted |
| **Iteration** | Re-write Python scripts | Iterate in SQL, save as views |

**IPLytics is not a dashboard tool.** It's a **semantic analytics layer** — you bring questions, it brings context.

> **Disclaimer:** This project is experimental and a student project. It is intended for learning, prototyping, and personal exploration rather than production or business-critical use. APIs, schemas, and behavior may change significantly over time.

---

## Quick Start (v1.0+)

### Prerequisites
- Python 3.10+
- [Cricsheet IPL data](https://cricsheet.org/downloads/ipl_json.zip) in `raw/cricsheet/ipl/` (for local build)

### 1. Install
```bash
pip install iplytics
```

### 2. Download Dataset (or build locally)
```bash
# Option A: Download pre-built dataset (~30MB)
iplytics download

# Option B: Build from raw Cricsheet data
iplytics build
```

### 3. Query Immediately
```python
from iplytics import IPLytics

ipl = IPLytics()
result = ipl.query("""
    SELECT player_name, total_runs, strike_rate 
    FROM mart_batting_stats 
    ORDER BY total_runs DESC 
    LIMIT 10
""")
print(result.data)
```

That's it. No API server needed for local use.

---

## Architecture

```
┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Cricsheet  │────▶│   Polars    │────▶│   Parquet   │────▶│    dbt      │
│    YAML     │     │    ETL      │     │   Lake      │     │   Models    │
└─────────────┘     └─────────────┘     └─────────────┘     └──────┬──────┘
                                                                     │
┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌────────▼──────┐
│   SDK/CLI   │◀───│  IPLytics   │◀───│  Execution  │◀───│   DuckDB      │
│             │     │   Core      │     │   Engine    │     │  (Warehouse)  │
└─────────────┘     └─────────────┘     └─────────────┘     └───────────────┘
```

### Two Ways to Run

| Mode | Use Case | Command |
|------|----------|---------|
| **Local (default)** | Notebooks, scripts, CLI | `from iplytics import IPLytics` |
| **Server** | REST API for other apps | `iplytics serve` |

The server is just another interface — the core engine is shared.

---

## Public API

```python
from iplytics import IPLytics

ipl = IPLytics()  # Auto-discovers ~/.iplytics/warehouse.duckdb

# Core query interface
ipl.query(sql)           # Execute SQL → QueryResponse
ipl.validate(sql)        # Validate without executing → ValidationResponse

# Semantic layer
ipl.metrics(tag="batting")  # List metrics (filter by tag/model)
ipl.metric("strike_rate")   # Get metric definition
ipl.dimensions()            # List dimensions

# Schema & catalog
ipl.tables()                # List all tables with metadata
ipl.table("mart_batting_stats")  # Table details
ipl.table_sample("matches", 5)   # Sample rows
ipl.catalog()               # Full catalog (tables + metrics + dimensions)

# Data management
ipl.download()              # Download pre-built dataset
ipl.build()                 # Build from raw data (ETL + dbt)
ipl.info()                  # Dataset info (version, size, tables)
ipl.clean()                 # Remove all data
```

### LocalClient (for advanced use)
```python
from iplytics import LocalClient

client = LocalClient()  # Same API, explicit local execution
result = client.query("SELECT * FROM matches LIMIT 10")
```

---

### Data Flow
1. **Ingest** — Cricsheet YAML → Polars → Partitioned Parquet
2. **Model** — dbt: staging → core (dim/fact) → semantic (metrics)
3. **Serve** — DuckDB → IPLytics Core → SDK/CLI/Server
4. **Analyze** — SQL → Semantic metrics → Visualization recommendations

---

## Core Concepts

### Semantic Metrics
Metrics are defined once in YAML, used everywhere:

```yaml
# semantic/metrics/batting.yml
strike_rate:
  label: "Strike Rate"
  description: "Runs per 100 balls faced"
  model: mart_batting_stats
  formula: "total_runs * 100.0 / NULLIF(total_balls, 0)"
  unit: "runs_per_100_balls"
  tags: ["batting", "core"]
```

Use anywhere:
```sql
SELECT player_name, strike_rate FROM mart_batting_stats ORDER BY strike_rate DESC;
```

### Phase-Aware Analytics
Every ball knows its phase:
- **Powerplay** (overs 1-6)
- **Middle** (overs 7-15)  
- **Death** (overs 16-20)

```sql
-- Powerplay strike rate by batter
SELECT batter, 
       SUM(runs_total) * 100.0 / COUNT(*) as pp_strike_rate
FROM fct_ball
WHERE phase = 'powerplay'
GROUP BY batter
ORDER BY pp_strike_rate DESC;
```

### Venue-Adjusted Metrics
```sql
-- Venue scoring bias
SELECT venue, 
       AVG(first_innings_score) as avg_score
FROM matches
GROUP BY venue
ORDER BY avg_score DESC;
```

---

## Project Structure

```
iplytics/
├── configs/                # Configuration files
├── dbt/                    # dbt models
│   ├── models/
│   │   ├── staging/        # Raw → clean
│   │   ├── intermediate/   # Reusable transformations
│   │   ├── core/           # dim/fact/mart
│   │   └── semantic/       # Metric definitions
├── etl/                    # Polars ETL pipeline
├── examples/
│   ├── sdk/                # Python SDK examples
│   └── sql/                # Canonical SQL queries
├── notebooks/              # Jupyter tutorials
├── raw/                    # Raw Cricsheet data (YAML/JSON)
├── semantic/               # Metric/dimension YAML
├── src/iplytics/           # Python package
│   ├── core.py             # Main IPLytics class (public API)
│   ├── models.py           # Public Pydantic models
│   ├── execution/          # Query engine (DuckDB)
│   ├── metadata/           # Semantic registry
│   ├── sdk/                # Python SDK (LocalClient, Client)
│   └── api/                # FastAPI endpoints (server mode)
├── tests/                  # Unit + API tests
├── warehouse/              # DuckDB + Parquet
└── docs/                   # Documentation
```

---

## Example Queries

### Orange Cap (Top Run Scorers)
```sql
SELECT player_name, total_runs, strike_rate, total_boundaries
FROM mart_batting_stats
ORDER BY total_runs DESC
LIMIT 10;
```

### Purple Cap (Top Wicket Takers)
```sql
SELECT player_name, total_wickets, economy, bowling_strike_rate
FROM mart_bowling_stats
ORDER BY total_wickets DESC
LIMIT 10;
```

### Venue Bias
```sql
SELECT venue, 
       COUNT(*) as matches,
       AVG(first_innings_score) as avg_first_innings,
       AVG(CASE WHEN winner = toss_winner THEN 1 ELSE 0 END) as toss_win_pct
FROM matches
GROUP BY venue
HAVING COUNT(*) > 10
ORDER BY avg_first_innings DESC;
```

### Powerplay Dominance
```sql
SELECT batting_team,
       SUM(runs_total) * 100.0 / COUNT(*) as pp_run_rate
FROM fct_ball
WHERE phase = 'powerplay'
GROUP BY batting_team
ORDER BY pp_run_rate DESC;
```

### Death Over Specialists
```sql
SELECT bowler,
       SUM(runs_total) * 6.0 / COUNT(*) as death_economy,
       COUNT(*) as balls_bowled
FROM fct_ball
WHERE phase = 'death'
GROUP BY bowler
HAVING COUNT(*) > 100
ORDER BY death_economy ASC;
```

---

## Tech Stack

| Layer | Technology |
|-------|------------|
| **ETL** | Polars, PyYAML |
| **Storage** | Parquet, DuckDB |
| **Modeling** | dbt-duckdb |
| **API** | FastAPI, Pydantic |
| **Execution** | DuckDB, SQLGlot |
| **Semantic** | YAML, Jinja2 |
| **Visualization** | Vega-Lite, Apache ECharts |
| **CLI** | Typer, Rich |
| **SDK** | httpx, Pydantic |
| **Tests** | pytest, pytest-asyncio |

---

## License

MIT — Free for personal and commercial use.

---

## Why "IPLytics"?

Because **IPL + Analytics = IPLytics**. 

Built for the analyst who wants to ask "What's Kohli's strike rate against left-arm spin in death overs at Chinnaswamy?" and get an answer in milliseconds — not hours of data wrangling.

---

*Star ⭐ this repo if you love cricket and data.*
