]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
De-emphasize notion of "default driver" (DBAPI)
authorGord Thompson <gord@gordthompson.com>
Mon, 8 Nov 2021 18:03:54 +0000 (11:03 -0700)
committerGord Thompson <gord@gordthompson.com>
Tue, 9 Nov 2021 13:12:39 +0000 (06:12 -0700)
Fixes: #6960
Even though a default driver still exists for
each dialect, remove most usages of `dialect://`
to encourage users to explicitly specify
`dialect+driver://`

Change-Id: I0ad42167582df509138fca64996bbb53e379b1af

42 files changed:
README.unittests.rst
doc/build/changelog/migration_20.rst
doc/build/core/connections.rst
doc/build/core/custom_types.rst
doc/build/core/engines.rst
doc/build/core/event.rst
doc/build/core/pooling.rst
doc/build/core/reflection.rst
doc/build/errors.rst
doc/build/faq/connections.rst
doc/build/faq/metadata_schema.rst
doc/build/glossary.rst
doc/build/orm/declarative_tables.rst
doc/build/orm/persistence_techniques.rst
doc/build/orm/session_basics.rst
doc/build/orm/session_transaction.rst
examples/large_collection/large_collection.py
examples/materialized_paths/materialized_paths.py
examples/postgis/postgis.py
lib/sqlalchemy/dialects/mysql/base.py
lib/sqlalchemy/dialects/oracle/base.py
lib/sqlalchemy/dialects/oracle/cx_oracle.py
lib/sqlalchemy/dialects/postgresql/base.py
lib/sqlalchemy/dialects/postgresql/json.py
lib/sqlalchemy/engine/base.py
lib/sqlalchemy/engine/create.py
lib/sqlalchemy/engine/events.py
lib/sqlalchemy/engine/mock.py
lib/sqlalchemy/engine/url.py
lib/sqlalchemy/orm/session.py
lib/sqlalchemy/pool/events.py
lib/sqlalchemy/sql/schema.py
setup.cfg
test/dialect/mssql/test_deprecations.py
test/dialect/mssql/test_engine.py
test/dialect/mysql/test_dialect.py
test/dialect/postgresql/test_dialect.py
test/engine/test_deprecations.py
test/engine/test_execute.py
test/engine/test_parseconnect.py
test/engine/test_reconnect.py
test/sql/test_deprecations.py

index 37238b7a1e1f67bc739ce4611019d079028a13e0..32b7446123875cf8113c93e365ea80557a905d5e 100644 (file)
@@ -83,17 +83,29 @@ a pre-set URL.  These can be seen using --dbs::
 
     $ pytest --dbs
     Available --db options (use --dburi to override)
+                aiomysql    mysql+aiomysql://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
+       aiomysql_fallback    mysql+aiomysql://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4&async_fallback=true
+               aiosqlite    sqlite+aiosqlite:///:memory:
+          aiosqlite_file    sqlite+aiosqlite:///async_querytest.db
+                 asyncmy    mysql+asyncmy://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
+        asyncmy_fallback    mysql+asyncmy://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4&async_fallback=true
+                 asyncpg    postgresql+asyncpg://scott:tiger@192.168.0.199/test
+    asyncpg_async_fallback  postgresql+asyncpg://scott:tiger@192.168.0.199/test?async_fallback=true
+        asyncpg_fallback    postgresql+asyncpg://scott:tiger@127.0.0.1:5432/test?async_fallback=true
                  default    sqlite:///:memory:
-                 mariadb    mariadb://scott:tiger@192.168.0.199:3307/test
-                   mssql    mssql+pyodbc://scott:tiger^5HHH@mssql2017:1433/test?driver=ODBC+Driver+13+for+SQL+Server
+            docker_mssql    mssql+pymssql://scott:tiger^5HHH@127.0.0.1:1433/test
+                 mariadb    mariadb+mysqldb://scott:tiger@127.0.0.1:3306/test
+                   mssql    mssql+pyodbc://scott:tiger^5HHH@localhost:1433/test?driver=ODBC+Driver+17+for+SQL+Server
+               mssql_199    mssql+pyodbc://scott:tiger^5HHH@192.168.0.199:1433/test?driver=ODBC+Driver+17+for+SQL+Server
            mssql_pymssql    mssql+pymssql://scott:tiger@ms_2008
-                   mysql    mysql://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
-                  oracle    oracle://scott:tiger@127.0.0.1:1521
-                 oracle8    oracle://scott:tiger@127.0.0.1:1521/?use_ansi=0
+                   mysql    mysql+mysqldb://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
+                  oracle    oracle+cx_oracle://scott:tiger@127.0.0.1:1521
+                 oracle8    oracle+cx_oracle://scott:tiger@127.0.0.1:1521/?use_ansi=0
                   pg8000    postgresql+pg8000://scott:tiger@127.0.0.1:5432/test
-              postgresql    postgresql://scott:tiger@127.0.0.1:5432/test
+              postgresql    postgresql+psycopg2://scott:tiger@192.168.0.199/test
     postgresql_psycopg2cffi postgresql+psycopg2cffi://scott:tiger@127.0.0.1:5432/test
                  pymysql    mysql+pymysql://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
+        pysqlcipher_file    sqlite+pysqlcipher://:test@/querytest.db.enc
                   sqlite    sqlite:///:memory:
              sqlite_file    sqlite:///querytest.db
 
@@ -110,7 +122,7 @@ creating a new file called ``test.cfg`` and adding your own ``[db]`` section::
 
     # test.cfg file
     [db]
-    my_postgresql=postgresql://username:pass@hostname/dbname
+    my_postgresql=postgresql+psycopg2://username:pass@hostname/dbname
 
 Above, we can now run the tests with ``my_postgresql``::
 
@@ -121,7 +133,7 @@ with the tox runner also::
 
     # test.cfg file
     [db]
-    postgresql=postgresql://username:pass@hostname/dbname
+    postgresql=postgresql+psycopg2://username:pass@hostname/dbname
 
 Now when we run ``tox -e py27-postgresql``, it will use our custom URL instead
 of the fixed one in setup.cfg.
index f2752b3def60c38ad0cf30e1410ec5cc1df9857c..afca522df3ab22e32693b5be74d7e2878826ba0f 100644 (file)
@@ -318,7 +318,7 @@ The new engine is described at :class:`_future.Engine` which delivers a new
 
     from sqlalchemy import create_engine
 
-    engine = create_engine("postgresql:///")
+    engine = create_engine("postgresql+psycopg2:///")
 
     with engine.connect() as conn:
         conn.execute(text("insert into table (x) values (:some_x)"), {"some_x": 10})
index d485008d8a55ec3c3b1eba52b954bfe93a2172d9..0cf3c2e2a3cb1b4e1bd5df49b8eab10a9eceaf49 100644 (file)
@@ -21,7 +21,7 @@ Basic Usage
 Recall from :doc:`/core/engines` that an :class:`_engine.Engine` is created via
 the :func:`_sa.create_engine` call::
 
-    engine = create_engine('mysql://scott:tiger@localhost/test')
+    engine = create_engine('mysql+mysqldb://scott:tiger@localhost/test')
 
 The typical usage of :func:`_sa.create_engine` is once per particular database
 URL, held globally for the lifetime of a single application process. A single
@@ -328,7 +328,7 @@ parameter to :func:`_sa.create_engine`::
     from sqlalchemy import create_engine
 
     eng = create_engine(
-        "postgresql://scott:tiger@localhost/test",
+        "postgresql+psycopg2://scott:tiger@localhost/test",
         execution_options={
             "isolation_level": "REPEATABLE READ"
         }
@@ -348,7 +348,7 @@ separated off from the main engine::
 
     from sqlalchemy import create_engine
 
-    eng = create_engine("postgresql://scott:tiger@localhost/test")
+    eng = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
 
     autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT")
 
@@ -789,7 +789,7 @@ used items when the size of the cache reaches a certain threshold.  The size
 of this cache defaults to 500 and may be configured using the
 :paramref:`_sa.create_engine.query_cache_size` parameter::
 
-    engine = create_engine("postgresql://scott:tiger@localhost/test", query_cache_size=1200)
+    engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test", query_cache_size=1200)
 
 The size of the cache can grow to be a factor of 150% of the size given, before
 it's pruned back down to the target size.  A cache of size 1200 above can therefore
index 6ec31ce089eca510f9e8b8625b1660ed00914724..e7564957ed331398c692b97f320cffe339cadd87 100644 (file)
@@ -446,7 +446,7 @@ transparently::
                         PGPString("this is my passphrase")),
                 )
 
