title: SQLAlchemy session.begin() giving transaction error when context manager doesn't
body: <p>In short, why am I getting an &quot;sqlalchemy.exc.InvalidRequestError: A transaction is already begun.  Use subtransactions=True to allow subtransactions&quot; error?</p>
  <p>Following the best practices of separating and keeping the session external, I created <code>foo(input)</code> with a context manager instead of using the try / except / else. If I use <code>foo(user)</code> instead of it I get the above error. My guess is that <code>foo()</code> isn't committing and closing the connection. <a href="https://docs.sqlalchemy.org/en/14/orm/session_transaction.html" rel="nofollow noreferrer">Howevere the documentation states otherwise.</a></p>
  <p><a href="https://flask.palletsprojects.com/en/1.1.x/patterns/sqlalchemy/" rel="nofollow noreferrer">Flask documentation</a> uses a <code>scoped_session</code> but the <a href="https://docs.sqlalchemy.org/en/14/orm/contextual.html#using-thread-local-scope-with-web-applications" rel="nofollow noreferrer">SQLAlchemy documentation</a> says &quot;It is however strongly recommended that the integration tools provided with the web framework itself be used, if available, instead of scoped_session.&quot; Perhaps the <code>scoped_session</code> is causing errors across threads with the requests?</p>
  <p>Here is my main code:</p>
  <pre><code>#__init__.py
  import os
  
  from flask import Flask, render_template, redirect, request, url_for
  
  
  def create_app(test_config=None):
      # create and configure the app
      app = Flask(__name__, instance_relative_config=False)
      app.config.from_object('config.DevelopmentConfig')
      
      # set up extensions
      # all flask extensions must support factory pattern
      # can run these two steps from the cli
      from app.database import init_db
      init_db()
  
      
      @app.route('/')
      def index():
          return render_template('index.html')
  
      from app.auth import RegistrationForm
      from app.models import User
      from app.database import db_session, foo
  
      @app.route('/register', methods=['GET', 'POST'])
      def register():
          form = RegistrationForm(request.form)
          if request.method == 'POST' and form.validate():
              user = User(form.name.data, form.email.data,
                          form.password.data)
              foo(user)
              # try:
              #     db_session.add(user)
              # except:
              #     db_session.rollback()
              #     raise
              # else:
              #     db_session.commit()
              return redirect(url_for('login'))
          return render_template('register.html', form=form)
  
      
      @app.route('/login', methods=['GET'])
      def login():
          return render_template('login.html')
      
  
      @app.teardown_appcontext
      def shutdown_session(exception=None):
          db_session.remove()
      
      return app
  </code></pre>
  <p>Here is my database code:</p>
  <pre><code>#database.py
  from sqlalchemy import create_engine 
  from sqlalchemy.orm import scoped_session, sessionmaker 
  from sqlalchemy.ext.declarative import declarative_base
  
  _database_uri = os.environ['DATABASE_URL'] engine = create_engine(_database_uri)
  db_session = scoped_session(sessionmaker(autocommit=False,
                                           autoflush=False,
                                           bind=engine))
  
  Base = declarative_base() Base.query = db_session.query_property()
  
  def init_db():
      # import all modules here that might define models so that
      # they will be registered properly on the metadata.  Otherwise
      # you will have to import them first before calling init_db()
      import app.models
      Base.metadata.create_all(bind=engine)
  
  
  def foo(input):
      with db_session.begin() as session:
          session.add(input)
  </code></pre>