diff --git a/CHANGES.rst b/CHANGES.rst
index 601d3d4..f29b756 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -24,6 +24,7 @@
 * New: ``coaster.utils.classmethodproperty``: like a property, but for class
   methods
 * New: ``coaster.views.endpoint_for``: discover an endpoint given a URL
+* Changed: ``UuidMixin`` no longer provides ``url_id``
 
 
 0.6.0
diff --git a/coaster/sqlalchemy/mixins.py b/coaster/sqlalchemy/mixins.py
index 47454f8..48e1e6b 100644
--- a/coaster/sqlalchemy/mixins.py
+++ b/coaster/sqlalchemy/mixins.py
@@ -102,31 +102,8 @@ class UuidMixin(object):
     """
     Provides a ``uuid`` attribute that is either a SQL UUID column or an alias
     to the existing ``id`` column if the class uses UUID primary keys. Also
-    provides hybrid properties ``url_id``, ``buid`` and ``suuid`` that provide
-    hex, BUID and ShortUUID representations of the ``uuid`` column.
-
-    :class:`UuidMixin` must appear before other classes in the base class order::
-
-        class MyDocument(UuidMixin, BaseMixin, db.Model):
-            pass
-
-    Compatibility table:
-
-    +-----------------------+-------------+-----------------------------------------+
-    | Base class            | Compatible? | Notes                                   |
-    +=======================+=============+=========================================+
-    | BaseMixin             | Yes         |                                         |
-    +-----------------------+-------------+-----------------------------------------+
-    | BaseIdNameMixin       | Yes         |                                         |
-    +-----------------------+-------------+-----------------------------------------+
-    | BaseNameMixin         | N/A         | ``name`` is secondary key, not ``uuid`` |
-    +-----------------------+-------------+-----------------------------------------+
-    | BaseScopedNameMixin   | N/A         | ``name`` is secondary key, not ``uuid`` |
-    +-----------------------+-------------+-----------------------------------------+
-    | BaseScopedIdMixin     | No          | Conflicting :attr:`url_id` attribute    |
-    +-----------------------+-------------+-----------------------------------------+
-    | BaseScopedIdNameMixin | No          | Conflicting :attr:`url_id` attribute    |
-    +-----------------------+-------------+-----------------------------------------+
+    provides hybrid properties ``huuid``, ``buid`` and ``suuid`` that provide
+    hex, URL-safe Base64 and ShortUUID representations of the ``uuid`` column.
     """
     @with_roles(read={'all'})
     @declared_attr
@@ -138,12 +115,12 @@ class UuidMixin(object):
             return immutable(Column(UUIDType(binary=False), default=uuid_.uuid4, unique=True, nullable=False))
 
     @hybrid_property
-    def url_id(self):
+    def huuid(self):
         """URL-friendly UUID representation as a hex string"""
         return self.uuid.hex
 
-    @url_id.comparator
-    def url_id(cls):
+    @huuid.comparator
+    def huuid(cls):
         # For some reason the test fails if we use `cls.uuid` here
         # but works fine in the `buid` and `suuid` comparators below
         if hasattr(cls, '__uuid_primary_key__') and cls.__uuid_primary_key__:
@@ -151,7 +128,7 @@ class UuidMixin(object):
         else:
             return SqlHexUuidComparator(cls.uuid)
 
-    url_id = with_roles(url_id, read={'all'})
+    huuid = with_roles(huuid, read={'all'})
 
     @hybrid_property
     def buid(self):
@@ -564,9 +541,9 @@ class BaseIdNameMixin(BaseMixin):
     @hybrid_property
     def url_id_name(self):
         """
-        Returns a URL name combining :attr:`url_id` and :attr:`name` in id-name
-        syntax. This property is also available as :attr:`url_name` for legacy
-        reasons.
+        Returns a URL name combining :attr:`url_id` and :attr:`name` in
+        id-name syntax. This property is also available as :attr:`url_name`
+        for legacy reasons.
         """
         return '%s-%s' % (self.url_id, self.name)
 
@@ -574,8 +551,6 @@ class BaseIdNameMixin(BaseMixin):
     def url_id_name(cls):
         if cls.__uuid_primary_key__:
             return SqlHexUuidComparator(cls.id, splitindex=0)
