# Buggy code
def new_session_factory(url="sqlite:///:memory:", reset=False, **kwargs):
    """Create a new session at url"""
    if url.startswith("sqlite"):
        kwargs.setdefault("connect_args", {"check_same_thread": False})
    elif url.startswith("mysql"):
        kwargs.setdefault("pool_recycle", 60)

    if url.endswith(":memory:"):
        # If we're using an in-memory database, ensure that only one connection
        # is ever created.
        kwargs.setdefault("poolclass", StaticPool)

    engine = create_engine(url, **kwargs)
    if reset:
        Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)

    session_factory = sessionmaker(bind=engine)
    return session_factory


# Traceback (sqlite3.OperationalError)
$ jupyterhub
...
$ jupyterhub upgrade-db
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 19c0846f6344, base revision for 0.5
INFO  [alembic.runtime.migration] Running upgrade 19c0846f6344 -> eeb276e51423, auth_state
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context
context)
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/engine/default.py", line 470, in do_execute
cursor.execute(statement, parameters)
sqlite3.OperationalError: duplicate column name: auth_state

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/usr/local/bin/alembic", line 11, in <module>
sys.exit(main())
File "/usr/local/lib/python3.5/dist-packages/alembic/config.py", line 479, in main
CommandLine(prog=prog).main(argv=argv)
File "/usr/local/lib/python3.5/dist-packages/alembic/config.py", line 473, in main
self.run_cmd(cfg, options)
File "/usr/local/lib/python3.5/dist-packages/alembic/config.py", line 456, in run_cmd
**dict((k, getattr(options, k, None)) for k in kwarg)
File "/usr/local/lib/python3.5/dist-packages/alembic/command.py", line 254, in upgrade
script.run_env()
File "/usr/local/lib/python3.5/dist-packages/alembic/script/base.py", line 416, in run_env
util.load_python_file(self.dir, 'env.py')
File "/usr/local/lib/python3.5/dist-packages/alembic/util/pyfiles.py", line 93, in load_python_file
module = load_module_py(module_id, path)
File "/usr/local/lib/python3.5/dist-packages/alembic/util/compat.py", line 64, in load_module_py
module_id, path).load_module(module_id)
File "<frozen importlib._bootstrap_external>", line 388, in _check_name_wrapper
File "<frozen importlib._bootstrap_external>", line 809, in load_module
File "<frozen importlib._bootstrap_external>", line 668, in load_module
File "<frozen importlib._bootstrap>", line 268, in _load_module_shim
File "<frozen importlib._bootstrap>", line 693, in _load
File "<frozen importlib._bootstrap>", line 673, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 665, in exec_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
File "/usr/local/lib/python3.5/dist-packages/jupyterhub/alembic/env.py", line 70, in <module>
run_migrations_online()
File "/usr/local/lib/python3.5/dist-packages/jupyterhub/alembic/env.py", line 65, in run_migrations_online
context.run_migrations()
File "<string>", line 8, in run_migrations
File "/usr/local/lib/python3.5/dist-packages/alembic/runtime/environment.py", line 817, in run_migrations
self.get_context().run_migrations(**kw)
File "/usr/local/lib/python3.5/dist-packages/alembic/runtime/migration.py", line 323, in run_migrations
step.migration_fn(**kw)
File "/usr/local/lib/python3.5/dist-packages/jupyterhub/alembic/versions/eeb276e51423_auth_state.py", line 21, in upgrade
op.add_column('users', sa.Column('auth_state', JSONDict))
File "<string>", line 8, in add_column
File "<string>", line 3, in add_column
File "/usr/local/lib/python3.5/dist-packages/alembic/operations/ops.py", line 1551, in add_column
return operations.invoke(op)
File "/usr/local/lib/python3.5/dist-packages/alembic/operations/base.py", line 318, in invoke
return fn(self, operation)
File "/usr/local/lib/python3.5/dist-packages/alembic/operations/toimpl.py", line 123, in add_column
schema=schema
File "/usr/local/lib/python3.5/dist-packages/alembic/ddl/impl.py", line 172, in add_column
self._exec(base.AddColumn(table_name, column, schema=schema))
File "/usr/local/lib/python3.5/dist-packages/alembic/ddl/impl.py", line 118, in _exec
return conn.execute(construct, *multiparams, **params)
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/engine/base.py", line 945, in execute
return meth(self, multiparams, params)
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/sql/ddl.py", line 68, in _execute_on_connection
return connection._execute_ddl(self, multiparams, params)
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/engine/base.py", line 1002, in _execute_ddl
compiled
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/engine/base.py", line 1189, in _execute_context
context)
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/engine/base.py", line 1402, in _handle_dbapi_exception
exc_info
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb, cause=cause)
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/util/compat.py", line 186, in reraise
raise value.with_traceback(tb)
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/engine/base.py", line 1182, in _execute_context
context)
File "/usr/local/lib/python3.5/dist-packages/sqlalchemy/engine/default.py", line 470, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) duplicate column name: auth_state [SQL: 'ALTER TABLE users ADD COLUMN auth_state TEXT']
[E 2017-06-02 19:55:16.017 JupyterHub app:1527]
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/jupyterhub/app.py", line 1525, in launch_instance_async
yield self.start()
File "/usr/local/lib/python3.5/dist-packages/jupyterhub/app.py", line 1436, in start
self.subapp.start()
File "/usr/local/lib/python3.5/dist-packages/jupyterhub/app.py", line 185, in start
dbutil.upgrade(hub.db_url)
File "/usr/local/lib/python3.5/dist-packages/jupyterhub/dbutil.py", line 80, in upgrade
['alembic', '-c', alembic_ini, 'upgrade', revision]
File "/usr/lib/python3.5/subprocess.py", line 581, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['alembic', '-c', '/tmp/tmpkqvnuq0a/alembic.ini', 'upgrade', 'head']' returned non-zero exit status 1

# Fixed code
def new_session_factory(url="sqlite:///:memory:", reset=False, **kwargs):
    """Create a new session at url"""
    if url.startswith("sqlite"):
        kwargs.setdefault("connect_args", {"check_same_thread": False})
    elif url.startswith("mysql"):
        kwargs.setdefault("pool_recycle", 60)

    if url.endswith(":memory:"):
        # If we're using an in-memory database, ensure that only one connection
        # is ever created.
        kwargs.setdefault("poolclass", StaticPool)

    engine = create_engine(url, **kwargs)
    if reset:
        Base.metadata.drop_all(engine)

    # check the db revision (will raise, pointing to `upgrade-db` if version doesn't match)
    check_db_revision(engine)
    Base.metadata.create_all(engine)

    session_factory = sessionmaker(bind=engine)
    return session_factory