]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Repaired the examples/versioning test runner
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 16 Jun 2011 16:09:45 +0000 (12:09 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 16 Jun 2011 16:09:45 +0000 (12:09 -0400)
to not rely upon SQLAlchemy test libs,
nosetests must be run from within
examples/versioning to get around setup.cfg
breaking it.

- Tweak to examples/versioning to pick the
correct foreign key in a multi-level
inheritance situation.

CHANGES
examples/versioning/__init__.py
examples/versioning/_lib.py [new file with mode: 0644]
examples/versioning/history_meta.py
examples/versioning/test_versioning.py

diff --git a/CHANGES b/CHANGES
index 8a8c6d04f5cfc24c9f01d43c6725f8bca49ded3a..f270e5d6320a7ce06a4bee117c1942be20a72059 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -32,6 +32,17 @@ CHANGES
     if Python unicodes are passed under
     certain circumstances.
 
+- examples
+  - Repaired the examples/versioning test runner
+    to not rely upon SQLAlchemy test libs,
+    nosetests must be run from within
+    examples/versioning to get around setup.cfg
+    breaking it.
+
+  - Tweak to examples/versioning to pick the
+    correct foreign key in a multi-level
+    inheritance situation.
+
 0.7.1
 =====
 - general
@@ -45,7 +56,7 @@ CHANGES
     self-referential relationships - this since
     SQLA 0.7 no longer enforces "parent with no 
     child" at the ORM level; this check is left
-    up to foreign key nullability.  
+    up to foreign key nullability.
     Related to [ticket:1912]
 
   - Repaired new "mutable" extension to propagate
@@ -87,10 +98,10 @@ CHANGES
 
   - Adjusted the __contains__() method of 
     a RowProxy result row such that no exception
-    throw is generated internally;  
+    throw is generated internally;
     NoSuchColumnError() also will generate its 
     message regardless of whether or not the column 
-    construct can be coerced to a string.  
+    construct can be coerced to a string.
     [ticket:2178].  Also in 0.6.8.
 
 - sqlite
@@ -106,7 +117,7 @@ CHANGES
     MATCH operator.   A potential floating-point
     inaccuracy issue was fixed, and certain tests 
     of the MATCH operator only execute within an 
-    EN-oriented locale for now.  [ticket:2175].  
+    EN-oriented locale for now.  [ticket:2175].
     Also in 0.6.8.
 
 - mysql
@@ -184,7 +195,7 @@ CHANGES
   - It is an error to call query.get() when the
     given entity is not a single, full class 
     entity or mapper (i.e. a column).  This is
-    a deprecation warning in 0.6.8.  
+    a deprecation warning in 0.6.8.
     [ticket:2144]
 
   - Fixed a potential KeyError which under some
@@ -310,7 +321,7 @@ CHANGES
 
     - The changelog for 0.6.7 and subsequent within
       the 0.6 series is now listed only in the 
-      CHANGES file within the 0.6 branch.  
+      CHANGES file within the 0.6 branch.
       In the 0.7 CHANGES file (i.e. this file), all the
       0.6 changes are listed inline within the 0.7
       section in which they were also applied 
@@ -529,7 +540,7 @@ CHANGES
     the given objects don't have any inter-attribute 
     references in memory, which was the behavior in 
     0.5 and earlier, so a flush of Parent/Child with
-    only foreign key/primary key set will succeed.  
+    only foreign key/primary key set will succeed.
     This while still maintaining 0.6 and above's not 
     generating a ton of useless internal dependency 
     structures within the flush that don't correspond 
@@ -539,7 +550,7 @@ CHANGES
   - Improvements to the error messages emitted when
     querying against column-only entities in conjunction
     with (typically incorrectly) using loader options, 
-    where the parent entity is not fully present.  
+    where the parent entity is not fully present.
     [ticket:2069]
 
   - Fixed bug in query.options() whereby a path 
@@ -579,7 +590,7 @@ CHANGES
     a Sequence object as its argument and renders the
     appropriate "next value" generation string on the
     target platform, if supported.  Also provides
-    ".next_value()" method on Sequence itself.   
+    ".next_value()" method on Sequence itself.
     [ticket:2085]
 
   - func.next_value() or other SQL expression can
@@ -944,7 +955,7 @@ CHANGES
 
   - Established consistency when server_default is present
     on an Integer PK column.  SQLA doesn't pre-fetch these,
-    nor do they come back in cursor.lastrowid (DBAPI).  
+    nor do they come back in cursor.lastrowid (DBAPI).
     Ensured all backends consistently return None 
     in result.inserted_primary_key for these. Regarding
     reflection for this case, reflection of an int PK col 
index 72edcca53080b89f4f0e6e7d45cebaf747a4cb2c..61b8f13c65cfe340e6ef4727c9b5953d3113a4b9 100644 (file)
@@ -8,7 +8,8 @@ represents historical versions of the target object.
 Usage is illustrated via a unit test module ``test_versioning.py``, which can
 be run via nose::
 
-    nosetests -w examples/versioning/
+    cd examples/versioning
+    nosetests -v 
 
 A fragment of example usage, using declarative::
 
diff --git a/examples/versioning/_lib.py b/examples/versioning/_lib.py
new file mode 100644 (file)
index 0000000..d5f2cb0
--- /dev/null
@@ -0,0 +1,96 @@
+"""copy of ComparableEntity and eq_() from test.lib.
+
+This is just to support running the example outside of
+the SQLA testing environment which is no longer part of 
+SQLAlchemy as of 0.7.
+
+"""
+
+import sqlalchemy as sa
+from sqlalchemy import exc as sa_exc
+
+
+def eq_(a, b, msg=None):
+    """Assert a == b, with repr messaging on failure."""
+    assert a == b, msg or "%r != %r" % (a, b)
+
+_repr_stack = set()
+class BasicEntity(object):
+    def __init__(self, **kw):
+        for key, value in kw.iteritems():
+            setattr(self, key, value)
+
+    def __repr__(self):
+        if id(self) in _repr_stack:
+            return object.__repr__(self)
+        _repr_stack.add(id(self))
+        try:
+            return "%s(%s)" % (
+                (self.__class__.__name__),
+                ', '.join(["%s=%r" % (key, getattr(self, key))
+                           for key in sorted(self.__dict__.keys())
+                           if not key.startswith('_')]))
+        finally:
+            _repr_stack.remove(id(self))
+
+_recursion_stack = set()
+class ComparableEntity(BasicEntity):
+    def __hash__(self):
+        return hash(self.__class__)
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __eq__(self, other):
+        """'Deep, sparse compare.
+
+        Deeply compare two entities, following the non-None attributes of the
+        non-persisted object, if possible.
+
+        """
+        if other is self:
+            return True
+        elif not self.__class__ == other.__class__:
+            return False
+
+        if id(self) in _recursion_stack:
+            return True
+        _recursion_stack.add(id(self))
+
+        try:
+            # pick the entity thats not SA persisted as the source
+            try:
+                self_key = sa.orm.attributes.instance_state(self).key
+            except sa.orm.exc.NO_STATE:
+                self_key = None
+
+            if other is None:
+                a = self
+                b = other
+            elif self_key is not None:
+                a = other
+                b = self
+            else:
+                a = self
+                b = other
+
+            for attr in a.__dict__.keys():
+                if attr.startswith('_'):
+                    continue
+                value = getattr(a, attr)
+
+                try:
+                    # handle lazy loader errors
+                    battr = getattr(b, attr)
+                except (AttributeError, sa_exc.UnboundExecutionError):
+                    return False
+
+                if hasattr(value, '__iter__'):
+                    if list(value) != list(battr):
+                        return False
+                else:
+                    if value is not None and value != battr:
+                        return False
+            return True
+        finally:
+            _recursion_stack.remove(id(self))
index 2983a33e21dec984fa9ee55fe3d2179af211f36c..5f3820f68005aa57f4d2ab2f95fbd9239fd44902 100644 (file)
@@ -35,7 +35,7 @@ def _history_mapper(local_mapper):
             col.unique = False
 
             if super_mapper and col_references_table(column, super_mapper.local_table):
-                super_fks.append((col.key, list(super_history_mapper.base_mapper.local_table.primary_key)[0]))
+                super_fks.append((col.key, list(super_history_mapper.local_table.primary_key)[0]))
 
             cols.append(col)
 
index d2d270c4321fafd2318dc487c39c4a8b5005bf14..5baf09530c3f67c360556aa667a0bfcd1e978ec6 100644 (file)
@@ -1,16 +1,16 @@
+from unittest import TestCase
 from sqlalchemy.ext.declarative import declarative_base
 from history_meta import VersionedMeta, VersionedListener
 from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
 from sqlalchemy.orm import clear_mappers, sessionmaker, deferred, relationship
-from test.lib.testing import TestBase, eq_
-from test.lib.entities import ComparableEntity
+from _lib import ComparableEntity, eq_
 
 def setup():
     global engine
     engine = create_engine('sqlite://', echo=True)
 
-class TestVersioning(fixtures.TestBase):
-    def setup(self):
+class TestVersioning(TestCase):
+    def setUp(self):
         global Base, Session, Versioned
         Base = declarative_base(bind=engine)
         class Versioned(object):
@@ -18,7 +18,7 @@ class TestVersioning(fixtures.TestBase):
             _decl_class_registry = Base._decl_class_registry
         Session = sessionmaker(extension=VersionedListener())
 
-    def teardown(self):
+    def tearDown(self):
         clear_mappers()
         Base.metadata.drop_all()