changeset 396:9c724e555c91

re.match is betraying me
author catherine@DellZilla
date Thu, 08 Oct 2009 09:36:07 -0400
parents bb434c623bca
children 510b6e2f0ae5
files setup.py sqlpython/schemagroup.py sqlpython/sqlpyPlus.py sqlpython/sqlpython.py
diffstat 4 files changed, 88 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/setup.py	Wed Oct 07 13:23:34 2009 -0400
+++ b/setup.py	Thu Oct 08 09:36:07 2009 -0400
@@ -17,7 +17,7 @@
       url="http://packages.python.org/sqlpython",
       packages=find_packages(),
       include_package_data=True,    
-      install_requires=['pyparsing','cmd2>=0.5.5','cx_Oracle>=5.0.2',
+      install_requires=['pyparsing','cmd2>=0.5.6','cx_Oracle>=5.0.2',
                         'genshi>=0.5','sqlalchemy'],
       keywords = 'client oracle database',
       license = 'MIT',
--- a/sqlpython/schemagroup.py	Wed Oct 07 13:23:34 2009 -0400
+++ b/sqlpython/schemagroup.py	Thu Oct 08 09:36:07 2009 -0400
@@ -37,7 +37,7 @@
         self.connection = connection
         self.gerald_connection_string = gerald_connection_string(connection_string)
         self.refresh_thread = RefreshGroupThread(self, minutes_between_refreshes)
-        self.complete = False
+        self.complete = 0
     def refresh_asynch(self):
         self.refresh_thread.start()
     def get_current_database_time(self):
@@ -57,7 +57,9 @@
             if (owner not in self) or (self[owner].refreshed < last_ddl_time):
                 self.refresh_one(owner, current_database_time)
                 # what if a user's last object is deleted?
-        self.complete = True
+            if isinstance(self.complete, int):
+                self.complete += 1
+        self.complete = 'all'
     def refresh_one(self, owner, current_database_time=None):
         if not current_database_time:
             current_database_time = self.get_current_database_time()
@@ -102,5 +104,5 @@
         else:
             return self.object_name   
     def descriptor(self, qualified=False):
-        return '%s/%s' % (self.db_type, name(qualified))
+        return '%s/%s' % (self.db_type, self.name(qualified))
         
\ No newline at end of file
--- a/sqlpython/sqlpyPlus.py	Wed Oct 07 13:23:34 2009 -0400
+++ b/sqlpython/sqlpyPlus.py	Thu Oct 08 09:36:07 2009 -0400
@@ -23,7 +23,9 @@
 
 - catherinedevlin.blogspot.com  May 31, 2006
 """
-import sys, os, re, sqlpython, cx_Oracle, pyparsing, re, completion, datetime, pickle, binascii, subprocess, time, itertools, hashlib
+import sys, os, re, sqlpython, cx_Oracle, pyparsing, re, completion
+import datetime, pickle, binascii, subprocess, time, itertools, hashlib
+import traceback
 from cmd2 import Cmd, make_option, options, Statekeeper, Cmd2TestCase
 from output_templates import output_templates
 from schemagroup import MetaData
@@ -387,13 +389,15 @@
         return cmd, arg, line
 
     def perror(self, err, statement=None):
+        if self.debug:
+            traceback.print_exc()            
         try:
             linenum, line, offset = offset_to_line(statement.parsed.raw, err.message.offset)
             print line.strip()
             print '%s*' % (' ' * offset)
             print 'ERROR at line %d:' % (linenum + 1)
         except AttributeError:
-            pass
+            pass        
         print str(err)
     def dbms_output(self):
         "Dumps contents of Oracle's DBMS_OUTPUT buffer (where PUT_LINE goes)"
@@ -789,74 +793,47 @@
         return self.onecmd('SELECT * FROM %s%s%s' % (arg, arg.parsed.terminator or ';',
                                                      arg.parsed.suffix or ''))
 
-    def _pull(self, arg, opts, vc=None):        
+    @options([make_option('-d', '--dump', action='store_true', help='dump results to files'),
+              make_option('-f', '--full', action='store_true', help='get dependent objects as well'),
+              make_option('-l', '--lines', action='store_true', help='print line numbers'),
+              make_option('-n', '--num', type='int', help='only code near line #num'),
+              make_option('-w', '--width', type='int', default=5, 
+                          help='# of lines before and after --lineNo'),
+              make_option('-a', '--all', action='store_true', help="all schemas' objects"),
+              #make_option('-x', '--exact', action='store_true', help="match object name exactly")
+              ])                
+    def do_pull(self, arg, opts, vc=None):        
         """Displays source code."""
-        if opts.dump:
-            statekeeper = Statekeeper(self, ('stdout',))                        
+        opts.exact = True
+        statekeeper = Statekeeper(opts.dump and self, ('stdout',))
         (username, schemas) = self.metadata()
-        for (name, obj, dbtype, descrip) in self._matching_database_objects(arg, opts):
-            self.poutput(descrip)
-            txt = obj.get_ddl()
-            if hasattr(opts, 'lines') and opts.lines:
-                txt = self._with_line_numbers(txt)
-
-            if opts.dump:
-                try:
-                    os.makedirs(os.path.join(owner.lower(), object_type.lower()))
-                except OSError:
-                    pass
-                filename = os.path.join(owner.lower(), object_type.lower(), '%s.sql' % object_name.lower())
-                self.stdout = open(filename, 'w')
-                if vc:
-                    subprocess.call(vc + [filename])
-                
-                
-                
-            self.poutput(txt)
-            
-            
         try:
-            for (owner, object_name, object_type) in self.resolve_many(arg, opts):  
-                if object_type in self.supported_ddl_types:
-                    object_type = {'DATABASE LINK': 'DB_LINK', 'JAVA CLASS': 'JAVA_SOURCE'
-                                   }.get(object_type) or object_type
-                    object_type = object_type.replace(' ', '_')
-                    if opts.dump:
-                        try:
-                            os.makedirs(os.path.join(owner.lower(), object_type.lower()))
-                        except OSError:
-                            pass
-                        filename = os.path.join(owner.lower(), object_type.lower(), '%s.sql' % object_name.lower())
-                        self.stdout = open(filename, 'w')
-                        if vc:
-                            subprocess.call(vc + [filename])
-                    if object_type == 'PACKAGE':
-                        ddl = [['PACKAGE_SPEC', object_name, owner],['PACKAGE_BODY', object_name, owner]]                            
-                    elif object_type in ['CONTEXT', 'DIRECTORY', 'JOB']:
-                        ddl = [[object_type, object_name]]
-                    else:
-                        ddl = [[object_type, object_name, owner]]
-                    for ddlargs in ddl:
-                        try:
-                            code = str(self.curs.callfunc('DBMS_METADATA.GET_DDL', cx_Oracle.CLOB, ddlargs))
-                            if hasattr(opts, 'lines') and opts.lines:
-                                code = code.splitlines()
-                                template = "%%-%dd:%%s" % len(str(len(code)))
-                                code = '\n'.join(template % (n+1, line) for (n, line) in enumerate(code))
-                            if hasattr(opts, 'num') and (opts.num is not None):
-                                code = code.splitlines()
-                                code = centeredSlice(code, center=opts.num+1, width=opts.width)
-                                code = '\n'.join(code)
-                                self.poutput(code)
-                            else:
-                                self.poutput('REMARK BEGIN %s\n%s\nREMARK END\n' % (object_name, code))
-                        except cx_Oracle.DatabaseError, errmsg:
-                            if object_type == 'JOB':
-                                self.pfeedback('%s: DBMS_METADATA.GET_DDL does not support JOBs (MetaLink DocID 567504.1)' % object_name)
-                            elif 'ORA-31603' in str(errmsg): # not found, as in package w/o package body
-                                pass
-                            else:
-                                raise
+            for metadata in self._matching_database_objects(arg, opts):
+                self.poutput(metadata.descriptor(qualified=True))
+                txt = metadata.db_object.get_ddl()
+                if opts.get('lines'):
+                    txt = self._with_line_numbers(txt)
+    
+                if opts.dump:
+                    path = os.path.join(metadata.schema_name.lower(), metadata.db_type.lower()) \
+                           .replace(' ', '_')
+                    try:
+                        os.makedirs(path)
+                    except OSError:
+                        pass
+                    filename = os.path.join(path, '%s.sql' % object_name.lower())
+                    self.stdout = open(filename, 'w')
+                if opts.get('num') is not None:
+                    txt = code.splitlines()
+                    txt = centeredSlice(txt, center=opts.num+1, width=opts.width)
+                    txt = '\n'.join(txt)
+                else:
+                    txt = 'REMARK BEGIN %s\n%s\nREMARK END\n' % (metadata.descriptor(qualified=True), txt)
+
+                self.poutput(txt)
+                if opts.full:
+                    # Hmm... dependent objects...
+            
                     if opts.full:
                         for dependent_type in ('OBJECT_GRANT', 'CONSTRAINT', 'TRIGGER'):        
                             try:
@@ -864,43 +841,22 @@
                                                                          [dependent_type, object_name, owner])))
                             except cx_Oracle.DatabaseError:
                                 pass
-                    if opts.dump:
-                        self.stdout.close()
+                if opts.dump:
+                    self.stdout.close()
+                    if vc:
+                        subprocess.call(vc + [filename])                    
         except:
-            if opts.dump:
-                statekeeper.restore()
+            statekeeper.restore()
             raise
-        if opts.dump:
-            statekeeper.restore()   
+        statekeeper.restore()   
           
-        def _with_line_numbers(self, txt):
-            txt = txt.splitlines()
-            template = "%%-%dd:%%s" % len(str(len(txt)))
-            txt = '\n'.join(template % (n+1, line) for (n, line) in 
-                            enumerate(txt))
-            return txt
-                
-    @options([make_option('-d', '--dump', action='store_true', help='dump results to files'),
-              make_option('-f', '--full', action='store_true', help='get dependent objects as well'),
-              make_option('-l', '--lines', action='store_true', help='print line numbers'),
-              make_option('-n', '--num', type='int', help='only code near line #num'),
-              make_option('-w', '--width', type='int', default=5, 
-                          help='# of lines before and after --lineNo'),
-              make_option('-a', '--all', action='store_true', help="all schemas' objects"),
-              make_option('-x', '--exact', action='store_true', help="match object name exactly")])            
-    def do_pull(self, arg, opts, vc=None):
-        if opts.dump:
-            statekeeper = Statekeeper(self, ('stdout',))
-        (username, schemas) = self.metadata()
-        for (name, obj, dbtype, descrip) in self._matching_database_objects(arg, opts):
-            self.poutput(descrip)
-            txt = obj.get_ddl()
-            if hasattr(opts, 'lines') and opts.lines:
-                txt = self._with_line_numbers(txt)
-            self.poutput(txt)
-        if opts.dump:
-            statekeeper.restore()   
-        
+    def _with_line_numbers(self, txt):
+        txt = txt.splitlines()
+        template = "%%-%dd:%%s" % len(str(len(txt)))
+        txt = '\n'.join(template % (n+1, line) for (n, line) in 
+                        enumerate(txt))
+        return txt
+                        
     def _show_shortcut(self, shortcut, argpieces):
         try:
             newarg = argpieces[1]
@@ -1485,34 +1441,41 @@
     def _matching_database_objects(self, arg, opts):
         # jrrt.p* should work even if not --all
         # doesn't get java$options
-        if hasattr(opts, 'immediate') and opts.immediate:
-            if hasattr(opts, 'all') and opts.all:
+        (username, schemas) = self.metadata()
+        if opts.get('immediate'):
+            if opts.get('all'):
                 self.perror('Cannot combine --all with --immediate - operation takes too long')
                 raise StopIteration
             else:
                 self.pfeedback('Refreshing metadata for %s...' % username)
                 schemas.refresh_one(username)
-        (username, schemas) = self.metadata()
+        if schemas.complete == 0:
+            self.pfeedback('No data available yet - still gathering schema information')
+            raise StopIteration
+        elif (opts.get('all') and (schemas.complete != 'all')):
+            self.pfeedback('Results are incomplete - only %d schemas mapped so far' % schemas.complete)        
         
-        seek = r'[/\\]?%s[/\\]?' % (
+        seekpatt = r'[/\\]?%s[/\\]?' % (
             arg.replace('*', '.*').replace('?','.').replace('%', '.*'))        
-        seek = re.compile(seek)
-        if hasattr(opts, 'exact') and opts.exact:
+        seek = re.compile(seekpatt, re.IGNORECASE)
+        if opts.get('exact'):
             find = seek.match
         else:
-            find = seek.search               
+            find = seek.search
+        import pdb; pdb.set_trace();
+        qualified = opts.get('all')
         for (schema_name, schema) in schemas.items():
-            if schema_name == username or (hasattr(opts, 'all') and opts.all):
+            if schema_name == username or opts.get('all'):
+                #import pdb; pdb.set_trace()        
                 for (name, dbobj) in schema.schema.items():                
                     metadata = MetaData(object_name=name, schema_name=schema_name, db_object=dbobj)
-                    q = hasattr(opts, 'all') and opts.all
                     if (not arg) or (
-                           find(metadata.descriptor(q), re.IGNORECASE) or 
-                           find(metadata.name(q), re.IGNORECASE) or 
-                           find(metadata.db_type, re.IGNORECASE)):
+                           find(metadata.descriptor(qualified)) or 
+                           find(metadata.name(qualified)) or 
+                           find(metadata.db_type)):
                         yield metadata
 
-    @options([#make_option('-l', '--long', action='store_true', help='long descriptions'),
+    @options([make_option('-l', '--long', action='store_true', help='long descriptions'),
               make_option('-a', '--all', action='store_true', help="all schemas' objects"),
               make_option('-i', '--immediate', action='store_true', help="force immediate refresh of metadata"),
               #make_option('-t', '--timesort', action='store_true', help="Sort by last_ddl_time"),              
@@ -1522,6 +1485,7 @@
         Lists objects as through they were in an {object_type}/{object_name} UNIX
         directory structure.  `*` and `%` may be used as wildcards.
         '''
+        opts.exact = True
         (username, schemas) = self.metadata()
         result = []
         for obj in self._matching_database_objects(arg, opts):
@@ -1530,12 +1494,6 @@
                 # if opts.long: status, last_ddl_time
             else:
                 result.append(obj.descriptor(qualified=opts.all))
-        if not schemas.complete:
-            if opts.all:
-                qualifier = 'may be '
-            else:
-                qualifier = ''
-            self.perror('Metadata discovery still in progress - results %sincomplete' % qualifier)        
         if result:
             result.sort(reverse=bool(opts.reverse))
             self.poutput('\n'.join(result))
@@ -1547,6 +1505,7 @@
         """grep {target} {table} [{table2,...}]
         search for {target} in any of {table}'s fields"""    
         arg = self.parsed(arg)
+        opts.exact = True
         args = arg.split()
         if len(args) < 2:
             self.perror(self.do_grep.__doc__)
@@ -1562,15 +1521,16 @@
                                 (opts.ignorecase and re.IGNORECASE) or 0)
         for target in targets:
             for m in self._matching_database_objects(target, opts):
