Commits

Vinay Sajip committed 736aae2

Interim update. All tests pass on 2.7, and all pass on 3.2 other than encryption tests (need pycrypto, which doesn't support Python 3).

Comments (0)

Files changed (21)

+\.py[co]$
+scratch.py
+\.log$
+\.egg-info$
+
+

elixir/__init__.py

     from sets import Set as set
 
 import sqlalchemy
+import sqlalchemy.orm
 from sqlalchemy.types import *
 
+# default session
+session = sqlalchemy.orm.scoped_session(sqlalchemy.orm.sessionmaker())
+
+# default metadata
+metadata = sqlalchemy.MetaData()
+
+metadatas = set()
+
+from elixir.collection import EntityCollection, GlobalEntityCollection
+
+# default entity collection
+entities = GlobalEntityCollection()
+
 from elixir.options import using_options, using_table_options, \
                            using_mapper_options, options_defaults, \
                            using_options_defaults
 from elixir.properties import has_property, GenericProperty, ColumnProperty, \
                               Synonym
 from elixir.statements import Statement
-from elixir.collection import EntityCollection, GlobalEntityCollection
-
 
 __version__ = '0.8.0dev'
 
                'setup_all', 'cleanup_all',
                'metadata', 'session']
 
-# default session
-session = sqlalchemy.orm.scoped_session(sqlalchemy.orm.sessionmaker())
-
-# default metadata
-metadata = sqlalchemy.MetaData()
-
-metadatas = set()
-
-# default entity collection
-entities = GlobalEntityCollection()
-
 
 def create_all(*args, **kwargs):
     '''Create the necessary tables for all declared entities'''
