Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -*- coding: utf-8 -*- 

2""" 

3@file 

4@brief Functions to help creating a setup 

5 

6.. versionadded:: 1.1 

7""" 

8import os 

9import sys 

10from ..installhelper import run_cmd 

11 

12_setup_py = """ 

13# -*- coding: utf-8 -*- 

14import sys 

15import os 

16import warnings 

17from distutils.core import setup 

18from setuptools import find_packages 

19 

20######### 

21# settings 

22######### 

23 

24 

25project_var_name = "__NAME__" 

26sversion = "__VERSION__" 

27subversion = "__SUBVERSION__" 

28versionPython = "%s.%s" % (sys.version_info.major, sys.version_info.minor) 

29path = "Lib/site-packages/" + project_var_name 

30readme = 'README.rst' 

31 

32 

33KEYWORDS = project_var_name 

34DESCRIPTION = '''__DESCRIPTION___''' 

35CLASSIFIERS = [ 

36 'Programming Language :: Python :: 3', 

37 'Intended Audience :: Developers', 

38 'Topic :: Scientific/Engineering', 

39 'Topic :: Education', 

40 'License :: OSI Approved :: MIT License', 

41 'Development Status :: 5 - Production/Stable' 

42] 

43 

44 

45####### 

46# data 

47####### 

48 

49packages = find_packages('src', exclude='src') 

50package_dir = {k: "src/" + k.replace(".", "/") for k in packages} 

51package_data = { 

52 project_var_name : ["*.pyd", "*.dll", "*.so" ], 

53} 

54 

55 

56def verbose(): 

57 print("---------------------------------") 

58 print("package_dir =", package_dir) 

59 print("packages =", packages) 

60 print("package_data=", package_data) 

61 print("current =", os.path.abspath(os.getcwd())) 

62 print("---------------------------------") 

63 

64 

65setup( 

66 name=project_var_name, 

67 version='%s%s' % (sversion, subversion), 

68 author='__AUTHOR__', 

69 author_email='__EMAIL__', 

70 url="__URL__", 

71 download_url="__DURL__", 

72 description=DESCRIPTION, 

73 long_description=long_description, 

74 keywords=KEYWORDS, 

75 classifiers=CLASSIFIERS, 

76 packages=packages, 

77 package_dir=package_dir, 

78 package_data=package_data, 

79 install_requires=[] 

80) 

81""" 

82 

83_readme_rst = ''' 

84.. _l-README: 

85 

86README / Changes 

87================ 

88 

89.. image:: https://travis-ci.org/sdpython/pymyinstall.svg?branch=master 

90 :target: https://travis-ci.org/sdpython/pymyinstall 

91 :alt: Build status 

92 

93.. image:: https://badge.fury.io/py/pymyinstall.svg 

94 :target: http://badge.fury.io/py/pymyinstall 

95 

96.. image:: http://img.shields.io/pypi/dm/pymyinstall.png 

97 :alt: PYPI Package 

98 :target: https://pypi.python.org/pypi/pymyinstall 

99 

100.. image:: http://img.shields.io/github/issues/sdpython/pymyinstall.png 

101 :alt: GitHub Issues 

102 :target: https://github.com/sdpython/pymyinstall/issues 

103 

104.. image:: https://img.shields.io/badge/license-MIT-blue.svg 

105 :alt: MIT License 

106 :target: http://opensource.org/licenses/MIT 

107 

108 

109**Links:** 

110 

111* `GitHub/__NAME__ <__URL__>`_ 

112* `documentation <__URL__>`_ 

113* `Blog <http:/__NAME__/helpsphinx/blog/main_0000.html#ap-main-0>`_ 

114''' 

115 

116if sys.version_info[0] == 2: 

117 from codecs import open 

118 

119 

120def create_empty_folder_setup(fold, name, author=None, description=None, url=None, durl=None, version="0.1", 

121 subversion="0"): 

