Package doapfiend :: Module utils
[hide private]
[frames] | no frames]

Source Code for Module doapfiend.utils

  1   
  2  """ 
  3   
  4  utils.py 
  5  ======== 
  6   
  7  Misc utilities for doapfiend 
  8  ---------------------------- 
  9   
 10  General purpose helper functions and classes for doapfiend 
 11  You'll probably want to use doaplib for most cases. 
 12   
 13  License: BSD-2 
 14   
 15  """ 
 16   
 17  #pylint: disable-msg=C0103 
 18   
 19  import urllib 
 20  import logging 
 21  import textwrap 
 22  import urlparse 
 23  from cStringIO import StringIO 
 24  from httplib import HTTPConnection 
 25  from urllib2 import build_opener, HTTPError, ProxyHandler 
 26   
 27  from rdflib import ConjunctiveGraph, Namespace 
 28  from rdfalchemy import rdfSubject 
 29   
 30   
 31  FOAF = Namespace("http://xmlns.com/foaf/0.1/") 
 32   
 33  __docformat__ = 'epytext' 
 34   
 35  LOG = logging.getLogger('doapfiend') 
 36   
 37  color = {'normal': "\033[0m", 
 38            'bold': "\033[1m", 
 39            'underline': "\033[4m", 
 40            'blink': "\033[5m", 
 41            'reverse': "\033[7m", 
 42            'black': "\033[30m", 
 43            'red': "\033[31m", 
 44            'green': "\033[32m", 
 45            'yellow': "\033[33m", 
 46            'blue': "\033[34m", 
 47            'magenta': "\033[35m", 
 48            'cyan': "\033[36m", 
 49            'white': "\033[37m"} 
 50   
 51   
