dbdriver.py :  » Database » PyTable » pytable-0.8.20a » pytable » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Database » PyTable 
PyTable » pytable 0.8.20a » pytable » dbdriver.py
"""Base class for database driver implementations"""
from basicproperty import propertied,common,basic
from basictypes import enumeration

DriverNameSet = enumeration.EnumerationSet.coerce( [
  # Each driver class should have a name attribute pointing to
  # a DriverName instance registered in this set.

  # add new drivers with calls to new( name, friendlyName, value )
  # add new default drivers to defaultdrivers.py module
])

class DriverName( enumeration.Enumeration ):
  """Specifier for a driver-name enumeration value"""
  datatype = 'enumeration.DriverName'
  set = DriverNameSet

class DriverCapabilities( propertied.Propertied ):
  """Object storing set of driver capability declarations

  At the moment, this is a fairly limited set of capability
  declarations, mostly because the system only supports
  a small number of features which are not considered
  important enough to be implemented across all supported
  databases.
  """
  serial = common.BooleanProperty(
    "serial", """Whether we have native support for serial datatype

  If the serial datatype is not supported, we'll have to
  generate code to create a sequence, track the name of
  that sequence and potentially rewrite the defaultValue
  field of the schema.
  """,
    defaultValue = 0,
    setDefaultOnGet = 0,
  )
  inherits = common.BooleanProperty(
    "inherits", """Whether we support PostgreSQL-style inheritance on tables

  Inherits is an object-relational database feature that
  provides (multiple) inheritance for database tables. If
  it's available, we can model object hierarchies more
  naturally.  If not, we need to do (complex, slow) joins
  across multiple tables to load base-class and sub-class
  data.
  """,
    defaultValue = 0,
    setDefaultOnGet = 0,
  )
  queryUnicode = common.BooleanProperty(
    "queryUnicode", """Whether can accept Unicode for query strings

  If this is false, then sqlquery needs to translate queries into
  strings, which it will do using utf-8 encodings.
  """,
    defaultValue = 1,
    setDefaultOnGet = 0,
  )
  queryPyformat = common.BooleanProperty(
    "queryPyformat", """Whether can handle pyformat paramstyle, if not will use pyformatsupport""",
    defaultValue = 1,
  )
  schemaSupport = common.BooleanProperty(
    "schemaSupport", """Whether the database supports sub-namespace/sub-schemas

    AFAIK only PostgreSQL actually supports the feature
  """,
    defaultValue = 0,
    setDefaultOnGet = 0,
  )
  lastRowID = common.BooleanProperty(
    "lastRowID", """Whether the database supports last-row-id reporting""",
    defaultValue = True,
    setDefaultOnGet = 0,
  )
  oids = common.BooleanProperty(
    "oids", """PostgreSQL concept of OID columns on tables""",
    defaultValue = False,
    setDefaultOnGet = 0,
  )