122 """ 

123 Creates a quick empty shell for a new project. 

124 

125 @param fold location 

126 @param name name of the project 

127 @param author author 

128 @param description description 

129 @param url url for the documentation 

130 @param durl url to download it 

131 @param version version 

132 @param subversion third part of the version number 

133 @return list of created files 

134 """ 

135 src = os.path.join(fold, "src") 

136 mod = os.path.join(src, name) 

137 create = [fold, src, mod] 

138 for f in create: 

139 if not os.path.exists(f): 

140 os.makedirs(f) 

141 

142 replace = dict(__AUTHOR__=author, 

143 __DESCRIPTION__=description, 

144 __URL__=url, 

145 __DURL__=durl, 

146 __VERSION__=version, 

147 __SUBVERSION__=subversion, 

148 __NAME__=name) 

149 

150 def adapt(content): 

151 for k, v in replace.items(): 

152 if v is not None: 

153 content = content.replace(k, v) 

154 return content 

155 

156 readme = os.path.join(fold, "README.rst") 

157 with open(readme, "w", encoding="utf-8") as f: 

158 f.write(adapt(_readme_rst)) 

159 

160 setup = os.path.join(fold, "setup.py") 

161 with open(setup, "w", encoding="utf-8") as f: 

162 f.write(adapt(_setup_py)) 

163 

164 writ = [setup, readme] 

165 

166 if sys.platform.startswith("win"): 

167 bat = os.path.join(fold, "wheel.bat") 

168 with open(bat, "w") as f: 

169 f.write("{0} setup.py bdist_wheel".format(sys.executable)) 

170 writ.append(bat) 

171 

172 return writ 

173 

174 

175_setup_py_existing = """ 

176# -*- coding: utf-8 -*- 

177import sys 

178import os 

179import warnings 

180from distutils.core import setup 

181from setuptools import find_packages 

182 

183DESCRIPTION = '''__DESCRIPTION__''' 

184 

185packages = find_packages('src', exclude='src') 

186package_dir = {k: 'src/' + k.replace(".", "/") for k in packages} 

187package_data = { 

188__PACKDATA__ 

189} 

190 

191setup(name="__FOLDER__", version="__VERSION__", 

192 description=DESCRIPTION, long_description=DESCRIPTION, 

193 packages=packages, package_dir=package_dir, 

194 package_data=package_data 

195) 

196""" 

197 

198 

199def create_folder_setup(fold, wheel=True, output_path=None, fLOG=None, version=None, description=None): 

200 """ 

201 Creates a quick setup for an existing or installed projects. 

202 

203 @param fold folder or module (must be imported first) 

204 @param wheel run the setup to build the wheel 

205 @param output_path copies everything here it not None 

206 @param version to overwrite version 

207 @param description to overwrite description 

208 @return list of created files 

209 

210 .. exref:: 

211 :title: Create a setup from installed packages 

212 :lid: ex-torch-setup 

213 

214 This packages :epkg:`pandas` into a wheel from the installed 

215 sources. Location of the sources can be specified too. 

216 

217 :: 

218 

219 from pymyinstall.setuphelper import create_folder_setup 

220 create_folder_setup('pandas', fLOG=print, output_path='.') 

221 """ 

222 if fLOG: 

223 fLOG("[create_folder_setup] process '{0}'".format(fold)) 

224 if not os.path.exists(fold): 

225 if fold not in sys.modules: 

226 raise ValueError("Unable to find module '{0}'".format(fold)) 

227 mod = sys.modules[fold] 

228 version = mod.__version__ if hasattr( 

229 mod, '__version__') else mod.VERSION 

230 info = dict(__VERSION__=version, 

231 __DESCRIPTION__=mod.__doc__, 

232 __FOLDER__=fold) 

233 fold = os.path.dirname(mod.__file__) 

234 else: 

235 info = dict() 

236 

237 # Module name 

238 name = os.path.split(fold)[-1] 

239 if fLOG: 

