]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- The ORM will set the docstring of all generated descriptors
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 Apr 2010 21:22:16 +0000 (17:22 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 Apr 2010 21:22:16 +0000 (17:22 -0400)
to None by default.  This can be overridden using 'doc'
(or if using Sphinx, attribute docstrings work too).

- Added kw argument 'doc' to all mapper property callables
as well as Column().  Will assemble the string 'doc' as
the '__doc__' attribute on the descriptor.

CHANGES
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/attributes.py
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/orm/strategies.py
lib/sqlalchemy/schema.py
test/orm/test_mapper.py

diff --git a/CHANGES b/CHANGES
index 4831295913b5017faced17731071a9508e210e0e..34458da77df21aad379dbcc268b484840290215f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -34,6 +34,14 @@ CHANGES
   - id(obj) is no longer used internally within topological.py,
     as the sorting functions now require hashable objects
     only.  [ticket:1756]
+
+  - The ORM will set the docstring of all generated descriptors
+    to None by default.  This can be overridden using 'doc'
+    (or if using Sphinx, attribute docstrings work too).
+    
+  - Added kw argument 'doc' to all mapper property callables 
+    as well as Column().  Will assemble the string 'doc' as 
+    the '__doc__' attribute on the descriptor.  
     
 - sql
   - Restored some bind-labeling logic from 0.5 which ensures
index 206c8d0c273d8c6aa72f304dedd03f2e1a8ef433..c2f6337bc9b1ecbb7b8da0cfa7866cdff8195bf9 100644 (file)
@@ -266,6 +266,9 @@ def relationship(argument, secondary=None, **kwargs):
       a class which extends :class:`RelationshipProperty.Comparator` which
       provides custom SQL clause generation for comparison operations.
 
+    :param doc:
+      docstring which will be applied to the resulting descriptor.
+      
     :param extension:
       an :class:`AttributeExtension` instance, or list of extensions,
       which will be prepended to the list of attribute listeners for
@@ -469,7 +472,7 @@ def relation(*arg, **kw):
 def dynamic_loader(argument, secondary=None, primaryjoin=None,
                    secondaryjoin=None, foreign_keys=None, backref=None,
                    post_update=False, cascade=False, remote_side=None,
-                   enable_typechecks=True, passive_deletes=False,
+                   enable_typechecks=True, passive_deletes=False, doc=None,
                    order_by=None, comparator_factory=None, query_class=None):
     """Construct a dynamically-loading mapper property.
 
@@ -508,7 +511,7 @@ def dynamic_loader(argument, secondary=None, primaryjoin=None,
         secondaryjoin=secondaryjoin, foreign_keys=foreign_keys, backref=backref,
         post_update=post_update, cascade=cascade, remote_side=remote_side,
         enable_typechecks=enable_typechecks, passive_deletes=passive_deletes,
-        order_by=order_by, comparator_factory=comparator_factory,
+        order_by=order_by, comparator_factory=comparator_factory,doc=doc,
         strategy_class=DynaLoader, query_class=query_class)
 
 def column_property(*args, **kwargs):
@@ -538,7 +541,11 @@ def column_property(*args, **kwargs):
           it does not load immediately, and is instead loaded when the
           attribute is first accessed on an instance.  See also
           :func:`~sqlalchemy.orm.deferred`.
-
+      
+      doc
+          optional string that will be applied as the doc on the
+          class-bound descriptor.
+          
       extension
         an :class:`~sqlalchemy.orm.interfaces.AttributeExtension` instance,
         or list of extensions, which will be prepended to the list of
@@ -612,6 +619,10 @@ def composite(class_, *cols, **kwargs):
       a class which extends ``sqlalchemy.orm.properties.CompositeProperty.Comparator``
       which provides custom SQL clause generation for comparison operations.
 
+    doc
+      optional string that will be applied as the doc on the
+      class-bound descriptor.
+
     extension
       an :class:`~sqlalchemy.orm.interfaces.AttributeExtension` instance,
       or list of extensions, which will be prepended to the list of
@@ -813,7 +824,7 @@ def mapper(class_, local_table=None, *args, **params):
     """
     return Mapper(class_, local_table, *args, **params)
 
-def synonym(name, map_column=False, descriptor=None, comparator_factory=None):
+def synonym(name, map_column=False, descriptor=None, comparator_factory=None, doc=None):
     """Set up `name` as a synonym to another mapped property.
 
     Used with the ``properties`` dictionary sent to  :func:`~sqlalchemy.orm.mapper`.
@@ -851,7 +862,10 @@ def synonym(name, map_column=False, descriptor=None, comparator_factory=None):
     proxy access to the column-based attribute.
 
     """
-    return SynonymProperty(name, map_column=map_column, descriptor=descriptor, comparator_factory=comparator_factory)
+    return SynonymProperty(name, map_column=map_column, 
+                            descriptor=descriptor, 
+                            comparator_factory=comparator_factory,
+                            doc=doc)
 
 def comparable_property(comparator_factory, descriptor=None):
     """Provide query semantics for an unmanaged attribute.
index 887d9a9c1211b8b7293748ad4773609514bbd45c..b631ea2c9f22be3c749a0d7b9d63c38a86cd70e0 100644 (file)
@@ -1366,12 +1366,12 @@ def unregister_class(class_):
     instrumentation_registry.unregister(class_)
 
 def register_attribute(class_, key, **kw):
-
     proxy_property = kw.pop('proxy_property', None)
     
     comparator = kw.pop('comparator', None)
     parententity = kw.pop('parententity', None)
-    register_descriptor(class_, key, proxy_property, comparator, parententity)
+    doc = kw.pop('doc', None)
+    register_descriptor(class_, key, proxy_property, comparator, parententity, doc=doc)
     if not proxy_property:
         register_attribute_impl(class_, key, **kw)
     
@@ -1405,7 +1405,8 @@ def register_attribute_impl(class_, key,
     
     manager.post_configure_attribute(key)
     
-def register_descriptor(class_, key, proxy_property=None, comparator=None, parententity=None, property_=None):
+def register_descriptor(class_, key, proxy_property=None, comparator=None, 
+                                parententity=None, property_=None, doc=None):
     manager = manager_of_class(class_)
 
     if proxy_property:
@@ -1413,7 +1414,9 @@ def register_descriptor(class_, key, proxy_property=None, comparator=None, paren
         descriptor = proxy_type(key, proxy_property, comparator, parententity)
     else:
         descriptor = InstrumentedAttribute(key, comparator=comparator, parententity=parententity)
-
+    
+    descriptor.__doc__ = doc
+        
     manager.instrument_attribute(key, descriptor)
 
 def unregister_attribute(class_, key):
index 2a5e92c1a8f6a76eae9ebebb942ad2ffc733ea2b..41024101b88c56ceb02d9502504eace901e3286b 100644 (file)
@@ -58,6 +58,8 @@ class ColumnProperty(StrategizedProperty):
         self.comparator_factory = kwargs.pop('comparator_factory', self.__class__.Comparator)
         self.descriptor = kwargs.pop('descriptor', None)
         self.extension = kwargs.pop('extension', None)
+        self.doc = kwargs.pop('doc', getattr(columns[0], 'doc', None))
+        
         if kwargs:
             raise TypeError(
                 "%s received unexpected keyword argument(s): %s" % (
@@ -80,7 +82,8 @@ class ColumnProperty(StrategizedProperty):
             self.key, 
             comparator=self.comparator_factory(self, mapper), 
             parententity=mapper,
-            property_=self
+            property_=self,
+            doc=self.doc
             )
         
     def do_init(self):
@@ -259,11 +262,12 @@ class SynonymProperty(MapperProperty):
 
     extension = None
 
-    def __init__(self, name, map_column=None, descriptor=None, comparator_factory=None):
+    def __init__(self, name, map_column=None, descriptor=None, comparator_factory=None, doc=None):
         self.name = name
         self.map_column = map_column
         self.descriptor = descriptor
         self.comparator_factory = comparator_factory
+        self.doc = doc or (descriptor and descriptor.__doc__) or None
         util.set_creation_order(self)
 
     def setup(self, context, entity, path, adapter, **kwargs):
@@ -303,7 +307,8 @@ class SynonymProperty(MapperProperty):
             comparator=comparator_callable(self, mapper), 
             parententity=mapper,
             property_=self,
-            proxy_property=self.descriptor
+            proxy_property=self.descriptor,
+            doc=self.doc
             )
 
     def merge(self, session, source_state, source_dict, dest_state, dest_dict, load, _recursive):
@@ -316,9 +321,10 @@ class ComparableProperty(MapperProperty):
 
     extension = None
     
-    def __init__(self, comparator_factory, descriptor=None):
+    def __init__(self, comparator_factory, descriptor=None, doc=None):
         self.descriptor = descriptor
         self.comparator_factory = comparator_factory
+        self.doc = doc or (descriptor and descriptor.__doc__) or None
         util.set_creation_order(self)
 
     def instrument_class(self, mapper):
@@ -330,7 +336,8 @@ class ComparableProperty(MapperProperty):
             comparator=self.comparator_factory(self, mapper), 
             parententity=mapper,
             property_=self,
-            proxy_property=self.descriptor
+            proxy_property=self.descriptor,
+            doc=self.doc,
             )
 
     def setup(self, context, entity, path, adapter, **kwargs):
@@ -364,6 +371,7 @@ class RelationshipProperty(StrategizedProperty):
         enable_typechecks=True, join_depth=None,
         comparator_factory=None,
         single_parent=False, innerjoin=False,
+        doc=None,
         strategy_class=None, _local_remote_pairs=None, query_class=None):
 
         self.uselist = uselist
@@ -384,7 +392,7 @@ class RelationshipProperty(StrategizedProperty):
         self.enable_typechecks = enable_typechecks
         self.query_class = query_class
         self.innerjoin = innerjoin
-
+        self.doc = doc
         self.join_depth = join_depth
         self.local_remote_pairs = _local_remote_pairs
         self.extension = extension
@@ -433,7 +441,8 @@ class RelationshipProperty(StrategizedProperty):
             self.key, 
             comparator=self.comparator_factory(self, mapper), 
             parententity=mapper,
-            property_=self
+            property_=self,
+            doc=self.doc,
             )
 
     class Comparator(PropComparator):
@@ -1149,7 +1158,7 @@ class RelationshipProperty(StrategizedProperty):
             parent = self.parent.primary_mapper()
             kwargs.setdefault('viewonly', self.viewonly)
             kwargs.setdefault('post_update', self.post_update)
-            
+
             self.back_populates = backref_key
             relationship = RelationshipProperty(
                                         parent, 
index 93b1170f45c18d6194d4047350a1e5fee3102ab4..39657564a0b42e2064e5b6e2a7ec388f33c617c9 100644 (file)
@@ -66,6 +66,7 @@ def _register_attribute(strategy, mapper, useobject,
                 callable_=callable_, 
                 active_history=active_history,
                 impl_class=impl_class,
+                doc=prop.doc,
                 **kw
                 )
 
index 8ffb68a4eb7c1ab05ce87118d6eb68acd1ab7d8a..0e03be686f614e5b04d1665d96286abcd9cfd154 100644 (file)
@@ -535,6 +535,10 @@ class Column(SchemaItem, expression.ColumnClause):
             Contrast this argument to ``server_default`` which creates a 
             default generator on the database side.
         
+        :param doc: optional String that can be used by the ORM or similar
+            to document attributes.   This attribute does not render SQL
+            comments (a future attribute 'comment' will achieve that).
+            
         :param key: An optional string identifier which will identify this
             ``Column`` object on the :class:`Table`. When a key is provided,
             this is the only identifier referencing the ``Column`` within the
@@ -651,6 +655,7 @@ class Column(SchemaItem, expression.ColumnClause):
         self.index = kwargs.pop('index', None)
         self.unique = kwargs.pop('unique', None)
         self.quote = kwargs.pop('quote', None)
+        self.doc = kwargs.pop('doc', None)
         self.onupdate = kwargs.pop('onupdate', None)
         self.autoincrement = kwargs.pop('autoincrement', True)
         self.constraints = set()
index 02be04edc6e0f629b96b8beb1dd4798545380d24..6687a9a611a7d246aab861ac8152d679c486daba 100644 (file)
@@ -1079,7 +1079,51 @@ class MapperTest(_fixtures.FixtureTest):
 
         mapper(B, users)
 
-
+class DocumentTest(_base.MappedTest):
+    @classmethod
+    def define_tables(cls, metadata):
+        Table('t1', metadata,
+            Column('col1', Integer, primary_key=True, doc="primary key column"),
+            Column('col2', String, doc="data col"),
+            Column('col3', String, doc="data col 2"),
+            Column('col4', String, doc="data col 3"),
+            Column('col5', String),
+        )
+        Table('t2', metadata,
+            Column('col1', Integer, primary_key=True, doc="primary key column"),
+            Column('col2', String, doc="data col"),
+            Column('col3', Integer, ForeignKey('t1.col1'), doc="foreign key to t1.col1")
+        )
+        
+    @testing.resolve_artifact_names
+    def test_doc_propagate(self):
+        class Foo(object):
+            pass
+        
+        class Bar(object):
+            pass
+            
+        mapper(Foo, t1, properties={
+            'bars':relationship(Bar, 
+                                    doc="bar relationship", 
+                                    backref=backref('foo',doc='foo relationship')
+                                ),
+            'foober':column_property(t1.c.col3, doc='alternate data col'),
+            'hoho':synonym(t1.c.col4, doc="syn of col4")
+        })
+        mapper(Bar, t2)
+        compile_mappers()
+        eq_(Foo.col1.__doc__, "primary key column")
+        eq_(Foo.col2.__doc__, "data col")
+        eq_(Foo.col5.__doc__, None)
+        eq_(Foo.foober.__doc__, "alternate data col")
+        eq_(Foo.bars.__doc__, "bar relationship")
+        eq_(Foo.hoho.__doc__, "syn of col4")
+        eq_(Bar.col1.__doc__, "primary key column")
+        eq_(Bar.foo.__doc__, "foo relationship")
+        
+        
+        
 class OptionsTest(_fixtures.FixtureTest):
 
     @testing.fails_on('maxdb', 'FIXME: unknown')