52 -class NotFoundError(Exception):
53 54 '''DOAP not found''' 55 56 #pylint: disable-msg=W0231
57 - def __init__(self, err_msg):
58 '''Initialize attributes''' 59 self.err_msg = err_msg
60
61 - def __str__(self):
62 return repr(self.err_msg)
63 64
65 -def http_filesize(url):
66 """ 67 Get the size of file without downloading it. 68 bla bla bla 69 blaba 70 71 @param url: URL of file 72 @type url: string 73 74 @rtype: string 75 @return: Size of file 76 77 Usage: 78 79 >>> http_filesize('http://trac.doapspace.org/test_file.txt') 80 '160' 81 """ 82 83 host, path = urlparse.urlsplit(url)[1:3] 84 if ':' in host: 85 # port specified, try to use it 86 host, port = host.split(':', 1) 87 try: 88 port = int(port) 89 except ValueError: 90 LOG.error('invalid port number %r' % port) 91 return False 92 else: 93 # no port specified, use default port 94 port = None 95 connection = HTTPConnection(host, port=port) 96 connection.request("HEAD", path) 97 resp = connection.getresponse() 98 return resp.getheader('content-length')
99 100
101 -def http_exists(url):
102 """ 103 A quick way to check if a file exists on the web. 104 105 @param url: URL of the document 106 @type url: string 107 @rtype: boolean 108 @return: True or False 109 110 Usage: 111 112 >>> http_exists('http://www.python.org/') 113 True 114 >>> http_exists('http://www.python.org/PenguinOnTheTelly') 115 False 116 """ 117 118 host, path = urlparse.urlsplit(url)[1:3] 119 if ':' in host: 120 #port specified, try to use it 121 host, port = host.split(':', 1) 122 try: 123 port = int(port) 124 except ValueError: 125 LOG.error('invalid port number %r' % port) 126 return False 127 else: 128 #no port specified, use default port 129 port = None 130 connection = HTTPConnection(host, port=port) 131 connection.request("HEAD", path) 132 resp = connection.getresponse() 133 if resp.status == 200: # normal 'found' status 134 found = True 135 elif resp.status == 302: # recurse on temporary redirect 136 found = http_exists(urlparse.urljoin(url, 137 resp.getheader('location', ''))) 138 else: # everything else -> not found 139 LOG.info("Status %d %s : %s" % (resp.status, resp.reason, url)) 140 found = False 141 return found
142 143
144 -def is_content_type(url_or_file, content_type):
145 """ 146 Tells whether the URL or pseudofile from urllib.urlopen is of 147 the required content type. 148 149 @param url_or_file: URL or file path 150 @type url_or_file: string 151 @param content_type: Content type we're looking for 152 @type content_type: string 153 154 @rtype: boolean 155 @returns: True if it can return the Content type we want 156 157 Usage: 158 159 >>> is_content_type('http://doapspace.org/doap/sf/nlyrics.rdf', \ 160 'application/rdf+xml') 161 True 162 >>> is_content_type('http://doapspace.org/', 'application/rdf+xml') 163 False 164 """ 165 try: 166 if isinstance(url_or_file, str): 167 thefile = urllib.urlopen(url_or_file) 168 else: 169 thefile = url_or_file 170 result = thefile.info().gettype() == content_type.lower() 171 if thefile is not url_or_file: 172 thefile.close() 173 except IOError: 174 result = False 175 return result
176 177
178 -def pretty_name(field):
179 """ 180 Convert DOAP element name to pretty printable label 181 182 @param field: Text to be formatted 183 @type field: C{string} 184 185 @return: formatted string 186 @rtype: string 187 """ 188 if field == 'programming_language': 189 field = 'Prog. Lang.' 190 if field == 'created': 191 field = 'DOAP Created' 192 field = field.capitalize() 193 field = field.replace('_', ' ') 194 field = field.replace('-', ' ') 195 return field
196 197
198 -def get_n3(xml_text):
199 ''' 200 Return N3 (Notation 3) text 201 202 @param xml_text: XML/RDF 203 @type xml_text: string 204 @return: Notation 3 205 @rtype: string 206 ''' 207 store = ConjunctiveGraph() 208 graph = store.parse(StringIO(xml_text), publicID=None, format="xml") 209 return graph.serialize(format="n3")
210 211 226 227
228 -def fetch_file(url, proxy=None):
229 ''' 230 Download file by URL 231 232 @param url: URL of a file 233 @type url: string 234 235 @param proxy: URL of HTTP Proxy 236 @type proxy: string 237 238 @return: File 239 @rtype: string 240 241 ''' 242 if not url.startswith('http://') and not url.startswith('ftp://'): 243 return open(url, 'r').read() 244 LOG.debug('Fetching ' + url) 245 if proxy: 246 opener = build_opener(ProxyHandler({'http': proxy})) 247 else: 248 opener = build_opener() 249 opener.addheaders = [('Accept', 'application/rdf+xml'), 250 ('User-agent', 251 'Mozilla/5.0 (compatible; doapfiend ' + 252 'http://trac.doapspace.org/doapfiend)')] 253 try: 254 result = opener.open(url) 255 except HTTPError, err_msg: 256 if err_msg.code == 404: 257 raise NotFoundError('Not found: %s' % url) 258 else: 259 LOG.error(err_msg) 260 return result.read()
261
262 -class DoapPrinter(object):
263 264 '''Prints DOAP in human readable text''' 265
266 - def __init__(self, doap, brief=False):
267 '''Initialize attributes''' 268 self.brief = brief 269 self.doap = doap
270
271 - def print_doap(self):
272 ''' 273 Print DOAP in human readable text, optionally colorized 274 275 @rtype: None 276 @return: Just prints DOAP 277 ''' 278 279 self.print_misc() 280 if self.brief: 281 return 282 self.print_people() 283 self.print_repos() 284 self.print_releases()
285
286 - def print_misc(self):
287 '''Prints basic DOAP metadata''' 288 #Tuples with boolean to indicate single or multiple values 289 #and line wrap or not 290 #(name, multiple, wrap) 291 fields = (('name', False, True), ('shortname', False, True), 292 ('homepage', False, False), ('shortdesc', True, True), 293 ('description', True, True), 294 ('old_homepage', True, False), ('created', False, True), 295 ('download_mirror', False, False)) 296 297 fields_verbose = (('license', True, True), 298 ('programming_language', True, True), 299 ('bug_database', False, False), 300 ('screenshots', False, False), ('oper_sys', True, True), 301 ('wiki', True, False), ('download_page', False, False), 302 ('mailing_list', True, False)) 303 304 for fld in fields: 305 self.print_field(fld) 306 if not self.brief: 307 for fld in fields_verbose: 308 self.print_field(fld)
309
310 - def print_repos(self):
311 '''Prints DOAP repository metadata''' 312 if hasattr(self.doap.cvs_repository, 'module') and \ 313 self.doap.cvs_repository.module is not None: 314 print_misc_field('CVS Module:', self.doap.cvs_repository.module) 315 print_misc_field('CVS Anon:', self.doap.cvs_repository.anon_root) 316 print_misc_field('CVS Browse:', 317 self.doap.cvs_repository.cvs_browse.resUri) 318 if hasattr(self.doap.svn_repository, 'location') and \ 319 self.doap.svn_repository.location is not None: 320 print_misc_field('SVN Location:', 321 self.doap.svn_repository.location.resUri) 322 print_misc_field('SVN Browse:', 323 self.doap.svn_repository.svn_browse.resUri)
324
325 - def print_releases(self):
326 '''Print DOAP package release metadata''' 327 if hasattr(self.doap, 'releases'): 328 for release in self.doap.releases: 329 print color['bold'] + color['cyan'] + release.name + \ 330 color['normal'] 331 print color['cyan'] + ' ' + release.revision + ' ' + \ 332 color['normal'] + release.created 333 for frel in release.file_releases: 334 print ' %s' % frel.resUri
335
336 - def print_people(self):
337 '''Print maintainers, documenters, helpers etc.''' 338 print_misc_field("Maintainers:", 339 ",".join([m[FOAF.name] for m in self.doap.maintainer]))
340
341 - def print_field(self, field):
342 ''' 343 Print a DOAP element 344 345 @param field: A misc DOAP element 346 @type field: string 347 348 @rtype: None 349 @return: Nothing 350 ''' 351 name, multi, wrap = field 352 if not hasattr(self.doap, name): 353 return 354 attr = getattr(self.doap, name) 355 if attr == [] or attr is None: 356 return 357 label = '%s' % color['bold'] + pretty_name(name) + \ 358 color['normal'] + ':' 359 label = label.ljust(21) 360 if multi: 361 #Can have multiple values per attribute 362 for thing in getattr(self.doap, name): 363 if isinstance(thing, rdfSubject): 364 text = thing.resUri 365 else: 366 #unicode object 367 text = thing 368 else: 369 text = getattr(self.doap, name) 370 if isinstance(text, rdfSubject): 371 text = text.resUri 372 if wrap: 373 print textwrap.fill('%s %s' % (label, text), 374 initial_indent='', 375 subsequent_indent = ' ') 376 377 else: 378 print '%s %s' % (label, text)
379 380 381 if __name__ == '__main__': 382 import doctest 383 doctest.testmod() 384