26
26
import io
27
27
import winreg
28
28
29
+ # SOURCE_PATTERN defines what an acceptable source package name is
30
+ SOURCE_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z]*[\-]?[0-9]*)(\.zip|\.tar\.gz|\-(py[2-7]*|py[2-7]*\.py[2-7]*)\-none\-any\.whl)'
31
+
32
+ # WHEELBIN_PATTERN defines what an acceptable binary wheel package is
33
+ WHEELBIN_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z0-9\+]*[0-9]?)-cp([0-9]*)\-[0-9|c|o|n|e|p|m]*\-(win32|win\_amd64)\.whl'
34
+
29
35
def get_python_executable (path = None ):
30
36
"""Return the path to the Python executable."""
31
37
python_path = sys .executable if path is None else path
@@ -43,36 +49,24 @@ def get_site_packages_path(path=None):
43
49
return str (pypy_site_packages if pypy_site_packages .is_dir () else site_packages )
44
50
45
51
def onerror (function , path , excinfo ):
46
- """Error handler for `shutil.rmtree`.
47
-
48
- If the error is due to an access error (read-only file), it
49
- attempts to add write permission and then retries.
50
- If the error is for another reason, it re-raises the error.
51
-
52
- Usage: `shutil.rmtree(path, onexc=onerror)"""
52
+ """Error handler for `shutil.rmtree`."""
53
53
if not os .access (path , os .W_OK ):
54
- # Is the error an access error?
55
54
os .chmod (path , stat .S_IWUSR )
56
55
function (path )
57
56
else :
58
57
raise
59
58
60
-
61
59
def getFileProperties (fname ):
62
- """
63
- Read all properties of the given file return them as a dictionary.
64
- """
65
- # from https://stackoverflow.com/questions/580924/how-to-access-a-files-properties-on-windows
60
+ """Read all properties of the given file return them as a dictionary."""
66
61
import win32api
67
- propNames = ('Comments' , 'InternalName' , 'ProductName' ,
68
- 'CompanyName ' , 'LegalCopyright ' , 'ProductVersion ' ,
69
- 'FileDescription' , 'LegalTrademarks' , 'PrivateBuild' ,
70
- 'FileVersion' , 'OriginalFilename' , 'SpecialBuild' )
71
-
62
+ propNames = (
63
+ 'Comments ' , 'InternalName ' , 'ProductName' , 'CompanyName' , 'LegalCopyright ' ,
64
+ 'ProductVersion' , ' FileDescription' , 'LegalTrademarks' , 'PrivateBuild' ,
65
+ 'FileVersion' , 'OriginalFilename' , 'SpecialBuild'
66
+ )
72
67
props = {'FixedFileInfo' : None , 'StringFileInfo' : None , 'FileVersion' : None }
73
68
74
69
try :
75
- # backslash as parm returns dictionary of numeric info corresponding to VS_FIXEDFILEINFO struc
76
70
fixedInfo = win32api .GetFileVersionInfo (fname , '\\ ' )
77
71
props ['FixedFileInfo' ] = fixedInfo
78
72
props ['FileVersion' ] = "%d.%d.%d.%d" % (fixedInfo ['FileVersionMS' ] / 65536 ,
@@ -85,7 +79,6 @@ def getFileProperties(fname):
85
79
86
80
# any other must be of the form \StringfileInfo\%04X%04X\parm_name, middle
87
81
# two are language/codepage pair returned from above
88
-
89
82
strInfo = {}
90
83
for propName in propNames :
91
84
strInfoPath = u'\\ StringFileInfo\\ %04X%04X\\ %s' % (lang , codepage , propName )
@@ -100,9 +93,8 @@ def getFileProperties(fname):
100
93
101
94
102
95
def get_special_folder_path (path_name ):
103
- """Return special folder path"""
96
+ """Return special folder path. """
104
97
from win32com .shell import shell , shellcon
105
-
106
98
for maybe in """
107
99
CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA
108
100
CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY
@@ -111,9 +103,7 @@ def get_special_folder_path(path_name):
111
103
CSIDL_PROGRAM_FILES CSIDL_FONTS""" .split ():
112
104
if maybe == path_name :
113
105
csidl = getattr (shellcon , maybe )
114
- return shell .SHGetSpecialFolderPath (
115
- 0 , csidl , False
116
- )
106
+ return shell .SHGetSpecialFolderPath (0 , csidl , False )
117
107
raise ValueError (
118
108
f"{ path_name } is an unknown path ID"
119
109
)
@@ -126,14 +116,9 @@ def get_winpython_start_menu_folder(current=True):
126
116
folder = get_special_folder_path ("CSIDL_PROGRAMS" )
127
117
else :
128
118
try :
129
- folder = get_special_folder_path (
130
- "CSIDL_COMMON_PROGRAMS"
131
- )
119
+ folder = get_special_folder_path ("CSIDL_COMMON_PROGRAMS" )
132
120
except OSError :
133
- # No CSIDL_COMMON_PROGRAMS on this platform
134
- folder = get_special_folder_path (
135
- "CSIDL_PROGRAMS"
136
- )
121
+ folder = get_special_folder_path ("CSIDL_PROGRAMS" )
137
122
return str (Path (folder ) / 'WinPython' )
138
123
139
124
def remove_winpython_start_menu_folder (current = True ):
@@ -143,47 +128,24 @@ def remove_winpython_start_menu_folder(current=True):
143
128
try :
144
129
shutil .rmtree (path , onexc = onerror )
145
130
except WindowsError :
146
- print (
147
- f"Directory { path } could not be removed" ,
148
- file = sys .stderr ,
149
- )
131
+ print (f"Directory { path } could not be removed" , file = sys .stderr )
150
132
151
133
def create_winpython_start_menu_folder (current = True ):
152
- """Create WinPython Start menu folder -- remove it if it already exists """
134
+ """Create WinPython Start menu folder. """
153
135
path = get_winpython_start_menu_folder (current = current )
154
136
if Path (path ).is_dir ():
155
137
try :
156
138
shutil .rmtree (path , onexc = onerror )
157
139
except WindowsError :
158
- print (
159
- f"Directory { path } could not be removed" ,
160
- file = sys .stderr ,
161
- )
162
- # create, or re-create !
140
+ print (f"Directory { path } could not be removed" , file = sys .stderr )
163
141
Path (path ).mkdir (parents = True , exist_ok = True )
164
142
return path
165
143
166
144
167
- def create_shortcut (
168
- path ,
169
- description ,
170
- filename ,
171
- arguments = "" ,
172
- workdir = "" ,
173
- iconpath = "" ,
174
- iconindex = 0 ,
175
- verbose = True ,
176
- ):
177
- """Create Windows shortcut (.lnk file)"""
145
+ def create_shortcut (path , description , filename , arguments = "" , workdir = "" , iconpath = "" , iconindex = 0 , verbose = True ):
146
+ """Create Windows shortcut (.lnk file)."""
178
147
import pythoncom
179
- from win32com .shell import shell
180
-
181
- ilink = pythoncom .CoCreateInstance (
182
- shell .CLSID_ShellLink ,
183
- None ,
184
- pythoncom .CLSCTX_INPROC_SERVER ,
185
- shell .IID_IShellLink ,
186
- )
148
+ ilink = pythoncom .CoCreateInstance (shell .CLSID_ShellLink , None , pythoncom .CLSCTX_INPROC_SERVER , shell .IID_IShellLink )
187
149
ilink .SetPath (path )
188
150
ilink .SetDescription (description )
189
151
if arguments :
@@ -201,105 +163,64 @@ def create_shortcut(
201
163
try :
202
164
ipf .Save (filename , 0 )
203
165
except :
204
- print ("a fail !" )
205
- pass
206
-
166
+ print ("a fail !" )
207
167
208
168
def print_box (text ):
209
169
"""Print text in a box"""
210
170
line0 = "+" + ("-" * (len (text ) + 2 )) + "+"
211
171
line1 = "| " + text + " |"
212
- print (
213
- ("\n \n " + "\n " .join ([line0 , line1 , line0 ]) + "\n " )
214
- )
215
-
172
+ print ("\n \n " + "\n " .join ([line0 , line1 , line0 ]) + "\n " )
216
173
217
174
def is_python_distribution (path ):
218
- """Return True if path is a Python distribution"""
219
- # XXX: This test could be improved but it seems to be sufficient
175
+ """Return True if path is a Python distribution."""
220
176
has_exec = Path (get_python_executable (path )).is_file ()
221
- has_site = Path (get_site_packages_path (path )).is_dir ()
177
+ has_site = Path (get_site_packages_path (path )).is_dir ()
222
178
return has_exec and has_site
223
179
224
-
225
180
def decode_fs_string (string ):
226
181
"""Convert string from file system charset to unicode"""
227
- charset = sys .getfilesystemencoding ()
228
- if charset is None :
229
- charset = locale .get
F42D
preferredencoding ()
182
+ charset = sys .getfilesystemencoding () or locale .getpreferredencoding ()
230
183
return string .decode (charset )
231
184
232
-
233
185
def exec_shell_cmd (args , path ):
234
- """Execute shell command (*args* is a list of arguments) in *path*"""
235
- # print " ".join(args)
236
- process = subprocess .Popen (
237
- args ,
238
- stdout = subprocess .PIPE ,
239
- stderr = subprocess .PIPE ,
240
- cwd = path ,
241
- shell = True
242
- )
186
+ """Execute shell command (*args* is a list of arguments) in *path*."""
187
+ process = subprocess .Popen (args , stdout = subprocess .PIPE , stderr = subprocess .PIPE , cwd = path , shell = True )
243
188
return decode_fs_string (process .stdout .read ())
244
189
245
190
def exec_run_cmd (args , path = None ):
246
- """run a single command (*args* is a list of arguments) in optional *path*"""
247
- # only applicable to Python-3.5+
248
- # python-3.7+ allows to replace "stdout and stderr ", per "capture_output=True"
249
- if path :
250
- process = subprocess .run (args ,
251
- capture_output = True ,
252
- cwd = path , text = True )
253
- #return decode_fs_string(process.stdout)
254
- return process .stdout
255
- else :
256
- process = subprocess .run (args ,
257
- capture_output = True ,
258
- cwd = path , text = True )
259
- #return decode_fs_string(process.stdout)
260
- return process .stdout
261
-
191
+ """Run a single command (*args* is a list of arguments) in optional *path*."""
192
+ process = subprocess .run (args , capture_output = True , cwd = path , text = True )
193
+ return process .stdout
262
194
263
195
def get_nodejs_version (path ):
264
- """Return version of the Nodejs installed in *path*"""
196
+ """Return version of the Nodejs installed
179B
in *path*. """
265
197
return exec_shell_cmd ("node -v" , path ).splitlines ()[0 ]
266
198
267
-
268
199
def get_npmjs_version (path ):
269
200
"""Return version of the Nodejs installed in *path*"""
270
201
return exec_shell_cmd ("npm -v" , path ).splitlines ()[0 ]
271
202
272
-
273
203
def get_pandoc_version (path ):
274
204
"""Return version of the Pandoc executable in *path*"""
275
205
return exec_shell_cmd ("pandoc -v" , path ).splitlines ()[0 ].split (" " )[- 1 ]
276
206
277
-
278
207
def python_query (cmd , path ):
279
- """Execute Python command using the Python interpreter located in *path*"""
208
+ """Execute Python command using the Python interpreter located in *path*. """
280
209
the_exe = get_python_executable (path )
281
- # debug2021-09-12
282
- # print(f'"{the_exe}" -c "{cmd}"', ' * ', path)
283
-
284
210
return exec_shell_cmd (f'"{ the_exe } " -c "{ cmd } "' , path ).splitlines ()[0 ]
285
211
286
-
287
212
def python_execmodule (cmd , path ):
288
- """Execute Python command using the Python interpreter located in *path*"""
213
+ """Execute Python command using the Python interpreter located in *path*. """
289
214
the_exe = get_python_executable (path )
290
215
exec_shell_cmd (f'{ the_exe } -m { cmd } ' , path )
291
216
292
-
293
217
def get_python_infos (path ):
294
218
"""Return (version, architecture) for the Python distribution located in
295
219
*path*. The version number is limited to MAJOR.MINOR, the architecture is
296
220
an integer: 32 or 64"""
297
221
is_64 = python_query ("import sys; print(sys.maxsize > 2**32)" , path )
298
222
arch = {"True" : 64 , "False" : 32 }.get (is_64 , None )
299
- ver = python_query (
300
- "import sys;print(f'{sys.version_info.major}.{sys.version_info.minor}')" ,
301
- path ,
302
- )
223
+ ver = python_query ("import sys;print(f'{sys.version_info.major}.{sys.version_info.minor}')" , path )
303
224
if re .match (r"([0-9]*)\.([0-9]*)" , ver ) is None :
304
225
ver = None
305
226
return ver , arch
@@ -446,20 +367,6 @@ def extract_archive(fname, targetdir=None, verbose=False):
446
367
obj .extractall (path = targetdir )
447
368
return targetdir
448
369
449
- # SOURCE_PATTERN defines what an acceptable source package name is
450
- # As of 2014-09-08 :
451
- # - the wheel package format is accepte in source directory
452
- # - the tricky regexp is tuned also to support the odd jolib naming :
453
- # . joblib-0.8.3_r1-py2.py3-none-any.whl,
454
- # . joblib-0.8.3-r1.tar.gz
455
-
456
- SOURCE_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z]*[\-]?[0-9]*)(\.zip|\.tar\.gz|\-(py[2-7]*|py[2-7]*\.py[2-7]*)\-none\-any\.whl)'
457
-
458
- # WHEELBIN_PATTERN defines what an acceptable binary wheel package is
459
- # "cp([0-9]*)" to replace per cp(34) for python3.4
460
- # "win32|win\_amd64" to replace per "win\_amd64" for 64bit
461
- WHEELBIN_PATTERN = r'([a-zA-Z0-9\-\_\.]*)-([0-9\.\_]*[a-z0-9\+]*[0-9]?)-cp([0-9]*)\-[0-9|c|o|n|e|p|m]*\-(win32|win\_amd64)\.whl'
462
-
463
370
464
371
def get_source_package_infos (fname ):
465
372
"""Return a tuple (name, version) of the Python source package."""
@@ -506,12 +413,7 @@ def buildflit_wininst(
506
413
)
507
414
508
415
for distname in os .listdir (distdir ):
509
- # for wheels (winpython here)
510
- match = re .match (SOURCE_PATTERN , distname )
511
- if match is not None :
512
- break
513
- match = re .match (WHEELBIN_PATTERN , distname )
514
- if match is not None :
416
+ if re .match (SOURCE_PATTERN , distname ) or re .match (WHEELBIN_PATTERN , distname ):
515
417
break
516
418
else :
517
419
raise RuntimeError (f"Build failed: not a pure Python package? { distdir } " )
@@ -527,12 +429,7 @@ def buildflit_wininst(
527
429
return dst_fname
528
430
529
431
530
- def direct_pip_install (
531
- fname ,
532
- python_exe = None ,
533
- verbose = False ,
534
- install_options = None ,
535
- ):
432
+ def direct_pip_install (fname , python_exe = None , verbose = False , install_options = None ):
536
433
"""Direct install via python -m pip !"""
537
434
copy_to = str (Path (fname ).parent )
538
435
0 commit comments