summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/schema.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-02-25 22:44:52 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-02-25 22:44:52 +0000
commit962c22c9eda7d2ab7dc0b41bd1c7a52cf0c9d008 (patch)
treef0ab113c7947c80dfea42d4a1bef52217bf6ed96 /lib/sqlalchemy/schema.py
parent8fa3becd5fac57bb898a0090bafaac377b60f070 (diff)
downloadsqlalchemy-962c22c9eda7d2ab7dc0b41bd1c7a52cf0c9d008.tar.gz
migrated (most) docstrings to pep-257 format, docstring generator using straight <pre> + trim() func
for now. applies most of [ticket:214], compliemnts of Lele Gaifax
Diffstat (limited to 'lib/sqlalchemy/schema.py')
-rw-r--r--lib/sqlalchemy/schema.py807
1 files changed, 524 insertions, 283 deletions
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py
index debde5754..ae4a0b162 100644
--- a/lib/sqlalchemy/schema.py
+++ b/lib/sqlalchemy/schema.py
@@ -4,16 +4,19 @@
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""the schema module provides the building blocks for database metadata. This means
-all the entities within a SQL database that we might want to look at, modify, or create
-and delete are described by these objects, in a database-agnostic way.
+"""The schema module provides the building blocks for database metadata.
-A structure of SchemaItems also provides a "visitor" interface which is the primary
-method by which other methods operate upon the schema. The SQL package extends this
-structure with its own clause-specific objects as well as the visitor interface, so that
-the schema package "plugs in" to the SQL package.
+This means all the entities within a SQL database that we might want
+to look at, modify, or create and delete are described by these
+objects, in a database-agnostic way.
+A structure of SchemaItems also provides a *visitor* interface which is
+the primary method by which other methods operate upon the schema.
+The SQL package extends this structure with its own clause-specific
+objects as well as the visitor interface, so that the schema package
+*plugs in* to the SQL package.
"""
+
from sqlalchemy import sql, types, exceptions,util, databases
import sqlalchemy
import copy, re, string
@@ -23,50 +26,66 @@ __all__ = ['SchemaItem', 'Table', 'Column', 'ForeignKey', 'Sequence', 'Index', '
'MetaData', 'BoundMetaData', 'DynamicMetaData', 'SchemaVisitor', 'PassiveDefault', 'ColumnDefault']
class SchemaItem(object):
- """base class for items that define a database schema."""
+ """Base class for items that define a database schema."""
+
def _init_items(self, *args):
- """initialize the list of child items for this SchemaItem"""
+ """Initialize the list of child items for this SchemaItem."""
+
for item in args:
if item is not None:
item._set_parent(self)
+
def _get_parent(self):
raise NotImplementedError()
+
def _set_parent(self, parent):
- """associate with this SchemaItem's parent object."""
+ """Associate with this SchemaItem's parent object."""
+
raise NotImplementedError()
+
def __repr__(self):
return "%s()" % self.__class__.__name__
+
def _derived_metadata(self):
- """return the the MetaData to which this item is bound"""
+ """Return the the MetaData to which this item is bound."""
+
return None
+
def _get_engine(self):
- """return the engine or None if no engine"""
+ """Return the engine or None if no engine."""
+
return self._derived_metadata().engine
+
def get_engine(self):
- """return the engine or raise an error if no engine"""
+ """Return the engine or raise an error if no engine."""
+
e = self._get_engine()
if e is not None:
return e
else:
raise exceptions.InvalidRequestError("This SchemaItem is not connected to any Engine")
-
+
def _set_casing_strategy(self, name, kwargs, keyname='case_sensitive'):
- """set the "case_sensitive" argument sent via keywords to the item's constructor.
-
- for the purposes of Table's 'schema' property, the name of the variable is
- optionally configurable."""
+ """Set the "case_sensitive" argument sent via keywords to the item's constructor.
+
+ For the purposes of Table's 'schema' property, the name of the
+ variable is optionally configurable.
+ """
setattr(self, '_%s_setting' % keyname, kwargs.pop(keyname, None))
+
def _determine_case_sensitive(self, name, keyname='case_sensitive'):
- """determine the "case_sensitive" value for this item.
-
- for the purposes of Table's 'schema' property, the name of the variable is
- optionally configurable.
-
- a local non-None value overrides all others. after that, the parent item
- (i.e. Column for a Sequence, Table for a Column, MetaData for a Table) is
- searched for a non-None setting, traversing each parent until none are found.
+ """Determine the `case_sensitive` value for this item.
+
+ For the purposes of Table's `schema` property, the name of the
+ variable is optionally configurable.
+
+ A local non-None value overrides all others. After that, the
+ parent item (i.e. ``Column`` for a ``Sequence``, ``Table`` for
+ a ``Column``, ``MetaData`` for a ``Table``) is searched for a
+ non-None setting, traversing each parent until none are found.
finally, case_sensitive is set to True as a default.
"""
+
local = getattr(self, '_%s_setting' % keyname, None)
if local is not None:
return local
@@ -77,7 +96,8 @@ class SchemaItem(object):
parentval = getattr(parent, '_case_sensitive_setting', None)
if parentval is not None:
return parentval
- return True
+ return True
+
def _get_case_sensitive(self):
try:
return self.__case_sensitive
@@ -85,18 +105,19 @@ class SchemaItem(object):
self.__case_sensitive = self._determine_case_sensitive(self.name)
return self.__case_sensitive
case_sensitive = property(_get_case_sensitive)
-
+
engine = property(lambda s:s._get_engine())
metadata = property(lambda s:s._derived_metadata())
-
+
def _get_table_key(name, schema):
if schema is None:
return name
else:
return schema + "." + name
-
+
class _TableSingleton(type):
- """a metaclass used by the Table object to provide singleton behavior."""
+ """A metaclass used by the ``Table`` object to provide singleton behavior."""
+
def __call__(self, name, metadata, *args, **kwargs):
if isinstance(metadata, sql.Executor):
# backwards compatibility - get a BoundSchema associated with the engine
@@ -109,10 +130,10 @@ class _TableSingleton(type):
args = list(args)
args.insert(0, metadata)
metadata = None
-
+
if metadata is None:
metadata = default_metadata
-
+
name = str(name) # in case of incoming unicode
schema = kwargs.get('schema', None)
autoload = kwargs.pop('autoload', False)
@@ -148,54 +169,90 @@ class _TableSingleton(type):
table._init_items(*args)
return table
-
+
class Table(SchemaItem, sql.TableClause):
- """represents a relational database table. This subclasses sql.TableClause to provide
- a table that is "wired" to an engine. Whereas TableClause represents a table as its
- used in a SQL expression, Table represents a table as its created in the database.
-
- Be sure to look at sqlalchemy.sql.TableImpl for additional methods defined on a Table."""
+ """Represent a relational database table.
+
+ This subclasses ``sql.TableClause`` to provide a table that is
+ *wired* to an engine.
+
+ Whereas ``TableClause`` represents a table as its used in a SQL
+ expression, ``Table`` represents a table as its created in the
+ database.
+
+ Be sure to look at ``sqlalchemy.sql.TableImpl`` for additional methods
+ defined on a ``Table``."""
+
__metaclass__ = _TableSingleton
-
+
def __init__(self, name, metadata, **kwargs):
"""Construct a Table.
-
- Table objects can be constructed directly. The init method is actually called via
- the TableSingleton metaclass. Arguments are:
-
- name : the name of this table, exactly as it appears, or will appear, in the database.
- This property, along with the "schema", indicates the "singleton identity" of this table.
- Further tables constructed with the same name/schema combination will return the same
- Table instance.
-
- *args : should contain a listing of the Column objects for this table.
-
- **kwargs : options include:
-
- schema=None : the "schema name" for this table, which is required if the table resides in a
- schema other than the default selected schema for the engine's database connection.
-
- autoload=False : the Columns for this table should be reflected from the database. Usually
- there will be no Column objects in the constructor if this property is set.
-
- mustexist=False : indicates that this Table must already have been defined elsewhere in the application,
- else an exception is raised.
-
- useexisting=False : indicates that if this Table was already defined elsewhere in the application, disregard
- the rest of the constructor arguments.
-
- owner=None : optional owning user of this table. useful for databases such as Oracle to aid in table
- reflection.
-
- quote=False : indicates that the Table identifier must be properly escaped and quoted before being sent
- to the database. This flag overrides all other quoting behavior.
-
- quote_schema=False : indicates that the Namespace identifier must be properly escaped and quoted before being sent
- to the database. This flag overrides all other quoting behavior.
-
- case_sensitive=True : indicates quoting should be used if the identifier contains mixed case.
-
- case_sensitive_schema=True : indicates quoting should be used if the identifier contains mixed case.
+
+ Table objects can be constructed directly. The init method is
+ actually called via the TableSingleton metaclass. Arguments
+ are:
+
+ name
+ The name of this table, exactly as it appears, or will
+ appear, in the database.
+
+ This property, along with the *schema*, indicates the
+ *singleton identity* of this table.
+
+ Further tables constructed with the same name/schema
+ combination will return the same Table instance.
+
+ *args
+ Should contain a listing of the Column objects for this table.
+
+ **kwargs
+ options include:
+
+ schema
+ Defaults to None: the *schema name* for this table, which is
+ required if the table resides in a schema other than the
+ default selected schema for the engine's database
+ connection.
+
+ autoload
+ Defaults to False: the Columns for this table should be
+ reflected from the database. Usually there will be no
+ Column objects in the constructor if this property is set.
+
+ mustexist
+ Defaults to False: indicates that this Table must already
+ have been defined elsewhere in the application, else an
+ exception is raised.
+
+ useexisting
+ Defaults to False: indicates that if this Table was
+ already defined elsewhere in the application, disregard
+ the rest of the constructor arguments.
+
+ owner
+ Defaults to None: optional owning user of this table.
+ useful for databases such as Oracle to aid in table
+ reflection.
+
+ quote
+ Defaults to False: indicates that the Table identifier
+ must be properly escaped and quoted before being sent to
+ the database. This flag overrides all other quoting
+ behavior.
+
+ quote_schema
+ Defaults to False: indicates that the Namespace identifier
+ must be properly escaped and quoted before being sent to
+ the database. This flag overrides all other quoting
+ behavior.
+
+ case_sensitive
+ Defaults to True: indicates quoting should be used if the
+ identifier contains mixed case.
+
+ case_sensitive_schema
+ Defaults to True: indicates quoting should be used if the
+ identifier contains mixed case.
"""
super(Table, self).__init__(name)
self._metadata = metadata
@@ -213,13 +270,13 @@ class Table(SchemaItem, sql.TableClause):
self._set_casing_strategy(name, kwargs)
self._set_casing_strategy(self.schema or '', kwargs, keyname='case_sensitive_schema')
-
+
if len([k for k in kwargs if not re.match(r'^(?:%s)_' % '|'.join(databases.__all__), k)]):
raise TypeError("Invalid argument(s) for Table: %s" % repr(kwargs.keys()))
-
+
# store extra kwargs, which should only contain db-specific options
self.kwargs = kwargs
-
+
def _get_case_sensitive_schema(self):
try:
return getattr(self, '_case_sensitive_schema')
@@ -234,39 +291,46 @@ class Table(SchemaItem, sql.TableClause):
self._primary_key = pk
self.constraints.add(pk)
primary_key = property(lambda s:s._primary_key, _set_primary_key)
-
+
def _derived_metadata(self):
return self._metadata
+
def __repr__(self):
return "Table(%s)" % string.join(
- [repr(self.name)] + [repr(self.metadata)] +
- [repr(x) for x in self.columns] +
- ["%s=%s" % (k, repr(getattr(self, k))) for k in ['schema']]
- , ',')
-
+ [repr(self.name)] + [repr(self.metadata)] +
+ [repr(x) for x in self.columns] +
+ ["%s=%s" % (k, repr(getattr(self, k))) for k in ['schema']]
+ , ',')
+
def __str__(self):
return _get_table_key(self.name, self.schema)
def append_column(self, column):
- """append a Column to this Table."""
+ """Append a ``Column`` to this ``Table``."""
+
column._set_parent(self)
+
def append_constraint(self, constraint):
- """append a Constraint to this Table."""
+ """Append a ``Constraint`` to this ``Table``."""
+
constraint._set_parent(self)
def _get_parent(self):
- return self._metadata
+ return self._metadata
+
def _set_parent(self, metadata):
metadata.tables[_get_table_key(self.name, self.schema)] = self
self._metadata = metadata
- def accept_schema_visitor(self, visitor, traverse=True):
+
+ def accept_schema_visitor(self, visitor, traverse=True):
if traverse:
for c in self.columns:
c.accept_schema_visitor(visitor, True)
return visitor.visit_table(self)
def exists(self, connectable=None):
- """return True if this table exists."""
+ """Return True if this table exists."""
+
if connectable is None:
connectable = self.get_engine()
@@ -276,17 +340,22 @@ class Table(SchemaItem, sql.TableClause):
return connectable.run_callable(do)
def create(self, connectable=None, checkfirst=False):
- """issue a CREATE statement for this table.
-
- see also metadata.create_all()."""
+ """Issue a ``CREATE`` statement for this table.
+
+ See also ``metadata.create_all()``."""
+
self.metadata.create_all(connectable=connectable, checkfirst=checkfirst, tables=[self])
+
def drop(self, connectable=None, checkfirst=False):
- """issue a DROP statement for this table.
-
- see also metadata.drop_all()."""
+ """Issue a ``DROP`` statement for this table.
+
+ See also ``metadata.drop_all()``."""
+
self.metadata.drop_all(connectable=connectable, checkfirst=checkfirst, tables=[self])
+
def tometadata(self, metadata, schema=None):
- """return a copy of this Table associated with a different MetaData."""
+ """Return a copy of this ``Table`` associated with a different ``MetaData``."""
+
try:
if schema is None:
schema = self.schema
@@ -301,70 +370,113 @@ class Table(SchemaItem, sql.TableClause):
return Table(self.name, metadata, schema=schema, *args)
class Column(SchemaItem, sql._ColumnClause):
- """represents a column in a database table. this is a subclass of sql.ColumnClause and
- represents an actual existing table in the database, in a similar fashion as TableClause/Table."""
+ """Represent a column in a database table.
+
+ This is a subclass of ``sql.ColumnClause`` and represents an
+ actual existing table in the database, in a similar fashion as
+ ``TableClause``/``Table``.
+ """
+
def __init__(self, name, type, *args, **kwargs):
- """constructs a new Column object. Arguments are:
-
- name : the name of this column. this should be the identical name as it appears,
- or will appear, in the database.
-
- type: the TypeEngine for this column.
- This can be any subclass of types.AbstractType, including the database-agnostic types defined
- in the types module, database-specific types defined within specific database modules, or user-defined types.
-
- type: the TypeEngine for this column. This can be any subclass of types.AbstractType, including
- the database-agnostic types defined in the types module, database-specific types defined within
- specific database modules, or user-defined types. If the column contains a ForeignKey,
- the type can also be None, in which case the type assigned will be that of the referenced column.
-
- *args: Constraint, ForeignKey, ColumnDefault and Sequence objects should be added as list values.
-
- **kwargs : keyword arguments include:
-
- key=None : an optional "alias name" for this column. The column will then be identified everywhere
- in an application, including the column list on its Table, by this key, and not the given name.
- Generated SQL, however, will still reference the column by its actual name.
-
- primary_key=False : True if this column is a primary key column. Multiple columns can have this flag
- set to specify composite primary keys. As an alternative, the primary key of a Table can be specified
- via an explicit PrimaryKeyConstraint instance appended to the Table's list of objects.
-
- nullable=True : True if this column should allow nulls. Defaults to True unless this column is a primary
- key column.
-
- default=None : a scalar, python callable, or ClauseElement representing the "default value" for this column,
- which will be invoked upon insert if this column is not present in the insert list or is given a value
- of None. The default expression will be converted into a ColumnDefault object upon initialization.
-
- _is_oid=False : used internally to indicate that this column is used as the quasi-hidden "oid" column
-
- index=False : Indicates that this column is
- indexed. The name of the index is autogenerated.
- to specify indexes with explicit names or indexes that contain multiple
- columns, use the Index construct instead.
-
- unique=False : Indicates that this column
- contains a unique constraint, or if index=True as well, indicates
- that the Index should be created with the unique flag.
- To specify multiple columns in the constraint/index or to specify an
- explicit name, use the UniqueConstraint or Index constructs instead.
-
- autoincrement=True : Indicates that integer-based primary key columns should have autoincrementing behavior,
- if supported by the underlying database. This will affect CREATE TABLE statements such that they will
- use the databases "auto-incrementing" keyword (such as SERIAL for postgres, AUTO_INCREMENT for mysql) and will
- also affect the behavior of some dialects during INSERT statement execution such that they will assume primary
- key values are created in this manner. If a Column has an explicit ColumnDefault object (such as via the
- "default" keyword, or a Sequence or PassiveDefault), then the value of autoincrement is ignored and is assumed
- to be False. autoincrement value is only significant for a column with a type or subtype of Integer.
-
- quote=False : indicates that the Column identifier must be properly escaped and quoted before being sent
- to the database. This flag should normally not be required as dialects can auto-detect conditions where quoting
- is required.
-
- case_sensitive=True : indicates quoting should be used if the identifier contains mixed case.
+ """Construct a new ``Column`` object.
+
+ Arguments are:
+
+ name
+ The name of this column. This should be the identical name
+ as it appears, or will appear, in the database.
+
+ type
+ The ``TypeEngine`` for this column. This can be any
+ subclass of ``types.AbstractType``, including the
+ database-agnostic types defined in the types module,
+ database-specific types defined within specific database
+ modules, or user-defined types. If the column contains a
+ ForeignKey, the type can also be None, in which case the
+ type assigned will be that of the referenced column.
+
+ *args
+ Constraint, ForeignKey, ColumnDefault and Sequence objects
+ should be added as list values.
+
+ **kwargs
+ Keyword arguments include:
+
+ key
+ Defaults to None: an optional *alias name* for this column.
+ The column will then be identified everywhere in an
+ application, including the column list on its Table, by
+ this key, and not the given name. Generated SQL, however,
+ will still reference the column by its actual name.
+
+ primary_key
+ Defaults to False: True if this column is a primary key
+ column. Multiple columns can have this flag set to
+ specify composite primary keys. As an alternative, the
+ primary key of a Table can be specified via an explicit
+ ``PrimaryKeyConstraint`` instance appended to the Table's
+ list of objects.
+
+ nullable
+ Defaults to True : True if this column should allow
+ nulls. True is the default unless this column is a primary
+ key column.
+
+ default
+ Defaults to None: a scalar, Python callable, or ``ClauseElement``
+ representing the *default value* for this column, which will
+ be invoked upon insert if this column is not present in
+ the insert list or is given a value of None. The default
+ expression will be converted into a ``ColumnDefault`` object
+ upon initialization.
+
+ _is_oid
+ Defaults to False: used internally to indicate that this
+ column is used as the quasi-hidden "oid" column
+
+ index
+ Defaults to False: indicates that this column is
+ indexed. The name of the index is autogenerated. to
+ specify indexes with explicit names or indexes that
+ contain multiple columns, use the ``Index`` construct instead.
+
+ unique
+ Defaults to False: indicates that this column contains a
+ unique constraint, or if `index` is True as well,
+ indicates that the Index should be created with the unique
+ flag. To specify multiple columns in the constraint/index
+ or to specify an explicit name, use the
+ ``UniqueConstraint`` or ``Index`` constructs instead.
+
+ autoincrement
+ Defaults to True: indicates that integer-based primary key
+ columns should have autoincrementing behavior, if
+ supported by the underlying database. This will affect
+ ``CREATE TABLE`` statements such that they will use the
+ databases *auto-incrementing* keyword (such as ``SERIAL``
+ for Postgres, ``AUTO_INCREMENT`` for Mysql) and will also
+ affect the behavior of some dialects during ``INSERT``
+ statement execution such that they will assume primary key
+ values are created in this manner. If a ``Column`` has an
+ explicit ``ColumnDefault`` object (such as via the `default`
+ keyword, or a ``Sequence`` or ``PassiveDefault``), then
+ the value of `autoincrement` is ignored and is assumed to be
+ False. `autoincrement` value is only significant for a
+ column with a type or subtype of Integer.
+
+ quote
+ Defaults to False: indicates that the Column identifier
+ must be properly escaped and quoted before being sent to
+ the database. This flag should normally not be required
+ as dialects can auto-detect conditions where quoting is
+ required.
+
+ case_sensitive
+ Defaults to True: indicates quoting should be used if the
+ identifier contains mixed case.
"""
- name = str(name) # in case of incoming unicode
+
+ name = str(name) # in case of incoming unicode
super(Column, self).__init__(name, None, type)
self.args = args
self.key = kwargs.pop('key', name)
@@ -396,15 +508,16 @@ class Column(SchemaItem, sql._ColumnClause):
return self.name
else:
return self.name
-
+
def _derived_metadata(self):
return self.table.metadata
+
def _get_engine(self):
return self.table.engine
-
+
def append_foreign_key(self, fk):
fk._set_parent(self)
-
+
def __repr__(self):
kwarg = []
if self.key != self.name:
@@ -418,14 +531,14 @@ class Column(SchemaItem, sql._ColumnClause):
if self.default:
kwarg.append('default')
return "Column(%s)" % string.join(
- [repr(self.name)] + [repr(self.type)] +
- [repr(x) for x in self.foreign_keys if x is not None] +
- [repr(x) for x in self.constraints] +
- ["%s=%s" % (k, repr(getattr(self, k))) for k in kwarg]
- , ',')
-
+ [repr(self.name)] + [repr(self.type)] +
+ [repr(x) for x in self.foreign_keys if x is not None] +
+ [repr(x) for x in self.constraints] +
+ ["%s=%s" % (k, repr(getattr(self, k))) for k in kwarg]
+ , ',')
+
def _get_parent(self):
- return self.table
+ return self.table
def _set_parent(self, table):
if getattr(self, 'table', None) is not None:
@@ -448,7 +561,7 @@ class Column(SchemaItem, sql._ColumnClause):
if isinstance(self.unique, str):
raise exceptions.ArgumentError("The 'unique' keyword argument on Column is boolean only. To create unique constraints or indexes with a specific name, append an explicit UniqueConstraint or Index object to the Table's list of elements.")
table.append_constraint(UniqueConstraint(self.key))
-
+
toinit = list(self.args)
if self.default is not None:
toinit.append(ColumnDefault(self.default))
@@ -457,15 +570,21 @@ class Column(SchemaItem, sql._ColumnClause):
self._init_items(*toinit)
self.args = None
- def copy(self):
- """creates a copy of this Column, unitialized. this is used in Table.tometadata."""
+ def copy(self):
+ """Create a copy of this ``Column``, unitialized.
+
+ This is used in ``Table.tometadata``.
+ """
+
return Column(self.name, self.type, self.default, key = self.key, primary_key = self.primary_key, nullable = self.nullable, _is_oid = self._is_oid, case_sensitive=self._case_sensitive_setting, quote=self.quote, *[c.copy() for c in self.constraints])
-
+
def _make_proxy(self, selectable, name = None):
- """create a "proxy" for this column.
-
- This is a copy of this Column referenced
- by a different parent (such as an alias or select statement)"""
+ """Create a *proxy* for this column.
+
+ This is a copy of this ``Column`` referenced by a different parent
+ (such as an alias or select statement).
+ """
+
fk = [ForeignKey(f._colspec) for f in self.foreign_keys]
c = Column(name or self.name, self.type, self.default, key = name or self.key, primary_key = self.primary_key, nullable = self.nullable, _is_oid = self._is_oid, quote=self.quote, *fk)
c.table = selectable
@@ -479,14 +598,16 @@ class Column(SchemaItem, sql._ColumnClause):
return c
def _case_sens(self):
- """redirect the 'case_sensitive' accessor to use the ultimate parent column which created
- this one."""
+ """Redirect the `case_sensitive` accessor to use the ultimate
+ parent column which created this one."""
+
return self.__originating_column._get_case_sensitive()
case_sensitive = property(_case_sens, lambda s,v:None)
-
+
def accept_schema_visitor(self, visitor, traverse=True):
- """traverses the given visitor to this Column's default and foreign key object,
- then calls visit_column on the visitor."""
+ """Traverse the given visitor to this ``Column``'s default and foreign key object,
+ then call `visit_column` on the visitor."""
+
if traverse:
if self.default is not None:
self.default.accept_schema_visitor(visitor, traverse=True)
@@ -500,22 +621,29 @@ class Column(SchemaItem, sql._ColumnClause):
class ForeignKey(SchemaItem):
- """defines a column-level ForeignKey constraint between two columns.
-
- ForeignKey is specified as an argument to a Column object.
-
- One or more ForeignKey objects are used within a ForeignKeyConstraint
- object which represents the table-level constraint definition."""
+ """Defines a column-level ``ForeignKey`` constraint between two columns.
+
+ ``ForeignKey`` is specified as an argument to a Column object.
+
+ One or more ``ForeignKey`` objects are used within a
+ ``ForeignKeyConstraint`` object which represents the table-level
+ constraint definition.
+ """
+
def __init__(self, column, constraint=None, use_alter=False, name=None, onupdate=None, ondelete=None):
- """Construct a new ForeignKey object.
-
- "column" can be a schema.Column object representing the relationship,
- or just its string name given as "tablename.columnname". schema can be
- specified as "schema.tablename.columnname"
-
- "constraint" is the owning ForeignKeyConstraint object, if any. if not given,
- then a ForeignKeyConstraint will be automatically created and added to the parent table.
+ """Construct a new ``ForeignKey`` object.
+
+ column
+ Can be a ``schema.Column`` object representing the relationship,
+ or just its string name given as ``tablename.columnname``.
+ schema can be specified as ``schema.tablename.columnname``.
+
+ constraint
+ Is the owning ``ForeignKeyConstraint`` object, if any. if not
+ given, then a ``ForeignKeyConstraint`` will be automatically
+ created and added to the parent table.
"""
+
if isinstance(column, unicode):
column = str(column)
self._colspec = column
@@ -525,14 +653,15 @@ class ForeignKey(SchemaItem):
self.name = name
self.onupdate = onupdate
self.ondelete = ondelete
-
+
def __repr__(self):
return "ForeignKey(%s)" % repr(self._get_colspec())
-
+
def copy(self):
- """produce a copy of this ForeignKey object."""
+ """Produce a copy of this ForeignKey object."""
+
return ForeignKey(self._get_colspec())
-
+
def _get_colspec(self):
if isinstance(self._colspec, str):
return self._colspec
@@ -540,17 +669,18 @@ class ForeignKey(SchemaItem):
return "%s.%s.%s" % (self._colspec.table.schema, self._colspec.table.name, self._colspec.key)
else:
return "%s.%s" % (self._colspec.table.name, self._colspec.key)
-
+
def references(self, table):
- """returns True if the given table is referenced by this ForeignKey."""
+ """Return True if the given table is referenced by this ``ForeignKey``."""
+
return table.corresponding_column(self.column, False) is not None
-
+
def _init_column(self):
# ForeignKey inits its remote column as late as possible, so tables can
# be defined without dependencies
if self._column is None:
if isinstance(self._colspec, str):
- # locate the parent table this foreign key is attached to.
+ # locate the parent table this foreign key is attached to.
# we use the "original" column which our parent column represents
# (its a list of columns/other ColumnElements if the parent table is a UNION)
for c in self.parent.orig_set:
@@ -582,15 +712,17 @@ class ForeignKey(SchemaItem):
if self.parent.type is types.NULLTYPE:
self.parent.type = self._column.type
return self._column
-
+
column = property(lambda s: s._init_column())
def accept_schema_visitor(self, visitor, traverse=True):
- """calls the visit_foreign_key method on the given visitor."""
+ """Call the `visit_foreign_key` method on the given visitor."""
+
visitor.visit_foreign_key(self)
-
+
def _get_parent(self):
return self.parent
+
def _set_parent(self, column):
self.parent = column
@@ -603,17 +735,21 @@ class ForeignKey(SchemaItem):
self.parent.table.foreign_keys.add(self)
class DefaultGenerator(SchemaItem):
- """Base class for column "default" values."""
+ """Base class for column *default* values."""
+
def __init__(self, for_update=False, metadata=None):
self.for_update = for_update
self._metadata = metadata
+
def _derived_metadata(self):
try:
return self.column.table.metadata
except AttributeError:
return self._metadata
+
def _get_parent(self):
return getattr(self, 'column', None)
+
def _set_parent(self, column):
self.column = column
self._metadata = self.column.table.metadata
@@ -621,38 +757,51 @@ class DefaultGenerator(SchemaItem):
self.column.onupdate = self
else:
self.column.default = self
+
def execute(self, **kwargs):
return self.get_engine().execute_default(self, **kwargs)
+
def __repr__(self):
return "DefaultGenerator()"
class PassiveDefault(DefaultGenerator):
- """a default that takes effect on the database side"""
+ """A default that takes effect on the database side."""
+
def __init__(self, arg, **kwargs):
super(PassiveDefault, self).__init__(**kwargs)
self.arg = arg
+
def accept_schema_visitor(self, visitor, traverse=True):
return visitor.visit_passive_default(self)
+
def __repr__(self):
return "PassiveDefault(%s)" % repr(self.arg)
-
+
class ColumnDefault(DefaultGenerator):
- """A plain default value on a column. this could correspond to a constant,
- a callable function, or a SQL clause."""
+ """A plain default value on a column.
+
+ This could correspond to a constant, a callable function, or a SQL
+ clause.
+ """
+
def __init__(self, arg, **kwargs):
super(ColumnDefault, self).__init__(**kwargs)
self.arg = arg
+
def accept_schema_visitor(self, visitor, traverse=True):
- """calls the visit_column_default method on the given visitor."""
+ """Call the visit_column_default method on the given visitor."""
+
if self.for_update:
return visitor.visit_column_onupdate(self)
else:
return visitor.visit_column_default(self)
+
def __repr__(self):
return "ColumnDefault(%s)" % repr(self.arg)
-
+
class Sequence(DefaultGenerator):
- """represents a sequence, which applies to Oracle and Postgres databases."""
+ """Represent a sequence, which applies to Oracle and Postgres databases."""
+
def __init__(self, name, start = None, increment = None, optional=False, quote=False, **kwargs):
super(Sequence, self).__init__(**kwargs)
self.name = name
@@ -661,42 +810,59 @@ class Sequence(DefaultGenerator):
self.optional=optional
self.quote = quote
self._set_casing_strategy(name, kwargs)
+
def __repr__(self):
return "Sequence(%s)" % string.join(
- [repr(self.name)] +
- ["%s=%s" % (k, repr(getattr(self, k))) for k in ['start', 'increment', 'optional']]
+ [repr(self.name)] +
+ ["%s=%s" % (k, repr(getattr(self, k))) for k in ['start', 'increment', 'optional']]
, ',')
+
def _set_parent(self, column):
super(Sequence, self)._set_parent(column)
column.sequence = self
+
def create(self):
self.get_engine().create(self)
return self
+
def drop(self):
self.get_engine().drop(self)
+
def accept_schema_visitor(self, visitor, traverse=True):
- """calls the visit_seauence method on the given visitor."""
+ """Call the visit_seauence method on the given visitor."""
+
return visitor.visit_sequence(self)
class Constraint(SchemaItem):
- """represents a table-level Constraint such as a composite primary key, foreign key, or unique constraint.
-
- Implements a hybrid of dict/setlike behavior with regards to the list of underying columns"""
+ """Represent a table-level ``Constraint`` such as a composite primary
+ key, foreign key, or unique constraint.
+
+ Implements a hybrid of dict/setlike behavior with regards to the
+ list of underying columns.
+ """
+
def __init__(self, name=None):
self.name = name
self.columns = sql.ColumnCollection()
+
def __contains__(self, x):
return x in self.columns
+
def keys(self):
return self.columns.keys()
+
def __add__(self, other):
return self.columns + other
+
def __iter__(self):
return iter(self.columns)
+
def __len__(self):
return len(self.columns)
+
def copy(self):
raise NotImplementedError()
+
def _get_parent(self):
return getattr(self, 'table', None)
@@ -704,19 +870,23 @@ class CheckConstraint(Constraint):
def __init__(self, sqltext, name=None):
super(CheckConstraint, self).__init__(name)
self.sqltext = sqltext
+
def accept_schema_visitor(self, visitor, traverse=True):
if isinstance(self.parent, Table):
visitor.visit_check_constraint(self)
else:
visitor.visit_column_check_constraint(self)
+
def _set_parent(self, parent):
self.parent = parent
parent.constraints.add(self)
+
def copy(self):
return CheckConstraint(self.sqltext, name=self.name)
-
+
class ForeignKeyConstraint(Constraint):
- """table-level foreign key constraint, represents a colleciton of ForeignKey objects."""
+ """Table-level foreign key constraint, represents a collection of ``ForeignKey`` objects."""
+
def __init__(self, columns, refcolumns, name=None, onupdate=None, ondelete=None, use_alter=False):
super(ForeignKeyConstraint, self).__init__(name)
self.__colnames = columns
@@ -727,78 +897,101 @@ class ForeignKeyConstraint(Constraint):
if self.name is None and use_alter:
raise exceptions.ArgumentError("Alterable ForeignKey/ForeignKeyConstraint requires a name")
self.use_alter = use_alter
+
def _set_parent(self, table):
self.table = table
table.constraints.add(self)
for (c, r) in zip(self.__colnames, self.__refcolnames):
self.append_element(c,r)
+
def accept_schema_visitor(self, visitor, traverse=True):
visitor.visit_foreign_key_constraint(self)
+
def append_element(self, col, refcol):
fk = ForeignKey(refcol, constraint=self)
fk._set_parent(self.table.c[col])
self._append_fk(fk)
+
def _append_fk(self, fk):
self.columns.add(self.table.c[fk.parent.key])
self.elements.add(fk)
+
def copy(self):
return ForeignKeyConstraint([x.parent.name for x in self.elements], [x._get_colspec() for x in self.elements], name=self.name, onupdate=self.onupdate, ondelete=self.ondelete)
-
+
class PrimaryKeyConstraint(Constraint):
def __init__(self, *columns, **kwargs):
super(PrimaryKeyConstraint, self).__init__(name=kwargs.pop('name', None))
self.__colnames = list(columns)
+
def _set_parent(self, table):
self.table = table
table.primary_key = self
for c in self.__colnames:
self.append_column(table.c[c])
+
def accept_schema_visitor(self, visitor, traverse=True):
visitor.visit_primary_key_constraint(self)
+
def add(self, col):
self.append_column(col)
+
def remove(self, col):
col.primary_key=False
del self.columns[col.key]
+
def append_column(self, col):
self.columns.add(col)
col.primary_key=True
+
def copy(self):
return PrimaryKeyConstraint(name=self.name, *[c.key for c in self])
+
def __eq__(self, other):
return self.columns == other
-
+
class UniqueConstraint(Constraint):
def __init__(self, *columns, **kwargs):
super(UniqueConstraint, self).__init__(name=kwargs.pop('name', None))
self.__colnames = list(columns)
+
def _set_parent(self, table):
self.table = table
table.constraints.add(self)
for c in self.__colnames:
self.append_column(table.c[c])
+
def append_column(self, col):
self.columns.add(col)
+
def accept_schema_visitor(self, visitor, traverse=True):
visitor.visit_unique_constraint(self)
+
def copy(self):
return UniqueConstraint(name=self.name, *self.__colnames)
-
+
class Index(SchemaItem):
- """Represents an index of columns from a database table
- """
+ """Represent an index of columns from a database table."""
+
def __init__(self, name, *columns, **kwargs):
- """Constructs an index object. Arguments are:
+ """Construct an index object.
+
+ Arguments are:
- name : the name of the index
+ name
+ The name of the index
- *columns : columns to include in the index. All columns must belong to
- the same table, and no column may appear more than once.
+ *columns
+ Columns to include in the index. All columns must belong to
+ the same table, and no column may appear more than once.
- **kw : keyword arguments include:
+ **kwargs
+ Keyword arguments include:
- unique=True : create a unique index
+ unique
+ Defaults to True: create a unique index.
"""
+
self.name = name
self.columns = []
self.table = None
@@ -807,11 +1000,14 @@ class Index(SchemaItem):
def _derived_metadata(self):
return self.table.metadata
+
def _init_items(self, *args):
for column in args:
self.append_column(column)
+
def _get_parent(self):
- return self.table
+ return self.table
+
def _set_parent(self, table):
self.table = table
table.indexes.add(self)
@@ -832,36 +1028,43 @@ class Index(SchemaItem):
"same index (%s already has column %s)"
% (self.name, column))
self.columns.append(column)
-
+
def create(self, connectable=None):
if connectable is not None:
connectable.create(self)
else:
self.get_engine().create(self)
return self
+
def drop(self, connectable=None):
if connectable is not None:
connectable.drop(self)
else:
self.get_engine().drop(self)
+
def accept_schema_visitor(self, visitor, traverse=True):
visitor.visit_index(self)
+
def __str__(self):
return repr(self)
+
def __repr__(self):
return 'Index("%s", %s%s)' % (self.name,
', '.join([repr(c)
for c in self.columns]),
(self.unique and ', unique=True') or '')
-
+
class MetaData(SchemaItem):
- """represents a collection of Tables and their associated schema constructs."""
+ """Represent a collection of Tables and their associated schema constructs."""
+
def __init__(self, name=None, **kwargs):
self.tables = {}
self.name = name
self._set_casing_strategy(name, kwargs)
+
def is_bound(self):
return False
+
def clear(self):
self.tables.clear()
@@ -873,64 +1076,80 @@ class MetaData(SchemaItem):
tables = util.Set(tables).intersection(self.tables.values())
sorter = sqlalchemy.sql_util.TableCollection(list(tables))
return iter(sorter.sort(reverse=reverse))
+
def _get_parent(self):
- return None
+ return None
+
def create_all(self, connectable=None, tables=None, checkfirst=True):
- """create all tables stored in this metadata.
-
- This will conditionally create tables depending on if they do not yet
- exist in the database.
-
- connectable - a Connectable used to access the database; or use the engine
- bound to this MetaData.
-
- tables - optional list of tables, which is a subset of the total
- tables in the MetaData (others are ignored)"""
+ """Create all tables stored in this metadata.
+
+ This will conditionally create tables depending on if they do
+ not yet exist in the database.
+
+ connectable
+ A ``Connectable`` used to access the database; or use the engine
+ bound to this ``MetaData``.
+
+ tables
+ Optional list of tables, which is a subset of the total
+ tables in the ``MetaData`` (others are ignored).
+ """
+
if connectable is None:
connectable = self.get_engine()
connectable.create(self, checkfirst=checkfirst, tables=tables)
-
+
def drop_all(self, connectable=None, tables=None, checkfirst=True):
- """drop all tables stored in this metadata.
-
- This will conditionally drop tables depending on if they currently
- exist in the database.
-
- connectable - a Connectable used to access the database; or use the engine
- bound to this MetaData.
-
- tables - optional list of tables, which is a subset of the total
- tables in the MetaData (others are ignored)
+ """Drop all tables stored in this metadata.
+
+ This will conditionally drop tables depending on if they
+ currently exist in the database.
+
+ connectable
+ A ``Connectable`` used to access the database; or use the engine
+ bound to this ``MetaData``.
+
+ tables
+ Optional list of tables, which is a subset of the total
+ tables in the ``MetaData`` (others are ignored).
"""
+
if connectable is None:
connectable = self.get_engine()
connectable.drop(self, checkfirst=checkfirst, tables=tables)
-
-
+
def accept_schema_visitor(self, visitor, traverse=True):
visitor.visit_metadata(self)
-
+
def _derived_metadata(self):
return self
+
def _get_engine(self):
if not self.is_bound():
return None
return self._engine
-
+
class BoundMetaData(MetaData):
- """builds upon MetaData to provide the capability to bind to an Engine implementation."""
+ """Build upon ``MetaData`` to provide the capability to bind to an
+ ``Engine`` implementation.
+ """
+
def __init__(self, engine_or_url, name=None, **kwargs):
super(BoundMetaData, self).__init__(name, **kwargs)
if isinstance(engine_or_url, basestring):
self._engine = sqlalchemy.create_engine(engine_or_url, **kwargs)
else:
self._engine = engine_or_url
+
def is_bound(self):
return True
class DynamicMetaData(MetaData):
- """builds upon MetaData to provide the capability to bind to multiple Engine implementations
- on a dynamically alterable, thread-local basis."""
+ """Build upon ``MetaData`` to provide the capability to bind to
+ multiple ``Engine`` implementations on a dynamically alterable,
+ thread-local basis.
+ """
+
def __init__(self, name=None, threadlocal=True, **kwargs):
super(DynamicMetaData, self).__init__(name, **kwargs)
if threadlocal:
@@ -938,6 +1157,7 @@ class DynamicMetaData(MetaData):
else:
self.context = self
self.__engines = {}
+
def connect(self, engine_or_url, **kwargs):
if isinstance(engine_or_url, str):
try:
@@ -950,59 +1170,80 @@ class DynamicMetaData(MetaData):
if not self.__engines.has_key(engine_or_url):
self.__engines[engine_or_url] = engine_or_url
self.context._engine = engine_or_url
+
def is_bound(self):
return hasattr(self.context, '_engine') and self.context._engine is not None
+
def dispose(self):
- """disposes all Engines to which this DynamicMetaData has been connected."""
+ """Dispose all ``Engines`` to which this ``DynamicMetaData`` has been connected."""
+
for e in self.__engines.values():
e.dispose()
+
def _get_engine(self):
if hasattr(self.context, '_engine'):
return self.context._engine
else:
return None
engine=property(_get_engine)
-
+
class SchemaVisitor(sql.ClauseVisitor):
- """defines the visiting for SchemaItem objects"""
+ """Define the visiting for ``SchemaItem`` objects."""
+
def visit_schema(self, schema):
- """visit a generic SchemaItem"""
+ """Visit a generic ``SchemaItem``."""
pass
+
def visit_table(self, table):
- """visit a Table."""
+ """Visit a ``Table``."""
pass
+
def visit_column(self, column):
- """visit a Column."""
+ """Visit a ``Column``."""
pass
+
def visit_foreign_key(self, join):
- """visit a ForeignKey."""
+ """Visit a ``ForeignKey``."""
pass
+
def visit_index(self, index):
- """visit an Index."""
+ """Visit an ``Index``."""
pass
+
def visit_passive_default(self, default):
- """visit a passive default"""
+ """Visit a passive default."""
pass
+
def visit_column_default(self, default):
- """visit a ColumnDefault."""
+ """Visit a ``ColumnDefault``."""
pass
+
def visit_column_onupdate(self, onupdate):
- """visit a ColumnDefault with the "for_update" flag set."""
+ """Visit a ``ColumnDefault`` with the `for_update` flag set."""
pass
+
def visit_sequence(self, sequence):
- """visit a Sequence."""
+ """Visit a ``Sequence``."""
pass
+
def visit_primary_key_constraint(self, constraint):
+ """Visit a ``PrimaryKeyConstraint``."""
pass
+
def visit_foreign_key_constraint(self, constraint):
+ """Visit a ``ForeignKeyConstraint``."""
pass
+
def visit_unique_constraint(self, constraint):
+ """Visit a ``UniqueConstraint``."""
pass
+
def visit_check_constraint(self, constraint):
+ """Visit a ``CheckConstraint``."""
pass
+
def visit_column_check_constraint(self, constraint):
+ """Visit a ``CheckConstraint`` on a ``Column``."""
pass
-
-default_metadata = DynamicMetaData('default')
-
+default_metadata = DynamicMetaData('default')