degal/filesystem.py
changeset 55 77abe8dca695
parent 51 0f39cb5e4b11
child 60 406da27a4be2
equal deleted inserted replaced
54:cc007b6ab972 55:77abe8dca695
     1 """
     1 """
     2     Filesystem path handling
     2     Filesystem path handling
     3 """
     3 """
     4 
     4 
     5 import os, os.path
     5 import os, os.path, errno
       
     6 import codecs
     6 
     7 
     7 class Node (object) :
     8 class Node (object) :
     8     """
     9     """
     9         A filesystem object is basically just complicated representation of a path.
    10         A filesystem object is basically just complicated representation of a path.
    10         
    11         
   130             Tests if this node represents a normal file on the filesystem
   131             Tests if this node represents a normal file on the filesystem
   131         """
   132         """
   132 
   133 
   133         return os.path.isfile(self.path)
   134         return os.path.isfile(self.path)
   134     
   135     
       
   136     def path_from (self, node) :
       
   137         """
       
   138             Returns a relative path to this node from the given node
       
   139         """
       
   140 
       
   141         XXX
       
   142 
       
   143     def stat (self, soft=False) :
       
   144         """
       
   145             Returns the os.stat struct for this node.
       
   146             
       
   147             If `soft` is given, returns None if this node doesn't exist
       
   148         """
       
   149 
       
   150         try :
       
   151             return os.stat(self.path)
       
   152 
       
   153         except OSError, e :
       
   154             # trap ENOENT for soft
       
   155             if soft and e.errno == errno.ENOENT :
       
   156                 return None
       
   157 
       
   158             else :
       
   159                 raise
       
   160 
   135     def __str__ (self) :
   161     def __str__ (self) :
   136         """
   162         """
   137             Returns the raw filesystem path
   163             Returns the raw filesystem path
   138         """
   164         """
   139 
   165 
   189         """
   215         """
   190             Tests if this file's extension is part of the recognized list of extensions
   216             Tests if this file's extension is part of the recognized list of extensions
   191         """
   217         """
   192         
   218         
   193         return (self.fileext.lower() in ext_list)
   219         return (self.fileext.lower() in ext_list)
       
   220     
       
   221     def open (self, mode='r', encoding=None, errors=None, bufsize=None) :
       
   222         """
       
   223             Wrapper for open/codecs.open
       
   224         """
       
   225 
       
   226         if encoding :
       
   227             return codecs.open(self.path, mode, encoding, errors, bufsize)
       
   228 
       
   229         else :
       
   230             return open(self.path, mode, bufsize)
   194 
   231 
   195 class Directory (Node) :
   232 class Directory (Node) :
   196     """
   233     """
   197         A directory is a node that contains other nodes.
   234         A directory is a node that contains other nodes.
   198     """
   235     """
   199 
   236 
   200     # a list of (test_func, node_type) tuples for use by children() to build subnodes with
   237     # a list of (test_func, node_type) tuples for use by children() to build subnodes with
   201     NODE_TYPES = None
   238     NODE_TYPES = None
   202    
   239    
   203     def subdir (self, name) :
   240     def subdir (self, name, create=False) :
   204         """
   241         """
   205             Returns a Directory object representing the name underneath this dir
   242             Returns a Directory object representing the name underneath this dir.
       
   243 
       
   244             If the create option is given, the directory will be created if it does not exist.
       
   245         """
       
   246 
       
   247         dir = Directory(self, name=name)
       
   248         
       
   249         # try and mkdir?
       
   250         if create and not dir.is_dir() :
       
   251             dir.mkdir()
       
   252     
       
   253     def subfile (self, name) :
       
   254         """
       
   255             Returns a File object representing the name underneath this dir
   206         """
   256         """
   207 
   257 
   208         return Directory(self, name=name)
   258         return Directory(self, name=name)
   209     
   259 
   210     def subfile (self, name) :
   260     def mkdir (self) :
   211         """
   261         """
   212             Returns a File object representing the name underneath this dir
   262             Create this directory with default permissions
   213         """
   263             
   214 
   264             XXX: mode argument
   215         return Directory(self, name=name)
   265         """
       
   266         
       
   267         # do it
       
   268         os.mkdir(self.path)
   216 
   269 
   217     def listdir (self, skip_dotfiles=True) :
   270     def listdir (self, skip_dotfiles=True) :
   218         """
   271         """
   219             Yield a series of raw fsnames for nodes in this dir
   272             Yield a series of raw fsnames for nodes in this dir
   220         """
   273         """
   221         
   274         
   222         # expressed 
   275         # expressed 
   223         return (fsname for fsname in os.listdir(self.path) if not (skip_dotfiles and fsname.startswith('.')))
   276         return (fsname for fsname in os.listdir(self.path) if not (skip_dotfiles and fsname.startswith('.')))
   224 
   277 
   225     def child_nodes (self, skip_dotfiles=True) :
   278     def subnodes (self, skip_dotfiles=True, sort=True) :
   226         """
   279         """
   227             Yield a series of nodes contained in this dir
   280             Yield a series of Nodes contained in this dir.
   228         """
   281 
   229 
   282             If skip_dotfiles is given, nodes that begin with a . are omitted.
   230         return (Node(self, fsname) for fsname in self.listdir(skip_dotfiles))
   283 
       
   284             If `sort` is given, the returned nodes will be in sorted order.
       
   285         """
       
   286 
       
   287         iter = (Node(self, fsname) for fsname in self.listdir(skip_dotfiles))
       
   288 
       
   289         if sort :
       
   290             return sorted(iter)
       
   291 
       
   292         else :
       
   293             return iter
   231 
   294 
   232     def __iter__ (self) :
   295     def __iter__ (self) :
   233         """
   296         """
   234             Iterating over a Directory yields sub-Nodes.
   297             Iterating over a Directory yields sub-Nodes.
   235 
   298 
   236             Dotfiles are skipped.
   299             Dotfiles are skipped.
   237         """
   300         """
   238         
   301         
   239         return self.childnodes()
   302         return self.subnodes()
   240 
   303 
   241     @property
   304     @property
   242     def root_path (self) :
   305     def root_path (self) :
   243         """
   306         """
   244             Build and return a relative path to the root of this dir tree
   307             Build and return a relative path to the root of this dir tree
       
   308 
       
   309             XXX: move to node
   245         """
   310         """
   246         
   311         
   247         # build using parent root_path
   312         # build using parent root_path
   248         return os.path.join('..', self.parent.root_path)
   313         return os.path.join('..', self.parent.root_path)
   249  
   314  
   254             This uses self.NODE_TYPES to figure out what kind of sub-node object to build. This should be a list of
   319             This uses self.NODE_TYPES to figure out what kind of sub-node object to build. This should be a list of
   255                 (test_func, node_type)
   320                 (test_func, node_type)
   256 
   321 
   257             tuples, of which the first is a function that takes a Node as it's sole argument, and returns a boolean.
   322             tuples, of which the first is a function that takes a Node as it's sole argument, and returns a boolean.
   258             For the first test_func which returns True, a Node-subclass object is constructed using node_type.from_node.
   323             For the first test_func which returns True, a Node-subclass object is constructed using node_type.from_node.
       
   324 
       
   325             XXX: never used
   259         """
   326         """
   260 
   327 
   261         for node in self :
   328         for node in self :
   262             # figure out what type to use
   329             # figure out what type to use
   263             for test_func, node_type in self.NODE_TYPES :
   330             for test_func, node_type in self.NODE_TYPES :