class DBDriver( propertied.Propertied):
  """Base class for database driver implementations

  The DBDriver object is roughly analogous to the DB-API
  module.  In addition, it allows for resolving data types
  from native driver-data-type-declarations to basicproperty/
  basictypes/wxoo-style declarations.

  Subclasses will generally provide a considerable number of
  common query objects for use in introspection queries.
  
  Each DBDriver subclass is known by a specifier string which
  is a key in the DriverName enumeration.  The specifier
  strings are specified in the DBSpecifier object to select
  the appropriate DBDriver run-time class.

  Where appropriate, the DBDriver sub-class should
  allow for querying to determine "system" databases,
  such as ODBC named data sources.
    See: getSystemSpecifiers()
  """
  capabilities = DriverCapabilities()
  name = basic.BasicProperty(
    'name', """DriverName enumeration identifying the driver in DBSpecifiers""",
    baseType = DriverName,
  )
  connections = common.WeakValueDictionaryProperty(
    "connections","""Mapping of specifier objects to live connections

  The DBDriver retains weak references to all active
  connections, to allow for connection sharing and/or
  properly shutting down all connections on exit.
  """,
    setDefaultOnGet = 1,
  )
  defaultConnectionClass = common.ClassByNameProperty(
    'defaultConnectionClass', """Default DBConnection sub-class to be used for this driver""",
    defaultValue = 'pytable.dbconnection.DBConnection',
  )
  friendlyName = common.StringProperty(
    "friendlyName", """Friendly name of the DBDriver type""",
    defaultValue = "",
  )
  paramstyle = common.StringProperty(
    "paramstyle", """DBAPI 2.0 parameter-style value""",
    defaultValue = "pyformat",
  )
  threadsafety = common.IntegerProperty(
    "paramstyle", """DBAPI 2.0 threadsafety value XXX should be an enumeration!""",
    defaultValue = 0,
  )
  apilevel = common.StringProperty(
    "apilevel", """DBAPI 2.0 apilevel value""",
    defaultValue = "2.0",
  )
  systemDBName = common.StringProperty(
    "systemDBName", """Default name for driver's system database (for listDatabases connections)""",
    defaultValue = "",
  )

  queries = {}
  userDescription = ""
  # properties which may be specified for a connection
  # file-based drivers likely will only have dsn in this set
  connectionProperties = ("dsn", "host","user","password", "database")
  fileBased = 0
  usesIntDescriptionTypes = True


  def copyErrorsFromModule( cls, source ):
    """Method to copy Error/Class names from source to the driver class"""
    for name in (
      'Warning','Error','InterfaceError',
      'DatabaseError','DataError','OperationalError',
      'IntegrityError', 'InternalError','ProgrammingError',
      'NotSupportedError',
    ):
      setattr(cls,name,getattr(source,name,StandardError))
    for name in (
      'Date','Time','Timestamp',
      'DateFromTicks','TimeFromTicks','TimestampFromTicks',
      'Binary',
      'STRING','BINARY','NUMBER','DATETIME','ROWID',
      'BOOLEAN',
    ):
      setattr(cls,name,getattr(source,name,None))
  copyErrorsFromModule = classmethod( copyErrorsFromModule )
  def connect(self, specifier = None, share=1, **namedarguments):
    """Connect using this driver to the specified database

    specifier -- the DBSpecifier object encoding the connection
      information to be used in establishing the connection
    
      If specifier is None, then create a new DBSpecifier
      using the named arguments as arguments to the DBSpecifier
      constructor.  Note: drivers with driver-specific specifier
      classes may construct those specific classes instead of
      the base DBSpecifier class.

      If specifier is not None, but there are namedarguments,
      the specifier will be cloned (copied) with the passed
      namedarguments as parameters to the clone method.  The
      result will be that the named argument values will override
      the specifier object's values.

    share -- if true, the connection will be shared with any existing
      connection which matches the calculated final specifier
    """
    specifier = self.unifySpecifier(specifier, **namedarguments)
    if share:
      for spec,conn in self.connections.iteritems():
        if specifier == spec and not conn.invalid:
          self.connections[specifier] = conn
          return conn
    connection = self.establishConnection(specifier)
    connection = self.wrapConnection( connection )
    self.connections[specifier] = connection
    connection.specifier = specifier
    return connection
  def reconnect( self, connection ):
    """Reconnect the given DBConnection object"""
    spec = None
    for spec,conn in self.connections.iteritems():
      if conn is connection:
        del self.connections[ spec ]
        break
    # prefer use of the connection's specifier attribute
    # use our local copy otherwise
    spec = getattr( connection, 'specifier', spec )
    if not spec:
      raise ValueError( """Attempting to reconnect a connection which is neither known to the system nor provides a 'specifier' property: %s"""%(
        connection,
      ))
    rawConnection = self.establishConnection( spec )
    connection.connection = rawConnection
    return connection
  def unifySpecifier(self, specifier, **namedarguments):
    """Given specifier and named arguments create finalSpecifier

    specifier -- DBSpecifer or None
    named -- dictionary of attribute name to attribute value

    See DBDriver.connect for discussion of the semantics
    """
    if specifier is None:
      specifier = self.createSpecifier( **namedarguments )
    elif namedarguments:
      specifier = specifier.clone( **namedarguments )
    return specifier
        
  
  def createSpecifier(self, **namedarguments):
    """Create a new specifier object for this driver

    namedarguments -- applied to the constructor of the
      DBSpecifier

    Note:
      the drivername property will be set to our name
      property's value
    """
    from pytable import dbspecifier
    namedarguments["drivername"] = self.name
    return dbspecifier.DBSpecifier( **namedarguments )
  def getSystemSpecifiers(self,*arguments,**namedarguments):
    """Customization Point: return list of system specifiers

    For APIs which have system-registered data sources,
    such as ODBC, this method should be overwritten to provide
    system specifiers for the system-registered data sources.
    """
    return []
  def wrapConnection( self, connection ):
    """Wrap the connection with a driver-aware connection object"""
    return self.defaultConnectionClass(
      connection = connection,
      driver = self,
    )

  ### Required customization points (abstract methods)
  def establishConnection(self, fullSpecifier):
    """Abstract Method: Connect using the fully specified specifier passed

    fullSpecifier -- a specifier with all arguments unified
      and ready to be connected.  This specifier should
      include everything required to do the actual
      connection (including passwords or the like).

    All sub-classes must override this method!
    """
    raise NotImplementedError("""DBDriver sub-class %s does not define an establishConnection method"""% (self.__class__.__name__,))

  _dataTypeRegistry = None
  def sqlToDataType( self, source ):
    """Convert given SQL data-type to the desired data-type specifier

    source -- the source specifier, an SQL identifier

    returns a wxoo specifier or raises KeyError, only returns
    the first-registered data-type, so sub-classes that want
    to override the defaults need to prepend their dataTypeRegistry
    to the dbdriver.DBDriver.dataTypeRegistry list.
    """
    if not self._dataTypeRegistry:
      self._dataTypeRegistry = {}
      for dbtype,wxootype,basetype in self.dataTypeRegistry:
        self._dataTypeRegistry.setdefault( dbtype, []).append( (wxootype,basetype) )
    source = source.lower()
    item = self._dataTypeRegistry.get(source, [('',object)])[0][0]
    if not item:
      raise KeyError( """Driver %r doesn't know how to calculate wxoo specifier for data-type %r"""%(
        self,source,
      ))
    return item
  def sqlToBaseType( self, source ):
    """Convert given SQL data-type to a property-base-type

    source -- the source specifier, an SQL identifier

    returns a base-type suitable for use in basicproperty
    properties to control the property's operation.
    """
    if not self._dataTypeRegistry:
      self._dataTypeRegistry = {}
      for dbtype,wxootype,basetype in self.dataTypeRegistry:
        self._dataTypeRegistry.setdefault( dbtype, []).append( (wxootype,basetype) )
    source = source.lower()
    item = self._dataTypeRegistry.get(source, [('',object)])[0][1]
    if not item:
      raise KeyError( """Driver %r doesn't know how to calculate wxoo specifier for data-type %r"""%(
        self,source,
      ))
    return item

  _localTypeRegistry = None
  def localToSQLType( self, source ):
    """Convert a local numeric data-type to an SQL string data-type

    source -- the source specifier

    returns an sql data-type for the given local SQL type, the
    sub-class must provide the actual implementation.
    """
    if not self._localTypeRegistry:
      self._localTypeRegistry = {}
      for key,value in self.localTypeRegistry:
        self._localTypeRegistry.setdefault( key, []).append( value )
    if self.usesIntDescriptionTypes:
      # everything save PyGreSQL, at the moment...
      source = int(source)
    item = self._localTypeRegistry.get( source, [''])[0]
    if not item:
      raise KeyError( """Driver %r doesn't know how to calculate SQL specifier for data-type %r"""%(
        self,source,
      ))
    return item

      
  localTypeRegistry = [
    # sub-classes will have to create a table to override this...
  ]
  dataTypeRegistry = [
    # partial registry of common SQL name -> wxoo name values...
    ("float", 'float', float) ,
    ("float4", 'float', float) ,
    ("float8" , 'float', float) ,

    ("int2", 'int', int) ,
    ("int4", 'int', int) ,
    ("int8", 'long', long) ,
    ("integer", 'int', int) ,
    
    #("bytea", 'str.long', str) ,
    ("char", 'str', str) ,
    ("text", 'str.long', str) ,
    ("varchar", 'str', str) ,

    ("bool", 'bool', 'basictypes.booleanfix.bool') ,

    ("blob", 'str.locale', str) ,
    ("bpchar", 'str.locale', str) ,

    ("date" , 'datetime', 'mx.DateTime.DateTimeType') ,
    ("interval" , 'datetimedelta', 'mx.DateTime.DateTimeDeltaType') ,
    ("time", 'timeofday', 'basictypes.datemx_types.mxTimeOfDay') ,
    ("timestamp", 'datetime', 'mx.DateTime.DateTimeType') ,
    ("timestamptz", 'datetime', 'mx.DateTime.DateTimeType') , # missing zone info here

    # these 4 aren't mapped to anything useful yet
    ("cash", 'decimal', int), 
    ("money", 'decimal', int),
    ("decimal", "decimal", int ),
    ("numeric", 'decimal', int),
  ]
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.