ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+AUTOBUILDSPHINXOPTS = -T .
.PHONY: help clean html autobuild dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest dist-html site-mako gettext
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
autobuild:
- $(AUTOBUILD) $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ $(AUTOBUILD) $(AUTOBUILDSPHINXOPTS) $(BUILDDIR)/html
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
..
+.. _operators_parentheses:
+
+Parentheses and Grouping
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Parenthesization of expressions is rendered based on operator precedence,
+not the placement of parentheses in Python code, since there is no means of
+detecting parentheses from interpreted Python expressions. So an expression
+like::
+
+ >>> expr = or_(
+ ... User.name == "squidward", and_(Address.user_id == User.id, User.name == "sandy")
+ ... )
+
+won't include parentheses, because the AND operator takes natural precedence over OR::
+
+ >>> print(expr)
+ user_account.name = :name_1 OR address.user_id = user_account.id AND user_account.name = :name_2
+
+Whereas this one, where OR would otherwise not be evaluated before the AND, does::
+
+ >>> expr = and_(
+ ... Address.user_id == User.id, or_(User.name == "squidward", User.name == "sandy")
+ ... )
+ >>> print(expr)
+ address.user_id = user_account.id AND (user_account.name = :name_1 OR user_account.name = :name_2)
+
+The same behavior takes effect for math operators. In the parenthesized
+Python expression below, the multiplication operator naturally takes precedence over
+the addition operator, therefore the SQL will not include parentheses::
+
+ >>> print(column("q") + (column("x") * column("y")))
+ {printsql}q + x * y{stop}
+
+Whereas this one, where the addition operator would not otherwise occur before
+the multiplication operator, does get parentheses::
+
+ >>> print(column("q") * (column("x") + column("y")))
+ {printsql}q * (x + y){stop}
+
+More background on this is in the FAQ at :ref:`faq_sql_expression_paren_rules`.
+
+
.. Setup code, not for display
>>> conn.close()
>>> print((column("q1") + column("q2")).self_group().op("->")(column("p")))
{printsql}(q1 + q2) -> p
+.. _faq_sql_expression_paren_rules:
+
Why are the parentheses rules like this?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
keeping the parenthesization rules more internally consistent seems to be
the safer approach.
+.. seealso::
+
+ :ref:`operators_parentheses` - in the Operator Reference
WHERE (user_account.name = :name_1 OR user_account.name = :name_2)
AND address.user_id = user_account.id
+.. tip::
+
+ The rendering of parentheses is based on operator precedence rules (there's no
+ way to detect parentheses from a Python expression at runtime), so if we combine
+ AND and OR in a way that matches the natural precedence of AND, the rendered
+ expression might not have similar looking parentheses as our Python code::
+
+ >>> print(
+ ... select(Address.email_address).where(
+ ... or_(
+ ... User.name == "squidward",
+ ... and_(Address.user_id == User.id, User.name == "sandy"),
+ ... )
+ ... )
+ ... )
+ {printsql}SELECT address.email_address
+ FROM address, user_account
+ WHERE user_account.name = :name_1 OR address.user_id = user_account.id AND user_account.name = :name_2
+
+ More background on parenthesization is in the :ref:`operators_parentheses` in the Operator Reference.
+
For simple "equality" comparisons against a single entity, there's also a
popular method known as :meth:`_sql.Select.filter_by` which accepts keyword
arguments that match to column keys or ORM attribute names. It will filter