From 8b3e5c602e5a5ceeb66cbd1d8f4588b5571bfa8d Mon Sep 17 00:00:00 2001 From: Daniel Frank Date: Sun, 9 Sep 2018 15:02:36 -0700 Subject: [PATCH] add snowflake as sqlalchemy duct protocol (#64) --- omniduct/_version.py | 4 ++++ omniduct/databases/sqlalchemy.py | 7 ++++--- omniduct/duct.py | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/omniduct/_version.py b/omniduct/_version.py index a70a2cf..adb4fe3 100644 --- a/omniduct/_version.py +++ b/omniduct/_version.py @@ -52,6 +52,10 @@ 'pyspark', # Primary client ], + 'snowflake': [ + 'snowflake-sqlalchemy', + ], + # Filesystems 'webhdfs': [ 'pywebhdfs', # Primary client diff --git a/omniduct/databases/sqlalchemy.py b/omniduct/databases/sqlalchemy.py index a2006cc..9eaff1d 100644 --- a/omniduct/databases/sqlalchemy.py +++ b/omniduct/databases/sqlalchemy.py @@ -8,12 +8,12 @@ class SQLAlchemyClient(DatabaseClient, SchemasMixin): - PROTOCOLS = ['sqlalchemy', 'firebird', 'mssql', 'mysql', 'oracle', 'postgresql', 'sybase'] + PROTOCOLS = ['sqlalchemy', 'firebird', 'mssql', 'mysql', 'oracle', 'postgresql', 'sybase', 'snowflake'] NAMESPACE_NAMES = ['database', 'table'] NAMESPACE_QUOTECHAR = '"' # TODO: Apply overrides depending on protocol? NAMESPACE_SEPARATOR = '.' - def _init(self, dialect=None, driver=None, database=''): + def _init(self, dialect=None, driver=None, database='', engine_opts=None): assert self._port is not None, "Omniduct requires SQLAlchemy databases to manually specify a port, as " \ "it will often be the case that ports are being forwarded." @@ -27,6 +27,7 @@ def _init(self, dialect=None, driver=None, database=''): self.driver = driver self.database = database self.connection_fields += ('schema',) + self.engine_opts = engine_opts or {} self.engine = None self.connection = None @@ -43,7 +44,7 @@ def db_uri(self): def _connect(self): import sqlalchemy - self.engine = sqlalchemy.create_engine(self.db_uri) + self.engine = sqlalchemy.create_engine(self.db_uri, **self.engine_opts) self._sqlalchemy_metadata = sqlalchemy.MetaData(self.engine) def _is_connected(self): diff --git a/omniduct/duct.py b/omniduct/duct.py index f683554..ad6c6be 100644 --- a/omniduct/duct.py +++ b/omniduct/duct.py @@ -237,13 +237,13 @@ class Duct(with_metaclass(ProtocolRegisteringQuirkDocumentedABCMeta, object)): class Type(Enum): """ The `Duct.Type` enum specifies all of the permissible values of - `Duct.DUCT_TYPE`. + `Duct.DUCT_TYPE`. Also determines the order in which ducts are loaded by DuctRegistry. """ REMOTE = 'remotes' FILESYSTEM = 'filesystems' - DATABASE = 'databases' CACHE = 'caches' RESTFUL = 'rest_clients' + DATABASE = 'databases' OTHER = 'other' AUTO_LOGGING_SCOPE = True @@ -405,6 +405,7 @@ def _prepare(self): and '_password'. - Ensures value of self.port is an integer (or None). """ + # Import necessary classes lazily (to prevent dependency cycles) from omniduct.registry import DuctRegistry from omniduct.caches.base import Cache