-    engine = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
+    engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test", echo=True)
     with engine.begin() as conn:
         metadata_obj.create_all(conn)
 
index cb114ef7f9e5529461063bcb677d41a15cdb889e..c277e7b23756984ee45d3a82ec22958cd21b4d29 100644 (file)
@@ -22,7 +22,7 @@ Creating an engine is just a matter of issuing a single call,
 :func:`_sa.create_engine()`::
 
     from sqlalchemy import create_engine
-    engine = create_engine('postgresql://scott:tiger@localhost:5432/mydatabase')
+    engine = create_engine('postgresql+psycopg2://scott:tiger@localhost:5432/mydatabase')
 
 The above engine creates a :class:`.Dialect` object tailored towards
 PostgreSQL, as well as a :class:`_pool.Pool` object which will establish a DBAPI
@@ -243,7 +243,7 @@ Engine Creation API
         for keys and either strings or tuples of strings for values, e.g.::
 
             >>> from sqlalchemy.engine import make_url
-            >>> url = make_url("postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
+            >>> url = make_url("postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
             >>> url.query
             immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': '/path/to/crt'})
 
@@ -360,7 +360,7 @@ underlying implementation the connection::
 
 
     engine = create_engine(
-        "postgresql://user:pass@hostname/dbname",
+        "postgresql+psycopg2://user:pass@hostname/dbname",
         connect_args={"connection_factory": MyConnectionFactory}
     )
 
@@ -387,7 +387,7 @@ collections can then be modified in place to alter how they are used::
 
     from sqlalchemy import event
 
-    engine = create_engine("postgresql://user:pass@hostname/dbname")
+    engine = create_engine("postgresql+psycopg2://user:pass@hostname/dbname")
 
     @event.listens_for(engine, "do_connect")
     def receive_do_connect(dialect, conn_rec, cargs, cparams):
@@ -406,7 +406,7 @@ parameter, this could be implemented as::
 
     from sqlalchemy import event
 
-    engine = create_engine("postgresql://user@hostname/dbname")
+    engine = create_engine("postgresql+psycopg2://user@hostname/dbname")
 
     @event.listens_for(engine, "do_connect")
     def provide_token(dialect, conn_rec, cargs, cparams):
@@ -430,7 +430,7 @@ SQLAlchemy::
     from sqlalchemy import event
 
     engine = create_engine(
-        "postgresql://user:pass@hostname/dbname"
+        "postgresql+psycopg2://user:pass@hostname/dbname"
     )
 
     @event.listens_for(engine, "connect")
@@ -450,7 +450,7 @@ and returning it::
     from sqlalchemy import event
 
     engine = create_engine(
-        "postgresql://user:pass@hostname/dbname"
+        "postgresql+psycopg2://user:pass@hostname/dbname"
     )
 
     @event.listens_for(engine, "do_connect")
index af4e33ba9a5c3558256c5a9b2f7595daa04c5305..0f1f87cb24367bc67c7c6526926b3242796dec5e 100644 (file)
@@ -99,7 +99,7 @@ and objects::
         return psycopg2.connect(user='ed', host='127.0.0.1', dbname='test')
 
     my_pool = QueuePool(connect)
-    my_engine = create_engine('postgresql://ed@localhost/test')
+    my_engine = create_engine('postgresql+psycopg2://ed@localhost/test')
 
     # associate listener with all instances of Pool
     listen(Pool, 'connect', my_on_connect)
index d0629a4a16c60445bdf5d499a56a176be6a4e3c6..3e13d9ab97a8c4487b440767ba5d7e8ceef5b216 100644 (file)
@@ -35,7 +35,7 @@ directly to :func:`~sqlalchemy.create_engine` as keyword arguments:
 ``pool_size``, ``max_overflow``, ``pool_recycle`` and
 ``pool_timeout``.  For example::
 
-  engine = create_engine('postgresql://me@localhost/mydb',
+  engine = create_engine('postgresql+psycopg2://me@localhost/mydb',
                          pool_size=20, max_overflow=0)
 
 In the case of SQLite, the :class:`.SingletonThreadPool` or
@@ -358,7 +358,7 @@ such as MySQL that automatically close connections that have been stale after a
 period of time::
 
     from sqlalchemy import create_engine
-    e = create_engine("mysql://scott:tiger@localhost/test", pool_recycle=3600)
+    e = create_engine("mysql+mysqldb://scott:tiger@localhost/test", pool_recycle=3600)
 
 Above, any DBAPI connection that has been open for more than one hour will be invalidated and replaced,
 upon next checkout.   Note that the invalidation **only** occurs during checkout - not on
@@ -469,7 +469,7 @@ are three general approaches to this:
    more than once::
 
     from sqlalchemy.pool import NullPool
-    engine = create_engine("mysql://user:pass@host/dbname", poolclass=NullPool)
+    engine = create_engine("mysql+mysqldb://user:pass@host/dbname", poolclass=NullPool)
 
 
 2. Call :meth:`_engine.Engine.dispose` on any given :class:`_engine.Engine` as
@@ -480,7 +480,7 @@ are three general approaches to this:
    single call to :meth:`_engine.Engine.dispose` will ensure any remaining
    connections are flushed. **This is the recommended approach**::
 
-    engine = create_engine("mysql://user:pass@host/dbname")
+    engine = create_engine("mysql+mysqldb://user:pass@host/dbname")
 
     def run_in_process():
         # process starts.  ensure engine.dispose() is called just once
index 0660823eb024d7ec3e4dff879665d80ce4be025f..796bd414f9548b43431fc76b9d54861148b408b9 100644 (file)
@@ -182,7 +182,7 @@ and options:
 .. sourcecode:: pycon+sql
 
     >>> from sqlalchemy import MetaData, Table, create_engine
-    >>> mysql_engine = create_engine("mysql://scott:tiger@localhost/test")
+    >>> mysql_engine = create_engine("mysql+mysqldb://scott:tiger@localhost/test")
     >>> metadata_obj = MetaData()
     >>> my_mysql_table = Table("my_table", metadata_obj, autoload_with=mysql_engine)
 
@@ -233,7 +233,7 @@ We now get a new :class:`_schema.Table` that is generic and uses
 
 .. sourcecode:: pycon+sql
 
-    >>> pg_engine = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
+    >>> pg_engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test", echo=True)
     >>> my_generic_table.create(pg_engine)
     {opensql}CREATE TABLE my_table (
         id SERIAL NOT NULL,
index 2318d39b039e5cc5bc224a696d6817ea8de4622c..41802240ac4f2a486c18910c051553e22b381e9b 100644 (file)
@@ -421,7 +421,7 @@ familiar with.
   **pool size plus the max overflow**.     That means if you have configured
   your engine as::
 
-   engine = create_engine("mysql://u:p@host/db", pool_size=10, max_overflow=20)
+   engine = create_engine("mysql+mysqldb://u:p@host/db", pool_size=10, max_overflow=20)
 
   The above :class:`_engine.Engine` will allow **at most 30 connections** to be in
   play at any time, not including connections that were detached from the
index 1bee24c324796e4d830c556cf66193fb72cf35dc..f8c4e5bcaad6791d622c6baa2e263381e2ab3c81 100644 (file)
@@ -27,13 +27,13 @@ How do I pass custom connect arguments to my database API?
 The :func:`_sa.create_engine` call accepts additional arguments either
 directly via the ``connect_args`` keyword argument::
 
-    e = create_engine("mysql://scott:tiger@localhost/test",
+    e = create_engine("mysql+mysqldb://scott:tiger@localhost/test",
                         connect_args={"encoding": "utf8"})
 
 Or for basic string and integer arguments, they can usually be specified
 in the query string of the URL::
 
-    e = create_engine("mysql://scott:tiger@localhost/test?encoding=utf8")
+    e = create_engine("mysql+mysqldb://scott:tiger@localhost/test?encoding=utf8")
 
 .. seealso::
 
@@ -312,7 +312,7 @@ using the following proof of concept script.  Once run, it will emit a
 
     if __name__ == "__main__":
 
-        engine = create_engine("mysql://scott:tiger@localhost/test", echo_pool=True)
+        engine = create_engine("mysql+mysqldb://scott:tiger@localhost/test", echo_pool=True)
 
         def do_a_thing(engine):
             with engine.begin() as conn:
@@ -322,7 +322,7 @@ using the following proof of concept script.  Once run, it will emit a
 
         e = reconnecting_engine(
             create_engine(
-                "mysql://scott:tiger@localhost/test", echo_pool=True
+                "mysql+mysqldb://scott:tiger@localhost/test", echo_pool=True
             ),
             num_retries=5,
             retry_interval=2,
@@ -379,7 +379,7 @@ configured using ``reset_on_return``::
     from sqlalchemy import create_engine
     from sqlalchemy.pool import QueuePool
 
-    engine = create_engine('mysql://scott:tiger@localhost/myisam_database', pool=QueuePool(reset_on_return=False))
+    engine = create_engine('mysql+mysqldb://scott:tiger@localhost/myisam_database', pool=QueuePool(reset_on_return=False))
 
 I'm on SQL Server - how do I turn those ROLLBACKs into COMMITs?
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -388,7 +388,7 @@ I'm on SQL Server - how do I turn those ROLLBACKs into COMMITs?
 to ``True``, ``False``, and ``None``.   Setting to ``commit`` will cause
 a COMMIT as any connection is returned to the pool::
 
-    engine = create_engine('mssql://scott:tiger@mydsn', pool=QueuePool(reset_on_return='commit'))
+    engine = create_engine('mssql+pyodbc://scott:tiger@mydsn', pool=QueuePool(reset_on_return='commit'))
 
 
 I am using multiple connections with a SQLite database (typically to test transaction operation), and my test program is not working!
index 2556db60c1a00ae4a37492b94a8d37cb989d6df2..ab879b0aecd6d57c370743fc0a988d508d1f2308 100644 (file)
@@ -90,7 +90,7 @@ metadata creation sequence as a string, using this recipe::
 
     def dump(sql, *multiparams, **params):
         print(sql.compile(dialect=engine.dialect))
-    engine = create_mock_engine('postgresql://', dump)
+    engine = create_mock_engine('postgresql+psycopg2://', dump)
     metadata_obj.create_all(engine, checkfirst=False)
 
 The `Alembic <https://alembic.sqlalchemy.org>`_ tool also supports
index 88980195be68178f131969ae4bcb312609dd72dd..57c0b2c90e841678eac61fb8d5fbecc3cb8dce45 100644 (file)
@@ -37,7 +37,7 @@ Glossary
             from sqlalchemy.orm import sessionmaker
 
 
-            engine = create_engine("mysql://user:pass@host/dbname", future=True)
+            engine = create_engine("mysql+mysqldb://user:pass@host/dbname", future=True)
             Session = sessionmaker(bind=engine, future=True)
 
         **ORM Queries in 2.0 style**
index e935193c7d3032116989e56994a3a0686b8e8f18..3c28ee4e47d1b64174d82f4e095c4ba7088490e2 100644 (file)
@@ -337,7 +337,7 @@ use a declarative hybrid mapping, passing the
 :paramref:`_schema.Table.autoload_with` parameter to the
 :class:`_schema.Table`::
 
-    engine = create_engine("postgresql://user:pass@hostname/my_existing_database")
+    engine = create_engine("postgresql+psycopg2://user:pass@hostname/my_existing_database")
 
     class MyClass(Base):
         __table__ = Table(
@@ -387,7 +387,7 @@ the ``Reflected.prepare`` method is called.   The above mapping is not
 complete until we do so, given an :class:`_engine.Engine`::
 
 
-    engine = create_engine("postgresql://user:pass@hostname/my_existing_database")
+    engine = create_engine("postgresql+psycopg2://user:pass@hostname/my_existing_database")
     Reflected.prepare(engine)
 
 The purpose of the ``Reflected`` class is to define the scope at which
index 38f289058b68d5072490ebc5ac4a572411f0c1ab..18bb984cdd942963349a378387c529cc0ba0e31f 100644 (file)
@@ -49,7 +49,7 @@ part of the object's primary key::
         pk = Column(Integer, primary_key=True)
         bar = Column(Integer)
 
-    e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
+    e = create_engine("postgresql+psycopg2://scott:tiger@localhost/test", echo=True)
     Base.metadata.create_all(e)
 
     session = Session(e)
@@ -663,8 +663,8 @@ The dictionary is consulted whenever the :class:`.Session` needs to
 emit SQL on behalf of a particular kind of mapped class in order to locate
 the appropriate source of database connectivity::
 
-    engine1 = create_engine('postgresql://db1')
-    engine2 = create_engine('postgresql://db2')
+    engine1 = create_engine('postgresql+psycopg2://db1')
+    engine2 = create_engine('postgresql+psycopg2://db2')
 
     Session = sessionmaker()
 
index a4faed69dbc995c41e54b87bbe535ef15da89b63..8102832d20f79718d1fa058239b5fd829ad41962 100644 (file)
@@ -61,7 +61,7 @@ may look like::
 
     # an Engine, which the Session will use for connection
     # resources
-    engine = create_engine('postgresql://scott:tiger@localhost/')
+    engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/')
 
     # create session and add objects
     with Session(engine) as session:
@@ -144,7 +144,7 @@ scope, the :class:`_orm.sessionmaker` can provide a factory for
 
     # an Engine, which the Session will use for connection
     # resources, typically in module scope
-    engine = create_engine('postgresql://scott:tiger@localhost/')
+    engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/')
 
     # a sessionmaker(), also in the same scope as the engine
     Session = sessionmaker(engine)
@@ -169,7 +169,7 @@ and also maintains a begin/commit/rollback block::
 
     # an Engine, which the Session will use for connection
     # resources
-    engine = create_engine('postgresql://scott:tiger@localhost/')
+    engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/')
 
     # a sessionmaker(), also in the same scope as the engine
     Session = sessionmaker(engine)
index 199e76b43c391e4bf8663f92c2d8697278945014..465668c1b5ea76d0747d605cfdd1a04703ed8983 100644 (file)
@@ -216,7 +216,7 @@ methods.   Using SQLAlchemy 2.0-style operation, these methods affect the
 
 Engine::
 
-    engine = create_engine("postgresql://user:pass@host/dbname", future=True)
+    engine = create_engine("postgresql+psycopg2://user:pass@host/dbname", future=True)
 
     with engine.connect() as conn:
         conn.execute(
@@ -252,7 +252,7 @@ that will maintain a begin/commit/rollback context for that object.
 
 Engine::
 
-    engine = create_engine("postgresql://user:pass@host/dbname", future=True)
+    engine = create_engine("postgresql+psycopg2://user:pass@host/dbname", future=True)
 
     with engine.begin() as conn:
         conn.execute(
@@ -290,7 +290,7 @@ specific behavior that is reversed from the 1.x series.
 
 Engine::
 
-    engine = create_engine("postgresql://user:pass@host/dbname", future=True)
+    engine = create_engine("postgresql+psycopg2://user:pass@host/dbname", future=True)
 
     with engine.begin() as conn:
         savepoint = conn.begin_nested()
@@ -383,8 +383,8 @@ also :meth:`_orm.Session.prepare` the session for
 interacting with transactions not managed by SQLAlchemy. To use two phase
 transactions set the flag ``twophase=True`` on the session::
 
-    engine1 = create_engine('postgresql://db1')
-    engine2 = create_engine('postgresql://db2')
+    engine1 = create_engine('postgresql+psycopg2://db1')
+    engine2 = create_engine('postgresql+psycopg2://db2')
 
     Session = sessionmaker(twophase=True)
 
@@ -448,7 +448,7 @@ in all cases, which is then used as the source of connectivity for a
     from sqlalchemy.orm import sessionmaker
 
     eng = create_engine(
-        "postgresql://scott:tiger@localhost/test",
+        "postgresql+psycopg2://scott:tiger@localhost/test",
         isolation_level='REPEATABLE READ'
     )
 
@@ -465,7 +465,7 @@ operations::
     from sqlalchemy import create_engine
     from sqlalchemy.orm import sessionmaker
 
-    eng = create_engine("postgresql://scott:tiger@localhost/test")
+    eng = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
 
     autocommit_engine = eng.execution_options(isolation_level="AUTOCOMMIT")
 
@@ -505,7 +505,7 @@ we can pass the ``bind`` argument directly, overriding the pre-existing bind.
 We can for example create our :class:`_orm.Session` from a default
 :class:`.sessionmaker` and pass an engine set for autocommit::
 
-    plain_engine = create_engine("postgresql://scott:tiger@localhost/test")
+    plain_engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
 
     autocommit_engine = plain_engine.execution_options(isolation_level="AUTOCOMMIT")
 
@@ -630,7 +630,7 @@ are reverted::
     # global application scope.  create Session class, engine
     Session = sessionmaker()
 
-    engine = create_engine('postgresql://...')
+    engine = create_engine('postgresql+psycopg2://...')
 
     class SomeTest(TestCase):
         def setUp(self):
index 0f34c54dc75bedcd5c304059a55f471d44c77249..2b8c57232a5e017700209f2f5e84754152dde1cf 100644 (file)
@@ -69,7 +69,7 @@ mapper(Member, member_table)
 
 if __name__ == "__main__":
     engine = create_engine(
-        "postgresql://scott:tiger@localhost/test", echo=True
+        "postgresql+psycopg2://scott:tiger@localhost/test", echo=True
     )
     meta.create_all(engine)
 
index 37e91684c19dbb016e40fb7ef5a83a4366d6c1f1..ad2a4f4a9a6c922f31abff7ea7f6241a842dd69b 100644 (file)
@@ -106,7 +106,7 @@ class Node(Base):
 
 if __name__ == "__main__":
     engine = create_engine(
-        "postgresql://scott:tiger@localhost/test", echo=True
+        "postgresql+psycopg2://scott:tiger@localhost/test", echo=True
     )
     Base.metadata.create_all(engine)
 
index a12b824ba10de696ed613d18066cd9ee7540e3b8..2b45b98f566821c1ba3970a6445294750adb795f 100644 (file)
@@ -233,7 +233,7 @@ if __name__ == "__main__":
     from sqlalchemy.ext.declarative import declarative_base
 
     engine = create_engine(
-        "postgresql://scott:tiger@localhost/test", echo=True
+        "postgresql+psycopg2://scott:tiger@localhost/test", echo=True
     )
     metadata = MetaData(engine)
     Base = declarative_base(metadata=metadata)
index 63a11fcc7146fca92426c25a4a70f0f9c491cfd1..5382e00db86afc7e2a6b13b4a6539477f7669802 100644 (file)
@@ -213,7 +213,7 @@ techniques are used.
 To set isolation level using :func:`_sa.create_engine`::
 
     engine = create_engine(
-                    "mysql://scott:tiger@localhost/test",
+                    "mysql+mysqldb://scott:tiger@localhost/test",
                     isolation_level="READ UNCOMMITTED"
                 )
 
@@ -423,7 +423,7 @@ the ``first_connect`` and ``connect`` events::
 
     from sqlalchemy import create_engine, event
 
-    eng = create_engine("mysql://scott:tiger@localhost/test", echo='debug')
+    eng = create_engine("mysql+mysqldb://scott:tiger@localhost/test", echo='debug')
 
     # `insert=True` will ensure this is the very first listener to run
     @event.listens_for(eng, "connect", insert=True)
@@ -950,7 +950,7 @@ SQLAlchemy also emits NOT NULL for TIMESTAMP columns that do specify
 
 
     from sqlalchemy import create_engine
-    e = create_engine("mysql://scott:tiger@localhost/test", echo=True)
+    e = create_engine("mysql+mysqldb://scott:tiger@localhost/test", echo=True)
     m.create_all(e)
 
 output::
index 9e62b931d9c3eb29ee6f4bd16d9f26d18e95edcd..5a43205dff239e21edcf16f946f6f25bbfe8a4ab 100644 (file)
@@ -306,7 +306,7 @@ an INSERT in order to increment a sequence within an INSERT statement and get
 the value back at the same time. To disable this feature across the board,
 specify ``implicit_returning=False`` to :func:`_sa.create_engine`::
 
-    engine = create_engine("oracle://scott:tiger@dsn",
+    engine = create_engine("oracle+cx_oracle://scott:tiger@dsn",
                            implicit_returning=False)
 
 Implicit returning can also be disabled on a table-by-table basis as a table
@@ -450,7 +450,7 @@ the ``exclude_tablespaces`` parameter::
 
     # exclude SYSAUX and SOME_TABLESPACE, but not SYSTEM
     e = create_engine(
-      "oracle://scott:tiger@xe",
+      "oracle+cx_oracle://scott:tiger@xe",
       exclude_tablespaces=["SYSAUX", "SOME_TABLESPACE"])
 
 .. versionadded:: 1.1
index 38e8648989415ee3a8f31b3087455d132bb53852..590c9d47c674c4bf4a469e76f8ea2414dd68bee1 100644 (file)
@@ -158,7 +158,7 @@ SQLAlchemy's pooling::
        encoding="UTF-8", nencoding="UTF-8"
     )
 
-    engine = create_engine("oracle://", creator=pool.acquire, poolclass=NullPool)
+    engine = create_engine("oracle+cx_oracle://", creator=pool.acquire, poolclass=NullPool)
 
 The above engine may then be used normally where cx_Oracle's pool handles
 connection pooling::
@@ -196,7 +196,7 @@ This can be achieved by wrapping ``pool.acquire()``::
     def creator():
         return pool.acquire(cclass="MYCLASS", purity=cx_Oracle.ATTR_PURITY_SELF)
 
-    engine = create_engine("oracle://", creator=creator, poolclass=NullPool)
+    engine = create_engine("oracle+cx_oracle://", creator=creator, poolclass=NullPool)
 
 The above engine may then be used normally where cx_Oracle handles session
 pooling and Oracle Database additionally uses DRCP::
index 87afa029362a5766868b42afdbbde4b02e4d3c9d..a00c26e87dd6927fba36115e95062396f48db04c 100644 (file)
@@ -346,7 +346,7 @@ were set to include ``test_schema``, and we invoked a table
 reflection process as follows::
 
     >>> from sqlalchemy import Table, MetaData, create_engine, text
-    >>> engine = create_engine("postgresql://scott:tiger@localhost/test")
+    >>> engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
     >>> with engine.connect() as conn:
     ...     conn.execute(text("SET search_path TO test_schema, public"))
     ...     meta = MetaData()
index 2acf177f539b1809ddf30c81882757d3baf0dc8c..ef046e3aec6f4289e707400528f5e94a8b711501 100644 (file)
@@ -159,7 +159,7 @@ class JSON(sqltypes.JSON):
     using psycopg2, the DBAPI only allows serializers at the per-cursor
     or per-connection level.   E.g.::
 
-        engine = create_engine("postgresql://scott:tiger@localhost/test",
+        engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test",
                                 json_serializer=my_serialize_fn,
                                 json_deserializer=my_deserialize_fn
                         )
index 41c5f4753e8cd9cb87ce4bce041a7a95764ce971..ef62825251f082b6d1b12b0a6e0ee7ebe531eb11 100644 (file)
@@ -1887,7 +1887,7 @@ class Transaction(TransactionalContext):
     :class:`_engine.Connection`::
 
         from sqlalchemy import create_engine
-        engine = create_engine("postgresql://scott:tiger@localhost/test")
+        engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
         connection = engine.connect()
         trans = connection.begin()
         connection.execute(text("insert into x (a, b) values (1, 2)"))
@@ -1914,7 +1914,7 @@ class Transaction(TransactionalContext):
 
     .. index::
       single: thread safety; Transaction
-    """
+    """  # noqa
 
     __slots__ = ()
 
@@ -2413,7 +2413,7 @@ class Engine(ConnectionEventsTarget, log.Identified):
             from sqlalchemy import event
             from sqlalchemy.engine import Engine
 
-            primary_engine = create_engine("mysql://")
+            primary_engine = create_engine("mysql+mysqldb://")
             shard1 = primary_engine.execution_options(shard_id="shard1")
             shard2 = primary_engine.execution_options(shard_id="shard2")
 
index 6e5a07098da3af822b6c3ca19795bd6377727c1a..bb657202ff8fa126e356cea45a16d46ef85b1160 100644 (file)
@@ -42,7 +42,7 @@ def create_engine(url, **kwargs):
     first positional argument, usually a string
     that indicates database dialect and connection arguments::
 
-        engine = create_engine("postgresql://scott:tiger@localhost/test")
+        engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
 
     .. note::
 
@@ -55,7 +55,7 @@ def create_engine(url, **kwargs):
     and its underlying :class:`.Dialect` and :class:`_pool.Pool`
     constructs::
 
-        engine = create_engine("mysql://scott:tiger@hostname/dbname",
+        engine = create_engine("mysql+mysqldb://scott:tiger@hostname/dbname",
                                     encoding='latin1', echo=True)
 
     The string form of the URL is
index cfb616affcfb72aa07b67056bead9ccd1f84111f..57628066d82ae570ad3de67bbb8ad7f2d5197ba8 100644 (file)
@@ -30,7 +30,7 @@ class ConnectionEvents(event.Events):
                                                         executemany):
             log.info("Received statement: %s", statement)
 
-        engine = create_engine('postgresql://scott:tiger@localhost/test')
+        engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/test')
         event.listen(engine, "before_cursor_execute", before_cursor_execute)
 
     or with a specific :class:`_engine.Connection`::
@@ -88,7 +88,7 @@ class ConnectionEvents(event.Events):
       and parameters.  See those methods for a description of
       specific return arguments.
 
-    """
+    """  # noqa
 
     _target_class_doc = "SomeEngine"
     _dispatch_target = ConnectionEventsTarget
index 5da716b6b6f7bc8e5ccda5fd502769dc019bf74a..731dacc33ade2a9953eac69b1a329a978fdff763 100644 (file)
@@ -62,7 +62,7 @@ def create_mock_engine(url, executor, **kw):
         def dump(sql, *multiparams, **params):
             print(sql.compile(dialect=engine.dialect))
 
-        engine = create_mock_engine('postgresql://', dump)
+        engine = create_mock_engine('postgresql+psycopg2://', dump)
         metadata.create_all(engine, checkfirst=False)
 
     :param url: A string URL which typically needs to contain only the
index be330eb6c72de03c7e4af78665a5cd356d210c18..7f09b1eac32957912d7c541937088bc2eacf280f 100644 (file)
@@ -286,10 +286,10 @@ class URL(
         E.g.::
 
             >>> from sqlalchemy.engine import make_url
-            >>> url = make_url("postgresql://user:pass@host/dbname")
+            >>> url = make_url("postgresql+psycopg2://user:pass@host/dbname")
             >>> url = url.update_query_string("alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
             >>> str(url)
-            'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
+            'postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
 
         :param query_string: a URL escaped query string, not including the
          question mark.
@@ -320,10 +320,10 @@ class URL(
         E.g.::
 
             >>> from sqlalchemy.engine import make_url
-            >>> url = make_url("postgresql://user:pass@host/dbname")
+            >>> url = make_url("postgresql+psycopg2://user:pass@host/dbname")
             >>> url = url.update_query_pairs([("alt_host", "host1"), ("alt_host", "host2"), ("ssl_cipher", "/path/to/crt")])
             >>> str(url)
-            'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
+            'postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
 
         :param key_value_pairs: A sequence of tuples containing two strings
          each.
@@ -389,10 +389,10 @@ class URL(
 
 
             >>> from sqlalchemy.engine import make_url
-            >>> url = make_url("postgresql://user:pass@host/dbname")
+            >>> url = make_url("postgresql+psycopg2://user:pass@host/dbname")
             >>> url = url.update_query_dict({"alt_host": ["host1", "host2"], "ssl_cipher": "/path/to/crt"})
             >>> str(url)
-            'postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
+            'postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt'
 
 
         :param query_parameters: A dictionary with string keys and values
@@ -485,7 +485,7 @@ class URL(
 
 
             >>> from sqlalchemy.engine import make_url
-            >>> url = make_url("postgresql://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
+            >>> url = make_url("postgresql+psycopg2://user:pass@host/dbname?alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt")
             >>> url.query
             immutabledict({'alt_host': ('host1', 'host2'), 'ssl_cipher': '/path/to/crt'})
             >>> url.normalized_query
index c76ece5de54de60db7fecf1e02dd34e52b1e4d39..95d329ab0df814cf6e2535810aa197fa29300b64 100644 (file)
@@ -1001,10 +1001,10 @@ class Session(_SessionClassMethods):
            described at :meth:`.Session.get_bind`.  Usage looks like::
 
             Session = sessionmaker(binds={
-                SomeMappedClass: create_engine('postgresql://engine1'),
-                SomeDeclarativeBase: create_engine('postgresql://engine2'),
-                some_mapper: create_engine('postgresql://engine3'),
-                some_table: create_engine('postgresql://engine4'),
+                SomeMappedClass: create_engine('postgresql+psycopg2://engine1'),
+                SomeDeclarativeBase: create_engine('postgresql+psycopg2://engine2'),
+                some_mapper: create_engine('postgresql+psycopg2://engine3'),
+                some_table: create_engine('postgresql+psycopg2://engine4'),
                 })
 
            .. seealso::
@@ -1086,7 +1086,7 @@ class Session(_SessionClassMethods):
         :param autocommit: the "autocommit" keyword is present for backwards
             compatibility but must remain at its default value of ``False``.
 
-        """
+        """  # noqa
 
         # considering allowing the "autocommit" keyword to still be accepted
         # as long as it's False, so that external test suites, oslo.db etc
@@ -3906,7 +3906,7 @@ class sessionmaker(_SessionClassMethods):
 
         # an Engine, which the Session will use for connection
         # resources
-        engine = create_engine('postgresql://scott:tiger@localhost/')
+        engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/')
 
         Session = sessionmaker(engine)
 
index 7c2cae7c5eb0fe1f275cb83433ada71e45ec0bff..57e3893b02bd9fe889cff7ac9c68ca4ad0f06191 100644 (file)
@@ -32,12 +32,12 @@ class PoolEvents(event.Events):
     targets, which will be resolved to the ``.pool`` attribute of the
     given engine or the :class:`_pool.Pool` class::
 
-        engine = create_engine("postgresql://scott:tiger@localhost/test")
+        engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
 
         # will associate with engine.pool
         event.listen(engine, 'checkout', my_on_checkout)
 
-    """
+    """  # noqa
 
     _target_class_doc = "SomeEngineOrPool"
     _dispatch_target = Pool
index dbd50d5d8cff805b3172c851156f3d59a9b54922..a600960cac5cc3ddff1fde8d98ed4c6a3d3d7160 100644 (file)
@@ -1431,7 +1431,7 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause):
                 from sqlalchemy.dialects.postgresql import array
 
                 engine = create_engine(
-                    'postgresql://scott:tiger@localhost/mydatabase'
+                    'postgresql+psycopg2://scott:tiger@localhost/mydatabase'
                 )
                 metadata_obj = MetaData()
                 tbl = Table(
index e886b69233866a487d5681cb47cc460f5643ec40..624ace1bdf1690c1992343f7437d3ad01fd17866 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -156,20 +156,20 @@ aiosqlite = sqlite+aiosqlite:///:memory:
 sqlite_file = sqlite:///querytest.db
 aiosqlite_file = sqlite+aiosqlite:///async_querytest.db
 pysqlcipher_file = sqlite+pysqlcipher://:test@/querytest.db.enc
-postgresql = postgresql://scott:tiger@127.0.0.1:5432/test
+postgresql = postgresql+psycopg2://scott:tiger@127.0.0.1:5432/test
 asyncpg = postgresql+asyncpg://scott:tiger@127.0.0.1:5432/test
 asyncpg_fallback = postgresql+asyncpg://scott:tiger@127.0.0.1:5432/test?async_fallback=true
 pg8000 = postgresql+pg8000://scott:tiger@127.0.0.1:5432/test
 postgresql_psycopg2cffi = postgresql+psycopg2cffi://scott:tiger@127.0.0.1:5432/test
-mysql = mysql://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
+mysql = mysql+mysqldb://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
 pymysql = mysql+pymysql://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
 aiomysql = mysql+aiomysql://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
 aiomysql_fallback = mysql+aiomysql://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4&async_fallback=true
 asyncmy = mysql+asyncmy://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4
 asyncmy_fallback = mysql+asyncmy://scott:tiger@127.0.0.1:3306/test?charset=utf8mb4&async_fallback=true
-mariadb = mariadb://scott:tiger@127.0.0.1:3306/test
+mariadb = mariadb+mysqldb://scott:tiger@127.0.0.1:3306/test
 mssql = mssql+pyodbc://scott:tiger^5HHH@mssql2017:1433/test?driver=ODBC+Driver+13+for+SQL+Server
 mssql_pymssql = mssql+pymssql://scott:tiger@ms_2008
 docker_mssql = mssql+pymssql://scott:tiger^5HHH@127.0.0.1:1433/test
-oracle = oracle://scott:tiger@127.0.0.1:1521
-oracle8 = oracle://scott:tiger@127.0.0.1:1521/?use_ansi=0
+oracle = oracle+cx_oracle://scott:tiger@127.0.0.1:1521
+oracle8 = oracle+cx_oracle://scott:tiger@127.0.0.1:1521/?use_ansi=0
index aecb813fa167d68a8a011c344a29f820fbe64a05..24625d65c7540fa05e5ef00a7a9988deb29d0d9d 100644 (file)
@@ -64,14 +64,14 @@ class LegacySchemaAliasingTest(fixtures.TestBase, AssertsCompiledSQL):
     @testing.combinations(
         (
             {
-                "sqlalchemy.url": "mssql://foodsn",
+                "sqlalchemy.url": "mssql+pyodbc://foodsn",
                 "sqlalchemy.legacy_schema_aliasing": "true",
             },
             True,
         ),
         (
             {
-                "sqlalchemy.url": "mssql://foodsn",
+                "sqlalchemy.url": "mssql+pyodbc://foodsn",
                 "sqlalchemy.legacy_schema_aliasing": "false",
             },
             False,
index 5482e261670aa7654f2dec9d4e1cc753db4e0c59..e14fd164a03f3020c04bdf319723190b2b03512d 100644 (file)
@@ -32,26 +32,27 @@ from sqlalchemy.testing.mock import Mock
 class ParseConnectTest(fixtures.TestBase):
     def test_pyodbc_connect_dsn_trusted(self):
         dialect = pyodbc.dialect()
-        u = url.make_url("mssql://mydsn")
+        u = url.make_url("mssql+pyodbc://mydsn")
         connection = dialect.create_connect_args(u)
         eq_([["dsn=mydsn;Trusted_Connection=Yes"], {}], connection)
 
     def test_pyodbc_connect_old_style_dsn_trusted(self):
         dialect = pyodbc.dialect()
-        u = url.make_url("mssql:///?dsn=mydsn")
+        u = url.make_url("mssql+pyodbc:///?dsn=mydsn")
         connection = dialect.create_connect_args(u)
         eq_([["dsn=mydsn;Trusted_Connection=Yes"], {}], connection)
 
     def test_pyodbc_connect_dsn_non_trusted(self):
         dialect = pyodbc.dialect()
-        u = url.make_url("mssql://username:password@mydsn")
+        u = url.make_url("mssql+pyodbc://username:password@mydsn")
         connection = dialect.create_connect_args(u)
         eq_([["dsn=mydsn;UID=username;PWD=password"], {}], connection)
 
     def test_pyodbc_connect_dsn_extra(self):
         dialect = pyodbc.dialect()
         u = url.make_url(
-            "mssql://username:password@mydsn/?LANGUAGE=us_" "english&foo=bar"
+            "mssql+pyodbc://username:password@mydsn/?LANGUAGE=us_"
+            "english&foo=bar"
         )
         connection = dialect.create_connect_args(u)
         dsn_string = connection[0][0]
@@ -61,7 +62,7 @@ class ParseConnectTest(fixtures.TestBase):
     def test_pyodbc_hostname(self):
         dialect = pyodbc.dialect()
         u = url.make_url(
-            "mssql://username:password@hostspec/database?driver=SQL+Server"
+            "mssql+pyodbc://username:password@hostspec/database?driver=SQL+Server"  # noqa
         )
         connection = dialect.create_connect_args(u)
         eq_(
@@ -84,7 +85,7 @@ class ParseConnectTest(fixtures.TestBase):
 
     def test_pyodbc_host_no_driver(self):
         dialect = pyodbc.dialect()
-        u = url.make_url("mssql://username:password@hostspec/database")
+        u = url.make_url("mssql+pyodbc://username:password@hostspec/database")
 
         def go():
             return dialect.create_connect_args(u)
@@ -111,7 +112,7 @@ class ParseConnectTest(fixtures.TestBase):
     def test_pyodbc_connect_comma_port(self):
         dialect = pyodbc.dialect()
         u = url.make_url(
-            "mssql://username:password@hostspec:12345/data"
+            "mssql+pyodbc://username:password@hostspec:12345/data"
             "base?driver=SQL Server"
         )
         connection = dialect.create_connect_args(u)
@@ -129,7 +130,7 @@ class ParseConnectTest(fixtures.TestBase):
     def test_pyodbc_connect_config_port(self):
         dialect = pyodbc.dialect()
         u = url.make_url(
-            "mssql://username:password@hostspec/database?p"
+            "mssql+pyodbc://username:password@hostspec/database?p"
             "ort=12345&driver=SQL+Server"
         )
         connection = dialect.create_connect_args(u)
@@ -147,7 +148,7 @@ class ParseConnectTest(fixtures.TestBase):
     def test_pyodbc_extra_connect(self):
         dialect = pyodbc.dialect()
         u = url.make_url(
-            "mssql://username:password@hostspec/database?L"
+            "mssql+pyodbc://username:password@hostspec/database?L"
             "ANGUAGE=us_english&foo=bar&driver=SQL+Server"
         )
         connection = dialect.create_connect_args(u)
@@ -186,7 +187,7 @@ class ParseConnectTest(fixtures.TestBase):
     def test_pyodbc_odbc_connect(self):
         dialect = pyodbc.dialect()
         u = url.make_url(
-            "mssql:///?odbc_connect=DRIVER%3D%7BSQL+Server"
+            "mssql+pyodbc:///?odbc_connect=DRIVER%3D%7BSQL+Server"
             "%7D%3BServer%3Dhostspec%3BDatabase%3Ddatabase"
             "%3BUID%3Dusername%3BPWD%3Dpassword"
         )
@@ -205,7 +206,7 @@ class ParseConnectTest(fixtures.TestBase):
     def test_pyodbc_odbc_connect_with_dsn(self):
         dialect = pyodbc.dialect()
         u = url.make_url(
-            "mssql:///?odbc_connect=dsn%3Dmydsn%3BDatabase"
+            "mssql+pyodbc:///?odbc_connect=dsn%3Dmydsn%3BDatabase"
             "%3Ddatabase%3BUID%3Dusername%3BPWD%3Dpassword"
         )
         connection = dialect.create_connect_args(u)
@@ -217,7 +218,7 @@ class ParseConnectTest(fixtures.TestBase):
     def test_pyodbc_odbc_connect_ignores_other_values(self):
         dialect = pyodbc.dialect()
         u = url.make_url(
-            "mssql://userdiff:passdiff@localhost/dbdiff?od"
+            "mssql+pyodbc://userdiff:passdiff@localhost/dbdiff?od"
             "bc_connect=DRIVER%3D%7BSQL+Server%7D%3BServer"
             "%3Dhostspec%3BDatabase%3Ddatabase%3BUID%3Duse"
             "rname%3BPWD%3Dpassword"
index 834e1874c521d7dcd03f90f3667901a206dd9ec9..9a0f2bc0dfb9e69bc4aa5d79f722d281430a8f85 100644 (file)
@@ -202,7 +202,7 @@ class DialectTest(fixtures.TestBase):
         dialect = mysqldb.dialect()
         connect_args = dialect.create_connect_args(
             make_url(
-                "mysql://scott:tiger@localhost:3306/test"
+                "mysql+mysqldb://scott:tiger@localhost:3306/test"
                 "?%s=%s" % (kwarg, value)
             )
         )
@@ -262,7 +262,7 @@ class DialectTest(fixtures.TestBase):
     def test_random_arg(self):
         dialect = testing.db.dialect
         kw = dialect.create_connect_args(
-            make_url("mysql://u:p@host/db?foo=true")
+            make_url("mysql+mysqldb://u:p@host/db?foo=true")
         )[1]
         eq_(kw["foo"], "true")
 
@@ -303,7 +303,7 @@ class DialectTest(fixtures.TestBase):
 
 class ParseVersionTest(fixtures.TestBase):
     def test_mariadb_madness(self):
-        mysql_dialect = make_url("mysql://").get_dialect()()
+        mysql_dialect = make_url("mysql+mysqldb://").get_dialect()()
 
         is_(mysql_dialect.is_mariadb, False)
 
index e7c4ebb7ce4b157765b3f01538e9181b18efc348..fe3700bbbc36e04542bd835d854b9791ac102ca1 100644 (file)
@@ -171,42 +171,44 @@ $$ LANGUAGE plpgsql;"""
 
     def test_psycopg2_empty_connection_string(self):
         dialect = psycopg2_dialect.dialect()
-        u = url.make_url("postgresql://")
+        u = url.make_url("postgresql+psycopg2://")
         cargs, cparams = dialect.create_connect_args(u)
         eq_(cargs, [""])
         eq_(cparams, {})
 
     def test_psycopg2_nonempty_connection_string(self):
         dialect = psycopg2_dialect.dialect()
-        u = url.make_url("postgresql://host")
+        u = url.make_url("postgresql+psycopg2://host")
         cargs, cparams = dialect.create_connect_args(u)
         eq_(cargs, [])
         eq_(cparams, {"host": "host"})
 
     def test_psycopg2_empty_connection_string_w_query_one(self):
         dialect = psycopg2_dialect.dialect()
-        u = url.make_url("postgresql:///?service=swh-log")
+        u = url.make_url("postgresql+psycopg2:///?service=swh-log")
         cargs, cparams = dialect.create_connect_args(u)
         eq_(cargs, [])
         eq_(cparams, {"service": "swh-log"})
 
     def test_psycopg2_empty_connection_string_w_query_two(self):
         dialect = psycopg2_dialect.dialect()
-        u = url.make_url("postgresql:///?any_random_thing=yes")
+        u = url.make_url("postgresql+psycopg2:///?any_random_thing=yes")
         cargs, cparams = dialect.create_connect_args(u)
         eq_(cargs, [])
         eq_(cparams, {"any_random_thing": "yes"})
 
     def test_psycopg2_nonempty_connection_string_w_query(self):
         dialect = psycopg2_dialect.dialect()
-        u = url.make_url("postgresql://somehost/?any_random_thing=yes")
+        u = url.make_url(
+            "postgresql+psycopg2://somehost/?any_random_thing=yes"
+        )
         cargs, cparams = dialect.create_connect_args(u)
         eq_(cargs, [])
         eq_(cparams, {"host": "somehost", "any_random_thing": "yes"})
 
     def test_psycopg2_nonempty_connection_string_w_query_two(self):
         dialect = psycopg2_dialect.dialect()
-        url_string = "postgresql://USER:PASS@/DB?host=hostA"
+        url_string = "postgresql+psycopg2://USER:PASS@/DB?host=hostA"
         u = url.make_url(url_string)
         cargs, cparams = dialect.create_connect_args(u)
         eq_(cargs, [])
@@ -215,7 +217,7 @@ $$ LANGUAGE plpgsql;"""
     def test_psycopg2_nonempty_connection_string_w_query_three(self):
         dialect = psycopg2_dialect.dialect()
         url_string = (
-            "postgresql://USER:PASS@/DB"
+            "postgresql+psycopg2://USER:PASS@/DB"
             "?host=hostA:portA&host=hostB&host=hostC"
         )
         u = url.make_url(url_string)
index 6e7169d12fa01073ef7e662ed399efb90a61ba1f..956524abd1e036391e069dceffc24c0538104a0e 100644 (file)
@@ -278,7 +278,7 @@ class CreateEngineTest(fixtures.TestBase):
             "only argument accepted is 'mock'"
         ):
             e = create_engine(
-                "postgresql://", strategy="mock", executor=executor
+                "postgresql+psycopg2://", strategy="mock", executor=executor
             )
 
         assert isinstance(e, MockConnection)
@@ -292,7 +292,7 @@ class CreateEngineTest(fixtures.TestBase):
                 tsa.exc.ArgumentError,
                 "unknown strategy: 'threadlocal'",
                 create_engine,
-                "postgresql://",
+                "postgresql+psycopg2://",
                 strategy="threadlocal",
             )
 
@@ -302,7 +302,7 @@ class CreateEngineTest(fixtures.TestBase):
             "and no longer has any effect."
         ):
             create_engine(
-                "postgresql://",
+                "postgresql+psycopg2://",
                 empty_in_strategy="static",
                 module=Mock(),
                 _initialize=False,
index afe95ba82680ec3edac5ad57deec280ad4b06963..3b691ebc9e98d041baedbeb75d282ce47550449e 100644 (file)
@@ -1161,7 +1161,7 @@ class MockStrategyTest(fixtures.TestBase):
         def dump(sql, *multiparams, **params):
             buf.write(util.text_type(sql.compile(dialect=engine.dialect)))
 
-        engine = create_mock_engine("postgresql://", executor=dump)
+        engine = create_mock_engine("postgresql+psycopg2://", executor=dump)
         return engine, buf
 
     def test_sequence_not_duped(self):
index 044dc2cbdc8ab1414624a857594f84c0a4f015e8..f0a1dba4bbdd3df9c2aca1550fac6cb04961ea50 100644 (file)
@@ -16,6 +16,7 @@ from sqlalchemy.testing import is_
 from sqlalchemy.testing import is_false
 from sqlalchemy.testing import is_true
 from sqlalchemy.testing import mock
+from sqlalchemy.testing import ne_
 from sqlalchemy.testing.assertions import expect_deprecated
 from sqlalchemy.testing.assertions import expect_raises_message
 from sqlalchemy.testing.mock import call
@@ -447,7 +448,7 @@ class CreateEngineTest(fixtures.TestBase):
     def test_connect_query(self):
         dbapi = MockDBAPI(foober="12", lala="18", fooz="somevalue")
         e = create_engine(
-            "postgresql://scott:tiger@somehost/test?foobe"
+            "postgresql+psycopg2://scott:tiger@somehost/test?foobe"
             "r=12&lala=18&fooz=somevalue",
             module=dbapi,
             _initialize=False,
@@ -459,7 +460,8 @@ class CreateEngineTest(fixtures.TestBase):
             foober=12, lala=18, hoho={"this": "dict"}, fooz="somevalue"
         )
         e = create_engine(
-            "postgresql://scott:tiger@somehost/test?fooz=" "somevalue",
+            "postgresql+psycopg2://scott:tiger@somehost/test?fooz="
+            "somevalue",
             connect_args={"foober": 12, "lala": 18, "hoho": {"this": "dict"}},
             module=dbapi,
             _initialize=False,
@@ -470,7 +472,7 @@ class CreateEngineTest(fixtures.TestBase):
         dbapi = mock_dbapi
 
         config = {
-            "sqlalchemy.url": "postgresql://scott:tiger@somehost/test"
+            "sqlalchemy.url": "postgresql+psycopg2://scott:tiger@somehost/test"
             "?fooz=somevalue",
             "sqlalchemy.pool_recycle": "50",
             "sqlalchemy.echo": "true",
@@ -479,7 +481,7 @@ class CreateEngineTest(fixtures.TestBase):
         e = engine_from_config(config, module=dbapi, _initialize=False)
         assert e.pool._recycle == 50
         assert e.url == url.make_url(
-            "postgresql://scott:tiger@somehost/test?foo" "z=somevalue"
+            "postgresql+psycopg2://scott:tiger@somehost/test?foo" "z=somevalue"
         )
         assert e.echo is True
 
@@ -487,7 +489,7 @@ class CreateEngineTest(fixtures.TestBase):
         dbapi = mock_dbapi
 
         config = {
-            "sqlalchemy.url": "postgresql://scott:tiger@somehost/test"
+            "sqlalchemy.url": "postgresql+psycopg2://scott:tiger@somehost/test"
             "?fooz=somevalue",
             "sqlalchemy.future": "true",
         }
@@ -498,7 +500,7 @@ class CreateEngineTest(fixtures.TestBase):
         dbapi = mock_dbapi
 
         config = {
-            "sqlalchemy.url": "postgresql://scott:tiger@somehost/test"
+            "sqlalchemy.url": "postgresql+psycopg2://scott:tiger@somehost/test"
             "?fooz=somevalue",
             "sqlalchemy.future": "false",
         }
@@ -519,7 +521,7 @@ class CreateEngineTest(fixtures.TestBase):
             ("none", pool.reset_none),
         ]:
             config = {
-                "sqlalchemy.url": "postgresql://scott:tiger@somehost/test",
+                "sqlalchemy.url": "postgresql+psycopg2://scott:tiger@somehost/test",  # noqa
                 "sqlalchemy.pool_reset_on_return": value,
             }
 
@@ -603,7 +605,10 @@ class CreateEngineTest(fixtures.TestBase):
         # module instead of psycopg
 
         e = create_engine(
-            "postgresql://", creator=connect, module=dbapi, _initialize=False
+            "postgresql+psycopg2://",
+            creator=connect,
+            module=dbapi,
+            _initialize=False,
         )
         e.connect()
 
@@ -612,7 +617,10 @@ class CreateEngineTest(fixtures.TestBase):
             foober=12, lala=18, hoho={"this": "dict"}, fooz="somevalue"
         )
         e = create_engine(
-            "postgresql://", pool_recycle=472, module=dbapi, _initialize=False
+            "postgresql+psycopg2://",
+            pool_recycle=472,
+            module=dbapi,
+            _initialize=False,
         )
         assert e.pool._recycle == 472
 
@@ -628,7 +636,7 @@ class CreateEngineTest(fixtures.TestBase):
             (False, pool.reset_none),
         ]:
             e = create_engine(
-                "postgresql://",
+                "postgresql+psycopg2://",
                 pool_reset_on_return=value,
                 module=dbapi,
                 _initialize=False,
@@ -638,7 +646,7 @@ class CreateEngineTest(fixtures.TestBase):
         assert_raises(
             exc.ArgumentError,
             create_engine,
-            "postgresql://",
+            "postgresql+psycopg2://",
             pool_reset_on_return="hi",
             module=dbapi,
             _initialize=False,
@@ -654,7 +662,7 @@ class CreateEngineTest(fixtures.TestBase):
         assert_raises(
             TypeError,
             create_engine,
-            "postgresql://",
+            "postgresql+psycopg2://",
             use_ansi=True,
             module=mock_dbapi,
         )
@@ -672,7 +680,7 @@ class CreateEngineTest(fixtures.TestBase):
         assert_raises(
             TypeError,
             create_engine,
-            "postgresql://",
+            "postgresql+psycopg2://",
             lala=5,
             module=mock_dbapi,
         )
@@ -695,25 +703,25 @@ class CreateEngineTest(fixtures.TestBase):
         """test the url attribute on ``Engine``."""
 
         e = create_engine(
-            "mysql://scott:tiger@localhost/test",
+            "mysql+mysqldb://scott:tiger@localhost/test",
             module=mock_dbapi,
             _initialize=False,
         )
-        u = url.make_url("mysql://scott:tiger@localhost/test")
+        u = url.make_url("mysql+mysqldb://scott:tiger@localhost/test")
         e2 = create_engine(u, module=mock_dbapi, _initialize=False)
-        assert e.url.drivername == e2.url.drivername == "mysql"
+        assert e.url.drivername == e2.url.drivername == "mysql+mysqldb"
         assert e.url.username == e2.url.username == "scott"
         assert e2.url is u
-        assert str(u) == "mysql://scott:tiger@localhost/test"
-        assert repr(u) == "mysql://scott:***@localhost/test"
-        assert repr(e) == "Engine(mysql://scott:***@localhost/test)"
-        assert repr(e2) == "Engine(mysql://scott:***@localhost/test)"
+        assert str(u) == "mysql+mysqldb://scott:tiger@localhost/test"
+        assert repr(u) == "mysql+mysqldb://scott:***@localhost/test"
+        assert repr(e) == "Engine(mysql+mysqldb://scott:***@localhost/test)"
+        assert repr(e2) == "Engine(mysql+mysqldb://scott:***@localhost/test)"
 
     def test_poolargs(self):
         """test that connection pool args make it thru"""
 
         e = create_engine(
-            "postgresql://",
+            "postgresql+psycopg2://",
             creator=None,
             pool_recycle=50,
             echo_pool=None,
@@ -725,7 +733,7 @@ class CreateEngineTest(fixtures.TestBase):
         # these args work for QueuePool
 
         e = create_engine(
-            "postgresql://",
+            "postgresql+psycopg2://",
             max_overflow=8,
             pool_timeout=60,
             poolclass=tsa.pool.QueuePool,
@@ -783,6 +791,26 @@ class CreateEngineTest(fixtures.TestBase):
         e.connect()
         eq_(sp.called, 1)
 
+    def test_default_driver(self):
+        successes = 0
+        for url_prefix, driver_name in [
+            ("mariadb://", "mysqldb"),
+            ("mssql://", "pyodbc"),
+            ("mysql://", "mysqldb"),
+            ("oracle://", "cx_oracle"),
+            ("postgresql://", "psycopg2"),
+            ("sqlite://", "pysqlite"),
+        ]:
+            try:
+                en = create_engine(url_prefix)
+                eq_(en.dialect.driver, driver_name)
+                successes += 1
+            except ModuleNotFoundError:
+                # not all test environments will have every driver installed
+                pass
+        # but we should at least find one
+        ne_(successes, 0, "No default drivers found.")
+
 
 class TestRegNewDBAPI(fixtures.TestBase):
     def test_register_base(self):
index 0c7f86a6234327ef2058d6044017c9f8b22529fd..c9894b0f285f92a994774a328fe29ac1f997c22a 100644 (file)
@@ -166,7 +166,7 @@ class PrePingMockTest(fixtures.TestBase):
 
     def _pool_fixture(self, pre_ping, pool_kw=None):
         dialect = url.make_url(
-            "postgresql://foo:bar@localhost/test"
+            "postgresql+psycopg2://foo:bar@localhost/test"
         ).get_dialect()()
         dialect.dbapi = self.dbapi
         _pool = pool.QueuePool(
@@ -360,7 +360,7 @@ class MockReconnectTest(fixtures.TestBase):
         self.dbapi = MockDBAPI()
 
         self.db = testing_engine(
-            "postgresql://foo:bar@localhost/test",
+            "postgresql+psycopg2://foo:bar@localhost/test",
             options=dict(module=self.dbapi, _initialize=False),
         )
 
index 22b743434f804eab9ccd132250e8e0795b77de19..93e280d4e1c19cdb29db654016098780b26182c0 100644 (file)
@@ -178,7 +178,9 @@ class DeprecationWarningsTest(fixtures.TestBase, AssertsCompiledSQL):
             "The create_engine.convert_unicode parameter and "
             "corresponding dialect-level"
         ):
-            create_engine("mysql://", convert_unicode=True, module=mock.Mock())
+            create_engine(
+                "mysql+mysqldb://", convert_unicode=True, module=mock.Mock()
+            )
 
     def test_empty_and_or(self):
         with testing.expect_deprecated(