sql-testing-library 0.10.0__tar.gz → 0.11.0__tar.gz

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.
Files changed (22) hide show
  1. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/CHANGELOG.md +12 -0
  2. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/PKG-INFO +70 -8
  3. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/README.md +69 -7
  4. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/pyproject.toml +1 -1
  5. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_adapters/snowflake.py +31 -1
  6. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_exceptions.py +14 -3
  7. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_sql_utils.py +9 -0
  8. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/LICENSE +0 -0
  9. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/__init__.py +0 -0
  10. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_adapters/__init__.py +0 -0
  11. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_adapters/athena.py +0 -0
  12. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_adapters/base.py +0 -0
  13. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_adapters/bigquery.py +0 -0
  14. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_adapters/presto.py +0 -0
  15. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_adapters/redshift.py +0 -0
  16. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_adapters/trino.py +0 -0
  17. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_core.py +0 -0
  18. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_mock_table.py +0 -0
  19. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_pytest_plugin.py +0 -0
  20. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_sql_logger.py +0 -0
  21. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/_types.py +0 -0
  22. {sql_testing_library-0.10.0 → sql_testing_library-0.11.0}/src/sql_testing_library/py.typed +0 -0
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 0.11.0 (2025-06-16)
9
+
10
+ ### Feat
11
+
12
+ - **snowflake**: ad support for map datatype in snowflake (#101)
13
+
14
+ ## 0.10.1 (2025-06-15)
15
+
16
+ ### Fix
17
+
18
+ - run unittests against different os/python versions (#100)
19
+
8
20
  ## 0.10.0 (2025-06-15)
9
21
 
10
22
  ### Feat
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sql-testing-library
3
- Version: 0.10.0
3
+ Version: 0.11.0
4
4
  Summary: A powerful Python framework for unit testing SQL queries across BigQuery, Snowflake, Redshift, Athena, and Trino with mock data
5
5
  License: MIT
6
6
  Keywords: sql,testing,unit-testing,mock-data,database-testing,bigquery,snowflake,redshift,athena,trino,data-engineering,etl-testing,sql-validation,query-testing
@@ -136,7 +136,7 @@ The library supports different data types across database engines. All checkmark
136
136
  | **Integer Array** | `List[int]` | ✅ | ✅ | ✅ | ✅ | ✅ |
137
137
  | **Decimal Array** | `List[Decimal]` | ✅ | ✅ | ✅ | ✅ | ✅ |
138
138
  | **Optional Array** | `Optional[List[T]]` | ✅ | ✅ | ✅ | ✅ | ✅ |
139
- | **Map/Dict** | `Dict[K, V]` | ✅ | ✅ | ✅ | ✅ | |
139
+ | **Map/Dict** | `Dict[K, V]` | ✅ | ✅ | ✅ | ✅ | |
140
140
  | **Struct/Record** | `dataclass` | ❌ | ❌ | ❌ | ❌ | ❌ |
141
141
  | **Nested Arrays** | `List[List[T]]` | ❌ | ❌ | ❌ | ❌ | ❌ |
142
142
 
@@ -146,7 +146,7 @@ The library supports different data types across database engines. All checkmark
146
146
  - **Athena**: 256KB query size limit; supports arrays and maps using `ARRAY[]` and `MAP(ARRAY[], ARRAY[])` syntax
147
147
  - **Redshift**: Arrays and maps implemented via SUPER type (JSON parsing); 16MB query size limit
148
148
  - **Trino**: Memory catalog for testing; excellent decimal precision; supports arrays and maps
149
- - **Snowflake**: Column names normalized to lowercase; 1MB query size limit
149
+ - **Snowflake**: Column names normalized to lowercase; 1MB query size limit; dict/map types implemented via VARIANT type (JSON parsing)
150
150
 
151
151
  ## Execution Modes Support
152
152
 
@@ -842,20 +842,83 @@ The adapter_type parameter will use the configuration from the corresponding sec
842
842
 
843
843
  ## Development Setup
844
844
 
845
+ ### Quick Start with Make
846
+
847
+ The project includes a Makefile for common development tasks:
848
+
849
+ ```bash
850
+ # Install all dependencies
851
+ make install
852
+
853
+ # Run unit tests
854
+ make test
855
+
856
+ # Run linting and type checking
857
+ make lint
858
+
859
+ # Format code
860
+ make format
861
+
862
+ # Run all checks (lint + format check + tests)
863
+ make check
864
+
865
+ # See all available commands
866
+ make help
867
+ ```
868
+
869
+ ### Available Make Commands
870
+
871
+ | Command | Description |
872
+ |---------|-------------|
873
+ | `make install` | Install all dependencies with poetry |
874
+ | `make test` | Run unit tests with coverage |
875
+ | `make test-unit` | Run unit tests (excludes integration tests) |
876
+ | `make test-integration` | Run integration tests (requires DB credentials) |
877
+ | `make test-all` | Run all tests (unit + integration) |
878
+ | `make test-tox` | Run tests across all Python versions (3.9-3.12) |
879
+ | `make lint` | Run ruff and mypy checks |
880
+ | `make format` | Format code with black and ruff |
881
+ | `make check` | Run all checks (lint + format + tests) |
882
+ | `make clean` | Remove build artifacts and cache files |
883
+ | `make build` | Build distribution packages |
884
+ | `make docs` | Build documentation |
885
+
886
+ ### Testing Across Python Versions
887
+
888
+ The project supports Python 3.9-3.12. You can test across all versions using:
889
+
890
+ ```bash
891
+ # Using tox (automatically tests all Python versions)
892
+ make test-tox
893
+
894
+ # Or directly with tox
895
+ tox
896
+
897
+ # Test specific Python version
898
+ tox -e py39 # Python 3.9
899
+ tox -e py310 # Python 3.10
900
+ tox -e py311 # Python 3.11
901
+ tox -e py312 # Python 3.12
902
+ ```
903
+
845
904
  ### Code Quality
846
905
 
847
906
  The project uses comprehensive tools to ensure code quality:
848
907
 
849
908
  1. **Ruff** for linting and formatting
850
- 2. **Pyright** for static type checking
851
- 3. **Pre-commit hooks** for automated checks
909
+ 2. **Black** for code formatting
910
+ 3. **Mypy** for static type checking
911
+ 4. **Pre-commit hooks** for automated checks
852
912
 
853
913
  To set up the development environment:
854
914
 
855
915
  1. Install development dependencies:
856
916
  ```bash
857
- # Install all dependencies including database adapters and dev tools
858
- poetry install --with bigquery,athena,redshift,trino,snowflake,dev
917
+ # Using make
918
+ make install
919
+
920
+ # Or directly with poetry
921
+ poetry install --all-extras
859
922
  ```
860
923
 
861
924
  2. Set up pre-commit hooks:
@@ -985,7 +1048,6 @@ The library has a few known limitations that are planned to be addressed in futu
985
1048
 
986
1049
  ### Snowflake Support
987
1050
  - Physical table tests for Snowflake are currently skipped due to complex mocking requirements
988
- - Need better support for Snowflake-specific data types (VARIANT, OBJECT, ARRAY)
989
1051
 
990
1052
  ### General Improvements
991
1053
  - Add support for more SQL dialects
@@ -79,7 +79,7 @@ The library supports different data types across database engines. All checkmark
79
79
  | **Integer Array** | `List[int]` | ✅ | ✅ | ✅ | ✅ | ✅ |
80
80
  | **Decimal Array** | `List[Decimal]` | ✅ | ✅ | ✅ | ✅ | ✅ |
81
81
  | **Optional Array** | `Optional[List[T]]` | ✅ | ✅ | ✅ | ✅ | ✅ |
82
- | **Map/Dict** | `Dict[K, V]` | ✅ | ✅ | ✅ | ✅ | |
82
+ | **Map/Dict** | `Dict[K, V]` | ✅ | ✅ | ✅ | ✅ | |
83
83
  | **Struct/Record** | `dataclass` | ❌ | ❌ | ❌ | ❌ | ❌ |
84
84
  | **Nested Arrays** | `List[List[T]]` | ❌ | ❌ | ❌ | ❌ | ❌ |
85
85
 
@@ -89,7 +89,7 @@ The library supports different data types across database engines. All checkmark
89
89
  - **Athena**: 256KB query size limit; supports arrays and maps using `ARRAY[]` and `MAP(ARRAY[], ARRAY[])` syntax
90
90
  - **Redshift**: Arrays and maps implemented via SUPER type (JSON parsing); 16MB query size limit
91
91
  - **Trino**: Memory catalog for testing; excellent decimal precision; supports arrays and maps
92
- - **Snowflake**: Column names normalized to lowercase; 1MB query size limit
92
+ - **Snowflake**: Column names normalized to lowercase; 1MB query size limit; dict/map types implemented via VARIANT type (JSON parsing)
93
93
 
94
94
  ## Execution Modes Support
95
95
 
@@ -785,20 +785,83 @@ The adapter_type parameter will use the configuration from the corresponding sec
785
785
 
786
786
  ## Development Setup
787
787
 
788
+ ### Quick Start with Make
789
+
790
+ The project includes a Makefile for common development tasks:
791
+
792
+ ```bash
793
+ # Install all dependencies
794
+ make install
795
+
796
+ # Run unit tests
797
+ make test
798
+
799
+ # Run linting and type checking
800
+ make lint
801
+
802
+ # Format code
803
+ make format
804
+
805
+ # Run all checks (lint + format check + tests)
806
+ make check
807
+
808
+ # See all available commands
809
+ make help
810
+ ```
811
+
812
+ ### Available Make Commands
813
+
814
+ | Command | Description |
815
+ |---------|-------------|
816
+ | `make install` | Install all dependencies with poetry |
817
+ | `make test` | Run unit tests with coverage |
818
+ | `make test-unit` | Run unit tests (excludes integration tests) |
819
+ | `make test-integration` | Run integration tests (requires DB credentials) |
820
+ | `make test-all` | Run all tests (unit + integration) |
821
+ | `make test-tox` | Run tests across all Python versions (3.9-3.12) |
822
+ | `make lint` | Run ruff and mypy checks |
823
+ | `make format` | Format code with black and ruff |
824
+ | `make check` | Run all checks (lint + format + tests) |
825
+ | `make clean` | Remove build artifacts and cache files |
826
+ | `make build` | Build distribution packages |
827
+ | `make docs` | Build documentation |
828
+
829
+ ### Testing Across Python Versions
830
+
831
+ The project supports Python 3.9-3.12. You can test across all versions using:
832
+
833
+ ```bash
834
+ # Using tox (automatically tests all Python versions)
835
+ make test-tox
836
+
837
+ # Or directly with tox
838
+ tox
839
+
840
+ # Test specific Python version
841
+ tox -e py39 # Python 3.9
842
+ tox -e py310 # Python 3.10
843
+ tox -e py311 # Python 3.11
844
+ tox -e py312 # Python 3.12
845
+ ```
846
+
788
847
  ### Code Quality
789
848
 
790
849
  The project uses comprehensive tools to ensure code quality:
791
850
 
792
851
  1. **Ruff** for linting and formatting
793
- 2. **Pyright** for static type checking
794
- 3. **Pre-commit hooks** for automated checks
852
+ 2. **Black** for code formatting
853
+ 3. **Mypy** for static type checking
854
+ 4. **Pre-commit hooks** for automated checks
795
855
 
796
856
  To set up the development environment:
797
857
 
798
858
  1. Install development dependencies:
799
859
  ```bash
800
- # Install all dependencies including database adapters and dev tools
801
- poetry install --with bigquery,athena,redshift,trino,snowflake,dev
860
+ # Using make
861
+ make install
862
+
863
+ # Or directly with poetry
864
+ poetry install --all-extras
802
865
  ```
803
866
 
804
867
  2. Set up pre-commit hooks:
@@ -928,7 +991,6 @@ The library has a few known limitations that are planned to be addressed in futu
928
991
 
929
992
  ### Snowflake Support
930
993
  - Physical table tests for Snowflake are currently skipped due to complex mocking requirements
931
- - Need better support for Snowflake-specific data types (VARIANT, OBJECT, ARRAY)
932
994
 
933
995
  ### General Improvements
934
996
  - Add support for more SQL dialects
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "sql-testing-library"
7
- version = "0.10.0"
7
+ version = "0.11.0"
8
8
  description = "A powerful Python framework for unit testing SQL queries across BigQuery, Snowflake, Redshift, Athena, and Trino with mock data"
9
9
  authors = ["Gurmeet Saran <gurmeetx@gmail.com>", "Kushal Thakkar <kushal.thakkar@gmail.com>"]
10
10
  maintainers = ["Gurmeet Saran <gurmeetx@gmail.com>", "Kushal Thakkar <kushal.thakkar@gmail.com>"]
@@ -30,6 +30,32 @@ class SnowflakeTypeConverter(BaseTypeConverter):
30
30
 
31
31
  def convert(self, value: Any, target_type: Type) -> Any:
32
32
  """Convert Snowflake result value to target type."""
33
+ # Handle None/NULL values first
34
+ if value is None:
35
+ return None
36
+
37
+ # Handle Optional types
38
+ if self.is_optional_type(target_type):
39
+ if value is None:
40
+ return None
41
+ target_type = self.get_optional_inner_type(target_type)
42
+
43
+ # Handle dict/map types from Snowflake VARIANT columns
44
+ if hasattr(target_type, "__origin__") and target_type.__origin__ is dict:
45
+ # Snowflake returns VARIANT types as Python dicts already
46
+ if isinstance(value, dict):
47
+ return value
48
+ # If it's a string, parse it
49
+ elif isinstance(value, str):
50
+ import json
51
+
52
+ try:
53
+ return json.loads(value)
54
+ except json.JSONDecodeError:
55
+ return {}
56
+ else:
57
+ return {}
58
+
33
59
  # Snowflake returns proper Python types in most cases, so use base converter
34
60
  return super().convert(value, target_type)
35
61
 
@@ -248,7 +274,11 @@ class SnowflakeAdapter(DatabaseAdapter):
248
274
  if non_none_types:
249
275
  col_type = non_none_types[0]
250
276
 
251
- snowflake_type = type_mapping.get(col_type, "VARCHAR")
277
+ # Handle dict/map types
278
+ if hasattr(col_type, "__origin__") and col_type.__origin__ is dict:
279
+ snowflake_type = "VARIANT"
280
+ else:
281
+ snowflake_type = type_mapping.get(col_type, "VARCHAR")
252
282
  column_defs.append(f'"{col_name}" {snowflake_type}')
253
283
 
254
284
  columns_sql = ",\n ".join(column_defs)
@@ -50,6 +50,17 @@ class TypeConversionError(SQLTestingError):
50
50
  self.value = value
51
51
  self.target_type = target_type
52
52
  self.column_name = column_name
53
- super().__init__(
54
- f"Cannot convert '{value}' to {target_type.__name__} for column '{column_name}'"
55
- )
53
+
54
+ # Handle type name extraction for various type forms
55
+ try:
56
+ type_name = target_type.__name__
57
+ except AttributeError:
58
+ # For types like Optional, Union, etc that don't have __name__
59
+ type_name = str(target_type)
60
+
61
+ if column_name:
62
+ message = f"Cannot convert '{value}' to {type_name} for column '{column_name}'"
63
+ else:
64
+ message = f"Cannot convert '{value}' to {type_name}"
65
+
66
+ super().__init__(message)
@@ -170,6 +170,9 @@ def format_sql_value(value: Any, column_type: Type, dialect: str = "standard") -
170
170
  elif dialect == "bigquery":
171
171
  # BigQuery JSON type handles NULL maps
172
172
  return "NULL"
173
+ elif dialect == "snowflake":
174
+ # Snowflake VARIANT type handles NULL maps
175
+ return "NULL::VARIANT"
173
176
  else:
174
177
  return "NULL"
175
178
 
@@ -298,6 +301,12 @@ def format_sql_value(value: Any, column_type: Type, dialect: str = "standard") -
298
301
  # Escape single quotes in JSON string for SQL
299
302
  json_str = json_str.replace("'", "''")
300
303
  return f"'{json_str}'"
304
+ elif dialect == "snowflake":
305
+ # Snowflake uses VARIANT type with PARSE_JSON function
306
+ json_str = json.dumps(value, cls=DecimalEncoder)
307
+ # Escape single quotes in JSON string for SQL
308
+ json_str = json_str.replace("'", "''")
309
+ return f"PARSE_JSON('{json_str}')"
301
310
  else:
302
311
  # Other databases don't have native map support yet
303
312
  raise NotImplementedError(f"Map type not yet supported for dialect: {dialect}")