+import sys
+
+if sys.version_info[0] < 3:
+    PY3 = False
+
+    def b(s):
+        return s
+
+    def u(s):
+        return unicode(s, "unicode_escape")
+
+    import StringIO
+    StringIO = BytesIO = StringIO.StringIO
+    text_type = unicode
+    binary_type = str
+    string_types = basestring,
+    integer_types = (int, long)
+
+    def with_metaclass(meta, base=object):
+        class NewBase(base):
+            __metaclass__ = meta
+        return NewBase
+
+    execfile_ = execfile
+else:
+    PY3 = True
+
+    def b(s):
+        return s.encode("latin-1")
+
+    def u(s):
+        return s
+
+    import io
+    StringIO = io.StringIO
+    BytesIO = io.BytesIO
+    text_type = str
+    binary_type = bytes
+    string_types = str,
+    integer_types = int,
+
+    exec_ = eval("exec")
+
+    def execfile_(file, globals=globals(), locals=locals()):
+        f = open(file, "r")
+        try:
+            exec_(f.read()+"\\n", globals, locals)
+        finally:
+            f.close()
+
+    def with_metaclass(meta, base=object):
+        ns = dict(base=base, meta=meta)
+        exec_("""class NewBase(base, metaclass=meta):
+    pass""", ns)
+        return ns["NewBase"]
+
+long_type = integer_types[-1]
+
 ``EntityMeta``.
 '''
 
+import logging
 import sys
 import types
 import warnings
 from sqlalchemy.sql import ColumnCollection
 
 import elixir
+from elixir.compat import string_types, with_metaclass
 from elixir.statements import process_mutators, MUTATORS
 from elixir import options
 from elixir.properties import Property
 
 __doc_all__ = ['Entity', 'EntityMeta']
 
+logger = logging.getLogger(__name__)
 
 def session_mapper_factory(scoped_session):
     def session_mapper(cls, *args, **kwargs):
             self.identity = self.identity(entity)
 
         if self.polymorphic:
-            if not isinstance(self.polymorphic, basestring):
+            if not isinstance(self.polymorphic, string_types):
                 self.polymorphic = options.DEFAULT_POLYMORPHIC_COL_NAME
 
     #---------------------
                         if col.primary_key:
                             self.add_column(col.copy())
             elif not self.has_pk and self.auto_primarykey:
-                if isinstance(self.auto_primarykey, basestring):
+                if isinstance(self.auto_primarykey, string_types):
                     colname = self.auto_primarykey
                 else:
                     colname = options.DEFAULT_AUTO_PRIMARYKEY_NAME
                                        options.POLYMORPHIC_COL_TYPE))
 
             if self.version_id_col:
-                if not isinstance(self.version_id_col, basestring):
+                if not isinstance(self.version_id_col, string_types):
                     self.version_id_col = options.DEFAULT_VERSION_ID_COL_NAME
                 self.add_column(Column(self.version_id_col, Integer))
 
         self.entity.table = Table(self.tablename, self.metadata,
                                   *args, **kwargs)
         if DEBUG:
-            print self.entity.table.repr2()
+            print(self.entity.table.repr2())
 
     def setup_reltables(self):
         self.call_builders('create_tables')
         methods = {}
 
         all_methods = getmembers(self.entity,
-                                 lambda a: isinstance(a, types.MethodType))
+                                 lambda a: isinstance(a, (types.MethodType,
+                                                          types.FunctionType)))
 
+        #logger.debug('all_methods: %s', all_methods)
         for name, method in all_methods:
             for event in getattr(method, '_elixir_events', []):
                 event_methods = methods.setdefault(event, [])
                 event_methods.append(method)
 
+        #logger.debug('elixir events: %s', methods)
         if not methods:
             return
 
         return children
 
     def translate_order_by(self, order_by):
-        if isinstance(order_by, basestring):
+        if isinstance(order_by, string_types):
             order_by = [order_by]
 
         order = []
                                 (col.key, table.name))
             table.append_column(col)
             if DEBUG:
-                print "table.append_column(%s)" % col
+                print("table.append_column(%s)" % col)
 
     def add_constraint(self, constraint):
         self.constraints.append(constraint)
         if mapper:
             mapper.add_property(name, property)
             if DEBUG:
-                print "mapper.add_property('%s', %s)" % (name, repr(property))
+                print("mapper.add_property('%s', %s)" % (name, repr(property)))
 
     def add_mapper_extension(self, extension):
         extensions = self.mapper_options.get('extension', [])
     EntityMeta. If we don't find any, it means it is either an unrelated class
     or an entity base class (like the 'Entity' class).
     """
+    result = False
     for base in cls.__bases__:
+        if base.__name__ == 'NewBase':
+            continue
         if isinstance(base, EntityMeta):
-            return True
-    return False
+            result = True
+            break
+    #logger.debug('is_entity: %s (%s) -> %s', cls, cls.__bases__, result)
+    return result
 
 
 # Note that we don't use inspect.getmembers because of
 
 def is_abstract_entity(dict_or_cls):
     if not isinstance(dict_or_cls, dict):
+        cls = dict_or_cls
         dict_or_cls = dict_or_cls.__dict__
+    else:
+        cls = None
+    result = False
     for mutator, args, kwargs in dict_or_cls.get(MUTATORS, []):
         if 'abstract' in kwargs:
-            return kwargs['abstract']
-
-    return False
+            result = kwargs['abstract']
+            break
+    #logger.debug('is_abstract_entity: %s -> %s', cls, result)
+    return result
 
 def instrument_class(cls):
     """
     Instrument a class as an Entity. This is usually done automatically through
     the EntityMeta metaclass.
     """
+    #logger.debug('instrument_class: %s', cls)
     # Create the entity descriptor
     desc = cls._descriptor = EntityDescriptor(cls)
 
 
     # Process attributes (using the assignment syntax), looking for
     # 'Property' instances and attaching them to this entity.
-    properties = [(name, attr) for name, attr in cls.__dict__.iteritems()
+    properties = [(name, attr) for name, attr in cls.__dict__.items()
                                if isinstance(attr, Property)]
     sorted_props = sorted(base_props + properties,
                           key=lambda i: i[1]._counter)
     for name, prop in sorted_props:
+        #logger.debug('instrument_class: processing property %s for %s', name, cls)
         prop.attach(cls, name)
 
     # setup misc options here (like tablename etc.)
         # delete all Elixir properties so that it doesn't interfere with
         # SQLAlchemy. At this point they should have be converted to
         # builders.
-        for name, attr in entity.__dict__.items():
+        items = list(entity.__dict__.items())
+        for name, attr in items:
             if isinstance(attr, Property):
                 delattr(entity, name)
 
             'setup_properties',
             'finalize'):
 #        if DEBUG:
-#            print "=" * 40
-#            print method_name
-#            print "=" * 40
+#            print("=" * 40)
+#            print(method_name)
+#            print("=" * 40)
         for entity in entities:
-#            print entity.__name__, "...",
+#            print(entity.__name__, "...",)
             if hasattr(entity, '_setup_done'):
-#                print "already done"
+#                print("already done")
                 continue
             method = getattr(entity._descriptor, method_name)
             method()
-#            print "ok"
+#            print("ok")
 
 
 def cleanup_entities(entities):
         self.set(**kwargs)
 
     def set(self, **kwargs):
-        for key, value in kwargs.iteritems():
+        for key, value in kwargs.items():
             setattr(self, key, value)
 
     @classmethod
 
         mapper = sqlalchemy.orm.object_mapper(self)
 
-        for key, value in data.iteritems():
+        for key, value in data.items():
             if isinstance(value, dict):
                 dbvalue = getattr(self, key)
                 rel_class = mapper.get_property(key).mapper.class_
                                       if isinstance(p, ColumnProperty)]
         data = dict([(name, getattr(self, name))
                      for name in col_prop_names if name not in exclude])
-        for rname, rdeep in deep.iteritems():
+        for rname, rdeep in deep.items():
             dbdata = getattr(self, rname)
             #FIXME: use attribute names (ie coltoprop) instead of column names
             fks = self.mapper.get_property(rname).remote_side
         return cls.query.get(*args, **kwargs)
 
 
-class Entity(EntityBase):
+class Entity(with_metaclass(EntityMeta, EntityBase)):
     '''
     The base class for all entities
 
     For further information, please refer to the provided examples or
     tutorial.
     '''
-    __metaclass__ = EntityMeta
+    pass
 
-
 from sqlalchemy.orm import deferred, synonym
 from sqlalchemy.ext.associationproxy import association_proxy
 
+from elixir.compat import string_types
 from elixir.statements import ClassMutator
 from elixir.properties import Property
 
     def create_properties(self):
         if self.deferred:
             group = None
-            if isinstance(self.deferred, basestring):
+            if isinstance(self.deferred, string_types):
                 group = self.deferred
             self.property = deferred(self.column, group=group)
         elif self.name != self.colname:

elixir/options.py

     table_options={}
 )
 
-valid_options = options_defaults.keys() + [
+valid_options = list(options_defaults.keys()) + [
     'metadata',
     'session',
     'collection'

elixir/properties.py

                          (c.quantity * c.unit_price).label('price')))
 '''
 
