]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Backport documentation warnings for relationship eval()
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 7 Apr 2020 21:37:14 +0000 (17:37 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 7 Apr 2020 21:44:52 +0000 (17:44 -0400)
Documentation that is taken from #5238.

Change-Id: Id802f403190adfab0ca034afe2214ba10fd9cfbb
(cherry picked from commit 11b2b645078ffb46217d493ef9f5aebdf79b8bfc)
(cherry picked from commit e2fb6c97826c3b3f6a2d7bf6d2d57a7a192787c8)
(cherry picked from commit 68f18033245387c98383c91e7a199e7951e6ef3a)

doc/build/orm/basic_relationships.rst
doc/build/orm/extensions/declarative/relationships.rst
doc/build/orm/join_conditions.rst
lib/sqlalchemy/orm/relationships.py

index fe9aa04da5a7c0401035cec8053ee2e029ab9aa0..2b033878789a916a31fed7164d33e41ec2d7a0c4 100644 (file)
@@ -240,6 +240,13 @@ is accepted as well, matching the name of the table as stored in ``Base.metadata
                         secondary="association",
                         backref="parents")
 
+.. warning:: When passed as a Python-evaluable string, the
+    :paramref:`.relationship.secondary` argument is interpreted using Python's
+    ``eval()`` function. **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**. See
+    :ref:`declarative_relationship_eval` for details on declarative
+    evaluation of :func:`.relationship` arguments.
+
+
 .. _relationships_many_to_many_deletion:
 
 Deleting Rows from the Many to Many Table
index 1763344c7634ce5600123510c27c5c8b0456d0f1..d47e56c0c86e2d6e197c938fa2be19b13003fb77 100644 (file)
@@ -44,13 +44,21 @@ class using them::
         user_id = Column(Integer, ForeignKey('users.id'))
         user = relationship(User, primaryjoin=user_id == User.id)
 
+.. _declarative_relationship_eval:
+
+Evaluation of relationship arguments
+=====================================
+
 In addition to the main argument for :func:`~sqlalchemy.orm.relationship`,
-other arguments which depend upon the columns present on an as-yet
-undefined class may also be specified as strings.  These strings are
-evaluated as Python expressions.  The full namespace available within
-this evaluation includes all classes mapped for this declarative base,
-as well as the contents of the ``sqlalchemy`` package, including
-expression functions like :func:`~sqlalchemy.sql.expression.desc` and
+other arguments which depend upon the columns present on an as-yet undefined
+class may also be specified as strings.   For all of these arguments
+**including** the main argument prior to SQLAlchemy 1.3.16, these strings are
+**evaluated as Python expressions using Python's built-in eval() function.**
+
+The full namespace available within this evaluation includes all classes mapped
+for this declarative base, as well as the contents of the ``sqlalchemy``
+package, including expression functions like
+:func:`~sqlalchemy.sql.expression.desc` and
 :attr:`~sqlalchemy.sql.expression.func`::
 
     class User(Base):
@@ -59,6 +67,31 @@ expression functions like :func:`~sqlalchemy.sql.expression.desc` and
                              order_by="desc(Address.email)",
                              primaryjoin="Address.user_id==User.id")
 
+.. warning::
+
+    The strings accepted by the following parameters:
+
+        :paramref:`.relationship.order_by`
+
+        :paramref:`.relationship.primaryjoin`
+
+        :paramref:`.relationship.secondaryjoin`
+
+        :paramref:`.relationship.secondary`
+
+        :paramref:`.relationship.remote_side`
+
+        :paramref:`.relationship.foreign_keys`
+
+        :paramref:`.relationship._user_defined_foreign_keys`
+
+    Are **evaluated as Python code expressions using eval().  DO NOT PASS
+    UNTRUSTED INPUT TO THESE ARGUMENTS.**
+
+    In addition, prior to version 1.3.16 of SQLAlchemy, the main
+    "argument" to :func:`.relationship` is also evaluated as Python
+    code.  **DO NOT PASS UNTRUSTED INPUT TO THIS ARGUMENT.**
+
 For the case where more than one module contains a class of the same name,
 string class names can also be specified as module-qualified paths
 within any of these string expressions::
index c14a927c2629aa26a2a1a360bd92d062da7b2a69..95c536734081e0aef95a3232621bce4998ad0e9c 100644 (file)
@@ -96,6 +96,13 @@ one :class:`.Column` we need::
 
         billing_address = relationship("Address", foreign_keys="Customer.billing_address_id")
 
+.. warning:: When passed as a Python-evaluable string, the
+    :paramref:`.relationship.foreign_keys` argument is interpreted using Python's
+    ``eval()`` function. **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**. See
+    :ref:`declarative_relationship_eval` for details on declarative
+    evaluation of :func:`.relationship` arguments.
+
+
 .. _relationship_primaryjoin:
 
 Specifying Alternate Join Conditions
@@ -138,12 +145,21 @@ load those ``Address`` objects which specify a city of "Boston"::
         state = Column(String)
         zip = Column(String)
 
