##// END OF EJS Templates
remove IPython.kernel scripts and put migration notice in docs....
MinRK -
Show More
@@ -0,0 +1,12 b''
1 .. _parallel_index:
2
3 ====================================
4 Using IPython for parallel computing
5 ====================================
6
7 The twisted-based :mod:`IPython.kernel` has been removed, in favor of
8 the new 0MQ-based :mod:`IPython.parallel`, whose merge into master is imminent.
9
10 Until that code is merged, it can be found in the `newparallel branch
11 <https://github.com/ipython/ipython/tree/newparallel>`_, and its draft documentation can be
12 found `here <http://minrk.github.com/ipython-doc/newparallel>`_. No newline at end of file
@@ -1,143 +1,143 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython Core Notification Center.
4 The IPython Core Notification Center.
5
5
6 See docs/source/development/notification_blueprint.txt for an overview of the
6 See docs/source/development/notification_blueprint.txt for an overview of the
7 notification module.
7 notification module.
8
8
9 Authors:
9 Authors:
10
10
11 * Barry Wark
11 * Barry Wark
12 * Brian Granger
12 * Brian Granger
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2009 The IPython Development Team
16 # Copyright (C) 2008-2009 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 # Code
23 # Code
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 class NotificationError(Exception):
27 class NotificationError(Exception):
28 pass
28 pass
29
29
30
30
31 class NotificationCenter(object):
31 class NotificationCenter(object):
32 """Synchronous notification center.
32 """Synchronous notification center.
33
33
34 Examples
34 Examples
35 --------
35 --------
36 Here is a simple example of how to use this::
36 Here is a simple example of how to use this::
37
37
38 import IPython.kernel.core.notification as notification
38 import IPython.util.notification as notification
39 def callback(ntype, theSender, args={}):
39 def callback(ntype, theSender, args={}):
40 print ntype,theSender,args
40 print ntype,theSender,args
41
41
42 notification.sharedCenter.add_observer(callback, 'NOTIFICATION_TYPE', None)
42 notification.sharedCenter.add_observer(callback, 'NOTIFICATION_TYPE', None)
43 notification.sharedCenter.post_notification('NOTIFICATION_TYPE', object()) # doctest:+ELLIPSIS
43 notification.sharedCenter.post_notification('NOTIFICATION_TYPE', object()) # doctest:+ELLIPSIS
44 NOTIFICATION_TYPE ...
44 NOTIFICATION_TYPE ...
45 """
45 """
46 def __init__(self):
46 def __init__(self):
47 super(NotificationCenter, self).__init__()
47 super(NotificationCenter, self).__init__()
48 self._init_observers()
48 self._init_observers()
49
49
50 def _init_observers(self):
50 def _init_observers(self):
51 """Initialize observer storage"""
51 """Initialize observer storage"""
52
52
53 self.registered_types = set() #set of types that are observed
53 self.registered_types = set() #set of types that are observed
54 self.registered_senders = set() #set of senders that are observed
54 self.registered_senders = set() #set of senders that are observed
55 self.observers = {} #map (type,sender) => callback (callable)
55 self.observers = {} #map (type,sender) => callback (callable)
56
56
57 def post_notification(self, ntype, sender, *args, **kwargs):
57 def post_notification(self, ntype, sender, *args, **kwargs):
58 """Post notification to all registered observers.
58 """Post notification to all registered observers.
59
59
60 The registered callback will be called as::
60 The registered callback will be called as::
61
61
62 callback(ntype, sender, *args, **kwargs)
62 callback(ntype, sender, *args, **kwargs)
63
63
64 Parameters
64 Parameters
65 ----------
65 ----------
66 ntype : hashable
66 ntype : hashable
67 The notification type.
67 The notification type.
68 sender : hashable
68 sender : hashable
69 The object sending the notification.
69 The object sending the notification.
70 *args : tuple
70 *args : tuple
71 The positional arguments to be passed to the callback.
71 The positional arguments to be passed to the callback.
72 **kwargs : dict
72 **kwargs : dict
73 The keyword argument to be passed to the callback.
73 The keyword argument to be passed to the callback.
74
74
75 Notes
75 Notes
76 -----
76 -----
77 * If no registered observers, performance is O(1).
77 * If no registered observers, performance is O(1).
78 * Notificaiton order is undefined.
78 * Notificaiton order is undefined.
79 * Notifications are posted synchronously.
79 * Notifications are posted synchronously.
80 """
80 """
81
81
82 if(ntype==None or sender==None):
82 if(ntype==None or sender==None):
83 raise NotificationError(
83 raise NotificationError(
84 "Notification type and sender are required.")
84 "Notification type and sender are required.")
85
85
86 # If there are no registered observers for the type/sender pair
86 # If there are no registered observers for the type/sender pair
87 if((ntype not in self.registered_types and
87 if((ntype not in self.registered_types and
88 None not in self.registered_types) or
88 None not in self.registered_types) or
89 (sender not in self.registered_senders and
89 (sender not in self.registered_senders and
90 None not in self.registered_senders)):
90 None not in self.registered_senders)):
91 return
91 return
92
92
93 for o in self._observers_for_notification(ntype, sender):
93 for o in self._observers_for_notification(ntype, sender):
94 o(ntype, sender, *args, **kwargs)
94 o(ntype, sender, *args, **kwargs)
95
95
96 def _observers_for_notification(self, ntype, sender):
96 def _observers_for_notification(self, ntype, sender):
97 """Find all registered observers that should recieve notification"""
97 """Find all registered observers that should recieve notification"""
98
98
99 keys = (
99 keys = (
100 (ntype,sender),
100 (ntype,sender),
101 (ntype, None),
101 (ntype, None),
102 (None, sender),
102 (None, sender),
103 (None,None)
103 (None,None)
104 )
104 )
105
105
106 obs = set()
106 obs = set()
107 for k in keys:
107 for k in keys:
108 obs.update(self.observers.get(k, set()))
108 obs.update(self.observers.get(k, set()))
109
109
110 return obs
110 return obs
111
111
112 def add_observer(self, callback, ntype, sender):
112 def add_observer(self, callback, ntype, sender):
113 """Add an observer callback to this notification center.
113 """Add an observer callback to this notification center.
114
114
115 The given callback will be called upon posting of notifications of
115 The given callback will be called upon posting of notifications of
116 the given type/sender and will receive any additional arguments passed
116 the given type/sender and will receive any additional arguments passed
117 to post_notification.
117 to post_notification.
118
118
119 Parameters
119 Parameters
120 ----------
120 ----------
121 callback : callable
121 callback : callable
122 The callable that will be called by :meth:`post_notification`
122 The callable that will be called by :meth:`post_notification`
123 as ``callback(ntype, sender, *args, **kwargs)
123 as ``callback(ntype, sender, *args, **kwargs)
124 ntype : hashable
124 ntype : hashable
125 The notification type. If None, all notifications from sender
125 The notification type. If None, all notifications from sender
126 will be posted.
126 will be posted.
127 sender : hashable
127 sender : hashable
128 The notification sender. If None, all notifications of ntype
128 The notification sender. If None, all notifications of ntype
129 will be posted.
129 will be posted.
130 """
130 """
131 assert(callback != None)
131 assert(callback != None)
132 self.registered_types.add(ntype)
132 self.registered_types.add(ntype)
133 self.registered_senders.add(sender)
133 self.registered_senders.add(sender)
134 self.observers.setdefault((ntype,sender), set()).add(callback)
134 self.observers.setdefault((ntype,sender), set()).add(callback)
135
135
136 def remove_all_observers(self):
136 def remove_all_observers(self):
137 """Removes all observers from this notification center"""
137 """Removes all observers from this notification center"""
138
138
139 self._init_observers()
139 self._init_observers()
140
140
141
141
142
142
143 shared_center = NotificationCenter()
143 shared_center = NotificationCenter()
@@ -1,32 +1,33 b''
1 =====================
1 =====================
2 IPython Documentation
2 IPython Documentation
3 =====================
3 =====================
4
4
5 .. htmlonly::
5 .. htmlonly::
6
6
7 :Release: |release|
7 :Release: |release|
8 :Date: |today|
8 :Date: |today|
9
9
10 Welcome to the official IPython documentation.
10 Welcome to the official IPython documentation.
11
11
12 Contents
12 Contents
13 ========
13 ========
14
14
15 .. toctree::
15 .. toctree::
16 :maxdepth: 1
16 :maxdepth: 1
17
17
18 overview.txt
18 overview.txt
19 whatsnew/index.txt
19 whatsnew/index.txt
20 install/index.txt
20 install/index.txt
21 interactive/index.txt
21 interactive/index.txt
22 parallel/index.txt
22 config/index.txt
23 config/index.txt
23 development/index.txt
24 development/index.txt
24 api/index.txt
25 api/index.txt
25 faq.txt
26 faq.txt
26 about/index.txt
27 about/index.txt
27
28
28 .. htmlonly::
29 .. htmlonly::
29 * :ref:`genindex`
30 * :ref:`genindex`
30 * :ref:`modindex`
31 * :ref:`modindex`
31 * :ref:`search`
32 * :ref:`search`
32
33
@@ -1,250 +1,250 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 """Setup script for IPython.
3 """Setup script for IPython.
4
4
5 Under Posix environments it works like a typical setup.py script.
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
6 Under Windows, the command sdist is not supported, since IPython
7 requires utilities which are not available under Windows."""
7 requires utilities which are not available under Windows."""
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (c) 2008-2010, IPython Development Team.
10 # Copyright (c) 2008-2010, IPython Development Team.
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 #
14 #
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16 #
16 #
17 # The full license is in the file COPYING.txt, distributed with this software.
17 # The full license is in the file COPYING.txt, distributed with this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Minimal Python version sanity check
21 # Minimal Python version sanity check
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import sys
24 import sys
25
25
26 # This check is also made in IPython/__init__, don't forget to update both when
26 # This check is also made in IPython/__init__, don't forget to update both when
27 # changing Python version requirements.
27 # changing Python version requirements.
28 if sys.version[0:3] < '2.6':
28 if sys.version[0:3] < '2.6':
29 error = """\
29 error = """\
30 ERROR: 'IPython requires Python Version 2.6 or above.'
30 ERROR: 'IPython requires Python Version 2.6 or above.'
31 Exiting."""
31 Exiting."""
32 print >> sys.stderr, error
32 print >> sys.stderr, error
33 sys.exit(1)
33 sys.exit(1)
34
34
35 # At least we're on the python version we need, move on.
35 # At least we're on the python version we need, move on.
36
36
37 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
38 # Imports
38 # Imports
39 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
40
40
41 # Stdlib imports
41 # Stdlib imports
42 import os
42 import os
43 import shutil
43 import shutil
44
44
45 from glob import glob
45 from glob import glob
46
46
47 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
47 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
48 # update it when the contents of directories change.
48 # update it when the contents of directories change.
49 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
49 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
50
50
51 from distutils.core import setup
51 from distutils.core import setup
52
52
53 # Our own imports
53 # Our own imports
54 from IPython.utils.path import target_update
54 from IPython.utils.path import target_update
55
55
56 from setupbase import (
56 from setupbase import (
57 setup_args,
57 setup_args,
58 find_packages,
58 find_packages,
59 find_package_data,
59 find_package_data,
60 find_scripts,
60 find_scripts,
61 find_data_files,
61 find_data_files,
62 check_for_dependencies,
62 check_for_dependencies,
63 record_commit_info,
63 record_commit_info,
64 )
64 )
65
65
66 isfile = os.path.isfile
66 isfile = os.path.isfile
67 pjoin = os.path.join
67 pjoin = os.path.join
68
68
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70 # Function definitions
70 # Function definitions
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72
72
73 def cleanup():
73 def cleanup():
74 """Clean up the junk left around by the build process"""
74 """Clean up the junk left around by the build process"""
75 if "develop" not in sys.argv:
75 if "develop" not in sys.argv:
76 try:
76 try:
77 shutil.rmtree('ipython.egg-info')
77 shutil.rmtree('ipython.egg-info')
78 except:
78 except:
79 try:
79 try:
80 os.unlink('ipython.egg-info')
80 os.unlink('ipython.egg-info')
81 except:
81 except:
82 pass
82 pass
83
83
84 #-------------------------------------------------------------------------------
84 #-------------------------------------------------------------------------------
85 # Handle OS specific things
85 # Handle OS specific things
86 #-------------------------------------------------------------------------------
86 #-------------------------------------------------------------------------------
87
87
88 if os.name == 'posix':
88 if os.name == 'posix':
89 os_name = 'posix'
89 os_name = 'posix'
90 elif os.name in ['nt','dos']:
90 elif os.name in ['nt','dos']:
91 os_name = 'windows'
91 os_name = 'windows'
92 else:
92 else:
93 print 'Unsupported operating system:',os.name
93 print 'Unsupported operating system:',os.name
94 sys.exit(1)
94 sys.exit(1)
95
95
96 # Under Windows, 'sdist' has not been supported. Now that the docs build with
96 # Under Windows, 'sdist' has not been supported. Now that the docs build with
97 # Sphinx it might work, but let's not turn it on until someone confirms that it
97 # Sphinx it might work, but let's not turn it on until someone confirms that it
98 # actually works.
98 # actually works.
99 if os_name == 'windows' and 'sdist' in sys.argv:
99 if os_name == 'windows' and 'sdist' in sys.argv:
100 print 'The sdist command is not available under Windows. Exiting.'
100 print 'The sdist command is not available under Windows. Exiting.'
101 sys.exit(1)
101 sys.exit(1)
102
102
103 #-------------------------------------------------------------------------------
103 #-------------------------------------------------------------------------------
104 # Things related to the IPython documentation
104 # Things related to the IPython documentation
105 #-------------------------------------------------------------------------------
105 #-------------------------------------------------------------------------------
106
106
107 # update the manuals when building a source dist
107 # update the manuals when building a source dist
108 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
108 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
109 import textwrap
109 import textwrap
110
110
111 # List of things to be updated. Each entry is a triplet of args for
111 # List of things to be updated. Each entry is a triplet of args for
112 # target_update()
112 # target_update()
113 to_update = [
113 to_update = [
114 # FIXME - Disabled for now: we need to redo an automatic way
114 # FIXME - Disabled for now: we need to redo an automatic way
115 # of generating the magic info inside the rst.
115 # of generating the magic info inside the rst.
116 #('docs/magic.tex',
116 #('docs/magic.tex',
117 #['IPython/Magic.py'],
117 #['IPython/Magic.py'],
118 #"cd doc && ./update_magic.sh" ),
118 #"cd doc && ./update_magic.sh" ),
119
119
120 ('docs/man/ipcluster.1.gz',
120 ('docs/man/ipcluster.1.gz',
121 ['docs/man/ipcluster.1'],
121 ['docs/man/ipcluster.1'],
122 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
122 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
123
123
124 ('docs/man/ipcontroller.1.gz',
124 ('docs/man/ipcontroller.1.gz',
125 ['docs/man/ipcontroller.1'],
125 ['docs/man/ipcontroller.1'],
126 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
126 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
127
127
128 ('docs/man/ipengine.1.gz',
128 ('docs/man/ipengine.1.gz',
129 ['docs/man/ipengine.1'],
129 ['docs/man/ipengine.1'],
130 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
130 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
131
131
132 ('docs/man/ipython.1.gz',
132 ('docs/man/ipython.1.gz',
133 ['docs/man/ipython.1'],
133 ['docs/man/ipython.1'],
134 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
134 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
135
135
136 ('docs/man/ipython-wx.1.gz',
136 ('docs/man/ipython-wx.1.gz',
137 ['docs/man/ipython-wx.1'],
137 ['docs/man/ipython-wx.1'],
138 'cd docs/man && gzip -9c ipython-wx.1 > ipython-wx.1.gz'),
138 'cd docs/man && gzip -9c ipython-wx.1 > ipython-wx.1.gz'),
139
139
140 ('docs/man/ipythonx.1.gz',
140 ('docs/man/ipythonx.1.gz',
141 ['docs/man/ipythonx.1'],
141 ['docs/man/ipythonx.1'],
142 'cd docs/man && gzip -9c ipythonx.1 > ipythonx.1.gz'),
142 'cd docs/man && gzip -9c ipythonx.1 > ipythonx.1.gz'),
143
143
144 ('docs/man/irunner.1.gz',
144 ('docs/man/irunner.1.gz',
145 ['docs/man/irunner.1'],
145 ['docs/man/irunner.1'],
146 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
146 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
147
147
148 ('docs/man/pycolor.1.gz',
148 ('docs/man/pycolor.1.gz',
149 ['docs/man/pycolor.1'],
149 ['docs/man/pycolor.1'],
150 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
150 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
151 ]
151 ]
152
152
153 # Only build the docs if sphinx is present
153 # Only build the docs if sphinx is present
154 try:
154 try:
155 import sphinx
155 import sphinx
156 except ImportError:
156 except ImportError:
157 pass
157 pass
158 else:
158 else:
159 # The Makefile calls the do_sphinx scripts to build html and pdf, so
159 # The Makefile calls the do_sphinx scripts to build html and pdf, so
160 # just one target is enough to cover all manual generation
160 # just one target is enough to cover all manual generation
161
161
162 # First, compute all the dependencies that can force us to rebuild the
162 # First, compute all the dependencies that can force us to rebuild the
163 # docs. Start with the main release file that contains metadata
163 # docs. Start with the main release file that contains metadata
164 docdeps = ['IPython/core/release.py']
164 docdeps = ['IPython/core/release.py']
165 # Inculde all the reST sources
165 # Inculde all the reST sources
166 pjoin = os.path.join
166 pjoin = os.path.join
167 for dirpath,dirnames,filenames in os.walk('docs/source'):
167 for dirpath,dirnames,filenames in os.walk('docs/source'):
168 if dirpath in ['_static','_templates']:
168 if dirpath in ['_static','_templates']:
169 continue
169 continue
170 docdeps += [ pjoin(dirpath,f) for f in filenames
170 docdeps += [ pjoin(dirpath,f) for f in filenames
171 if f.endswith('.txt') ]
171 if f.endswith('.txt') ]
172 # and the examples
172 # and the examples
173 for dirpath,dirnames,filenames in os.walk('docs/example'):
173 for dirpath,dirnames,filenames in os.walk('docs/example'):
174 docdeps += [ pjoin(dirpath,f) for f in filenames
174 docdeps += [ pjoin(dirpath,f) for f in filenames
175 if not f.endswith('~') ]
175 if not f.endswith('~') ]
176 # then, make them all dependencies for the main PDF (the html will get
176 # then, make them all dependencies for the main PDF (the html will get
177 # auto-generated as well).
177 # auto-generated as well).
178 to_update.append(
178 to_update.append(
179 ('docs/dist/ipython.pdf',
179 ('docs/dist/ipython.pdf',
180 docdeps,
180 docdeps,
181 "cd docs && make dist")
181 "cd docs && make dist")
182 )
182 )
183
183
184 [ target_update(*t) for t in to_update ]
184 [ target_update(*t) for t in to_update ]
185
185
186 #---------------------------------------------------------------------------
186 #---------------------------------------------------------------------------
187 # Find all the packages, package data, scripts and data_files
187 # Find all the packages, package data, scripts and data_files
188 #---------------------------------------------------------------------------
188 #---------------------------------------------------------------------------
189
189
190 packages = find_packages()
190 packages = find_packages()
191 package_data = find_package_data()
191 package_data = find_package_data()
192 scripts = find_scripts()
192 scripts = find_scripts()
193 data_files = find_data_files()
193 data_files = find_data_files()
194
194
195 #---------------------------------------------------------------------------
195 #---------------------------------------------------------------------------
196 # Handle dependencies and setuptools specific things
196 # Handle dependencies and setuptools specific things
197 #---------------------------------------------------------------------------
197 #---------------------------------------------------------------------------
198
198
199 # For some commands, use setuptools. Note that we do NOT list install here!
199 # For some commands, use setuptools. Note that we do NOT list install here!
200 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
200 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
201 if len(set(('develop', 'sdist', 'release', 'bdist_egg', 'bdist_rpm',
201 if len(set(('develop', 'sdist', 'release', 'bdist_egg', 'bdist_rpm',
202 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
202 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
203 'build_sphinx', 'egg_info', 'easy_install', 'upload',
203 'build_sphinx', 'egg_info', 'easy_install', 'upload',
204 )).intersection(sys.argv)) > 0:
204 )).intersection(sys.argv)) > 0:
205 import setuptools
205 import setuptools
206
206
207 # This dict is used for passing extra arguments that are setuptools
207 # This dict is used for passing extra arguments that are setuptools
208 # specific to setup
208 # specific to setup
209 setuptools_extra_args = {}
209 setuptools_extra_args = {}
210
210
211 if 'setuptools' in sys.modules:
211 if 'setuptools' in sys.modules:
212 setuptools_extra_args['zip_safe'] = False
212 setuptools_extra_args['zip_safe'] = False
213 setuptools_extra_args['entry_points'] = {
213 setuptools_extra_args['entry_points'] = {
214 'console_scripts': [
214 'console_scripts': [
215 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
215 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
216 'ipython-qtconsole = IPython.frontend.qt.console.ipythonqt:main',
216 'ipython-qtconsole = IPython.frontend.qt.console.ipythonqt:main',
217 'pycolor = IPython.utils.PyColorize:main',
217 'pycolor = IPython.utils.PyColorize:main',
218 'ipcontroller = IPython.kernel.ipcontrollerapp:launch_new_instance',
218 # 'ipcontroller = IPython.kernel.ipcontrollerapp:launch_new_instance',
219 'ipengine = IPython.kernel.ipengineapp:launch_new_instance',
219 # 'ipengine = IPython.kernel.ipengineapp:launch_new_instance',
220 'ipcluster = IPython.kernel.ipclusterapp:launch_new_instance',
220 # 'ipcluster = IPython.kernel.ipclusterapp:launch_new_instance',
221 'iptest = IPython.testing.iptest:main',
221 'iptest = IPython.testing.iptest:main',
222 'irunner = IPython.lib.irunner:main'
222 'irunner = IPython.lib.irunner:main'
223 ]
223 ]
224 }
224 }
225 setup_args['extras_require'] = dict(
225 setup_args['extras_require'] = dict(
226 doc='Sphinx>=0.3',
226 doc='Sphinx>=0.3',
227 test='nose>=0.10.1',
227 test='nose>=0.10.1',
228 security='pyOpenSSL>=0.6'
228 security='pyOpenSSL>=0.6'
229 )
229 )
230 else:
230 else:
231 # If we are running without setuptools, call this function which will
231 # If we are running without setuptools, call this function which will
232 # check for dependencies an inform the user what is needed. This is
232 # check for dependencies an inform the user what is needed. This is
233 # just to make life easy for users.
233 # just to make life easy for users.
234 check_for_dependencies()
234 check_for_dependencies()
235
235
236 #---------------------------------------------------------------------------
236 #---------------------------------------------------------------------------
237 # Do the actual setup now
237 # Do the actual setup now
238 #---------------------------------------------------------------------------
238 #---------------------------------------------------------------------------
239
239
240 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython')}
240 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython')}
241 setup_args['packages'] = packages
241 setup_args['packages'] = packages
242 setup_args['package_data'] = package_data
242 setup_args['package_data'] = package_data
243 setup_args['scripts'] = scripts
243 setup_args['scripts'] = scripts
244 setup_args['data_files'] = data_files
244 setup_args['data_files'] = data_files
245 setup_args.update(setuptools_extra_args)
245 setup_args.update(setuptools_extra_args)
246
246
247
247
248 if __name__ == '__main__':
248 if __name__ == '__main__':
249 setup(**setup_args)
249 setup(**setup_args)
250 cleanup()
250 cleanup()
@@ -1,379 +1,374 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.validate')
122 add_package(packages, 'external.validate')
123 add_package(packages, 'kernel')
123 add_package(packages, 'frontend')
124 add_package(packages, 'frontend')
124 add_package(packages, 'frontend.qt')
125 add_package(packages, 'frontend.qt')
125 add_package(packages, 'frontend.qt.console', tests=True)
126 add_package(packages, 'frontend.qt.console', tests=True)
126 add_package(packages, 'frontend.terminal', tests=True)
127 add_package(packages, 'frontend.terminal', tests=True)
127 add_package(packages, 'lib', tests=True)
128 add_package(packages, 'lib', tests=True)
128 add_package(packages, 'quarantine', tests=True)
129 add_package(packages, 'quarantine', tests=True)
129 add_package(packages, 'scripts')
130 add_package(packages, 'scripts')
130 add_package(packages, 'testing', tests=True)
131 add_package(packages, 'testing', tests=True)
131 add_package(packages, 'testing.plugin', tests=False)
132 add_package(packages, 'testing.plugin', tests=False)
132 add_package(packages, 'utils', tests=True)
133 add_package(packages, 'utils', tests=True)
133 add_package(packages, 'zmq')
134 add_package(packages, 'zmq')
134 add_package(packages, 'zmq.pylab')
135 add_package(packages, 'zmq.pylab')
135 return packages
136 return packages
136
137
137 #---------------------------------------------------------------------------
138 #---------------------------------------------------------------------------
138 # Find package data
139 # Find package data
139 #---------------------------------------------------------------------------
140 #---------------------------------------------------------------------------
140
141
141 def find_package_data():
142 def find_package_data():
142 """
143 """
143 Find IPython's package_data.
144 Find IPython's package_data.
144 """
145 """
145 # This is not enough for these things to appear in an sdist.
146 # This is not enough for these things to appear in an sdist.
146 # We need to muck with the MANIFEST to get this to work
147 # We need to muck with the MANIFEST to get this to work
147 package_data = {
148 package_data = {
148 'IPython.config.userconfig' : ['*'],
149 'IPython.config.userconfig' : ['*'],
149 'IPython.testing' : ['*.txt']
150 'IPython.testing' : ['*.txt']
150 }
151 }
151 return package_data
152 return package_data
152
153
153
154
154 #---------------------------------------------------------------------------
155 #---------------------------------------------------------------------------
155 # Find data files
156 # Find data files
156 #---------------------------------------------------------------------------
157 #---------------------------------------------------------------------------
157
158
158 def make_dir_struct(tag,base,out_base):
159 def make_dir_struct(tag,base,out_base):
159 """Make the directory structure of all files below a starting dir.
160 """Make the directory structure of all files below a starting dir.
160
161
161 This is just a convenience routine to help build a nested directory
162 This is just a convenience routine to help build a nested directory
162 hierarchy because distutils is too stupid to do this by itself.
163 hierarchy because distutils is too stupid to do this by itself.
163
164
164 XXX - this needs a proper docstring!
165 XXX - this needs a proper docstring!
165 """
166 """
166
167
167 # we'll use these a lot below
168 # we'll use these a lot below
168 lbase = len(base)
169 lbase = len(base)
169 pathsep = os.path.sep
170 pathsep = os.path.sep
170 lpathsep = len(pathsep)
171 lpathsep = len(pathsep)
171
172
172 out = []
173 out = []
173 for (dirpath,dirnames,filenames) in os.walk(base):
174 for (dirpath,dirnames,filenames) in os.walk(base):
174 # we need to strip out the dirpath from the base to map it to the
175 # we need to strip out the dirpath from the base to map it to the
175 # output (installation) path. This requires possibly stripping the
176 # output (installation) path. This requires possibly stripping the
176 # path separator, because otherwise pjoin will not work correctly
177 # path separator, because otherwise pjoin will not work correctly
177 # (pjoin('foo/','/bar') returns '/bar').
178 # (pjoin('foo/','/bar') returns '/bar').
178
179
179 dp_eff = dirpath[lbase:]
180 dp_eff = dirpath[lbase:]
180 if dp_eff.startswith(pathsep):
181 if dp_eff.startswith(pathsep):
181 dp_eff = dp_eff[lpathsep:]
182 dp_eff = dp_eff[lpathsep:]
182 # The output path must be anchored at the out_base marker
183 # The output path must be anchored at the out_base marker
183 out_path = pjoin(out_base,dp_eff)
184 out_path = pjoin(out_base,dp_eff)
184 # Now we can generate the final filenames. Since os.walk only produces
185 # Now we can generate the final filenames. Since os.walk only produces
185 # filenames, we must join back with the dirpath to get full valid file
186 # filenames, we must join back with the dirpath to get full valid file
186 # paths:
187 # paths:
187 pfiles = [pjoin(dirpath,f) for f in filenames]
188 pfiles = [pjoin(dirpath,f) for f in filenames]
188 # Finally, generate the entry we need, which is a pari of (output
189 # Finally, generate the entry we need, which is a pari of (output
189 # path, files) for use as a data_files parameter in install_data.
190 # path, files) for use as a data_files parameter in install_data.
190 out.append((out_path, pfiles))
191 out.append((out_path, pfiles))
191
192
192 return out
193 return out
193
194
194
195
195 def find_data_files():
196 def find_data_files():
196 """
197 """
197 Find IPython's data_files.
198 Find IPython's data_files.
198
199
199 Most of these are docs.
200 Most of these are docs.
200 """
201 """
201
202
202 docdirbase = pjoin('share', 'doc', 'ipython')
203 docdirbase = pjoin('share', 'doc', 'ipython')
203 manpagebase = pjoin('share', 'man', 'man1')
204 manpagebase = pjoin('share', 'man', 'man1')
204
205
205 # Simple file lists can be made by hand
206 # Simple file lists can be made by hand
206 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
207 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
207 igridhelpfiles = filter(isfile,
208 igridhelpfiles = filter(isfile,
208 glob(pjoin('IPython','extensions','igrid_help.*')))
209 glob(pjoin('IPython','extensions','igrid_help.*')))
209
210
210 # For nested structures, use the utility above
211 # For nested structures, use the utility above
211 example_files = make_dir_struct(
212 example_files = make_dir_struct(
212 'data',
213 'data',
213 pjoin('docs','examples'),
214 pjoin('docs','examples'),
214 pjoin(docdirbase,'examples')
215 pjoin(docdirbase,'examples')
215 )
216 )
216 manual_files = make_dir_struct(
217 manual_files = make_dir_struct(
217 'data',
218 'data',
218 pjoin('docs','dist'),
219 pjoin('docs','dist'),
219 pjoin(docdirbase,'manual')
220 pjoin(docdirbase,'manual')
220 )
221 )
221
222
222 # And assemble the entire output list
223 # And assemble the entire output list
223 data_files = [ (manpagebase, manpages),
224 data_files = [ (manpagebase, manpages),
224 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
225 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
225 ] + manual_files + example_files
226 ] + manual_files + example_files
226
227
227 return data_files
228 return data_files
228
229
229
230
230 def make_man_update_target(manpage):
231 def make_man_update_target(manpage):
231 """Return a target_update-compliant tuple for the given manpage.
232 """Return a target_update-compliant tuple for the given manpage.
232
233
233 Parameters
234 Parameters
234 ----------
235 ----------
235 manpage : string
236 manpage : string
236 Name of the manpage, must include the section number (trailing number).
237 Name of the manpage, must include the section number (trailing number).
237
238
238 Example
239 Example
239 -------
240 -------
240
241
241 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
242 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
242 ('docs/man/ipython.1.gz',
243 ('docs/man/ipython.1.gz',
243 ['docs/man/ipython.1'],
244 ['docs/man/ipython.1'],
244 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
245 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
245 """
246 """
246 man_dir = pjoin('docs', 'man')
247 man_dir = pjoin('docs', 'man')
247 manpage_gz = manpage + '.gz'
248 manpage_gz = manpage + '.gz'
248 manpath = pjoin(man_dir, manpage)
249 manpath = pjoin(man_dir, manpage)
249 manpath_gz = pjoin(man_dir, manpage_gz)
250 manpath_gz = pjoin(man_dir, manpage_gz)
250 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
251 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
251 locals() )
252 locals() )
252 return (manpath_gz, [manpath], gz_cmd)
253 return (manpath_gz, [manpath], gz_cmd)
253
254
254 #---------------------------------------------------------------------------
255 #---------------------------------------------------------------------------
255 # Find scripts
256 # Find scripts
256 #---------------------------------------------------------------------------
257 #---------------------------------------------------------------------------
257
258
258 def find_scripts():
259 def find_scripts():
259 """
260 """
260 Find IPython's scripts.
261 Find IPython's scripts.
261 """
262 """
262 kernel_scripts = pjoin('IPython','kernel','scripts')
263 # kernel_scripts = pjoin('IPython','kernel','scripts')
263 main_scripts = pjoin('IPython','scripts')
264 main_scripts = pjoin('IPython','scripts')
264 scripts = [pjoin(kernel_scripts, 'ipengine'),
265 scripts = [# pjoin(kernel_scripts, 'ipengine'),
265 pjoin(kernel_scripts, 'ipcontroller'),
266 # pjoin(kernel_scripts, 'ipcontroller'),
266 pjoin(kernel_scripts, 'ipcluster'),
267 # pjoin(kernel_scripts, 'ipcluster'),
267 pjoin(main_scripts, 'ipython'),
268 pjoin(main_scripts, 'ipython'),
268 pjoin(main_scripts, 'ipython-qtconsole'),
269 pjoin(main_scripts, 'ipython-qtconsole'),
269 pjoin(main_scripts, 'pycolor'),
270 pjoin(main_scripts, 'pycolor'),
270 pjoin(main_scripts, 'irunner'),
271 pjoin(main_scripts, 'irunner'),
271 pjoin(main_scripts, 'iptest')
272 pjoin(main_scripts, 'iptest')
272 ]
273 ]
273
274
274 # Script to be run by the windows binary installer after the default setup
275 # Script to be run by the windows binary installer after the default setup
275 # routine, to add shortcuts and similar windows-only things. Windows
276 # routine, to add shortcuts and similar windows-only things. Windows
276 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
277 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
277 # doesn't find them.
278 # doesn't find them.
278 if 'bdist_wininst' in sys.argv:
279 if 'bdist_wininst' in sys.argv:
279 if len(sys.argv) > 2 and \
280 if len(sys.argv) > 2 and \
280 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
281 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
281 print("ERROR: bdist_wininst must be run alone. Exiting.",
282 print("ERROR: bdist_wininst must be run alone. Exiting.",
282 file=sys.stderr)
283 file=sys.stderr)
283 sys.exit(1)
284 sys.exit(1)
284 scripts.append(pjoin('scripts','ipython_win_post_install.py'))
285 scripts.append(pjoin('scripts','ipython_win_post_install.py'))
285
286
286 return scripts
287 return scripts
287
288
288 #---------------------------------------------------------------------------
289 #---------------------------------------------------------------------------
289 # Verify all dependencies
290 # Verify all dependencies
290 #---------------------------------------------------------------------------
291 #---------------------------------------------------------------------------
291
292
292 def check_for_dependencies():
293 def check_for_dependencies():
293 """Check for IPython's dependencies.
294 """Check for IPython's dependencies.
294
295
295 This function should NOT be called if running under setuptools!
296 This function should NOT be called if running under setuptools!
296 """
297 """
297 from setupext.setupext import (
298 from setupext.setupext import (
298 print_line, print_raw, print_status,
299 print_line, print_raw, print_status,
299 check_for_zopeinterface, check_for_twisted,
300 check_for_foolscap, check_for_pyopenssl,
301 check_for_sphinx, check_for_pygments,
300 check_for_sphinx, check_for_pygments,
302 check_for_nose, check_for_pexpect
301 check_for_nose, check_for_pexpect
303 )
302 )
304 print_line()
303 print_line()
305 print_raw("BUILDING IPYTHON")
304 print_raw("BUILDING IPYTHON")
306 print_status('python', sys.version)
305 print_status('python', sys.version)
307 print_status('platform', sys.platform)
306 print_status('platform', sys.platform)
308 if sys.platform == 'win32':
307 if sys.platform == 'win32':
309 print_status('Windows version', sys.getwindowsversion())
308 print_status('Windows version', sys.getwindowsversion())
310
309
311 print_raw("")
310 print_raw("")
312 print_raw("OPTIONAL DEPENDENCIES")
311 print_raw("OPTIONAL DEPENDENCIES")
313
312
314 check_for_zopeinterface()
315 check_for_twisted()
316 check_for_foolscap()
317 check_for_pyopenssl()
318 check_for_sphinx()
313 check_for_sphinx()
319 check_for_pygments()
314 check_for_pygments()
320 check_for_nose()
315 check_for_nose()
321 check_for_pexpect()
316 check_for_pexpect()
322
317
323
318
324 def record_commit_info(pkg_dir, build_cmd=build_py):
319 def record_commit_info(pkg_dir, build_cmd=build_py):
325 """ Return extended build command class for recording commit
320 """ Return extended build command class for recording commit
326
321
327 The extended command tries to run git to find the current commit, getting
322 The extended command tries to run git to find the current commit, getting
328 the empty string if it fails. It then writes the commit hash into a file
323 the empty string if it fails. It then writes the commit hash into a file
329 in the `pkg_dir` path, named ``.git_commit_info.ini``.
324 in the `pkg_dir` path, named ``.git_commit_info.ini``.
330
325
331 In due course this information can be used by the package after it is
326 In due course this information can be used by the package after it is
332 installed, to tell you what commit it was installed from if known.
327 installed, to tell you what commit it was installed from if known.
333
328
334 To make use of this system, you need a package with a .git_commit_info.ini
329 To make use of this system, you need a package with a .git_commit_info.ini
335 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
330 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
336 this::
331 this::
337
332
338 # This is an ini file that may contain information about the code state
333 # This is an ini file that may contain information about the code state
339 [commit hash]
334 [commit hash]
340 # The line below may contain a valid hash if it has been substituted
335 # The line below may contain a valid hash if it has been substituted
341 # during 'git archive'
336 # during 'git archive'
342 archive_subst_hash=$Format:%h$
337 archive_subst_hash=$Format:%h$
343 # This line may be modified by the install process
338 # This line may be modified by the install process
344 install_hash=
339 install_hash=
345
340
346 The .git_commit_info file above is also designed to be used with git
341 The .git_commit_info file above is also designed to be used with git
347 substitution - so you probably also want a ``.gitattributes`` file in the
342 substitution - so you probably also want a ``.gitattributes`` file in the
348 root directory of your working tree that contains something like this::
343 root directory of your working tree that contains something like this::
349
344
350 myproject/.git_commit_info.ini export-subst
345 myproject/.git_commit_info.ini export-subst
351
346
352 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
347 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
353 archive`` - useful in case someone makes such an archive - for example with
348 archive`` - useful in case someone makes such an archive - for example with
354 via the github 'download source' button.
349 via the github 'download source' button.
355
350
356 Although all the above will work as is, you might consider having something
351 Although all the above will work as is, you might consider having something
357 like a ``get_info()`` function in your package to display the commit
352 like a ``get_info()`` function in your package to display the commit
358 information at the terminal. See the ``pkg_info.py`` module in the nipy
353 information at the terminal. See the ``pkg_info.py`` module in the nipy
359 package for an example.
354 package for an example.
360 """
355 """
361 class MyBuildPy(build_cmd):
356 class MyBuildPy(build_cmd):
362 ''' Subclass to write commit data into installation tree '''
357 ''' Subclass to write commit data into installation tree '''
363 def run(self):
358 def run(self):
364 build_py.run(self)
359 build_py.run(self)
365 import subprocess
360 import subprocess
366 proc = subprocess.Popen('git rev-parse --short HEAD',
361 proc = subprocess.Popen('git rev-parse --short HEAD',
367 stdout=subprocess.PIPE,
362 stdout=subprocess.PIPE,
368 stderr=subprocess.PIPE,
363 stderr=subprocess.PIPE,
369 shell=True)
364 shell=True)
370 repo_commit, _ = proc.communicate()
365 repo_commit, _ = proc.communicate()
371 # We write the installation commit even if it's empty
366 # We write the installation commit even if it's empty
372 cfg_parser = ConfigParser()
367 cfg_parser = ConfigParser()
373 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
368 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
374 cfg_parser.set('commit hash', 'install_hash', repo_commit)
369 cfg_parser.set('commit hash', 'install_hash', repo_commit)
375 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
370 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
376 out_file = open(out_pth, 'wt')
371 out_file = open(out_pth, 'wt')
377 cfg_parser.write(out_file)
372 cfg_parser.write(out_file)
378 out_file.close()
373 out_file.close()
379 return MyBuildPy
374 return MyBuildPy
General Comments 0
You need to be logged in to leave comments. Login now