(usage/snowmobile)= # Snowmobile
snowmobile.core.connection An instance of {class}`~snowmobile.Snowmobile`, , represents a distinct [session](https://docs.snowflake.com/en/sql-reference/functions/current_session.html) along with the contents of the [snowmobile.toml](./snowmobile_toml.md#snowmobiletoml) with which it was instantiated. ```{div} sn-dedent-v-t-h, sn-dedent-v-b-h Its purpose is to provide an entry point that will: ``` 1. Locate, parse, and instantiate [snowmobile.toml](./snowmobile_toml.md#snowmobiletoml) as a {class}`~snowmobile.Configuration` object, {attr}`sn.cfg ` 1. Establish connections to {xref}`snowflake` 1. Store the {xref}`SnowflakeConnection`, {attr}`sn.con `, and execute commands against the database +++


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (snowmobile/usage)= ## Usage ```{div} sn-dedent-list, sn-depth1 - [Connecting](usage/snowmobile/connecting) - [Executing Raw SQL](usage/snowmobile/executing) - [Aliasing Credentials](usage/snowmobile/aliasing-credentials) - [Parameter Resolution](usage/snowmobile/parameter-resolution) - [Delaying Connection](usage/snowmobile/delaying-connection) - [Specifying snowmobile.toml](usage/snowmobile/specifying-snowmobiletoml) - [Using *ensure_alive*](usage/snowmobile/using-ensure-alive) ```
````{admonition} Setup :class: toggle, todo, is-setup, toggle-shown, toggle-color-setup (connector/usage/setup)= **This section assumes the following about the contents of** [**snowmobile.toml**](./snowmobile_toml.md#snowmobiletoml): 1. {ref}`[connection.credentials.creds1] ` and {ref}`[connection.credentials.creds2]` are: 1. Populated with valid credentials 1. The first and second credentials stored respectively 1. Aliased as *creds1* and *creds2* respectively 1. {ref}`default-creds` has been left blank ```` +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (usage/snowmobile/connecting)= ### Connecting to {xref}`snowflake`
``````{div} sn-tabbed-section `````{tabbed}   ````{div} sn-pre-code-s, sn-dedent-v-t-container ```{div} sn-dedent-v-t-container-neg2 Establishing a connection can be done with: ``` ```` ```{literalinclude} ../snippets/snowmobile/connecting.py :language: python :lines: 4-6 ``` ```{div} sn-pre-code-s Here's some basic information on the composition of `sn`: ``` ```{literalinclude} ../snippets/snowmobile/connecting.py :language: python :lines: 8-10 ```
````{div} sn-pre-code-s Given [{fa}`cog`](connector/usage/setup), `sn` is implicitly using the same connection arguments as: ```` ```{literalinclude} ../snippets/snowmobile/connecting.py :language: python :lines: 12-12 ``` ```{div} sn-pre-code-s Here's some context on how to think about these two instances of {class}`~snowmobile.core.Snowmobile`: ``` ```{literalinclude} ../snippets/snowmobile/connecting.py :language: python :lines: 14-16 ``` ```{div} sn-snippet [{fa}`file-code-o` connecting.py](../snippets.md#connectingpy) ``` ````` ```````
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (usage/snowmobile/executing)= ### Executing Raw SQL
````````{div} sn-tabbed-section ``````{tabbed}   ```{div} sn-dedent-v-b-container-neg2 *The following three methods are available for statement execution directly off* . ``` `````{tabbed} sn.query() ````{div} sn-rm-code-margin ```{literalinclude} ../snippets/snowmobile/executing.py :language: python :lines: 9-10 ``` ```` ````` ````{tabbed} + {meth}`~snowmobile.core.connection.Snowmobile.query()` implements {meth}`pandas.read_sql` for querying results into a {class}`pandas.DataFrame`. ```{literalinclude} ../snippets/snowmobile/executing.py :language: python :lines: 9-17 :emphasize-lines: 4-10 ```
```` ````{tabbed} sn.ex() :new-group: ```{literalinclude} ../snippets/snowmobile/executing.py :language: python :lines: 21-22 ``` ```` ````{tabbed} + {meth}`~snowmobile.core.connection.Snowmobile.ex()` implements {meth}`SnowflakeConnection.cursor().execute()` for executing commands within a {xref}`SnowflakeCursor`. ```{literalinclude} ../snippets/snowmobile/executing.py :language: python :lines: 21-27 :emphasize-lines: 4-8 ```
```` ````{tabbed} sn.exd() :new-group: ```{literalinclude} ../snippets/snowmobile/executing.py :language: python :lines: 31-32 ``` ```` ````{tabbed} + {meth}`~snowmobile.core.connection.Snowmobile.exd()` implements {meth}`SnowflakeConnection.cursor(DictCursor).execute()` for executing commands within {xref}`DictCursor`. ```{literalinclude} ../snippets/snowmobile/executing.py :language: python :lines: 31-39 :emphasize-lines: 4-10 ```
```` ```{div} sn-snippet-trunc [{fa}`file-code-o` executing.py](../snippets.md#executingpy) ```   `````{admonition} SnowflakeCursor / DictCursor :class: note, toggle, toggle-shown, sn-indent-cell, sn-indent-h-sub-cell-right ````{tabbed} Note The accessors `sn.cursor` and `sn.dictcursor` are **properties** of {attr}`~snowmobile.Snowmobile` that return a new instance each time they are accessed. Depending on the intended use of {xref}`SnowflakeCursor` or {xref}`DictCursor`, it could be better to store an instance for re-referencing as opposed to repeatedly instantiating new instances off `sn`. ```` ````{tabbed} + The below demonstrates the difference between calling two methods on the {attr}`~snowmobile.Snowmobile.cursor` property compared to on the same instance of {xref}`SnowflakeCursor`. ```{literalinclude} ../snippets/snowmobile/connector_cursor_note.py :language: python :lines: 5-17 ``` ```{div} sn-snippet [{fa}`file-code-o` connector_cursor_note.py](../snippets.md#connector_cursor_notepy) ``` ```` `````   `````` ```````` +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`````{admonition} Naming Convention :class: tip, toggle, toggle-shown ````{tabbed} Tip The following convention of variable/attribute name to associated object is used throughout {ref}`snowmobile`'s documentation and source code, including in method signatures: - **`sn`**: {class}`snowmobile.Snowmobile` - **`cfg`**: {class}`snowmobile.Configuration` - **`con`**: {xref}`snowflake.connector.SnowflakeConnection` - **`cursor`**: {xref}`snowflake.connector.cursor.SnowflakeCursor` ```` ````{tabbed} + ```{div} sn-pre-code-s For example, see the below attributes of {class}`~snowmobile.core.Snowmobile`: ``` ```{literalinclude} ../snippets/snowmobile/inspect_connector.py :language: python :lines: 5-15 ``` ```{div} sn-snippet-hanging [{fa}`file-code-o` inspect_connector.py](../snippets.md#inspect_connectorpy) ```
```` `````
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (usage/snowmobile/aliasing-credentials)= ### Aliasing Credentials
````````{div} sn-tabbed-section ``````{tabbed}   The [default snowmobile.toml](./snowmobile_toml.md#file-contents) contains scaffolding for two sets of credentials, aliased `creds1` and `creds2` respectively. By changing `default-creds = ''` to `default-creds = 'creds2'`, [Snowmobile](/usage/snowmobile) will use the credentials from `creds2` regardless of where it falls relative to all the other credentials stored. ```{div} sn-pre-code-s The change can be verified with: ``` ```{literalinclude} ../snippets/snowmobile/verify_default_alias_change.py :language: python :lines: 5-11 ``` ```{div} sn-snippet [{fa}`file-code-o` verify_default_alias_change.py](../snippets.md#verify_default_alias_changepy) ``` `````` ````````
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (usage/snowmobile/parameter-resolution)= ### Parameter Resolution
````````{div} sn-tabbed-section ```````{tabbed} - ```{div} sn-hanging-p will look in the following three places to compile the connection arguments that it passes to {xref}`snowflake.connector.connect()` when establishing a connection: ``` 1. {ref}`[connection.default-arguments]` 1. {ref}`[connection.credentials.alias_name]` 1. Keyword arguments passed to {meth}`snowmobile.connect()`

```{div} sn-dedent-v-b-h If the same argument is defined in more than one entry point, the **last** value found will take precedent; the purpose of this resolution order is to enable: ``` - Embedding connection arguments (e.g. timezone or transaction mode) within an aliased credentials block whose **values** differ from defaults specified in {ref}`[connection.default-arguments]` - Superseding any connection parameters configured in [](./snowmobile_toml.md) with keyword arguments passed directly to {meth}`snowmobile.connect()`   ``````` ```````{tabbed} Details The way implements resolving connection parameters from multiple entry points is outlined below.
```{div} sn-pre-code-s The {ref}`[connection.default-arguments]` and {ref}`[connection.credentials.alias_name]` are merged as the {attr}`~snowmobile.core.cfg.connection.Connection.connect_kwargs` property of {attr}`~snowmobile.core.cfg.connection.Connection` with: ``` ```{code-block} python :emphasize-lines: 4,4 @property def connect_kwargs(self) -> Dict: """Arguments from snowmobile.toml for `snowflake.connector.connect()`.""" return {**self.defaults, **self.current.credentials} ``` +++ ```{div} sn-post-code, sn-pre-code-s {attr}`~snowmobile.core.cfg.connection.Connection.connect_kwargs` is then combined with keyword arguments passed to {meth}`snowmobile.connect()` within the method itself as the {attr}`~snowmobile.Snowmobile.con` attribute of is being set: ``` ```{code-block} python :emphasize-lines: 8-9 def connect(self, **kwargs) -> Snowmobile: """Establishes connection to Snowflake. ... """ try: self.con = connect( **{ **self.cfg.connection.connect_kwargs, # snowmobile.toml **kwargs, # any kwarg over-rides } ) self.sql = sql.SQL(sn=self) print(f"..connected: {str(self)}") return self except DatabaseError as e: raise e ``` ``````` ````````
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (usage/snowmobile/delaying-connection)= ### Delaying Connection
````````{div} sn-tabbed-section ```````{tabbed} - ```{div} sn-hanging-p Sometimes it's helpful to create a {class}`~snowmobile.Snowmobile` without establishing a connection; this is accomplished with: ``` ```{code-block} python :emphasize-lines: 3,3 import snowmobile sn = snowmobile.connect(delay=True) ``` When provided with `delay=True`, the that's returned omits connecting to {xref}`snowflake` upon its instantiation; its {attr}`~snowmobile.Snowmobile.con` attribute is *None*, but its {attr}`~snowmobile.Snowmobile.cfg` attribute is a fully valid {class}`~snowmobile.core.configuration.Configuration` object. See the tabbed *Examples* for more info.   ``````` ```````{tabbed} Example: Implicit Connection (delaying-connection-example)= When provided with `delay=True`, the {attr}`~snowmobile.Snowmobile.con` attribute of will be *None* until a method is called on it that requires a connection. If such a method is invoked, a call is made by to {xref}`snowflake.connector.connect()`, a connection established, and the attribute set. ```{literalinclude} ../snippets/snowmobile/connector_delayed1.py :language: python :lines: 5-15 ``` ```{div} sn-snippet [{fa}`file-code-o` connector_delayed1.py](../snippets.md#connector_delayed1py) ``` ``````` ```````{tabbed} Example: Explicit Connection In addition to implictly connecting by executing a query, the {meth}`~snowmobile.connect()` method can be called on an existing instance of ; this will establish an initial connection if was created with `delay=True` or a new session with the existing connection arguments otherwise. ```{literalinclude} ../snippets/snowmobile/connector_delayed2.py :language: python :lines: 5-21 ``` ```{div} sn-snippet [{fa}`file-code-o` connector_delayed2.py](../snippets.md#connector_delayed2py) ``` ``````` ````````
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (usage/snowmobile/specifying-snowmobiletoml)= ### Specifying [snowmobile.toml](./snowmobile_toml.md)
````````{div} sn-tabbed-section ```````{tabbed} From File Path A full path ({class}`pathlib.Path` or {class}`str`) to a [snowmobile.toml](./snowmobile_toml.md) file can be provided to the `from_config` parameter to instantiate from a specific configuration file. ```{div} sn-pre-code-s In practice, this looks like: ``` ```{literalinclude} ../snippets/snowmobile/specifying_configuration.py :language: python :lines: 5-11 :emphasize-lines: 7,7 ``` ```{div} sn-snippet [{fa}`file-code-o` specifying_configuration.py](../snippets.md#specifying_configurationpy) ``` ```{div} sn-hanging-p This will bypass any checks for a cached path and is useful for: ``` 1. Testing different sets of configuration options without altering the original [snowmobile.toml](./snowmobile_toml.md) file 1. Binding a specific configuration with a process for sql-parsing purposes 1. Hard coding the configuration source in processes that have access to limited file systems (e.g. containers or VMs)   ``````` ```````{tabbed} From File Name [Snowmobile](#snowmobile) caches locations based on the file **name** provided to the `config_file_nm` parameter of {meth}`snowmobile.connect()`, the default value of which is `snowmobile.toml`. If an alternate file name is provided, it will be located and its location cached in the same way as the global [snowmobile.toml](./snowmobile_toml.md) file so that future instances of on the same machine can make use of it upon instantiation without having to re-locate it.

(specifying_configuration/setup)= The below codes are a contrived example demonstrating this behavior in practice. ````{admonition} Setup :class: todo, is-setup, toggle-shown, toggle, sn-dedent-v-t-container All code blocks in this example are from [the same code file](../snippets.md#specifying_configuration2py), assumed to be executed in full starting with code directly below in which a second configuration file called *snowmobile2.toml* is created in the same folder as the global [*snowmobile.toml*](./snowmobile_toml.md) file. ```{literalinclude} ../snippets/snowmobile/specifying_configuration2.py :language: python :lines: 7-17 ```
```` ```{div} sn-hanging-p Below, {any}`alt_sn()` is used to create `sn_alt1` and `sn_alt2`, representing an initial and future instance of respectively: ``` ```{literalinclude} ../snippets/snowmobile/specifying_configuration2.py :language: python :lines: 22-39 :emphasize-lines: 12-13 ```
Cleanup is done with the following two lines which remove the *snowmobile2.toml* file created during the [{fa}`cog`](specifying_configuration/setup) for this example: ```{literalinclude} ../snippets/snowmobile/specifying_configuration2.py :language: python :lines: 45-46 ``` ```{div} sn-snippet [{fa}`file-code-o` specifying_configuration2.py](../snippets.md#specifying_configuration2py) ``` ``````` ````````
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (usage/snowmobile/using-ensure-alive)= ### Using ensure_alive
````````{div} sn-tabbed-section ```````{tabbed}   Controlling the behavior of {class}`~snowmobile.Snowmobile` when a connection is lost or intentionally killed is done through the {attr}`~snowmobile.Snowmobile.ensure_alive` parameter. Its default value is *True,* meaning that if the {attr}`~snowmobile.Snowmobile.alive` property evaluates to *False*, **and a method is invoked that requires a connection,** it will re-connect to {xref}`snowflake` before continuing execution. ```{admonition} Note :class: note, sn-dedent-v-container, sn-indent-cell, sn-indent-h-sub-cell-right A re-established connection will not be on the same session as the original connection. See [this snippet](../snippets.md#ensure_alivepy) for additional details. ``` ```````
````````