+from elixir.compat import with_metaclass
 from elixir.statements import PropertyStatement
 from sqlalchemy.orm import column_property, synonym
 
         return instance
 
 
-class Property(EntityBuilder):
+class Property(with_metaclass(CounterMeta, EntityBuilder)):
     '''
     Abstract base class for all properties of an Entity.
     '''
-    __metaclass__ = CounterMeta
 
     def __init__(self, *args, **kwargs):
         self.entity = None

elixir/relationships.py

 from sqlalchemy.orm import relation, backref, class_mapper
 from sqlalchemy.ext.associationproxy import association_proxy
 
-import options
+from elixir import options
+from elixir.compat import string_types
 from elixir.statements import ClassMutator
 from elixir.properties import Property
 from elixir.entity import EntityMeta, DEBUG
     @property
     def target(self):
         if not self._target:
-            if isinstance(self.of_kind, basestring):
+            if isinstance(self.of_kind, string_types):
                 collection = self.entity._descriptor.collection
                 self._target = collection.resolve(self.of_kind, self.entity)
             else:
             self.table = Table(tablename, e1_desc.metadata,
                                schema=schema, *args, **complete_kwargs)
             if DEBUG:
-                print self.table.repr2()
+                print(self.table.repr2())
 
     def _build_join_clauses(self):
         # In the case we have a self-reference, we need to build join clauses
     # match.
 
 #TODO: rewrite this. Even with the comment, I don't even understand it myself.
