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
6.. versionadded:: 1.1
7"""
8import os
9import sys
10from ..installhelper import run_cmd
12_setup_py = """
13# -*- coding: utf-8 -*-
14import sys
15import os
16import warnings
17from distutils.core import setup
18from setuptools import find_packages
20#########
21# settings
22#########
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'
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]
45#######
46# data
47#######
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}
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("---------------------------------")
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"""
83_readme_rst = '''
84.. _l-README:
86README / Changes
87================
89.. image:: https://travis-ci.com/sdpython/pymyinstall.svg?branch=master
90 :target: https://app.travis-ci.com/github/sdpython/pymyinstall
91 :alt: Build status
93.. image:: https://badge.fury.io/py/pymyinstall.svg
94 :target: http://badge.fury.io/py/pymyinstall
96.. image:: http://img.shields.io/pypi/dm/pymyinstall.png
97 :alt: PYPI Package
98 :target: https://pypi.python.org/pypi/pymyinstall
100.. image:: http://img.shields.io/github/issues/sdpython/pymyinstall.png
101 :alt: GitHub Issues
102 :target: https://github.com/sdpython/pymyinstall/issues
104.. image:: https://img.shields.io/badge/license-MIT-blue.svg
105 :alt: MIT License
106 :target: http://opensource.org/licenses/MIT
109**Links:**
111* `GitHub/__NAME__ <__URL__>`_
112* `documentation <__URL__>`_
113* `Blog <http:/__NAME__/helpsphinx/blog/main_0000.html#ap-main-0>`_
114'''
116if sys.version_info[0] == 2:
117 from codecs import open
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.
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)
142 replace = dict(__AUTHOR__=author,
143 __DESCRIPTION__=description,
144 __URL__=url,
145 __DURL__=durl,
146 __VERSION__=version,
147 __SUBVERSION__=subversion,
148 __NAME__=name)
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
156 readme = os.path.join(fold, "README.rst")
157 with open(readme, "w", encoding="utf-8") as f:
158 f.write(adapt(_readme_rst))
160 setup = os.path.join(fold, "setup.py")
161 with open(setup, "w", encoding="utf-8") as f:
162 f.write(adapt(_setup_py))
164 writ = [setup, readme]
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)
172 return writ
175_setup_py_existing = """
176# -*- coding: utf-8 -*-
177import sys
178import os
179import warnings
180from distutils.core import setup
181from setuptools import find_packages
183DESCRIPTION = '''__DESCRIPTION__'''
185packages = find_packages('src', exclude='src')
186package_dir = {k: 'src/' + k.replace(".", "/") for k in packages}
187package_data = {
188__PACKDATA__
189}
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"""
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.
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
210 .. exref::
211 :title: Create a setup from installed packages
212 :lid: ex-torch-setup
214 This packages :epkg:`pandas` into a wheel from the installed
215 sources. Location of the sources can be specified too.
217 ::
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 = {}
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))
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")
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
270 mod = __import__(name)
271 if rem:
272 ind = sys.path.index(f_)
273 del sys.path[ind]
274 del sys.modules[name]
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)
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)
310 if fLOG:
311 fLOG("[create_folder_setup] add '{0}' in '{1}'".format(n, f))
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)
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)
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]