]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- ForeignKey(constraint=some_parent) is now private _constraint
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 9 Nov 2009 23:40:57 +0000 (23:40 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 9 Nov 2009 23:40:57 +0000 (23:40 +0000)
- ForeignKey and ForeignKeyConstraint objects now correctly
copy() all their public keyword arguments.  [ticket:1605]

CHANGES
lib/sqlalchemy/schema.py
test/engine/test_metadata.py

diff --git a/CHANGES b/CHANGES
index a59bf971e51fc6aea451c5751339c25aa9efaa60..698c4760e276a18e860e42dc3f01202ef04b8957 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -323,6 +323,7 @@ CHANGES
         - Column.bind       (get via column.table.bind)
         - Column.metadata   (get via column.table.metadata)
         - Column.sequence   (use column.default)
+        - ForeignKey(constraint=some_parent) (is now private _constraint)
         
     - The use_alter flag on ForeignKey is now a shortcut option
       for operations that can be hand-constructed using the
@@ -332,7 +333,10 @@ CHANGES
       ALTER for foreign keys. This has no effect on SQLite's
       behavior since SQLite does not actually honor FOREIGN KEY
       constraints.
-
+    
+    - ForeignKey and ForeignKeyConstraint objects now correctly
+      copy() all their public keyword arguments.  [ticket:1605]
+      
 - Reflection/Inspection
     - Table reflection has been expanded and generalized into 
       a new API called "sqlalchemy.engine.reflection.Inspector".
index 00a21a30af67f4520c43dda1c7ceb9e3a4e59a46..3dee2a0ba08d01ea96c7d9f1fe4dc11431854cab 100644 (file)
@@ -840,61 +840,64 @@ class ForeignKey(SchemaItem):
             Column("remote_id", ForeignKey("main_table.id"))
         )
 
-    For a composite (multiple column) FOREIGN KEY, use a :class:`ForeignKeyConstraint`
-    object specified at the level of the :class:`Table`.
+    For a composite (multiple column) FOREIGN KEY, use a
+    :class:`ForeignKeyConstraint` object specified at the level of the
+    :class:`Table`.
     
-    Further examples of foreign key configuration are in :ref:`metadata_foreignkeys`.
+    Further examples of foreign key configuration are in
+    :ref:`metadata_foreignkeys`.
 
     """
 
     __visit_name__ = 'foreign_key'
 
-    def __init__(self, column, constraint=None, use_alter=False, name=None, onupdate=None, 
-                    ondelete=None, deferrable=None, initially=None, link_to_name=False):
+    def __init__(self, column, _constraint=None, use_alter=False, name=None,
+                    onupdate=None, ondelete=None, deferrable=None,
+                    initially=None, link_to_name=False):
         """
         Construct a column-level FOREIGN KEY.  
         
-        The :class:`ForeignKey` object when constructed generates a :class:`ForeignKeyConstraint`
-        which is associated with the parent :class:`Table` object's collection of constraints.
+        The :class:`ForeignKey` object when constructed generates a
+        :class:`ForeignKeyConstraint` which is associated with the parent
+        :class:`Table` object's collection of constraints.
 
-        :param column: A single target column for the key relationship.  A :class:`Column`
-          object or a column name as a string: ``tablename.columnkey`` or
-          ``schema.tablename.columnkey``.  ``columnkey`` is the ``key`` which has been assigned
-          to the column (defaults to the column name itself), unless ``link_to_name`` is ``True``
-          in which case the rendered name of the column is used.
+        :param column: A single target column for the key relationship. A
+        :class:`Column` object or a column name as a string:
+        ``tablename.columnkey`` or ``schema.tablename.columnkey``.
+        ``columnkey`` is the ``key`` which has been assigned to the column
+        (defaults to the column name itself), unless ``link_to_name`` is
+        ``True`` in which case the rendered name of the column is used.
 
-        :param constraint: Optional.  A parent :class:`ForeignKeyConstraint` object.  If not
-          supplied, a :class:`ForeignKeyConstraint` will be automatically created
-          and added to the parent table.
+        :param name: Optional string. An in-database name for the key if
+        `constraint` is not provided.
 
-        :param name: Optional string.  An in-database name for the key if `constraint` is
-          not provided.
+        :param onupdate: Optional string. If set, emit ON UPDATE <value> when
+        issuing DDL for this constraint. Typical values include CASCADE,
+        DELETE and RESTRICT.
 
-        :param onupdate: Optional string.  If set, emit ON UPDATE <value> when issuing DDL
-          for this constraint.  Typical values include CASCADE, DELETE and
-          RESTRICT.
+        :param ondelete: Optional string. If set, emit ON DELETE <value> when
+        issuing DDL for this constraint. Typical values include CASCADE,
+        DELETE and RESTRICT.
 
