@@ -448,78 +448,69 @@ def supports_key(self, key: str) -> bool:
448448 return False
449449
450450
451- class CliEnvironment (ValueSource ):
451+ # Base configuration keys that can be set via environment
452+ _ENV_CONFIG_KEYS = [
453+ "account" ,
454+ "user" ,
455+ "password" ,
456+ "database" ,
457+ "schema" ,
458+ "role" ,
459+ "warehouse" ,
460+ "protocol" ,
461+ "host" ,
462+ "port" ,
463+ "region" ,
464+ "authenticator" ,
465+ "workload_identity_provider" ,
466+ "private_key_file" ,
467+ "private_key_path" , # Used by integration tests
468+ "private_key_raw" , # Used by integration tests
469+ "private_key_passphrase" , # Private key passphrase for encrypted keys
470+ "token" , # OAuth token
471+ "session_token" , # Session token for session-based authentication
472+ "master_token" , # Master token for advanced authentication
473+ "token_file_path" ,
474+ "oauth_client_id" ,
475+ "oauth_client_secret" ,
476+ "oauth_authorization_url" ,
477+ "oauth_token_request_url" ,
478+ "oauth_redirect_uri" ,
479+ "oauth_scope" ,
480+ "oauth_enable_pkce" , # Fixed typo: was "oatuh_enable_pkce"
481+ "oauth_enable_refresh_tokens" ,
482+ "oauth_enable_single_use_refresh_tokens" ,
483+ "client_store_temporary_credential" ,
484+ ]
485+
486+
487+ class ConnectionSpecificEnvironment (ValueSource ):
452488 """
453- CLI environment variables source.
454-
455- Discovers SNOWFLAKE_* environment variables with two patterns:
456- 1. General: SNOWFLAKE_ACCOUNT (applies to all connections)
457- 2. Connection-specific: SNOWFLAKE_CONNECTIONS_<name>_ACCOUNT (overrides general)
489+ Connection-specific environment variables source.
458490
459- Connection-specific variables take precedence within this source.
491+ Discovers SNOWFLAKE_CONNECTIONS_<name>_<key> environment variables.
492+ Returns prefixed keys: connections.{name}.{key}
460493
461494 Examples:
462- SNOWFLAKE_ACCOUNT -> account (general)
463- SNOWFLAKE_CONNECTIONS_INTEGRATION_ACCOUNT -> account (for "integration" connection)
464- SNOWFLAKE_USER -> user
465- SNOWFLAKE_CONNECTIONS_DEV_USER -> user (for "dev" connection)
495+ SNOWFLAKE_CONNECTIONS_INTEGRATION_ACCOUNT=x -> connections.integration.account=x
496+ SNOWFLAKE_CONNECTIONS_DEV_USER=y -> connections.dev.user=y
466497 """
467498
468- # Base configuration keys that can be set via environment
469- CONFIG_KEYS = [
470- "account" ,
471- "user" ,
472- "password" ,
473- "database" ,
474- "schema" ,
475- "role" ,
476- "warehouse" ,
477- "protocol" ,
478- "host" ,
479- "port" ,
480- "region" ,
481- "authenticator" ,
482- "workload_identity_provider" ,
483- "private_key_file" ,
484- "private_key_path" , # Used by integration tests
485- "private_key_raw" , # Used by integration tests
486- "private_key_passphrase" , # Private key passphrase for encrypted keys
487- "token" , # OAuth token
488- "session_token" , # Session token for session-based authentication
489- "master_token" , # Master token for advanced authentication
490- "token_file_path" ,
491- "oauth_client_id" ,
492- "oauth_client_secret" ,
493- "oauth_authorization_url" ,
494- "oauth_token_request_url" ,
495- "oauth_redirect_uri" ,
496- "oauth_scope" ,
497- "oauth_enable_pkce" , # Fixed typo: was "oatuh_enable_pkce"
498- "oauth_enable_refresh_tokens" ,
499- "oauth_enable_single_use_refresh_tokens" ,
500- "client_store_temporary_credential" ,
501- ]
502-
503499 @property
504500 def source_name (self ) -> str :
505- return "cli_env "
501+ return "connection_specific_env "
506502
507503 def discover (self , key : Optional [str ] = None ) -> Dict [str , ConfigValue ]:
508504 """
509- Discover SNOWFLAKE_ * environment variables.
510- Returns both general (flat) and connection-specific (prefixed) keys.
505+ Discover SNOWFLAKE_CONNECTIONS_ * environment variables.
506+ Returns connection-specific (prefixed) keys only .
511507
512- Patterns:
513- 1. SNOWFLAKE_ACCOUNT=x -> account=x (flat key)
514- 2. SNOWFLAKE_CONNECTIONS_INTEGRATION_ACCOUNT=y -> connections.integration.account=y
508+ Pattern: SNOWFLAKE_CONNECTIONS_<NAME>_<KEY>=value -> connections.{name}.{key}=value
515509 """
516510 values : Dict [str , ConfigValue ] = {}
517511
518512 # Scan all environment variables
519513 for env_name , env_value in os .environ .items ():
520- if not env_name .startswith ("SNOWFLAKE_" ):
521- continue
522-
523514 # Check for connection-specific pattern: SNOWFLAKE_CONNECTIONS_<NAME>_<KEY>
524515 if env_name .startswith ("SNOWFLAKE_CONNECTIONS_" ):
525516 # Extract connection name and config key
@@ -530,7 +521,7 @@ def discover(self, key: Optional[str] = None) -> Dict[str, ConfigValue]:
530521 conn_name = conn_name_upper .lower ()
531522 config_key = config_key_upper .lower ()
532523
533- if config_key in self . CONFIG_KEYS :
524+ if config_key in _ENV_CONFIG_KEYS :
534525 full_key = f"connections.{ conn_name } .{ config_key } "
535526 if key is None or full_key == key :
536527 values [full_key ] = ConfigValue (
@@ -540,40 +531,79 @@ def discover(self, key: Optional[str] = None) -> Dict[str, ConfigValue]:
540531 raw_value = f"{ env_name } ={ env_value } " ,
541532 )
542533
534+ return values
535+
536+ def supports_key (self , key : str ) -> bool :
537+ # Check if key matches pattern connections.{name}.{param}
538+ if key .startswith ("connections." ):
539+ parts = key .split ("." , 2 )
540+ if len (parts ) == 3 :
541+ _ , conn_name , config_key = parts
542+ env_var = (
543+ f"SNOWFLAKE_CONNECTIONS_{ conn_name .upper ()} _{ config_key .upper ()} "
544+ )
545+ return os .getenv (env_var ) is not None
546+ return False
547+
548+
549+ class CliEnvironment (ValueSource ):
550+ """
551+ CLI general environment variables source.
552+
553+ Discovers general SNOWFLAKE_* environment variables (not connection-specific).
554+ Returns flat keys that apply to all connections.
555+
556+ Examples:
557+ SNOWFLAKE_ACCOUNT -> account (general, applies to all connections)
558+ SNOWFLAKE_USER -> user
559+ SNOWFLAKE_PASSWORD -> password
560+ """
561+
562+ @property
563+ def source_name (self ) -> str :
564+ return "cli_env"
565+
566+ def discover (self , key : Optional [str ] = None ) -> Dict [str , ConfigValue ]:
567+ """
568+ Discover general SNOWFLAKE_* environment variables.
569+ Returns general (flat) keys only.
570+
571+ Pattern: SNOWFLAKE_<KEY>=value -> {key}=value
572+ """
573+ values : Dict [str , ConfigValue ] = {}
574+
575+ # Scan all environment variables
576+ for env_name , env_value in os .environ .items ():
577+ if not env_name .startswith ("SNOWFLAKE_" ):
578+ continue
579+
580+ # Skip connection-specific variables
581+ if env_name .startswith ("SNOWFLAKE_CONNECTIONS_" ):
582+ continue
583+
543584 # Check for general pattern: SNOWFLAKE_<KEY>
544- elif not env_name .startswith ("SNOWFLAKE_CONNECTIONS_" ):
545- config_key_upper = env_name [len ("SNOWFLAKE_" ) :]
546- config_key = config_key_upper .lower ()
547-
548- if config_key in self .CONFIG_KEYS :
549- if key is None or config_key == key :
550- values [config_key ] = ConfigValue (
551- key = config_key ,
552- value = env_value ,
553- source_name = self .source_name ,
554- raw_value = f"{ env_name } ={ env_value } " ,
555- )
585+ config_key_upper = env_name [len ("SNOWFLAKE_" ) :]
586+ config_key = config_key_upper .lower ()
587+
588+ if config_key in _ENV_CONFIG_KEYS :
589+ if key is None or config_key == key :
590+ values [config_key ] = ConfigValue (
591+ key = config_key ,
592+ value = env_value ,
593+ source_name = self .source_name ,
594+ raw_value = f"{ env_name } ={ env_value } " ,
595+ )
556596
557597 return values
558598
559599 def supports_key (self , key : str ) -> bool :
560- discovered = self .discover ()
561- if key in discovered :
562- return True
563-
564- # Check general var
565- if os .getenv (f"SNOWFLAKE_{ key .upper ()} " ) is not None :
566- return True
567-
568- # Check connection-specific var
569- if hasattr (self , "_connection_name" ) and self ._connection_name :
570- conn_var = (
571- f"SNOWFLAKE_CONNECTIONS_{ self ._connection_name .upper ()} _{ key .upper ()} "
572- )
573- if os .getenv (conn_var ) is not None :
574- return True
600+ # Only support flat keys (not prefixed with connections.)
601+ if "." in key :
602+ return False
575603
576- return False
604+ # Check if the general env var exists
605+ env_var = f"SNOWFLAKE_{ key .upper ()} "
606+ return os .getenv (env_var ) is not None
577607
578608
579609class CliParameters (ValueSource ):
0 commit comments