Commits

Andrew Godwin committed 02ea2df

Introspection is now 'fully functional', in most senses. Deleted a part of modelsparser I don't need.

Comments (0)

Files changed (3)

+.*\.pyc
+\.hgignore

south/modelsinspector.py

     ),
 ]
 
+# Similar, but for Meta, so just the inner level (kwds).
+meta_details = {
+    "db_table": ["db_table", {"default_attr_concat": ["%s_%s", "app_label", "module_name"]}],
+    "db_tablespace": ["db_tablespace", {"default": settings.DEFAULT_TABLESPACE}],
+    "unique_together": ["unique_together", {"default": []}],
+}
+
 # 2.4 compatability
 any = lambda x: reduce(lambda y, z: y or z, x, False)
 
         default_value = get_attribute(field, options['default_attr'])
         if value == default_value:
             raise IsDefault
+    # Some are made from a formatting string and several attrs (e.g. db_table)
+    if "default_attr_concat" in options:
+        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
+        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
+        if value == default_value:
+            raise IsDefault
     # Models get their own special repr()
     if type(value) is ModelBase:
         return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
             field_defs[field.name] = field.south_field_triple()
         # Can we introspect it?
         elif can_introspect(field):
-            if NOISY:
-                print "Introspecting field: %s" % field.name
+            #if NOISY:
+            #    print "Introspecting field: %s" % field.name
             # Get the full field class path.
             field_class = field.__class__.__module__ + "." + field.__class__.__name__
             # Run this field through the introspector
     """
     Given a model class, will return the dict representing the Meta class.
     """
-    return modelsparser.get_model_meta(model)
+    
+    # Get the introspected attributes
+    meta_def = {}
+    for kwd, defn in meta_details.items():
+        try:
+            meta_def[kwd] = get_value(model._meta, defn)
+        except IsDefault:
+            pass
+    
+    return meta_def

south/modelsparser.py

 """
 Parsing module for models.py files. Extracts information in a more reliable
 way than inspect + regexes.
+Now only used as a fallback when introspection and the South custom hook both fail.
 """
 
 import re
         
     
     return fields
-
-
-def get_model_meta(model):
-    """
-    Given a model class, will return the dict representing the Meta class.
-    """
-    tree = get_model_tree(model)
-    
-    # No tree? No response.
-    if tree is None:
-        return None
-    
-    result = {}
-    
-    # First, try to get any unusual inherited classes
-    for base in model.__bases__:
-        if base is not models.Model:
-            if hasattr(base, '_meta') and not base._meta.abstract:
-                # Abstract models' fields are included anyway, and we don't
-                # want extra dependencies
-                if "_bases" not in result:
-                    result['_bases'] = []
-                result['_bases'].append(base.__module__ + "." + base.__name__)
-    
-    # Find all classes exactly two levels deep
-    possible_meta_classes = set(tree.find("classdef classdef"))
-    possible_meta_classes.difference(set(tree.find("classdef classdef classdef")))
-    
-    # Select only those called 'Meta', and expand all their assignments
-    possible_meta_classes = [
-        tree.find("^ > suite > stmt > simple_stmt > small_stmt > expr_stmt")
-        for tree in possible_meta_classes
-        if tree.value[2][1] == "Meta"
-    ]
-    
-    if possible_meta_classes:
-        # Now, for each possible definition, try it. (Only for last Meta,
-        # since that's how python interprets it)
-        for defn in possible_meta_classes[-1]:
-            bits = defn.flatten()
-            if len(bits) > 1 and bits[1] == token.EQUAL:
-                result[bits[0][1]] = reform(bits[2:])
-    
-    return result or None