changeset 348:c652478be4fd

migrated \dt to gerald
author catherine@cordelia
date Fri, 24 Apr 2009 15:09:29 -0400
parents 1c6e5410619e
children f92e15f3d0ed
files docs/source/capabilities.rst docs/source/conf.py docs/source/index.rst docs/source/intro.rst docs/source/limitations.rst setup.py sqlpython/README.txt sqlpython/completion.py sqlpython/exampleSession.txt sqlpython/metadata.py sqlpython/mysqlpy.py sqlpython/output_templates.py sqlpython/plothandler.py sqlpython/setup_test_db.sql sqlpython/sqlpyPlus.py sqlpython/sqlpython.py sqlpython/test_sqlpyPlus.py sqlpython/test_sqlpyPlus.txt sqlpython_epm.list
diffstat 5 files changed, 61 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/setup.py	Thu Apr 23 19:10:05 2009 -0400
+++ b/setup.py	Fri Apr 24 15:09:29 2009 -0400
@@ -17,8 +17,11 @@
       url="http://packages.python.org/sqlpython",
       packages=find_packages(),
       include_package_data=True,    
-      install_requires=['pyparsing','cmd2>=0.5.2','cx_Oracle','genshi>=0.5','sqlalchemy',],
-      keywords = 'client oracle database',
+      install_requires=['pyparsing','cmd2>=0.5.2','genshi>=0.5','sqlalchemy','gerald'],
+      extras_require = {'oracle': ['cx_Oracle'],
+                        'mysql': ['MySQL-python'],
+                        'postgres': ['psycopg2']},
+      keywords = 'client oracle database rdbms sql',
       license = 'MIT',
       platforms = ['any'],
       entry_points = """
--- a/sqlpython/mysqlpy.py	Thu Apr 23 19:10:05 2009 -0400
+++ b/sqlpython/mysqlpy.py	Fri Apr 24 15:09:29 2009 -0400
@@ -183,14 +183,9 @@
     try:
         if sys.argv[1][0] != '@':
             connectstring = sys.argv.pop(1)
-            try:   # attach AS SYSDBA or AS SYSOPER if present
-                for connectmode in my.connection_modes.keys():
-                    if connectmode.search(' %s %s' % tuple(sys.argv[1:3])):
-                        for i in (1,2):
-                            connectstring += ' ' + sys.argv.pop(1)
-                        break
-            except TypeError:
-                pass
+            if len(sys.argv) >= 3 and sys.argv[1].lower() == 'as': # attach AS SYSDBA or AS SYSOPER if present
+                for i in (1,2):
+                    connectstring += ' ' + sys.argv.pop(1)
             my.do_connect(connectstring)
         for arg in sys.argv[1:]:
             if my.onecmd(arg + '\n') == my._STOP_AND_EXIT:
--- a/sqlpython/plothandler.py	Thu Apr 23 19:10:05 2009 -0400
+++ b/sqlpython/plothandler.py	Fri Apr 24 15:09:29 2009 -0400
@@ -1,10 +1,9 @@
-import shelve, pickle, cx_Oracle, datetime, sys, itertools
+import shelve, pickle, datetime, sys, itertools
 shelvename = 'plot.shelve'
 
 try:
     import pylab
     class Plot(object):
-        plottable_types = (cx_Oracle.NUMBER, datetime.datetime)    
         def __init__(self):
             self.legends = []
             self.yserieslists = []
@@ -14,7 +13,7 @@
             self.title = sqlSession.tblname
             self.xlabel = sqlSession.curs.description[0][0]
             self.datatypes = [d[1] for d in sqlSession.curs.description]
-            plottableSeries = [dt in self.plottable_types for dt in self.datatypes]
+            plottableSeries = [hasattr(dt, '__sub__') for dt in self.datatypes]
             if plottableSeries.count(True) == 0:
                 raise ValueError, 'At least one quantitative column needed to plot.'
             elif len(plottableSeries) == 1: # only one column, but it is plottable
--- a/sqlpython/sqlpyPlus.py	Thu Apr 23 19:10:05 2009 -0400
+++ b/sqlpython/sqlpyPlus.py	Fri Apr 24 15:09:29 2009 -0400
@@ -23,7 +23,7 @@
 
 - catherinedevlin.blogspot.com  May 31, 2006
 """
-import sys, os, re, sqlpython, cx_Oracle, pyparsing, re, completion, datetime, pickle, binascii, subprocess
+import sys, os, re, sqlpython, pyparsing, re, completion, datetime, pickle, binascii, subprocess
 from cmd2 import Cmd, make_option, options, Statekeeper, Cmd2TestCase
 from output_templates import output_templates
 from metadata import metaqueries
