Package pyplusplus :: Package file_writers :: Module writer

Source Code for Module pyplusplus.file_writers.writer

  1  # Copyright 2004-2008 Roman Yakovenko. 
  2  # Distributed under the Boost Software License, Version 1.0. (See 
  3  # accompanying file LICENSE_1_0.txt or copy at 
  4  # http://www.boost.org/LICENSE_1_0.txt) 
  5   
  6  """defines interface for all classes that writes L{code_creators.module_t} to file(s)""" 
  7   
  8  import os 
  9  import time 
 10  import codecs 
 11  import md5sum_repository 
 12  from pyplusplus import utils 
 13  from pyplusplus import _logging_ 
 14  from pyplusplus import code_creators 
 15  from pyplusplus import code_repository 
16 17 -class writer_t(object):
18 """Base class for all module/code writers. 19 20 All writers should have similar usage:: 21 22 w = writer_class(module, file, ...) 23 w.write() 24 """ 25 logger = _logging_.loggers.file_writer 26
27 - def __init__(self, extmodule, files_sum_repository=None, encoding='ascii'):
28 object.__init__(self) 29 self.__extmodule = extmodule 30 self.__files_sum_repository = files_sum_repository 31 self.__encoding=encoding 32 if None is files_sum_repository: 33 self.__files_sum_repository = md5sum_repository.dummy_repository_t() 34 self.__exposed_decls_db = utils.exposed_decls_db_t() 35 self.__exposed_decls_db.register_decls( extmodule.global_ns 36 , extmodule.specially_exposed_decls )
37 38 @property
39 - def encoding( self ):
40 """encoding name used to write generated code to files""" 41 return self.__encoding
42 43 @property
44 - def extmodule(self):
45 """The root of the code creator tree ( code_creators.module_t )""" 46 return self.__extmodule
47 48 @property
49 - def files_sum_repository( self ):
50 return self.__files_sum_repository
51
52 - def write(self):
53 """ Main write method. Should be overridden by derived classes. """ 54 raise NotImplementedError()
55 56 @staticmethod
57 - def create_backup(fpath):
58 """creates backup of the file, by renaming it to C{fpath + ~}""" 59 if not os.path.exists( fpath ): 60 return 61 backup_fpath = fpath + '~' 62 if os.path.exists( backup_fpath ): 63 os.remove( backup_fpath ) 64 os.rename( fpath, backup_fpath )
65
66 - def write_code_repository(self, dir):
67 """creates files defined in L{code_repository} package""" 68 system_headers = self.extmodule.get_system_headers( recursive=True ) 69 for cr in code_repository.all: 70 if cr.file_name in system_headers: 71 #check whether file from code repository is used 72 self.write_file( os.path.join( dir, cr.file_name ), cr.code ) 73 #named_tuple.py is a special case :-( 74 self.write_file( os.path.join( dir, code_repository.named_tuple.file_name ) 75 , code_repository.named_tuple.code )
76 @staticmethod
77 - def write_file( fpath, content, files_sum_repository=None, encoding='ascii' ):
78 """Write a source file. 79 80 This method writes the string content into the specified file. 81 An additional fixed header is written at the top of the file before 82 content. 83 84 @param fpath: File name 85 @type fpath: str 86 @param content: The content of the file 87 @type content: str 88 """ 89 fname = os.path.split( fpath )[1] 90 writer_t.logger.debug( 'write code to file "%s" - started' % fpath ) 91 start_time = time.clock() 92 fcontent_new = [] 93 if os.path.splitext( fpath )[1] == '.py': 94 fcontent_new.append( '# This file has been generated by Py++.' ) 95 else: 96 fcontent_new.append( '// This file has been generated by Py++.' ) 97 fcontent_new.append( os.linesep * 2 ) 98 fcontent_new.append( content ) 99 fcontent_new.append( os.linesep ) #keep gcc happy 100 fcontent_new = ''.join( fcontent_new ) 101 if not isinstance( fcontent_new, unicode ): 102 fcontent_new = unicode( fcontent_new, encoding ) 103 104 new_hash_value = None 105 curr_hash_value = None 106 if files_sum_repository: 107 new_hash_value = files_sum_repository.get_text_value( fcontent_new ) 108 curr_hash_value = files_sum_repository.get_file_value( fname ) 109 if new_hash_value == curr_hash_value: 110 writer_t.logger.debug( 'file was not changed( hash ) - done( %f seconds )' 111 % ( time.clock() - start_time ) ) 112 return 113 114 if None is curr_hash_value and os.path.exists( fpath ): 115 #It could be a first time the user uses files_sum_repository, don't force him 116 #to recompile the code 117 #small optimization to cut down compilation time 118 f = codecs.open( fpath, 'rb', encoding ) 119 fcontent = f.read() 120 f.close() 121 if fcontent == fcontent_new: 122 writer_t.logger.debug( 'file was not changed( content ) - done( %f seconds )' 123 % ( time.clock() - start_time ) ) 124 return 125 126 writer_t.logger.debug( 'file changed or it does not exist' ) 127 128 writer_t.create_backup( fpath ) 129 f = codecs.open( fpath, 'w+b', encoding ) 130 f.write( fcontent_new ) 131 f.close() 132 if new_hash_value: 133 files_sum_repository.update_value( fname, new_hash_value ) 134 writer_t.logger.info( 'file "%s" - updated( %f seconds )' % ( fname, time.clock() - start_time ) )
135
136 - def get_user_headers( self, creators ):
137 headers = [] 138 creators = filter( lambda creator: isinstance( creator, code_creators.declaration_based_t ) 139 , creators ) 140 map( lambda creator: headers.extend( creator.get_user_headers() ) 141 , creators ) 142 return code_creators.code_creator_t.unique_headers( headers )
143
144 - def save_exposed_decls_db( self, file_path ):
145 self.__exposed_decls_db.save( file_path )
146