Changeset 490 for elixir/trunk/elixir
- Timestamp:
- 10/02/09 12:06:14 (3 years ago)
- Location:
- elixir/trunk/elixir
- Files:
-
- 2 removed
- 5 modified
-
__init__.py (modified) (1 diff)
-
collection.py (modified) (2 diffs)
-
entity.py (modified) (9 diffs)
-
ext/list.py (deleted)
-
options.py (modified) (2 diffs)
-
py23compat.py (deleted)
-
relationships.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
elixir/trunk/elixir/__init__.py
r416 r490 86 86 '''Setup the table and mapper of all entities in the default entity 87 87 collection. 88 89 This is called automatically if any entity of the collection is configured90 with the `autosetup` option and it is first accessed,91 instanciated (called) or the create_all method of a metadata containing92 tables from any of those entities is called.93 88 ''' 94 89 setup_entities(entities) -
elixir/trunk/elixir/collection.py
r439 r490 3 3 ''' 4 4 import sys 5 6 from elixir.py23compat import rsplit7 5 8 6 # default entity collection … … 33 31 "source" entity when resolving relationship targets. 34 32 ''' 35 path = rsplit(key,'.', 1)33 path = key.rsplit('.', 1) 36 34 classname = path.pop() 37 35 if path: -
elixir/trunk/elixir/entity.py
r480 r490 3 3 ``EntityMeta``. 4 4 ''' 5 6 from py23compat import sorted7 5 8 6 import sys … … 499 497 self.has_pk = True 500 498 501 # Autosetup triggers shouldn't be active anymore at this point, so we 502 # can theoretically access the entity's table safely. But the problem 503 # is that if, for some reason, the trigger removal phase didn't 504 # happen, we'll get an infinite loop. So we just make sure we don't 505 # get one in any case. 506 table = type.__getattribute__(self.entity, 'table') 499 table = self.entity.table 507 500 if table is not None: 508 501 if check_duplicate and col.key in table.columns.keys(): … … 691 684 692 685 693 class TriggerProxy(object):694 """695 A class that serves as a "trigger" ; accessing its attributes runs696 the setup_all function.697 698 Note that the `setup_all` is called on each access of the attribute.699 """700 701 def __init__(self, class_, attrname):702 self.class_ = class_703 self.attrname = attrname704 705 def __getattr__(self, name):706 elixir.setup_all()707 #FIXME: it's possible to get an infinite loop here if setup_all doesn't708 #remove the triggers for this entity. This can happen if the entity is709 #not in the `entities` list for some reason.710 proxied_attr = getattr(self.class_, self.attrname)711 return getattr(proxied_attr, name)712 713 def __repr__(self):714 proxied_attr = getattr(self.class_, self.attrname)715 return "<TriggerProxy (%s)>" % (self.class_.__name__)716 717 718 class TriggerAttribute(object):719 720 def __init__(self, attrname):721 self.attrname = attrname722 723 def __get__(self, instance, owner):724 #FIXME: it's possible to get an infinite loop here if setup_all doesn't725 #remove the triggers for this entity. This can happen if the entity is726 #not in the `entities` list for some reason.727 elixir.setup_all()728 return getattr(owner, self.attrname)729 730 686 def is_entity(cls): 731 687 """ … … 774 730 prop.attach(cls, name) 775 731 776 # Process mutators. Needed before _install_autosetup_triggers so that 777 # we know of the metadata (and whether the entity is autosetuped or not). 732 # Process mutators 778 733 process_mutators(cls) 779 734 780 735 # setup misc options here (like tablename etc.) 781 736 desc.setup_options() 782 783 # create trigger proxies784 # TODO: support entity_name... It makes sense only for autoloaded785 # tables for now, and would make more sense if we support "external"786 # tables787 if desc.autosetup:788 _install_autosetup_triggers(cls)789 737 790 738 … … 808 756 instrument_class(cls) 809 757 810 def __call__(cls, *args, **kwargs):811 if cls._descriptor.autosetup and not hasattr(cls, '_setup_done'):812 elixir.setup_all()813 return type.__call__(cls, *args, **kwargs)814 815 758 def __setattr__(cls, key, value): 816 759 if isinstance(value, Property): … … 824 767 825 768 826 def _install_autosetup_triggers(cls, entity_name=None):827 #TODO: move as much as possible of those "_private" values to the828 # descriptor, so that we don't mess the initial class.829 warnings.warn("The 'autosetup' option on entities is deprecated. "830 "Please call setup_all() manually after all your entities have been "831 "declared.", DeprecationWarning, stacklevel=4)832 tablename = cls._descriptor.tablename833 schema = cls._descriptor.table_options.get('schema', None)834 cls._table_key = sqlalchemy.schema._get_table_key(tablename, schema)835 836 table_proxy = TriggerProxy(cls, 'table')837 838 md = cls._descriptor.metadata839 md.tables[cls._table_key] = table_proxy840 841 # We need to monkeypatch the metadata's table iterator method because842 # otherwise it doesn't work if the setup is triggered by the843 # metadata.create_all().844 # This is because ManyToMany relationships add tables AFTER the list845 # of tables that are going to be created is "computed"846 # (metadata.tables.values()).847 # see:848 # - table_iterator method in MetaData class in sqlalchemy/schema.py849 # - visit_metadata method in sqlalchemy/ansisql.py850 if SA05orlater:851 warnings.warn(852 "The automatic setup via metadata.create_all() through "853 "the autosetup option doesn't work with SQLAlchemy 0.5 and later!")854 else:855 # SA 0.6 does not use table_iterator anymore (it was already deprecated856 # since SA 0.5.0)857 original_table_iterator = md.table_iterator858 if not hasattr(original_table_iterator,859 '_non_elixir_patched_iterator'):860 def table_iterator(*args, **kwargs):861 elixir.setup_all()862 return original_table_iterator(*args, **kwargs)863 table_iterator.__doc__ = original_table_iterator.__doc__864 table_iterator._non_elixir_patched_iterator = \865 original_table_iterator866 md.table_iterator = table_iterator867 868 #TODO: we might want to add all columns that will be available as869 #attributes on the class itself (in SA 0.4+). This is a pretty870 #rare usecase, as people will normally hit the query attribute before the871 #column attributes, but I've seen people hitting this problem...872 for name in ('c', 'table', 'mapper', 'query'):873 setattr(cls, name, TriggerAttribute(name))874 875 cls._has_triggers = True876 877 878 def _cleanup_autosetup_triggers(cls):879 if not hasattr(cls, '_has_triggers'):880 return881 882 for name in ('table', 'mapper'):883 setattr(cls, name, None)884 885 for name in ('c', 'query'):886 delattr(cls, name)887 888 desc = cls._descriptor889 md = desc.metadata890 891 # the fake table could have already been removed (namely in a892 # single table inheritance scenario)893 md.tables.pop(cls._table_key, None)894 895 # restore original table iterator if not done already896 if not SA05orlater:897 if hasattr(md.table_iterator, '_non_elixir_patched_iterator'):898 md.table_iterator = \899 md.table_iterator._non_elixir_patched_iterator900 901 del cls._has_triggers902 903 904 769 def setup_entities(entities): 905 770 '''Setup all entities in the list passed as argument''' … … 912 777 if isinstance(attr, Property): 913 778 delattr(entity, name) 914 915 if entity._descriptor.autosetup:916 _cleanup_autosetup_triggers(entity)917 779 918 780 for method_name in ( … … 940 802 """ 941 803 Try to revert back the list of entities passed as argument to the state 942 they had just before their setup phase. It will not work entirely for 943 autosetup entities as we need to remove the autosetup triggers. 804 they had just before their setup phase. 944 805 945 806 As of now, this function is *not* functional in that it doesn't revert to … … 953 814 for entity in entities: 954 815 desc = entity._descriptor 955 if desc.autosetup:956 _cleanup_autosetup_triggers(entity)957 816 958 817 if hasattr(entity, '_setup_done'): -
elixir/trunk/elixir/options.py
r484 r490 116 116 | | that module. | 117 117 +---------------------+-------------------------------------------------------+ 118 | ``autosetup`` | DEPRECATED. Specify whether that entity will contain |119 | | automatic setup triggers. |120 | | That is if this entity will be |121 | | automatically setup (along with all other entities |122 | | which were already declared) if any of the following |123 | | condition happen: some of its attributes are accessed |124 | | ('c', 'table', 'mapper' or 'query'), instanciated |125 | | (called) or the create_all method of this entity's |126 | | metadata is called. Defaults to ``False``. |127 +---------------------+-------------------------------------------------------+128 118 | ``allowcoloverride``| Specify whether it is allowed to override columns. | 129 119 | | By default, Elixir forbids you to add a column to an | … … 214 204 # 215 205 options_defaults = dict( 216 autosetup=False,217 206 inheritance='single', 218 207 polymorphic=True, -
elixir/trunk/elixir/relationships.py
r488 r490 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 |306 | | naming the |307 | | columns in the mapping table. The default value is |308 | | defined in ``elixir.options.M2MCOL_NAMEFORMAT``. You |309 | | will be passed ``tablename``, ``key``, and ``entity`` |310 | | as arguments to the format string. |311 305 +--------------------+--------------------------------------------------------+ 312 306 … … 839 833 ondelete=None, onupdate=None, 840 834 table=None, schema=None, 841 column_format=None,842 835 filter=None, 843 836 table_kwargs=None, … … 858 851 self.schema = schema 859 852 860 if column_format: 861 warnings.warn("The 'column_format' argument on ManyToMany " 862 "relationships is deprecated. Please use the 'local_colname' " 863 "and/or 'remote_colname' arguments if you want custom " 864 "column names for this table only, or modify " 865 "options.M2MCOL_NAMEFORMAT if you want a custom format for " 866 "all ManyToMany tables", DeprecationWarning, stacklevel=3) 867 self.column_format = column_format or options.M2MCOL_NAMEFORMAT 853 #TODO: this can probably be simplified/moved elsewhere since the 854 #argument disappeared 855 self.column_format = options.M2MCOL_NAMEFORMAT 868 856 if not hasattr(self.column_format, '__call__'): 869 857 # we need to store the format in a variable so that the … … 890 878 891 879 super(ManyToMany, self).__init__(of_kind, *args, **kwargs) 892 893 def get_table(self):894 warnings.warn("The secondary_table attribute on ManyToMany objects is "895 "deprecated. You should rather use the table attribute.",896 DeprecationWarning, stacklevel=2)897 return self.table898 secondary_table = property(get_table)899 880 900 881 def match_type_of(self, other):
