##// END OF EJS Templates
Make installation with Python 3 possible.
Thomas Kluyver -
Show More
@@ -0,0 +1,9 b''
1 import os.path
2 from setuptools import setup
3
4 from setupbase import (setup_args, find_scripts, find_packages)
5
6 setup_args['entry_points'] = find_scripts(True)
7 setup_args['packages'] = find_packages()
8
9 setup(use_2to3 = True, **setup_args)
@@ -1,363 +1,373 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 This module defines the things that are used in setup.py for building IPython
3 This module defines the things that are used in setup.py for building IPython
4
4
5 This includes:
5 This includes:
6
6
7 * The basic arguments to setup
7 * The basic arguments to setup
8 * Functions for finding things like packages, package data, etc.
8 * Functions for finding things like packages, package data, etc.
9 * A function for checking dependencies.
9 * A function for checking dependencies.
10 """
10 """
11 from __future__ import print_function
11 from __future__ import print_function
12
12
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
19
19
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import os
23 import os
24 import sys
24 import sys
25
25
26 try:
27 from configparser import ConfigParser
28 except:
26 from ConfigParser import ConfigParser
29 from ConfigParser import ConfigParser
27 from distutils.command.build_py import build_py
30 from distutils.command.build_py import build_py
28 from glob import glob
31 from glob import glob
29
32
30 from setupext import install_data_ext
33 from setupext import install_data_ext
31
34
32 #-------------------------------------------------------------------------------
35 #-------------------------------------------------------------------------------
33 # Useful globals and utility functions
36 # Useful globals and utility functions
34 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
35
38
36 # A few handy globals
39 # A few handy globals
37 isfile = os.path.isfile
40 isfile = os.path.isfile
38 pjoin = os.path.join
41 pjoin = os.path.join
39
42
40 def oscmd(s):
43 def oscmd(s):
41 print(">", s)
44 print(">", s)
42 os.system(s)
45 os.system(s)
43
46
47 try:
48 execfile
49 except NameError:
50 def execfile(fname, globs, locs=None):
51 locs = locs or globs
52 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
53
44 # A little utility we'll need below, since glob() does NOT allow you to do
54 # A little utility we'll need below, since glob() does NOT allow you to do
45 # exclusion on multiple endings!
55 # exclusion on multiple endings!
46 def file_doesnt_endwith(test,endings):
56 def file_doesnt_endwith(test,endings):
47 """Return true if test is a file and its name does NOT end with any
57 """Return true if test is a file and its name does NOT end with any
48 of the strings listed in endings."""
58 of the strings listed in endings."""
49 if not isfile(test):
59 if not isfile(test):
50 return False
60 return False
51 for e in endings:
61 for e in endings:
52 if test.endswith(e):
62 if test.endswith(e):
53 return False
63 return False
54 return True
64 return True
55
65
56 #---------------------------------------------------------------------------
66 #---------------------------------------------------------------------------
57 # Basic project information
67 # Basic project information
58 #---------------------------------------------------------------------------
68 #---------------------------------------------------------------------------
59
69
60 # release.py contains version, authors, license, url, keywords, etc.
70 # release.py contains version, authors, license, url, keywords, etc.
61 execfile(pjoin('IPython','core','release.py'))
71 execfile(pjoin('IPython','core','release.py'), globals())
62
72
63 # Create a dict with the basic information
73 # Create a dict with the basic information
64 # This dict is eventually passed to setup after additional keys are added.
74 # This dict is eventually passed to setup after additional keys are added.
65 setup_args = dict(
75 setup_args = dict(
66 name = name,
76 name = name,
67 version = version,
77 version = version,
68 description = description,
78 description = description,
69 long_description = long_description,
79 long_description = long_description,
70 author = author,
80 author = author,
71 author_email = author_email,
81 author_email = author_email,
72 url = url,
82 url = url,
73 download_url = download_url,
83 download_url = download_url,
74 license = license,
84 license = license,
75 platforms = platforms,
85 platforms = platforms,
76 keywords = keywords,
86 keywords = keywords,
77 cmdclass = {'install_data': install_data_ext},
87 cmdclass = {'install_data': install_data_ext},
78 )
88 )
79
89
80
90
81 #---------------------------------------------------------------------------
91 #---------------------------------------------------------------------------
82 # Find packages
92 # Find packages
83 #---------------------------------------------------------------------------
93 #---------------------------------------------------------------------------
84
94
85 def find_packages():
95 def find_packages():
86 """
96 """
87 Find all of IPython's packages.
97 Find all of IPython's packages.
88 """
98 """
89 excludes = ['deathrow']
99 excludes = ['deathrow']
90 packages = []
100 packages = []
91 for dir,subdirs,files in os.walk('IPython'):
101 for dir,subdirs,files in os.walk('IPython'):
92 package = dir.replace(os.path.sep, '.')
102 package = dir.replace(os.path.sep, '.')
93 if any([ package.startswith('IPython.'+exc) for exc in excludes ]):
103 if any([ package.startswith('IPython.'+exc) for exc in excludes ]):
94 # package is to be excluded (e.g. deathrow)
104 # package is to be excluded (e.g. deathrow)
95 continue
105 continue
96 if '__init__.py' not in files:
106 if '__init__.py' not in files:
97 # not a package
107 # not a package
98 continue
108 continue
99 packages.append(package)
109 packages.append(package)
100 return packages
110 return packages
101
111
102 #---------------------------------------------------------------------------
112 #---------------------------------------------------------------------------
103 # Find package data
113 # Find package data
104 #---------------------------------------------------------------------------
114 #---------------------------------------------------------------------------
105
115
106 def find_package_data():
116 def find_package_data():
107 """
117 """
108 Find IPython's package_data.
118 Find IPython's package_data.
109 """
119 """
110 # This is not enough for these things to appear in an sdist.
120 # This is not enough for these things to appear in an sdist.
111 # We need to muck with the MANIFEST to get this to work
121 # We need to muck with the MANIFEST to get this to work
112
122
113 # walk notebook resources:
123 # walk notebook resources:
114 cwd = os.getcwd()
124 cwd = os.getcwd()
115 os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook'))
125 os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook'))
116 static_walk = list(os.walk('static'))
126 static_walk = list(os.walk('static'))
117 os.chdir(cwd)
127 os.chdir(cwd)
118 static_data = []
128 static_data = []
119 for parent, dirs, files in static_walk:
129 for parent, dirs, files in static_walk:
120 for f in files:
130 for f in files:
121 static_data.append(os.path.join(parent, f))
131 static_data.append(os.path.join(parent, f))
122
132
123 package_data = {
133 package_data = {
124 'IPython.config.profile' : ['README', '*/*.py'],
134 'IPython.config.profile' : ['README', '*/*.py'],
125 'IPython.testing' : ['*.txt'],
135 'IPython.testing' : ['*.txt'],
126 'IPython.frontend.html.notebook' : ['templates/*']+static_data
136 'IPython.frontend.html.notebook' : ['templates/*']+static_data
127 }
137 }
128 return package_data
138 return package_data
129
139
130
140
131 #---------------------------------------------------------------------------
141 #---------------------------------------------------------------------------
132 # Find data files
142 # Find data files
133 #---------------------------------------------------------------------------
143 #---------------------------------------------------------------------------
134
144
135 def make_dir_struct(tag,base,out_base):
145 def make_dir_struct(tag,base,out_base):
136 """Make the directory structure of all files below a starting dir.
146 """Make the directory structure of all files below a starting dir.
137
147
138 This is just a convenience routine to help build a nested directory
148 This is just a convenience routine to help build a nested directory
139 hierarchy because distutils is too stupid to do this by itself.
149 hierarchy because distutils is too stupid to do this by itself.
140
150
141 XXX - this needs a proper docstring!
151 XXX - this needs a proper docstring!
142 """
152 """
143
153
144 # we'll use these a lot below
154 # we'll use these a lot below
145 lbase = len(base)
155 lbase = len(base)
146 pathsep = os.path.sep
156 pathsep = os.path.sep
147 lpathsep = len(pathsep)
157 lpathsep = len(pathsep)
148
158
149 out = []
159 out = []
150 for (dirpath,dirnames,filenames) in os.walk(base):
160 for (dirpath,dirnames,filenames) in os.walk(base):
151 # we need to strip out the dirpath from the base to map it to the
161 # we need to strip out the dirpath from the base to map it to the
152 # output (installation) path. This requires possibly stripping the
162 # output (installation) path. This requires possibly stripping the
153 # path separator, because otherwise pjoin will not work correctly
163 # path separator, because otherwise pjoin will not work correctly
154 # (pjoin('foo/','/bar') returns '/bar').
164 # (pjoin('foo/','/bar') returns '/bar').
155
165
156 dp_eff = dirpath[lbase:]
166 dp_eff = dirpath[lbase:]
157 if dp_eff.startswith(pathsep):
167 if dp_eff.startswith(pathsep):
158 dp_eff = dp_eff[lpathsep:]
168 dp_eff = dp_eff[lpathsep:]
159 # The output path must be anchored at the out_base marker
169 # The output path must be anchored at the out_base marker
160 out_path = pjoin(out_base,dp_eff)
170 out_path = pjoin(out_base,dp_eff)
161 # Now we can generate the final filenames. Since os.walk only produces
171 # Now we can generate the final filenames. Since os.walk only produces
162 # filenames, we must join back with the dirpath to get full valid file
172 # filenames, we must join back with the dirpath to get full valid file
163 # paths:
173 # paths:
164 pfiles = [pjoin(dirpath,f) for f in filenames]
174 pfiles = [pjoin(dirpath,f) for f in filenames]
165 # Finally, generate the entry we need, which is a pari of (output
175 # Finally, generate the entry we need, which is a pari of (output
166 # path, files) for use as a data_files parameter in install_data.
176 # path, files) for use as a data_files parameter in install_data.
167 out.append((out_path, pfiles))
177 out.append((out_path, pfiles))
168
178
169 return out
179 return out
170
180
171
181
172 def find_data_files():
182 def find_data_files():
173 """
183 """
174 Find IPython's data_files.
184 Find IPython's data_files.
175
185
176 Most of these are docs.
186 Most of these are docs.
177 """
187 """
178
188
179 docdirbase = pjoin('share', 'doc', 'ipython')
189 docdirbase = pjoin('share', 'doc', 'ipython')
180 manpagebase = pjoin('share', 'man', 'man1')
190 manpagebase = pjoin('share', 'man', 'man1')
181
191
182 # Simple file lists can be made by hand
192 # Simple file lists can be made by hand
183 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
193 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
184 if not manpages:
194 if not manpages:
185 # When running from a source tree, the manpages aren't gzipped
195 # When running from a source tree, the manpages aren't gzipped
186 manpages = filter(isfile, glob(pjoin('docs','man','*.1')))
196 manpages = filter(isfile, glob(pjoin('docs','man','*.1')))
187 igridhelpfiles = filter(isfile,
197 igridhelpfiles = filter(isfile,
188 glob(pjoin('IPython','extensions','igrid_help.*')))
198 glob(pjoin('IPython','extensions','igrid_help.*')))
189
199
190 # For nested structures, use the utility above
200 # For nested structures, use the utility above
191 example_files = make_dir_struct(
201 example_files = make_dir_struct(
192 'data',
202 'data',
193 pjoin('docs','examples'),
203 pjoin('docs','examples'),
194 pjoin(docdirbase,'examples')
204 pjoin(docdirbase,'examples')
195 )
205 )
196 manual_files = make_dir_struct(
206 manual_files = make_dir_struct(
197 'data',
207 'data',
198 pjoin('docs','html'),
208 pjoin('docs','html'),
199 pjoin(docdirbase,'manual')
209 pjoin(docdirbase,'manual')
200 )
210 )
201
211
202 # And assemble the entire output list
212 # And assemble the entire output list
203 data_files = [ (manpagebase, manpages),
213 data_files = [ (manpagebase, manpages),
204 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
214 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
205 ] + manual_files + example_files
215 ] + manual_files + example_files
206
216
207 return data_files
217 return data_files
208
218
209
219
210 def make_man_update_target(manpage):
220 def make_man_update_target(manpage):
211 """Return a target_update-compliant tuple for the given manpage.
221 """Return a target_update-compliant tuple for the given manpage.
212
222
213 Parameters
223 Parameters
214 ----------
224 ----------
215 manpage : string
225 manpage : string
216 Name of the manpage, must include the section number (trailing number).
226 Name of the manpage, must include the section number (trailing number).
217
227
218 Example
228 Example
219 -------
229 -------
220
230
221 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
231 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
222 ('docs/man/ipython.1.gz',
232 ('docs/man/ipython.1.gz',
223 ['docs/man/ipython.1'],
233 ['docs/man/ipython.1'],
224 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
234 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
225 """
235 """
226 man_dir = pjoin('docs', 'man')
236 man_dir = pjoin('docs', 'man')
227 manpage_gz = manpage + '.gz'
237 manpage_gz = manpage + '.gz'
228 manpath = pjoin(man_dir, manpage)
238 manpath = pjoin(man_dir, manpage)
229 manpath_gz = pjoin(man_dir, manpage_gz)
239 manpath_gz = pjoin(man_dir, manpage_gz)
230 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
240 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
231 locals() )
241 locals() )
232 return (manpath_gz, [manpath], gz_cmd)
242 return (manpath_gz, [manpath], gz_cmd)
233
243
234 #---------------------------------------------------------------------------
244 #---------------------------------------------------------------------------
235 # Find scripts
245 # Find scripts
236 #---------------------------------------------------------------------------
246 #---------------------------------------------------------------------------
237
247
238 def find_scripts(entry_points=False):
248 def find_scripts(entry_points=False):
239 """Find IPython's scripts.
249 """Find IPython's scripts.
240
250
241 if entry_points is True:
251 if entry_points is True:
242 return setuptools entry_point-style definitions
252 return setuptools entry_point-style definitions
243 else:
253 else:
244 return file paths of plain scripts [default]
254 return file paths of plain scripts [default]
245 """
255 """
246 if entry_points:
256 if entry_points:
247 console_scripts = [
257 console_scripts = [
248 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
258 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
249 'pycolor = IPython.utils.PyColorize:main',
259 'pycolor = IPython.utils.PyColorize:main',
250 'ipcontroller = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
260 'ipcontroller = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
251 'ipengine = IPython.parallel.apps.ipengineapp:launch_new_instance',
261 'ipengine = IPython.parallel.apps.ipengineapp:launch_new_instance',
252 'iplogger = IPython.parallel.apps.iploggerapp:launch_new_instance',
262 'iplogger = IPython.parallel.apps.iploggerapp:launch_new_instance',
253 'ipcluster = IPython.parallel.apps.ipclusterapp:launch_new_instance',
263 'ipcluster = IPython.parallel.apps.ipclusterapp:launch_new_instance',
254 'iptest = IPython.testing.iptest:main',
264 'iptest = IPython.testing.iptest:main',
255 'irunner = IPython.lib.irunner:main'
265 'irunner = IPython.lib.irunner:main'
256 ]
266 ]
257 gui_scripts = [
267 gui_scripts = [
258 'ipython-qtconsole = IPython.frontend.qt.console.qtconsoleapp:main',
268 'ipython-qtconsole = IPython.frontend.qt.console.qtconsoleapp:main',
259 ]
269 ]
260 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
270 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
261 else:
271 else:
262 parallel_scripts = pjoin('IPython','parallel','scripts')
272 parallel_scripts = pjoin('IPython','parallel','scripts')
263 main_scripts = pjoin('IPython','scripts')
273 main_scripts = pjoin('IPython','scripts')
264 scripts = [
274 scripts = [
265 pjoin(parallel_scripts, 'ipengine'),
275 pjoin(parallel_scripts, 'ipengine'),
266 pjoin(parallel_scripts, 'ipcontroller'),
276 pjoin(parallel_scripts, 'ipcontroller'),
267 pjoin(parallel_scripts, 'ipcluster'),
277 pjoin(parallel_scripts, 'ipcluster'),
268 pjoin(parallel_scripts, 'iplogger'),
278 pjoin(parallel_scripts, 'iplogger'),
269 pjoin(main_scripts, 'ipython'),
279 pjoin(main_scripts, 'ipython'),
270 pjoin(main_scripts, 'pycolor'),
280 pjoin(main_scripts, 'pycolor'),
271 pjoin(main_scripts, 'irunner'),
281 pjoin(main_scripts, 'irunner'),
272 pjoin(main_scripts, 'iptest')
282 pjoin(main_scripts, 'iptest')
273 ]
283 ]
274 return scripts
284 return scripts
275
285
276 #---------------------------------------------------------------------------
286 #---------------------------------------------------------------------------
277 # Verify all dependencies
287 # Verify all dependencies
278 #---------------------------------------------------------------------------
288 #---------------------------------------------------------------------------
279
289
280 def check_for_dependencies():
290 def check_for_dependencies():
281 """Check for IPython's dependencies.
291 """Check for IPython's dependencies.
282
292
283 This function should NOT be called if running under setuptools!
293 This function should NOT be called if running under setuptools!
284 """
294 """
285 from setupext.setupext import (
295 from setupext.setupext import (
286 print_line, print_raw, print_status,
296 print_line, print_raw, print_status,
287 check_for_sphinx, check_for_pygments,
297 check_for_sphinx, check_for_pygments,
288 check_for_nose, check_for_pexpect,
298 check_for_nose, check_for_pexpect,
289 check_for_pyzmq, check_for_readline
299 check_for_pyzmq, check_for_readline
290 )
300 )
291 print_line()
301 print_line()
292 print_raw("BUILDING IPYTHON")
302 print_raw("BUILDING IPYTHON")
293 print_status('python', sys.version)
303 print_status('python', sys.version)
294 print_status('platform', sys.platform)
304 print_status('platform', sys.platform)
295 if sys.platform == 'win32':
305 if sys.platform == 'win32':
296 print_status('Windows version', sys.getwindowsversion())
306 print_status('Windows version', sys.getwindowsversion())
297
307
298 print_raw("")
308 print_raw("")
299 print_raw("OPTIONAL DEPENDENCIES")
309 print_raw("OPTIONAL DEPENDENCIES")
300
310
301 check_for_sphinx()
311 check_for_sphinx()
302 check_for_pygments()
312 check_for_pygments()
303 check_for_nose()
313 check_for_nose()
304 check_for_pexpect()
314 check_for_pexpect()
305 check_for_pyzmq()
315 check_for_pyzmq()
306 check_for_readline()
316 check_for_readline()
307
317
308 def record_commit_info(pkg_dir, build_cmd=build_py):
318 def record_commit_info(pkg_dir, build_cmd=build_py):
309 """ Return extended build command class for recording commit
319 """ Return extended build command class for recording commit
310
320
311 The extended command tries to run git to find the current commit, getting
321 The extended command tries to run git to find the current commit, getting
312 the empty string if it fails. It then writes the commit hash into a file
322 the empty string if it fails. It then writes the commit hash into a file
313 in the `pkg_dir` path, named ``.git_commit_info.ini``.
323 in the `pkg_dir` path, named ``.git_commit_info.ini``.
314
324
315 In due course this information can be used by the package after it is
325 In due course this information can be used by the package after it is
316 installed, to tell you what commit it was installed from if known.
326 installed, to tell you what commit it was installed from if known.
317
327
318 To make use of this system, you need a package with a .git_commit_info.ini
328 To make use of this system, you need a package with a .git_commit_info.ini
319 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
329 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
320 this::
330 this::
321
331
322 # This is an ini file that may contain information about the code state
332 # This is an ini file that may contain information about the code state
323 [commit hash]
333 [commit hash]
324 # The line below may contain a valid hash if it has been substituted
334 # The line below may contain a valid hash if it has been substituted
325 # during 'git archive'
335 # during 'git archive'
326 archive_subst_hash=$Format:%h$
336 archive_subst_hash=$Format:%h$
327 # This line may be modified by the install process
337 # This line may be modified by the install process
328 install_hash=
338 install_hash=
329
339
330 The .git_commit_info file above is also designed to be used with git
340 The .git_commit_info file above is also designed to be used with git
331 substitution - so you probably also want a ``.gitattributes`` file in the
341 substitution - so you probably also want a ``.gitattributes`` file in the
332 root directory of your working tree that contains something like this::
342 root directory of your working tree that contains something like this::
333
343
334 myproject/.git_commit_info.ini export-subst
344 myproject/.git_commit_info.ini export-subst
335
345
336 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
346 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
337 archive`` - useful in case someone makes such an archive - for example with
347 archive`` - useful in case someone makes such an archive - for example with
338 via the github 'download source' button.
348 via the github 'download source' button.
339
349
340 Although all the above will work as is, you might consider having something
350 Although all the above will work as is, you might consider having something
341 like a ``get_info()`` function in your package to display the commit
351 like a ``get_info()`` function in your package to display the commit
342 information at the terminal. See the ``pkg_info.py`` module in the nipy
352 information at the terminal. See the ``pkg_info.py`` module in the nipy
343 package for an example.
353 package for an example.
344 """
354 """
345 class MyBuildPy(build_cmd):
355 class MyBuildPy(build_cmd):
346 ''' Subclass to write commit data into installation tree '''
356 ''' Subclass to write commit data into installation tree '''
347 def run(self):
357 def run(self):
348 build_py.run(self)
358 build_py.run(self)
349 import subprocess
359 import subprocess
350 proc = subprocess.Popen('git rev-parse --short HEAD',
360 proc = subprocess.Popen('git rev-parse --short HEAD',
351 stdout=subprocess.PIPE,
361 stdout=subprocess.PIPE,
352 stderr=subprocess.PIPE,
362 stderr=subprocess.PIPE,
353 shell=True)
363 shell=True)
354 repo_commit, _ = proc.communicate()
364 repo_commit, _ = proc.communicate()
355 # We write the installation commit even if it's empty
365 # We write the installation commit even if it's empty
356 cfg_parser = ConfigParser()
366 cfg_parser = ConfigParser()
357 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
367 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
358 cfg_parser.set('commit hash', 'install_hash', repo_commit)
368 cfg_parser.set('commit hash', 'install_hash', repo_commit)
359 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
369 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
360 out_file = open(out_pth, 'wt')
370 out_file = open(out_pth, 'wt')
361 cfg_parser.write(out_file)
371 cfg_parser.write(out_file)
362 out_file.close()
372 out_file.close()
363 return MyBuildPy
373 return MyBuildPy
@@ -1,3 +1,3 b''
1 # load extended setup modules for distuils
1 # load extended setup modules for distuils
2
2
3 from install_data_ext import install_data_ext
3 from .install_data_ext import install_data_ext
General Comments 0
You need to be logged in to leave comments. Login now