##// END OF EJS Templates
rename ipythonqt to qtconsoleapp...
MinRK -
Show More
1 NO CONTENT: file renamed from IPython/frontend/qt/console/ipythonqt.py to IPython/frontend/qt/console/qtconsoleapp.py
NO CONTENT: file renamed from IPython/frontend/qt/console/ipythonqt.py to IPython/frontend/qt/console/qtconsoleapp.py
@@ -1,357 +1,356 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.newapplication.Application` object for the command
4 The :class:`~IPython.core.newapplication.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6
6
7 Authors
7 Authors
8 -------
8 -------
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Min Ragan-Kelley
12 * Min Ragan-Kelley
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2010 The IPython Development Team
16 # Copyright (C) 2008-2010 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 from __future__ import absolute_import
26 from __future__ import absolute_import
27
27
28 import logging
28 import logging
29 import os
29 import os
30 import sys
30 import sys
31
31
32 from IPython.config.loader import (
32 from IPython.config.loader import (
33 Config, PyFileConfigLoader
33 Config, PyFileConfigLoader
34 )
34 )
35 from IPython.config.application import boolean_flag
35 from IPython.config.application import boolean_flag
36 from IPython.core import release
36 from IPython.core import release
37 from IPython.core import usage
37 from IPython.core import usage
38 from IPython.core.crashhandler import CrashHandler
38 from IPython.core.crashhandler import CrashHandler
39 from IPython.core.formatters import PlainTextFormatter
39 from IPython.core.formatters import PlainTextFormatter
40 from IPython.core.newapplication import (
40 from IPython.core.newapplication import (
41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
42 )
42 )
43 from IPython.core.shellapp import (
43 from IPython.core.shellapp import (
44 InteractiveShellApp, shell_flags, shell_aliases
44 InteractiveShellApp, shell_flags, shell_aliases
45 )
45 )
46 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
46 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
47 from IPython.lib import inputhook
47 from IPython.lib import inputhook
48 from IPython.utils.path import get_ipython_dir, check_for_old_config
48 from IPython.utils.path import get_ipython_dir, check_for_old_config
49 from IPython.utils.traitlets import (
49 from IPython.utils.traitlets import (
50 Bool, Dict, CaselessStrEnum
50 Bool, Dict, CaselessStrEnum
51 )
51 )
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Globals, utilities and helpers
54 # Globals, utilities and helpers
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 #: The default config file name for this application.
57 #: The default config file name for this application.
58 default_config_file_name = u'ipython_config.py'
58 default_config_file_name = u'ipython_config.py'
59
59
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Crash handler for this application
62 # Crash handler for this application
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65 _message_template = """\
65 _message_template = """\
66 Oops, $self.app_name crashed. We do our best to make it stable, but...
66 Oops, $self.app_name crashed. We do our best to make it stable, but...
67
67
68 A crash report was automatically generated with the following information:
68 A crash report was automatically generated with the following information:
69 - A verbatim copy of the crash traceback.
69 - A verbatim copy of the crash traceback.
70 - A copy of your input history during this session.
70 - A copy of your input history during this session.
71 - Data on your current $self.app_name configuration.
71 - Data on your current $self.app_name configuration.
72
72
73 It was left in the file named:
73 It was left in the file named:
74 \t'$self.crash_report_fname'
74 \t'$self.crash_report_fname'
75 If you can email this file to the developers, the information in it will help
75 If you can email this file to the developers, the information in it will help
76 them in understanding and correcting the problem.
76 them in understanding and correcting the problem.
77
77
78 You can mail it to: $self.contact_name at $self.contact_email
78 You can mail it to: $self.contact_name at $self.contact_email
79 with the subject '$self.app_name Crash Report'.
79 with the subject '$self.app_name Crash Report'.
80
80
81 If you want to do it now, the following command will work (under Unix):
81 If you want to do it now, the following command will work (under Unix):
82 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
82 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
83
83
84 To ensure accurate tracking of this issue, please file a report about it at:
84 To ensure accurate tracking of this issue, please file a report about it at:
85 $self.bug_tracker
85 $self.bug_tracker
86 """
86 """
87
87
88 class IPAppCrashHandler(CrashHandler):
88 class IPAppCrashHandler(CrashHandler):
89 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
89 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
90
90
91 message_template = _message_template
91 message_template = _message_template
92
92
93 def __init__(self, app):
93 def __init__(self, app):
94 contact_name = release.authors['Fernando'][0]
94 contact_name = release.authors['Fernando'][0]
95 contact_email = release.authors['Fernando'][1]
95 contact_email = release.authors['Fernando'][1]
96 bug_tracker = 'http://github.com/ipython/ipython/issues'
96 bug_tracker = 'http://github.com/ipython/ipython/issues'
97 super(IPAppCrashHandler,self).__init__(
97 super(IPAppCrashHandler,self).__init__(
98 app, contact_name, contact_email, bug_tracker
98 app, contact_name, contact_email, bug_tracker
99 )
99 )
100
100
101 def make_report(self,traceback):
101 def make_report(self,traceback):
102 """Return a string containing a crash report."""
102 """Return a string containing a crash report."""
103
103
104 sec_sep = self.section_sep
104 sec_sep = self.section_sep
105 # Start with parent report
105 # Start with parent report
106 report = [super(IPAppCrashHandler, self).make_report(traceback)]
106 report = [super(IPAppCrashHandler, self).make_report(traceback)]
107 # Add interactive-specific info we may have
107 # Add interactive-specific info we may have
108 rpt_add = report.append
108 rpt_add = report.append
109 try:
109 try:
110 rpt_add(sec_sep+"History of session input:")
110 rpt_add(sec_sep+"History of session input:")
111 for line in self.app.shell.user_ns['_ih']:
111 for line in self.app.shell.user_ns['_ih']:
112 rpt_add(line)
112 rpt_add(line)
113 rpt_add('\n*** Last line of input (may not be in above history):\n')
113 rpt_add('\n*** Last line of input (may not be in above history):\n')
114 rpt_add(self.app.shell._last_input_line+'\n')
114 rpt_add(self.app.shell._last_input_line+'\n')
115 except:
115 except:
116 pass
116 pass
117
117
118 return ''.join(report)
118 return ''.join(report)
119
119
120 #-----------------------------------------------------------------------------
120 #-----------------------------------------------------------------------------
121 # Aliases and Flags
121 # Aliases and Flags
122 #-----------------------------------------------------------------------------
122 #-----------------------------------------------------------------------------
123 flags = dict(base_flags)
123 flags = dict(base_flags)
124 flags.update(shell_flags)
124 flags.update(shell_flags)
125 addflag = lambda *args: flags.update(boolean_flag(*args))
125 addflag = lambda *args: flags.update(boolean_flag(*args))
126 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
126 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
127 'Turn on auto editing of files with syntax errors.',
127 'Turn on auto editing of files with syntax errors.',
128 'Turn off auto editing of files with syntax errors.'
128 'Turn off auto editing of files with syntax errors.'
129 )
129 )
130 addflag('banner', 'TerminalIPythonApp.display_banner',
130 addflag('banner', 'TerminalIPythonApp.display_banner',
131 "Display a banner upon starting IPython.",
131 "Display a banner upon starting IPython.",
132 "Don't display a banner upon starting IPython."
132 "Don't display a banner upon starting IPython."
133 )
133 )
134 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
134 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
135 """Set to confirm when you try to exit IPython with an EOF (Control-D
135 """Set to confirm when you try to exit IPython with an EOF (Control-D
136 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
136 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
137 you can force a direct exit without any confirmation.""",
137 you can force a direct exit without any confirmation.""",
138 "Don't prompt the user when exiting."
138 "Don't prompt the user when exiting."
139 )
139 )
140 addflag('term-title', 'TerminalInteractiveShell.term_title',
140 addflag('term-title', 'TerminalInteractiveShell.term_title',
141 "Enable auto setting the terminal title.",
141 "Enable auto setting the terminal title.",
142 "Disable auto setting the terminal title."
142 "Disable auto setting the terminal title."
143 )
143 )
144 classic_config = Config()
144 classic_config = Config()
145 classic_config.InteractiveShell.cache_size = 0
145 classic_config.InteractiveShell.cache_size = 0
146 classic_config.PlainTextFormatter.pprint = False
146 classic_config.PlainTextFormatter.pprint = False
147 classic_config.InteractiveShell.prompt_in1 = '>>> '
147 classic_config.InteractiveShell.prompt_in1 = '>>> '
148 classic_config.InteractiveShell.prompt_in2 = '... '
148 classic_config.InteractiveShell.prompt_in2 = '... '
149 classic_config.InteractiveShell.prompt_out = ''
149 classic_config.InteractiveShell.prompt_out = ''
150 classic_config.InteractiveShell.separate_in = ''
150 classic_config.InteractiveShell.separate_in = ''
151 classic_config.InteractiveShell.separate_out = ''
151 classic_config.InteractiveShell.separate_out = ''
152 classic_config.InteractiveShell.separate_out2 = ''
152 classic_config.InteractiveShell.separate_out2 = ''
153 classic_config.InteractiveShell.colors = 'NoColor'
153 classic_config.InteractiveShell.colors = 'NoColor'
154 classic_config.InteractiveShell.xmode = 'Plain'
154 classic_config.InteractiveShell.xmode = 'Plain'
155
155
156 flags['classic']=(
156 flags['classic']=(
157 classic_config,
157 classic_config,
158 "Gives IPython a similar feel to the classic Python prompt."
158 "Gives IPython a similar feel to the classic Python prompt."
159 )
159 )
160 # # log doesn't make so much sense this way anymore
160 # # log doesn't make so much sense this way anymore
161 # paa('--log','-l',
161 # paa('--log','-l',
162 # action='store_true', dest='InteractiveShell.logstart',
162 # action='store_true', dest='InteractiveShell.logstart',
163 # help="Start logging to the default log file (./ipython_log.py).")
163 # help="Start logging to the default log file (./ipython_log.py).")
164 #
164 #
165 # # quick is harder to implement
165 # # quick is harder to implement
166 flags['quick']=(
166 flags['quick']=(
167 {'TerminalIPythonApp' : {'quick' : True}},
167 {'TerminalIPythonApp' : {'quick' : True}},
168 "Enable quick startup with no config files."
168 "Enable quick startup with no config files."
169 )
169 )
170
170
171 flags['i'] = (
171 flags['i'] = (
172 {'TerminalIPythonApp' : {'force_interact' : True}},
172 {'TerminalIPythonApp' : {'force_interact' : True}},
173 "If running code from the command line, become interactive afterwards."
173 "If running code from the command line, become interactive afterwards."
174 )
174 )
175 flags['pylab'] = (
175 flags['pylab'] = (
176 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
176 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
177 """Pre-load matplotlib and numpy for interactive use with
177 """Pre-load matplotlib and numpy for interactive use with
178 the default matplotlib backend."""
178 the default matplotlib backend."""
179 )
179 )
180
180
181 aliases = dict(base_aliases)
181 aliases = dict(base_aliases)
182 aliases.update(shell_aliases)
182 aliases.update(shell_aliases)
183
183
184 # it's possible we don't want short aliases for *all* of these:
184 # it's possible we don't want short aliases for *all* of these:
185 aliases.update(dict(
185 aliases.update(dict(
186 gui='TerminalIPythonApp.gui',
186 gui='TerminalIPythonApp.gui',
187 pylab='TerminalIPythonApp.pylab',
187 pylab='TerminalIPythonApp.pylab',
188 ))
188 ))
189
189
190 #-----------------------------------------------------------------------------
190 #-----------------------------------------------------------------------------
191 # Main classes and functions
191 # Main classes and functions
192 #-----------------------------------------------------------------------------
192 #-----------------------------------------------------------------------------
193
193
194 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
194 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
195 name = u'ipython'
195 name = u'ipython'
196 description = usage.cl_usage
196 description = usage.cl_usage
197 # command_line_loader = IPAppConfigLoader
198 default_config_file_name = default_config_file_name
197 default_config_file_name = default_config_file_name
199 crash_handler_class = IPAppCrashHandler
198 crash_handler_class = IPAppCrashHandler
200
199
201 flags = Dict(flags)
200 flags = Dict(flags)
202 aliases = Dict(aliases)
201 aliases = Dict(aliases)
203 classes = [InteractiveShellApp, TerminalInteractiveShell, ProfileDir, PlainTextFormatter]
202 classes = [InteractiveShellApp, TerminalInteractiveShell, ProfileDir, PlainTextFormatter]
204 subcommands = Dict(dict(
203 subcommands = Dict(dict(
205 qtconsole=('IPython.frontend.qt.console.ipythonqt.IPythonQtConsoleApp',
204 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
206 """Launch the IPython QtConsole. Also launched as ipython-qtconsole"""
205 """Launch the IPython Qt Console."""
207 )
206 )
208 ))
207 ))
209
208
210 # *do* autocreate requested profile
209 # *do* autocreate requested profile
211 auto_create=Bool(True)
210 auto_create=Bool(True)
212 copy_config_files=Bool(True)
211 copy_config_files=Bool(True)
213 # configurables
212 # configurables
214 ignore_old_config=Bool(False, config=True,
213 ignore_old_config=Bool(False, config=True,
215 help="Suppress warning messages about legacy config files"
214 help="Suppress warning messages about legacy config files"
216 )
215 )
217 quick = Bool(False, config=True,
216 quick = Bool(False, config=True,
218 help="""Start IPython quickly by skipping the loading of config files."""
217 help="""Start IPython quickly by skipping the loading of config files."""
219 )
218 )
220 def _quick_changed(self, name, old, new):
219 def _quick_changed(self, name, old, new):
221 if new:
220 if new:
222 self.load_config_file = lambda *a, **kw: None
221 self.load_config_file = lambda *a, **kw: None
223 self.ignore_old_config=True
222 self.ignore_old_config=True
224
223
225 gui = CaselessStrEnum(('qt','wx','gtk'), config=True,
224 gui = CaselessStrEnum(('qt','wx','gtk'), config=True,
226 help="Enable GUI event loop integration ('qt', 'wx', 'gtk')."
225 help="Enable GUI event loop integration ('qt', 'wx', 'gtk')."
227 )
226 )
228 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
227 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
229 config=True,
228 config=True,
230 help="""Pre-load matplotlib and numpy for interactive use,
229 help="""Pre-load matplotlib and numpy for interactive use,
231 selecting a particular matplotlib backend and loop integration.
230 selecting a particular matplotlib backend and loop integration.
232 """
231 """
233 )
232 )
234 display_banner = Bool(True, config=True,
233 display_banner = Bool(True, config=True,
235 help="Whether to display a banner upon starting IPython."
234 help="Whether to display a banner upon starting IPython."
236 )
235 )
237
236
238 # if there is code of files to run from the cmd line, don't interact
237 # if there is code of files to run from the cmd line, don't interact
239 # unless the --i flag (App.force_interact) is true.
238 # unless the --i flag (App.force_interact) is true.
240 force_interact = Bool(False, config=True,
239 force_interact = Bool(False, config=True,
241 help="""If a command or file is given via the command-line,
240 help="""If a command or file is given via the command-line,
242 e.g. 'ipython foo.py"""
241 e.g. 'ipython foo.py"""
243 )
242 )
244 def _force_interact_changed(self, name, old, new):
243 def _force_interact_changed(self, name, old, new):
245 if new:
244 if new:
246 self.interact = True
245 self.interact = True
247
246
248 def _file_to_run_changed(self, name, old, new):
247 def _file_to_run_changed(self, name, old, new):
249 if new and not self.force_interact:
248 if new and not self.force_interact:
250 self.interact = False
249 self.interact = False
251 _code_to_run_changed = _file_to_run_changed
250 _code_to_run_changed = _file_to_run_changed
252
251
253 # internal, not-configurable
252 # internal, not-configurable
254 interact=Bool(True)
253 interact=Bool(True)
255
254
256
255
257 def initialize(self, argv=None):
256 def initialize(self, argv=None):
258 """Do actions after construct, but before starting the app."""
257 """Do actions after construct, but before starting the app."""
259 super(TerminalIPythonApp, self).initialize(argv)
258 super(TerminalIPythonApp, self).initialize(argv)
260 if self.subapp is not None:
259 if self.subapp is not None:
261 # don't bother initializing further, starting subapp
260 # don't bother initializing further, starting subapp
262 return
261 return
263 if not self.ignore_old_config:
262 if not self.ignore_old_config:
264 check_for_old_config(self.ipython_dir)
263 check_for_old_config(self.ipython_dir)
265 # print self.extra_args
264 # print self.extra_args
266 if self.extra_args:
265 if self.extra_args:
267 self.file_to_run = self.extra_args[0]
266 self.file_to_run = self.extra_args[0]
268 # create the shell
267 # create the shell
269 self.init_shell()
268 self.init_shell()
270 # and draw the banner
269 # and draw the banner
271 self.init_banner()
270 self.init_banner()
272 # Now a variety of things that happen after the banner is printed.
271 # Now a variety of things that happen after the banner is printed.
273 self.init_gui_pylab()
272 self.init_gui_pylab()
274 self.init_extensions()
273 self.init_extensions()
275 self.init_code()
274 self.init_code()
276
275
277 def init_shell(self):
276 def init_shell(self):
278 """initialize the InteractiveShell instance"""
277 """initialize the InteractiveShell instance"""
279 # I am a little hesitant to put these into InteractiveShell itself.
278 # I am a little hesitant to put these into InteractiveShell itself.
280 # But that might be the place for them
279 # But that might be the place for them
281 sys.path.insert(0, '')
280 sys.path.insert(0, '')
282
281
283 # Create an InteractiveShell instance.
282 # Create an InteractiveShell instance.
284 # shell.display_banner should always be False for the terminal
283 # shell.display_banner should always be False for the terminal
285 # based app, because we call shell.show_banner() by hand below
284 # based app, because we call shell.show_banner() by hand below
286 # so the banner shows *before* all extension loading stuff.
285 # so the banner shows *before* all extension loading stuff.
287 self.shell = TerminalInteractiveShell.instance(config=self.config,
286 self.shell = TerminalInteractiveShell.instance(config=self.config,
288 display_banner=False, profile_dir=self.profile_dir,
287 display_banner=False, profile_dir=self.profile_dir,
289 ipython_dir=self.ipython_dir)
288 ipython_dir=self.ipython_dir)
290
289
291 def init_banner(self):
290 def init_banner(self):
292 """optionally display the banner"""
291 """optionally display the banner"""
293 if self.display_banner and self.interact:
292 if self.display_banner and self.interact:
294 self.shell.show_banner()
293 self.shell.show_banner()
295 # Make sure there is a space below the banner.
294 # Make sure there is a space below the banner.
296 if self.log_level <= logging.INFO: print
295 if self.log_level <= logging.INFO: print
297
296
298
297
299 def init_gui_pylab(self):
298 def init_gui_pylab(self):
300 """Enable GUI event loop integration, taking pylab into account."""
299 """Enable GUI event loop integration, taking pylab into account."""
301 gui = self.gui
300 gui = self.gui
302
301
303 # Using `pylab` will also require gui activation, though which toolkit
302 # Using `pylab` will also require gui activation, though which toolkit
304 # to use may be chosen automatically based on mpl configuration.
303 # to use may be chosen automatically based on mpl configuration.
305 if self.pylab:
304 if self.pylab:
306 activate = self.shell.enable_pylab
305 activate = self.shell.enable_pylab
307 if self.pylab == 'auto':
306 if self.pylab == 'auto':
308 gui = None
307 gui = None
309 else:
308 else:
310 gui = self.pylab
309 gui = self.pylab
311 else:
310 else:
312 # Enable only GUI integration, no pylab
311 # Enable only GUI integration, no pylab
313 activate = inputhook.enable_gui
312 activate = inputhook.enable_gui
314
313
315 if gui or self.pylab:
314 if gui or self.pylab:
316 try:
315 try:
317 self.log.info("Enabling GUI event loop integration, "
316 self.log.info("Enabling GUI event loop integration, "
318 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
317 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
319 activate(gui)
318 activate(gui)
320 except:
319 except:
321 self.log.warn("Error in enabling GUI event loop integration:")
320 self.log.warn("Error in enabling GUI event loop integration:")
322 self.shell.showtraceback()
321 self.shell.showtraceback()
323
322
324 def start(self):
323 def start(self):
325 if self.subapp is not None:
324 if self.subapp is not None:
326 return self.subapp.start()
325 return self.subapp.start()
327 # perform any prexec steps:
326 # perform any prexec steps:
328 if self.interact:
327 if self.interact:
329 self.log.debug("Starting IPython's mainloop...")
328 self.log.debug("Starting IPython's mainloop...")
330 self.shell.mainloop()
329 self.shell.mainloop()
331 else:
330 else:
332 self.log.debug("IPython not interactive...")
331 self.log.debug("IPython not interactive...")
333
332
334
333
335 def load_default_config(ipython_dir=None):
334 def load_default_config(ipython_dir=None):
336 """Load the default config file from the default ipython_dir.
335 """Load the default config file from the default ipython_dir.
337
336
338 This is useful for embedded shells.
337 This is useful for embedded shells.
339 """
338 """
340 if ipython_dir is None:
339 if ipython_dir is None:
341 ipython_dir = get_ipython_dir()
340 ipython_dir = get_ipython_dir()
342 profile_dir = os.path.join(ipython_dir, 'profile_default')
341 profile_dir = os.path.join(ipython_dir, 'profile_default')
343 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
342 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
344 config = cl.load_config()
343 config = cl.load_config()
345 return config
344 return config
346
345
347
346
348 def launch_new_instance():
347 def launch_new_instance():
349 """Create and run a full blown IPython instance"""
348 """Create and run a full blown IPython instance"""
350 app = TerminalIPythonApp.instance()
349 app = TerminalIPythonApp.instance()
351 app.initialize()
350 app.initialize()
352 app.start()
351 app.start()
353
352
354
353
355 if __name__ == '__main__':
354 if __name__ == '__main__':
356 launch_new_instance()
355 launch_new_instance()
357
356
@@ -1,389 +1,388 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 from ConfigParser import ConfigParser
26 from ConfigParser import ConfigParser
27 from distutils.command.build_py import build_py
27 from distutils.command.build_py import build_py
28 from glob import glob
28 from glob import glob
29
29
30 from setupext import install_data_ext
30 from setupext import install_data_ext
31
31
32 #-------------------------------------------------------------------------------
32 #-------------------------------------------------------------------------------
33 # Useful globals and utility functions
33 # Useful globals and utility functions
34 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
35
35
36 # A few handy globals
36 # A few handy globals
37 isfile = os.path.isfile
37 isfile = os.path.isfile
38 pjoin = os.path.join
38 pjoin = os.path.join
39
39
40 def oscmd(s):
40 def oscmd(s):
41 print(">", s)
41 print(">", s)
42 os.system(s)
42 os.system(s)
43
43
44 # A little utility we'll need below, since glob() does NOT allow you to do
44 # A little utility we'll need below, since glob() does NOT allow you to do
45 # exclusion on multiple endings!
45 # exclusion on multiple endings!
46 def file_doesnt_endwith(test,endings):
46 def file_doesnt_endwith(test,endings):
47 """Return true if test is a file and its name does NOT end with any
47 """Return true if test is a file and its name does NOT end with any
48 of the strings listed in endings."""
48 of the strings listed in endings."""
49 if not isfile(test):
49 if not isfile(test):
50 return False
50 return False
51 for e in endings:
51 for e in endings:
52 if test.endswith(e):
52 if test.endswith(e):
53 return False
53 return False
54 return True
54 return True
55
55
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57 # Basic project information
57 # Basic project information
58 #---------------------------------------------------------------------------
58 #---------------------------------------------------------------------------
59
59
60 # release.py contains version, authors, license, url, keywords, etc.
60 # release.py contains version, authors, license, url, keywords, etc.
61 execfile(pjoin('IPython','core','release.py'))
61 execfile(pjoin('IPython','core','release.py'))
62
62
63 # Create a dict with the basic information
63 # Create a dict with the basic information
64 # This dict is eventually passed to setup after additional keys are added.
64 # This dict is eventually passed to setup after additional keys are added.
65 setup_args = dict(
65 setup_args = dict(
66 name = name,
66 name = name,
67 version = version,
67 version = version,
68 description = description,
68 description = description,
69 long_description = long_description,
69 long_description = long_description,
70 author = author,
70 author = author,
71 author_email = author_email,
71 author_email = author_email,
72 url = url,
72 url = url,
73 download_url = download_url,
73 download_url = download_url,
74 license = license,
74 license = license,
75 platforms = platforms,
75 platforms = platforms,
76 keywords = keywords,
76 keywords = keywords,
77 cmdclass = {'install_data': install_data_ext},
77 cmdclass = {'install_data': install_data_ext},
78 )
78 )
79
79
80
80
81 #---------------------------------------------------------------------------
81 #---------------------------------------------------------------------------
82 # Find packages
82 # Find packages
83 #---------------------------------------------------------------------------
83 #---------------------------------------------------------------------------
84
84
85 def add_package(packages,pname,config=False,tests=False,scripts=False,
85 def add_package(packages,pname,config=False,tests=False,scripts=False,
86 others=None):
86 others=None):
87 """
87 """
88 Add a package to the list of packages, including certain subpackages.
88 Add a package to the list of packages, including certain subpackages.
89 """
89 """
90 packages.append('.'.join(['IPython',pname]))
90 packages.append('.'.join(['IPython',pname]))
91 if config:
91 if config:
92 packages.append('.'.join(['IPython',pname,'config']))
92 packages.append('.'.join(['IPython',pname,'config']))
93 if tests:
93 if tests:
94 packages.append('.'.join(['IPython',pname,'tests']))
94 packages.append('.'.join(['IPython',pname,'tests']))
95 if scripts:
95 if scripts:
96 packages.append('.'.join(['IPython',pname,'scripts']))
96 packages.append('.'.join(['IPython',pname,'scripts']))
97 if others is not None:
97 if others is not None:
98 for o in others:
98 for o in others:
99 packages.append('.'.join(['IPython',pname,o]))
99 packages.append('.'.join(['IPython',pname,o]))
100
100
101 def find_packages():
101 def find_packages():
102 """
102 """
103 Find all of IPython's packages.
103 Find all of IPython's packages.
104 """
104 """
105 packages = ['IPython']
105 packages = ['IPython']
106 add_package(packages, 'config', tests=True, others=['default','profile'])
106 add_package(packages, 'config', tests=True, others=['default','profile'])
107 add_package(packages, 'core', tests=True)
107 add_package(packages, 'core', tests=True)
108 add_package(packages, 'deathrow', tests=True)
108 add_package(packages, 'deathrow', tests=True)
109 add_package(packages, 'extensions')
109 add_package(packages, 'extensions')
110 add_package(packages, 'external')
110 add_package(packages, 'external')
111 add_package(packages, 'external.argparse')
111 add_package(packages, 'external.argparse')
112 add_package(packages, 'external.configobj')
112 add_package(packages, 'external.configobj')
113 add_package(packages, 'external.decorator')
113 add_package(packages, 'external.decorator')
114 add_package(packages, 'external.decorators')
114 add_package(packages, 'external.decorators')
115 add_package(packages, 'external.guid')
115 add_package(packages, 'external.guid')
116 add_package(packages, 'external.Itpl')
116 add_package(packages, 'external.Itpl')
117 add_package(packages, 'external.mglob')
117 add_package(packages, 'external.mglob')
118 add_package(packages, 'external.path')
118 add_package(packages, 'external.path')
119 add_package(packages, 'external.pexpect')
119 add_package(packages, 'external.pexpect')
120 add_package(packages, 'external.pyparsing')
120 add_package(packages, 'external.pyparsing')
121 add_package(packages, 'external.simplegeneric')
121 add_package(packages, 'external.simplegeneric')
122 add_package(packages, 'external.ssh')
122 add_package(packages, 'external.ssh')
123 add_package(packages, 'external.validate')
123 add_package(packages, 'external.validate')
124 add_package(packages, 'kernel')
124 add_package(packages, 'kernel')
125 add_package(packages, 'frontend')
125 add_package(packages, 'frontend')
126 add_package(packages, 'frontend.qt')
126 add_package(packages, 'frontend.qt')
127 add_package(packages, 'frontend.qt.console', tests=True)
127 add_package(packages, 'frontend.qt.console', tests=True)
128 add_package(packages, 'frontend.terminal', tests=True)
128 add_package(packages, 'frontend.terminal', tests=True)
129 add_package(packages, 'lib', tests=True)
129 add_package(packages, 'lib', tests=True)
130 add_package(packages, 'parallel', tests=True, scripts=True,
130 add_package(packages, 'parallel', tests=True, scripts=True,
131 others=['apps','engine','client','controller'])
131 others=['apps','engine','client','controller'])
132 add_package(packages, 'quarantine', tests=True)
132 add_package(packages, 'quarantine', tests=True)
133 add_package(packages, 'scripts')
133 add_package(packages, 'scripts')
134 add_package(packages, 'testing', tests=True)
134 add_package(packages, 'testing', tests=True)
135 add_package(packages, 'testing.plugin', tests=False)
135 add_package(packages, 'testing.plugin', tests=False)
136 add_package(packages, 'utils', tests=True)
136 add_package(packages, 'utils', tests=True)
137 add_package(packages, 'zmq')
137 add_package(packages, 'zmq')
138 add_package(packages, 'zmq.pylab')
138 add_package(packages, 'zmq.pylab')
139 add_package(packages, 'zmq.gui')
139 add_package(packages, 'zmq.gui')
140 return packages
140 return packages
141
141
142 #---------------------------------------------------------------------------
142 #---------------------------------------------------------------------------
143 # Find package data
143 # Find package data
144 #---------------------------------------------------------------------------
144 #---------------------------------------------------------------------------
145
145
146 def find_package_data():
146 def find_package_data():
147 """
147 """
148 Find IPython's package_data.
148 Find IPython's package_data.
149 """
149 """
150 # This is not enough for these things to appear in an sdist.
150 # This is not enough for these things to appear in an sdist.
151 # We need to muck with the MANIFEST to get this to work
151 # We need to muck with the MANIFEST to get this to work
152 package_data = {
152 package_data = {
153 'IPython.config.profile' : ['README', '*/*.py'],
153 'IPython.config.profile' : ['README', '*/*.py'],
154 'IPython.testing' : ['*.txt'],
154 'IPython.testing' : ['*.txt'],
155 }
155 }
156 return package_data
156 return package_data
157
157
158
158
159 #---------------------------------------------------------------------------
159 #---------------------------------------------------------------------------
160 # Find data files
160 # Find data files
161 #---------------------------------------------------------------------------
161 #---------------------------------------------------------------------------
162
162
163 def make_dir_struct(tag,base,out_base):
163 def make_dir_struct(tag,base,out_base):
164 """Make the directory structure of all files below a starting dir.
164 """Make the directory structure of all files below a starting dir.
165
165
166 This is just a convenience routine to help build a nested directory
166 This is just a convenience routine to help build a nested directory
167 hierarchy because distutils is too stupid to do this by itself.
167 hierarchy because distutils is too stupid to do this by itself.
168
168
169 XXX - this needs a proper docstring!
169 XXX - this needs a proper docstring!
170 """
170 """
171
171
172 # we'll use these a lot below
172 # we'll use these a lot below
173 lbase = len(base)
173 lbase = len(base)
174 pathsep = os.path.sep
174 pathsep = os.path.sep
175 lpathsep = len(pathsep)
175 lpathsep = len(pathsep)
176
176
177 out = []
177 out = []
178 for (dirpath,dirnames,filenames) in os.walk(base):
178 for (dirpath,dirnames,filenames) in os.walk(base):
179 # we need to strip out the dirpath from the base to map it to the
179 # we need to strip out the dirpath from the base to map it to the
180 # output (installation) path. This requires possibly stripping the
180 # output (installation) path. This requires possibly stripping the
181 # path separator, because otherwise pjoin will not work correctly
181 # path separator, because otherwise pjoin will not work correctly
182 # (pjoin('foo/','/bar') returns '/bar').
182 # (pjoin('foo/','/bar') returns '/bar').
183
183
184 dp_eff = dirpath[lbase:]
184 dp_eff = dirpath[lbase:]
185 if dp_eff.startswith(pathsep):
185 if dp_eff.startswith(pathsep):
186 dp_eff = dp_eff[lpathsep:]
186 dp_eff = dp_eff[lpathsep:]
187 # The output path must be anchored at the out_base marker
187 # The output path must be anchored at the out_base marker
188 out_path = pjoin(out_base,dp_eff)
188 out_path = pjoin(out_base,dp_eff)
189 # Now we can generate the final filenames. Since os.walk only produces
189 # Now we can generate the final filenames. Since os.walk only produces
190 # filenames, we must join back with the dirpath to get full valid file
190 # filenames, we must join back with the dirpath to get full valid file
191 # paths:
191 # paths:
192 pfiles = [pjoin(dirpath,f) for f in filenames]
192 pfiles = [pjoin(dirpath,f) for f in filenames]
193 # Finally, generate the entry we need, which is a pari of (output
193 # Finally, generate the entry we need, which is a pari of (output
194 # path, files) for use as a data_files parameter in install_data.
194 # path, files) for use as a data_files parameter in install_data.
195 out.append((out_path, pfiles))
195 out.append((out_path, pfiles))
196
196
197 return out
197 return out
198
198
199
199
200 def find_data_files():
200 def find_data_files():
201 """
201 """
202 Find IPython's data_files.
202 Find IPython's data_files.
203
203
204 Most of these are docs.
204 Most of these are docs.
205 """
205 """
206
206
207 docdirbase = pjoin('share', 'doc', 'ipython')
207 docdirbase = pjoin('share', 'doc', 'ipython')
208 manpagebase = pjoin('share', 'man', 'man1')
208 manpagebase = pjoin('share', 'man', 'man1')
209
209
210 # Simple file lists can be made by hand
210 # Simple file lists can be made by hand
211 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
211 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
212 igridhelpfiles = filter(isfile,
212 igridhelpfiles = filter(isfile,
213 glob(pjoin('IPython','extensions','igrid_help.*')))
213 glob(pjoin('IPython','extensions','igrid_help.*')))
214
214
215 # For nested structures, use the utility above
215 # For nested structures, use the utility above
216 example_files = make_dir_struct(
216 example_files = make_dir_struct(
217 'data',
217 'data',
218 pjoin('docs','examples'),
218 pjoin('docs','examples'),
219 pjoin(docdirbase,'examples')
219 pjoin(docdirbase,'examples')
220 )
220 )
221 manual_files = make_dir_struct(
221 manual_files = make_dir_struct(
222 'data',
222 'data',
223 pjoin('docs','dist'),
223 pjoin('docs','dist'),
224 pjoin(docdirbase,'manual')
224 pjoin(docdirbase,'manual')
225 )
225 )
226
226
227 # And assemble the entire output list
227 # And assemble the entire output list
228 data_files = [ (manpagebase, manpages),
228 data_files = [ (manpagebase, manpages),
229 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
229 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
230 ] + manual_files + example_files
230 ] + manual_files + example_files
231
231
232 return data_files
232 return data_files
233
233
234
234
235 def make_man_update_target(manpage):
235 def make_man_update_target(manpage):
236 """Return a target_update-compliant tuple for the given manpage.
236 """Return a target_update-compliant tuple for the given manpage.
237
237
238 Parameters
238 Parameters
239 ----------
239 ----------
240 manpage : string
240 manpage : string
241 Name of the manpage, must include the section number (trailing number).
241 Name of the manpage, must include the section number (trailing number).
242
242
243 Example
243 Example
244 -------
244 -------
245
245
246 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
246 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
247 ('docs/man/ipython.1.gz',
247 ('docs/man/ipython.1.gz',
248 ['docs/man/ipython.1'],
248 ['docs/man/ipython.1'],
249 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
249 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
250 """
250 """
251 man_dir = pjoin('docs', 'man')
251 man_dir = pjoin('docs', 'man')
252 manpage_gz = manpage + '.gz'
252 manpage_gz = manpage + '.gz'
253 manpath = pjoin(man_dir, manpage)
253 manpath = pjoin(man_dir, manpage)
254 manpath_gz = pjoin(man_dir, manpage_gz)
254 manpath_gz = pjoin(man_dir, manpage_gz)
255 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
255 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
256 locals() )
256 locals() )
257 return (manpath_gz, [manpath], gz_cmd)
257 return (manpath_gz, [manpath], gz_cmd)
258
258
259 #---------------------------------------------------------------------------
259 #---------------------------------------------------------------------------
260 # Find scripts
260 # Find scripts
261 #---------------------------------------------------------------------------
261 #---------------------------------------------------------------------------
262
262
263 def find_scripts(entry_points=False):
263 def find_scripts(entry_points=False):
264 """Find IPython's scripts.
264 """Find IPython's scripts.
265
265
266 if entry_points is True:
266 if entry_points is True:
267 return setuptools entry_point-style definitions
267 return setuptools entry_point-style definitions
268 else:
268 else:
269 return file paths of plain scripts [default]
269 return file paths of plain scripts [default]
270 """
270 """
271 if entry_points:
271 if entry_points:
272 console_scripts = [
272 console_scripts = [
273 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
273 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
274 'pycolor = IPython.utils.PyColorize:main',
274 'pycolor = IPython.utils.PyColorize:main',
275 'ipcontroller = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
275 'ipcontroller = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
276 'ipengine = IPython.parallel.apps.ipengineapp:launch_new_instance',
276 'ipengine = IPython.parallel.apps.ipengineapp:launch_new_instance',
277 'iplogger = IPython.parallel.apps.iploggerapp:launch_new_instance',
277 'iplogger = IPython.parallel.apps.iploggerapp:launch_new_instance',
278 'ipcluster = IPython.parallel.apps.ipclusterapp:launch_new_instance',
278 'ipcluster = IPython.parallel.apps.ipclusterapp:launch_new_instance',
279 'iptest = IPython.testing.iptest:main',
279 'iptest = IPython.testing.iptest:main',
280 'irunner = IPython.lib.irunner:main'
280 'irunner = IPython.lib.irunner:main'
281 ]
281 ]
282 gui_scripts = [
282 gui_scripts = [
283 'ipython-qtconsole = IPython.frontend.qt.console.ipythonqt:main',
283 'ipython-qtconsole = IPython.frontend.qt.console.qtconsoleapp:main',
284 ]
284 ]
285 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
285 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
286 else:
286 else:
287 parallel_scripts = pjoin('IPython','parallel','scripts')
287 parallel_scripts = pjoin('IPython','parallel','scripts')
288 main_scripts = pjoin('IPython','scripts')
288 main_scripts = pjoin('IPython','scripts')
289 scripts = [
289 scripts = [
290 pjoin(parallel_scripts, 'ipengine'),
290 pjoin(parallel_scripts, 'ipengine'),
291 pjoin(parallel_scripts, 'ipcontroller'),
291 pjoin(parallel_scripts, 'ipcontroller'),
292 pjoin(parallel_scripts, 'ipcluster'),
292 pjoin(parallel_scripts, 'ipcluster'),
293 pjoin(parallel_scripts, 'iplogger'),
293 pjoin(parallel_scripts, 'iplogger'),
294 pjoin(main_scripts, 'ipython'),
294 pjoin(main_scripts, 'ipython'),
295 pjoin(main_scripts, 'ipython-qtconsole'),
296 pjoin(main_scripts, 'pycolor'),
295 pjoin(main_scripts, 'pycolor'),
297 pjoin(main_scripts, 'irunner'),
296 pjoin(main_scripts, 'irunner'),
298 pjoin(main_scripts, 'iptest')
297 pjoin(main_scripts, 'iptest')
299 ]
298 ]
300 return scripts
299 return scripts
301
300
302 #---------------------------------------------------------------------------
301 #---------------------------------------------------------------------------
303 # Verify all dependencies
302 # Verify all dependencies
304 #---------------------------------------------------------------------------
303 #---------------------------------------------------------------------------
305
304
306 def check_for_dependencies():
305 def check_for_dependencies():
307 """Check for IPython's dependencies.
306 """Check for IPython's dependencies.
308
307
309 This function should NOT be called if running under setuptools!
308 This function should NOT be called if running under setuptools!
310 """
309 """
311 from setupext.setupext import (
310 from setupext.setupext import (
312 print_line, print_raw, print_status,
311 print_line, print_raw, print_status,
313 check_for_sphinx, check_for_pygments,
312 check_for_sphinx, check_for_pygments,
314 check_for_nose, check_for_pexpect,
313 check_for_nose, check_for_pexpect,
315 check_for_pyzmq, check_for_readline
314 check_for_pyzmq, check_for_readline
316 )
315 )
317 print_line()
316 print_line()
318 print_raw("BUILDING IPYTHON")
317 print_raw("BUILDING IPYTHON")
319 print_status('python', sys.version)
318 print_status('python', sys.version)
320 print_status('platform', sys.platform)
319 print_status('platform', sys.platform)
321 if sys.platform == 'win32':
320 if sys.platform == 'win32':
322 print_status('Windows version', sys.getwindowsversion())
321 print_status('Windows version', sys.getwindowsversion())
323
322
324 print_raw("")
323 print_raw("")
325 print_raw("OPTIONAL DEPENDENCIES")
324 print_raw("OPTIONAL DEPENDENCIES")
326
325
327 check_for_sphinx()
326 check_for_sphinx()
328 check_for_pygments()
327 check_for_pygments()
329 check_for_nose()
328 check_for_nose()
330 check_for_pexpect()
329 check_for_pexpect()
331 check_for_pyzmq()
330 check_for_pyzmq()
332 check_for_readline()
331 check_for_readline()
333
332
334 def record_commit_info(pkg_dir, build_cmd=build_py):
333 def record_commit_info(pkg_dir, build_cmd=build_py):
335 """ Return extended build command class for recording commit
334 """ Return extended build command class for recording commit
336
335
337 The extended command tries to run git to find the current commit, getting
336 The extended command tries to run git to find the current commit, getting
338 the empty string if it fails. It then writes the commit hash into a file
337 the empty string if it fails. It then writes the commit hash into a file
339 in the `pkg_dir` path, named ``.git_commit_info.ini``.
338 in the `pkg_dir` path, named ``.git_commit_info.ini``.
340
339
341 In due course this information can be used by the package after it is
340 In due course this information can be used by the package after it is
342 installed, to tell you what commit it was installed from if known.
341 installed, to tell you what commit it was installed from if known.
343
342
344 To make use of this system, you need a package with a .git_commit_info.ini
343 To make use of this system, you need a package with a .git_commit_info.ini
345 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
344 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
346 this::
345 this::
347
346
348 # This is an ini file that may contain information about the code state
347 # This is an ini file that may contain information about the code state
349 [commit hash]
348 [commit hash]
350 # The line below may contain a valid hash if it has been substituted
349 # The line below may contain a valid hash if it has been substituted
351 # during 'git archive'
350 # during 'git archive'
352 archive_subst_hash=$Format:%h$
351 archive_subst_hash=$Format:%h$
353 # This line may be modified by the install process
352 # This line may be modified by the install process
354 install_hash=
353 install_hash=
355
354
356 The .git_commit_info file above is also designed to be used with git
355 The .git_commit_info file above is also designed to be used with git
357 substitution - so you probably also want a ``.gitattributes`` file in the
356 substitution - so you probably also want a ``.gitattributes`` file in the
358 root directory of your working tree that contains something like this::
357 root directory of your working tree that contains something like this::
359
358
360 myproject/.git_commit_info.ini export-subst
359 myproject/.git_commit_info.ini export-subst
361
360
362 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
361 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
363 archive`` - useful in case someone makes such an archive - for example with
362 archive`` - useful in case someone makes such an archive - for example with
364 via the github 'download source' button.
363 via the github 'download source' button.
365
364
366 Although all the above will work as is, you might consider having something
365 Although all the above will work as is, you might consider having something
367 like a ``get_info()`` function in your package to display the commit
366 like a ``get_info()`` function in your package to display the commit
368 information at the terminal. See the ``pkg_info.py`` module in the nipy
367 information at the terminal. See the ``pkg_info.py`` module in the nipy
369 package for an example.
368 package for an example.
370 """
369 """
371 class MyBuildPy(build_cmd):
370 class MyBuildPy(build_cmd):
372 ''' Subclass to write commit data into installation tree '''
371 ''' Subclass to write commit data into installation tree '''
373 def run(self):
372 def run(self):
374 build_py.run(self)
373 build_py.run(self)
375 import subprocess
374 import subprocess
376 proc = subprocess.Popen('git rev-parse --short HEAD',
375 proc = subprocess.Popen('git rev-parse --short HEAD',
377 stdout=subprocess.PIPE,
376 stdout=subprocess.PIPE,
378 stderr=subprocess.PIPE,
377 stderr=subprocess.PIPE,
379 shell=True)
378 shell=True)
380 repo_commit, _ = proc.communicate()
379 repo_commit, _ = proc.communicate()
381 # We write the installation commit even if it's empty
380 # We write the installation commit even if it's empty
382 cfg_parser = ConfigParser()
381 cfg_parser = ConfigParser()
383 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
382 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
384 cfg_parser.set('commit hash', 'install_hash', repo_commit)
383 cfg_parser.set('commit hash', 'install_hash', repo_commit)
385 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
384 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
386 out_file = open(out_pth, 'wt')
385 out_file = open(out_pth, 'wt')
387 cfg_parser.write(out_file)
386 cfg_parser.write(out_file)
388 out_file.close()
387 out_file.close()
389 return MyBuildPy
388 return MyBuildPy
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now