-        :param ondelete: Optional string.  If set, emit ON DELETE <value> when issuing DDL
-          for this constraint.  Typical values include CASCADE, DELETE and
-          RESTRICT.
+        :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT
+        DEFERRABLE when issuing DDL for this constraint.
 
-        :param deferrable: Optional bool.  If set, emit DEFERRABLE or NOT DEFERRABLE when
-          issuing DDL for this constraint.
-
-        :param initially: Optional string.  If set, emit INITIALLY <value> when issuing DDL
-          for this constraint.
+        :param initially: Optional string. If set, emit INITIALLY <value> when
+        issuing DDL for this constraint.
         
-        :param link_to_name: if True, the string name given in ``column`` is the rendered
-          name of the referenced column, not its locally assigned ``key``.
+        :param link_to_name: if True, the string name given in ``column`` is
+        the rendered name of the referenced column, not its locally assigned
+        ``key``.
           
-        :param use_alter: passed to the underlying :class:`ForeignKeyConstraint` to indicate the
-          constraint should be generated/dropped externally from the CREATE TABLE/
-          DROP TABLE statement.  See that classes' constructor for details.
+        :param use_alter: passed to the underlying
+        :class:`ForeignKeyConstraint` to indicate the constraint should be
+        generated/dropped externally from the CREATE TABLE/ DROP TABLE
+        statement. See that classes' constructor for details.
         
         """
 
         self._colspec = column
-        self.constraint = constraint
+        self.constraint = _constraint
         self.use_alter = use_alter
         self.name = name
         self.onupdate = onupdate
@@ -909,7 +912,16 @@ class ForeignKey(SchemaItem):
     def copy(self, schema=None):
         """Produce a copy of this ForeignKey object."""
 
-        return ForeignKey(self._get_colspec(schema=schema))
+        return ForeignKey(
+                self._get_colspec(schema=schema),
+                use_alter=self.use_alter,
+                name=self.name,
+                onupdate=self.onupdate,
+                ondelete=self.ondelete,
+                deferrable=self.deferrable,
+                initially=self.initially,
+                link_to_name=self.link_to_name
+                )
 
     def _get_colspec(self, schema=None):
         if schema:
@@ -1394,52 +1406,56 @@ class ForeignKeyConstraint(Constraint):
 
     Defines a single column or composite FOREIGN KEY ... REFERENCES
     constraint. For a no-frills, single column foreign key, adding a
-    :class:`ForeignKey` to the definition of a :class:`Column` is a shorthand equivalent
-    for an unnamed, single column :class:`ForeignKeyConstraint`.
+    :class:`ForeignKey` to the definition of a :class:`Column` is a shorthand
+    equivalent for an unnamed, single column :class:`ForeignKeyConstraint`.
     
     Examples of foreign key configuration are in :ref:`metadata_foreignkeys`.
     
     """
     __visit_name__ = 'foreign_key_constraint'
 
-    def __init__(self, columns, refcolumns, name=None, onupdate=None, ondelete=None, 
-                    deferrable=None, initially=None, use_alter=False, link_to_name=False, table=None):
+    def __init__(self, columns, refcolumns, name=None, onupdate=None,
+            ondelete=None, deferrable=None, initially=None, use_alter=False,
+            link_to_name=False, table=None):
         """Construct a composite-capable FOREIGN KEY.
 
-        :param columns: A sequence of local column names.  The named columns must be defined
-          and present in the parent Table.  The names should match the ``key`` given 
-          to each column (defaults to the name) unless ``link_to_name`` is True.
+        :param columns: A sequence of local column names. The named columns
+        must be defined and present in the parent Table. The names should
+        match the ``key`` given to each column (defaults to the name) unless
+        ``link_to_name`` is True.
 
-        :param refcolumns: A sequence of foreign column names or Column objects.  The columns
-          must all be located within the same Table.
+        :param refcolumns: A sequence of foreign column names or Column
+        objects. The columns must all be located within the same Table.
 
         :param name: Optional, the in-database name of the key.
 
-        :param onupdate: Optional string.  If set, emit ON UPDATE <value> when issuing DDL
-          for this constraint.  Typical values include CASCADE, DELETE and
-          RESTRICT.
-
-        :param ondelete: Optional string.  If set, emit ON DELETE <value> when issuing DDL
-          for this constraint.  Typical values include CASCADE, DELETE and
-          RESTRICT.
-
-        :param deferrable: Optional bool.  If set, emit DEFERRABLE or NOT DEFERRABLE when
-          issuing DDL for this constraint.
-
-        :param initially: Optional string.  If set, emit INITIALLY <value> when issuing DDL
-          for this constraint.
-
-        :param link_to_name: if True, the string name given in ``column`` is the rendered
-          name of the referenced column, not its locally assigned ``key``.
-
-        :param use_alter: If True, do not emit the DDL for this constraint
-          as part of the CREATE TABLE definition.  Instead, generate it via an 
-          ALTER TABLE statement issued after the full collection of tables have been 
-          created, and drop it via an ALTER TABLE statement before the full collection 
-          of tables are dropped.   This is shorthand for the usage of 
-          :class:`AddConstraint` and :class:`DropConstraint` applied as "after-create"
-          and "before-drop" events on the MetaData object.   This is normally used to
-          generate/drop constraints on objects that are mutually dependent on each other.
+        :param onupdate: Optional string. If set, emit ON UPDATE <value> when
+        issuing DDL for this constraint. Typical values include CASCADE,
+        DELETE and RESTRICT.
+
+        :param ondelete: Optional string. If set, emit ON DELETE <value> when
+        issuing DDL for this constraint. Typical values include CASCADE,
+        DELETE and RESTRICT.
+
+        :param deferrable: Optional bool. If set, emit DEFERRABLE or NOT
+        DEFERRABLE when issuing DDL for this constraint.
+
+        :param initially: Optional string. If set, emit INITIALLY <value> when
+        issuing DDL for this constraint.
+
+        :param link_to_name: if True, the string name given in ``column`` is
+        the rendered name of the referenced column, not its locally assigned
+        ``key``.
+
+        :param use_alter: If True, do not emit the DDL for this constraint as
+        part of the CREATE TABLE definition. Instead, generate it via an ALTER
+        TABLE statement issued after the full collection of tables have been
+        created, and drop it via an ALTER TABLE statement before the full
+        collection of tables are dropped. This is shorthand for the usage of
+        :class:`AddConstraint` and :class:`DropConstraint` applied as
+        "after-create" and "before-drop" events on the MetaData object. This
+        is normally used to generate/drop constraints on objects that are
+        mutually dependent on each other.
           
         """
         super(ForeignKeyConstraint, self).__init__(name, deferrable, initially)
