)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"f604b210f579956f2e411878daff9e0d9c2dbd83","unresolved":false,"context_lines":[{"line_number":16,"context_line":"which must be detected and fixed."},{"line_number":17,"context_line":"Fortunately, we can now rely on alembic + sqlalchemy implementation"},{"line_number":18,"context_line":"of schema comparison instead of writing our own tools."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"Mirrored from: I0758c7e09d1d46ce870c3f94f76c2a177955e143"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"Blueprint: sync-models-with-migrations"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"7adec928_17dd8ee0","line":19,"updated":"2014-05-15 08:51:41.000000000","message":"I\u0027m pretty sure, that you missed \"co-authored-with\" line","commit_id":"9fbd4dd0b3d669252c3d74932365dd1a2b2124fb"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"94eca556ac0b86aa7f9dcd07970aa29cc93be67e","unresolved":false,"context_lines":[{"line_number":16,"context_line":"which must be detected and fixed."},{"line_number":17,"context_line":"Fortunately, we can now rely on alembic + sqlalchemy implementation"},{"line_number":18,"context_line":"of schema comparison instead of writing our own tools."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"Mirrored from: I0758c7e09d1d46ce870c3f94f76c2a177955e143"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"Blueprint: sync-models-with-migrations"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"7adec928_777c12b6","line":19,"in_reply_to":"7adec928_17dd8ee0","updated":"2014-05-15 08:57:48.000000000","message":"This is not co-authored. I did not done not any line in it. So I put line 20 with the link to the original patch. But if you insist I\u0027ll put Co-Authored line here.","commit_id":"9fbd4dd0b3d669252c3d74932365dd1a2b2124fb"}],"oslo/db/sqlalchemy/test_migrations.py":[{"author":{"_account_id":2472,"name":"Doug Hellmann","email":"dhellmann@redhat.com","username":"doug-hellmann"},"change_message_id":"a0a95dd7d98dff840ccd1ee994f4b35a0a30bd76","unresolved":false,"context_lines":[{"line_number":393,"context_line":"    def test_models_sync(self):"},{"line_number":394,"context_line":"        # recent versions of sqlalchemy and alembic are needed for running of"},{"line_number":395,"context_line":"        # this test, but we already have them in requirements"},{"line_number":396,"context_line":"        sa_version \u003d tuple(int(p) for p in sqlalchemy.__version__.split(\u0027.\u0027))"},{"line_number":397,"context_line":"        alembic_version \u003d tuple(int(p) for p in alembic.__version__.split(\u0027.\u0027))"},{"line_number":398,"context_line":"        if not (sa_version \u003e (0, 8, 3) and alembic_version \u003e (0, 6, 2)):"},{"line_number":399,"context_line":"            self.skipTest(\u0027sqlalchemy\u003e\u003d0.8.4 and alembic\u003e\u003d0.6.3 are required\u0027"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_cff13603","line":396,"updated":"2014-06-16 14:09:56.000000000","message":"Using the __version__ private attribute depends on the author continuing to use that technique to set their version. A more reliable way that works for any package installed via setuptools is to use pkg_resources.\n\n  import pkg_resources\n  dist \u003d pkg_resources.get_distribution(\u0027sqlalchemy\u0027)\n  sa_version \u003d dist.version.split(\u0027.\u0027)\n\nIn this case, you should use pkg_resources.require() to ensure that a requirement is installed. It will raise DistributionNotFound for missing packages and VersionConflict for packages using a version that does not match the requirement.\n\n  try:\n    pkg_resources.require(\u0027sqlalchemy\u003e\u003d0.8.4\u0027, \u0027alembic\u003e\u003d0.6.3\u0027)\n  except (pkg_resources.VersionConflict, pkg_resources.DistributionNotFound) as e:\n    self.skipTest(\u0027Skipping because requirements for model testing not installed: %s\u0027 % e)\n\nBesides not relying on the (possibly missing) __version__ attribute of the package, pkg_resources has the advantage that it knows how to deal with alpha and dev release versions, which include values like \u00271.0.0.0a1\u0027 and \u00270.15.7.gff1f0fd\u0027 that won\u0027t parse with the logic you have here because some of the fields aren\u0027t integers.\n\nhttps://pythonhosted.org/setuptools/pkg_resources.html#basic-workingset-methods","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"d0d382bffbeaeb237754eb744bd10593768203fc","unresolved":false,"context_lines":[{"line_number":393,"context_line":"    def test_models_sync(self):"},{"line_number":394,"context_line":"        # recent versions of sqlalchemy and alembic are needed for running of"},{"line_number":395,"context_line":"        # this test, but we already have them in requirements"},{"line_number":396,"context_line":"        sa_version \u003d tuple(int(p) for p in sqlalchemy.__version__.split(\u0027.\u0027))"},{"line_number":397,"context_line":"        alembic_version \u003d tuple(int(p) for p in alembic.__version__.split(\u0027.\u0027))"},{"line_number":398,"context_line":"        if not (sa_version \u003e (0, 8, 3) and alembic_version \u003e (0, 6, 2)):"},{"line_number":399,"context_line":"            self.skipTest(\u0027sqlalchemy\u003e\u003d0.8.4 and alembic\u003e\u003d0.6.3 are required\u0027"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_138fa476","line":396,"in_reply_to":"1ae5cdf2_2a07e81e","updated":"2014-06-17 10:28:07.000000000","message":"The approach recommended by Doug seems to me very clear and correct, since we guaranteed use Setuptools. So I prefer to implement it here.","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42ac14effefd7eaef668bfdf5a0d8d5eea98c89c","unresolved":false,"context_lines":[{"line_number":393,"context_line":"    def test_models_sync(self):"},{"line_number":394,"context_line":"        # recent versions of sqlalchemy and alembic are needed for running of"},{"line_number":395,"context_line":"        # this test, but we already have them in requirements"},{"line_number":396,"context_line":"        sa_version \u003d tuple(int(p) for p in sqlalchemy.__version__.split(\u0027.\u0027))"},{"line_number":397,"context_line":"        alembic_version \u003d tuple(int(p) for p in alembic.__version__.split(\u0027.\u0027))"},{"line_number":398,"context_line":"        if not (sa_version \u003e (0, 8, 3) and alembic_version \u003e (0, 6, 2)):"},{"line_number":399,"context_line":"            self.skipTest(\u0027sqlalchemy\u003e\u003d0.8.4 and alembic\u003e\u003d0.6.3 are required\u0027"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_2a07e81e","line":396,"in_reply_to":"1ae5cdf2_cff13603","updated":"2014-06-16 15:08:28.000000000","message":"sqlalchemy.__version__ isn\u0027t private, it\u0027s documented and is free to use.   I wasn\u0027t sure where I got this convention from originally, so I tracked down http://legacy.python.org/dev/peps/pep-0396/ which talks about the __version__ attribute as a Python standard practice.    \n\nthough this is outside of my pay grade, I tend to be -1 on relying upon setuptools to get versions of things as I often like to run tests and things in environments that aren\u0027t necessarily 100% setuptools oriented (like, I\u0027ll use PYTHONPATH quite often instead).   But this is more of a personal thing, obviously within Openstack it\u0027s standard practice to use packages installed in virtualenvs.  And the point about parsing the version id is a good one.   Our version numbers should meet verlib spec: https://pypi.python.org/pypi/verlib if parsing __version__ directly were a concern.","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42ac14effefd7eaef668bfdf5a0d8d5eea98c89c","unresolved":false,"context_lines":[{"line_number":395,"context_line":"        # this test, but we already have them in requirements"},{"line_number":396,"context_line":"        sa_version \u003d tuple(int(p) for p in sqlalchemy.__version__.split(\u0027.\u0027))"},{"line_number":397,"context_line":"        alembic_version \u003d tuple(int(p) for p in alembic.__version__.split(\u0027.\u0027))"},{"line_number":398,"context_line":"        if not (sa_version \u003e (0, 8, 3) and alembic_version \u003e (0, 6, 2)):"},{"line_number":399,"context_line":"            self.skipTest(\u0027sqlalchemy\u003e\u003d0.8.4 and alembic\u003e\u003d0.6.3 are required\u0027"},{"line_number":400,"context_line":"                          \u0027 for running of this test.\u0027)"},{"line_number":401,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_c50d97ea","line":398,"updated":"2014-06-16 15:08:28.000000000","message":"would this be clearer as:\n\n    if sa_version \u003c (0, 8, 4) or alembic_version \u003c (0, 6, 3):\n\n?","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"d0d382bffbeaeb237754eb744bd10593768203fc","unresolved":false,"context_lines":[{"line_number":395,"context_line":"        # this test, but we already have them in requirements"},{"line_number":396,"context_line":"        sa_version \u003d tuple(int(p) for p in sqlalchemy.__version__.split(\u0027.\u0027))"},{"line_number":397,"context_line":"        alembic_version \u003d tuple(int(p) for p in alembic.__version__.split(\u0027.\u0027))"},{"line_number":398,"context_line":"        if not (sa_version \u003e (0, 8, 3) and alembic_version \u003e (0, 6, 2)):"},{"line_number":399,"context_line":"            self.skipTest(\u0027sqlalchemy\u003e\u003d0.8.4 and alembic\u003e\u003d0.6.3 are required\u0027"},{"line_number":400,"context_line":"                          \u0027 for running of this test.\u0027)"},{"line_number":401,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_33e1002b","line":398,"in_reply_to":"1ae5cdf2_c50d97ea","updated":"2014-06-17 10:28:07.000000000","message":"As I implement Doug\u0027s tip, this line is removed.","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42ac14effefd7eaef668bfdf5a0d8d5eea98c89c","unresolved":false,"context_lines":[{"line_number":403,"context_line":"        def cleanup():"},{"line_number":404,"context_line":"            meta \u003d sqlalchemy.MetaData(bind\u003dself.get_engine())"},{"line_number":405,"context_line":"            meta.reflect()"},{"line_number":406,"context_line":"            meta.drop_all()"},{"line_number":407,"context_line":"            # for PostgreSQL ENUM types aren\u0027t reflected and dropped; drop them"},{"line_number":408,"context_line":"            # using the corresponding definitions from models metadata"},{"line_number":409,"context_line":"            self.get_metadata().drop_all(bind\u003dself.get_engine())"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_c5fcb775","line":406,"updated":"2014-06-16 15:08:28.000000000","message":"this is fine for now but there are more robust/efficient ways of dropping all tables (and other things that might be present like views) we might want to look into.  the recipe at https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/DropEverything is the basic idea.  it doesn\u0027t spend time reflecting all the columns and datatypes and also can handle the case where foreign key dependencies are in a cycle between tables.","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"d0d382bffbeaeb237754eb744bd10593768203fc","unresolved":false,"context_lines":[{"line_number":403,"context_line":"        def cleanup():"},{"line_number":404,"context_line":"            meta \u003d sqlalchemy.MetaData(bind\u003dself.get_engine())"},{"line_number":405,"context_line":"            meta.reflect()"},{"line_number":406,"context_line":"            meta.drop_all()"},{"line_number":407,"context_line":"            # for PostgreSQL ENUM types aren\u0027t reflected and dropped; drop them"},{"line_number":408,"context_line":"            # using the corresponding definitions from models metadata"},{"line_number":409,"context_line":"            self.get_metadata().drop_all(bind\u003dself.get_engine())"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_562afae7","line":406,"in_reply_to":"1ae5cdf2_c5fcb775","updated":"2014-06-17 10:28:07.000000000","message":"I had implemented `cleanup` method in appropriate with your recipe.","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"42ac14effefd7eaef668bfdf5a0d8d5eea98c89c","unresolved":false,"context_lines":[{"line_number":421,"context_line":"            mc \u003d alembic.migration.MigrationContext.configure(conn, opts\u003dopts)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"            # compare schemas and fail with diff, if it\u0027s not empty"},{"line_number":424,"context_line":"            diff \u003d alembic.autogenerate.compare_metadata(mc,"},{"line_number":425,"context_line":"                                                         self.get_metadata())"},{"line_number":426,"context_line":"            if diff:"},{"line_number":427,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_c59d970c","line":424,"updated":"2014-06-16 15:08:28.000000000","message":"hmmmm.    I think I need to understand better what we really want to accomplish here.   alembic\u0027s compare_metadata won\u0027t catch lots of things, and other things it might get wrong, like table or column renames.   What is the case where a database has an alembic_version table, the version number in that table is correct compared to what\u0027s in the version scripts, but the answer is still wrong?  are we trying to catch where someone added new model elements but forgot to create new migration scripts?","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"b9d1dbefe66a32937e9f680ac43f39ab910699e2","unresolved":false,"context_lines":[{"line_number":421,"context_line":"            mc \u003d alembic.migration.MigrationContext.configure(conn, opts\u003dopts)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"            # compare schemas and fail with diff, if it\u0027s not empty"},{"line_number":424,"context_line":"            diff \u003d alembic.autogenerate.compare_metadata(mc,"},{"line_number":425,"context_line":"                                                         self.get_metadata())"},{"line_number":426,"context_line":"            if diff:"},{"line_number":427,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_d22dfffe","line":424,"in_reply_to":"1ae5cdf2_3eafcf2c","updated":"2014-06-18 08:11:38.000000000","message":"I\u0027m sorry, I can\u0027t find you in OpenStack IRC channels. Can you, please, tell me your  irc nick and channels where I can talk to you? Thanks!","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"fcb71d19549991332ab85eed2ba2c05465fdb247","unresolved":false,"context_lines":[{"line_number":421,"context_line":"            mc \u003d alembic.migration.MigrationContext.configure(conn, opts\u003dopts)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"            # compare schemas and fail with diff, if it\u0027s not empty"},{"line_number":424,"context_line":"            diff \u003d alembic.autogenerate.compare_metadata(mc,"},{"line_number":425,"context_line":"                                                         self.get_metadata())"},{"line_number":426,"context_line":"            if diff:"},{"line_number":427,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_3eafcf2c","line":424,"in_reply_to":"1ae5cdf2_9f01ee06","updated":"2014-06-18 07:53:55.000000000","message":"Let\u0027s talk about this approach in IRC.","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"d0d382bffbeaeb237754eb744bd10593768203fc","unresolved":false,"context_lines":[{"line_number":421,"context_line":"            mc \u003d alembic.migration.MigrationContext.configure(conn, opts\u003dopts)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"            # compare schemas and fail with diff, if it\u0027s not empty"},{"line_number":424,"context_line":"            diff \u003d alembic.autogenerate.compare_metadata(mc,"},{"line_number":425,"context_line":"                                                         self.get_metadata())"},{"line_number":426,"context_line":"            if diff:"},{"line_number":427,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_f94db7c6","line":424,"in_reply_to":"1ae5cdf2_c59d970c","updated":"2014-06-17 10:28:07.000000000","message":"The main idea is to compare actual models and migrations. It must have 100% conformity, in purpose to prevent any database errors related with database and models nonconformity. So, yes, we are trying to catch where someone added new model elements but forgot to create new migration scripts. Is compare_metadata correct choice for our purposes?","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"ae27882af2af78c0f327b880157b8baeb7eca932","unresolved":false,"context_lines":[{"line_number":421,"context_line":"            mc \u003d alembic.migration.MigrationContext.configure(conn, opts\u003dopts)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"            # compare schemas and fail with diff, if it\u0027s not empty"},{"line_number":424,"context_line":"            diff \u003d alembic.autogenerate.compare_metadata(mc,"},{"line_number":425,"context_line":"                                                         self.get_metadata())"},{"line_number":426,"context_line":"            if diff:"},{"line_number":427,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_caf37671","line":424,"in_reply_to":"1ae5cdf2_d22dfffe","updated":"2014-06-18 15:20:55.000000000","message":"hi ilya -  \n\nmy nick is \u0027zzzeek\u0027 and i am typically on openstack-dev , openstack-oslo and openstack-nova at the moment.   \n\n- mike","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"76a78bb79907923ed50c76d73d7aed7796fb9a92","unresolved":false,"context_lines":[{"line_number":421,"context_line":"            mc \u003d alembic.migration.MigrationContext.configure(conn, opts\u003dopts)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"            # compare schemas and fail with diff, if it\u0027s not empty"},{"line_number":424,"context_line":"            diff \u003d alembic.autogenerate.compare_metadata(mc,"},{"line_number":425,"context_line":"                                                         self.get_metadata())"},{"line_number":426,"context_line":"            if diff:"},{"line_number":427,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"}],"source_content_type":"text/x-python","patch_set":4,"id":"1ae5cdf2_9f01ee06","line":424,"in_reply_to":"1ae5cdf2_f94db7c6","updated":"2014-06-17 13:13:25.000000000","message":"there\u0027s no function available that guarantees anywhere near 100% conformity.  Alembic\u0027s autogenerate feature only knows to suggest \"candidate\" migrations when comparing a database to a metadata instance, which must then be manually authored for full correctness - it only handles table/column adds and removals, some constraint/index changes, and optionally changes in datatypes/server defaults with many caveats.  See the guidelines at http://alembic.readthedocs.org/en/latest/tutorial.html#auto-generating-migrations.","commit_id":"d2365340480988c0872f3e0677a337ed2ac72536"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"90a911afb4c121fce6051874b663a35ac3e0818b","unresolved":false,"context_lines":[{"line_number":18,"context_line":"import functools"},{"line_number":19,"context_line":"import logging"},{"line_number":20,"context_line":"import os"},{"line_number":21,"context_line":"import pkg_resources as pkg"},{"line_number":22,"context_line":"import pprint"},{"line_number":23,"context_line":"import subprocess"},{"line_number":24,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"1ae5cdf2_3ce468ab","line":21,"updated":"2014-06-18 08:01:58.000000000","message":"I\u0027m not sure, but it seems to be, that `pkg_resources` - is this party library","commit_id":"aeb6c703cf64ac08cabc7a052870312716dd95f0"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"e6deeaf780f7fe769675c9f7f78d99753fffadf4","unresolved":false,"context_lines":[{"line_number":18,"context_line":"import functools"},{"line_number":19,"context_line":"import logging"},{"line_number":20,"context_line":"import os"},{"line_number":21,"context_line":"import pkg_resources as pkg"},{"line_number":22,"context_line":"import pprint"},{"line_number":23,"context_line":"import subprocess"},{"line_number":24,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"1ae5cdf2_524e4fc3","line":21,"in_reply_to":"1ae5cdf2_3ce468ab","updated":"2014-06-19 05:03:19.000000000","message":"Yes, you are right.","commit_id":"aeb6c703cf64ac08cabc7a052870312716dd95f0"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"90a911afb4c121fce6051874b663a35ac3e0818b","unresolved":false,"context_lines":[{"line_number":425,"context_line":"        try:"},{"line_number":426,"context_line":"            pkg.require(\u0027sqlalchemy\u003e\u003d0.8.4\u0027, \u0027alembic\u003e\u003d0.6.2\u0027)"},{"line_number":427,"context_line":"        except (pkg.VersionConflict, pkg.DistributionNotFound) as e:"},{"line_number":428,"context_line":"            self.skipTest(\u0027Skipping because requirements\u0027"},{"line_number":429,"context_line":"                          \u0027 for model testing not installed: %s\u0027 % e)"},{"line_number":430,"context_line":""},{"line_number":431,"context_line":"        # drop all tables after a test run"}],"source_content_type":"text/x-python","patch_set":5,"id":"1ae5cdf2_1cfc0c3f","line":428,"updated":"2014-06-18 08:01:58.000000000","message":"IMO, the previous message was more clear","commit_id":"aeb6c703cf64ac08cabc7a052870312716dd95f0"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"e6deeaf780f7fe769675c9f7f78d99753fffadf4","unresolved":false,"context_lines":[{"line_number":425,"context_line":"        try:"},{"line_number":426,"context_line":"            pkg.require(\u0027sqlalchemy\u003e\u003d0.8.4\u0027, \u0027alembic\u003e\u003d0.6.2\u0027)"},{"line_number":427,"context_line":"        except (pkg.VersionConflict, pkg.DistributionNotFound) as e:"},{"line_number":428,"context_line":"            self.skipTest(\u0027Skipping because requirements\u0027"},{"line_number":429,"context_line":"                          \u0027 for model testing not installed: %s\u0027 % e)"},{"line_number":430,"context_line":""},{"line_number":431,"context_line":"        # drop all tables after a test run"}],"source_content_type":"text/x-python","patch_set":5,"id":"1ae5cdf2_9248d7b4","line":428,"in_reply_to":"1ae5cdf2_1cfc0c3f","updated":"2014-06-19 05:03:19.000000000","message":"Agree, I will fix it.","commit_id":"aeb6c703cf64ac08cabc7a052870312716dd95f0"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"70b491db761c57bcfc45b84010bc23fbe13137c7","unresolved":false,"context_lines":[{"line_number":294,"context_line":"    The difference between MODELS and MIGRATION scripts will be printed and"},{"line_number":295,"context_line":"    the test will fail, if the difference is not empty."},{"line_number":296,"context_line":""},{"line_number":297,"context_line":"    Method include_object() can be overriden to exclude some tables from"},{"line_number":298,"context_line":"    comparison (e.g. migrate_repo)."},{"line_number":299,"context_line":""},{"line_number":300,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"1ae5cdf2_691aec7d","line":297,"updated":"2014-06-23 13:32:14.000000000","message":"nit: overridden","commit_id":"4062b32da2f1e08f94c0502ca383718fde3f7976"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"47625b13ae5027a9efab719b2b1ca1ea70243640","unresolved":false,"context_lines":[{"line_number":294,"context_line":"    The difference between MODELS and MIGRATION scripts will be printed and"},{"line_number":295,"context_line":"    the test will fail, if the difference is not empty."},{"line_number":296,"context_line":""},{"line_number":297,"context_line":"    Method include_object() can be overriden to exclude some tables from"},{"line_number":298,"context_line":"    comparison (e.g. migrate_repo)."},{"line_number":299,"context_line":""},{"line_number":300,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"1ae5cdf2_8728fc86","line":297,"in_reply_to":"1ae5cdf2_691aec7d","updated":"2014-06-23 15:57:17.000000000","message":"Done","commit_id":"4062b32da2f1e08f94c0502ca383718fde3f7976"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"70b491db761c57bcfc45b84010bc23fbe13137c7","unresolved":false,"context_lines":[{"line_number":426,"context_line":"            pkg.require(\u0027sqlalchemy\u003e\u003d0.8.4\u0027, \u0027alembic\u003e\u003d0.6.2\u0027)"},{"line_number":427,"context_line":"        except (pkg.VersionConflict, pkg.DistributionNotFound) as e:"},{"line_number":428,"context_line":"            self.skipTest(\u0027sqlalchemy\u003e\u003d0.8.4 and alembic\u003e\u003d0.6.3 are required\u0027"},{"line_number":429,"context_line":"                          \u0027 for running of this test:\u0027 % e)"},{"line_number":430,"context_line":""},{"line_number":431,"context_line":"        # drop all tables after a test run"},{"line_number":432,"context_line":"        self.addCleanup(self._cleanup)"}],"source_content_type":"text/x-python","patch_set":6,"id":"1ae5cdf2_8909f886","line":429,"updated":"2014-06-23 13:32:14.000000000","message":"missed placeholder for ``e``","commit_id":"4062b32da2f1e08f94c0502ca383718fde3f7976"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"47625b13ae5027a9efab719b2b1ca1ea70243640","unresolved":false,"context_lines":[{"line_number":426,"context_line":"            pkg.require(\u0027sqlalchemy\u003e\u003d0.8.4\u0027, \u0027alembic\u003e\u003d0.6.2\u0027)"},{"line_number":427,"context_line":"        except (pkg.VersionConflict, pkg.DistributionNotFound) as e:"},{"line_number":428,"context_line":"            self.skipTest(\u0027sqlalchemy\u003e\u003d0.8.4 and alembic\u003e\u003d0.6.3 are required\u0027"},{"line_number":429,"context_line":"                          \u0027 for running of this test:\u0027 % e)"},{"line_number":430,"context_line":""},{"line_number":431,"context_line":"        # drop all tables after a test run"},{"line_number":432,"context_line":"        self.addCleanup(self._cleanup)"}],"source_content_type":"text/x-python","patch_set":6,"id":"1ae5cdf2_2731e8ed","line":429,"in_reply_to":"1ae5cdf2_8909f886","updated":"2014-06-23 15:57:17.000000000","message":"Done","commit_id":"4062b32da2f1e08f94c0502ca383718fde3f7976"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"484a124fe7f8d529c48d4f23cc81460987773dad","unresolved":false,"context_lines":[{"line_number":444,"context_line":""},{"line_number":445,"context_line":"            # compare schemas and fail with diff, if it\u0027s not empty"},{"line_number":446,"context_line":"            diff \u003d alembic.autogenerate.compare_metadata(mc,"},{"line_number":447,"context_line":"                                                         self.get_metadata())"},{"line_number":448,"context_line":"            if diff:"},{"line_number":449,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"},{"line_number":450,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"1ae5cdf2_0d59f834","line":447,"updated":"2014-06-18 15:25:05.000000000","message":"we\u0027ll talk more in IRC, but I\u0027ll note it\u0027s not a *bad* thing to do this test, it will catch big things, like tables/columns and indexes that forgot to get added.  it just will often not catch lots of other things.","commit_id":"4062b32da2f1e08f94c0502ca383718fde3f7976"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"924de9fedd230241b1e13f54eaae56cf07e00355","unresolved":false,"context_lines":[{"line_number":444,"context_line":""},{"line_number":445,"context_line":"            # compare schemas and fail with diff, if it\u0027s not empty"},{"line_number":446,"context_line":"            diff \u003d alembic.autogenerate.compare_metadata(mc,"},{"line_number":447,"context_line":"                                                         self.get_metadata())"},{"line_number":448,"context_line":"            if diff:"},{"line_number":449,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"},{"line_number":450,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"1ae5cdf2_9167c3e9","line":447,"in_reply_to":"1ae5cdf2_0d59f834","updated":"2014-06-19 08:07:31.000000000","message":"Thanks! That is good.","commit_id":"4062b32da2f1e08f94c0502ca383718fde3f7976"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"220525fefef131e315ddc3bc1484f78d01590b21","unresolved":false,"context_lines":[{"line_number":448,"context_line":"            if diff:"},{"line_number":449,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"},{"line_number":450,"context_line":""},{"line_number":451,"context_line":"                LOG.error("},{"line_number":452,"context_line":"                    \"Models and migration scripts aren\u0027t in sync:\\n%s\" % msg)"},{"line_number":453,"context_line":"                raise AssertionError"}],"source_content_type":"text/x-python","patch_set":10,"id":"baada198_ff71ac0c","line":451,"updated":"2014-07-04 09:30:26.000000000","message":"I\u0027d prefer to see difference on stdout, and not looking for in in log","commit_id":"09b2adbd842f98019e16a66165210bb62fc2a32b"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"d2b62125e65c54af5a615035790bd9f31b3ddc76","unresolved":false,"context_lines":[{"line_number":448,"context_line":"            if diff:"},{"line_number":449,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"},{"line_number":450,"context_line":""},{"line_number":451,"context_line":"                LOG.error("},{"line_number":452,"context_line":"                    \"Models and migration scripts aren\u0027t in sync:\\n%s\" % msg)"},{"line_number":453,"context_line":"                raise AssertionError"}],"source_content_type":"text/x-python","patch_set":10,"id":"baada198_70b309e9","line":451,"in_reply_to":"baada198_ff71ac0c","updated":"2014-07-04 11:21:22.000000000","message":"Done. Now it\u0027s in stderr, AssertError raised directly with the message.","commit_id":"09b2adbd842f98019e16a66165210bb62fc2a32b"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"18b125de1e48088ef0ac4d59b53e3a15188b3170","unresolved":false,"context_lines":[{"line_number":394,"context_line":"        return None  # tells alembic to use the default comparison method"},{"line_number":395,"context_line":""},{"line_number":396,"context_line":"    def _cleanup(self):"},{"line_number":397,"context_line":"        engine \u003d self.get_engine()"},{"line_number":398,"context_line":"        with engine.begin() as conn:"},{"line_number":399,"context_line":"            inspector \u003d reflection.Inspector.from_engine(engine)"},{"line_number":400,"context_line":"            metadata \u003d schema.MetaData()"}],"source_content_type":"text/x-python","patch_set":11,"id":"baada198_981a58c4","line":397,"updated":"2014-07-07 14:33:14.000000000","message":"oh this is my cleanup() code, right :).    Maybe a function \"drop_schema()\" should be part of oslo.db.utils.","commit_id":"716a9650d7eba0180bb2f37606db8c16af37664f"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"9de37d199dc2f005a86d378d872c19fb4250eb55","unresolved":false,"context_lines":[{"line_number":394,"context_line":"        return None  # tells alembic to use the default comparison method"},{"line_number":395,"context_line":""},{"line_number":396,"context_line":"    def _cleanup(self):"},{"line_number":397,"context_line":"        engine \u003d self.get_engine()"},{"line_number":398,"context_line":"        with engine.begin() as conn:"},{"line_number":399,"context_line":"            inspector \u003d reflection.Inspector.from_engine(engine)"},{"line_number":400,"context_line":"            metadata \u003d schema.MetaData()"}],"source_content_type":"text/x-python","patch_set":11,"id":"baada198_33424dae","line":397,"in_reply_to":"baada198_981a58c4","updated":"2014-07-07 16:05:00.000000000","message":"This is it :) Seems to me like a good idea. But I\u0027m sure that people will insist for a separated patch.","commit_id":"716a9650d7eba0180bb2f37606db8c16af37664f"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"b76bb6d044ae449c137ee77efc3ba7ae551af24a","unresolved":false,"context_lines":[{"line_number":447,"context_line":"                                                         self.get_metadata())"},{"line_number":448,"context_line":"            if diff:"},{"line_number":449,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"},{"line_number":450,"context_line":"                raise AssertionError("},{"line_number":451,"context_line":"                    \"Models and migration scripts aren\u0027t in sync:\\n%s\" % msg)"}],"source_content_type":"text/x-python","patch_set":11,"id":"baada198_36534ae3","line":450,"updated":"2014-07-04 15:12:50.000000000","message":"self.fail() do actually the same thing","commit_id":"716a9650d7eba0180bb2f37606db8c16af37664f"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"9de37d199dc2f005a86d378d872c19fb4250eb55","unresolved":false,"context_lines":[{"line_number":447,"context_line":"                                                         self.get_metadata())"},{"line_number":448,"context_line":"            if diff:"},{"line_number":449,"context_line":"                msg \u003d pprint.pformat(diff, indent\u003d2, width\u003d20)"},{"line_number":450,"context_line":"                raise AssertionError("},{"line_number":451,"context_line":"                    \"Models and migration scripts aren\u0027t in sync:\\n%s\" % msg)"}],"source_content_type":"text/x-python","patch_set":11,"id":"baada198_8c377bfe","line":450,"in_reply_to":"baada198_36534ae3","updated":"2014-07-07 16:05:00.000000000","message":"Hmmm... really. Done","commit_id":"716a9650d7eba0180bb2f37606db8c16af37664f"}],"tests/sqlalchemy/test_migrations.py":[{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"5dad391717e91354594be55aaa119430d97a2f16","unresolved":false,"context_lines":[{"line_number":218,"context_line":"    def test_models_not_sync(self):"},{"line_number":219,"context_line":"        self.metadata_migrations.clear()"},{"line_number":220,"context_line":"        sa.Table("},{"line_number":221,"context_line":"            \u0027testtbl3\u0027, self.metadata_migrations,"},{"line_number":222,"context_line":"            sa.Column(\u0027id\u0027, sa.Integer, primary_key\u003dTrue),"},{"line_number":223,"context_line":"            sa.Column(\u0027spam\u0027, sa.String(8), nullable\u003dTrue),"},{"line_number":224,"context_line":"            sa.Column(\u0027eggs\u0027, sa.DateTime),"}],"source_content_type":"text/x-python","patch_set":8,"id":"baada198_2572b57c","line":221,"updated":"2014-07-01 14:43:40.000000000","message":"Actually I don\u0027t like this non-DRY way, but alternative is metaclass and it looks pretty complex for just a test case.","commit_id":"d8a32adfb71a1e9370372a4c1e49844cfef02d65"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"9d64e67ad6b3deb2ef4c5ec499b178e465d2216c","unresolved":false,"context_lines":[{"line_number":218,"context_line":"    def test_models_not_sync(self):"},{"line_number":219,"context_line":"        self.metadata_migrations.clear()"},{"line_number":220,"context_line":"        sa.Table("},{"line_number":221,"context_line":"            \u0027testtbl3\u0027, self.metadata_migrations,"},{"line_number":222,"context_line":"            sa.Column(\u0027id\u0027, sa.Integer, primary_key\u003dTrue),"},{"line_number":223,"context_line":"            sa.Column(\u0027spam\u0027, sa.String(8), nullable\u003dTrue),"},{"line_number":224,"context_line":"            sa.Column(\u0027eggs\u0027, sa.DateTime),"}],"source_content_type":"text/x-python","patch_set":8,"id":"baada198_66e3d407","line":221,"in_reply_to":"baada198_2572b57c","updated":"2014-07-01 15:22:21.000000000","message":"well, so why don\u0027t you make something like this:\n\n class ModelsMigrationSyncMixin(test.BaseTestCase):\n     ...\n     def _test_models_not_sync(self):\n         ...\n         self.assertRaises(AssertionError, self.test_models_sync)\n\n\n class ModelsMigrationsSyncMysql(ModelsMigrationSyncMixin,\n                                 migrate.ModelsMigrationsSync,\n                                 test_base.MySQLOpportunisticTestCase):\n\n     def test_models_not_sync(self):\n         self._test_models_not_sync()","commit_id":"d8a32adfb71a1e9370372a4c1e49844cfef02d65"},{"author":{"_account_id":6928,"name":"Ben Nemec","email":"openstack@nemebean.com","username":"bnemec"},"change_message_id":"46976d8db10894a856a7fdb484df40c82ad592f4","unresolved":false,"context_lines":[{"line_number":218,"context_line":"    def test_models_not_sync(self):"},{"line_number":219,"context_line":"        self.metadata_migrations.clear()"},{"line_number":220,"context_line":"        sa.Table("},{"line_number":221,"context_line":"            \u0027testtbl3\u0027, self.metadata_migrations,"},{"line_number":222,"context_line":"            sa.Column(\u0027id\u0027, sa.Integer, primary_key\u003dTrue),"},{"line_number":223,"context_line":"            sa.Column(\u0027spam\u0027, sa.String(8), nullable\u003dTrue),"},{"line_number":224,"context_line":"            sa.Column(\u0027eggs\u0027, sa.DateTime),"}],"source_content_type":"text/x-python","patch_set":8,"id":"baada198_2cf45d5a","line":221,"in_reply_to":"baada198_66e3d407","updated":"2014-07-01 16:17:49.000000000","message":"That\u0027s more what I had in mind for this too.","commit_id":"d8a32adfb71a1e9370372a4c1e49844cfef02d65"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"8c9dea07eed1b610f512d31e422fa845e33b41d7","unresolved":false,"context_lines":[{"line_number":218,"context_line":"    def test_models_not_sync(self):"},{"line_number":219,"context_line":"        self.metadata_migrations.clear()"},{"line_number":220,"context_line":"        sa.Table("},{"line_number":221,"context_line":"            \u0027testtbl3\u0027, self.metadata_migrations,"},{"line_number":222,"context_line":"            sa.Column(\u0027id\u0027, sa.Integer, primary_key\u003dTrue),"},{"line_number":223,"context_line":"            sa.Column(\u0027spam\u0027, sa.String(8), nullable\u003dTrue),"},{"line_number":224,"context_line":"            sa.Column(\u0027eggs\u0027, sa.DateTime),"}],"source_content_type":"text/x-python","patch_set":8,"id":"baada198_9bbbc4e4","line":221,"in_reply_to":"baada198_66e3d407","updated":"2014-07-02 08:41:05.000000000","message":"There is no test_models_sync method on mix-in. So, it is possible to add negative test in the mix-in as metadata modifier and use it later in ultimate test cases.\n\nbtw, there is an approach with metaclass http://goo.gl/w1tgFG.\n\nDone.","commit_id":"d8a32adfb71a1e9370372a4c1e49844cfef02d65"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"1814ce2cbdde379221c53271cb850f612005bf8a","unresolved":false,"context_lines":[{"line_number":218,"context_line":"    def test_models_not_sync(self):"},{"line_number":219,"context_line":"        self.metadata_migrations.clear()"},{"line_number":220,"context_line":"        sa.Table("},{"line_number":221,"context_line":"            \u0027testtbl3\u0027, self.metadata_migrations,"},{"line_number":222,"context_line":"            sa.Column(\u0027id\u0027, sa.Integer, primary_key\u003dTrue),"},{"line_number":223,"context_line":"            sa.Column(\u0027spam\u0027, sa.String(8), nullable\u003dTrue),"},{"line_number":224,"context_line":"            sa.Column(\u0027eggs\u0027, sa.DateTime),"}],"source_content_type":"text/x-python","patch_set":8,"id":"baada198_7715eae3","line":221,"in_reply_to":"baada198_9bbbc4e4","updated":"2014-07-03 12:55:43.000000000","message":"Fixed, please see the comment in the next patch set.","commit_id":"d8a32adfb71a1e9370372a4c1e49844cfef02d65"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"78707a8b507d536d82be803c836a9bd983563ebc","unresolved":false,"context_lines":[{"line_number":228,"context_line":"            sa.Column(\u0027bar\u0027, sa.BigInteger),"},{"line_number":229,"context_line":"            sa.UniqueConstraint(\u0027spam\u0027, \u0027foo\u0027, name\u003d\u0027uniq_cons\u0027),"},{"line_number":230,"context_line":"        )"},{"line_number":231,"context_line":"        self.assertRaises(AssertionError, self.test_models_sync)"},{"line_number":232,"context_line":""},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"class ModelsMigrationsSyncPsql(ModelsMigrationSyncMixin,"}],"source_content_type":"text/x-python","patch_set":8,"id":"baada198_862548c4","line":231,"updated":"2014-07-01 15:35:38.000000000","message":"also it\u0027s would be really nice to check error message here","commit_id":"d8a32adfb71a1e9370372a4c1e49844cfef02d65"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"1814ce2cbdde379221c53271cb850f612005bf8a","unresolved":false,"context_lines":[{"line_number":228,"context_line":"            sa.Column(\u0027bar\u0027, sa.BigInteger),"},{"line_number":229,"context_line":"            sa.UniqueConstraint(\u0027spam\u0027, \u0027foo\u0027, name\u003d\u0027uniq_cons\u0027),"},{"line_number":230,"context_line":"        )"},{"line_number":231,"context_line":"        self.assertRaises(AssertionError, self.test_models_sync)"},{"line_number":232,"context_line":""},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"class ModelsMigrationsSyncPsql(ModelsMigrationSyncMixin,"}],"source_content_type":"text/x-python","patch_set":8,"id":"baada198_77b40a35","line":231,"in_reply_to":"baada198_862548c4","updated":"2014-07-03 12:55:43.000000000","message":"This trivial issue became pretty difficult to realize.\n\n* The log string has no guarantee of logged items order.\n* The log string contains memory addresses (which will never be the same), so if we are comparing strings as strings we must use regexp.\n* There is a lot of parentheses, so regexp become very long and critical complex, with all of this escaping.\n* We cant parse json from the string, because it is not valid json — amount of python objects used in the log string.\n\nChosen an occult approach: to check is it contains \"Models and migration scripts aren\u0027t in sync\" substring or not. This approach doesn\u0027t give us assurance that log is correct, but in this way we know for sure, that our test failed in the correct place.","commit_id":"d8a32adfb71a1e9370372a4c1e49844cfef02d65"},{"author":{"_account_id":6849,"name":"Roman Podoliaka","email":"roman.podoliaka@gmail.com","username":"rpodolyaka"},"change_message_id":"c5f9120fe21d4da8458f312cc3e6a5e21af2187a","unresolved":false,"context_lines":[{"line_number":231,"context_line":""},{"line_number":232,"context_line":"    def test_models_not_sync(self):"},{"line_number":233,"context_line":"        super(ModelsMigrationsSyncMysql, self)._test_models_not_sync()"},{"line_number":234,"context_line":"        self.assertRaises(AssertionError, self.test_models_sync)"},{"line_number":235,"context_line":""},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"class ModelsMigrationsSyncPsql(ModelsMigrationSyncMixin,"}],"source_content_type":"text/x-python","patch_set":9,"id":"baada198_522f4af6","line":234,"updated":"2014-07-02 10:09:03.000000000","message":"not a big deal, but why not use the version suggested by Victor here? we could move the assertion into the base method and we won\u0027t need super() anymore","commit_id":"38e9720f3edecf5aa700154c04a5fc741d3dde27"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"69da7b6db3df2f9f3b2604f94e4ea03e8c0a7bf2","unresolved":false,"context_lines":[{"line_number":231,"context_line":""},{"line_number":232,"context_line":"    def test_models_not_sync(self):"},{"line_number":233,"context_line":"        super(ModelsMigrationsSyncMysql, self)._test_models_not_sync()"},{"line_number":234,"context_line":"        self.assertRaises(AssertionError, self.test_models_sync)"},{"line_number":235,"context_line":""},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"class ModelsMigrationsSyncPsql(ModelsMigrationSyncMixin,"}],"source_content_type":"text/x-python","patch_set":9,"id":"baada198_5c4c8dc8","line":234,"in_reply_to":"baada198_522f4af6","updated":"2014-07-03 12:56:24.000000000","message":"In some strange circumstances this approach haven\u0027t worked. But today, with Victor, I realized that now it works well. So, fixed. Thanks you, guys!","commit_id":"38e9720f3edecf5aa700154c04a5fc741d3dde27"},{"author":{"_account_id":6928,"name":"Ben Nemec","email":"openstack@nemebean.com","username":"bnemec"},"change_message_id":"5c7043cc978eff47dcef5cb1b8c9ddf390156925","unresolved":false,"context_lines":[{"line_number":229,"context_line":"        )"},{"line_number":230,"context_line":""},{"line_number":231,"context_line":"        self.assertRaises(AssertionError, self.test_models_sync)"},{"line_number":232,"context_line":"        self.assertIn(\u0027Models and migration scripts aren\\\u0027t in sync:\u0027,"},{"line_number":233,"context_line":"                      self.stream.output)"},{"line_number":234,"context_line":""},{"line_number":235,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"baada198_e02da8ff","line":232,"updated":"2014-07-03 17:02:12.000000000","message":"It might be nice to also assert table/column/constraint names in the output, assuming those are included.  That would give us pretty solid evidence that this is finding the errors we expect.","commit_id":"09b2adbd842f98019e16a66165210bb62fc2a32b"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"d2b62125e65c54af5a615035790bd9f31b3ddc76","unresolved":false,"context_lines":[{"line_number":229,"context_line":"        )"},{"line_number":230,"context_line":""},{"line_number":231,"context_line":"        self.assertRaises(AssertionError, self.test_models_sync)"},{"line_number":232,"context_line":"        self.assertIn(\u0027Models and migration scripts aren\\\u0027t in sync:\u0027,"},{"line_number":233,"context_line":"                      self.stream.output)"},{"line_number":234,"context_line":""},{"line_number":235,"context_line":""}],"source_content_type":"text/x-python","patch_set":10,"id":"baada198_30bd11b8","line":232,"in_reply_to":"baada198_e02da8ff","updated":"2014-07-04 11:21:22.000000000","message":"Done","commit_id":"09b2adbd842f98019e16a66165210bb62fc2a32b"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"bd5908f397695e67c5ed9a35c28f5d474eb8c6a9","unresolved":false,"context_lines":[{"line_number":230,"context_line":"        try:"},{"line_number":231,"context_line":"            self.test_models_sync()"},{"line_number":232,"context_line":"        except AssertionError as e:"},{"line_number":233,"context_line":"            msg \u003d unicode(e)"},{"line_number":234,"context_line":"            self.assertTrue(msg.startswith("},{"line_number":235,"context_line":"                \u0027Models and migration scripts aren\\\u0027t in sync:\u0027))"},{"line_number":236,"context_line":"            # NOTE(I159): Check mentioning of the table and columns."}],"source_content_type":"text/x-python","patch_set":11,"id":"baada198_a1937959","line":233,"updated":"2014-07-07 06:53:29.000000000","message":"I\u0027m really not sure, that this is preferred way to get error message. This at least will fail with py3","commit_id":"716a9650d7eba0180bb2f37606db8c16af37664f"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"9de37d199dc2f005a86d378d872c19fb4250eb55","unresolved":false,"context_lines":[{"line_number":230,"context_line":"        try:"},{"line_number":231,"context_line":"            self.test_models_sync()"},{"line_number":232,"context_line":"        except AssertionError as e:"},{"line_number":233,"context_line":"            msg \u003d unicode(e)"},{"line_number":234,"context_line":"            self.assertTrue(msg.startswith("},{"line_number":235,"context_line":"                \u0027Models and migration scripts aren\\\u0027t in sync:\u0027))"},{"line_number":236,"context_line":"            # NOTE(I159): Check mentioning of the table and columns."}],"source_content_type":"text/x-python","patch_set":11,"id":"baada198_cc5c1380","line":233,"in_reply_to":"baada198_38cdcc66","updated":"2014-07-07 16:05:00.000000000","message":"Thanks, this is crucial. I haven\u0027t thought that assert functions can return something, haven\u0027t even tried \u003d) cool\n\nDone.","commit_id":"716a9650d7eba0180bb2f37606db8c16af37664f"},{"author":{"_account_id":6928,"name":"Ben Nemec","email":"openstack@nemebean.com","username":"bnemec"},"change_message_id":"a43fe7aefc5e58822a0b94ac0880b75e6bbbfb4b","unresolved":false,"context_lines":[{"line_number":230,"context_line":"        try:"},{"line_number":231,"context_line":"            self.test_models_sync()"},{"line_number":232,"context_line":"        except AssertionError as e:"},{"line_number":233,"context_line":"            msg \u003d unicode(e)"},{"line_number":234,"context_line":"            self.assertTrue(msg.startswith("},{"line_number":235,"context_line":"                \u0027Models and migration scripts aren\\\u0027t in sync:\u0027))"},{"line_number":236,"context_line":"            # NOTE(I159): Check mentioning of the table and columns."}],"source_content_type":"text/x-python","patch_set":11,"id":"baada198_ac827fc5","line":233,"in_reply_to":"baada198_38cdcc66","updated":"2014-07-07 15:37:40.000000000","message":"six.text_type is the right way to get the message out of the exception.","commit_id":"716a9650d7eba0180bb2f37606db8c16af37664f"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"18b125de1e48088ef0ac4d59b53e3a15188b3170","unresolved":false,"context_lines":[{"line_number":230,"context_line":"        try:"},{"line_number":231,"context_line":"            self.test_models_sync()"},{"line_number":232,"context_line":"        except AssertionError as e:"},{"line_number":233,"context_line":"            msg \u003d unicode(e)"},{"line_number":234,"context_line":"            self.assertTrue(msg.startswith("},{"line_number":235,"context_line":"                \u0027Models and migration scripts aren\\\u0027t in sync:\u0027))"},{"line_number":236,"context_line":"            # NOTE(I159): Check mentioning of the table and columns."}],"source_content_type":"text/x-python","patch_set":11,"id":"baada198_38cdcc66","line":233,"in_reply_to":"baada198_a1937959","updated":"2014-07-07 14:33:14.000000000","message":"self.assertRaises() will return the exception object, so that should be used to run test_models_sync here.  then for the unicode(), we can use six.str() or whatever six supplies.","commit_id":"716a9650d7eba0180bb2f37606db8c16af37664f"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"ed73836e2a36f0b218068d8200b26bd27d0e7da3","unresolved":false,"context_lines":[{"line_number":160,"context_line":""},{"line_number":161,"context_line":"class ModelsMigrationSyncMixin(test.BaseTestCase):"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"    longMessage \u003d True"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"    def setUp(self):"},{"line_number":166,"context_line":"        super(ModelsMigrationSyncMixin, self).setUp()"}],"source_content_type":"text/x-python","patch_set":12,"id":"baada198_45319f58","line":163,"updated":"2014-07-08 06:17:23.000000000","message":"why do we need this?","commit_id":"47ee8f2ecdbbadfd1c90e7d6ac8376564f9e133a"},{"author":{"_account_id":7536,"name":"Ilya Pekelny","email":"ipekelny@mirantis.com","username":"I159"},"change_message_id":"7119750e686061d8801048c0e1fd262ca9ed969c","unresolved":false,"context_lines":[{"line_number":160,"context_line":""},{"line_number":161,"context_line":"class ModelsMigrationSyncMixin(test.BaseTestCase):"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"    longMessage \u003d True"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"    def setUp(self):"},{"line_number":166,"context_line":"        super(ModelsMigrationSyncMixin, self).setUp()"}],"source_content_type":"text/x-python","patch_set":12,"id":"baada198_6843da6b","line":163,"in_reply_to":"baada198_45319f58","updated":"2014-07-08 07:14:26.000000000","message":"We don\u0027t. I forgot it to delete. Thanks!","commit_id":"47ee8f2ecdbbadfd1c90e7d6ac8376564f9e133a"}]}
