sql-glider 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,721 @@
1
+ Metadata-Version: 2.4
2
+ Name: sql-glider
3
+ Version: 0.1.2
4
+ Summary: SQL Utility Toolkit for better understanding, use, and governance of your queries in a native environment.
5
+ Project-URL: Homepage, https://github.com/rycowhi/sql-glider/
6
+ Project-URL: Repository, https://github.com/rycowhi/sql-glider/
7
+ Project-URL: Documentation, https://github.com/rycowhi/sql-glider/
8
+ Project-URL: Issues, https://github.com/rycowhi/sql-glider/issues
9
+ Author-email: Ryan Whitcomb <ryankwhitcomb@gmail.com>
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ Keywords: data-governance,data-lineage,lineage,sql,sqlglot
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: Apache Software License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: SQL
19
+ Classifier: Topic :: Database
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: jinja2>=3.0.0
24
+ Requires-Dist: pydantic>=2.0.0
25
+ Requires-Dist: rich>=13.0.0
26
+ Requires-Dist: rustworkx>=0.15.0
27
+ Requires-Dist: sqlglot[rs]>=25.0.0
28
+ Requires-Dist: typer>=0.9.0
29
+ Description-Content-Type: text/markdown
30
+
31
+ # SQL Glider
32
+
33
+ SQL Utility Toolkit for better understanding, use, and governance of your queries in a native environment.
34
+
35
+ ## Overview
36
+
37
+ SQL Glider provides powerful column-level and table-level lineage analysis for SQL queries using SQLGlot. It operates on standalone SQL files without requiring a full project setup, making it perfect for ad-hoc analysis, data governance, and understanding query dependencies.
38
+
39
+ ## Features
40
+
41
+ - **Forward Lineage:** Trace output columns back to their source tables and columns
42
+ - **Reverse Lineage:** Impact analysis - find which output columns are affected by a source column
43
+ - **Table Extraction:** List all tables in SQL files with usage type (INPUT/OUTPUT) and object type (TABLE/VIEW/CTE)
44
+ - **Multi-level Tracing:** Automatically handles CTEs, subqueries, and complex expressions
45
+ - **Graph-Based Lineage:** Build and query lineage graphs across thousands of SQL files
46
+ - **Multiple Output Formats:** Text (human-readable), JSON (machine-readable), CSV (spreadsheet-ready)
47
+ - **Dialect Support:** Works with Spark, PostgreSQL, Snowflake, BigQuery, MySQL, and many more SQL dialects
48
+ - **File Export:** Save lineage results to files for documentation or further processing
49
+
50
+ ## Installation
51
+
52
+ SQL Glider is available on PyPI and can be installed with pip or uv. Python 3.11+ is required.
53
+
54
+ ```bash
55
+ # Install with pip
56
+ pip install sql-glider
57
+
58
+ # Or install with uv
59
+ uv pip install sql-glider
60
+ ```
61
+
62
+ After installation, the `sqlglider` command is available:
63
+
64
+ ```bash
65
+ sqlglider lineage query.sql
66
+ ```
67
+
68
+ ### Development Setup
69
+
70
+ If you want to contribute or run from source:
71
+
72
+ ```bash
73
+ # Clone the repository
74
+ git clone https://github.com/ryanholmdahl/sql-glider.git
75
+ cd sql-glider
76
+
77
+ # Install dependencies with uv
78
+ uv sync
79
+
80
+ # Run from source
81
+ uv run sqlglider lineage <sql_file>
82
+ ```
83
+
84
+ ## Quick Start
85
+
86
+ ### Forward Lineage (Source Tracing)
87
+
88
+ Find out where your output columns come from:
89
+
90
+ ```bash
91
+ # Analyze all output columns
92
+ uv run sqlglider lineage query.sql
93
+
94
+ # Analyze a specific output column
95
+ uv run sqlglider lineage query.sql --column customer_name
96
+ ```
97
+
98
+ **Example Output:**
99
+ ```
100
+ Query 0: SELECT customer_name, o.order_total FROM customers c JOIN orders o ...
101
+ +-----------------------------------------------------------------------------+
102
+ | Output Column | Source Column |
103
+ |-----------------+------------------------------------------------------------|
104
+ | customer_name | c.customer_name |
105
+ +-----------------------------------------------------------------------------+
106
+ Total: 1 row(s)
107
+ ```
108
+
109
+ This shows that the output column `customer_name` in Query 0 comes from `c.customer_name` (the `customer_name` column in table `c`).
110
+
111
+ ### Reverse Lineage (Impact Analysis)
112
+
113
+ Find out which output columns are affected by a source column:
114
+
115
+ ```bash
116
+ # Find outputs affected by a source column
117
+ uv run sqlglider lineage query.sql --source-column orders.customer_id
118
+ ```
119
+
120
+ **Example Output:**
121
+ ```
122
+ Query 0: SELECT customer_id, segment FROM ...
123
+ +---------------------------------------------------------+
124
+ | Output Column | Source Column |
125
+ |--------------------+------------------------------------|
126
+ | orders.customer_id | orders.customer_id |
127
+ +---------------------------------------------------------+
128
+ Total: 1 row(s)
129
+ ```
130
+
131
+ This shows that if `orders.customer_id` changes, it will impact the output column `customer_id` in Query 0.
132
+
133
+ ## Usage Examples
134
+
135
+ ### Basic Column Lineage
136
+
137
+ ```bash
138
+ # Forward lineage for all columns
139
+ uv run sqlglider lineage query.sql
140
+
141
+ # Forward lineage for specific column
142
+ uv run sqlglider lineage query.sql --column order_total
143
+
144
+ # Reverse lineage (impact analysis)
145
+ uv run sqlglider lineage query.sql --source-column orders.customer_id
146
+ ```
147
+
148
+ ### Different Output Formats
149
+
150
+ ```bash
151
+ # JSON output
152
+ uv run sqlglider lineage query.sql --output-format json
153
+
154
+ # CSV output
155
+ uv run sqlglider lineage query.sql --output-format csv
156
+
157
+ # Export to file
158
+ uv run sqlglider lineage query.sql --output-format json --output-file lineage.json
159
+ ```
160
+
161
+ ### Table-Level Lineage
162
+
163
+ ```bash
164
+ # Show which tables are used
165
+ uv run sqlglider lineage query.sql --level table
166
+ ```
167
+
168
+ ### Table Extraction
169
+
170
+ List all tables involved in SQL files with usage and type information:
171
+
172
+ ```bash
173
+ # List all tables in a SQL file
174
+ uv run sqlglider tables query.sql
175
+
176
+ # JSON output with detailed table info
177
+ uv run sqlglider tables query.sql --output-format json
178
+
179
+ # Export to CSV
180
+ uv run sqlglider tables query.sql --output-format csv --output-file tables.csv
181
+ ```
182
+
183
+ **Example Output (JSON):**
184
+ ```json
185
+ {
186
+ "queries": [{
187
+ "query_index": 0,
188
+ "tables": [
189
+ {"name": "customers", "usage": "INPUT", "object_type": "UNKNOWN"},
190
+ {"name": "orders", "usage": "INPUT", "object_type": "UNKNOWN"}
191
+ ]
192
+ }]
193
+ }
194
+ ```
195
+
196
+ **Table Usage Types:**
197
+ - `INPUT`: Table is read from (SELECT, JOIN, subqueries)
198
+ - `OUTPUT`: Table is written to (INSERT, CREATE TABLE/VIEW, UPDATE)
199
+ - `BOTH`: Table is both read from and written to
200
+
201
+ **Object Types:**
202
+ - `TABLE`: CREATE TABLE or DROP TABLE statement
203
+ - `VIEW`: CREATE VIEW or DROP VIEW statement
204
+ - `CTE`: Common Table Expression (WITH clause)
205
+ - `UNKNOWN`: Cannot determine type from SQL alone
206
+
207
+ ### Different SQL Dialects
208
+
209
+ ```bash
210
+ # PostgreSQL
211
+ uv run sqlglider lineage query.sql --dialect postgres
212
+
213
+ # Snowflake
214
+ uv run sqlglider lineage query.sql --dialect snowflake
215
+
216
+ # BigQuery
217
+ uv run sqlglider lineage query.sql --dialect bigquery
218
+ ```
219
+
220
+ ### Multi-Query Files
221
+
222
+ SQL Glider automatically detects and analyzes multiple SQL statements in a single file:
223
+
224
+ ```bash
225
+ # Analyze all queries in a file
226
+ uv run sqlglider lineage multi_query.sql
227
+
228
+ # Filter to only queries that reference a specific table
229
+ uv run sqlglider lineage multi_query.sql --table customers
230
+
231
+ # Analyze specific column across all queries
232
+ uv run sqlglider lineage multi_query.sql --column customer_id
233
+
234
+ # Reverse lineage across all queries (impact analysis)
235
+ uv run sqlglider lineage multi_query.sql --source-column orders.customer_id
236
+ ```
237
+
238
+ **Example multi-query file:**
239
+ ```sql
240
+ -- multi_query.sql
241
+ SELECT customer_id, customer_name FROM customers;
242
+
243
+ SELECT order_id, customer_id, order_total FROM orders;
244
+
245
+ INSERT INTO customer_orders
246
+ SELECT c.customer_id, c.customer_name, o.order_id
247
+ FROM customers c
248
+ JOIN orders o ON c.customer_id = o.customer_id;
249
+ ```
250
+
251
+ **Output includes query index for each statement:**
252
+ ```
253
+ Query 0: SELECT customer_id, customer_name FROM customers
254
+ +---------------------------------------------------+
255
+ | Output Column | Source Column |
256
+ |-------------------------+-------------------------|
257
+ | customers.customer_id | customers.customer_id |
258
+ | customers.customer_name | customers.customer_name |
259
+ +---------------------------------------------------+
260
+ Total: 2 row(s)
261
+
262
+ Query 1: SELECT order_id, customer_id, order_total FROM orders
263
+ +---------------------------------------------+
264
+ | Output Column | Source Column |
265
+ |--------------------+------------------------|
266
+ | orders.customer_id | orders.customer_id |
267
+ | orders.order_id | orders.order_id |
268
+ | orders.order_total | orders.order_total |
269
+ +---------------------------------------------+
270
+ Total: 3 row(s)
271
+
272
+ Query 2: INSERT INTO customer_orders ...
273
+ +---------------------------------------------+
274
+ | Output Column | Source Column |
275
+ |--------------------+------------------------|
276
+ ...
277
+ ```
278
+
279
+ ### Graph-Based Lineage (Cross-File Analysis)
280
+
281
+ For analyzing lineage across multiple SQL files, SQL Glider provides graph commands:
282
+
283
+ ```bash
284
+ # Build a lineage graph from a single file
285
+ uv run sqlglider graph build query.sql -o graph.json
286
+
287
+ # Build from multiple files
288
+ uv run sqlglider graph build query1.sql query2.sql query3.sql -o graph.json
289
+
290
+ # Build from a directory (recursively finds all .sql files)
291
+ uv run sqlglider graph build ./queries/ -r -o graph.json
292
+
293
+ # Build from a manifest CSV file
294
+ uv run sqlglider graph build --manifest manifest.csv -o graph.json
295
+
296
+ # Merge multiple graphs into one
297
+ uv run sqlglider graph merge graph1.json graph2.json -o merged.json
298
+
299
+ # Query upstream dependencies (find all sources for a column)
300
+ uv run sqlglider graph query graph.json --upstream orders.customer_id
301
+
302
+ # Query downstream dependencies (find all columns affected by a source)
303
+ uv run sqlglider graph query graph.json --downstream customers.id
304
+ ```
305
+
306
+ **Example Upstream Query Output:**
307
+ ```
308
+ Sources for 'order_totals.total'
309
+ +--------------------------------------------------------------------------------------------+
310
+ | Column | Table | Hops | Root | Leaf | Paths | File |
311
+ |--------+--------+------+------+------+------------------------------------+----------------|
312
+ | amount | orders | 1 | Y | N | orders.amount -> order_totals.total| test_graph.sql |
313
+ +--------------------------------------------------------------------------------------------+
314
+
315
+ Total: 1 column(s)
316
+ ```
317
+
318
+ **Example Downstream Query Output:**
319
+ ```
320
+ Affected Columns for 'orders.amount'
321
+ +--------------------------------------------------------------------------------------------+
322
+ | Column | Table | Hops | Root | Leaf | Paths | File |
323
+ |--------+--------------+------+------+------+------------------------------------+----------------|
324
+ | total | order_totals | 1 | N | Y | orders.amount -> order_totals.total| test_graph.sql |
325
+ +--------------------------------------------------------------------------------------------+
326
+
327
+ Total: 1 column(s)
328
+ ```
329
+
330
+ **Output Fields:**
331
+ - **Root**: `Y` if the column has no upstream dependencies (source column)
332
+ - **Leaf**: `Y` if the column has no downstream dependencies (final output)
333
+ - **Paths**: All paths from the dependency to the queried column
334
+
335
+ **Manifest File Format:**
336
+ ```csv
337
+ file_path,dialect
338
+ queries/orders.sql,spark
339
+ queries/customers.sql,postgres
340
+ queries/legacy.sql,
341
+ ```
342
+
343
+ The graph feature is designed for scale - it can handle thousands of SQL files and provides efficient upstream/downstream queries using rustworkx.
344
+
345
+ ## Use Cases
346
+
347
+ ### Data Governance
348
+
349
+ **Impact Assessment:**
350
+ ```bash
351
+ # Before modifying a source column, check its impact
352
+ uv run sqlglider lineage analytics_dashboard.sql --source-column orders.revenue
353
+ ```
354
+
355
+ This helps you understand which downstream outputs will be affected by schema changes.
356
+
357
+ ### Query Understanding
358
+
359
+ **Source Tracing:**
360
+ ```bash
361
+ # Understand where a metric comes from
362
+ uv run sqlglider lineage metrics.sql --column total_revenue
363
+ ```
364
+
365
+ Quickly trace complex calculations back to their source tables.
366
+
367
+ ### Documentation
368
+
369
+ **Export Lineage:**
370
+ ```bash
371
+ # Generate documentation for your queries
372
+ uv run sqlglider lineage query.sql --output-format csv --output-file docs/lineage.csv
373
+ ```
374
+
375
+ Create machine-readable lineage documentation for data catalogs.
376
+
377
+ ### Literal Value Handling
378
+
379
+ When analyzing UNION queries, SQL Glider identifies literal values (constants) as sources and displays them clearly:
380
+
381
+ ```sql
382
+ -- query.sql
383
+ SELECT customer_id, last_order_date FROM active_customers
384
+ UNION ALL
385
+ SELECT customer_id, NULL AS last_order_date FROM prospects
386
+ UNION ALL
387
+ SELECT customer_id, 'unknown' AS status FROM legacy_data
388
+ ```
389
+
390
+ ```bash
391
+ uv run sqlglider lineage query.sql
392
+ ```
393
+
394
+ **Example Output:**
395
+ ```
396
+ Query 0: SELECT customer_id, last_order_date FROM active_customers ...
397
+ +---------------------------------------------------------------------+
398
+ | Output Column | Source Column |
399
+ |----------------------------------+----------------------------------|
400
+ | active_customers.customer_id | active_customers.customer_id |
401
+ | | prospects.customer_id |
402
+ | active_customers.last_order_date | <literal: NULL> |
403
+ | | active_customers.last_order_date |
404
+ +---------------------------------------------------------------------+
405
+ Total: 4 row(s)
406
+ ```
407
+
408
+ Literal values are displayed as `<literal: VALUE>` to clearly distinguish them from actual column sources:
409
+ - `<literal: NULL>` - NULL values
410
+ - `<literal: 0>` - Numeric literals
411
+ - `<literal: 'string'>` - String literals
412
+ - `<literal: CURRENT_TIMESTAMP()>` - Function calls
413
+
414
+ This helps identify which branches of a UNION contribute actual data lineage versus hardcoded values.
415
+
416
+ ### Multi-Level Analysis
417
+
418
+ SQL Glider automatically traces through CTEs and subqueries:
419
+
420
+ ```sql
421
+ -- query.sql
422
+ WITH order_totals AS (
423
+ SELECT customer_id, SUM(order_amount) as total_amount
424
+ FROM orders
425
+ GROUP BY customer_id
426
+ ),
427
+ customer_segments AS (
428
+ SELECT
429
+ ot.customer_id,
430
+ c.customer_name,
431
+ CASE
432
+ WHEN ot.total_amount > 10000 THEN 'Premium'
433
+ ELSE 'Standard'
434
+ END as segment
435
+ FROM order_totals ot
436
+ JOIN customers c ON ot.customer_id = c.customer_id
437
+ )
438
+ SELECT customer_name, segment, total_amount
439
+ FROM customer_segments
440
+ ```
441
+
442
+ ```bash
443
+ # Trace segment back to its ultimate sources
444
+ uv run sqlglider lineage query.sql --column segment
445
+ # Output: orders.order_amount (through the CASE statement and SUM)
446
+
447
+ # Find what's affected by order_amount
448
+ uv run sqlglider lineage query.sql --source-column orders.order_amount
449
+ # Output: segment, total_amount
450
+ ```
451
+
452
+ ## CLI Reference
453
+
454
+ ```
455
+ sqlglider lineage <sql_file> [OPTIONS]
456
+
457
+ Arguments:
458
+ sql_file Path to SQL file to analyze [required]
459
+
460
+ Options:
461
+ --level, -l Analysis level: 'column' or 'table' [default: column]
462
+ --dialect, -d SQL dialect (spark, postgres, snowflake, etc.) [default: spark]
463
+ --column, -c Specific output column for forward lineage [optional]
464
+ --source-column, -s Source column for reverse lineage (impact analysis) [optional]
465
+ --table, -t Filter to only queries that reference this table (multi-query files) [optional]
466
+ --output-format, -f Output format: 'text', 'json', or 'csv' [default: text]
467
+ --output-file, -o Write output to file instead of stdout [optional]
468
+ --help Show help message and exit
469
+ ```
470
+
471
+ **Notes:**
472
+ - `--column` and `--source-column` are mutually exclusive. Use one or the other.
473
+ - `--table` filter is useful for multi-query files to analyze only queries that reference a specific table.
474
+
475
+ ### Tables Command
476
+
477
+ ```
478
+ sqlglider tables <sql_file> [OPTIONS]
479
+
480
+ Arguments:
481
+ sql_file Path to SQL file to analyze [required]
482
+
483
+ Options:
484
+ --dialect, -d SQL dialect (spark, postgres, snowflake, etc.) [default: spark]
485
+ --table Filter to only queries that reference this table [optional]
486
+ --output-format, -f Output format: 'text', 'json', or 'csv' [default: text]
487
+ --output-file, -o Write output to file instead of stdout [optional]
488
+ --templater, -t Templater for SQL preprocessing (e.g., 'jinja', 'none') [optional]
489
+ --var, -v Template variable in key=value format (repeatable) [optional]
490
+ --vars-file Path to variables file (JSON or YAML) [optional]
491
+ --help Show help message and exit
492
+ ```
493
+
494
+ ### Graph Commands
495
+
496
+ ```
497
+ sqlglider graph build <paths> [OPTIONS]
498
+
499
+ Arguments:
500
+ paths SQL file(s) or directory to process [optional]
501
+
502
+ Options:
503
+ --output, -o Output JSON file path [required]
504
+ --manifest, -m Path to manifest CSV file [optional]
505
+ --recursive, -r Recursively search directories [default: True]
506
+ --glob, -g Glob pattern for SQL files [default: *.sql]
507
+ --dialect, -d SQL dialect [default: spark]
508
+ --node-format, -n Node format: 'qualified' or 'structured' [default: qualified]
509
+ ```
510
+
511
+ ```
512
+ sqlglider graph merge <inputs> [OPTIONS]
513
+
514
+ Arguments:
515
+ inputs JSON graph files to merge [optional]
516
+
517
+ Options:
518
+ --output, -o Output file path [required]
519
+ --glob, -g Glob pattern for graph files [optional]
520
+ ```
521
+
522
+ ```
523
+ sqlglider graph query <graph_file> [OPTIONS]
524
+
525
+ Arguments:
526
+ graph_file Path to graph JSON file [required]
527
+
528
+ Options:
529
+ --upstream, -u Find source columns for this column [optional]
530
+ --downstream, -d Find affected columns for this source [optional]
531
+ --output-format, -f Output format: 'text', 'json', or 'csv' [default: text]
532
+ ```
533
+
534
+ **Notes:**
535
+ - `--upstream` and `--downstream` are mutually exclusive. Use one or the other.
536
+ - Graph queries are case-insensitive for column matching.
537
+
538
+ ## Output Formats
539
+
540
+ ### Text Format (Default)
541
+
542
+ Human-readable Rich table format showing query index and preview:
543
+
544
+ ```
545
+ Query 0: SELECT customer_name FROM customers c ...
546
+ +---------------------------------------------------+
547
+ | Output Column | Source Column |
548
+ |-----------------+---------------------------------|
549
+ | customer_name | c.customer_name |
550
+ +---------------------------------------------------+
551
+ Total: 1 row(s)
552
+ ```
553
+
554
+ ### JSON Format
555
+
556
+ Machine-readable structured format with query metadata:
557
+
558
+ ```json
559
+ {
560
+ "queries": [
561
+ {
562
+ "query_index": 0,
563
+ "query_preview": "SELECT customer_name FROM customers c ...",
564
+ "level": "column",
565
+ "lineage": [
566
+ {
567
+ "output_name": "customer_name",
568
+ "source_name": "c.customer_name"
569
+ }
570
+ ]
571
+ }
572
+ ]
573
+ }
574
+ ```
575
+
576
+ ### CSV Format
577
+
578
+ Spreadsheet-ready tabular format with query index:
579
+
580
+ ```csv
581
+ query_index,output_column,source_column
582
+ 0,customer_name,c.customer_name
583
+ ```
584
+
585
+ **Note:** Each source column gets its own row. If an output column has multiple sources, there will be multiple rows with the same `query_index` and `output_column`.
586
+
587
+ ## Development
588
+
589
+ ### Setup
590
+
591
+ ```bash
592
+ # Install dependencies
593
+ uv sync
594
+
595
+ # Run linter
596
+ uv run ruff check
597
+
598
+ # Auto-fix issues
599
+ uv run ruff check --fix
600
+
601
+ # Format code
602
+ uv run ruff format
603
+
604
+ # Type checking
605
+ uv run basedpyright
606
+ ```
607
+
608
+ ### Project Structure
609
+
610
+ See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed technical documentation.
611
+
612
+ ```
613
+ src/sqlglider/
614
+ ├── cli.py # Typer CLI entry point
615
+ ├── graph/
616
+ │ ├── builder.py # Build graphs from SQL files
617
+ │ ├── merge.py # Merge multiple graphs
618
+ │ ├── query.py # Query upstream/downstream lineage
619
+ │ └── models.py # Graph data models
620
+ ├── lineage/
621
+ │ ├── analyzer.py # Core lineage analysis using SQLGlot
622
+ │ └── formatters.py # Output formatters (text, JSON, CSV)
623
+ └── utils/
624
+ └── file_utils.py # File I/O utilities
625
+ ```
626
+
627
+ ## Publishing
628
+
629
+ SQL Glider is configured for publishing to both TestPyPI and PyPI using `uv`.
630
+
631
+ ### Versioning
632
+
633
+ SQL Glider uses Git tags for version management via [hatch-vcs](https://github.com/ofek/hatch-vcs). The version is automatically derived from Git:
634
+
635
+ - **Tagged commits:** Version matches the tag (e.g., `git tag v0.2.0` produces version `0.2.0`)
636
+ - **Untagged commits:** Version includes development info (e.g., `0.1.dev18+g7216a59`)
637
+
638
+ **Creating a new release:**
639
+
640
+ ```bash
641
+ # Create and push a version tag
642
+ git tag v0.2.0
643
+ git push origin v0.2.0
644
+
645
+ # Build will now produce version 0.2.0
646
+ uv build
647
+ ```
648
+
649
+ **Tag format:** Use `v` prefix (e.g., `v1.0.0`, `v0.2.1`). The `v` is stripped from the final version number.
650
+
651
+ ### Building the Package
652
+
653
+ ```bash
654
+ # Build the distribution files (wheel and sdist)
655
+ uv build
656
+ ```
657
+
658
+ This creates distribution files in the `dist/` directory.
659
+
660
+ ### Publishing to TestPyPI
661
+
662
+ Always test your release on TestPyPI first:
663
+
664
+ ```bash
665
+ # Publish to TestPyPI
666
+ uv publish --index testpypi --token <YOUR_TESTPYPI_TOKEN>
667
+
668
+ # Test installation from TestPyPI
669
+ uv pip install --index-url https://test.pypi.org/simple/ sql-glider
670
+ ```
671
+
672
+ ### Publishing to PyPI
673
+
674
+ Once verified on TestPyPI, publish to production:
675
+
676
+ ```bash
677
+ # Publish to PyPI
678
+ uv publish --index pypi --token <YOUR_PYPI_TOKEN>
679
+ ```
680
+
681
+ ### Token Setup
682
+
683
+ You'll need API tokens from both registries:
684
+
685
+ 1. **TestPyPI Token:** Create at https://test.pypi.org/manage/account/token/
686
+ 2. **PyPI Token:** Create at https://pypi.org/manage/account/token/
687
+
688
+ **Option 1: Pass token directly (shown above)**
689
+
690
+ **Option 2: Environment variable**
691
+ ```bash
692
+ export UV_PUBLISH_TOKEN=pypi-...
693
+ uv publish --index pypi
694
+ ```
695
+
696
+ **Option 3: Store in `.env` file (not committed to git)**
697
+ ```bash
698
+ # .env
699
+ UV_PUBLISH_TOKEN=pypi-...
700
+ ```
701
+
702
+ **Security Note:** Never commit API tokens to version control. The `.gitignore` file should include `.env`.
703
+
704
+ ## Dependencies
705
+
706
+ - **sqlglot[rs]:** SQL parser and lineage analysis library with Rust extensions
707
+ - **typer:** CLI framework with type hints
708
+ - **rich:** Terminal formatting and colored output
709
+ - **pydantic:** Data validation and serialization
710
+ - **rustworkx:** High-performance graph library for cross-file lineage analysis
711
+
712
+ ## References
713
+
714
+ - [SQLGlot Documentation](https://sqlglot.com/)
715
+ - [UV Documentation](https://docs.astral.sh/uv/)
716
+ - [Typer Documentation](https://typer.tiangolo.com/)
717
+ - [Ruff Documentation](https://docs.astral.sh/ruff/configuration/)
718
+
719
+ ## License
720
+
721
+ See LICENSE file for details.