-    for cols, constraint in constraint_map.iteritems():
+    for cols, constraint in constraint_map.items():
         if cols == cols1 or (cols != cols2 and
                              not cols1 and (cols2 in constraint_map or
                                             cols2 is None)):

examples/videostore/videostore/tests/test_controllers.py

 
 def test_method():
     "the index method should return a string called now"
-    import types
     result = testutil.call(cherrypy.root.index)
-    assert type(result["now"]) == types.StringType
+    assert type(result["now"]) == type('')
 test_method = with_setup(teardown=teardown_func)(test_method)
 
 def test_indextitle():
 modules = elixir, elixir.ext.associable, elixir.ext.encrypted,
           elixir.ext.list, elixir.ext.perform_ddl, elixir.ext.versioned,
 trac_browser_url = http://elixir.ematia.de/trac/browser/elixir/tags/0.7.0
-trac_link_format = %s%s#L%s%s
+trac_link_format = %%s%%s#L%%s%%s
 
 from setuptools import setup, find_packages
 import sys
 
-extra = {}
-if sys.version_info >= (3,):
-    extra['use_2to3'] = True
-
 setup(name="Elixir",
       version="0.8.0",
       description="Declarative Mapper for SQLAlchemy",
       url="http://elixir.ematia.de",
       license = "MIT License",
       install_requires = [
-          "SQLAlchemy >= 0.5.0"
+          "SQLAlchemy >= 0.5.0, < 0.7.0"
       ],
       packages=find_packages(exclude=['ez_setup', 'tests', 'examples']),
       classifiers=[
           "Topic :: Database :: Front-Ends",
           "Topic :: Software Development :: Libraries :: Python Modules"
       ],
-      test_suite = 'nose.collector',
-      **extra)
+      test_suite = 'nose.collector')

tests/db1/__init__.py

-import a, b, c
+from tests.db1 import a, b, c

tests/db2/__init__.py

-import a
+from tests.db2 import a

tests/test_abstract.py

 import re
 
 from elixir import *
+from elixir.compat import u
 import elixir
 
 def camel_to_underscore(entity):
         assert DatedContact._descriptor.identity == 'dated_contact'
         assert DatedContact.table.name == 'dated_contact'
 
-        contact1 = DatedContact(first_name=u"Guido", last_name=u"van Rossum")
+        contact1 = DatedContact(first_name=u("Guido"), last_name=u("van Rossum"))
         session.commit()
 
     def test_mixed_inheritance(self):
         assert MixedDatedContact._descriptor.identity == 'mixed_dated_contact'
         assert MixedDatedContact.table.name == 'mixed_dated_contact'
 
-        contact1 = MixedDatedContact(first_name=u"Guido",
-                                     last_name=u"van Rossum")
+        contact1 = MixedDatedContact(first_name=u("Guido"),
+                                     last_name=u("van Rossum"))
         session.commit()
 

tests/test_autoload.py

 def setup_entity_raise(cls):
     try:
         setup_entities([cls])
-    except Exception, e:
+    except Exception:
         pass
     else:
         assert False, "Exception did not occur setting up %s" % cls.__name__