-Within this string SQL expression, we made use of the :func:`.and_` conjunction construct to establish
-two distinct predicates for the join condition - joining both the ``User.id`` and
-``Address.user_id`` columns to each other, as well as limiting rows in ``Address``
-to just ``city='Boston'``.   When using Declarative, rudimentary SQL functions like
-:func:`.and_` are automatically available in the evaluated namespace of a string
-:func:`.relationship` argument.
+Within this string SQL expression, we made use of the :func:`.and_` conjunction
+construct to establish two distinct predicates for the join condition - joining
+both the ``User.id`` and ``Address.user_id`` columns to each other, as well as
+limiting rows in ``Address`` to just ``city='Boston'``.   When using
+Declarative, rudimentary SQL functions like :func:`.and_` are automatically
+available in the evaluated namespace of a string :func:`.relationship`
+argument.
+
+.. warning:: When passed as a Python-evaluable string, the
+    :paramref:`.relationship.primaryjoin` argument is interpreted using
+    Python's
+    ``eval()`` function. **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**. See
+    :ref:`declarative_relationship_eval` for details on declarative
+    evaluation of :func:`.relationship` arguments.
+
 
 The custom criteria we use in a :paramref:`~.relationship.primaryjoin`
 is generally only significant when SQLAlchemy is rendering SQL in
@@ -518,6 +534,14 @@ use the string name of the table as it is present in the :class:`.MetaData`::
                             backref="left_nodes"
         )
 
+.. warning:: When passed as a Python-evaluable string, the
+    :paramref:`.relationship.primaryjoin` and
+    :paramref:`.relationship.secondaryjoin` arguments are interpreted using
+    Python's ``eval()`` function. **DO NOT PASS UNTRUSTED INPUT TO THESE
+    STRINGS**. See :ref:`declarative_relationship_eval` for details on
+    declarative evaluation of :func:`.relationship` arguments.
+
+
 A classical mapping situation here is similar, where ``node_to_node`` can be joined
 to ``node.c.id``::
 
index c4908c7ff57c94e0da83421deae9df6e7bc8cd1d..6de66f0f2bc91808554775b431ab9bb695cf9223 100644 (file)
@@ -169,7 +169,13 @@ class RelationshipProperty(StrategizedProperty):
 
           :paramref:`~.relationship.argument` may also be passed as a callable
           function which is evaluated at mapper initialization time, and may
-          be passed as a Python-evaluable string when using Declarative.
+          be passed as a string name when using Declarative.
+
+          .. warning:: Prior to SQLAlchemy 1.3.16, this value is interpreted
+             using Python's ``eval()`` function.
+             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+             See :ref:`declarative_relationship_eval` for details on
+             declarative evaluation of :func:`.relationship` arguments.
 
           .. seealso::
 
@@ -189,6 +195,12 @@ class RelationshipProperty(StrategizedProperty):
           present in the :class:`.MetaData` collection associated with the
           parent-mapped :class:`.Table`.
 
+          .. warning:: When passed as a Python-evaluable string, the
+             argument is interpreted using Python's ``eval()`` function.
+             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+             See :ref:`declarative_relationship_eval` for details on
+             declarative evaluation of :func:`.relationship` arguments.
+
           The :paramref:`~.relationship.secondary` keyword argument is
           typically applied in the case where the intermediary :class:`.Table`
           is not otherwise expressed in any direct class mapping. If the
@@ -443,6 +455,12 @@ class RelationshipProperty(StrategizedProperty):
           and may be passed as a Python-evaluable string when using
           Declarative.
 
+          .. warning:: When passed as a Python-evaluable string, the
+             argument is interpreted using Python's ``eval()`` function.
+             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+             See :ref:`declarative_relationship_eval` for details on
+             declarative evaluation of :func:`.relationship` arguments.
+
           .. seealso::
 
             :ref:`relationship_foreign_keys`
@@ -595,6 +613,12 @@ class RelationshipProperty(StrategizedProperty):
           function which is evaluated at mapper initialization time, and may
           be passed as a Python-evaluable string when using Declarative.
 
+          .. warning:: When passed as a Python-evaluable string, the
+             argument is interpreted using Python's ``eval()`` function.
+             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+             See :ref:`declarative_relationship_eval` for details on
+             declarative evaluation of :func:`.relationship` arguments.
+
         :param passive_deletes=False:
            Indicates loading behavior during delete operations.
 
@@ -687,6 +711,12 @@ class RelationshipProperty(StrategizedProperty):
           and may be passed as a Python-evaluable string when using
           Declarative.
 
+          .. warning:: When passed as a Python-evaluable string, the
+             argument is interpreted using Python's ``eval()`` function.
+             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+             See :ref:`declarative_relationship_eval` for details on
+             declarative evaluation of :func:`.relationship` arguments.
+
           .. seealso::
 
               :ref:`relationship_primaryjoin`
@@ -700,6 +730,12 @@ class RelationshipProperty(StrategizedProperty):
           and may be passed as a Python-evaluable string when using
           Declarative.
 
+          .. warning:: When passed as a Python-evaluable string, the
+             argument is interpreted using Python's ``eval()`` function.
+             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+             See :ref:`declarative_relationship_eval` for details on
+             declarative evaluation of :func:`.relationship` arguments.
+
           .. seealso::
 
             :ref:`self_referential` - in-depth explanation of how
@@ -734,6 +770,12 @@ class RelationshipProperty(StrategizedProperty):
           and may be passed as a Python-evaluable string when using
           Declarative.
 
+          .. warning:: When passed as a Python-evaluable string, the
+             argument is interpreted using Python's ``eval()`` function.
+             **DO NOT PASS UNTRUSTED INPUT TO THIS STRING**.
+             See :ref:`declarative_relationship_eval` for details on
+             declarative evaluation of :func:`.relationship` arguments.
+
           .. seealso::
 
               :ref:`relationship_primaryjoin`