Package eggbasket :: Module pkginfo
[hide private]

Source Code for Module eggbasket.pkginfo

  1  # -*- coding: UTF-8 -*- 
  2  """Helper functions for handling package meta data.""" 
  3   
  4  __all__ = [ 
  5      'parse_pkg_info', 
  6      'read_pkg_info' 
  7      'read_pkg_info_from_egg', 
  8      'read_pkg_info_from_tar' 
  9  ] 
 10   
 11  import logging 
 12  import re 
 13  import sys 
 14  import tarfile 
 15  import zipfile 
 16   
 17  from os.path import isdir, join 
 18   
 19  import turbogears as tg 
 20   
 21  from eggbasket.util import has_extension, get_base_url 
 22   
 23   
 24  _line_rx = re.compile(r'^([\w-]+?):\s?(.*)') 
 25  log = logging.getLogger("eggbasket.controllers") 
 26   
 27   
28 -class ParseError(Exception):
29 pass
30 -class UnsupportedFormatError(Exception):
31 pass
32
33 -def _to_unicode(s):
34 """Convert string to unicode by assuming ISO-8859-15 encoding.""" 35 try: 36 return unicode(s, 'iso-8859-15') 37 except UnicodeDecodeError: 38 return unicode(s, 'utf-8')
39
40 -def read_pkg_info_from_tar(filename):
41 """Read PKG-INFO file from (compresse/gzipped/bzipped) tar file.""" 42 if not tarfile.is_tarfile(filename): 43 raise UnsupportedFormatError("Unsupported tar file") 44 tar = tarfile.open(filename) 45 try: 46 # get path of PKG-INFO file in archive 47 pkg_info_filename = (i.name for i in tar 48 if i.name.endswith('egg-info/PKG-INFO')).next() 49 fo = tar.extractfile(pkg_info_filename) 50 except (StopIteration, tarfile.TarError), exc: 51 raise UnsupportedFormatError("Can't read PKG-INFO from '%s'." % filename) 52 else: 53 pkg_info_src = fo.read() 54 fo.close() 55 tar.close() 56 57 return pkg_info_src
58
59 -def read_pkg_info_from_egg(filename):
60 """Read PKG-INFO file from Python egg file or directory.""" 61 if isdir(filename): 62 pkg = open(join(filename, 'EGG-INFO', 'PKG-INFO')) 63 pkg_info_src = fo.read() 64 else: 65 try: 66 pkg = zipfile.ZipFile(filename, 'r') 67 except zipfile.error: 68 raise IOError("Can't read egg/zip file '%s'." % filename) 69 else: 70 try: 71 pkg_info_filename = (name for name in pkg.namelist() 72 if name.endswith('/PKG-INFO')).next() 73 pkg_info_src = pkg.read(pkg_info_filename) 74 except (StopIteration, zipfile.error), exc: 75 raise UnsupportedFormatError( 76 "Can't read PKG-INFO from '%s'." % filename) 77 pkg.close() 78 79 return pkg_info_src
80
81 -def set_pkg_info_field(pkg_info, field, value):
82 """Sets field value in pkg_info. 83 84 If field is already set, value will be a list of all values. 85 86 """ 87 if field in pkg_info: 88 if not isinstance(pkg_info[field], list): 89 pkg_info[field] = [pkg_info[field]] 90 pkg_info[field].append(value) 91 else: 92 pkg_info[field] = value
93
94 -def parse_pkg_info(pkg_info_src):
95 """Parse string with PKG-INFO meta data. 96 97 Returns dictionary with PKG-INFO fields as keys. Mutiple field values 98 are collected in a list value. 99 100 Raises ParseError on any malformatted line. 101 102 """ 103 lines = pkg_info_src.split('\n') 104 pkg_info = dict() 105 field = None 106 value = '' 107 108 for i, line in enumerate(lines): 109 if line and line[0] in [' ', '\t']: 110 # continuation line 111 if field: 112 value += '\n' + line.strip() 113 else: 114 raise ParseError('Misplaced continuation line: %s' % line) 115 else: 116 if not line.strip(): 117 # empty line 118 continue 119 mo = _line_rx.match(line) 120 if mo: 121 # new field -> set accumulated value for previous field 122 if field: 123 set_pkg_info_field(pkg_info, field, value) 124 field = mo.group(1).lower() 125 value = _to_unicode(mo.group(2).strip()) 126 else: 127 # invalid line format 128 raise ParseError('Invalid PKG-INFO line: %s' % line) 129 else: 130 set_pkg_info_field(pkg_info, field, value) 131 return pkg_info
132
133 -def read_pkg_info(filename):
134 """Read PKG-INFO meta data from given package distribution file. 135 136 If the package file format is not supported, returns empty dict. 137 138 See parse_pkg_info() for more information. 139 140 """ 141 try: 142 if has_extension(filename, ('.egg', '.zip')): 143 pkg_info_src = read_pkg_info_from_egg(filename) 144 elif has_extension(filename, 145 ('.tar', 'tar.bz2', 'tar.gz', 'tar.Z', '.tgz')): 146 pkg_info_src = read_pkg_info_from_tar(filename) 147 else: 148 raise UnsupportedFormatError 149 except (IOError, OSError, ParseError, UnsupportedFormatError), exc: 150 log.warning("Could not read PKG-INFO from file '%s': %s", filename, exc) 151 return dict() 152 else: 153 return parse_pkg_info(pkg_info_src)
154 155 if __name__ == '__main__': 156 import pprint 157 pprint.pprint(parse_pkg_info(read_pkg_info_from_egg(sys.argv[1]))) 158