tests/test_custombase.py

 """
 
 from elixir import *
+from elixir.compat import PY3, with_metaclass
 import elixir
+import logging
+
+logger = logging.getLogger(__name__)
 
 def setup():
     metadata.bind = 'sqlite://'
 
     global MyBase
 
-    class MyBase(object):
-        __metaclass__ = EntityMeta
+    class MyBase(with_metaclass(EntityMeta)):
 
         def __init__(self, **kwargs):
             for key, value in kwargs.items():
             def __get__(*args):
                 raise AttributeError
 
-        class MyEntity(EntityBase):
-            __metaclass__ = EntityMeta
+        class MyEntity(with_metaclass(EntityMeta, EntityBase)):
 
             d = BrokenDescriptor()
 
             def test(self):
                 return "success"
 
-        class InheritedBase(BaseParent):
-            __metaclass__ = EntityMeta
+        class InheritedBase(with_metaclass(EntityMeta, BaseParent)):
+            pass
 
         class A(InheritedBase):
             name = Field(String(30))
         assert a.test() == "success"
 
     def test_base_with_fields(self):
-        class FieldBase(object):
-            __metaclass__ = EntityMeta
-
+        class FieldBase(with_metaclass(EntityMeta)):
             common = Field(String(32))
 
         class A(FieldBase):
         assert 'common' in B.table.columns
 
     def test_base_with_relation(self):
-        class FieldBase(object):
-            __metaclass__ = EntityMeta
-
+        class FieldBase(with_metaclass(EntityMeta)):
             common = ManyToOne('A')
 
         class A(FieldBase):
         class BaseParent(object):
             common1 = Field(String(32))
 
-        class FieldBase(BaseParent):
-            __metaclass__ = EntityMeta
-
+        class FieldBase(with_metaclass(EntityMeta, BaseParent)):
             common2 = Field(String(32))
 
         class A(FieldBase):
 
         setup_all(True)
 
+        logger.debug('columns in A: %s', A.table.columns)
         assert 'name' in A.table.columns
         assert 'common1' in A.table.columns
         assert 'common1' in B.table.columns
         def camel_to_underscore(entity):
             return re.sub(r'(.+?)([A-Z])+?', r'\1_\2', entity.__name__).lower()
 
-        class OptionBase(object):
-            __metaclass__ = EntityMeta
-
+        class OptionBase(with_metaclass(EntityMeta)):
             options_defaults = dict(tablename=camel_to_underscore)
             using_options_defaults(identity=camel_to_underscore)
             using_options_defaults(inheritance='multi')
 
         collection = elixir.collection.RelativeEntityCollection()
 
-        class Base(object):
-            __metaclass__ = EntityMeta
+        class Base(with_metaclass(EntityMeta)):
             using_options_defaults(collection=collection)
 
         class A(Base):
         class B(Base):
             a = OneToOne('A')
 
+        logger.debug('Elixir entities: %s', elixir.entities)
         assert not elixir.entities
         assert A.table is None
         assert B.table is None
     def test_base_custom_session(self):
         from sqlalchemy.orm import sessionmaker
 
-        class Base(object):
-            __metaclass__ = EntityMeta
+        class Base(with_metaclass(EntityMeta)):
             using_options_defaults(session=None)
 
         class A(Base):

tests/test_inherit.py

         res[class_.__name__].sort(key=lambda o: o.__class__.__name__)
 
     for query_class in ('A', 'B', 'C', 'D', 'E'):
-#        print res[query_class], expected_res[query_class]
+#        print(res[query_class], expected_res[query_class])
         assert len(res[query_class]) == len(expected_res[query_class])
         for real, expected in zip(res[query_class], expected_res[query_class]):
             assert real.__class__.__name__ == expected
     def test_inheritance_wh_schema(self):
         # I can only test schema stuff on postgres
         if metadata.bind.name != 'postgres':
-            print "schema test skipped"
+            print("schema test skipped")
             return
 
         class A(Entity):

tests/test_o2m.py

 """
 
 from elixir import *