240 fLOG("[create_folder_setup] name='{0}'".format(name)) 

241 fLOG("[create_folder_setup] fold='{0}'".format(fold)) 

242 

243 if output_path is not None: 

244 # Copies everything. 

245 if fLOG: 

246 fLOG("[create_folder_setup] copy to '{0}'".format(output_path)) 

247 from pyquickhelper.filehelper import synchronize_folder 

248 dest = os.path.join(output_path, 'src', name) 

249 if not os.path.exists(dest): 

250 os.makedirs(dest) 

251 # , filter_copy=lambda name: '__pycache__' not in name) 

252 synchronize_folder(fold, dest) 

253 fold = dest 

254 fold_ = output_path 

255 else: 

256 raise ValueError("output_path must be specified") 

257 

258 if len(info) == 0 and version is None: 

259 # Import the module. 

260 if name in sys.modules: 

261 del sys.modules[name] 

262 f = os.path.normpath(os.path.abspath(fold)) 

263 f_ = os.path.normpath(os.path.join(fold, '..')) 

264 if fold_ not in sys.path: 

265 sys.path.insert(0, f_) 

266 rem = True 

267 else: 

268 rem = False 

269 

270 mod = __import__(name) 

271 if rem: 

272 ind = sys.path.index(f_) 

273 del sys.path[ind] 

274 del sys.modules[name] 

275 

276 info = dict(__VERSION__=mod.__version__, 

277 __DESCRIPTION__=description or mod.__doc__, 

278 __FOLDER__=name) 

279 else: 

280 info = dict(__VERSION__=version, 

281 __DESCRIPTION__=description, 

282 __FOLDER__=name) 

283 

284 # Package data 

285 from pyquickhelper.filehelper import explore_folder 

286 _, files = explore_folder(fold, fullname=False) 

287 pack = {} 

288 for f in files: 

289 ff = os.path.split(f)[0] 

290 f = os.path.relpath(f, fold) 

291 if '__pycache__' in f: 

292 continue 

293 ext = os.path.splitext(f)[-1] 

294 if ext in {'.py', '.pyc'}: # , '.pyd'}: 

295 continue 

296 f, n = os.path.split(f) 

297 f = f .replace("\\", "/").replace("/", ".") 

298 if f not in pack: 

299 pack[f] = [] 

300 init = os.path.join(ff, "__init__.py") 

301 while not os.path.exists(init): 

302 if fLOG: 

303 fLOG("[create_folder_setup] add '{0}'".format(init)) 

304 with open(init, "w") as fi: 

305 fi.write('# added for additional files') 

306 ff = os.path.split(ff)[0] 

307 init = os.path.join(ff, "__init__.py") 

308 pack[f].append(n) 

309 

310 if fLOG: 

311 fLOG("[create_folder_setup] add '{0}' in '{1}'".format(n, f)) 

312 

313 rows = [" '{2}{3}{0}': {1},".format( 

314 k, v, name, '.' if k else '') for k, v in pack.items()] 

315 info['__PACKDATA__'] = "\n".join(rows) 

316 

317 # Writes setup.py 

318 script = _setup_py_existing 

319 for k, v in info.items(): 

320 if v is not None: 

321 script = script.replace(k, v) 

322 setup = os.path.join(fold_, 'setup.py') 

323 if fLOG: 

324 fLOG("[create_folder_setup] write='{0}'".format(setup)) 

325 with open(setup, "w") as f: 

326 f.write(script) 

327 

328 if wheel: 

329 cmd = '"{0}" -u setup.py bdist_wheel'.format( 

330 sys.executable.replace("w.exe", ".exe")) 

331 out, err = run_cmd(cmd, wait=True, fLOG=fLOG, change_path=fold_) 

332 if fLOG: 

333 fLOG('[create_folder_setup] OUT --------------\n' + out) 

334 fLOG('[create_folder_setup] ERR --------------\n' + err) 

335 return [setup] 

336 else: 

337 return [setup]