<p dir="auto"><strong>Migrated issue, originally created by Anonymous</strong></p>
<p dir="auto">We are doing some stuff with history and have a little problem.</p>
<p dir="auto">After commit, history has been reseted to empty state: there no value in <code class="notranslate">unchanged</code> and after attribute is changed there is no value in <code class="notranslate">deleted</code>.</p>
<p dir="auto">Probably, it is a bug. If it is correct behaviour, how is it expained?</p>
<p dir="auto">Both on 0.8.2 and dev versions. Here is a test case.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="class HistoryTest(_fixtures.FixtureTest):
    run_inserts = None

    def test_commit_history(self):
        from sqlalchemy.orm.attributes import get_history, History

        User, users = self.classes.User, self.tables.users

        m2 = sa.MetaData()
        users_unbound = users.tometadata(m2)
        mapper(User, users_unbound)

        sess = Session(binds={User: self.metadata.bind})
        u = User(id=1, name='daniel')
        sess.add(u)
        print get_history(u, 'name')
        assert get_history(u, 'name') ==\
                         History(['daniel']('daniel'), (), ())

        sess.commit()
        print get_history(u, 'name')
        assert get_history(u, 'name') == \
                         History((), ['daniel']('daniel'), ())
                         # fails: History((), (), ())

        u.name = 'peter'
        print get_history(u, 'name')
        assert get_history(u, 'name') == \
                         History(['peter']('peter'), (), ['daniel']('daniel'))
                         # fails: History(['peter']('peter'), (), ())"><pre class="notranslate"><code class="notranslate">class HistoryTest(_fixtures.FixtureTest):
    run_inserts = None

    def test_commit_history(self):
        from sqlalchemy.orm.attributes import get_history, History

        User, users = self.classes.User, self.tables.users

        m2 = sa.MetaData()
        users_unbound = users.tometadata(m2)
        mapper(User, users_unbound)

        sess = Session(binds={User: self.metadata.bind})
        u = User(id=1, name='daniel')
        sess.add(u)
        print get_history(u, 'name')
        assert get_history(u, 'name') ==\
                         History(['daniel']('daniel'), (), ())

        sess.commit()
        print get_history(u, 'name')
        assert get_history(u, 'name') == \
                         History((), ['daniel']('daniel'), ())
                         # fails: History((), (), ())

        u.name = 'peter'
        print get_history(u, 'name')
        assert get_history(u, 'name') == \
                         History(['peter']('peter'), (), ['daniel']('daniel'))
                         # fails: History(['peter']('peter'), (), ())
</code></pre></div>
<hr>
<p dir="auto">Attachments: <a href="../wiki/imported_issue_attachments/2787/2787.patch">2787.patch</a></p>
<p dir="auto">Unittest an API, where test code fixture is trying to create a resource and then get the response to verify the previous step, and then again to try to create the same resource again, SqlAlchemy is randomizing the exception between Integrity and Flush Error.</p>
<p dir="auto">Libs:<br>
Flask==1.0.2<br>
Flask-Cors==3.0.6<br>
Flask-SQLAlchemy==2.3.2<br>
SQLAlchemy==1.2.7<br>
Werkzeug==0.14.1</p>
<p dir="auto">I have been working on that project for the last 10 month, all the time I have seen only Integrity error, not flush error.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="        new_item.before_created(request_data)
        db.session.add(new_item)
        new_item.after_created(request_data)
        db.session.commit()

        headers = {'Location': new_item.get_url()} if new_item.get_url() else None
        return (jsonify({}), 201, headers) if headers else (jsonify({}), 201)
    except KeyError as e:
        raise ValidationError(
            ErrorCode.MISSING_MANDATORY_DATA,
            error_msg=f&quot;the {e.args[0]} field is required.&quot;,
        )
    except ValueError as e:
        raise ValidationError(ErrorCode.INVALID_REQUEST_DATA, error_msg=e.args[0])
    except BadRequest:
        raise ValidationError(ErrorCode.INVALID_REQUEST_FORMAT)
    except IntegrityError:
        raise ValidationError(ErrorCode.INTEGRITY_ERROR, status_code=409)
    except Conflict as e:
        raise ValidationError(e.description, status_code=409)
    finally:
        db.session.rollback()"><pre class="notranslate"><code class="notranslate">        new_item.before_created(request_data)
        db.session.add(new_item)
        new_item.after_created(request_data)
        db.session.commit()

        headers = {'Location': new_item.get_url()} if new_item.get_url() else None
        return (jsonify({}), 201, headers) if headers else (jsonify({}), 201)
    except KeyError as e:
        raise ValidationError(
            ErrorCode.MISSING_MANDATORY_DATA,
            error_msg=f"the {e.args[0]} field is required.",
        )
    except ValueError as e:
        raise ValidationError(ErrorCode.INVALID_REQUEST_DATA, error_msg=e.args[0])
    except BadRequest:
        raise ValidationError(ErrorCode.INVALID_REQUEST_FORMAT)
    except IntegrityError:
        raise ValidationError(ErrorCode.INTEGRITY_ERROR, status_code=409)
    except Conflict as e:
        raise ValidationError(e.description, status_code=409)
    finally:
        db.session.rollback()
</code></pre></div>
<p dir="auto">TEST CODE:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="    def test_create_new_product(self):
          Product.delete(self.product_no, True)

    # create a asset with the request data.
    response = self.client.post(
        &quot;/assets/&quot;,
        content_type=&quot;application/json&quot;,
        data=json.dumps(self.default_req_data),
    )
    res_data = json.loads(response.data.decode())
    self.assertEqual({}, res_data)
    self.assertEqual(response.status_code, 201)

    # check the asset that we already created.
    response = self.client.get(
        &quot;/assets/{0}&quot;.format(self.product_no), content_type=&quot;application/json&quot;
    )
    res_data = json.loads(response.data.decode())
    self.assertEqual(response.status_code, 200)

    for key in self.default_req_data.keys():
        self.assertEqual(self.default_req_data[key], res_data[key])

    # try create duplicated asset
    response = self.client.post(
        &quot;/assets/&quot;,
        content_type=&quot;application/json&quot;,
        data=json.dumps(self.default_req_data),
    )
    res_data = json.loads(response.data.decode())
    self.assertEqual(response.status_code, 409)"><pre class="notranslate"><code class="notranslate">    def test_create_new_product(self):
          Product.delete(self.product_no, True)

    # create a asset with the request data.
    response = self.client.post(
        "/assets/",
        content_type="application/json",
        data=json.dumps(self.default_req_data),
    )
    res_data = json.loads(response.data.decode())
    self.assertEqual({}, res_data)
    self.assertEqual(response.status_code, 201)

    # check the asset that we already created.
    response = self.client.get(
        "/assets/{0}".format(self.product_no), content_type="application/json"
    )
    res_data = json.loads(response.data.decode())
    self.assertEqual(response.status_code, 200)

    for key in self.default_req_data.keys():
        self.assertEqual(self.default_req_data[key], res_data[key])

    # try create duplicated asset
    response = self.client.post(
        "/assets/",
        content_type="application/json",
        data=json.dumps(self.default_req_data),
    )
    res_data = json.loads(response.data.decode())
    self.assertEqual(response.status_code, 409)
</code></pre></div>
<p dir="auto">This fixture is called by several other fixtures but all them get Integrity error except one of them is getting flushError.</p>
<p dir="auto">If I run all the test together I am facing this issue, alone it works fine.</p>