home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 May / maximum-cd-2010-05.iso / DiscContents / boxee-0.9.20.10711.exe / scripts / OpenSubtitles / resources / lib / RecursiveParser.py < prev    next >
Encoding:
Python Source  |  2009-07-20  |  14.5 KB  |  255 lines

  1. # Python is a feature-rich language and it can also be extended via libraries.  In
  2. # this file, we need to include functionality inside the "os" library module.  We
  3. # include this library by typing "import os"
  4. import os
  5.  
  6. # Creating classes in Python is easy.  Simply declare it as shown below and indent
  7. # everything that belongs in the class.
  8. #
  9. # On another note, you may have noticed I comment everything using the # mark
  10. # and that my comments appear above the code that they discuss.  You may have also
  11. # noticed the comment listed below the line "class RecursiveParser:" that uses three
  12. # single quote marks to designate the beginning and end of the comment.  These are
  13. # special comments that can be used to self-document your classes and methods for
  14. # use in PyDoc documentation and IDEs that support them for things like automatic
  15. # line completion, etc.  They must appear BELOW the class, function, and method
  16. # declarations they are associated with.
  17. class RecursiveParser:
  18.     '''
  19.     The RecursiveParser class contains methods to recursively find directories, files, or specific files in a
  20.     directory structure
  21.     '''
  22.     
  23.     # The getRecursiveDirList() method accepts a directory path as an argument and
  24.     # then recursively searches through that path looking for directories to return
  25.     # to you in the form of a list.
  26.     #
  27.     # If you look at the bottom of the file on line ????????, you will notice we
  28.     # are only passing one argument (a directory path) to this method.  However, 
  29.     # when we declare the method here, we are specifying two arguments.
  30.     #
  31.     # This is, in my opinion, an oddity with Python classes.  If this
  32.     # method were a stand-alone function outside of a class, then you would not need the
  33.     # "self" argument.  The reasons for this oddity are beyond the scope of this tutorial so
  34.     # just take in on faith for now that whenever you create a method inside of a class,
  35.     # its first argument must be "self", followed by any other arguments you wish to add.
  36.     def getRecursiveDirList(self, basedir):
  37.         '''
  38.         getRecursiveDirList takes a directory in the form of a string and returns a list of all
  39.         subdirectories contained therein
  40.         (e.g. getRecursiveDirList('/home/user/files')
  41.         '''
  42.         # I want all of my directory paths to have a trailing slash (e.g. /home/user/documents/).
  43.         # However, if I add the ability to this code to accept command line arguments, I can't
  44.         # guarantee that all users of my code will add this slash.  Therefore, I have created a
  45.         # method that checks to see if the trailing slash exists and appends one if it does not.
  46.         basedir = self.addSlash(basedir)
  47.             
  48.         # Here we specify two variables.  subdirlist keeps a list of all the directories contained
  49.         # within the current directory and dirlist keeps a running list of all the directories found
  50.         # throughout the entire directory structure.
  51.         subdirlist = []
  52.         dirlist = []
  53.         
  54.         # Since we know that the argument "basedir" is a directory (or should be) we will add it to
  55.         # the dirlist variable.
  56.         dirlist.append(basedir)
  57.         
  58.         # Next, we are going to list all the contents of the current directory and then check each
  59.         # item one at a time to see if it is a directory or a file.  If it is a directory, then we
  60.         # will add it to the dirlist variable (our final, definitive list of all directories contained in a
  61.         # given path) and also the subdirlst variable (a list of directories we still need to check).
  62.         #
  63.         # Since things can go wrong, like a user mistakenly entering their first name instead of a valid
  64.         # directory, we need to place this code within a try: except: statement.  If we didn't do this,
  65.         # and a user entered invalid data, our program would crash.  By placing error handling
  66.         # around our code like this, we are able to print out a friendly, trust-inspiring message
  67.         # to the user instead of a bleak stack trace.  In this case, I'm only catching a "WindowsError",
  68.         # which is sort of robust, but not really.
  69.         try:
  70.             for item in os.listdir(basedir):
  71.                 if os.path.isdir(os.path.join(basedir, item)):
  72.                     dirlist.append(os.path.join(basedir, item))
  73.                     subdirlist.append(os.path.join(basedir, item))
  74.                     
  75.         # There are, of course, other exception types and a generic except statement that can
  76.         # catch all errors.  The generic would look like "except:".  I ran into a permission
  77.         # issue on my Windows machine when I ran this script, so I thought I'd use the WindowsError
  78.         # exception as an example of catching a specific type of error.
  79.         #
  80.         # Using specific exception types in your error handling allows you to customize
  81.         # error messages for each type of error that occurs instead of always printing
  82.         # a generic "Something went wrong but I don't know what it was" type of error.
  83.         except WindowsError:
  84.             print "An error has occured.  You may not have permission"
  85.             print "to access all files and folders in the specified path."
  86.             
  87.         # Now we need to recursively call getRecursiveDirList until you reach the end of
  88.         # the directory structure.  This means that getRecursiveDirList will call itself
  89.         # over and over again until there are no more subdirectories left to process.
  90.         for subdir in subdirlist:
  91.             dirlist += self.getRecursiveDirList(subdir)
  92.             
  93.         # Return a comprehensive list of all directories contained within 'basedir' 
  94.         return dirlist
  95.         
  96.     # The getRecursiveFileList() method accepts a directory path as an argument and
  97.     # then recursively searches through that path looking for files to return
  98.     # to you in the form of a list.
  99.     #
  100.     # Notice that this method also has "self" as its first argument.  This is because
  101.     # it is also part of a class.  If it were a stand-alone function, we wouldn't need
  102.     # this argument.  In fact, our program would probably crash if we had it there in
  103.     # that case.
  104.     #
  105.     # You probably noticed that getRecursiveFileList has one more parameter than
  106.     # getRecursiveDirList has (extensions=[]).  This allows us to limit the list of
  107.     # files to a certain extension, or list of extensions.  For example, if I
  108.     # called this method like this:
  109.     #       getRecursiveFileList('/home/user/documents', ['html', 'htm', 'txt'])
  110.     # then the method would only return files to me that had those three extensions.
  111.     #
  112.     # On the other hand, I don't want to have to type ALL possible extensions when
  113.     # I want absolutely everything, so I declare the extensions variable like this:
  114.     #        extensions=[]
  115.     # This means that "extensions" is optional.  The method will take whatever
  116.     # extensions I give it, but if I choose to leave them off, it will default
  117.     # to an empty list, which my code interprets to mean "everything".
  118.     #
  119.     # You can make any parameter optional by appending an equals sign to it and
  120.     # following that with a default value (e.g. printName(fname="unknown", lname="unknown")).
  121.     #
  122.     # IMPORTANT NOTE: Python orders the variables you pass to a method by applying the
  123.     # first variable to the first item in the method's parameter list, second to second,
  124.     # and so forth.  So, if you had this method:
  125.     #        printName(fname="unknown", lname="unknown")
  126.     # and you were trying to print a name, but you only knew the last name, Smith, you
  127.     # couldn't just type "printName("Smith") because Python would assign the last name
  128.     # Smith to the fname (first name) variable; which isn't what you want.
  129.     #
  130.     # In this case, to get the variables to align correctly, you would have to either type
  131.     # "printName("unknown", "Smith"), which doesn't take advantage of your optional parameters,
  132.     # or better yet, type "printName(lname="Smith)".  This will assign smith to the lname variable
  133.     # and let the fname variable revert to its default value automatically.
  134.     def getRecursiveFileList(self, basedir, extensions=[]):
  135.         '''
  136.         getRecursiveFileList takes a directory in the form of a string and returns a list of all
  137.         of the files contained therein.  If you would like to search only for specific file
  138.         extensions, pass a list of extensions as the second argument
  139.         (e.g. getRecursiveFileList('/home/user/files', ['htm', 'html', 'css'])
  140.         '''
  141.         # Add a trailing slash if one doesn't alreay exist
  142.         # You have already seen the next three lines of code.  Refer to
  143.         # getRecursiveDirList() if you have forgotten what they are for.
  144.         basedir = self.addSlash(basedir)
  145.         
  146.         subdirlist = []
  147.         filelist = []
  148.         
  149.         # This code is almost identical to the try: except: segment of getRecursiveDirList().
  150.         # The differences here are that instead of directories, we are searching for files
  151.         # and adding them to the definitive list "filelist".
  152.         try:
  153.             # First, we check to see if the "extensions" variable has any items in it.  If
  154.             # it does, then we first check to see if the current item is a file or not, and
  155.             # if it is a file, we check to see if its extension is one of the ones specified
  156.             # in the "extensions" variable.  If all these tests pass, then we add the file
  157.             # to the file list.  If not, we don't.
  158.             if len(extensions) > 0:
  159.                 for item in os.listdir(basedir):
  160.                     if os.path.isfile(os.path.join(basedir, item)):
  161.                         if extensions.count(item[item.rfind('.') + 1:]) > 0:
  162.                             filelist.append(os.path.join(basedir, item))
  163.                     else:
  164.                         subdirlist.append(os.path.join(basedir, item))
  165.             # If the "extensions" variable is empty, then we add anything that is a file to
  166.             # "filelist".
  167.             else:
  168.                 for item in os.listdir(basedir):
  169.                     if os.path.isfile(os.path.join(basedir, item)):
  170.                         filelist.append(os.path.join(basedir, item))
  171.                     else:                        
  172.                         subdirlist.append(os.path.join(basedir, item))
  173.                         
  174.         # Here again you can see an example of catching a specific type of error.  In this
  175.         # example, I am catching both a WindowsError exception and also a TypeError exception
  176.         # While my error messages are probably lame, this shows that you can customize your
  177.         # error handling in order to let your users (or you yourself) know what is going on when
  178.         # a problem occurs while running your code.
  179.         #except WindowsError:
  180.             #print "An error has occured.  You may not have permission"
  181.             #print "to access all files and folders in the specified path."
  182.             
  183.         except TypeError:
  184.             print "The calling code has passed an invalid parameter to"
  185.             print "getRecursiveFileList."
  186.         
  187.         # This is an example of a generic catchall for exceptions.
  188.         except:
  189.             print "Failure! Failure! A failure has occured! We don't know"
  190.             print "what failed exactly, but whatever it was, it failed!" 
  191.  
  192.                     
  193.         # Recursively call getRecursiveDirList until you reach the end of the directory structure
  194.         for subdir in subdirlist:
  195.             filelist += self.getRecursiveFileList(subdir, extensions)
  196.             
  197.         # Return a comprehensive list of all files (or specified files) contained within 'basedir' 
  198.         return filelist
  199.  
  200.     def addSlash(self, dir):
  201.         '''
  202.         addSlash(dir) adds a trailing slash to a string representation of a directory
  203.         '''        
  204.         # I want to make sure that all the paths I pass to my program have a trailing
  205.         # slash character.  I could have written more code in the methods to handle both
  206.         # cases, but I chose to do it this way in order to keep things simple.
  207.         if dir[-1:] != '/':
  208.             dir += '/'
  209.         
  210.         return dir
  211.  
  212. # In Python, if you run code directly from the command line, the internal variable
  213. # __name__ will have a value of "__main__".  If you call the file via an "include"
  214. # statement to use it within some other code, then "__name__" will be something else.
  215. #
  216. # This is nice because it lets you add code to all your files that will run when called
  217. # from the command line, but will not run when your code is used as a library.  You can
  218. # use this to add unit testing to library files.  When you run your libraries from the
  219. # command line, then your unit tests will run, but when a user imports your library
  220. # into their code, your unit test code is ignored.
  221. #
  222. # We do this by using the statement "if __name__ == '__main__':".  Anything contained
  223. # within this code block will be executed when the file is run from the command line
  224. # and ignored when it is run in any other way.
  225. #
  226. # While this is not serious unit testing, it demonstrates a good strategy and
  227. # it will exercise the two main methods of our class and display the results
  228. # onto the screen (in an albeit ugly way). 
  229. #if __name__ == '__main__':
  230.     ## This is how you create an instance of your RecursiveParser class
  231.     #parser = RecursiveParser()
  232.     
  233.     ## Replace /home/user/documents with whichever path you wish to search
  234.     #print 'PRINTING DIRECTORIES\n'
  235.     #dirs = parser.getRecursiveDirList('/home/user/documents')
  236.     #print dirs
  237.     
  238.     ## Replace /home/user/documents with whichever path you wish to extract a list of files from
  239.     ## Remember that the extensions argument is optional.  If you leave it off the returned list
  240.     ## contain a list of all the files in the specified directory.
  241.     #print 'PRINTING ALL FILES\n'
  242.     #files = parser.getRecursiveFileList('/home/user/documents')
  243.     #print files
  244.     
  245.     ## Here is an example that specifies some file extensions.
  246.     #print 'PRINTING ALL HTML, TXT, and DOC FILES\n'
  247.     #files = parser.getRecursiveFileList('/home/user/documents', ['html', 'txt', 'doc'])
  248.     #print files
  249.     
  250.     ## Finally, here is an example that specifies only one file extension.  Note that even
  251.     ## when there is only one file extension, it still needs to be in a list
  252.     #print 'PRINTING ALL HTML FILES\n'
  253.     #files = parser.getRecursiveFileList('/home/user/documents', ['html'])
  254.     #print files
  255.