2626import io
2727import winreg
2828
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+
2935def get_python_executable (path = None ):
3036 """Return the path to the Python executable."""
3137 python_path = sys .executable if path is None else path
@@ -43,36 +49,24 @@ def get_site_packages_path(path=None):
4349 return str (pypy_site_packages if pypy_site_packages .is_dir () else site_packages )
4450
4551def 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`."""
5353 if not os .access (path , os .W_OK ):
54- # Is the error an access error?
5554 os .chmod (path , stat .S_IWUSR )
5655 function (path )
5756 else :
5857 raise
5958
60-
6159def 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."""
6661 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+ )
7267 props = {'FixedFileInfo' : None , 'StringFileInfo' : None , 'FileVersion' : None }
7368
7469 try :
75- # backslash as parm returns dictionary of numeric info corresponding to VS_FIXEDFILEINFO struc
7670 fixedInfo = win32api .GetFileVersionInfo (fname , '\\ ' )
7771 props ['FixedFileInfo' ] = fixedInfo
7872 props ['FileVersion' ] = "%d.%d.%d.%d" % (fixedInfo ['FileVersionMS' ] / 65536 ,
@@ -85,7 +79,6 @@ def getFileProperties(fname):
8579
8680 # any other must be of the form \StringfileInfo\%04X%04X\parm_name, middle
8781 # two are language/codepage pair returned from above
88-
8982 strInfo = {}
9083 for propName in propNames :
9184 strInfoPath = u'\\ StringFileInfo\\ %04X%04X\\ %s' % (lang , codepage , propName )
@@ -100,9 +93,8 @@ def getFileProperties(fname):
10093
10194
10295def get_special_folder_path (path_name ):
103- """Return special folder path"""
96+ """Return special folder path. """
10497 from win32com .shell import shell , shellcon
105-
10698 for maybe in """
10799 CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA
108100 CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY
@@ -111,9 +103,7 @@ def get_special_folder_path(path_name):
111103 CSIDL_PROGRAM_FILES CSIDL_FONTS""" .split ():
112104 if maybe == path_name :
113105 csidl = getattr (shellcon , maybe )
114- return shell .SHGetSpecialFolderPath (
115- 0 , csidl , False
116- )
106+ return shell .SHGetSpecialFolderPath (0 , csidl , False )
117107 raise ValueError (
118108 f"{ path_name } is an unknown path ID"
119109 )
@@ -126,14 +116,9 @@ def get_winpython_start_menu_folder(current=True):
126116 folder = get_special_folder_path ("CSIDL_PROGRAMS" )
127117 else :
128118 try :
129- folder = get_special_folder_path (
130- "CSIDL_COMMON_PROGRAMS"
131- )
119+ folder = get_special_folder_path ("CSIDL_COMMON_PROGRAMS" )
132120 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" )
137122 return str (Path (folder ) / 'WinPython' )
138123
139124def remove_winpython_start_menu_folder (current = True ):
@@ -143,47 +128,24 @@ def remove_winpython_start_menu_folder(current=True):
143128 try :
144129 shutil .rmtree (path , onexc = onerror )
145130 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 )
150132
151133def 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. """
153135 path = get_winpython_start_menu_folder (current = current )
154136 if Path (path ).is_dir ():
155137 try :
156138 shutil .rmtree (path , onexc = onerror )
157139 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 )
163141 Path (path ).mkdir (parents = True , exist_ok = True )
164142 return path
165143
166144
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)."""
178147 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 )
187149 ilink .SetPath (path )
188150 ilink .SetDescription (description )
189151 if arguments :
@@ -201,105 +163,64 @@ def create_shortcut(
201163 try :
202164 ipf .Save (filename , 0 )
203165 except :
204- print ("a fail !" )
205- pass
206-
166+ print ("a fail !" )
207167
208168def print_box (text ):
209169 """Print text in a box"""
210170 line0 = "+" + ("-" * (len (text ) + 2 )) + "+"
211171 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 " )
216173
217174def 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."""
220176 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 ()
222178 return has_exec and has_site
223179
224-
225180def decode_fs_string (string ):
226181 """Convert string from file system charset to unicode"""
227- charset = sys .getfilesystemencoding ()
228- if charset is None :
229- charset = locale .getpreferredencoding ()
182+ charset = sys .getfilesystemencoding () or locale .getpreferredencoding ()
230183 return string .decode (charset )
231184
232-
233185def 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 )
243188 return decode_fs_string (process .stdout .read ())
244189
245190def 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
262194
263195def get_nodejs_version (path ):
264- """Return version of the Nodejs installed in *path*"""
196+ """Return version of the Nodejs installed in *path*. """
265197 return exec_shell_cmd ("node -v" , path ).splitlines ()[0 ]
266198
267-
268199def get_npmjs_version (path ):
269200 """Return version of the Nodejs installed in *path*"""
270201 return exec_shell_cmd ("npm -v" , path ).splitlines ()[0 ]
271202
272-
273203def get_pandoc_version (path ):
274204 """Return version of the Pandoc executable in *path*"""
275205 return exec_shell_cmd ("pandoc -v" , path ).splitlines ()[0 ].split (" " )[- 1 ]
276206
277-
278207def 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*. """
280209 the_exe = get_python_executable (path )
281- # debug2021-09-12
282- # print(f'"{the_exe}" -c "{cmd}"', ' * ', path)
283-
284210 return exec_shell_cmd (f'"{ the_exe } " -c "{ cmd } "' , path ).splitlines ()[0 ]
285211
286-
287212def 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*. """
289214 the_exe = get_python_executable (path )
290215 exec_shell_cmd (f'{ the_exe } -m { cmd } ' , path )
291216
292-
293217def get_python_infos (path ):
294218 """Return (version, architecture) for the Python distribution located in
295219 *path*. The version number is limited to MAJOR.MINOR, the architecture is
296220 an integer: 32 or 64"""
297221 is_64 = python_query ("import sys; print(sys.maxsize > 2**32)" , path )
298222 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 )
303224 if re .match (r"([0-9]*)\.([0-9]*)" , ver ) is None :
304225 ver = None
305226 return ver , arch
@@ -446,20 +367,6 @@ def extract_archive(fname, targetdir=None, verbose=False):
446367 obj .extractall (path = targetdir )
447368 return targetdir
448369
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-
463370
464371def get_source_package_infos (fname ):
465372 """Return a tuple (name, version) of the Python source package."""
@@ -506,12 +413,7 @@ def buildflit_wininst(
506413 )
507414
508415 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 ):
515417 break
516418 else :
517419 raise RuntimeError (f"Build failed: not a pure Python package? { distdir } " )
@@ -527,12 +429,7 @@ def buildflit_wininst(
527429 return dst_fname
528430
529431
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 ):
536433 """Direct install via python -m pip !"""
537434 copy_to = str (Path (fname ).parent )
538435
0 commit comments