From: Mike Bayer Date: Fri, 7 Nov 2008 22:36:21 +0000 (+0000) Subject: docstring updates X-Git-Tag: rel_0_5rc4~32 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cfca625e9445f9c52fe20c6542dd7268f2c55b6d;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git docstring updates --- diff --git a/doc/build/gen_docstrings.py b/doc/build/gen_docstrings.py index ee9bcf0ba3..b065505b6d 100644 --- a/doc/build/gen_docstrings.py +++ b/doc/build/gen_docstrings.py @@ -2,8 +2,8 @@ from toc import TOCElement import docstring import re -from sqlalchemy import schema, types, engine, sql, pool, orm, exceptions, databases, interfaces -from sqlalchemy.sql import compiler, expression +from sqlalchemy import schema, types, engine, sql, pool, orm, exceptions, databases, interfaces, util +from sqlalchemy.sql import compiler, expression, visitors from sqlalchemy.engine import default, strategies, threadlocal, url from sqlalchemy.orm import shard from sqlalchemy.ext import orderinglist, associationproxy, sqlsoup, declarative, serializer @@ -26,10 +26,15 @@ def make_all_docs(): make_doc(obj=interfaces), make_doc(obj=pool), make_doc(obj=schema), - #make_doc(obj=sql,include_all_classes=True), make_doc(obj=compiler), - make_doc(obj=expression,include_all_classes=True), + make_doc(obj=expression, + classes=[getattr(expression, key) for key in expression.__all__ if isinstance(getattr(expression, key), type)] + + [expression._CompareMixin, expression.Operators, expression.ColumnOperators, + expression._SelectBaseMixin, expression._Immutable, expression._ValuesBase, expression._UpdateBase] + ), + make_doc(obj=visitors), make_doc(obj=types), + make_doc(obj=util), make_doc(obj=orm), make_doc(obj=orm.attributes), make_doc(obj=orm.collections, classes=[orm.collections.collection, diff --git a/lib/sqlalchemy/sql/__init__.py b/lib/sqlalchemy/sql/__init__.py index f311ed93e9..90e140936f 100644 --- a/lib/sqlalchemy/sql/__init__.py +++ b/lib/sqlalchemy/sql/__init__.py @@ -33,6 +33,7 @@ from sqlalchemy.sql.expression import ( intersect, intersect_all, join, + label, literal, literal_column, modifier, diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 92659494f8..2838cc896a 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -45,7 +45,7 @@ __all__ = [ 'between', 'bindparam', 'case', 'cast', 'column', 'delete', 'desc', 'distinct', 'except_', 'except_all', 'exists', 'extract', 'func', 'modifier', 'collate', - 'insert', 'intersect', 'intersect_all', 'join', 'literal', + 'insert', 'intersect', 'intersect_all', 'join', 'label', 'literal', 'literal_column', 'not_', 'null', 'or_', 'outparam', 'outerjoin', 'select', 'subquery', 'table', 'text', 'union', 'union_all', 'update', ] @@ -1143,26 +1143,47 @@ class ClauseElement(Visitable): def compile(self, bind=None, column_keys=None, compiler=None, dialect=None, inline=False): """Compile this SQL expression. - - Uses the given ``Compiler``, or the given ``AbstractDialect`` - or ``Engine`` to create a ``Compiler``. If no `compiler` - arguments are given, tries to use the underlying ``Engine`` - this ``ClauseElement`` is bound to to create a ``Compiler``, - if any. - - Finally, if there is no bound ``Engine``, uses an - ``DefaultDialect`` to create a default ``Compiler``. - - `parameters` is a dictionary representing the default bind - parameters to be used with the statement. If `parameters` is - a list, it is assumed to be a list of dictionaries and the - first dictionary in the list is used with which to compile - against. - - The bind parameters can in some cases determine the output of - the compilation, such as for ``UPDATE`` and ``INSERT`` - statements the bind parameters that are present determine the - ``SET`` and ``VALUES`` clause of those statements. + + The return value is a [sqlalchemy.engine#Compiled] object. + Calling `str()` or `unicode()` on the returned value will yield + a string representation of the result. The ``Compiled`` + object also can return a dictionary of bind parameter names and + values using the `params` accessor. + + bind + An ``Engine`` or ``Connection`` from which a + ``Compiled`` will be acquired. This argument + takes precedence over this ``ClauseElement``'s + bound engine, if any. + + column_keys + Used for INSERT and UPDATE statements, a list of + column names which should be present in the VALUES clause + of the compiled statement. If ``None``, all columns + from the target table object are rendered. + + compiler + A ``Compiled`` instance which will be used to compile + this expression. This argument takes precedence + over the `bind` and `dialect` arguments as well as + this ``ClauseElement``'s bound engine, if + any. + + dialect + A ``Dialect`` instance frmo which a ``Compiled`` + will be acquired. This argument takes precedence + over the `bind` argument as well as this + ``ClauseElement``'s bound engine, if any. + + inline + Used for INSERT statements, for a dialect which does + not support inline retrieval of newly generated + primary key columns, will force the expression used + to create the new primary key value to be rendered + inline within the INSERT statement's VALUES clause. + This typically refers to Sequence execution but + may also refer to any server-side default generation + function associated with a primary key `Column`. """ if compiler is None: @@ -1172,13 +1193,12 @@ class ClauseElement(Visitable): compiler = bind.statement_compiler(self, column_keys=column_keys, inline=inline) elif self.bind is not None: compiler = self.bind.statement_compiler(self, column_keys=column_keys, inline=inline) - - if compiler is None: - global DefaultDialect - if DefaultDialect is None: - from sqlalchemy.engine.default import DefaultDialect - dialect = DefaultDialect() - compiler = dialect.statement_compiler(dialect, self, column_keys=column_keys, inline=inline) + else: + global DefaultDialect + if DefaultDialect is None: + from sqlalchemy.engine.default import DefaultDialect + dialect = DefaultDialect() + compiler = dialect.statement_compiler(dialect, self, column_keys=column_keys, inline=inline) compiler.compile() return compiler @@ -2658,7 +2678,7 @@ class _Label(ColumnElement): @util.memoized_property def type(self): - return sqltypes.to_instance(self._type or getattr(element, 'type', None)) + return sqltypes.to_instance(self._type or getattr(self._element, 'type', None)) @util.memoized_property def element(self): diff --git a/lib/sqlalchemy/sql/visitors.py b/lib/sqlalchemy/sql/visitors.py index 371c6ec4be..e6edce5e82 100644 --- a/lib/sqlalchemy/sql/visitors.py +++ b/lib/sqlalchemy/sql/visitors.py @@ -1,8 +1,37 @@ +"""Visitor/traversal interface and library functions. + +SQLAlchemy schema and expression constructs rely on a Python-centric +version of the classic "visitor" pattern as the primary way in which +they apply functionality. The most common use of this pattern +is statement compilation, where individual expression classes match +up to rendering methods that produce a string result. Beyond this, +the visitor system is also used to inspect expressions for various +information and patterns, as well as for usage in +some kinds of expression transformation. Other kinds of transformation +use a non-visitor traversal system. + +For many examples of how the visit system is used, see the +sqlalchemy.sql.util and the sqlalchemy.sql.compiler modules. +For an introduction to clause adaption, see +http://techspot.zzzeek.org/?p=19 . + +""" + from collections import deque import re from sqlalchemy import util +__all__ = ['VisitableType', 'Visitable', 'ClauseVisitor', + 'CloningVisitor', 'ReplacingCloningVisitor', 'iterate', + 'iterate_depthfirst', 'traverse_using', 'traverse', + 'cloned_traverse', 'replacement_traverse'] + class VisitableType(type): + """Metaclass which applies a `__visit_name__` attribute and + `_compiler_dispatch` method to classes. + + """ + def __init__(cls, clsname, bases, dict): if not '__visit_name__' in cls.__dict__: m = re.match(r'_?(\w+?)(?:Expression|Clause|Element|$)', clsname) @@ -27,9 +56,19 @@ class VisitableType(type): super(VisitableType, cls).__init__(clsname, bases, dict) class Visitable(object): + """Base class for visitable objects, applies the + ``VisitableType`` metaclass. + + """ + __metaclass__ = VisitableType class ClauseVisitor(object): + """Base class for visitor objects which can traverse using + the traverse() function. + + """ + __traverse_options__ = {} def traverse_single(self, obj): @@ -77,6 +116,11 @@ class ClauseVisitor(object): return self class CloningVisitor(ClauseVisitor): + """Base class for visitor objects which can traverse using + the cloned_traverse() function. + + """ + def copy_and_process(self, list_): """Apply cloned traversal to the given list of elements, and return the new list.""" @@ -88,6 +132,11 @@ class CloningVisitor(ClauseVisitor): return cloned_traverse(obj, self.__traverse_options__, self._visitor_dict) class ReplacingCloningVisitor(CloningVisitor): + """Base class for visitor objects which can traverse using + the replacement_traverse() function. + + """ + def replace(self, elem): """receive pre-copied elements during a cloning traversal. @@ -155,6 +204,8 @@ def traverse_depthfirst(obj, opts, visitors): return traverse_using(iterate_depthfirst(obj, opts), obj, visitors) def cloned_traverse(obj, opts, visitors): + """clone the given expression structure, allowing modifications by visitors.""" + cloned = {} def clone(element): @@ -180,6 +231,8 @@ def cloned_traverse(obj, opts, visitors): return obj def replacement_traverse(obj, opts, replace): + """clone the given expression structure, allowing element replacement by a given replacement function.""" + cloned = {} stop_on = set(opts.get('stop_on', [])) diff --git a/lib/sqlalchemy/util.py b/lib/sqlalchemy/util.py index 1a153ce55f..68cd4adc63 100644 --- a/lib/sqlalchemy/util.py +++ b/lib/sqlalchemy/util.py @@ -225,9 +225,10 @@ def get_cls_kwargs(cls): """Return the full set of inherited kwargs for the given `cls`. Probes a class's __init__ method, collecting all named arguments. If the - __init__ defines a **kwargs catch-all, then the constructor is presumed to + __init__ defines a \**kwargs catch-all, then the constructor is presumed to pass along unrecognized keywords to it's base classes, and the collection process is repeated recursively on each of the bases. + """ for c in cls.__mro__: @@ -411,7 +412,7 @@ def asbool(obj): return bool(obj) def coerce_kw_type(kw, key, type_, flexi_bool=True): - """If 'key' is present in dict 'kw', coerce its value to type 'type_' if + """If 'key' is present in dict 'kw', coerce its value to type 'type\_' if necessary. If 'flexi_bool' is True, the string '0' is considered false when coercing to boolean. """ diff --git a/test/sql/select.py b/test/sql/select.py index e959a79922..91585e37e4 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -2,7 +2,7 @@ import testenv; testenv.configure_for_tests() import datetime, re, operator from sqlalchemy import * from sqlalchemy import exc, sql, util -from sqlalchemy.sql import table, column, compiler +from sqlalchemy.sql import table, column, label, compiler from sqlalchemy.engine import default from sqlalchemy.databases import sqlite, postgres, mysql, oracle, firebird, mssql from testlib import * @@ -339,6 +339,7 @@ sq.myothertable_othername AS sq_myothertable_othername FROM (" + sqstring + ") A x = func.lala(table1.c.myid).label('foo') self.assert_compile(select([x], x==5), "SELECT lala(mytable.myid) AS foo FROM mytable WHERE lala(mytable.myid) = :param_1") + self.assert_compile(label('bar', column('foo', type_=String)) + "foo", "foo || :param_1") def test_conjunctions(self):