qgis-snowflake-plugin

star 10

Architecture and contributor guide for the QGIS Snowflake Connector plugin. Use when adding features, fixing bugs, writing tests, understanding data flow, or troubleshooting the plugin. Covers connection management, data providers, H3/geography handling, the export algorithm, UI dialogs, and packaging.

snowflakedb By snowflakedb schedule Updated 4/22/2026

name: qgis-snowflake-plugin description: Architecture and contributor guide for the QGIS Snowflake Connector plugin. Use when adding features, fixing bugs, writing tests, understanding data flow, or troubleshooting the plugin. Covers connection management, data providers, H3/geography handling, the export algorithm, UI dialogs, and packaging.

QGIS Snowflake Connector -- Contributor Skill

Repository Layout

__init__.py                          # classFactory entry point, dependency checks
qgis_snowflake_connector.py          # Plugin class (initGui / unload / update check)
qgis_snowflake_connector_algorithm.py # "Export to Snowflake" processing algorithm
qgis_snowflake_connector_provider.py  # Processing provider registration

managers/
  sf_connection_manager.py           # Singleton Snowflake connection pool

providers/
  sf_vector_data_provider.py         # Core data provider (fields, features, extent)
  sf_feature_iterator.py             # Feature fetching + H3 polygon conversion
  sf_feature_source.py               # Feature source wrapper
  sf_data_source_provider.py         # Thin query executor for algorithms
  sf_data_item_provider.py           # Browser panel provider
  sf_source_select_provider.py       # Data Source Manager integration
  sf_metadata_provider.py            # Provider metadata (encodeUri/decodeUri)

entities/
  sf_data_item.py                    # Browser tree items (connections/schemas/tables)

helpers/
  sql.py          # quote_identifier, quote_literal, qualified_table_name
  utils.py        # Settings, auth, URI parsing, dependency install
  mappings.py     # Snowflake type -> QMetaType/QgsWkbTypes maps
  limits.py       # Row-fetch limits (DEFAULT_ROW_LIMIT, H3_ROW_LIMIT)
  data_base.py    # Schema/table DDL helpers, INFORMATION_SCHEMA queries
  layer_creation.py # Build QgsVectorLayer from query results
  wrapper.py      # parse_uri (delegates to provider metadata)
  messages.py     # UI message boxes

dialogs/
  sf_connection_string_dialog.py     # Connection settings (auth, key pair, SSO)
  sf_data_source_manager_widget.py   # Data Source Manager tab
  sf_sql_query_dialog.py             # SQL query execution dialog
  sf_new_table_dialog.py / sf_new_schema_dialog.py

tasks/
  sf_connect_task.py                 # Background connection task
  sf_convert_column_to_layer_task.py # Column -> map layer
  sf_convert_sql_query_to_layer_task.py
  sf_execute_sql_query_task.py

ui/    # Generated PyQt .py/.ui files (do NOT hand-edit .py files)
test/  # Regression tests (see testing section below)

Key Concepts

URI Format

Every Snowflake layer is identified by a URI string with space-separated key=value pairs:

connection_name=MyConn schema_name=PUBLIC table_name=CITIES
srid=4326 geom_column=GEOM geometry_type=Point
geo_column_type=GEOGRAPHY primary_key=ID

Parsed by helpers/wrapper.py:parse_uri() and helpers/utils.py:decodeUri().

Geometry Column Types (geo_column_type)

Value Meaning Provider subclass
GEOGRAPHY Snowflake native geography (WGS84) SFGeoVectorDataProvider
GEOMETRY Snowflake native geometry (any SRID) SFGeoVectorDataProvider
NUMBER H3 cell index stored as integer SFH3VectorDataProvider
TEXT H3 cell index stored as hex string SFH3VectorDataProvider

The factory method SFVectorDataProvider.createProvider() dispatches based on geo_column_type.

H3 Architecture (TEXT-normalized)

H3 is handled entirely via Snowflake server-side functions. The Python h3 package is not a dependency.

Normalization: NUMBER H3 columns are converted to hex strings via H3_INT_TO_STRING() in the feature iterator SELECT. Internally, the plugin always works with TEXT (hex string) H3 values. This avoids float precision loss (64-bit int → 53-bit Double) and eliminates NUMBER/TEXT branching.

Rendering: ST_ASWKB(H3_CELL_TO_BOUNDARY(col)) returns WKB polygons from Snowflake. The standard geometry.fromWkb() path is used — no special H3 branch.

Export: H3 layers always create a TEXT column. Values are always quoted with quote_literal().

Detection: filter_geo_columns() checks INFORMATION_SCHEMA.COLUMNS for NUMBER/TEXT columns with "h3" in the COMMENT, then validates with H3_IS_VALID_CELL(). The SQL query task always sets geo_column_type="TEXT" for H3.

Type Mappings

helpers/mappings.py defines two key dicts:

  • mapping_snowflake_qgis_type -- Snowflake SQL type name -> QMetaType.Type
  • SNOWFLAKE_METADATA_TYPE_CODE_DICT -- Snowflake type code (int) -> QMetaType

NUMBER maps to Double, TEXT/VARCHAR to QString. Be aware that H3 cell indices stored as NUMBER lose precision when converted to float (53-bit mantissa vs 64-bit int).

Data Flow Details

For deep dives into specific subsystems, see the companion files:

Testing

Tests live in test/test_issue_regressions.py. They use source-file assertions (no Snowflake connection needed):

python -c "
import sys, types
qgis = types.ModuleType('qgis')
sys.modules['qgis'] = qgis
import unittest
loader = unittest.TestLoader()
suite = loader.discover('test', pattern='test_issue_regressions.py', top_level_dir='.')
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
sys.exit(0 if result.wasSuccessful() else 1)
"

The qgis module must be stubbed because the test environment has no QGIS runtime.

Packaging

Build the installable zip (must have a root folder matching the plugin directory name):

rm -rf /tmp/build && mkdir -p /tmp/build/qgis-snowflake-connector
rsync -a --exclude='__pycache__' --exclude='*.pyc' --exclude='.DS_Store' \
  __init__.py metadata.txt icon.png favicon-32x32.webp \
  qgis_snowflake_connector.py qgis_snowflake_connector_algorithm.py \
  qgis_snowflake_connector_provider.py \
  helpers managers providers entities enums dialogs ui assets tasks scripts help \
  /tmp/build/qgis-snowflake-connector/
cd /tmp/build && zip -r output.zip qgis-snowflake-connector/

Common packaging mistakes:

  • Missing root folder -> "No root folder was found inside"
  • Missing tasks/ or other directories -> ImportError on load
  • Trailing / on rsync directory args flattens structure

SQL Safety

All identifiers must use quote_identifier(), all literals must use quote_literal(). Both are in helpers/sql.py. Use qualified_table_name(db, schema, table) for fully-qualified references. Never use f-string interpolation for user-supplied names without quoting.

Install via CLI
npx skills add https://github.com/snowflakedb/qgis-snowflake-connector --skill qgis-snowflake-plugin
Repository Details
star Stars 10
call_split Forks 5
navigation Branch main
article Path SKILL.md
More from Creator