| Viewing file:  fixtures.py (10.47 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# testing/fixtures.py# Copyright (C) 2005-2016 the SQLAlchemy authors and contributors
 # <see AUTHORS file>
 #
 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 from . import config
 from . import assertions, schema
 from .util import adict
 from .. import util
 from .engines import drop_all_tables
 from .entities import BasicEntity, ComparableEntity
 import sys
 import sqlalchemy as sa
 from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
 
 # whether or not we use unittest changes things dramatically,
 # as far as how py.test collection works.
 
 
 class TestBase(object):
 # A sequence of database names to always run, regardless of the
 # constraints below.
 __whitelist__ = ()
 
 # A sequence of requirement names matching testing.requires decorators
 __requires__ = ()
 
 # A sequence of dialect names to exclude from the test class.
 __unsupported_on__ = ()
 
 # If present, test class is only runnable for the *single* specified
 # dialect.  If you need multiple, use __unsupported_on__ and invert.
 __only_on__ = None
 
 # A sequence of no-arg callables. If any are True, the entire testcase is
 # skipped.
 __skip_if__ = None
 
 def assert_(self, val, msg=None):
 assert val, msg
 
 # apparently a handful of tests are doing this....OK
 def setup(self):
 if hasattr(self, "setUp"):
 self.setUp()
 
 def teardown(self):
 if hasattr(self, "tearDown"):
 self.tearDown()
 
 
 class TablesTest(TestBase):
 
 # 'once', None
 run_setup_bind = 'once'
 
 # 'once', 'each', None
 run_define_tables = 'once'
 
 # 'once', 'each', None
 run_create_tables = 'once'
 
 # 'once', 'each', None
 run_inserts = 'each'
 
 # 'each', None
 run_deletes = 'each'
 
 # 'once', None
 run_dispose_bind = None
 
 bind = None
 metadata = None
 tables = None
 other = None
 
 @classmethod
 def setup_class(cls):
 cls._init_class()
 
 cls._setup_once_tables()
 
 cls._setup_once_inserts()
 
 @classmethod
 def _init_class(cls):
 if cls.run_define_tables == 'each':
 if cls.run_create_tables == 'once':
 cls.run_create_tables = 'each'
 assert cls.run_inserts in ('each', None)
 
 cls.other = adict()
 cls.tables = adict()
 
 cls.bind = cls.setup_bind()
 cls.metadata = sa.MetaData()
 cls.metadata.bind = cls.bind
 
 @classmethod
 def _setup_once_inserts(cls):
 if cls.run_inserts == 'once':
 cls._load_fixtures()
 cls.insert_data()
 
 @classmethod
 def _setup_once_tables(cls):
 if cls.run_define_tables == 'once':
 cls.define_tables(cls.metadata)
 if cls.run_create_tables == 'once':
 cls.metadata.create_all(cls.bind)
 cls.tables.update(cls.metadata.tables)
 
 def _setup_each_tables(self):
 if self.run_define_tables == 'each':
 self.tables.clear()
 if self.run_create_tables == 'each':
 drop_all_tables(self.metadata, self.bind)
 self.metadata.clear()
 self.define_tables(self.metadata)
 if self.run_create_tables == 'each':
 self.metadata.create_all(self.bind)
 self.tables.update(self.metadata.tables)
 elif self.run_create_tables == 'each':
 drop_all_tables(self.metadata, self.bind)
 self.metadata.create_all(self.bind)
 
 def _setup_each_inserts(self):
 if self.run_inserts == 'each':
 self._load_fixtures()
 self.insert_data()
 
 def _teardown_each_tables(self):
 # no need to run deletes if tables are recreated on setup
 if self.run_define_tables != 'each' and self.run_deletes == 'each':
 with self.bind.connect() as conn:
 for table in reversed(self.metadata.sorted_tables):
 try:
 conn.execute(table.delete())
 except sa.exc.DBAPIError as ex:
 util.print_(
 ("Error emptying table %s: %r" % (table, ex)),
 file=sys.stderr)
 
 def setup(self):
 self._setup_each_tables()
 self._setup_each_inserts()
 
 def teardown(self):
 self._teardown_each_tables()
 
 @classmethod
 def _teardown_once_metadata_bind(cls):
 if cls.run_create_tables:
 drop_all_tables(cls.metadata, cls.bind)
 
 if cls.run_dispose_bind == 'once':
 cls.dispose_bind(cls.bind)
 
 cls.metadata.bind = None
 
 if cls.run_setup_bind is not None:
 cls.bind = None
 
 @classmethod
 def teardown_class(cls):
 cls._teardown_once_metadata_bind()
 
 @classmethod
 def setup_bind(cls):
 return config.db
 
 @classmethod
 def dispose_bind(cls, bind):
 if hasattr(bind, 'dispose'):
 bind.dispose()
 elif hasattr(bind, 'close'):
 bind.close()
 
 @classmethod
 def define_tables(cls, metadata):
 pass
 
 @classmethod
 def fixtures(cls):
 return {}
 
 @classmethod
 def insert_data(cls):
 pass
 
 def sql_count_(self, count, fn):
 self.assert_sql_count(self.bind, fn, count)
 
 def sql_eq_(self, callable_, statements):
 self.assert_sql(self.bind, callable_, statements)
 
 @classmethod
 def _load_fixtures(cls):
 """Insert rows as represented by the fixtures() method."""
 headers, rows = {}, {}
 for table, data in cls.fixtures().items():
 if len(data) < 2:
 continue
 if isinstance(table, util.string_types):
 table = cls.tables[table]
 headers[table] = data[0]
 rows[table] = data[1:]
 for table in cls.metadata.sorted_tables:
 if table not in headers:
 continue
 cls.bind.execute(
 table.insert(),
 [dict(zip(headers[table], column_values))
 for column_values in rows[table]])
 
 from sqlalchemy import event
 
 
 class RemovesEvents(object):
 @util.memoized_property
 def _event_fns(self):
 return set()
 
 def event_listen(self, target, name, fn):
 self._event_fns.add((target, name, fn))
 event.listen(target, name, fn)
 
 def teardown(self):
 for key in self._event_fns:
 event.remove(*key)
 super_ = super(RemovesEvents, self)
 if hasattr(super_, "teardown"):
 super_.teardown()
 
 
 class _ORMTest(object):
 
 @classmethod
 def teardown_class(cls):
 sa.orm.session.Session.close_all()
 sa.orm.clear_mappers()
 
 
 class ORMTest(_ORMTest, TestBase):
 pass
 
 
 class MappedTest(_ORMTest, TablesTest, assertions.AssertsExecutionResults):
 # 'once', 'each', None
 run_setup_classes = 'once'
 
 # 'once', 'each', None
 run_setup_mappers = 'each'
 
 classes = None
 
 @classmethod
 def setup_class(cls):
 cls._init_class()
 
 if cls.classes is None:
 cls.classes = adict()
 
 cls._setup_once_tables()
 cls._setup_once_classes()
 cls._setup_once_mappers()
 cls._setup_once_inserts()
 
 @classmethod
 def teardown_class(cls):
 cls._teardown_once_class()
 cls._teardown_once_metadata_bind()
 
 def setup(self):
 self._setup_each_tables()
 self._setup_each_classes()
 self._setup_each_mappers()
 self._setup_each_inserts()
 
 def teardown(self):
 sa.orm.session.Session.close_all()
 self._teardown_each_mappers()
 self._teardown_each_classes()
 self._teardown_each_tables()
 
 @classmethod
 def _teardown_once_class(cls):
 cls.classes.clear()
 _ORMTest.teardown_class()
 
 @classmethod
 def _setup_once_classes(cls):
 if cls.run_setup_classes == 'once':
 cls._with_register_classes(cls.setup_classes)
 
 @classmethod
 def _setup_once_mappers(cls):
 if cls.run_setup_mappers == 'once':
 cls._with_register_classes(cls.setup_mappers)
 
 def _setup_each_mappers(self):
 if self.run_setup_mappers == 'each':
 self._with_register_classes(self.setup_mappers)
 
 def _setup_each_classes(self):
 if self.run_setup_classes == 'each':
 self._with_register_classes(self.setup_classes)
 
 @classmethod
 def _with_register_classes(cls, fn):
 """Run a setup method, framing the operation with a Base class
 that will catch new subclasses to be established within
 the "classes" registry.
 
 """
 cls_registry = cls.classes
 
 class FindFixture(type):
 def __init__(cls, classname, bases, dict_):
 cls_registry[classname] = cls
 return type.__init__(cls, classname, bases, dict_)
 
 class _Base(util.with_metaclass(FindFixture, object)):
 pass
 
 class Basic(BasicEntity, _Base):
 pass
 
 class Comparable(ComparableEntity, _Base):
 pass
 
 cls.Basic = Basic
 cls.Comparable = Comparable
 fn()
 
 def _teardown_each_mappers(self):
 # some tests create mappers in the test bodies
 # and will define setup_mappers as None -
 # clear mappers in any case
 if self.run_setup_mappers != 'once':
 sa.orm.clear_mappers()
 
 def _teardown_each_classes(self):
 if self.run_setup_classes != 'once':
 self.classes.clear()
 
 @classmethod
 def setup_classes(cls):
 pass
 
 @classmethod
 def setup_mappers(cls):
 pass
 
 
 class DeclarativeMappedTest(MappedTest):
 run_setup_classes = 'once'
 run_setup_mappers = 'once'
 
 @classmethod
 def _setup_once_tables(cls):
 pass
 
 @classmethod
 def _with_register_classes(cls, fn):
 cls_registry = cls.classes
 
 class FindFixtureDeclarative(DeclarativeMeta):
 def __init__(cls, classname, bases, dict_):
 cls_registry[classname] = cls
 return DeclarativeMeta.__init__(
 cls, classname, bases, dict_)
 
 class DeclarativeBasic(object):
 __table_cls__ = schema.Table
 
 _DeclBase = declarative_base(metadata=cls.metadata,
 metaclass=FindFixtureDeclarative,
 cls=DeclarativeBasic)
 cls.DeclarativeBasic = _DeclBase
 fn()
 
 if cls.metadata.tables and cls.run_create_tables:
 cls.metadata.create_all(config.db)
 
 |