- Timestamp:
- 11/13/09 21:40:37 (3 years ago)
- Location:
- elixir/branches/0.7.x
- Files:
-
- 9 added
- 20 modified
-
AUTHORS (modified) (1 diff)
-
CHANGES (modified) (1 diff)
-
elixir/__init__.py (modified) (2 diffs)
-
elixir/collection.py (modified) (5 diffs)
-
elixir/entity.py (modified) (14 diffs)
-
elixir/ext/perform_ddl.py (modified) (1 diff)
-
elixir/ext/versioned.py (modified) (2 diffs)
-
elixir/options.py (modified) (7 diffs)
-
elixir/relationships.py (modified) (2 diffs)
-
examples/videostore/start-videostore.py (modified) (1 diff)
-
examples/videostore/videostore/controllers/root.py (modified) (6 diffs)
-
examples/videostore/videostore/model.py (modified) (3 diffs)
-
examples/videostore/videostore/tests/test_controllers.py (modified) (1 diff)
-
release.howto (modified) (2 diffs)
-
setup.cfg (modified) (1 diff)
-
tests/db1 (added)
-
tests/db1/__init__.py (added)
-
tests/db1/a.py (added)
-
tests/db1/b.py (added)
-
tests/db1/c.py (added)
-
tests/db2 (added)
-
tests/db2/__init__.py (added)
-
tests/db2/a.py (added)
-
tests/test_abstract.py (added)
-
tests/test_custombase.py (modified) (5 diffs)
-
tests/test_events.py (modified) (2 diffs)
-
tests/test_options.py (modified) (3 diffs)
-
tests/test_packages.py (modified) (4 diffs)
-
tests/test_through.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
elixir/branches/0.7.x/AUTHORS
r409 r517 16 16 - Graham Higgins 17 17 - Jason R. Coombs 18 - Johannes Janssen 18 19 - Neil Blakey-Milner 19 20 - Paul Johnston 20 21 - Remi Jolin 21 22 - Robin Munn 23 - Stéphane Klein 24 - Valentin Lab 22 25 - some anonymous contributions I couldn't trace to someone in particular -
elixir/branches/0.7.x/CHANGES
r486 r517 1 0.7.1 - 2009-11-.. 2 3 New features: 4 - Entities can now be declared "abstract" so that they do not create a table, 5 etc... This allows, among others, an entity to inherit from multiple abstract 6 classes (patch from Stéphane Klein, closes #89). 7 - Added a new collection which can resolve entities relative to the current 8 entity, for example "..other_module.Class" (based on patches from Johannes 9 Janssen, closes #93). 10 - Added a new entity option "resolve_root", which allows one to specify the 11 root module where your entities are defined. The string will be prepended 12 to all "absolute" entity paths. It can also be used on a per-entity basis. 13 This feature is based on a patch from Johannes Janssen, see #93. 14 15 Changes: 16 - using_options_defaults and using_table_options statements can be used several 17 times within the same class (closes #70). 18 19 Bug fixes: 20 - Fixed custom base classes and versioned extension when used with zope 21 interfaces (closes #98, patch from Valentin Lab) 22 - Fixed having relationships in custom base classes (based on patch 23 by Stéphane Klein) 24 1 25 0.7.0 - 2009-10-01 2 26 -
elixir/branches/0.7.x/elixir/__init__.py
r492 r517 36 36 Synonym 37 37 from elixir.statements import Statement 38 from elixir.collection import EntityCollection 38 from elixir.collection import EntityCollection, GlobalEntityCollection 39 39 40 40 … … 68 68 69 69 # default entity collection 70 entities = EntityCollection()70 entities = GlobalEntityCollection() 71 71 72 72 -
elixir/branches/0.7.x/elixir/collection.py
r439 r517 3 3 ''' 4 4 import sys 5 import re 5 6 6 7 from elixir.py23compat import rsplit 7 8 8 # default entity collection 9 class EntityCollection(list): 9 class BaseCollection(list): 10 10 def __init__(self, entities=None): 11 # _entities is a dict of entities keyed on their name.12 self._entities = {}13 11 list.__init__(self) 14 12 if entities is not None: … … 18 16 for e in entities: 19 17 self.append(e) 18 19 def clear(self): 20 del self[:] 21 22 def resolve_absolute(self, key, full_path, entity=None, root=None): 23 if root is None: 24 root = entity._descriptor.resolve_root 25 if root: 26 full_path = '%s.%s' % (root, full_path) 27 module_path, classname = rsplit(full_path, '.', 1) 28 module = sys.modules[module_path] 29 res = getattr(module, classname, None) 30 if res is None: 31 if entity is not None: 32 raise Exception("Couldn't resolve target '%s' <%s> in '%s'!" 33 % (key, full_path, entity.__name__)) 34 else: 35 raise Exception("Couldn't resolve target '%s' <%s>!" 36 % (key, full_path)) 37 return res 38 39 def __getattr__(self, key): 40 return self.resolve(key) 41 42 # default entity collection 43 class GlobalEntityCollection(BaseCollection): 44 def __init__(self, entities=None): 45 # _entities is a dict of entities keyed on their name. 46 self._entities = {} 47 super(GlobalEntityCollection, self).__init__(entities) 20 48 21 49 def append(self, entity): … … 33 61 "source" entity when resolving relationship targets. 34 62 ''' 35 path = rsplit(key, '.', 1) 36 classname = path.pop() 37 if path: 38 # Do we have a fully qualified entity name? 39 module = sys.modules[path.pop()] 40 return getattr(module, classname, None) 63 # Do we have a fully qualified entity name? 64 if '.' in key: 65 return self.resolve_absolute(key, key, entity) 41 66 else: 42 67 # Otherwise we look in the entities of this collection … … 44 69 if res is None: 45 70 if entity: 46 raise Exception("Couldn't resolve target '%s' in '%s'" \71 raise Exception("Couldn't resolve target '%s' in '%s'" 47 72 % (key, entity.__name__)) 48 73 else: … … 59 84 def clear(self): 60 85 self._entities = {} 61 del self[:] 86 super(GlobalEntityCollection, self).clear() 87 88 # backward compatible name 89 EntityCollection = GlobalEntityCollection 90 91 _leading_dots = re.compile('^([.]*).*$') 92 93 class RelativeEntityCollection(BaseCollection): 94 # the entity=None does not make any sense with a relative entity collection 95 def resolve(self, key, entity): 96 ''' 97 Resolve a key to an Entity. The optional `entity` argument is the 98 "source" entity when resolving relationship targets. 99 ''' 100 full_path = key 101 102 if '.' not in key or key.startswith('.'): 103 # relative target 104 105 # any leading dot is stripped and with each dot removed, 106 # the entity_module is stripped of one more chunk (starting with 107 # the last one). 108 num_dots = _leading_dots.match(full_path).end(1) 109 full_path = full_path[num_dots:] 110 chunks = entity.__module__.split('.') 111 chunkstokeep = len(chunks) - num_dots 112 if chunkstokeep < 0: 113 raise Exception("Couldn't resolve relative target " 114 "'%s' relative to '%s'" % (key, entity.__module__)) 115 entity_module = '.'.join(chunks[:chunkstokeep]) 116 117 if entity_module and entity_module is not '__main__': 118 full_path = '%s.%s' % (entity_module, full_path) 119 120 root = '' 121 else: 122 root = None 123 return self.resolve_absolute(key, full_path, entity, root=root) 62 124 63 125 def __getattr__(self, key): 64 r eturn self.resolve(key)126 raise NotImplementedError 65 127 66 -
elixir/branches/0.7.x/elixir/entity.py
r480 r517 7 7 8 8 import sys 9 import inspect10 9 import types 11 10 import warnings 12 11 13 from copy import copy12 from copy import deepcopy 14 13 15 14 import sqlalchemy … … 22 21 23 22 import elixir 24 from elixir.statements import process_mutators 23 from elixir.statements import process_mutators, MUTATORS 25 24 from elixir import options 26 25 from elixir.properties import Property … … 55 54 56 55 def __init__(self, entity): 57 entity.table = None58 entity.mapper = None59 60 56 self.entity = entity 61 # entity.__module__ is not always reliable (eg in mod_python)62 self.module = sys.modules.get(entity.__module__)63 64 # used for multi-table inheritance65 self.join_condition = None66 self.has_pk = False67 self._pk_col_done = False68 69 self.builders = []70 71 57 self.parent = None 72 #XXX: use entity.__subclasses__ ? 73 self.children = [] 74 58 59 bases = [] 75 60 for base in entity.__bases__: 76 61 if isinstance(base, EntityMeta): 77 if is_entity(base) :62 if is_entity(base) and not is_abstract_entity(base): 78 63 if self.parent: 79 64 raise Exception( … … 83 68 else: 84 69 self.parent = base 85 self.base = base._descriptor.base70 bases.extend(base._descriptor.bases) 86 71 self.parent._descriptor.children.append(entity) 87 72 else: 88 self.base = base 73 bases.append(base) 74 self.bases = bases 75 if not is_entity(entity) or is_abstract_entity(entity): 76 return 77 78 # entity.__module__ is not always reliable (eg in mod_python) 79 self.module = sys.modules.get(entity.__module__) 80 81 self.builders = [] 82 83 #XXX: use entity.__subclasses__ ? 84 self.children = [] 85 86 # used for multi-table inheritance 87 self.join_condition = None 88 self.has_pk = False 89 self._pk_col_done = False 89 90 90 91 # columns and constraints waiting for a table to exist … … 103 104 self.table_args = [] 104 105 105 # base class options_defaults 106 base_defaults = getattr(self.base, 'options_defaults', {}) 106 # base class(es) options_defaults 107 options_defaults = self.options_defaults() 108 107 109 complete_defaults = options.options_defaults.copy() 108 110 complete_defaults.update({ … … 114 116 # set default value for other options 115 117 for key in options.valid_options: 116 value = base_defaults.get(key, complete_defaults[key])118 value = options_defaults.get(key, complete_defaults[key]) 117 119 if isinstance(value, dict): 118 120 value = value.copy() … … 124 126 if hasattr(self.module, attr): 125 127 setattr(self, key, getattr(self.module, attr)) 128 129 def options_defaults(self): 130 base_defaults = {} 131 for base in self.bases: 132 base_defaults.update(base._descriptor.options_defaults()) 133 base_defaults.update(getattr(self.entity, 'options_defaults', {})) 134 return base_defaults 126 135 127 136 def setup_options(self): … … 153 162 self.identity = self.mapper_options['polymorphic_identity'] 154 163 else: 155 #TODO: include module name 164 #TODO: include module name (We could have b.Account inherit 165 # from a.Account) 156 166 self.identity = entity.__name__.lower() 157 167 elif 'polymorphic_identity' in self.mapper_options: … … 273 283 self.add_column(col.copy()) 274 284 275 #FIXME: use the public equivalent of _get_colspec when276 # available (e.target_fullname)277 285 for con in self.parent._descriptor.constraints: 278 286 self.add_constraint( … … 326 334 # create a list of callbacks for each event 327 335 methods = {} 328 entity = self.entity 329 330 # Note that we don't use inspect.getmembers because of 331 # http://bugs.python.org/issue1785 332 # See also http://elixir.ematia.de/trac/changeset/262 333 334 # dir returns the attributes of the class and *all its parents* listed 335 # alphabetically. 336 for key in dir(entity): 337 try: 338 value = getattr(entity, key) 339 if isinstance(value, types.MethodType): 340 for event in getattr(value, '_elixir_events', []): 341 event_methods = methods.setdefault(event, []) 342 event_methods.append(value) 343 except AttributeError: 344 pass 336 337 all_methods = getmembers(self.entity, 338 lambda a: isinstance(a, types.MethodType)) 339 340 for name, method in all_methods: 341 for event in getattr(method, '_elixir_events', []): 342 event_methods = methods.setdefault(event, []) 343 event_methods.append(method) 344 345 345 if not methods: 346 346 return … … 740 740 741 741 742 # Note that we don't use inspect.getmembers because of 743 # http://bugs.python.org/issue1785 744 # See also http://elixir.ematia.de/trac/changeset/262 745 def getmembers(object, predicate=None): 746 base_props = [] 747 for key in dir(object): 748 try: 749 value = getattr(object, key) 750 except AttributeError: 751 continue 752 if not predicate or predicate(value): 753 base_props.append((key, value)) 754 return base_props 755 756 def is_abstract_entity(dict_or_cls): 757 if not isinstance(dict_or_cls, dict): 758 dict_or_cls = dict_or_cls.__dict__ 759 for mutator, args, kwargs in dict_or_cls.get(MUTATORS, []): 760 if 'abstract' in kwargs: 761 return kwargs['abstract'] 762 763 return False 764 742 765 def instrument_class(cls): 743 766 """ … … 745 768 the EntityMeta metaclass. 746 769 """ 747 # create the entity descriptor770 # Create the entity descriptor 748 771 desc = cls._descriptor = EntityDescriptor(cls) 749 772 750 # Determine whether this entity is a *direct* subclass of its base entity 751 entity_base = None 773 # Process mutators 774 # We *do* want mutators to be processed for base/abstract classes 775 # (so that statements like using_options_defaults work). 776 process_mutators(cls) 777 778 # We do not want to do any more processing for base/abstract classes 779 # (Entity et al.). 780 if not is_entity(cls) or is_abstract_entity(cls): 781 return 782 783 cls.table = None 784 cls.mapper = None 785 786 # Copy the properties ('Property' instances) of the entity base class(es). 787 # We use getmembers (instead of __dict__) so that we also get the 788 # properties from the parents of the base class if any. 789 base_props = [] 752 790 for base in cls.__bases__: 753 if isinstance(base, EntityMeta): 754 if not is_entity(base): 755 entity_base = base 756 757 if entity_base: 758 # If so, copy the base entity properties ('Property' instances). 759 # We use inspect.getmembers (instead of __dict__) so that we also 760 # get the properties from the parents of the base_class if any. 761 base_props = inspect.getmembers(entity_base, 762 lambda a: isinstance(a, Property)) 763 base_props = [(name, copy(attr)) for name, attr in base_props] 764 else: 765 base_props = [] 791 if isinstance(base, EntityMeta) and \ 792 (not is_entity(base) or is_abstract_entity(base)): 793 base_props += [(name, deepcopy(attr)) for name, attr in 794 getmembers(base, lambda a: isinstance(a, Property))] 766 795 767 796 # Process attributes (using the assignment syntax), looking for … … 774 803 prop.attach(cls, name) 775 804 776 # Process mutators. Needed before _install_autosetup_triggers so that777 # we know of the metadata (and whether the entity is autosetuped or not).778 process_mutators(cls)779 780 805 # setup misc options here (like tablename etc.) 781 806 desc.setup_options() … … 797 822 798 823 def __init__(cls, name, bases, dict_): 799 # Only process further subclasses of the base classes (Entity et al.),800 # not the base classes themselves. We don't want the base entities to801 # be registered in an entity collection, nor to have a table name and802 # so on.803 if not is_entity(cls):804 if isinstance(cls, EntityMeta):805 process_mutators(cls)806 return807 808 824 instrument_class(cls) 809 825 -
elixir/branches/0.7.x/elixir/ext/perform_ddl.py
r443 r517 8 8 The 'when' argument can be either 'before-create' or 'after-create'. 9 9 The 'statement' argument can be one of: 10 10 11 - a single string statement 11 12 - a list of string statements, in which case, each of them will be executed -
elixir/branches/0.7.x/elixir/ext/versioned.py
r409 r517 56 56 from elixir.statements import Statement 57 57 from elixir.properties import EntityBuilder 58 from elixir.entity import getmembers 58 59 59 60 __all__ = ['acts_as_versioned', 'after_revert'] … … 177 178 # look for events 178 179 after_revert_events = [] 179 for name, func in inspect.getmembers(entity, inspect.ismethod):180 for name, func in getmembers(entity, inspect.ismethod): 180 181 if getattr(func, '_elixir_after_revert', False): 181 182 after_revert_events.append(func) -
elixir/branches/0.7.x/elixir/options.py
r484 r517 21 21 22 22 using_options(shortnames=True, order_by='name') 23 23 24 The list of supported arguments are as follows: 24 25 … … 34 35 | | #mapping-class-inheritance-hierarchies for an | 35 36 | | explanation of the different kinds of inheritances. | 37 +---------------------+-------------------------------------------------------+ 38 | ``abstract`` | Set 'abstract'=True to declare abstract entity. | 39 | | Abstract base classes are useful when you want to put | 40 | | some common information into a number of other | 41 | | entities. Abstract entity will not be used to create | 42 | | any database table. Instead, when it is used as a base| 43 | | class for other entity, its fields will be added to | 44 | | those of the child class. | 36 45 +---------------------+-------------------------------------------------------+ 37 46 | ``polymorphic`` | Whether the inheritance should be polymorphic or not. | … … 174 183 using_options_defaults (nor specifically on a particular Entity) will use the 175 184 global defaults, so you don't have to provide a default value for all options, 176 but only those you want to change. 177 185 but only those you want to change. Please also note that this statement does 186 not work on normal entities, and the normal using_options statement does not 187 work on base classes (because normal options do not and should not propagate to 188 the children classes). 178 189 ''' 179 190 … … 214 225 # 215 226 options_defaults = dict( 227 abstract=False, 216 228 autosetup=False, 217 229 inheritance='single', … … 225 237 allowcoloverride=False, 226 238 order_by=None, 239 resolve_root=None, 227 240 mapper_options={}, 228 241 table_options={} … … 242 255 % kwarg) 243 256 244 entity.options_defaults = kwargs 257 # We use __dict__ instead of hasattr to not check its presence within the 258 # parent, and thus update the parent dict instead of creating a local dict. 259 if not entity.__dict__.get('options_defaults'): 260 entity.options_defaults = {} 261 entity.options_defaults.update(kwargs) 245 262 246 263 … … 255 272 256 273 def using_table_options_handler(entity, *args, **kwargs): 257 entity._descriptor.table_args = list(args)274 entity._descriptor.table_args.extend(list(args)) 258 275 entity._descriptor.table_options.update(kwargs) 259 276 -
elixir/branches/0.7.x/elixir/relationships.py
r488 r517 185 185 +--------------------+--------------------------------------------------------+ 186 186 | ``filter`` | Specify a filter criterion (as a clause element) for | 187 | | this relationship. This criterion will be and_'ed with|188 | | the normal join criterion (primaryjoin) generated by|189 | | Elixir for the relationship. For example:|190 | | boston_addresses = \|191 | | OneToMany('Address', filter=Address.city == 'Boston')|187 | | this relationship. This criterion will be ``and_`` ed | 188 | | with the normal join criterion (primaryjoin) generated | 189 | | by Elixir for the relationship. For example: | 190 | | boston_addresses = | 191 | | OneToMany('Address', filter=Address.city == 'Boston') | 192 192 +--------------------+--------------------------------------------------------+ 193 193 … … 303 303 | ``table_kwargs`` | A dictionary holding any other keyword argument you | 304 304 | | might want to pass to the underlying Table object. | 305 +--------------------+--------------------------------------------------------+| ``column_format`` | DEPRECATED. Specify an alternate format string for | 305 +--------------------+--------------------------------------------------------+ 306 | ``column_format`` | DEPRECATED. Specify an alternate format string for | 306 307 | | naming the | 307 308 | | columns in the mapping table. The default value is | -
elixir/branches/0.7.x/examples/videostore/start-videostore.py
r11 r517 14 14 # probably installed 15 15 if len(sys.argv) > 1: 16 update_config(configfile=sys.argv[1], 16 update_config(configfile=sys.argv[1], 17 17 modulename="videostore.config") 18 18 elif exists(join(dirname(__file__), "setup.py")): -
elixir/branches/0.7.x/examples/videostore/videostore/controllers/root.py
r298 r517 7 7 8 8 class Root(RootController): 9 9 10 10 @expose(template='videostore.templates.index') 11 11 @identity.require(identity.not_anonymous()) 12 12 def index(self): 13 13 return dict(movies=Movie.query.all()) 14 15 14 15 16 16 @expose(template='videostore.templates.movie') 17 17 @identity.require(identity.not_anonymous()) … … 19 19 def movie(self, movieID): 20 20 return dict(movie=Movie.get(movieID)) 21 22 21 22 23 23 @expose(template='videostore.templates.actor') 24 24 @identity.require(identity.not_anonymous()) … … 26 26 def actor(self, actorID): 27 27 return dict(actor=Actor.get(actorID)) 28 29 28 29 30 30 @expose(template='videostore.templates.director') 31 31 @identity.require(identity.not_anonymous()) … … 33 33 def director(self, directorID): 34 34 return dict(director=Director.get(directorID)) 35 36 35 36 37 37 @expose(template='videostore.templates.login') 38 38 def login(self, forward_url=None, previous_url=None, *args, **kw): … … 41 41 identity.get_identity_errors(): 42 42 raise redirect(forward_url) 43 43 44 44 forward_url = None 45 45 previous_url = request.path 46 46 47 47 if identity.was_login_attempted(): 48 48 msg = 'The credentials you supplied were not correct.' … … 52 52 msg = 'Please log in.' 53 53 forward_url = request.headers.get('Referer', '/') 54 54 55 55 response.status = 403 56 return dict(message=msg, 57 previous_url=previous_url, 56 return dict(message=msg, 57 previous_url=previous_url, 58 58 logging_in=True, 59 59 original_parameters=request.params, 60 60 forward_url=forward_url) 61 62 61 62 63 63 @expose() 64 64 def logout(self): -
elixir/branches/0.7.x/examples/videostore/videostore/model.py
r316 r517 29 29 movies = ManyToMany('Movie', inverse='actors', tablename='movie_casting') 30 30 using_options(tablename='actors') 31 31 32 32 33 33 # 34 34 # identity model 35 # 35 # 36 36 37 37 class Visit(Entity): … … 40 40 expiry = Field(DateTime) 41 41 using_options(tablename='visit') 42 42 43 43 @classmethod 44 44 def lookup_visit(cls, visit_key): … … 68 68 groups = ManyToMany('Group', inverse='users') 69 69 using_options(tablename='tg_user') 70 70 71 71 @property 72 72 def permissions(self): -
elixir/branches/0.7.x/examples/videostore/videostore/tests/test_controllers.py
r11 r517 7 7 def teardown_func(): 8 8 """Tests for apps using identity need to stop CP/TG after each test to 9 stop the VisitManager thread. See http://trac.turbogears.org/turbogears/ticket/121710 for details.9 stop the VisitManager thread. 10 See http://trac.turbogears.org/turbogears/ticket/1217 for details. 11 11 """ 12 12 turbogears.startup.stopTurboGears() -
elixir/branches/0.7.x/release.howto
r390 r517 6 6 - change version in setup.py 7 7 - change version in setup.cfg (trac link) 8 - make sure API doc generates properly: apydia -v -c setup.cfg 8 9 - commit 9 10 - add version to the trac, mark milestone as completed11 10 12 11 - make tag in subversion … … 24 23 On older systems, you might need to upload the files manually to Pypi. 25 24 25 - add version to the trac, mark milestone as completed 26 26 27 - announce release on our news page (link to CHANGES) 27 28 -
elixir/branches/0.7.x/setup.cfg
r444 r517 10 10 elixir.ext.list, elixir.ext.perform_ddl, elixir.ext.versioned, 11 11 trac_browser_url = http://elixir.ematia.de/trac/browser/elixir/tags/0.7.0 12 trac_link_format = %s%s#L%s%s 12 13 -
elixir/branches/0.7.x/tests/test_custombase.py
r467 r517 4 4 5 5 from elixir import * 6 import elixir 6 7 7 8 def setup(): … … 35 36 36 37 assert a.name == 'a1' 38 39 def test_bad_property(self): 40 # create a meta entity which mimick cases where dir() method 41 # will report attribute that can't be directly accessed. 42 # Note: this happens with zope.interface. See ticket #98. 43 class BrokenDescriptor(object): 44 def __get__(*args): 45 raise AttributeError 46 47 class MyEntity(EntityBase): 48 __metaclass__ = EntityMeta 49 50 d = BrokenDescriptor() 51 52 class A(MyEntity): 53 value = Field(Unicode) 54 55 # we just check that the instrument_class phases doesn't trigger an 56 # exception 37 57 38 58 def test_inherit(self): … … 96 116 assert 'common' in A.table.columns 97 117 assert 'common' in B.table.columns 118 119 def test_base_with_relation(self): 120 class FieldBase(object): 121 __metaclass__ = EntityMeta 122 123 common = ManyToOne('A') 124 125 class A(FieldBase): 126 name = Field(String(32)) 127 128 class B(FieldBase): 129 pass 130 131 setup_all(True) 132 133 assert 'name' in A.table.columns 134 assert 'common_id' in A.table.columns 135 assert 'common_id' in B.table.columns 98 136 99 137 def test_base_with_fields_in_parent(self): … … 129 167 __metaclass__ = EntityMeta 130 168 131 using_options_defaults(tablename=camel_to_underscore) 169 options_defaults = dict(tablename=camel_to_underscore) 170 using_options_defaults(identity=camel_to_underscore) 171 using_options_defaults(inheritance='multi') 132 172 133 173 class TestA(OptionBase): 134 174 name = Field(String(32)) 135 175 136 class SuperTestB( OptionBase):176 class SuperTestB(TestA): 137 177 pass 138 178 … … 141 181 assert TestA.table.name == 'test_a' 142 182 assert SuperTestB.table.name == 'super_test_b' 143 183 assert TestA._descriptor.identity == 'test_a' 184 185 def test_base_custom_collection(self): 186 global A, B 187 188 collection = elixir.collection.RelativeEntityCollection() 189 190 class Base(object): 191 __metaclass__ = EntityMeta 192 using_options_defaults(collection=collection) 193 194 class A(Base): 195 b = ManyToOne('B') 196 197 class B(Base): 198 a = OneToOne('A') 199 200 assert not elixir.entities 201 assert A.table is None 202 assert B.table is None 203 204 setup_entities(collection) 205 206 assert A.table is not None 207 assert B.table is not None 208 209 del A 210 del B 211 212 def test_base_custom_session(self): 213 from sqlalchemy.orm import sessionmaker 214 215 class Base(object): 216 __metaclass__ = EntityMeta 217 using_options_defaults(session=None) 218 219 class A(Base): 220 b = ManyToOne('B') 221 222 class B(Base): 223 a = OneToOne('A') 224 225 setup_all(True) 226 227 a = A() 228 229 assert a not in elixir.session 230 231 session = sessionmaker()() 232 session.add(a) 233 assert a in session 234 -
elixir/branches/0.7.x/tests/test_events.py
r467 r517 4 4 from sqlalchemy import Table, Column 5 5 6 stateDict = {}7 8 def teardown():9 cleanup_all()10 6 11 7 class TestEvents(object): 12 def setup(self): 13 # reset counters 14 stateDict.update({ 8 def teardown(self): 9 cleanup_all(True) 10 11 def test_events(self): 12 # initialize counters 13 stateDict = { 15 14 'reconstructor_called': 0, 16 15 'before_insert_called': 0, … … 21 20 'after_delete_called': 0, 22 21 'before_any_called': 0 23 } )22 } 24 23 25 def teardown(self):26 cleanup_all()27 28 def test_events(self):29 24 events = Table('events', metadata, 30 25 Column('id', Integer, primary_key=True), -
elixir/branches/0.7.x/tests/test_options.py
r480 r517 60 60 setup_all(True) 61 61 62 raised = False63 62 try: 64 63 MyEntity._descriptor.add_column(Column('name', String(30))) 64 assert False 65 65 except Exception: 66 raised = True 67 68 assert raised 66 pass 69 67 70 68 def test_allowcoloverride_true(self): … … 204 202 205 203 def teardown(self): 206 cleanup_all( )204 cleanup_all(True) 207 205 208 206 def test_unique_constraint(self): 209 210 207 class Person(Entity): 211 208 firstname = Field(String(30)) … … 223 220 homer2 = Person(firstname="Homer", surname='Simpson') 224 221 225 raised = False 226 try: 227 session.commit() 228 except SQLError: 229 raised = True 230 231 assert raised 222 try: 223 session.commit() 224 assert False 225 except SQLError: 226 pass 227 228 def test_several_statements(self): 229 class A(Entity): 230 name1 = Field(String(30)) 231 name2 = Field(String(30)) 232 name3 = Field(String(30)) 233 using_table_options(UniqueConstraint('name1', 'name2')) 234 using_table_options(UniqueConstraint('name2', 'name3')) 235 236 setup_all(True) 237 238 a000 = A(name1='0', name2='0', name3='0') 239 a010 = A(name1='0', name2='1', name3='0') 240 session.commit() 241 242 a001 = A(name1='0', name2='0', name3='1') 243 try: 244 session.commit() 245 assert False 246 except SQLError: 247 session.close() 248 249 a100 = A(name1='1', name2='0', name3='0') 250 try: 251 session.commit() 252 assert False 253 except SQLError: 254 session.close() 232 255 233 256 def test_unique_constraint_many_to_one(self): -
elixir/branches/0.7.x/tests/test_packages.py
r467 r517 5 5 import sys 6 6 7 import elixir 7 8 from elixir import * 8 9 9 10 def setup(): 10 11 metadata.bind = 'sqlite://' 11 sys.modules.pop('tests.a', None)12 sys.modules.pop('tests.b', None)12 for module in ('a', 'b', 'db1', 'db1.a', 'db1.b', 'db1.c', 'db2', 'db2.a'): 13 sys.modules.pop('tests.%s' % module, None) 13 14 14 15 … … 46 47 def test_ref_to_imported_entity_using_class(self): 47 48 from tests.a import A 48 from tests.b import B49 import tests.b 49 50 50 51 class C(Entity): … … 57 58 58 59 def test_ref_to_imported_entity_using_name(self): 59 from tests.a import A60 from tests.b import B60 import tests.a 61 import tests.b 61 62 62 63 class C(Entity): … … 68 69 assert 'a_id' in C.table.columns 69 70 71 def test_resolve_root(self): 72 import tests.a 73 import tests.b 74 75 class C(Entity): 76 using_options(resolve_root='tests') 77 78 name = Field(String(30)) 79 a = ManyToOne('a.A') 80 81 setup_all(True) 82 83 assert 'a_id' in C.table.columns 84 85 def test_relative_collection(self): 86 from elixir.collection import RelativeEntityCollection, \ 87 GlobalEntityCollection 88 89 elixir.entities = RelativeEntityCollection() 90 91 import db1 92 import db2 93 94 setup_all(True) 95 96 try: 97 assert len(elixir.entities) == 5 98 finally: 99 elixir.entities = GlobalEntityCollection() -
elixir/branches/0.7.x/tests/test_through.py
r484 r517 39 39 40 40 user = User(name='log') 41 keywords = [Keyword('its_big'), Keyword('its_heavy'), Keyword('its_wood')] 41 keywords = [Keyword('its_big'), Keyword('its_heavy'), 42 Keyword('its_wood')] 42 43 for kw in keywords: 43 44 user.keywords.append(kw)