-        elif issubclass(cls, UuidMixin):
-            return SqlHexUuidComparator(cls.uuid, splitindex=0)
         else:
             return SqlSplitIdComparator(cls.id, splitindex=0)
 
@@ -588,19 +563,11 @@ class BaseIdNameMixin(BaseMixin):
         Returns a URL name combining :attr:`name` and :attr:`suuid` in name-suuid syntax.
         To use this, the class must derive from :class:`UuidMixin`.
         """
-        if isinstance(self, UuidMixin):
-            return '%s-%s' % (self.name, self.suuid)
-        else:
-            return '%s-%s' % (self.name, self.url_id)
+        return '%s-%s' % (self.name, self.suuid)
 
     @url_name_suuid.comparator
     def url_name_suuid(cls):
-        if issubclass(cls, UuidMixin):
-            return SqlSuuidComparator(cls.uuid, splitindex=-1)
-        elif cls.__uuid_primary_key__:
-            return SqlHexUuidComparator(cls.id, splitindex=-1)
-        else:
-            return SqlSplitIdComparator(cls.id, splitindex=-1)
+        return SqlSuuidComparator(cls.uuid, splitindex=-1)
 
 
 class BaseScopedIdMixin(BaseMixin):

UuidMixin conflicts with BaseScopedIdMixin and BaseScopedIdNameMixin
The conflict derives from conflicting uses of the `url_id` attribute. Both mixins provide it, but one provides a column while the other provides a rendering of a UUID.

In the migration from Talkfunnel.com to HasGeek.com, we want to use both simultaneously, with the scoped numbering on the existing Talkfunnel site and UUID-based URLs on the new site. This requires using both mixins at once, so the conflict needs to be removed somehow. One proposal: move `UuidMixin`'s `url_id` into another mixin. We are unlikely to be using UUID `url_id` since the general pattern has been to move to SUUID. However, a survey of existing code is necessary.
diff --git a/tests/test_models.py b/tests/test_models.py
index cc788e4..bac428c 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -623,9 +623,15 @@ class TestCoasterModels(unittest.TestCase):
 
     def test_uuid_url_id(self):
         """