+from elixir.compat import u
 from sqlalchemy import and_
 from sqlalchemy.ext.orderinglist import ordering_list
 
         class User(Entity):
             name = Field(String(50))
             boston_addresses = OneToMany('Address', primaryjoin=lambda:
-                and_(Address.user_id == User.id, Address.city == u'Boston'),
+                and_(Address.user_id == User.id, Address.city == u('Boston')),
                 viewonly=True
             )
             addresses = OneToMany('Address')
         setup_all(True)
 
         user = User(name="u1",
-                    addresses=[Address(street=u"Queen Astrid Avenue, 32",
-                                       city=u"Brussels"),
-                               Address(street=u"Cambridge Street, 5",
-                                       city=u"Boston")])
+                    addresses=[Address(street=u("Queen Astrid Avenue, 32"),
+                                       city=u("Brussels")),
+                               Address(street=u("Cambridge Street, 5"),
+                                       city=u("Boston"))])
 
         session.commit()
         session.expunge_all()
         class User(Entity):
             name = Field(String(50))
             boston_addresses = OneToMany('Address', filter=lambda c:
-                                         c.city == u'Boston')
+                                         c.city == u('Boston'))
             addresses = OneToMany('Address')
 
         class Address(Entity):
         setup_all(True)
 
         user = User(name="u1",
-                    addresses=[Address(street=u"Queen Astrid Avenue, 32",
-                                       city=u"Brussels"),
-                               Address(street=u"Cambridge Street, 5",
-                                       city=u"Boston")])
+                    addresses=[Address(street=u("Queen Astrid Avenue, 32"),
+                                       city=u("Brussels")),
+                               Address(street=u("Cambridge Street, 5"),
+                                       city=u("Boston"))])
 
         session.commit()
         session.expunge_all()
         setup_all(True)
 
         user = User(name="u1",
-                    blurbs=[Blurb(text=u'zero'),
-                            Blurb(text=u'one'),
-                            Blurb(text=u'two')])
+                    blurbs=[Blurb(text=u('zero')),
+                            Blurb(text=u('one')),
+                            Blurb(text=u('two'))])
 
         session.commit()
         session.expunge_all()
 
         user = User.get(1)
         assert len(user.blurbs) == 3
-        user.blurbs.insert(1, Blurb(text=u'new one'))
+        user.blurbs.insert(1, Blurb(text=u('new one')))
         assert user.blurbs[2].text == "one"
         assert user.blurbs[2].position == 2
         assert user.blurbs[3].text == "two"

tests/test_packages.py

 
         elixir.entities = elixir.collection.RelativeEntityCollection()
 
-        import db1
-        import db2
+        import tests.db1
+        import tests.db2
 
         setup_all(True)
 

tests/test_perform_ddl.py

 from elixir import *
+from elixir.compat import u
 from elixir.ext.perform_ddl import perform_ddl, preload_data
 
 
             year = Field(Integer)
 
             preload_data(('title', 'year'),
-                         [(u'Alien', 1979), (u'Star Wars', 1977)])
+                         [(u('Alien'), 1979), (u('Star Wars'), 1977)])
             preload_data(('year', 'title'),
-                         [(1982, u'Blade Runner')])
-            preload_data(data=[(u'Batman', 1966)])
+                         [(1982, u('Blade Runner'))])
+            preload_data(data=[(u('Batman'), 1966)])
 
         setup_all(True)
         assert Movie.query.count() == 4

tests/test_properties.py

 from sqlalchemy import select, func
 from sqlalchemy.orm import column_property
 from elixir import *
+from elixir.compat import u
 
 def setup():
     metadata.bind = 'sqlite://'
         setup_all(True)
 
         alexandre = Person(
-            name = u'Alexandre da Silva',
-            email_address = u'x@y.com'
+            name = u('Alexandre da Silva'),
+            email_address = u('x@y.com')
         )
         johann = User(
             name = 'Johann Felipe Voigt',
         p = Person.get_by(name='Alexandre da Silva')
         assert p.primary_email == 'x@y.com'
 
-        u = User.get_by(user_name='Johann Felipe Voigt')
-        assert u.email_address == 'y@z.com'
+        user = User.get_by(user_name='Johann Felipe Voigt')
+        assert user.email_address == 'y@z.com'
 
-        u.email_address = 'new@z.com'
+        user.email_address = 'new@z.com'
         session.commit(); session.expunge_all()
 
         p = Person.get_by(name='Johann Felipe Voigt')