@@ -118,13 +118,14 @@ def _path_isdir(path):
118118 return _path_is_mode_type (path , 0o040000 )
119119
120120
121- def _write_atomic (path , data ):
121+ def _write_atomic (path , data , mode = 0o666 ):
122122 """Best-effort function to write data to a path atomically.
123123 Be prepared to handle a FileExistsError if concurrent writing of the
124124 temporary file is attempted."""
125125 # id() is used to generate a pseudo-random filename.
126126 path_tmp = '{}.{}' .format (path , id (path ))
127- fd = _os .open (path_tmp , _os .O_EXCL | _os .O_CREAT | _os .O_WRONLY , 0o666 )
127+ fd = _os .open (path_tmp ,
128+ _os .O_EXCL | _os .O_CREAT | _os .O_WRONLY , mode & 0o666 )
128129 try :
129130 # We first write data to a temporary file, and then use os.replace() to
130131 # perform an atomic rename.
@@ -887,6 +888,16 @@ def path_stats(self, path):
887888 """
888889 return {'mtime' : self .path_mtime (path )}
889890
891+ def _cache_bytecode (self , source_path , cache_path , data ):
892+ """Optional method which writes data (bytes) to a file path (a str).
893+
894+ Implementing this method allows for the writing of bytecode files.
895+
896+ The source path is needed in order to correctly transfer permissions
897+ """
898+ # For backwards compatibility, we delegate to set_data()
899+ return self .set_data (cache_path , data )
900+
890901 def set_data (self , path , data ):
891902 """Optional method which writes data (bytes) to a file path (a str).
892903
@@ -974,7 +985,7 @@ def get_code(self, fullname):
974985 data .extend (_w_long (len (source_bytes )))
975986 data .extend (marshal .dumps (code_object ))
976987 try :
977- self .set_data ( bytecode_path , data )
988+ self ._cache_bytecode ( source_path , bytecode_path , data )
978989 _verbose_message ('wrote {!r}' , bytecode_path )
979990 except NotImplementedError :
980991 pass
@@ -1029,7 +1040,11 @@ def path_stats(self, path):
10291040 st = _os .stat (path )
10301041 return {'mtime' : st .st_mtime , 'size' : st .st_size }
10311042
1032- def set_data (self , path , data ):
1043+ def _cache_bytecode (self , source_path , bytecode_path , data ):
1044+ # Adapt between the two APIs
1045+ return self .set_data (bytecode_path , data , source_path = source_path )
1046+
1047+ def set_data (self , path , data , * , source_path = None ):
10331048 """Write bytes data to a file."""
10341049 parent , filename = _path_split (path )
10351050 path_parts = []
@@ -1049,8 +1064,14 @@ def set_data(self, path, data):
10491064 # If can't get proper access, then just forget about writing
10501065 # the data.
10511066 return
1067+ mode = 0o666
1068+ if source_path is not None :
1069+ try :
1070+ mode = _os .stat (source_path ).st_mode
1071+ except OSError :
1072+ pass
10521073 try :
1053- _write_atomic (path , data )
1074+ _write_atomic (path , data , mode )
10541075 _verbose_message ('created {!r}' , path )
10551076 except (PermissionError , FileExistsError ):
10561077 # Don't worry if you can't write bytecode or someone is writing
0 commit comments