-                self.pfeedback(m.description(qualified=opts.all()))
+                self.pfeedback(m.descriptor(qualified=opts.all))
                 if hasattr(m.db_object, 'columns'):
                     clauses = []
                     for col in m.db_object.columns:
                         clauses.append(comparitor % (col, sql_pattern))
-                    sql = "SELECT * FROM %s WHERE 1=0\n%s;" % (name, ' '.join(clauses))
+                    sql = "SELECT * FROM %s WHERE 1=0\n%s;" % (m.object_name, ' '.join(clauses))
                     sql = self.parsed(sql, 
                                           terminator=arg.parsed.terminator or ';',
                                           suffix=arg.parsed.suffix)
+                    import pdb; pdb.set_trace()
                     self.do_select(sql)
                 elif hasattr(m.db_object, 'source'):
                     for (line_num, line) in m.db_object.source:
--- a/sqlpython/sqlpython.py	Wed Oct 07 13:23:34 2009 -0400
+++ b/sqlpython/sqlpython.py	Thu Oct 08 09:36:07 2009 -0400
@@ -12,8 +12,6 @@
 import sqlalchemy, pyparsing, schemagroup
 __version__ = '1.6.8'    
 
-cmd2.undefined_options_are_None = True
-
 class Parser(object):
     comment_def = "--" + ~ ('-' + pyparsing.CaselessKeyword('begin')) + pyparsing.ZeroOrMore(pyparsing.CharsNotIn("\n"))    
     def __init__(self, scanner, retainSeparator=True):