@@ -34,6 +34,18 @@
 except (RuntimeError, ImportError):
     pass
 
+DatabaseErrors = []
+try:
+    import psycopg2
+    DatabaseErrors.append(psycopg2.DatabaseError)
+except ImportError:
+    psycopg2 = None
+try:
+    import cx_Oracle
+    DatabaseErrors.append(cx_Oracle.DatabaseError)
+except ImportError:
+    cx_Oracle = None
+
 queries = {
 'resolve': """
 SELECT object_type, object_name, owner FROM (
@@ -258,6 +270,9 @@
         return lst[center-width:end]
     else:
         return lst[max(center-width,0):center+width+1] 
+
+def oracle_wildcards_to_regex(input):
+    return re.escape(input.lower().strip()).replace('\\*','.*').replace('\\%','.*').replace('\\_','.')
     
 class sqlpyPlus(sqlpython.sqlpython):
     defaultExtension = 'sql'
@@ -757,11 +772,11 @@
         return self._pull(arg, opts, vc=None)
     
     def _pull(self, arg, opts, vc=None):
-        for (descrip, objtype, obj) in self.gerald_resolve(arg):
+        for (descrip, obj) in sorted(self.gerald_resolve(arg)):
             txt = obj.get_ddl()
             if vc or opts.dump:
                 try:
-                    os.mkdir(objtype)
+                    os.mkdir(obj.type)
                 except OSError:
                     pass
                 fname = descrip + '.sql'
@@ -904,7 +919,7 @@
             return self._do_describe_oracle ()       
         if opts.refresh:
             self.connections[self.connection_number]['gerald_result'] = self.connections[self.connection_number]['gerald']()
-        for (descriptor, objtype, obj) in self.gerald_resolve(arg):
+        for (descriptor, obj) in sorted(self.gerald_resolve(arg)):
             self.poutput(descriptor)
             if hasattr(obj, 'columns'):
                 self.tblname = obj.name
@@ -1078,15 +1093,11 @@
         except KeyError:
             self.perror('psql command \%s not yet supported.' % abbrev)
 
-    @options([all_users_option])
-    def do__dir_tables(self, arg, opts):
+    def do__dir_tables(self, arg):
         '''
         Lists all tables whose names match argument.
         '''        
-        sql = """SELECT table_name, 'TABLE' as type%s FROM %s_tables WHERE table_name LIKE '%%%s%%';""" % \
-                       (opts.scope['col'], opts.scope['view'], arg.upper())
-        self.sqlfeedback(sql)
-        self.do_select(self.parsed(sql, terminator=arg.parsed.terminator or ';', suffix=arg.parsed.suffix))
+        self.onecmd('ls table/%s' % arg)
         
     @options([all_users_option])
     def do__dir_views(self, arg, opts):
@@ -1185,7 +1196,7 @@
                 try:
                     self.curs.execute('SELECT %s FROM dual' % val)
                     return True, var, self.curs.fetchone()[0]
-                except cx_Oracle.DatabaseError:
+                except DatabaseErrors:
                     return True, var, val  # we give up and assume it's a string
             
     def do_setbind(self, arg):
@@ -1347,23 +1358,26 @@
         self.select_output(arg.parsed.raw, terminator=arg.parsed.terminator, rowlimit=arg.parsed.suffix)    
                 
     def gerald_resolve(self, target):
-        target = target.lower().strip()
+        target = oracle_wildcards_to_regex(target.rstrip('/')) 
+        typetarget = target + '/?$'
+        nametarget = target + '$'
         schema = self.connections[self.connection_number]['gerald_result'].schema
         for (objname, obj) in schema.items():
-            objtype = str(type(obj)).split('.')[-1].rstrip("'>")
-            descriptor = os.path.join(objtype, objname)
-            if (not target) or (objname == target) or (descriptor == target):
-                yield (descriptor, objtype, obj)
+            if not hasattr(obj, 'type'):
+                setattr(obj, 'type', str(type(obj)).strip("'>").split('.')[-1])  # would prefer Gerald to give this to us
+            descriptor = os.path.join(obj.type, objname)
+            if (not target) or re.match(typetarget, obj.type, re.I) or re.match(nametarget, objname, re.I) or re.match(nametarget, descriptor, re.I):
+                yield (descriptor, obj)
 
     @options([make_option('-l', '--long', action='store_true', help='long descriptions'),
           make_option('-a', '--all', action='store_true', help="all schemas' objects"),
           make_option('-t', '--timesort', action='store_true', help="Sort by last_ddl_time"),              
           make_option('-r', '--reverse', action='store_true', help="Reverse order while sorting")])        
     def do_ls(self, arg, opts):
-        if self.rdbms == 'oracle':
+        if False and self.rdbms == 'oracle':
             return self._do_ls_oracle(arg, opts)
         rows = []
-        for (descriptor, objtype, obj) in self.gerald_resolve(arg):
+        for (descriptor, obj) in sorted(self.gerald_resolve(arg)):
             if opts.long:
                 rows.append((descriptor,))
             else:
--- a/sqlpython/sqlpython.py	Thu Apr 23 19:10:05 2009 -0400
+++ b/sqlpython/sqlpython.py	Fri Apr 24 15:09:29 2009 -0400
@@ -8,7 +8,7 @@
 # Best used with the companion modules sqlpyPlus and mysqlpy 
 # See also http://twiki.cern.ch/twiki/bin/view/PSSGroup/SqlPython
 
-import cmd2,getpass,binascii,cx_Oracle,re,os,functools
+import cmd2,getpass,binascii,re,os,functools
 import sqlpyPlus, sqlalchemy, pyparsing, gerald
 __version__ = '1.6.4'    
 
@@ -97,7 +97,9 @@
             
     gerald_classes = {'oracle': (gerald.OracleSchema, 'oracle',),
                       'postgres': (gerald.PostgresSchema, 'public'),
-                      'mysql': (gerald.MySQLSchema, 'nil')}
+                      'mysql': (gerald.MySQLSchema, 'nil'),
+                      'mssql': None,
+                      'sqlite': None}
     def url_connect(self, arg):
         eng = sqlalchemy.create_engine(arg) 
         self.conn = eng.connect().connection
@@ -105,14 +107,20 @@
                  'rdbms': eng.url.drivername, 'user': eng.url.username or '', 
                  'eng': eng}
         gerclass = self.gerald_classes[eng.url.drivername]
-        conn['gerald'] = functools.partial(gerclass[0], gerclass[1], arg.split('/?')[:1][0])
-        conn['gerald_result'] = conn['gerald']()
+        if gerclass:
+            conn['gerald'] = functools.partial(gerclass[0], gerclass[1], arg.split('/?')[:1][0])
+        else:
+            conn['gerald'] = list
+        conn['gerald_result'] = conn['gerald']()        
         return conn
     
     def ora_connect(self, arg):
+        import cx_Oracle
+        connection_modes = {re.compile(' AS SYSDBA', re.IGNORECASE): cx_Oracle.SYSDBA, 
+                        re.compile(' AS SYSOPER', re.IGNORECASE): cx_Oracle.SYSOPER}        
         modeval = 0
         oraserv = None
-        for modere, modevalue in self.connection_modes.items():
+        for modere, modevalue in connection_modes.items():
             if modere.search(arg):
                 arg = modere.sub('', arg)
                 modeval = modevalue
@@ -145,10 +153,9 @@
             modeval = cx_Oracle.SYSOPER
         result = self.url_connect('oracle://%s:%s@%s/?mode=%d' % (orauser, orapass, oraserv, modeval))
         result['dbname'] = oraserv
+        result['sid'] = sid
         return result
     
-    connection_modes = {re.compile(' AS SYSDBA', re.IGNORECASE): cx_Oracle.SYSDBA, 
-                        re.compile(' AS SYSOPER', re.IGNORECASE): cx_Oracle.SYSOPER}
     @cmd2.options([cmd2.make_option('-a', '--add', action='store_true', 
                                     help='add connection (keep current connection)'),
                    cmd2.make_option('-c', '--close', action='store_true', 
@@ -176,14 +183,17 @@
             return
         try:
             connect_info = self.url_connect(arg)
-        except sqlalchemy.exc.ArgumentError, e:
+        except sqlalchemy.exc.DatabaseError, e:
+            self.perror(e)
+            return
+        except (sqlalchemy.exc.ArgumentError, ImportError), e:
             connect_info = self.ora_connect(arg)
         if opts.add or (self.connection_number is None):
             try:
                 self.connection_number = max(self.connections.keys()) + 1
             except ValueError:
                 self.connection_number = 0
-        connect_info['prompt'] = '%d:%s@%s> ' % (self.connection_number, connect_info['user'], connect_info['dbname'])
+        connect_info['prompt'] = '%d:%s@%s> ' % (self.connection_number, connect_info['user'], connect_info.get('sid') or connect_info['dbname'])
         self.connections[self.connection_number] = connect_info
         self.make_connection_current(self.connection_number)
         self.curs = self.conn.cursor()