| 
									
										
										
										
											2002-12-23 16:30:00 +00:00
										 |  |  | """Utilities to support packages.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def extend_path(path, name): | 
					
						
							|  |  |  |     """Extend a package's path.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Intended use is to place the following code in a package's __init__.py: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         from pkgutil import extend_path | 
					
						
							|  |  |  |         __path__ = extend_path(__path__, __name__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This will add to the package's __path__ all subdirectories of | 
					
						
							|  |  |  |     directories on sys.path named after the package.  This is useful | 
					
						
							|  |  |  |     if one wants to distribute different parts of a single logical | 
					
						
							|  |  |  |     package as multiple directories. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     It also looks for *.pkg files beginning where * matches the name | 
					
						
							|  |  |  |     argument.  This feature is similar to *.pth files (see site.py), | 
					
						
							|  |  |  |     except that it doesn't special-case lines starting with 'import'. | 
					
						
							|  |  |  |     A *.pkg file is trusted at face value: apart from checking for | 
					
						
							|  |  |  |     duplicates, all entries found in a *.pkg file are added to the | 
					
						
							|  |  |  |     path, regardless of whether they are exist the filesystem.  (This | 
					
						
							|  |  |  |     is a feature.) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     If the input path is not a list (as is the case for frozen | 
					
						
							|  |  |  |     packages) it is returned unchanged.  The input path is not | 
					
						
							|  |  |  |     modified; an extended copy is returned.  Items are only appended | 
					
						
							|  |  |  |     to the copy at the end. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     It is assumed that sys.path is a sequence.  Items of sys.path that | 
					
						
							|  |  |  |     are not (unicode or 8-bit) strings referring to existing | 
					
						
							|  |  |  |     directories are ignored.  Unicode items of sys.path that cause | 
					
						
							|  |  |  |     errors when used as filenames may cause this function to raise an | 
					
						
							|  |  |  |     exception (in line with os.path.isdir() behavior). | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not isinstance(path, list): | 
					
						
							|  |  |  |         # This could happen e.g. when this is called from inside a | 
					
						
							|  |  |  |         # frozen package.  Return the path unchanged in that case. | 
					
						
							|  |  |  |         return path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pname = os.path.join(*name.split('.')) # Reconstitute as relative path | 
					
						
							|  |  |  |     # Just in case os.extsep != '.' | 
					
						
							|  |  |  |     sname = os.extsep.join(name.split('.')) | 
					
						
							|  |  |  |     sname_pkg = sname + os.extsep + "pkg" | 
					
						
							|  |  |  |     init_py = "__init__" + os.extsep + "py" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     path = path[:] # Start with a copy of the existing path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for dir in sys.path: | 
					
						
							| 
									
										
										
										
											2003-09-17 05:50:59 +00:00
										 |  |  |         if not isinstance(dir, basestring) or not os.path.isdir(dir): | 
					
						
							| 
									
										
										
										
											2002-12-23 16:30:00 +00:00
										 |  |  |             continue | 
					
						
							|  |  |  |         subdir = os.path.join(dir, pname) | 
					
						
							|  |  |  |         # XXX This may still add duplicate entries to path on | 
					
						
							|  |  |  |         # case-insensitive filesystems | 
					
						
							|  |  |  |         initfile = os.path.join(subdir, init_py) | 
					
						
							|  |  |  |         if subdir not in path and os.path.isfile(initfile): | 
					
						
							|  |  |  |             path.append(subdir) | 
					
						
							|  |  |  |         # XXX Is this the right thing for subpackages like zope.app? | 
					
						
							|  |  |  |         # It looks for a file named "zope.app.pkg" | 
					
						
							|  |  |  |         pkgfile = os.path.join(dir, sname_pkg) | 
					
						
							|  |  |  |         if os.path.isfile(pkgfile): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 f = open(pkgfile) | 
					
						
							|  |  |  |             except IOError, msg: | 
					
						
							|  |  |  |                 sys.stderr.write("Can't open %s: %s\n" % | 
					
						
							|  |  |  |                                  (pkgfile, msg)) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 for line in f: | 
					
						
							|  |  |  |                     line = line.rstrip('\n') | 
					
						
							|  |  |  |                     if not line or line.startswith('#'): | 
					
						
							|  |  |  |                         continue | 
					
						
							|  |  |  |                     path.append(line) # Don't check for existence! | 
					
						
							|  |  |  |                 f.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return path |