@@ -1455,7 +1471,7 @@ class ForeignKeyConstraint(Constraint):
         for col, refcol in zip(columns, refcolumns):
             self._elements[col] = ForeignKey(
                     refcol, 
-                    constraint=self, 
+                    _constraint=self, 
                     name=self.name, 
                     onupdate=self.onupdate, 
                     ondelete=self.ondelete, 
@@ -1494,7 +1510,10 @@ class ForeignKeyConstraint(Constraint):
                     name=self.name, 
                     onupdate=self.onupdate, 
                     ondelete=self.ondelete, 
-                    use_alter=self.use_alter
+                    use_alter=self.use_alter,
+                    deferrable=self.deferrable,
+                    initially=self.initially,
+                    link_to_name=self.link_to_name
                 )
 
 class PrimaryKeyConstraint(ColumnCollectionConstraint):
index e8e7b472faf42970fc5282b24baebe3b707b9d8a..56b6d6a102b32c2e2347a50b537940df856b3814 100644 (file)
@@ -1,6 +1,7 @@
 from sqlalchemy.test.testing import assert_raises, assert_raises_message
 import pickle
-from sqlalchemy import Integer, String, UniqueConstraint, CheckConstraint, ForeignKey, MetaData, Sequence
+from sqlalchemy import Integer, String, UniqueConstraint, CheckConstraint,\
+                        ForeignKey, MetaData, Sequence, ForeignKeyConstraint
 from sqlalchemy.test.schema import Table, Column
 from sqlalchemy import schema
 import sqlalchemy as tsa
@@ -53,6 +54,28 @@ class MetaDataTest(TestBase, ComparesTables):
         finally:
             metadata.drop_all()
     
+    def test_fk_copy(self):
+        c1 = Column('foo', Integer)
+        c2 = Column('bar', Integer)
+        m = MetaData()
+        t1 = Table('t', m, c1, c2)
+        
+        kw = dict(onupdate="X", 
+                        ondelete="Y", use_alter=True, name='f1',
+                        deferrable="Z", initially="Q", link_to_name=True)
+                        
+        fk1 = ForeignKey(c1, **kw) 
+        fk2 = ForeignKeyConstraint((c1,), (c2,), **kw)
+        
+        t1.append_constraint(fk2)
+        fk1c = fk1.copy()
+        fk2c = fk2.copy()
+        
+        for k in kw:
+            eq_(getattr(fk1c, k), kw[k])
+            eq_(getattr(fk2c, k), kw[k])
+        
+        
     @testing.exclude('mysql', '<', (4, 1, 1), 'early types are squirrely')
     def test_to_metadata(self):
         meta = MetaData()
@@ -69,7 +92,9 @@ class MetaDataTest(TestBase, ComparesTables):
 
         table2 = Table('othertable', meta,
             Column('id', Integer, Sequence('foo_seq'), primary_key=True),
-            Column('myid', Integer, ForeignKey('mytable.myid')),
+            Column('myid', Integer, 
+                        ForeignKey('mytable.myid'),
+                    ),
             test_needs_fk=True,
             )