-        IdMixin and UuidMixin provide a url_id that renders as a string of
-        either the integer primary key or the UUID primary key
+        IdMixin provides a url_id that renders as a string of either the
+        integer primary key or the UUID primary key. In addition, UuidMixin
+        provides a huuid that always renders a UUID against either the
+        id or uuid columns.
         """
+        # TODO: This test is a little muddled because UuidMixin renamed
+        # its url_id property (which overrode IdMixin's url_id) to huuid.
+        # This test needs to be broken down into separate tests for each of
+        # these properties.
         u1 = NonUuidKey()
         u2 = UuidKey()
         u3 = NonUuidMixinKey()
@@ -648,14 +654,14 @@ class TestCoasterModels(unittest.TestCase):
         self.assertFalse('-' in u2.url_id)  # Without dashes
 
         self.assertIsInstance(i3, uuid.UUID)
-        self.assertEqual(u3.url_id, i3.hex)
-        self.assertEqual(len(u3.url_id), 32)  # This is a 32-byte hex representation
-        self.assertFalse('-' in u3.url_id)  # Without dashes
+        self.assertEqual(u3.huuid, i3.hex)
+        self.assertEqual(len(u3.huuid), 32)  # This is a 32-byte hex representation
+        self.assertFalse('-' in u3.huuid)  # Without dashes
 
         self.assertIsInstance(i4, uuid.UUID)
-        self.assertEqual(u4.url_id, i4.hex)
-        self.assertEqual(len(u4.url_id), 32)  # This is a 32-byte hex representation
-        self.assertFalse('-' in u4.url_id)  # Without dashes
+        self.assertEqual(u4.huuid, i4.hex)
+        self.assertEqual(len(u4.huuid), 32)  # This is a 32-byte hex representation
+        self.assertFalse('-' in u4.huuid)  # Without dashes
 
         # Querying against `url_id` redirects the query to
         # `id` (IdMixin) or `uuid` (UuidMixin).
@@ -672,7 +678,7 @@ class TestCoasterModels(unittest.TestCase):
             "non_uuid_key.id = '1'")
 
         # With UUID primary keys, `url_id` casts the value into a UUID
-        # and then queries against `id` or ``uuid``
+        # and then queries against `id`
 
         # Note that `literal_binds` here doesn't know how to render UUIDs if
         # no engine is specified, and so casts them into a string. We test this
@@ -715,7 +721,7 @@ class TestCoasterModels(unittest.TestCase):
                 ).compile(compile_kwargs={'literal_binds': True})),
             "non_uuid_key.id IS NULL")
         self.assertEqual(
-            six.text_type((NonUuidMixinKey.url_id == None  # NOQA
+            six.text_type((NonUuidMixinKey.huuid == None  # NOQA
                 ).compile(compile_kwargs={'literal_binds': True})),
             "non_uuid_mixin_key.uuid IS NULL")
 
@@ -729,11 +735,11 @@ class TestCoasterModels(unittest.TestCase):
 
         # Repeat against UuidMixin classes (with only hex keys for brevity)
         self.assertEqual(
-            six.text_type((NonUuidMixinKey.url_id == '74d588574a7611e78c27c38403d0935c'
+            six.text_type((NonUuidMixinKey.huuid == '74d588574a7611e78c27c38403d0935c'
                 ).compile(compile_kwargs={'literal_binds': True})),
             "non_uuid_mixin_key.uuid = '74d588574a7611e78c27c38403d0935c'")
         self.assertEqual(
-            six.text_type((UuidMixinKey.url_id == '74d588574a7611e78c27c38403d0935c'
+            six.text_type((UuidMixinKey.huuid == '74d588574a7611e78c27c38403d0935c'
                 ).compile(compile_kwargs={'literal_binds': True})),
             "uuid_mixin_key.id = '74d588574a7611e78c27c38403d0935c'")
 
@@ -843,13 +849,15 @@ class TestCoasterModels(unittest.TestCase):
 
         self.assertEqual(u1.url_id, '74d588574a7611e78c27c38403d0935c')
         self.assertEqual(u1.url_id_name, '74d588574a7611e78c27c38403d0935c-test')
-        # No UuidMixin means no suuid, so fallback to hex UUID
-        self.assertEqual(u1.url_name_suuid, 'test-74d588574a7611e78c27c38403d0935c')
-        self.assertEqual(u2.url_id, '74d588574a7611e78c27c38403d0935c')
+        # No suuid without UuidMixin
+        with self.assertRaises(AttributeError):
+            self.assertEqual(u1.url_name_suuid, 'test-vVoaZTeXGiD4qrMtYNosnN')
+        self.assertEqual(u2.huuid, '74d588574a7611e78c27c38403d0935c')
         self.assertEqual(u2.url_id_name, '74d588574a7611e78c27c38403d0935c-test')
         self.assertEqual(u2.url_name_suuid, 'test-vVoaZTeXGiD4qrMtYNosnN')
-        self.assertEqual(u3.url_id, '74d588574a7611e78c27c38403d0935c')
-        self.assertEqual(u3.url_id_name, '74d588574a7611e78c27c38403d0935c-test')
+        self.assertEqual(u3.huuid, '74d588574a7611e78c27c38403d0935c')
+        # url_id_name in BaseIdNameMixin uses the id column, not the uuid column
+        self.assertEqual(u3.url_id_name, '1-test')
         self.assertEqual(u3.url_name_suuid, 'test-vVoaZTeXGiD4qrMtYNosnN')
 
         # url_name is legacy
diff --git a/tests/test_roles.py b/tests/test_roles.py
index e7cefb1..765bc3a 100644
--- a/tests/test_roles.py
+++ b/tests/test_roles.py
@@ -155,7 +155,7 @@ class TestCoasterRoles(unittest.TestCase):
 
     def test_uuidmixin_roles(self):
         """A model with UuidMixin provides 'all' read access to uuid, url_id, buid and suuid"""
-        self.assertLessEqual({'uuid', 'url_id', 'buid', 'suuid'}, UuidModel.__roles__['all']['read'])
+        self.assertLessEqual({'uuid', 'huuid', 'buid', 'suuid'}, UuidModel.__roles__['all']['read'])
 
     def test_roles_for_anon(self):
         """An anonymous actor should have 'all' and 'anon' roles"""
diff --git a/tests/test_statemanager.py b/tests/test_statemanager.py
index c436b74..d9ec599 100644
--- a/tests/test_statemanager.py
+++ b/tests/test_statemanager.py
@@ -593,7 +593,7 @@ class TestStateManager(unittest.TestCase):
         """State managers maintain the order of transitions from the class definition"""
         self.assertTrue(self.post.state.DRAFT)
         # `submit` must come before `publish`
-        self.assertEqual(list(self.post.state.transitions(current=False).keys()[:2]), ['submit', 'publish'])
+        self.assertEqual(list(self.post.state.transitions(current=False).keys())[:2], ['submit', 'publish'])
 
     def test_currently_available_transitions(self):
         """State managers indicate the currently available transitions (using current_auth)"""

pip install -e .[dev]
parse_log_pytest
requirements.txt
3.6
test_requirements.txt dev_requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alembic==1.7.7
attrs==22.2.0
bcrypt==4.0.1
bleach==4.1.0
blinker==1.5
certifi==2021.5.30
charset-normalizer==2.0.12
click==8.0.4
-e git+https://github.com/hasgeek/coaster.git@837b984370ed0a06511dd7a3b31f61e340d7cb4d#egg=coaster
coverage==6.2
coveralls==3.3.1
dataclasses==0.8
docflow==0.3.3
docopt==0.6.2
filelock==3.4.1
Flask==2.0.3
Flask-Assets==2.1.0
Flask-Migrate==4.0.1
Flask-Script==2.0.6
Flask-SQLAlchemy==2.5.1
greenlet==2.0.2
html2text==2020.1.16
html5lib==1.1
idna==3.10
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
isoweek==1.3.3
itsdangerous==2.0.1
Jinja2==3.0.3
joblib==1.1.1
Mako==1.1.6
Markdown==3.3.7
MarkupSafe==2.0.1
nltk==3.6.7
packaging==21.3
pluggy==1.0.0
psycopg2==2.7.7
py==1.11.0
PyExecJS==1.5.1
Pygments==2.14.0
pyparsing==3.1.4
pytest==7.0.1
pytz==2025.2
regex==2023.8.8
requests==2.27.1
requests-file==2.1.0
semantic-version==2.10.0
shortuuid==1.0.13
simplejson==3.20.1
six==1.17.0
SQLAlchemy==1.4.54
SQLAlchemy-Utils==0.41.1
tldextract==3.1.2
tomli==1.2.3
tqdm==4.64.1
typing_extensions==4.1.1
UgliPyJS==0.2.5
Unidecode==1.3.8
urllib3==1.26.20
webassets==2.0
webencodings==0.5.1
Werkzeug==2.0.3
zipp==3.6.0

name: coaster
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alembic==1.7.7
      - attrs==22.2.0
      - bcrypt==4.0.1
      - bleach==4.1.0
      - blinker==1.5
      - charset-normalizer==2.0.12
      - click==8.0.4
      - coverage==6.2
      - coveralls==3.3.1
      - dataclasses==0.8
      - docflow==0.3.3
      - docopt==0.6.2
      - filelock==3.4.1
      - flask==2.0.3
      - flask-assets==2.1.0
      - flask-migrate==4.0.1
      - flask-script==2.0.6
      - flask-sqlalchemy==2.5.1
      - greenlet==2.0.2
      - html2text==2020.1.16
      - html5lib==1.1
      - idna==3.10
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - isoweek==1.3.3
      - itsdangerous==2.0.1
      - jinja2==3.0.3
      - joblib==1.1.1
      - mako==1.1.6
      - markdown==3.3.7
      - markupsafe==2.0.1
      - nltk==3.6.7
      - packaging==21.3
      - pluggy==1.0.0
      - psycopg2==2.7.7
      - py==1.11.0
      - pyexecjs==1.5.1
      - pygments==2.14.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytz==2025.2
      - regex==2023.8.8
      - requests==2.27.1
      - requests-file==2.1.0
      - semantic-version==2.10.0
      - shortuuid==1.0.13
      - simplejson==3.20.1
      - six==1.17.0
      - sqlalchemy==1.4.54
      - sqlalchemy-utils==0.41.1
      - tldextract==3.1.2
      - tomli==1.2.3
      - tqdm==4.64.1
      - typing-extensions==4.1.1
      - uglipyjs==0.2.5
      - unidecode==1.3.8
      - urllib3==1.26.20
      - webassets==2.0
      - webencodings==0.5.1
      - werkzeug==2.0.3
      - zipp==3.6.0
prefix: /opt/conda/envs/coaster

tests/test_roles.py::TestCoasterRoles::test_uuidmixin_roles
tests/test_models.py::TestCoasterModels::test_uuid_buid_suuid tests/test_models.py::TestCoasterModels::test_uuid_url_id tests/test_models.py::TestCoasterModels::test_uuid_url_id_name_suuid tests/test_models.py::TestCoasterModelsPG::test_auto_init_default tests/test_models.py::TestCoasterModelsPG::test_container tests/test_models.py::TestCoasterModelsPG::test_failsafe_add tests/test_models.py::TestCoasterModelsPG::test_failsafe_add_existing tests/test_models.py::TestCoasterModelsPG::test_failsafe_add_fail tests/test_models.py::TestCoasterModelsPG::test_failsafe_add_silent_fail tests/test_models.py::TestCoasterModelsPG::test_has_timestamps tests/test_models.py::TestCoasterModelsPG::test_id_named tests/test_models.py::TestCoasterModelsPG::test_jsondict tests/test_models.py::TestCoasterModelsPG::test_named tests/test_models.py::TestCoasterModelsPG::test_named_blank_allowed tests/test_models.py::TestCoasterModelsPG::test_named_blank_disallowed tests/test_models.py::TestCoasterModelsPG::test_parent_child_primary tests/test_models.py::TestCoasterModelsPG::test_parent_child_primary_sql_validator tests/test_models.py::TestCoasterModelsPG::test_query tests/test_models.py::TestCoasterModelsPG::test_reserved_name tests/test_models.py::TestCoasterModelsPG::test_scoped_id tests/test_models.py::TestCoasterModelsPG::test_scoped_id_named tests/test_models.py::TestCoasterModelsPG::test_scoped_id_without_parent tests/test_models.py::TestCoasterModelsPG::test_scoped_named tests/test_models.py::TestCoasterModelsPG::test_scoped_named_short_title tests/test_models.py::TestCoasterModelsPG::test_scoped_named_without_parent tests/test_models.py::TestCoasterModelsPG::test_timestamp tests/test_models.py::TestCoasterModelsPG::test_unnamed tests/test_models.py::TestCoasterModelsPG::test_url_for tests/test_models.py::TestCoasterModelsPG::test_uuid_buid_suuid tests/test_models.py::TestCoasterModelsPG::test_uuid_default tests/test_models.py::TestCoasterModelsPG::test_uuid_key tests/test_models.py::TestCoasterModelsPG::test_uuid_url_id tests/test_models.py::TestCoasterModelsPG::test_uuid_url_id_name_suuid
tests/test_models.py::TestCoasterModels::test_auto_init_default tests/test_models.py::TestCoasterModels::test_container tests/test_models.py::TestCoasterModels::test_failsafe_add tests/test_models.py::TestCoasterModels::test_failsafe_add_existing tests/test_models.py::TestCoasterModels::test_failsafe_add_fail tests/test_models.py::TestCoasterModels::test_failsafe_add_silent_fail tests/test_models.py::TestCoasterModels::test_has_timestamps tests/test_models.py::TestCoasterModels::test_id_named tests/test_models.py::TestCoasterModels::test_jsondict tests/test_models.py::TestCoasterModels::test_named tests/test_models.py::TestCoasterModels::test_named_blank_allowed tests/test_models.py::TestCoasterModels::test_named_blank_disallowed tests/test_models.py::TestCoasterModels::test_parent_child_primary tests/test_models.py::TestCoasterModels::test_query tests/test_models.py::TestCoasterModels::test_reserved_name tests/test_models.py::TestCoasterModels::test_scoped_id tests/test_models.py::TestCoasterModels::test_scoped_id_named tests/test_models.py::TestCoasterModels::test_scoped_id_without_parent tests/test_models.py::TestCoasterModels::test_scoped_named tests/test_models.py::TestCoasterModels::test_scoped_named_short_title tests/test_models.py::TestCoasterModels::test_scoped_named_without_parent tests/test_models.py::TestCoasterModels::test_timestamp tests/test_models.py::TestCoasterModels::test_unnamed tests/test_models.py::TestCoasterModels::test_url_for tests/test_models.py::TestCoasterModels::test_uuid_default tests/test_models.py::TestCoasterModels::test_uuid_key tests/test_roles.py::TestCoasterRoles::test_access_for_all tests/test_roles.py::TestCoasterRoles::test_access_for_roles_and_actor_or_anchors tests/test_roles.py::TestCoasterRoles::test_access_for_syntax tests/test_roles.py::TestCoasterRoles::test_attr_dict_access tests/test_roles.py::TestCoasterRoles::test_autorole_dict tests/test_roles.py::TestCoasterRoles::test_bad_decorator tests/test_roles.py::TestCoasterRoles::test_base_is_clean tests/test_roles.py::TestCoasterRoles::test_basemixin_roles tests/test_roles.py::TestCoasterRoles::test_current_access tests/test_roles.py::TestCoasterRoles::test_current_roles tests/test_roles.py::TestCoasterRoles::test_dictionary_comparison tests/test_roles.py::TestCoasterRoles::test_diff_roles tests/test_roles.py::TestCoasterRoles::test_method_call tests/test_roles.py::TestCoasterRoles::test_no_write tests/test_roles.py::TestCoasterRoles::test_role_dict tests/test_roles.py::TestCoasterRoles::test_roles_for_actor tests/test_roles.py::TestCoasterRoles::test_roles_for_anon tests/test_roles.py::TestCoasterRoles::test_roles_for_owner tests/test_roles.py::TestCoasterRoles::test_write_without_read tests/test_statemanager.py::TestStateManager::test_added_regular_state_transition tests/test_statemanager.py::TestStateManager::test_added_state_group tests/test_statemanager.py::TestStateManager::test_added_state_transition tests/test_statemanager.py::TestStateManager::test_available_transitions tests/test_statemanager.py::TestStateManager::test_available_transitions_for tests/test_statemanager.py::TestStateManager::test_available_transitions_order tests/test_statemanager.py::TestStateManager::test_bestmatch_state tests/test_statemanager.py::TestStateManager::test_change_state_invalid tests/test_statemanager.py::TestStateManager::test_conditional_state tests/test_statemanager.py::TestStateManager::test_conditional_state_label tests/test_statemanager.py::TestStateManager::test_conditional_state_unmanaged_state tests/test_statemanager.py::TestStateManager::test_current_states tests/test_statemanager.py::TestStateManager::test_currently_available_transitions tests/test_statemanager.py::TestStateManager::test_duplicate_transition tests/test_statemanager.py::TestStateManager::test_group_by_state tests/test_statemanager.py::TestStateManager::test_has_nonstate tests/test_statemanager.py::TestStateManager::test_has_state tests/test_statemanager.py::TestStateManager::test_is_state tests/test_statemanager.py::TestStateManager::test_managed_state_wrapper tests/test_statemanager.py::TestStateManager::test_readonly tests/test_statemanager.py::TestStateManager::test_requires tests/test_statemanager.py::TestStateManager::test_reviewstate_also_changes tests/test_statemanager.py::TestStateManager::test_role_proxy_transitions tests/test_statemanager.py::TestStateManager::test_sql_query_added_state tests/test_statemanager.py::TestStateManager::test_sql_query_multi_value tests/test_statemanager.py::TestStateManager::test_sql_query_single_value tests/test_statemanager.py::TestStateManager::test_sql_query_state_group tests/test_statemanager.py::TestStateManager::test_state_already_exists tests/test_statemanager.py::TestStateManager::test_state_group_invalid tests/test_statemanager.py::TestStateManager::test_state_labels tests/test_statemanager.py::TestStateManager::test_transition_abort tests/test_statemanager.py::TestStateManager::test_transition_data tests/test_statemanager.py::TestStateManager::test_transition_data_name_invalid tests/test_statemanager.py::TestStateManager::test_transition_from_none tests/test_statemanager.py::TestStateManager::test_transition_invalid_from_to tests/test_statemanager.py::TestStateManager::test_transition_is_available tests/test_statemanager.py::TestStateManager::test_transition_publish_datetime tests/test_statemanager.py::TestStateManager::test_transition_publish_invalid tests/test_statemanager.py::TestStateManager::test_transition_state_lock tests/test_statemanager.py::TestStateManager::test_transition_submit
coaster/sqlalchemy/mixins.py CHANGES.rst
coaster/sqlalchemy/mixins.py CHANGES.rst