##// END OF EJS Templates
Merge branch 'version-info' into trunk
Fernando Perez -
r3216:133507fb merge
parent child Browse files
Show More
@@ -0,0 +1,1
1 IPython/.git_commit_info.ini export-subst
@@ -0,0 +1,9
1 # This is an ini file that may contain information about the code state
2 [commit hash]
3
4 # The line below may contain a valid hash if it has been substituted during
5 # 'git archive'
6 archive_subst_hash=$Format:%h$
7
8 # This line may be modified by the install process
9 install_hash=
@@ -1,8 +1,10
1 build
2 ./dist
1 docs/dist
3 docs/dist
2 docs/build/*
4 docs/build/*
3 docs/source/api/generated
5 docs/source/api/generated
4 *.pyc
6 *.py[co]
5 build
7 build
6 *.egg-info
8 *.egg-info
7 *.py~
9 *~
8 *.bak
10 *.bak
@@ -1,77 +1,85
1 IPython is licensed under the terms of the new or revised BSD license, as follows:
1 =============================
2 The IPython licensing terms
3 =============================
2
4
3 Copyright (c) 2008, IPython Development Team
5 IPython is licensed under the terms of the Modified BSD License (also known as
6 New or Revised BSD), as follows:
7
8 Copyright (c) 2008-2010, IPython Development Team
9 Copyright (c) 2001-2007, Fernando Perez. <fernando.perez@colorado.edu>
10 Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
11 Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
4
12
5 All rights reserved.
13 All rights reserved.
6
14
7 Redistribution and use in source and binary forms, with or without modification,
15 Redistribution and use in source and binary forms, with or without
8 are permitted provided that the following conditions are met:
16 modification, are permitted provided that the following conditions are met:
9
17
10 Redistributions of source code must retain the above copyright notice, this list of
18 Redistributions of source code must retain the above copyright notice, this
11 conditions and the following disclaimer.
19 list of conditions and the following disclaimer.
12
20
13 Redistributions in binary form must reproduce the above copyright notice, this list
21 Redistributions in binary form must reproduce the above copyright notice, this
14 of conditions and the following disclaimer in the documentation and/or other
22 list of conditions and the following disclaimer in the documentation and/or
15 materials provided with the distribution.
23 other materials provided with the distribution.
16
24
17 Neither the name of the IPython Development Team nor the names of its contributors
25 Neither the name of the IPython Development Team nor the names of its
18 may be used to endorse or promote products derived from this software without
26 contributors may be used to endorse or promote products derived from this
19 specific prior written permission.
27 software without specific prior written permission.
20
28
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
25 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 POSSIBILITY OF SUCH DAMAGE.
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
39
32 About the IPython Development Team
40 About the IPython Development Team
33 ----------------------------------
41 ----------------------------------
34
42
35 Fernando Perez began IPython in 2001 based on code from Janko Hauser <jhauser@zscout.de>
43 Fernando Perez began IPython in 2001 based on code from Janko Hauser
36 and Nathaniel Gray <n8gray@caltech.edu>. Fernando is still the project lead.
44 <jhauser@zscout.de> and Nathaniel Gray <n8gray@caltech.edu>. Fernando is still
45 the project lead.
46
47 The IPython Development Team is the set of all contributors to the IPython
48 project. This includes all of the IPython subprojects. A full list with
49 details is kept in the documentation directory, in the file
50 ``about/credits.txt``.
37
51
38 The IPython Development Team is the set of all contributors to the IPython project.
52 The core team that coordinates development on GitHub can be found here:
39 This includes all of the IPython subprojects. Here is a list of the currently active contributors:
53 http://github.com/ipython. As of late 2010, it consists of:
40
54
41 * Matthieu Brucher
55 * Brian E. Granger
42 * Ondrej Certik
56 * Jonathan March
43 * Laurent Dufrechou
57 * Evan Patterson
44 * Robert Kern
58 * Fernando Perez
45 * Brian E. Granger
59 * Min Ragan-Kelley
46 * Fernando Perez (project leader)
60 * Robert Kern
47 * Benjamin Ragan-Kelley
48 * Ville M. Vainio
49 * Gael Varoququx
50 * Stefan van der Walt
51 * Tech-X Corporation
52 * Barry Wark
53
61
54 If your name is missing, please add it.
55
62
56 Our Copyright Policy
63 Our Copyright Policy
57 --------------------
64 --------------------
58
65
59 IPython uses a shared copyright model. Each contributor maintains copyright over
66 IPython uses a shared copyright model. Each contributor maintains copyright
60 their contributions to IPython. But, it is important to note that these
67 over their contributions to IPython. But, it is important to note that these
61 contributions are typically only changes to the repositories. Thus, the IPython
68 contributions are typically only changes to the repositories. Thus, the IPython
62 source code, in its entirety is not the copyright of any single person or
69 source code, in its entirety is not the copyright of any single person or
63 institution. Instead, it is the collective copyright of the entire IPython
70 institution. Instead, it is the collective copyright of the entire IPython
64 Development Team. If individual contributors want to maintain a record of what
71 Development Team. If individual contributors want to maintain a record of what
65 changes/contributions they have specific copyright on, they should indicate their
72 changes/contributions they have specific copyright on, they should indicate
66 copyright in the commit message of the change, when they commit the change to
73 their copyright in the commit message of the change, when they commit the
67 one of the IPython repositories.
74 change to one of the IPython repositories.
68
75
69 With this in mind, the following banner should be used in any source code file to
76 With this in mind, the following banner should be used in any source code file
70 indicate the copyright and license terms:
77 to indicate the copyright and license terms:
71
78
72 #-------------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
73 # Copyright (C) 2008 The IPython Development Team
80 # Copyright (c) 2010, IPython Development Team.
81 #
82 # Distributed under the terms of the Modified BSD License.
74 #
83 #
75 # Distributed under the terms of the BSD License. The full license is in
84 # The full license is in the file COPYING.txt, distributed with this software.
76 # the file COPYING, distributed as part of this software.
85 #-----------------------------------------------------------------------------
77 #------------------------------------------------------------------------------- No newline at end of file
@@ -1,55 +1,59
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 IPython.
4 IPython.
5
5
6 IPython is a set of tools for interactive and exploratory computing in Python.
6 IPython is a set of tools for interactive and exploratory computing in Python.
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (c) 2008-2010, IPython Development Team.
10 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
11 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
12 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
10 #
13 #
11 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the Modified BSD License.
12 # the file COPYING, distributed as part of this software.
15 #
16 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
14
18
15 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
16 # Imports
20 # Imports
17 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
18 from __future__ import absolute_import
22 from __future__ import absolute_import
19
23
20 import os
24 import os
21 import sys
25 import sys
22
26
23 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
24 # Setup everything
28 # Setup everything
25 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
26
30
27 # Don't forget to also update setup.py when this changes!
31 # Don't forget to also update setup.py when this changes!
28 if sys.version[0:3] < '2.6':
32 if sys.version[0:3] < '2.6':
29 raise ImportError('Python Version 2.6 or above is required for IPython.')
33 raise ImportError('Python Version 2.6 or above is required for IPython.')
30
34
31
35
32 # Make it easy to import extensions - they are always directly on pythonpath.
36 # Make it easy to import extensions - they are always directly on pythonpath.
33 # Therefore, non-IPython modules can be added to extensions directory.
37 # Therefore, non-IPython modules can be added to extensions directory.
34 # This should probably be in ipapp.py.
38 # This should probably be in ipapp.py.
35 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
39 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
36
40
37 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
38 # Setup the top level names
42 # Setup the top level names
39 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
40
44
41 from .config.loader import Config
45 from .config.loader import Config
42 from .core import release
46 from .core import release
43 from .core.application import Application
47 from .core.application import Application
44 from .frontend.terminal.embed import embed
48 from .frontend.terminal.embed import embed
45 from .core.error import TryNext
49 from .core.error import TryNext
46 from .core.interactiveshell import InteractiveShell
50 from .core.interactiveshell import InteractiveShell
47 from .testing import test
51 from .testing import test
52 from .utils.sysinfo import sys_info
48
53
49 # Release data
54 # Release data
50 __author__ = ''
55 __author__ = ''
51 for author, email in release.authors.itervalues():
56 for author, email in release.authors.itervalues():
52 __author__ += author + ' <' + email + '>\n'
57 __author__ += author + ' <' + email + '>\n'
53 __license__ = release.license
58 __license__ = release.license
54 __version__ = release.version
59 __version__ = release.version
55 __revision__ = release.revision
@@ -1,122 +1,123
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Release data for the IPython project."""
2 """Release data for the IPython project."""
3
3
4 #*****************************************************************************
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2009 The IPython Development Team
5 # Copyright (c) 2008-2010, IPython Development Team.
6 # Copyright (C) 2001-2008 Fernando Perez <fperez@colorado.edu>
6 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
7 # Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and Nathaniel Gray
7 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
8 # <n8gray@caltech.edu>
8 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the Modified BSD License.
11 # the file COPYING, distributed as part of this software.
11 #
12 #*****************************************************************************
12 # The full license is in the file COPYING.txt, distributed with this software.
13 #-----------------------------------------------------------------------------
13
14
14 # Name of the package for release purposes. This is the name which labels
15 # Name of the package for release purposes. This is the name which labels
15 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
16 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
16 name = 'ipython'
17 name = 'ipython'
17
18
18 # For versions with substrings (like 0.6.16.svn), use an extra . to separate
19 # IPython version information. An empty _version_extra corresponds to a full
19 # the new substring. We have to avoid using either dashes or underscores,
20 # release. 'dev' as a _version_extra string means this is a development
20 # because bdist_rpm does not accept dashes (an RPM) convention, and
21 # version
21 # bdist_deb does not accept underscores (a Debian convention).
22 _version_major = 0
23 _version_minor = 11
24 _version_micro = '' # use '' for first of series, number for 1 and above
25 _version_extra = 'dev'
26 #_version_extra = '' # Uncomment this for full releases
22
27
23 development = True # change this to False to do a release
28 # Construct full version string from these.
24 version_base = '0.11.alpha1'
29 _ver = [_version_major, _version_minor]
25 branch = 'ipython'
30 if _version_micro:
26 # This needs to be updated to something that is meaningful for git
31 _ver.append(_version_micro)
27 revision = '0'
32 if _version_extra:
33 _ver.append(_version_extra)
28
34
29 if development:
35 __version__ = '.'.join(map(str, _ver))
30 if branch == 'ipython':
31 version = '%s.git' % (version_base)
32 else:
33 version = '%s.git.%s' % (version_base, branch)
34 else:
35 version = version_base
36
36
37 version = __version__ # backwards compatibility name
37
38
38 description = "An interactive computing environment for Python"
39 description = "An interactive computing environment for Python"
39
40
40 long_description = \
41 long_description = \
41 """
42 """
42 The goal of IPython is to create a comprehensive environment for
43 The goal of IPython is to create a comprehensive environment for
43 interactive and exploratory computing. To support this goal, IPython
44 interactive and exploratory computing. To support this goal, IPython
44 has two main components:
45 has two main components:
45
46
46 * An enhanced interactive Python shell.
47 * An enhanced interactive Python shell.
47
48
48 * An architecture for interactive parallel computing.
49 * An architecture for interactive parallel computing.
49
50
50 The enhanced interactive Python shell has the following main features:
51 The enhanced interactive Python shell has the following main features:
51
52
52 * Comprehensive object introspection.
53 * Comprehensive object introspection.
53
54
54 * Input history, persistent across sessions.
55 * Input history, persistent across sessions.
55
56
56 * Caching of output results during a session with automatically generated
57 * Caching of output results during a session with automatically generated
57 references.
58 references.
58
59
59 * Readline based name completion.
60 * Readline based name completion.
60
61
61 * Extensible system of 'magic' commands for controlling the environment and
62 * Extensible system of 'magic' commands for controlling the environment and
62 performing many tasks related either to IPython or the operating system.
63 performing many tasks related either to IPython or the operating system.
63
64
64 * Configuration system with easy switching between different setups (simpler
65 * Configuration system with easy switching between different setups (simpler
65 than changing $PYTHONSTARTUP environment variables every time).
66 than changing $PYTHONSTARTUP environment variables every time).
66
67
67 * Session logging and reloading.
68 * Session logging and reloading.
68
69
69 * Extensible syntax processing for special purpose situations.
70 * Extensible syntax processing for special purpose situations.
70
71
71 * Access to the system shell with user-extensible alias system.
72 * Access to the system shell with user-extensible alias system.
72
73
73 * Easily embeddable in other Python programs and wxPython GUIs.
74 * Easily embeddable in other Python programs and wxPython GUIs.
74
75
75 * Integrated access to the pdb debugger and the Python profiler.
76 * Integrated access to the pdb debugger and the Python profiler.
76
77
77 The parallel computing architecture has the following main features:
78 The parallel computing architecture has the following main features:
78
79
79 * Quickly parallelize Python code from an interactive Python/IPython session.
80 * Quickly parallelize Python code from an interactive Python/IPython session.
80
81
81 * A flexible and dynamic process model that be deployed on anything from
82 * A flexible and dynamic process model that be deployed on anything from
82 multicore workstations to supercomputers.
83 multicore workstations to supercomputers.
83
84
84 * An architecture that supports many different styles of parallelism, from
85 * An architecture that supports many different styles of parallelism, from
85 message passing to task farming.
86 message passing to task farming.
86
87
87 * Both blocking and fully asynchronous interfaces.
88 * Both blocking and fully asynchronous interfaces.
88
89
89 * High level APIs that enable many things to be parallelized in a few lines
90 * High level APIs that enable many things to be parallelized in a few lines
90 of code.
91 of code.
91
92
92 * Share live parallel jobs with other users securely.
93 * Share live parallel jobs with other users securely.
93
94
94 * Dynamically load balanced task farming system.
95 * Dynamically load balanced task farming system.
95
96
96 * Robust error handling in parallel code.
97 * Robust error handling in parallel code.
97
98
98 The latest development version is always available from IPython's `Launchpad
99 The latest development version is always available from IPython's `GitHub
99 site <http://launchpad.net/ipython>`_.
100 site <http://github.com/ipython>`_.
100 """
101 """
101
102
102 license = 'BSD'
103 license = 'BSD'
103
104
104 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
105 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
105 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
106 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
106 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
107 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
107 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
108 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
108 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
109 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
109 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com')
110 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com')
110 }
111 }
111
112
112 author = 'The IPython Development Team'
113 author = 'The IPython Development Team'
113
114
114 author_email = 'ipython-dev@scipy.org'
115 author_email = 'ipython-dev@scipy.org'
115
116
116 url = 'http://ipython.scipy.org'
117 url = 'http://ipython.scipy.org'
117
118
118 download_url = 'http://ipython.scipy.org/dist'
119 download_url = 'http://ipython.scipy.org/dist'
119
120
120 platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME']
121 platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME']
121
122
122 keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed']
123 keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed']
@@ -1,665 +1,664
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.application.Application` object for the command
4 The :class:`~IPython.core.application.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 """
12 """
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2008-2010 The IPython Development Team
15 # Copyright (C) 2008-2010 The IPython Development Team
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 from __future__ import absolute_import
25 from __future__ import absolute_import
26
26
27 import logging
27 import logging
28 import os
28 import os
29 import sys
29 import sys
30
30
31 from IPython.core import release
31 from IPython.core import release
32 from IPython.core.crashhandler import CrashHandler
32 from IPython.core.crashhandler import CrashHandler
33 from IPython.core.application import Application, BaseAppConfigLoader
33 from IPython.core.application import Application, BaseAppConfigLoader
34 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
34 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
35 from IPython.config.loader import (
35 from IPython.config.loader import (
36 Config,
36 Config,
37 PyFileConfigLoader
37 PyFileConfigLoader
38 )
38 )
39 from IPython.lib import inputhook
39 from IPython.lib import inputhook
40 from IPython.utils.path import filefind, get_ipython_dir
40 from IPython.utils.path import filefind, get_ipython_dir
41 from IPython.core import usage
41 from IPython.core import usage
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Globals, utilities and helpers
44 # Globals, utilities and helpers
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 #: The default config file name for this application.
47 #: The default config file name for this application.
48 default_config_file_name = u'ipython_config.py'
48 default_config_file_name = u'ipython_config.py'
49
49
50
50
51 class IPAppConfigLoader(BaseAppConfigLoader):
51 class IPAppConfigLoader(BaseAppConfigLoader):
52
52
53 def _add_arguments(self):
53 def _add_arguments(self):
54 super(IPAppConfigLoader, self)._add_arguments()
54 super(IPAppConfigLoader, self)._add_arguments()
55 paa = self.parser.add_argument
55 paa = self.parser.add_argument
56 paa('-p',
56 paa('-p',
57 '--profile', dest='Global.profile', type=unicode,
57 '--profile', dest='Global.profile', type=unicode,
58 help=
58 help=
59 """The string name of the ipython profile to be used. Assume that your
59 """The string name of the ipython profile to be used. Assume that your
60 config file is ipython_config-<name>.py (looks in current dir first,
60 config file is ipython_config-<name>.py (looks in current dir first,
61 then in IPYTHON_DIR). This is a quick way to keep and load multiple
61 then in IPYTHON_DIR). This is a quick way to keep and load multiple
62 config files for different tasks, especially if include your basic one
62 config files for different tasks, especially if include your basic one
63 in your more specialized ones. You can keep a basic
63 in your more specialized ones. You can keep a basic
64 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
64 IPYTHON_DIR/ipython_config.py file and then have other 'profiles' which
65 include this one and load extra things for particular tasks.""",
65 include this one and load extra things for particular tasks.""",
66 metavar='Global.profile')
66 metavar='Global.profile')
67 paa('--config-file',
67 paa('--config-file',
68 dest='Global.config_file', type=unicode,
68 dest='Global.config_file', type=unicode,
69 help=
69 help=
70 """Set the config file name to override default. Normally IPython
70 """Set the config file name to override default. Normally IPython
71 loads ipython_config.py (from current directory) or
71 loads ipython_config.py (from current directory) or
72 IPYTHON_DIR/ipython_config.py. If the loading of your config file
72 IPYTHON_DIR/ipython_config.py. If the loading of your config file
73 fails, IPython starts with a bare bones configuration (no modules
73 fails, IPython starts with a bare bones configuration (no modules
74 loaded at all).""",
74 loaded at all).""",
75 metavar='Global.config_file')
75 metavar='Global.config_file')
76 paa('--autocall',
76 paa('--autocall',
77 dest='InteractiveShell.autocall', type=int,
77 dest='InteractiveShell.autocall', type=int,
78 help=
78 help=
79 """Make IPython automatically call any callable object even if you
79 """Make IPython automatically call any callable object even if you
80 didn't type explicit parentheses. For example, 'str 43' becomes
80 didn't type explicit parentheses. For example, 'str 43' becomes
81 'str(43)' automatically. The value can be '0' to disable the feature,
81 'str(43)' automatically. The value can be '0' to disable the feature,
82 '1' for 'smart' autocall, where it is not applied if there are no more
82 '1' for 'smart' autocall, where it is not applied if there are no more
83 arguments on the line, and '2' for 'full' autocall, where all callable
83 arguments on the line, and '2' for 'full' autocall, where all callable
84 objects are automatically called (even if no arguments are present).
84 objects are automatically called (even if no arguments are present).
85 The default is '1'.""",
85 The default is '1'.""",
86 metavar='InteractiveShell.autocall')
86 metavar='InteractiveShell.autocall')
87 paa('--autoindent',
87 paa('--autoindent',
88 action='store_true', dest='InteractiveShell.autoindent',
88 action='store_true', dest='InteractiveShell.autoindent',
89 help='Turn on autoindenting.')
89 help='Turn on autoindenting.')
90 paa('--no-autoindent',
90 paa('--no-autoindent',
91 action='store_false', dest='InteractiveShell.autoindent',
91 action='store_false', dest='InteractiveShell.autoindent',
92 help='Turn off autoindenting.')
92 help='Turn off autoindenting.')
93 paa('--automagic',
93 paa('--automagic',
94 action='store_true', dest='InteractiveShell.automagic',
94 action='store_true', dest='InteractiveShell.automagic',
95 help=
95 help=
96 """Turn on the auto calling of magic commands. Type %%magic at the
96 """Turn on the auto calling of magic commands. Type %%magic at the
97 IPython prompt for more information.""")
97 IPython prompt for more information.""")
98 paa('--no-automagic',
98 paa('--no-automagic',
99 action='store_false', dest='InteractiveShell.automagic',
99 action='store_false', dest='InteractiveShell.automagic',
100 help='Turn off the auto calling of magic commands.')
100 help='Turn off the auto calling of magic commands.')
101 paa('--autoedit-syntax',
101 paa('--autoedit-syntax',
102 action='store_true', dest='TerminalInteractiveShell.autoedit_syntax',
102 action='store_true', dest='TerminalInteractiveShell.autoedit_syntax',
103 help='Turn on auto editing of files with syntax errors.')
103 help='Turn on auto editing of files with syntax errors.')
104 paa('--no-autoedit-syntax',
104 paa('--no-autoedit-syntax',
105 action='store_false', dest='TerminalInteractiveShell.autoedit_syntax',
105 action='store_false', dest='TerminalInteractiveShell.autoedit_syntax',
106 help='Turn off auto editing of files with syntax errors.')
106 help='Turn off auto editing of files with syntax errors.')
107 paa('--banner',
107 paa('--banner',
108 action='store_true', dest='Global.display_banner',
108 action='store_true', dest='Global.display_banner',
109 help='Display a banner upon starting IPython.')
109 help='Display a banner upon starting IPython.')
110 paa('--no-banner',
110 paa('--no-banner',
111 action='store_false', dest='Global.display_banner',
111 action='store_false', dest='Global.display_banner',
112 help="Don't display a banner upon starting IPython.")
112 help="Don't display a banner upon starting IPython.")
113 paa('--cache-size',
113 paa('--cache-size',
114 type=int, dest='InteractiveShell.cache_size',
114 type=int, dest='InteractiveShell.cache_size',
115 help=
115 help=
116 """Set the size of the output cache. The default is 1000, you can
116 """Set the size of the output cache. The default is 1000, you can
117 change it permanently in your config file. Setting it to 0 completely
117 change it permanently in your config file. Setting it to 0 completely
118 disables the caching system, and the minimum value accepted is 20 (if
118 disables the caching system, and the minimum value accepted is 20 (if
119 you provide a value less than 20, it is reset to 0 and a warning is
119 you provide a value less than 20, it is reset to 0 and a warning is
120 issued). This limit is defined because otherwise you'll spend more
120 issued). This limit is defined because otherwise you'll spend more
121 time re-flushing a too small cache than working""",
121 time re-flushing a too small cache than working""",
122 metavar='InteractiveShell.cache_size')
122 metavar='InteractiveShell.cache_size')
123 paa('--classic',
123 paa('--classic',
124 action='store_true', dest='Global.classic',
124 action='store_true', dest='Global.classic',
125 help="Gives IPython a similar feel to the classic Python prompt.")
125 help="Gives IPython a similar feel to the classic Python prompt.")
126 paa('--colors',
126 paa('--colors',
127 type=str, dest='InteractiveShell.colors',
127 type=str, dest='InteractiveShell.colors',
128 help="Set the color scheme (NoColor, Linux, and LightBG).",
128 help="Set the color scheme (NoColor, Linux, and LightBG).",
129 metavar='InteractiveShell.colors')
129 metavar='InteractiveShell.colors')
130 paa('--color-info',
130 paa('--color-info',
131 action='store_true', dest='InteractiveShell.color_info',
131 action='store_true', dest='InteractiveShell.color_info',
132 help=
132 help=
133 """IPython can display information about objects via a set of func-
133 """IPython can display information about objects via a set of func-
134 tions, and optionally can use colors for this, syntax highlighting
134 tions, and optionally can use colors for this, syntax highlighting
135 source code and various other elements. However, because this
135 source code and various other elements. However, because this
136 information is passed through a pager (like 'less') and many pagers get
136 information is passed through a pager (like 'less') and many pagers get
137 confused with color codes, this option is off by default. You can test
137 confused with color codes, this option is off by default. You can test
138 it and turn it on permanently in your ipython_config.py file if it
138 it and turn it on permanently in your ipython_config.py file if it
139 works for you. Test it and turn it on permanently if it works with
139 works for you. Test it and turn it on permanently if it works with
140 your system. The magic function %%color_info allows you to toggle this
140 your system. The magic function %%color_info allows you to toggle this
141 inter- actively for testing.""")
141 inter- actively for testing.""")
142 paa('--no-color-info',
142 paa('--no-color-info',
143 action='store_false', dest='InteractiveShell.color_info',
143 action='store_false', dest='InteractiveShell.color_info',
144 help="Disable using colors for info related things.")
144 help="Disable using colors for info related things.")
145 paa('--confirm-exit',
145 paa('--confirm-exit',
146 action='store_true', dest='TerminalInteractiveShell.confirm_exit',
146 action='store_true', dest='TerminalInteractiveShell.confirm_exit',
147 help=
147 help=
148 """Set to confirm when you try to exit IPython with an EOF (Control-D
148 """Set to confirm when you try to exit IPython with an EOF (Control-D
149 in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or
149 in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or
150 '%%Exit', you can force a direct exit without any confirmation.""")
150 '%%Exit', you can force a direct exit without any confirmation.""")
151 paa('--no-confirm-exit',
151 paa('--no-confirm-exit',
152 action='store_false', dest='TerminalInteractiveShell.confirm_exit',
152 action='store_false', dest='TerminalInteractiveShell.confirm_exit',
153 help="Don't prompt the user when exiting.")
153 help="Don't prompt the user when exiting.")
154 paa('--deep-reload',
154 paa('--deep-reload',
155 action='store_true', dest='InteractiveShell.deep_reload',
155 action='store_true', dest='InteractiveShell.deep_reload',
156 help=
156 help=
157 """Enable deep (recursive) reloading by default. IPython can use the
157 """Enable deep (recursive) reloading by default. IPython can use the
158 deep_reload module which reloads changes in modules recursively (it
158 deep_reload module which reloads changes in modules recursively (it
159 replaces the reload() function, so you don't need to change anything to
159 replaces the reload() function, so you don't need to change anything to
160 use it). deep_reload() forces a full reload of modules whose code may
160 use it). deep_reload() forces a full reload of modules whose code may
161 have changed, which the default reload() function does not. When
161 have changed, which the default reload() function does not. When
162 deep_reload is off, IPython will use the normal reload(), but
162 deep_reload is off, IPython will use the normal reload(), but
163 deep_reload will still be available as dreload(). This fea- ture is off
163 deep_reload will still be available as dreload(). This fea- ture is off
164 by default [which means that you have both normal reload() and
164 by default [which means that you have both normal reload() and
165 dreload()].""")
165 dreload()].""")
166 paa('--no-deep-reload',
166 paa('--no-deep-reload',
167 action='store_false', dest='InteractiveShell.deep_reload',
167 action='store_false', dest='InteractiveShell.deep_reload',
168 help="Disable deep (recursive) reloading by default.")
168 help="Disable deep (recursive) reloading by default.")
169 paa('--editor',
169 paa('--editor',
170 type=str, dest='TerminalInteractiveShell.editor',
170 type=str, dest='TerminalInteractiveShell.editor',
171 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
171 help="Set the editor used by IPython (default to $EDITOR/vi/notepad).",
172 metavar='TerminalInteractiveShell.editor')
172 metavar='TerminalInteractiveShell.editor')
173 paa('--log','-l',
173 paa('--log','-l',
174 action='store_true', dest='InteractiveShell.logstart',
174 action='store_true', dest='InteractiveShell.logstart',
175 help="Start logging to the default log file (./ipython_log.py).")
175 help="Start logging to the default log file (./ipython_log.py).")
176 paa('--logfile','-lf',
176 paa('--logfile','-lf',
177 type=unicode, dest='InteractiveShell.logfile',
177 type=unicode, dest='InteractiveShell.logfile',
178 help="Start logging to logfile with this name.",
178 help="Start logging to logfile with this name.",
179 metavar='InteractiveShell.logfile')
179 metavar='InteractiveShell.logfile')
180 paa('--log-append','-la',
180 paa('--log-append','-la',
181 type=unicode, dest='InteractiveShell.logappend',
181 type=unicode, dest='InteractiveShell.logappend',
182 help="Start logging to the given file in append mode.",
182 help="Start logging to the given file in append mode.",
183 metavar='InteractiveShell.logfile')
183 metavar='InteractiveShell.logfile')
184 paa('--pdb',
184 paa('--pdb',
185 action='store_true', dest='InteractiveShell.pdb',
185 action='store_true', dest='InteractiveShell.pdb',
186 help="Enable auto calling the pdb debugger after every exception.")
186 help="Enable auto calling the pdb debugger after every exception.")
187 paa('--no-pdb',
187 paa('--no-pdb',
188 action='store_false', dest='InteractiveShell.pdb',
188 action='store_false', dest='InteractiveShell.pdb',
189 help="Disable auto calling the pdb debugger after every exception.")
189 help="Disable auto calling the pdb debugger after every exception.")
190 paa('--pprint',
190 paa('--pprint',
191 action='store_true', dest='InteractiveShell.pprint',
191 action='store_true', dest='InteractiveShell.pprint',
192 help="Enable auto pretty printing of results.")
192 help="Enable auto pretty printing of results.")
193 paa('--no-pprint',
193 paa('--no-pprint',
194 action='store_false', dest='InteractiveShell.pprint',
194 action='store_false', dest='InteractiveShell.pprint',
195 help="Disable auto auto pretty printing of results.")
195 help="Disable auto auto pretty printing of results.")
196 paa('--prompt-in1','-pi1',
196 paa('--prompt-in1','-pi1',
197 type=str, dest='InteractiveShell.prompt_in1',
197 type=str, dest='InteractiveShell.prompt_in1',
198 help=
198 help=
199 """Set the main input prompt ('In [\#]: '). Note that if you are using
199 """Set the main input prompt ('In [\#]: '). Note that if you are using
200 numbered prompts, the number is represented with a '\#' in the string.
200 numbered prompts, the number is represented with a '\#' in the string.
201 Don't forget to quote strings with spaces embedded in them. Most
201 Don't forget to quote strings with spaces embedded in them. Most
202 bash-like escapes can be used to customize IPython's prompts, as well
202 bash-like escapes can be used to customize IPython's prompts, as well
203 as a few additional ones which are IPython-spe- cific. All valid
203 as a few additional ones which are IPython-spe- cific. All valid
204 prompt escapes are described in detail in the Customization section of
204 prompt escapes are described in detail in the Customization section of
205 the IPython manual.""",
205 the IPython manual.""",
206 metavar='InteractiveShell.prompt_in1')
206 metavar='InteractiveShell.prompt_in1')
207 paa('--prompt-in2','-pi2',
207 paa('--prompt-in2','-pi2',
208 type=str, dest='InteractiveShell.prompt_in2',
208 type=str, dest='InteractiveShell.prompt_in2',
209 help=
209 help=
210 """Set the secondary input prompt (' .\D.: '). Similar to the previous
210 """Set the secondary input prompt (' .\D.: '). Similar to the previous
211 option, but used for the continuation prompts. The special sequence
211 option, but used for the continuation prompts. The special sequence
212 '\D' is similar to '\#', but with all digits replaced by dots (so you
212 '\D' is similar to '\#', but with all digits replaced by dots (so you
213 can have your continuation prompt aligned with your input prompt).
213 can have your continuation prompt aligned with your input prompt).
214 Default: ' .\D.: ' (note three spaces at the start for alignment with
214 Default: ' .\D.: ' (note three spaces at the start for alignment with
215 'In [\#]')""",
215 'In [\#]')""",
216 metavar='InteractiveShell.prompt_in2')
216 metavar='InteractiveShell.prompt_in2')
217 paa('--prompt-out','-po',
217 paa('--prompt-out','-po',
218 type=str, dest='InteractiveShell.prompt_out',
218 type=str, dest='InteractiveShell.prompt_out',
219 help="Set the output prompt ('Out[\#]:')",
219 help="Set the output prompt ('Out[\#]:')",
220 metavar='InteractiveShell.prompt_out')
220 metavar='InteractiveShell.prompt_out')
221 paa('--quick',
221 paa('--quick',
222 action='store_true', dest='Global.quick',
222 action='store_true', dest='Global.quick',
223 help="Enable quick startup with no config files.")
223 help="Enable quick startup with no config files.")
224 paa('--readline',
224 paa('--readline',
225 action='store_true', dest='InteractiveShell.readline_use',
225 action='store_true', dest='InteractiveShell.readline_use',
226 help="Enable readline for command line usage.")
226 help="Enable readline for command line usage.")
227 paa('--no-readline',
227 paa('--no-readline',
228 action='store_false', dest='InteractiveShell.readline_use',
228 action='store_false', dest='InteractiveShell.readline_use',
229 help="Disable readline for command line usage.")
229 help="Disable readline for command line usage.")
230 paa('--screen-length','-sl',
230 paa('--screen-length','-sl',
231 type=int, dest='TerminalInteractiveShell.screen_length',
231 type=int, dest='TerminalInteractiveShell.screen_length',
232 help=
232 help=
233 """Number of lines of your screen, used to control printing of very
233 """Number of lines of your screen, used to control printing of very
234 long strings. Strings longer than this number of lines will be sent
234 long strings. Strings longer than this number of lines will be sent
235 through a pager instead of directly printed. The default value for
235 through a pager instead of directly printed. The default value for
236 this is 0, which means IPython will auto-detect your screen size every
236 this is 0, which means IPython will auto-detect your screen size every
237 time it needs to print certain potentially long strings (this doesn't
237 time it needs to print certain potentially long strings (this doesn't
238 change the behavior of the 'print' keyword, it's only triggered
238 change the behavior of the 'print' keyword, it's only triggered
239 internally). If for some reason this isn't working well (it needs
239 internally). If for some reason this isn't working well (it needs
240 curses support), specify it yourself. Otherwise don't change the
240 curses support), specify it yourself. Otherwise don't change the
241 default.""",
241 default.""",
242 metavar='TerminalInteractiveShell.screen_length')
242 metavar='TerminalInteractiveShell.screen_length')
243 paa('--separate-in','-si',
243 paa('--separate-in','-si',
244 type=str, dest='InteractiveShell.separate_in',
244 type=str, dest='InteractiveShell.separate_in',
245 help="Separator before input prompts. Default '\\n'.",
245 help="Separator before input prompts. Default '\\n'.",
246 metavar='InteractiveShell.separate_in')
246 metavar='InteractiveShell.separate_in')
247 paa('--separate-out','-so',
247 paa('--separate-out','-so',
248 type=str, dest='InteractiveShell.separate_out',
248 type=str, dest='InteractiveShell.separate_out',
249 help="Separator before output prompts. Default 0 (nothing).",
249 help="Separator before output prompts. Default 0 (nothing).",
250 metavar='InteractiveShell.separate_out')
250 metavar='InteractiveShell.separate_out')
251 paa('--separate-out2','-so2',
251 paa('--separate-out2','-so2',
252 type=str, dest='InteractiveShell.separate_out2',
252 type=str, dest='InteractiveShell.separate_out2',
253 help="Separator after output prompts. Default 0 (nonight).",
253 help="Separator after output prompts. Default 0 (nonight).",
254 metavar='InteractiveShell.separate_out2')
254 metavar='InteractiveShell.separate_out2')
255 paa('--no-sep',
255 paa('--no-sep',
256 action='store_true', dest='Global.nosep',
256 action='store_true', dest='Global.nosep',
257 help="Eliminate all spacing between prompts.")
257 help="Eliminate all spacing between prompts.")
258 paa('--term-title',
258 paa('--term-title',
259 action='store_true', dest='TerminalInteractiveShell.term_title',
259 action='store_true', dest='TerminalInteractiveShell.term_title',
260 help="Enable auto setting the terminal title.")
260 help="Enable auto setting the terminal title.")
261 paa('--no-term-title',
261 paa('--no-term-title',
262 action='store_false', dest='TerminalInteractiveShell.term_title',
262 action='store_false', dest='TerminalInteractiveShell.term_title',
263 help="Disable auto setting the terminal title.")
263 help="Disable auto setting the terminal title.")
264 paa('--xmode',
264 paa('--xmode',
265 type=str, dest='InteractiveShell.xmode',
265 type=str, dest='InteractiveShell.xmode',
266 help=
266 help=
267 """Exception reporting mode ('Plain','Context','Verbose'). Plain:
267 """Exception reporting mode ('Plain','Context','Verbose'). Plain:
268 similar to python's normal traceback printing. Context: prints 5 lines
268 similar to python's normal traceback printing. Context: prints 5 lines
269 of context source code around each line in the traceback. Verbose:
269 of context source code around each line in the traceback. Verbose:
270 similar to Context, but additionally prints the variables currently
270 similar to Context, but additionally prints the variables currently
271 visible where the exception happened (shortening their strings if too
271 visible where the exception happened (shortening their strings if too
272 long). This can potentially be very slow, if you happen to have a huge
272 long). This can potentially be very slow, if you happen to have a huge
273 data structure whose string representation is complex to compute.
273 data structure whose string representation is complex to compute.
274 Your computer may appear to freeze for a while with cpu usage at 100%%.
274 Your computer may appear to freeze for a while with cpu usage at 100%%.
275 If this occurs, you can cancel the traceback with Ctrl-C (maybe hitting
275 If this occurs, you can cancel the traceback with Ctrl-C (maybe hitting
276 it more than once).
276 it more than once).
277 """,
277 """,
278 metavar='InteractiveShell.xmode')
278 metavar='InteractiveShell.xmode')
279 paa('--ext',
279 paa('--ext',
280 type=str, dest='Global.extra_extension',
280 type=str, dest='Global.extra_extension',
281 help="The dotted module name of an IPython extension to load.",
281 help="The dotted module name of an IPython extension to load.",
282 metavar='Global.extra_extension')
282 metavar='Global.extra_extension')
283 paa('-c',
283 paa('-c',
284 type=str, dest='Global.code_to_run',
284 type=str, dest='Global.code_to_run',
285 help="Execute the given command string.",
285 help="Execute the given command string.",
286 metavar='Global.code_to_run')
286 metavar='Global.code_to_run')
287 paa('-i',
287 paa('-i',
288 action='store_true', dest='Global.force_interact',
288 action='store_true', dest='Global.force_interact',
289 help=
289 help=
290 "If running code from the command line, become interactive afterwards.")
290 "If running code from the command line, become interactive afterwards.")
291
291
292 # Options to start with GUI control enabled from the beginning
292 # Options to start with GUI control enabled from the beginning
293 paa('--gui',
293 paa('--gui',
294 type=str, dest='Global.gui',
294 type=str, dest='Global.gui',
295 help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
295 help="Enable GUI event loop integration ('qt', 'wx', 'gtk').",
296 metavar='gui-mode')
296 metavar='gui-mode')
297 paa('--pylab','-pylab',
297 paa('--pylab','-pylab',
298 type=str, dest='Global.pylab',
298 type=str, dest='Global.pylab',
299 nargs='?', const='auto', metavar='gui-mode',
299 nargs='?', const='auto', metavar='gui-mode',
300 help="Pre-load matplotlib and numpy for interactive use. "+
300 help="Pre-load matplotlib and numpy for interactive use. "+
301 "If no value is given, the gui backend is matplotlib's, else use "+
301 "If no value is given, the gui backend is matplotlib's, else use "+
302 "one of: ['tk', 'qt', 'wx', 'gtk'].")
302 "one of: ['tk', 'qt', 'wx', 'gtk'].")
303
303
304 # Legacy GUI options. Leave them in for backwards compatibility, but the
304 # Legacy GUI options. Leave them in for backwards compatibility, but the
305 # 'thread' names are really a misnomer now.
305 # 'thread' names are really a misnomer now.
306 paa('--wthread', '-wthread',
306 paa('--wthread', '-wthread',
307 action='store_true', dest='Global.wthread',
307 action='store_true', dest='Global.wthread',
308 help=
308 help=
309 """Enable wxPython event loop integration. (DEPRECATED, use --gui wx)""")
309 """Enable wxPython event loop integration. (DEPRECATED, use --gui wx)""")
310 paa('--q4thread', '--qthread', '-q4thread', '-qthread',
310 paa('--q4thread', '--qthread', '-q4thread', '-qthread',
311 action='store_true', dest='Global.q4thread',
311 action='store_true', dest='Global.q4thread',
312 help=
312 help=
313 """Enable Qt4 event loop integration. Qt3 is no longer supported.
313 """Enable Qt4 event loop integration. Qt3 is no longer supported.
314 (DEPRECATED, use --gui qt)""")
314 (DEPRECATED, use --gui qt)""")
315 paa('--gthread', '-gthread',
315 paa('--gthread', '-gthread',
316 action='store_true', dest='Global.gthread',
316 action='store_true', dest='Global.gthread',
317 help=
317 help=
318 """Enable GTK event loop integration. (DEPRECATED, use --gui gtk)""")
318 """Enable GTK event loop integration. (DEPRECATED, use --gui gtk)""")
319
319
320
320
321 #-----------------------------------------------------------------------------
321 #-----------------------------------------------------------------------------
322 # Crash handler for this application
322 # Crash handler for this application
323 #-----------------------------------------------------------------------------
323 #-----------------------------------------------------------------------------
324
324
325
326 _message_template = """\
325 _message_template = """\
327 Oops, $self.app_name crashed. We do our best to make it stable, but...
326 Oops, $self.app_name crashed. We do our best to make it stable, but...
328
327
329 A crash report was automatically generated with the following information:
328 A crash report was automatically generated with the following information:
330 - A verbatim copy of the crash traceback.
329 - A verbatim copy of the crash traceback.
331 - A copy of your input history during this session.
330 - A copy of your input history during this session.
332 - Data on your current $self.app_name configuration.
331 - Data on your current $self.app_name configuration.
333
332
334 It was left in the file named:
333 It was left in the file named:
335 \t'$self.crash_report_fname'
334 \t'$self.crash_report_fname'
336 If you can email this file to the developers, the information in it will help
335 If you can email this file to the developers, the information in it will help
337 them in understanding and correcting the problem.
336 them in understanding and correcting the problem.
338
337
339 You can mail it to: $self.contact_name at $self.contact_email
338 You can mail it to: $self.contact_name at $self.contact_email
340 with the subject '$self.app_name Crash Report'.
339 with the subject '$self.app_name Crash Report'.
341
340
342 If you want to do it now, the following command will work (under Unix):
341 If you want to do it now, the following command will work (under Unix):
343 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
342 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
344
343
345 To ensure accurate tracking of this issue, please file a report about it at:
344 To ensure accurate tracking of this issue, please file a report about it at:
346 $self.bug_tracker
345 $self.bug_tracker
347 """
346 """
348
347
349 class IPAppCrashHandler(CrashHandler):
348 class IPAppCrashHandler(CrashHandler):
350 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
349 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
351
350
352 message_template = _message_template
351 message_template = _message_template
353
352
354 def __init__(self, app):
353 def __init__(self, app):
355 contact_name = release.authors['Fernando'][0]
354 contact_name = release.authors['Fernando'][0]
356 contact_email = release.authors['Fernando'][1]
355 contact_email = release.authors['Fernando'][1]
357 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
356 bug_tracker = 'http://github.com/ipython/ipython/issues'
358 super(IPAppCrashHandler,self).__init__(
357 super(IPAppCrashHandler,self).__init__(
359 app, contact_name, contact_email, bug_tracker
358 app, contact_name, contact_email, bug_tracker
360 )
359 )
361
360
362 def make_report(self,traceback):
361 def make_report(self,traceback):
363 """Return a string containing a crash report."""
362 """Return a string containing a crash report."""
364
363
365 sec_sep = self.section_sep
364 sec_sep = self.section_sep
366 # Start with parent report
365 # Start with parent report
367 report = [super(IPAppCrashHandler, self).make_report(traceback)]
366 report = [super(IPAppCrashHandler, self).make_report(traceback)]
368 # Add interactive-specific info we may have
367 # Add interactive-specific info we may have
369 rpt_add = report.append
368 rpt_add = report.append
370 try:
369 try:
371 rpt_add(sec_sep+"History of session input:")
370 rpt_add(sec_sep+"History of session input:")
372 for line in self.app.shell.user_ns['_ih']:
371 for line in self.app.shell.user_ns['_ih']:
373 rpt_add(line)
372 rpt_add(line)
374 rpt_add('\n*** Last line of input (may not be in above history):\n')
373 rpt_add('\n*** Last line of input (may not be in above history):\n')
375 rpt_add(self.app.shell._last_input_line+'\n')
374 rpt_add(self.app.shell._last_input_line+'\n')
376 except:
375 except:
377 pass
376 pass
378
377
379 return ''.join(report)
378 return ''.join(report)
380
379
381
380
382 #-----------------------------------------------------------------------------
381 #-----------------------------------------------------------------------------
383 # Main classes and functions
382 # Main classes and functions
384 #-----------------------------------------------------------------------------
383 #-----------------------------------------------------------------------------
385
384
386 class IPythonApp(Application):
385 class IPythonApp(Application):
387 name = u'ipython'
386 name = u'ipython'
388 #: argparse formats better the 'usage' than the 'description' field
387 #: argparse formats better the 'usage' than the 'description' field
389 description = None
388 description = None
390 usage = usage.cl_usage
389 usage = usage.cl_usage
391 command_line_loader = IPAppConfigLoader
390 command_line_loader = IPAppConfigLoader
392 default_config_file_name = default_config_file_name
391 default_config_file_name = default_config_file_name
393 crash_handler_class = IPAppCrashHandler
392 crash_handler_class = IPAppCrashHandler
394
393
395 def create_default_config(self):
394 def create_default_config(self):
396 super(IPythonApp, self).create_default_config()
395 super(IPythonApp, self).create_default_config()
397 # Eliminate multiple lookups
396 # Eliminate multiple lookups
398 Global = self.default_config.Global
397 Global = self.default_config.Global
399
398
400 # Set all default values
399 # Set all default values
401 Global.display_banner = True
400 Global.display_banner = True
402
401
403 # If the -c flag is given or a file is given to run at the cmd line
402 # If the -c flag is given or a file is given to run at the cmd line
404 # like "ipython foo.py", normally we exit without starting the main
403 # like "ipython foo.py", normally we exit without starting the main
405 # loop. The force_interact config variable allows a user to override
404 # loop. The force_interact config variable allows a user to override
406 # this and interact. It is also set by the -i cmd line flag, just
405 # this and interact. It is also set by the -i cmd line flag, just
407 # like Python.
406 # like Python.
408 Global.force_interact = False
407 Global.force_interact = False
409
408
410 # By default always interact by starting the IPython mainloop.
409 # By default always interact by starting the IPython mainloop.
411 Global.interact = True
410 Global.interact = True
412
411
413 # No GUI integration by default
412 # No GUI integration by default
414 Global.gui = False
413 Global.gui = False
415 # Pylab off by default
414 # Pylab off by default
416 Global.pylab = False
415 Global.pylab = False
417
416
418 # Deprecated versions of gui support that used threading, we support
417 # Deprecated versions of gui support that used threading, we support
419 # them just for bacwards compatibility as an alternate spelling for
418 # them just for bacwards compatibility as an alternate spelling for
420 # '--gui X'
419 # '--gui X'
421 Global.qthread = False
420 Global.qthread = False
422 Global.q4thread = False
421 Global.q4thread = False
423 Global.wthread = False
422 Global.wthread = False
424 Global.gthread = False
423 Global.gthread = False
425
424
426 def load_file_config(self):
425 def load_file_config(self):
427 if hasattr(self.command_line_config.Global, 'quick'):
426 if hasattr(self.command_line_config.Global, 'quick'):
428 if self.command_line_config.Global.quick:
427 if self.command_line_config.Global.quick:
429 self.file_config = Config()
428 self.file_config = Config()
430 return
429 return
431 super(IPythonApp, self).load_file_config()
430 super(IPythonApp, self).load_file_config()
432
431
433 def post_load_file_config(self):
432 def post_load_file_config(self):
434 if hasattr(self.command_line_config.Global, 'extra_extension'):
433 if hasattr(self.command_line_config.Global, 'extra_extension'):
435 if not hasattr(self.file_config.Global, 'extensions'):
434 if not hasattr(self.file_config.Global, 'extensions'):
436 self.file_config.Global.extensions = []
435 self.file_config.Global.extensions = []
437 self.file_config.Global.extensions.append(
436 self.file_config.Global.extensions.append(
438 self.command_line_config.Global.extra_extension)
437 self.command_line_config.Global.extra_extension)
439 del self.command_line_config.Global.extra_extension
438 del self.command_line_config.Global.extra_extension
440
439
441 def pre_construct(self):
440 def pre_construct(self):
442 config = self.master_config
441 config = self.master_config
443
442
444 if hasattr(config.Global, 'classic'):
443 if hasattr(config.Global, 'classic'):
445 if config.Global.classic:
444 if config.Global.classic:
446 config.InteractiveShell.cache_size = 0
445 config.InteractiveShell.cache_size = 0
447 config.InteractiveShell.pprint = 0
446 config.InteractiveShell.pprint = 0
448 config.InteractiveShell.prompt_in1 = '>>> '
447 config.InteractiveShell.prompt_in1 = '>>> '
449 config.InteractiveShell.prompt_in2 = '... '
448 config.InteractiveShell.prompt_in2 = '... '
450 config.InteractiveShell.prompt_out = ''
449 config.InteractiveShell.prompt_out = ''
451 config.InteractiveShell.separate_in = \
450 config.InteractiveShell.separate_in = \
452 config.InteractiveShell.separate_out = \
451 config.InteractiveShell.separate_out = \
453 config.InteractiveShell.separate_out2 = ''
452 config.InteractiveShell.separate_out2 = ''
454 config.InteractiveShell.colors = 'NoColor'
453 config.InteractiveShell.colors = 'NoColor'
455 config.InteractiveShell.xmode = 'Plain'
454 config.InteractiveShell.xmode = 'Plain'
456
455
457 if hasattr(config.Global, 'nosep'):
456 if hasattr(config.Global, 'nosep'):
458 if config.Global.nosep:
457 if config.Global.nosep:
459 config.InteractiveShell.separate_in = \
458 config.InteractiveShell.separate_in = \
460 config.InteractiveShell.separate_out = \
459 config.InteractiveShell.separate_out = \
461 config.InteractiveShell.separate_out2 = ''
460 config.InteractiveShell.separate_out2 = ''
462
461
463 # if there is code of files to run from the cmd line, don't interact
462 # if there is code of files to run from the cmd line, don't interact
464 # unless the -i flag (Global.force_interact) is true.
463 # unless the -i flag (Global.force_interact) is true.
465 code_to_run = config.Global.get('code_to_run','')
464 code_to_run = config.Global.get('code_to_run','')
466 file_to_run = False
465 file_to_run = False
467 if self.extra_args and self.extra_args[0]:
466 if self.extra_args and self.extra_args[0]:
468 file_to_run = True
467 file_to_run = True
469 if file_to_run or code_to_run:
468 if file_to_run or code_to_run:
470 if not config.Global.force_interact:
469 if not config.Global.force_interact:
471 config.Global.interact = False
470 config.Global.interact = False
472
471
473 def construct(self):
472 def construct(self):
474 # I am a little hesitant to put these into InteractiveShell itself.
473 # I am a little hesitant to put these into InteractiveShell itself.
475 # But that might be the place for them
474 # But that might be the place for them
476 sys.path.insert(0, '')
475 sys.path.insert(0, '')
477
476
478 # Create an InteractiveShell instance.
477 # Create an InteractiveShell instance.
479 self.shell = TerminalInteractiveShell.instance(config=self.master_config)
478 self.shell = TerminalInteractiveShell.instance(config=self.master_config)
480
479
481 def post_construct(self):
480 def post_construct(self):
482 """Do actions after construct, but before starting the app."""
481 """Do actions after construct, but before starting the app."""
483 config = self.master_config
482 config = self.master_config
484
483
485 # shell.display_banner should always be False for the terminal
484 # shell.display_banner should always be False for the terminal
486 # based app, because we call shell.show_banner() by hand below
485 # based app, because we call shell.show_banner() by hand below
487 # so the banner shows *before* all extension loading stuff.
486 # so the banner shows *before* all extension loading stuff.
488 self.shell.display_banner = False
487 self.shell.display_banner = False
489 if config.Global.display_banner and \
488 if config.Global.display_banner and \
490 config.Global.interact:
489 config.Global.interact:
491 self.shell.show_banner()
490 self.shell.show_banner()
492
491
493 # Make sure there is a space below the banner.
492 # Make sure there is a space below the banner.
494 if self.log_level <= logging.INFO: print
493 if self.log_level <= logging.INFO: print
495
494
496 # Now a variety of things that happen after the banner is printed.
495 # Now a variety of things that happen after the banner is printed.
497 self._enable_gui_pylab()
496 self._enable_gui_pylab()
498 self._load_extensions()
497 self._load_extensions()
499 self._run_exec_lines()
498 self._run_exec_lines()
500 self._run_exec_files()
499 self._run_exec_files()
501 self._run_cmd_line_code()
500 self._run_cmd_line_code()
502
501
503 def _enable_gui_pylab(self):
502 def _enable_gui_pylab(self):
504 """Enable GUI event loop integration, taking pylab into account."""
503 """Enable GUI event loop integration, taking pylab into account."""
505 Global = self.master_config.Global
504 Global = self.master_config.Global
506
505
507 # Select which gui to use
506 # Select which gui to use
508 if Global.gui:
507 if Global.gui:
509 gui = Global.gui
508 gui = Global.gui
510 # The following are deprecated, but there's likely to be a lot of use
509 # The following are deprecated, but there's likely to be a lot of use
511 # of this form out there, so we might as well support it for now. But
510 # of this form out there, so we might as well support it for now. But
512 # the --gui option above takes precedence.
511 # the --gui option above takes precedence.
513 elif Global.wthread:
512 elif Global.wthread:
514 gui = inputhook.GUI_WX
513 gui = inputhook.GUI_WX
515 elif Global.qthread:
514 elif Global.qthread:
516 gui = inputhook.GUI_QT
515 gui = inputhook.GUI_QT
517 elif Global.gthread:
516 elif Global.gthread:
518 gui = inputhook.GUI_GTK
517 gui = inputhook.GUI_GTK
519 else:
518 else:
520 gui = None
519 gui = None
521
520
522 # Using --pylab will also require gui activation, though which toolkit
521 # Using --pylab will also require gui activation, though which toolkit
523 # to use may be chosen automatically based on mpl configuration.
522 # to use may be chosen automatically based on mpl configuration.
524 if Global.pylab:
523 if Global.pylab:
525 activate = self.shell.enable_pylab
524 activate = self.shell.enable_pylab
526 if Global.pylab == 'auto':
525 if Global.pylab == 'auto':
527 gui = None
526 gui = None
528 else:
527 else:
529 gui = Global.pylab
528 gui = Global.pylab
530 else:
529 else:
531 # Enable only GUI integration, no pylab
530 # Enable only GUI integration, no pylab
532 activate = inputhook.enable_gui
531 activate = inputhook.enable_gui
533
532
534 if gui or Global.pylab:
533 if gui or Global.pylab:
535 try:
534 try:
536 self.log.info("Enabling GUI event loop integration, "
535 self.log.info("Enabling GUI event loop integration, "
537 "toolkit=%s, pylab=%s" % (gui, Global.pylab) )
536 "toolkit=%s, pylab=%s" % (gui, Global.pylab) )
538 activate(gui)
537 activate(gui)
539 except:
538 except:
540 self.log.warn("Error in enabling GUI event loop integration:")
539 self.log.warn("Error in enabling GUI event loop integration:")
541 self.shell.showtraceback()
540 self.shell.showtraceback()
542
541
543 def _load_extensions(self):
542 def _load_extensions(self):
544 """Load all IPython extensions in Global.extensions.
543 """Load all IPython extensions in Global.extensions.
545
544
546 This uses the :meth:`ExtensionManager.load_extensions` to load all
545 This uses the :meth:`ExtensionManager.load_extensions` to load all
547 the extensions listed in ``self.master_config.Global.extensions``.
546 the extensions listed in ``self.master_config.Global.extensions``.
548 """
547 """
549 try:
548 try:
550 if hasattr(self.master_config.Global, 'extensions'):
549 if hasattr(self.master_config.Global, 'extensions'):
551 self.log.debug("Loading IPython extensions...")
550 self.log.debug("Loading IPython extensions...")
552 extensions = self.master_config.Global.extensions
551 extensions = self.master_config.Global.extensions
553 for ext in extensions:
552 for ext in extensions:
554 try:
553 try:
555 self.log.info("Loading IPython extension: %s" % ext)
554 self.log.info("Loading IPython extension: %s" % ext)
556 self.shell.extension_manager.load_extension(ext)
555 self.shell.extension_manager.load_extension(ext)
557 except:
556 except:
558 self.log.warn("Error in loading extension: %s" % ext)
557 self.log.warn("Error in loading extension: %s" % ext)
559 self.shell.showtraceback()
558 self.shell.showtraceback()
560 except:
559 except:
561 self.log.warn("Unknown error in loading extensions:")
560 self.log.warn("Unknown error in loading extensions:")
562 self.shell.showtraceback()
561 self.shell.showtraceback()
563
562
564 def _run_exec_lines(self):
563 def _run_exec_lines(self):
565 """Run lines of code in Global.exec_lines in the user's namespace."""
564 """Run lines of code in Global.exec_lines in the user's namespace."""
566 try:
565 try:
567 if hasattr(self.master_config.Global, 'exec_lines'):
566 if hasattr(self.master_config.Global, 'exec_lines'):
568 self.log.debug("Running code from Global.exec_lines...")
567 self.log.debug("Running code from Global.exec_lines...")
569 exec_lines = self.master_config.Global.exec_lines
568 exec_lines = self.master_config.Global.exec_lines
570 for line in exec_lines:
569 for line in exec_lines:
571 try:
570 try:
572 self.log.info("Running code in user namespace: %s" %
571 self.log.info("Running code in user namespace: %s" %
573 line)
572 line)
574 self.shell.run_cell(line)
573 self.shell.run_cell(line)
575 except:
574 except:
576 self.log.warn("Error in executing line in user "
575 self.log.warn("Error in executing line in user "
577 "namespace: %s" % line)
576 "namespace: %s" % line)
578 self.shell.showtraceback()
577 self.shell.showtraceback()
579 except:
578 except:
580 self.log.warn("Unknown error in handling Global.exec_lines:")
579 self.log.warn("Unknown error in handling Global.exec_lines:")
581 self.shell.showtraceback()
580 self.shell.showtraceback()
582
581
583 def _exec_file(self, fname):
582 def _exec_file(self, fname):
584 full_filename = filefind(fname, [u'.', self.ipython_dir])
583 full_filename = filefind(fname, [u'.', self.ipython_dir])
585 if os.path.isfile(full_filename):
584 if os.path.isfile(full_filename):
586 if full_filename.endswith(u'.py'):
585 if full_filename.endswith(u'.py'):
587 self.log.info("Running file in user namespace: %s" %
586 self.log.info("Running file in user namespace: %s" %
588 full_filename)
587 full_filename)
589 # Ensure that __file__ is always defined to match Python behavior
588 # Ensure that __file__ is always defined to match Python behavior
590 self.shell.user_ns['__file__'] = fname
589 self.shell.user_ns['__file__'] = fname
591 try:
590 try:
592 self.shell.safe_execfile(full_filename, self.shell.user_ns)
591 self.shell.safe_execfile(full_filename, self.shell.user_ns)
593 finally:
592 finally:
594 del self.shell.user_ns['__file__']
593 del self.shell.user_ns['__file__']
595 elif full_filename.endswith('.ipy'):
594 elif full_filename.endswith('.ipy'):
596 self.log.info("Running file in user namespace: %s" %
595 self.log.info("Running file in user namespace: %s" %
597 full_filename)
596 full_filename)
598 self.shell.safe_execfile_ipy(full_filename)
597 self.shell.safe_execfile_ipy(full_filename)
599 else:
598 else:
600 self.log.warn("File does not have a .py or .ipy extension: <%s>"
599 self.log.warn("File does not have a .py or .ipy extension: <%s>"
601 % full_filename)
600 % full_filename)
602 def _run_exec_files(self):
601 def _run_exec_files(self):
603 try:
602 try:
604 if hasattr(self.master_config.Global, 'exec_files'):
603 if hasattr(self.master_config.Global, 'exec_files'):
605 self.log.debug("Running files in Global.exec_files...")
604 self.log.debug("Running files in Global.exec_files...")
606 exec_files = self.master_config.Global.exec_files
605 exec_files = self.master_config.Global.exec_files
607 for fname in exec_files:
606 for fname in exec_files:
608 self._exec_file(fname)
607 self._exec_file(fname)
609 except:
608 except:
610 self.log.warn("Unknown error in handling Global.exec_files:")
609 self.log.warn("Unknown error in handling Global.exec_files:")
611 self.shell.showtraceback()
610 self.shell.showtraceback()
612
611
613 def _run_cmd_line_code(self):
612 def _run_cmd_line_code(self):
614 if hasattr(self.master_config.Global, 'code_to_run'):
613 if hasattr(self.master_config.Global, 'code_to_run'):
615 line = self.master_config.Global.code_to_run
614 line = self.master_config.Global.code_to_run
616 try:
615 try:
617 self.log.info("Running code given at command line (-c): %s" %
616 self.log.info("Running code given at command line (-c): %s" %
618 line)
617 line)
619 self.shell.run_cell(line)
618 self.shell.run_cell(line)
620 except:
619 except:
621 self.log.warn("Error in executing line in user namespace: %s" %
620 self.log.warn("Error in executing line in user namespace: %s" %
622 line)
621 line)
623 self.shell.showtraceback()
622 self.shell.showtraceback()
624 return
623 return
625 # Like Python itself, ignore the second if the first of these is present
624 # Like Python itself, ignore the second if the first of these is present
626 try:
625 try:
627 fname = self.extra_args[0]
626 fname = self.extra_args[0]
628 except:
627 except:
629 pass
628 pass
630 else:
629 else:
631 try:
630 try:
632 self._exec_file(fname)
631 self._exec_file(fname)
633 except:
632 except:
634 self.log.warn("Error in executing file in user namespace: %s" %
633 self.log.warn("Error in executing file in user namespace: %s" %
635 fname)
634 fname)
636 self.shell.showtraceback()
635 self.shell.showtraceback()
637
636
638 def start_app(self):
637 def start_app(self):
639 if self.master_config.Global.interact:
638 if self.master_config.Global.interact:
640 self.log.debug("Starting IPython's mainloop...")
639 self.log.debug("Starting IPython's mainloop...")
641 self.shell.mainloop()
640 self.shell.mainloop()
642 else:
641 else:
643 self.log.debug("IPython not interactive, start_app is no-op...")
642 self.log.debug("IPython not interactive, start_app is no-op...")
644
643
645
644
646 def load_default_config(ipython_dir=None):
645 def load_default_config(ipython_dir=None):
647 """Load the default config file from the default ipython_dir.
646 """Load the default config file from the default ipython_dir.
648
647
649 This is useful for embedded shells.
648 This is useful for embedded shells.
650 """
649 """
651 if ipython_dir is None:
650 if ipython_dir is None:
652 ipython_dir = get_ipython_dir()
651 ipython_dir = get_ipython_dir()
653 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
652 cl = PyFileConfigLoader(default_config_file_name, ipython_dir)
654 config = cl.load_config()
653 config = cl.load_config()
655 return config
654 return config
656
655
657
656
658 def launch_new_instance():
657 def launch_new_instance():
659 """Create and run a full blown IPython instance"""
658 """Create and run a full blown IPython instance"""
660 app = IPythonApp()
659 app = IPythonApp()
661 app.start()
660 app.start()
662
661
663
662
664 if __name__ == '__main__':
663 if __name__ == '__main__':
665 launch_new_instance()
664 launch_new_instance()
@@ -1,538 +1,538
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The IPython cluster directory
4 The IPython cluster directory
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from __future__ import with_statement
18 from __future__ import with_statement
19
19
20 import os
20 import os
21 import shutil
21 import shutil
22 import sys
22 import sys
23 import warnings
23 import warnings
24
24
25 from twisted.python import log
25 from twisted.python import log
26
26
27 from IPython.config.loader import PyFileConfigLoader
27 from IPython.config.loader import PyFileConfigLoader
28 from IPython.core.application import Application, BaseAppConfigLoader
28 from IPython.core.application import Application, BaseAppConfigLoader
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.core.crashhandler import CrashHandler
30 from IPython.core.crashhandler import CrashHandler
31 from IPython.core import release
31 from IPython.core import release
32 from IPython.utils.path import (
32 from IPython.utils.path import (
33 get_ipython_package_dir,
33 get_ipython_package_dir,
34 expand_path
34 expand_path
35 )
35 )
36 from IPython.utils.traitlets import Unicode
36 from IPython.utils.traitlets import Unicode
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Warnings control
39 # Warnings control
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Twisted generates annoying warnings with Python 2.6, as will do other code
41 # Twisted generates annoying warnings with Python 2.6, as will do other code
42 # that imports 'sets' as of today
42 # that imports 'sets' as of today
43 warnings.filterwarnings('ignore', 'the sets module is deprecated',
43 warnings.filterwarnings('ignore', 'the sets module is deprecated',
44 DeprecationWarning )
44 DeprecationWarning )
45
45
46 # This one also comes from Twisted
46 # This one also comes from Twisted
47 warnings.filterwarnings('ignore', 'the sha module is deprecated',
47 warnings.filterwarnings('ignore', 'the sha module is deprecated',
48 DeprecationWarning)
48 DeprecationWarning)
49
49
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51 # Module errors
51 # Module errors
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53
53
54 class ClusterDirError(Exception):
54 class ClusterDirError(Exception):
55 pass
55 pass
56
56
57
57
58 class PIDFileError(Exception):
58 class PIDFileError(Exception):
59 pass
59 pass
60
60
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # Class for managing cluster directories
63 # Class for managing cluster directories
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65
65
66 class ClusterDir(Configurable):
66 class ClusterDir(Configurable):
67 """An object to manage the cluster directory and its resources.
67 """An object to manage the cluster directory and its resources.
68
68
69 The cluster directory is used by :command:`ipcontroller`,
69 The cluster directory is used by :command:`ipcontroller`,
70 :command:`ipcontroller` and :command:`ipcontroller` to manage the
70 :command:`ipcontroller` and :command:`ipcontroller` to manage the
71 configuration, logging and security of these applications.
71 configuration, logging and security of these applications.
72
72
73 This object knows how to find, create and manage these directories. This
73 This object knows how to find, create and manage these directories. This
74 should be used by any code that want's to handle cluster directories.
74 should be used by any code that want's to handle cluster directories.
75 """
75 """
76
76
77 security_dir_name = Unicode('security')
77 security_dir_name = Unicode('security')
78 log_dir_name = Unicode('log')
78 log_dir_name = Unicode('log')
79 pid_dir_name = Unicode('pid')
79 pid_dir_name = Unicode('pid')
80 security_dir = Unicode(u'')
80 security_dir = Unicode(u'')
81 log_dir = Unicode(u'')
81 log_dir = Unicode(u'')
82 pid_dir = Unicode(u'')
82 pid_dir = Unicode(u'')
83 location = Unicode(u'')
83 location = Unicode(u'')
84
84
85 def __init__(self, location=u''):
85 def __init__(self, location=u''):
86 super(ClusterDir, self).__init__(location=location)
86 super(ClusterDir, self).__init__(location=location)
87
87
88 def _location_changed(self, name, old, new):
88 def _location_changed(self, name, old, new):
89 if not os.path.isdir(new):
89 if not os.path.isdir(new):
90 os.makedirs(new)
90 os.makedirs(new)
91 self.security_dir = os.path.join(new, self.security_dir_name)
91 self.security_dir = os.path.join(new, self.security_dir_name)
92 self.log_dir = os.path.join(new, self.log_dir_name)
92 self.log_dir = os.path.join(new, self.log_dir_name)
93 self.pid_dir = os.path.join(new, self.pid_dir_name)
93 self.pid_dir = os.path.join(new, self.pid_dir_name)
94 self.check_dirs()
94 self.check_dirs()
95
95
96 def _log_dir_changed(self, name, old, new):
96 def _log_dir_changed(self, name, old, new):
97 self.check_log_dir()
97 self.check_log_dir()
98
98
99 def check_log_dir(self):
99 def check_log_dir(self):
100 if not os.path.isdir(self.log_dir):
100 if not os.path.isdir(self.log_dir):
101 os.mkdir(self.log_dir)
101 os.mkdir(self.log_dir)
102
102
103 def _security_dir_changed(self, name, old, new):
103 def _security_dir_changed(self, name, old, new):
104 self.check_security_dir()
104 self.check_security_dir()
105
105
106 def check_security_dir(self):
106 def check_security_dir(self):
107 if not os.path.isdir(self.security_dir):
107 if not os.path.isdir(self.security_dir):
108 os.mkdir(self.security_dir, 0700)
108 os.mkdir(self.security_dir, 0700)
109 os.chmod(self.security_dir, 0700)
109 os.chmod(self.security_dir, 0700)
110
110
111 def _pid_dir_changed(self, name, old, new):
111 def _pid_dir_changed(self, name, old, new):
112 self.check_pid_dir()
112 self.check_pid_dir()
113
113
114 def check_pid_dir(self):
114 def check_pid_dir(self):
115 if not os.path.isdir(self.pid_dir):
115 if not os.path.isdir(self.pid_dir):
116 os.mkdir(self.pid_dir, 0700)
116 os.mkdir(self.pid_dir, 0700)
117 os.chmod(self.pid_dir, 0700)
117 os.chmod(self.pid_dir, 0700)
118
118
119 def check_dirs(self):
119 def check_dirs(self):
120 self.check_security_dir()
120 self.check_security_dir()
121 self.check_log_dir()
121 self.check_log_dir()
122 self.check_pid_dir()
122 self.check_pid_dir()
123
123
124 def load_config_file(self, filename):
124 def load_config_file(self, filename):
125 """Load a config file from the top level of the cluster dir.
125 """Load a config file from the top level of the cluster dir.
126
126
127 Parameters
127 Parameters
128 ----------
128 ----------
129 filename : unicode or str
129 filename : unicode or str
130 The filename only of the config file that must be located in
130 The filename only of the config file that must be located in
131 the top-level of the cluster directory.
131 the top-level of the cluster directory.
132 """
132 """
133 loader = PyFileConfigLoader(filename, self.location)
133 loader = PyFileConfigLoader(filename, self.location)
134 return loader.load_config()
134 return loader.load_config()
135
135
136 def copy_config_file(self, config_file, path=None, overwrite=False):
136 def copy_config_file(self, config_file, path=None, overwrite=False):
137 """Copy a default config file into the active cluster directory.
137 """Copy a default config file into the active cluster directory.
138
138
139 Default configuration files are kept in :mod:`IPython.config.default`.
139 Default configuration files are kept in :mod:`IPython.config.default`.
140 This function moves these from that location to the working cluster
140 This function moves these from that location to the working cluster
141 directory.
141 directory.
142 """
142 """
143 if path is None:
143 if path is None:
144 import IPython.config.default
144 import IPython.config.default
145 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
145 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
146 path = os.path.sep.join(path)
146 path = os.path.sep.join(path)
147 src = os.path.join(path, config_file)
147 src = os.path.join(path, config_file)
148 dst = os.path.join(self.location, config_file)
148 dst = os.path.join(self.location, config_file)
149 if not os.path.isfile(dst) or overwrite:
149 if not os.path.isfile(dst) or overwrite:
150 shutil.copy(src, dst)
150 shutil.copy(src, dst)
151
151
152 def copy_all_config_files(self, path=None, overwrite=False):
152 def copy_all_config_files(self, path=None, overwrite=False):
153 """Copy all config files into the active cluster directory."""
153 """Copy all config files into the active cluster directory."""
154 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
154 for f in [u'ipcontroller_config.py', u'ipengine_config.py',
155 u'ipcluster_config.py']:
155 u'ipcluster_config.py']:
156 self.copy_config_file(f, path=path, overwrite=overwrite)
156 self.copy_config_file(f, path=path, overwrite=overwrite)
157
157
158 @classmethod
158 @classmethod
159 def create_cluster_dir(csl, cluster_dir):
159 def create_cluster_dir(csl, cluster_dir):
160 """Create a new cluster directory given a full path.
160 """Create a new cluster directory given a full path.
161
161
162 Parameters
162 Parameters
163 ----------
163 ----------
164 cluster_dir : str
164 cluster_dir : str
165 The full path to the cluster directory. If it does exist, it will
165 The full path to the cluster directory. If it does exist, it will
166 be used. If not, it will be created.
166 be used. If not, it will be created.
167 """
167 """
168 return ClusterDir(location=cluster_dir)
168 return ClusterDir(location=cluster_dir)
169
169
170 @classmethod
170 @classmethod
171 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
171 def create_cluster_dir_by_profile(cls, path, profile=u'default'):
172 """Create a cluster dir by profile name and path.
172 """Create a cluster dir by profile name and path.
173
173
174 Parameters
174 Parameters
175 ----------
175 ----------
176 path : str
176 path : str
177 The path (directory) to put the cluster directory in.
177 The path (directory) to put the cluster directory in.
178 profile : str
178 profile : str
179 The name of the profile. The name of the cluster directory will
179 The name of the profile. The name of the cluster directory will
180 be "cluster_<profile>".
180 be "cluster_<profile>".
181 """
181 """
182 if not os.path.isdir(path):
182 if not os.path.isdir(path):
183 raise ClusterDirError('Directory not found: %s' % path)
183 raise ClusterDirError('Directory not found: %s' % path)
184 cluster_dir = os.path.join(path, u'cluster_' + profile)
184 cluster_dir = os.path.join(path, u'cluster_' + profile)
185 return ClusterDir(location=cluster_dir)
185 return ClusterDir(location=cluster_dir)
186
186
187 @classmethod
187 @classmethod
188 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
188 def find_cluster_dir_by_profile(cls, ipython_dir, profile=u'default'):
189 """Find an existing cluster dir by profile name, return its ClusterDir.
189 """Find an existing cluster dir by profile name, return its ClusterDir.
190
190
191 This searches through a sequence of paths for a cluster dir. If it
191 This searches through a sequence of paths for a cluster dir. If it
192 is not found, a :class:`ClusterDirError` exception will be raised.
192 is not found, a :class:`ClusterDirError` exception will be raised.
193
193
194 The search path algorithm is:
194 The search path algorithm is:
195 1. ``os.getcwd()``
195 1. ``os.getcwd()``
196 2. ``ipython_dir``
196 2. ``ipython_dir``
197 3. The directories found in the ":" separated
197 3. The directories found in the ":" separated
198 :env:`IPCLUSTER_DIR_PATH` environment variable.
198 :env:`IPCLUSTER_DIR_PATH` environment variable.
199
199
200 Parameters
200 Parameters
201 ----------
201 ----------
202 ipython_dir : unicode or str
202 ipython_dir : unicode or str
203 The IPython directory to use.
203 The IPython directory to use.
204 profile : unicode or str
204 profile : unicode or str
205 The name of the profile. The name of the cluster directory
205 The name of the profile. The name of the cluster directory
206 will be "cluster_<profile>".
206 will be "cluster_<profile>".
207 """
207 """
208 dirname = u'cluster_' + profile
208 dirname = u'cluster_' + profile
209 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
209 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
210 if cluster_dir_paths:
210 if cluster_dir_paths:
211 cluster_dir_paths = cluster_dir_paths.split(':')
211 cluster_dir_paths = cluster_dir_paths.split(':')
212 else:
212 else:
213 cluster_dir_paths = []
213 cluster_dir_paths = []
214 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
214 paths = [os.getcwd(), ipython_dir] + cluster_dir_paths
215 for p in paths:
215 for p in paths:
216 cluster_dir = os.path.join(p, dirname)
216 cluster_dir = os.path.join(p, dirname)
217 if os.path.isdir(cluster_dir):
217 if os.path.isdir(cluster_dir):
218 return ClusterDir(location=cluster_dir)
218 return ClusterDir(location=cluster_dir)
219 else:
219 else:
220 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
220 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
221
221
222 @classmethod
222 @classmethod
223 def find_cluster_dir(cls, cluster_dir):
223 def find_cluster_dir(cls, cluster_dir):
224 """Find/create a cluster dir and return its ClusterDir.
224 """Find/create a cluster dir and return its ClusterDir.
225
225
226 This will create the cluster directory if it doesn't exist.
226 This will create the cluster directory if it doesn't exist.
227
227
228 Parameters
228 Parameters
229 ----------
229 ----------
230 cluster_dir : unicode or str
230 cluster_dir : unicode or str
231 The path of the cluster directory. This is expanded using
231 The path of the cluster directory. This is expanded using
232 :func:`IPython.utils.genutils.expand_path`.
232 :func:`IPython.utils.genutils.expand_path`.
233 """
233 """
234 cluster_dir = expand_path(cluster_dir)
234 cluster_dir = expand_path(cluster_dir)
235 if not os.path.isdir(cluster_dir):
235 if not os.path.isdir(cluster_dir):
236 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
236 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
237 return ClusterDir(location=cluster_dir)
237 return ClusterDir(location=cluster_dir)
238
238
239
239
240 #-----------------------------------------------------------------------------
240 #-----------------------------------------------------------------------------
241 # Command line options
241 # Command line options
242 #-----------------------------------------------------------------------------
242 #-----------------------------------------------------------------------------
243
243
244 class ClusterDirConfigLoader(BaseAppConfigLoader):
244 class ClusterDirConfigLoader(BaseAppConfigLoader):
245
245
246 def _add_cluster_profile(self, parser):
246 def _add_cluster_profile(self, parser):
247 paa = parser.add_argument
247 paa = parser.add_argument
248 paa('-p', '--profile',
248 paa('-p', '--profile',
249 dest='Global.profile',type=unicode,
249 dest='Global.profile',type=unicode,
250 help=
250 help=
251 """The string name of the profile to be used. This determines the name
251 """The string name of the profile to be used. This determines the name
252 of the cluster dir as: cluster_<profile>. The default profile is named
252 of the cluster dir as: cluster_<profile>. The default profile is named
253 'default'. The cluster directory is resolve this way if the
253 'default'. The cluster directory is resolve this way if the
254 --cluster-dir option is not used.""",
254 --cluster-dir option is not used.""",
255 metavar='Global.profile')
255 metavar='Global.profile')
256
256
257 def _add_cluster_dir(self, parser):
257 def _add_cluster_dir(self, parser):
258 paa = parser.add_argument
258 paa = parser.add_argument
259 paa('--cluster-dir',
259 paa('--cluster-dir',
260 dest='Global.cluster_dir',type=unicode,
260 dest='Global.cluster_dir',type=unicode,
261 help="""Set the cluster dir. This overrides the logic used by the
261 help="""Set the cluster dir. This overrides the logic used by the
262 --profile option.""",
262 --profile option.""",
263 metavar='Global.cluster_dir')
263 metavar='Global.cluster_dir')
264
264
265 def _add_work_dir(self, parser):
265 def _add_work_dir(self, parser):
266 paa = parser.add_argument
266 paa = parser.add_argument
267 paa('--work-dir',
267 paa('--work-dir',
268 dest='Global.work_dir',type=unicode,
268 dest='Global.work_dir',type=unicode,
269 help='Set the working dir for the process.',
269 help='Set the working dir for the process.',
270 metavar='Global.work_dir')
270 metavar='Global.work_dir')
271
271
272 def _add_clean_logs(self, parser):
272 def _add_clean_logs(self, parser):
273 paa = parser.add_argument
273 paa = parser.add_argument
274 paa('--clean-logs',
274 paa('--clean-logs',
275 dest='Global.clean_logs', action='store_true',
275 dest='Global.clean_logs', action='store_true',
276 help='Delete old log flies before starting.')
276 help='Delete old log flies before starting.')
277
277
278 def _add_no_clean_logs(self, parser):
278 def _add_no_clean_logs(self, parser):
279 paa = parser.add_argument
279 paa = parser.add_argument
280 paa('--no-clean-logs',
280 paa('--no-clean-logs',
281 dest='Global.clean_logs', action='store_false',
281 dest='Global.clean_logs', action='store_false',
282 help="Don't Delete old log flies before starting.")
282 help="Don't Delete old log flies before starting.")
283
283
284 def _add_arguments(self):
284 def _add_arguments(self):
285 super(ClusterDirConfigLoader, self)._add_arguments()
285 super(ClusterDirConfigLoader, self)._add_arguments()
286 self._add_cluster_profile(self.parser)
286 self._add_cluster_profile(self.parser)
287 self._add_cluster_dir(self.parser)
287 self._add_cluster_dir(self.parser)
288 self._add_work_dir(self.parser)
288 self._add_work_dir(self.parser)
289 self._add_clean_logs(self.parser)
289 self._add_clean_logs(self.parser)
290 self._add_no_clean_logs(self.parser)
290 self._add_no_clean_logs(self.parser)
291
291
292
292
293 #-----------------------------------------------------------------------------
293 #-----------------------------------------------------------------------------
294 # Crash handler for this application
294 # Crash handler for this application
295 #-----------------------------------------------------------------------------
295 #-----------------------------------------------------------------------------
296
296
297
297
298 _message_template = """\
298 _message_template = """\
299 Oops, $self.app_name crashed. We do our best to make it stable, but...
299 Oops, $self.app_name crashed. We do our best to make it stable, but...
300
300
301 A crash report was automatically generated with the following information:
301 A crash report was automatically generated with the following information:
302 - A verbatim copy of the crash traceback.
302 - A verbatim copy of the crash traceback.
303 - Data on your current $self.app_name configuration.
303 - Data on your current $self.app_name configuration.
304
304
305 It was left in the file named:
305 It was left in the file named:
306 \t'$self.crash_report_fname'
306 \t'$self.crash_report_fname'
307 If you can email this file to the developers, the information in it will help
307 If you can email this file to the developers, the information in it will help
308 them in understanding and correcting the problem.
308 them in understanding and correcting the problem.
309
309
310 You can mail it to: $self.contact_name at $self.contact_email
310 You can mail it to: $self.contact_name at $self.contact_email
311 with the subject '$self.app_name Crash Report'.
311 with the subject '$self.app_name Crash Report'.
312
312
313 If you want to do it now, the following command will work (under Unix):
313 If you want to do it now, the following command will work (under Unix):
314 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
314 mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname
315
315
316 To ensure accurate tracking of this issue, please file a report about it at:
316 To ensure accurate tracking of this issue, please file a report about it at:
317 $self.bug_tracker
317 $self.bug_tracker
318 """
318 """
319
319
320 class ClusterDirCrashHandler(CrashHandler):
320 class ClusterDirCrashHandler(CrashHandler):
321 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
321 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
322
322
323 message_template = _message_template
323 message_template = _message_template
324
324
325 def __init__(self, app):
325 def __init__(self, app):
326 contact_name = release.authors['Brian'][0]
326 contact_name = release.authors['Brian'][0]
327 contact_email = release.authors['Brian'][1]
327 contact_email = release.authors['Brian'][1]
328 bug_tracker = 'https://bugs.launchpad.net/ipython/+filebug'
328 bug_tracker = 'http://github.com/ipython/ipython/issues'
329 super(ClusterDirCrashHandler,self).__init__(
329 super(ClusterDirCrashHandler,self).__init__(
330 app, contact_name, contact_email, bug_tracker
330 app, contact_name, contact_email, bug_tracker
331 )
331 )
332
332
333
333
334 #-----------------------------------------------------------------------------
334 #-----------------------------------------------------------------------------
335 # Main application
335 # Main application
336 #-----------------------------------------------------------------------------
336 #-----------------------------------------------------------------------------
337
337
338 class ApplicationWithClusterDir(Application):
338 class ApplicationWithClusterDir(Application):
339 """An application that puts everything into a cluster directory.
339 """An application that puts everything into a cluster directory.
340
340
341 Instead of looking for things in the ipython_dir, this type of application
341 Instead of looking for things in the ipython_dir, this type of application
342 will use its own private directory called the "cluster directory"
342 will use its own private directory called the "cluster directory"
343 for things like config files, log files, etc.
343 for things like config files, log files, etc.
344
344
345 The cluster directory is resolved as follows:
345 The cluster directory is resolved as follows:
346
346
347 * If the ``--cluster-dir`` option is given, it is used.
347 * If the ``--cluster-dir`` option is given, it is used.
348 * If ``--cluster-dir`` is not given, the application directory is
348 * If ``--cluster-dir`` is not given, the application directory is
349 resolve using the profile name as ``cluster_<profile>``. The search
349 resolve using the profile name as ``cluster_<profile>``. The search
350 path for this directory is then i) cwd if it is found there
350 path for this directory is then i) cwd if it is found there
351 and ii) in ipython_dir otherwise.
351 and ii) in ipython_dir otherwise.
352
352
353 The config file for the application is to be put in the cluster
353 The config file for the application is to be put in the cluster
354 dir and named the value of the ``config_file_name`` class attribute.
354 dir and named the value of the ``config_file_name`` class attribute.
355 """
355 """
356
356
357 command_line_loader = ClusterDirConfigLoader
357 command_line_loader = ClusterDirConfigLoader
358 crash_handler_class = ClusterDirCrashHandler
358 crash_handler_class = ClusterDirCrashHandler
359 auto_create_cluster_dir = True
359 auto_create_cluster_dir = True
360
360
361 def create_default_config(self):
361 def create_default_config(self):
362 super(ApplicationWithClusterDir, self).create_default_config()
362 super(ApplicationWithClusterDir, self).create_default_config()
363 self.default_config.Global.profile = u'default'
363 self.default_config.Global.profile = u'default'
364 self.default_config.Global.cluster_dir = u''
364 self.default_config.Global.cluster_dir = u''
365 self.default_config.Global.work_dir = os.getcwd()
365 self.default_config.Global.work_dir = os.getcwd()
366 self.default_config.Global.log_to_file = False
366 self.default_config.Global.log_to_file = False
367 self.default_config.Global.clean_logs = False
367 self.default_config.Global.clean_logs = False
368
368
369 def find_resources(self):
369 def find_resources(self):
370 """This resolves the cluster directory.
370 """This resolves the cluster directory.
371
371
372 This tries to find the cluster directory and if successful, it will
372 This tries to find the cluster directory and if successful, it will
373 have done:
373 have done:
374 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
374 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
375 the application.
375 the application.
376 * Sets ``self.cluster_dir`` attribute of the application and config
376 * Sets ``self.cluster_dir`` attribute of the application and config
377 objects.
377 objects.
378
378
379 The algorithm used for this is as follows:
379 The algorithm used for this is as follows:
380 1. Try ``Global.cluster_dir``.
380 1. Try ``Global.cluster_dir``.
381 2. Try using ``Global.profile``.
381 2. Try using ``Global.profile``.
382 3. If both of these fail and ``self.auto_create_cluster_dir`` is
382 3. If both of these fail and ``self.auto_create_cluster_dir`` is
383 ``True``, then create the new cluster dir in the IPython directory.
383 ``True``, then create the new cluster dir in the IPython directory.
384 4. If all fails, then raise :class:`ClusterDirError`.
384 4. If all fails, then raise :class:`ClusterDirError`.
385 """
385 """
386
386
387 try:
387 try:
388 cluster_dir = self.command_line_config.Global.cluster_dir
388 cluster_dir = self.command_line_config.Global.cluster_dir
389 except AttributeError:
389 except AttributeError:
390 cluster_dir = self.default_config.Global.cluster_dir
390 cluster_dir = self.default_config.Global.cluster_dir
391 cluster_dir = expand_path(cluster_dir)
391 cluster_dir = expand_path(cluster_dir)
392 try:
392 try:
393 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
393 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
394 except ClusterDirError:
394 except ClusterDirError:
395 pass
395 pass
396 else:
396 else:
397 self.log.info('Using existing cluster dir: %s' % \
397 self.log.info('Using existing cluster dir: %s' % \
398 self.cluster_dir_obj.location
398 self.cluster_dir_obj.location
399 )
399 )
400 self.finish_cluster_dir()
400 self.finish_cluster_dir()
401 return
401 return
402
402
403 try:
403 try:
404 self.profile = self.command_line_config.Global.profile
404 self.profile = self.command_line_config.Global.profile
405 except AttributeError:
405 except AttributeError:
406 self.profile = self.default_config.Global.profile
406 self.profile = self.default_config.Global.profile
407 try:
407 try:
408 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
408 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
409 self.ipython_dir, self.profile)
409 self.ipython_dir, self.profile)
410 except ClusterDirError:
410 except ClusterDirError:
411 pass
411 pass
412 else:
412 else:
413 self.log.info('Using existing cluster dir: %s' % \
413 self.log.info('Using existing cluster dir: %s' % \
414 self.cluster_dir_obj.location
414 self.cluster_dir_obj.location
415 )
415 )
416 self.finish_cluster_dir()
416 self.finish_cluster_dir()
417 return
417 return
418
418
419 if self.auto_create_cluster_dir:
419 if self.auto_create_cluster_dir:
420 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
420 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
421 self.ipython_dir, self.profile
421 self.ipython_dir, self.profile
422 )
422 )
423 self.log.info('Creating new cluster dir: %s' % \
423 self.log.info('Creating new cluster dir: %s' % \
424 self.cluster_dir_obj.location
424 self.cluster_dir_obj.location
425 )
425 )
426 self.finish_cluster_dir()
426 self.finish_cluster_dir()
427 else:
427 else:
428 raise ClusterDirError('Could not find a valid cluster directory.')
428 raise ClusterDirError('Could not find a valid cluster directory.')
429
429
430 def finish_cluster_dir(self):
430 def finish_cluster_dir(self):
431 # Set the cluster directory
431 # Set the cluster directory
432 self.cluster_dir = self.cluster_dir_obj.location
432 self.cluster_dir = self.cluster_dir_obj.location
433
433
434 # These have to be set because they could be different from the one
434 # These have to be set because they could be different from the one
435 # that we just computed. Because command line has the highest
435 # that we just computed. Because command line has the highest
436 # priority, this will always end up in the master_config.
436 # priority, this will always end up in the master_config.
437 self.default_config.Global.cluster_dir = self.cluster_dir
437 self.default_config.Global.cluster_dir = self.cluster_dir
438 self.command_line_config.Global.cluster_dir = self.cluster_dir
438 self.command_line_config.Global.cluster_dir = self.cluster_dir
439
439
440 def find_config_file_name(self):
440 def find_config_file_name(self):
441 """Find the config file name for this application."""
441 """Find the config file name for this application."""
442 # For this type of Application it should be set as a class attribute.
442 # For this type of Application it should be set as a class attribute.
443 if not hasattr(self, 'default_config_file_name'):
443 if not hasattr(self, 'default_config_file_name'):
444 self.log.critical("No config filename found")
444 self.log.critical("No config filename found")
445 else:
445 else:
446 self.config_file_name = self.default_config_file_name
446 self.config_file_name = self.default_config_file_name
447
447
448 def find_config_file_paths(self):
448 def find_config_file_paths(self):
449 # Set the search path to to the cluster directory. We should NOT
449 # Set the search path to to the cluster directory. We should NOT
450 # include IPython.config.default here as the default config files
450 # include IPython.config.default here as the default config files
451 # are ALWAYS automatically moved to the cluster directory.
451 # are ALWAYS automatically moved to the cluster directory.
452 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
452 conf_dir = os.path.join(get_ipython_package_dir(), 'config', 'default')
453 self.config_file_paths = (self.cluster_dir,)
453 self.config_file_paths = (self.cluster_dir,)
454
454
455 def pre_construct(self):
455 def pre_construct(self):
456 # The log and security dirs were set earlier, but here we put them
456 # The log and security dirs were set earlier, but here we put them
457 # into the config and log them.
457 # into the config and log them.
458 config = self.master_config
458 config = self.master_config
459 sdir = self.cluster_dir_obj.security_dir
459 sdir = self.cluster_dir_obj.security_dir
460 self.security_dir = config.Global.security_dir = sdir
460 self.security_dir = config.Global.security_dir = sdir
461 ldir = self.cluster_dir_obj.log_dir
461 ldir = self.cluster_dir_obj.log_dir
462 self.log_dir = config.Global.log_dir = ldir
462 self.log_dir = config.Global.log_dir = ldir
463 pdir = self.cluster_dir_obj.pid_dir
463 pdir = self.cluster_dir_obj.pid_dir
464 self.pid_dir = config.Global.pid_dir = pdir
464 self.pid_dir = config.Global.pid_dir = pdir
465 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
465 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
466 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
466 config.Global.work_dir = unicode(expand_path(config.Global.work_dir))
467 # Change to the working directory. We do this just before construct
467 # Change to the working directory. We do this just before construct
468 # is called so all the components there have the right working dir.
468 # is called so all the components there have the right working dir.
469 self.to_work_dir()
469 self.to_work_dir()
470
470
471 def to_work_dir(self):
471 def to_work_dir(self):
472 wd = self.master_config.Global.work_dir
472 wd = self.master_config.Global.work_dir
473 if unicode(wd) != unicode(os.getcwd()):
473 if unicode(wd) != unicode(os.getcwd()):
474 os.chdir(wd)
474 os.chdir(wd)
475 self.log.info("Changing to working dir: %s" % wd)
475 self.log.info("Changing to working dir: %s" % wd)
476
476
477 def start_logging(self):
477 def start_logging(self):
478 # Remove old log files
478 # Remove old log files
479 if self.master_config.Global.clean_logs:
479 if self.master_config.Global.clean_logs:
480 log_dir = self.master_config.Global.log_dir
480 log_dir = self.master_config.Global.log_dir
481 for f in os.listdir(log_dir):
481 for f in os.listdir(log_dir):
482 if f.startswith(self.name + u'-') and f.endswith('.log'):
482 if f.startswith(self.name + u'-') and f.endswith('.log'):
483 os.remove(os.path.join(log_dir, f))
483 os.remove(os.path.join(log_dir, f))
484 # Start logging to the new log file
484 # Start logging to the new log file
485 if self.master_config.Global.log_to_file:
485 if self.master_config.Global.log_to_file:
486 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
486 log_filename = self.name + u'-' + str(os.getpid()) + u'.log'
487 logfile = os.path.join(self.log_dir, log_filename)
487 logfile = os.path.join(self.log_dir, log_filename)
488 open_log_file = open(logfile, 'w')
488 open_log_file = open(logfile, 'w')
489 else:
489 else:
490 open_log_file = sys.stdout
490 open_log_file = sys.stdout
491 log.startLogging(open_log_file)
491 log.startLogging(open_log_file)
492
492
493 def write_pid_file(self, overwrite=False):
493 def write_pid_file(self, overwrite=False):
494 """Create a .pid file in the pid_dir with my pid.
494 """Create a .pid file in the pid_dir with my pid.
495
495
496 This must be called after pre_construct, which sets `self.pid_dir`.
496 This must be called after pre_construct, which sets `self.pid_dir`.
497 This raises :exc:`PIDFileError` if the pid file exists already.
497 This raises :exc:`PIDFileError` if the pid file exists already.
498 """
498 """
499 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
499 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
500 if os.path.isfile(pid_file):
500 if os.path.isfile(pid_file):
501 pid = self.get_pid_from_file()
501 pid = self.get_pid_from_file()
502 if not overwrite:
502 if not overwrite:
503 raise PIDFileError(
503 raise PIDFileError(
504 'The pid file [%s] already exists. \nThis could mean that this '
504 'The pid file [%s] already exists. \nThis could mean that this '
505 'server is already running with [pid=%s].' % (pid_file, pid)
505 'server is already running with [pid=%s].' % (pid_file, pid)
506 )
506 )
507 with open(pid_file, 'w') as f:
507 with open(pid_file, 'w') as f:
508 self.log.info("Creating pid file: %s" % pid_file)
508 self.log.info("Creating pid file: %s" % pid_file)
509 f.write(repr(os.getpid())+'\n')
509 f.write(repr(os.getpid())+'\n')
510
510
511 def remove_pid_file(self):
511 def remove_pid_file(self):
512 """Remove the pid file.
512 """Remove the pid file.
513
513
514 This should be called at shutdown by registering a callback with
514 This should be called at shutdown by registering a callback with
515 :func:`reactor.addSystemEventTrigger`. This needs to return
515 :func:`reactor.addSystemEventTrigger`. This needs to return
516 ``None``.
516 ``None``.
517 """
517 """
518 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
518 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
519 if os.path.isfile(pid_file):
519 if os.path.isfile(pid_file):
520 try:
520 try:
521 self.log.info("Removing pid file: %s" % pid_file)
521 self.log.info("Removing pid file: %s" % pid_file)
522 os.remove(pid_file)
522 os.remove(pid_file)
523 except:
523 except:
524 self.log.warn("Error removing the pid file: %s" % pid_file)
524 self.log.warn("Error removing the pid file: %s" % pid_file)
525
525
526 def get_pid_from_file(self):
526 def get_pid_from_file(self):
527 """Get the pid from the pid file.
527 """Get the pid from the pid file.
528
528
529 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
529 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
530 """
530 """
531 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
531 pid_file = os.path.join(self.pid_dir, self.name + u'.pid')
532 if os.path.isfile(pid_file):
532 if os.path.isfile(pid_file):
533 with open(pid_file, 'r') as f:
533 with open(pid_file, 'r') as f:
534 pid = int(f.read().strip())
534 pid = int(f.read().strip())
535 return pid
535 return pid
536 else:
536 else:
537 raise PIDFileError('pid file not found: %s' % pid_file)
537 raise PIDFileError('pid file not found: %s' % pid_file)
538
538
@@ -1,442 +1,442
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """IPython Test Suite Runner.
2 """IPython Test Suite Runner.
3
3
4 This module provides a main entry point to a user script to test IPython
4 This module provides a main entry point to a user script to test IPython
5 itself from the command line. There are two ways of running this script:
5 itself from the command line. There are two ways of running this script:
6
6
7 1. With the syntax `iptest all`. This runs our entire test suite by
7 1. With the syntax `iptest all`. This runs our entire test suite by
8 calling this script (with different arguments) or trial recursively. This
8 calling this script (with different arguments) or trial recursively. This
9 causes modules and package to be tested in different processes, using nose
9 causes modules and package to be tested in different processes, using nose
10 or trial where appropriate.
10 or trial where appropriate.
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 the script simply calls nose, but with special command line flags and
12 the script simply calls nose, but with special command line flags and
13 plugins loaded.
13 plugins loaded.
14
14
15 For now, this script requires that both nose and twisted are installed. This
15 For now, this script requires that both nose and twisted are installed. This
16 will change in the future.
16 will change in the future.
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2009 The IPython Development Team
20 # Copyright (C) 2009 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 # Stdlib
30 # Stdlib
31 import os
31 import os
32 import os.path as path
32 import os.path as path
33 import signal
33 import signal
34 import sys
34 import sys
35 import subprocess
35 import subprocess
36 import tempfile
36 import tempfile
37 import time
37 import time
38 import warnings
38 import warnings
39
39
40 # Note: monkeypatch!
40 # Note: monkeypatch!
41 # We need to monkeypatch a small problem in nose itself first, before importing
41 # We need to monkeypatch a small problem in nose itself first, before importing
42 # it for actual use. This should get into nose upstream, but its release cycle
42 # it for actual use. This should get into nose upstream, but its release cycle
43 # is slow and we need it for our parametric tests to work correctly.
43 # is slow and we need it for our parametric tests to work correctly.
44 from IPython.testing import nosepatch
44 from IPython.testing import nosepatch
45 # Now, proceed to import nose itself
45 # Now, proceed to import nose itself
46 import nose.plugins.builtin
46 import nose.plugins.builtin
47 from nose.core import TestProgram
47 from nose.core import TestProgram
48
48
49 # Our own imports
49 # Our own imports
50 from IPython.utils.path import get_ipython_module_path
50 from IPython.utils.path import get_ipython_module_path
51 from IPython.utils.process import find_cmd, pycmd2argv
51 from IPython.utils.process import find_cmd, pycmd2argv
52 from IPython.utils.sysinfo import sys_info
52 from IPython.utils.sysinfo import sys_info
53
53
54 from IPython.testing import globalipapp
54 from IPython.testing import globalipapp
55 from IPython.testing.plugin.ipdoctest import IPythonDoctest
55 from IPython.testing.plugin.ipdoctest import IPythonDoctest
56
56
57 pjoin = path.join
57 pjoin = path.join
58
58
59
59
60 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
61 # Globals
61 # Globals
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63
63
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # Warnings control
66 # Warnings control
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68
68
69 # Twisted generates annoying warnings with Python 2.6, as will do other code
69 # Twisted generates annoying warnings with Python 2.6, as will do other code
70 # that imports 'sets' as of today
70 # that imports 'sets' as of today
71 warnings.filterwarnings('ignore', 'the sets module is deprecated',
71 warnings.filterwarnings('ignore', 'the sets module is deprecated',
72 DeprecationWarning )
72 DeprecationWarning )
73
73
74 # This one also comes from Twisted
74 # This one also comes from Twisted
75 warnings.filterwarnings('ignore', 'the sha module is deprecated',
75 warnings.filterwarnings('ignore', 'the sha module is deprecated',
76 DeprecationWarning)
76 DeprecationWarning)
77
77
78 # Wx on Fedora11 spits these out
78 # Wx on Fedora11 spits these out
79 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
79 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
80 UserWarning)
80 UserWarning)
81
81
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83 # Logic for skipping doctests
83 # Logic for skipping doctests
84 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
85
85
86 def test_for(mod):
86 def test_for(mod):
87 """Test to see if mod is importable."""
87 """Test to see if mod is importable."""
88 try:
88 try:
89 __import__(mod)
89 __import__(mod)
90 except (ImportError, RuntimeError):
90 except (ImportError, RuntimeError):
91 # GTK reports Runtime error if it can't be initialized even if it's
91 # GTK reports Runtime error if it can't be initialized even if it's
92 # importable.
92 # importable.
93 return False
93 return False
94 else:
94 else:
95 return True
95 return True
96
96
97 # Global dict where we can store information on what we have and what we don't
97 # Global dict where we can store information on what we have and what we don't
98 # have available at test run time
98 # have available at test run time
99 have = {}
99 have = {}
100
100
101 have['curses'] = test_for('_curses')
101 have['curses'] = test_for('_curses')
102 have['wx'] = test_for('wx')
102 have['wx'] = test_for('wx')
103 have['wx.aui'] = test_for('wx.aui')
103 have['wx.aui'] = test_for('wx.aui')
104 have['zope.interface'] = test_for('zope.interface')
104 have['zope.interface'] = test_for('zope.interface')
105 have['twisted'] = test_for('twisted')
105 have['twisted'] = test_for('twisted')
106 have['foolscap'] = test_for('foolscap')
106 have['foolscap'] = test_for('foolscap')
107 have['pexpect'] = test_for('pexpect')
107 have['pexpect'] = test_for('pexpect')
108 have['gtk'] = test_for('gtk')
108 have['gtk'] = test_for('gtk')
109 have['gobject'] = test_for('gobject')
109 have['gobject'] = test_for('gobject')
110
110
111 #-----------------------------------------------------------------------------
111 #-----------------------------------------------------------------------------
112 # Functions and classes
112 # Functions and classes
113 #-----------------------------------------------------------------------------
113 #-----------------------------------------------------------------------------
114
114
115 def report():
115 def report():
116 """Return a string with a summary report of test-related variables."""
116 """Return a string with a summary report of test-related variables."""
117
117
118 out = [ sys_info() ]
118 out = [ sys_info(), '\n']
119
119
120 avail = []
120 avail = []
121 not_avail = []
121 not_avail = []
122
122
123 for k, is_avail in have.items():
123 for k, is_avail in have.items():
124 if is_avail:
124 if is_avail:
125 avail.append(k)
125 avail.append(k)
126 else:
126 else:
127 not_avail.append(k)
127 not_avail.append(k)
128
128
129 if avail:
129 if avail:
130 out.append('\nTools and libraries available at test time:\n')
130 out.append('\nTools and libraries available at test time:\n')
131 avail.sort()
131 avail.sort()
132 out.append(' ' + ' '.join(avail)+'\n')
132 out.append(' ' + ' '.join(avail)+'\n')
133
133
134 if not_avail:
134 if not_avail:
135 out.append('\nTools and libraries NOT available at test time:\n')
135 out.append('\nTools and libraries NOT available at test time:\n')
136 not_avail.sort()
136 not_avail.sort()
137 out.append(' ' + ' '.join(not_avail)+'\n')
137 out.append(' ' + ' '.join(not_avail)+'\n')
138
138
139 return ''.join(out)
139 return ''.join(out)
140
140
141
141
142 def make_exclude():
142 def make_exclude():
143 """Make patterns of modules and packages to exclude from testing.
143 """Make patterns of modules and packages to exclude from testing.
144
144
145 For the IPythonDoctest plugin, we need to exclude certain patterns that
145 For the IPythonDoctest plugin, we need to exclude certain patterns that
146 cause testing problems. We should strive to minimize the number of
146 cause testing problems. We should strive to minimize the number of
147 skipped modules, since this means untested code.
147 skipped modules, since this means untested code.
148
148
149 These modules and packages will NOT get scanned by nose at all for tests.
149 These modules and packages will NOT get scanned by nose at all for tests.
150 """
150 """
151 # Simple utility to make IPython paths more readably, we need a lot of
151 # Simple utility to make IPython paths more readably, we need a lot of
152 # these below
152 # these below
153 ipjoin = lambda *paths: pjoin('IPython', *paths)
153 ipjoin = lambda *paths: pjoin('IPython', *paths)
154
154
155 exclusions = [ipjoin('external'),
155 exclusions = [ipjoin('external'),
156 pjoin('IPython_doctest_plugin'),
156 pjoin('IPython_doctest_plugin'),
157 ipjoin('quarantine'),
157 ipjoin('quarantine'),
158 ipjoin('deathrow'),
158 ipjoin('deathrow'),
159 ipjoin('testing', 'attic'),
159 ipjoin('testing', 'attic'),
160 # This guy is probably attic material
160 # This guy is probably attic material
161 ipjoin('testing', 'mkdoctests'),
161 ipjoin('testing', 'mkdoctests'),
162 # Testing inputhook will need a lot of thought, to figure out
162 # Testing inputhook will need a lot of thought, to figure out
163 # how to have tests that don't lock up with the gui event
163 # how to have tests that don't lock up with the gui event
164 # loops in the picture
164 # loops in the picture
165 ipjoin('lib', 'inputhook'),
165 ipjoin('lib', 'inputhook'),
166 # Config files aren't really importable stand-alone
166 # Config files aren't really importable stand-alone
167 ipjoin('config', 'default'),
167 ipjoin('config', 'default'),
168 ipjoin('config', 'profile'),
168 ipjoin('config', 'profile'),
169 ]
169 ]
170
170
171 if not have['wx']:
171 if not have['wx']:
172 exclusions.append(ipjoin('lib', 'inputhookwx'))
172 exclusions.append(ipjoin('lib', 'inputhookwx'))
173
173
174 if not have['gtk'] or not have['gobject']:
174 if not have['gtk'] or not have['gobject']:
175 exclusions.append(ipjoin('lib', 'inputhookgtk'))
175 exclusions.append(ipjoin('lib', 'inputhookgtk'))
176
176
177 # These have to be skipped on win32 because the use echo, rm, cd, etc.
177 # These have to be skipped on win32 because the use echo, rm, cd, etc.
178 # See ticket https://bugs.launchpad.net/bugs/366982
178 # See ticket https://bugs.launchpad.net/bugs/366982
179 if sys.platform == 'win32':
179 if sys.platform == 'win32':
180 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
180 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
181 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
181 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
182
182
183 if not have['pexpect']:
183 if not have['pexpect']:
184 exclusions.extend([ipjoin('scripts', 'irunner'),
184 exclusions.extend([ipjoin('scripts', 'irunner'),
185 ipjoin('lib', 'irunner')])
185 ipjoin('lib', 'irunner')])
186
186
187 # This is scary. We still have things in frontend and testing that
187 # This is scary. We still have things in frontend and testing that
188 # are being tested by nose that use twisted. We need to rethink
188 # are being tested by nose that use twisted. We need to rethink
189 # how we are isolating dependencies in testing.
189 # how we are isolating dependencies in testing.
190 if not (have['twisted'] and have['zope.interface'] and have['foolscap']):
190 if not (have['twisted'] and have['zope.interface'] and have['foolscap']):
191 exclusions.extend(
191 exclusions.extend(
192 [ipjoin('testing', 'parametric'),
192 [ipjoin('testing', 'parametric'),
193 ipjoin('testing', 'util'),
193 ipjoin('testing', 'util'),
194 ipjoin('testing', 'tests', 'test_decorators_trial'),
194 ipjoin('testing', 'tests', 'test_decorators_trial'),
195 ] )
195 ] )
196
196
197 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
197 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
198 if sys.platform == 'win32':
198 if sys.platform == 'win32':
199 exclusions = [s.replace('\\','\\\\') for s in exclusions]
199 exclusions = [s.replace('\\','\\\\') for s in exclusions]
200
200
201 return exclusions
201 return exclusions
202
202
203
203
204 class IPTester(object):
204 class IPTester(object):
205 """Call that calls iptest or trial in a subprocess.
205 """Call that calls iptest or trial in a subprocess.
206 """
206 """
207 #: string, name of test runner that will be called
207 #: string, name of test runner that will be called
208 runner = None
208 runner = None
209 #: list, parameters for test runner
209 #: list, parameters for test runner
210 params = None
210 params = None
211 #: list, arguments of system call to be made to call test runner
211 #: list, arguments of system call to be made to call test runner
212 call_args = None
212 call_args = None
213 #: list, process ids of subprocesses we start (for cleanup)
213 #: list, process ids of subprocesses we start (for cleanup)
214 pids = None
214 pids = None
215
215
216 def __init__(self, runner='iptest', params=None):
216 def __init__(self, runner='iptest', params=None):
217 """Create new test runner."""
217 """Create new test runner."""
218 p = os.path
218 p = os.path
219 if runner == 'iptest':
219 if runner == 'iptest':
220 iptest_app = get_ipython_module_path('IPython.testing.iptest')
220 iptest_app = get_ipython_module_path('IPython.testing.iptest')
221 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
221 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
222 elif runner == 'trial':
222 elif runner == 'trial':
223 # For trial, it needs to be installed system-wide
223 # For trial, it needs to be installed system-wide
224 self.runner = pycmd2argv(p.abspath(find_cmd('trial')))
224 self.runner = pycmd2argv(p.abspath(find_cmd('trial')))
225 else:
225 else:
226 raise Exception('Not a valid test runner: %s' % repr(runner))
226 raise Exception('Not a valid test runner: %s' % repr(runner))
227 if params is None:
227 if params is None:
228 params = []
228 params = []
229 if isinstance(params, str):
229 if isinstance(params, str):
230 params = [params]
230 params = [params]
231 self.params = params
231 self.params = params
232
232
233 # Assemble call
233 # Assemble call
234 self.call_args = self.runner+self.params
234 self.call_args = self.runner+self.params
235
235
236 # Store pids of anything we start to clean up on deletion, if possible
236 # Store pids of anything we start to clean up on deletion, if possible
237 # (on posix only, since win32 has no os.kill)
237 # (on posix only, since win32 has no os.kill)
238 self.pids = []
238 self.pids = []
239
239
240 if sys.platform == 'win32':
240 if sys.platform == 'win32':
241 def _run_cmd(self):
241 def _run_cmd(self):
242 # On Windows, use os.system instead of subprocess.call, because I
242 # On Windows, use os.system instead of subprocess.call, because I
243 # was having problems with subprocess and I just don't know enough
243 # was having problems with subprocess and I just don't know enough
244 # about win32 to debug this reliably. Os.system may be the 'old
244 # about win32 to debug this reliably. Os.system may be the 'old
245 # fashioned' way to do it, but it works just fine. If someone
245 # fashioned' way to do it, but it works just fine. If someone
246 # later can clean this up that's fine, as long as the tests run
246 # later can clean this up that's fine, as long as the tests run
247 # reliably in win32.
247 # reliably in win32.
248 # What types of problems are you having. They may be related to
248 # What types of problems are you having. They may be related to
249 # running Python in unboffered mode. BG.
249 # running Python in unboffered mode. BG.
250 return os.system(' '.join(self.call_args))
250 return os.system(' '.join(self.call_args))
251 else:
251 else:
252 def _run_cmd(self):
252 def _run_cmd(self):
253 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
253 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
254 subp = subprocess.Popen(self.call_args)
254 subp = subprocess.Popen(self.call_args)
255 self.pids.append(subp.pid)
255 self.pids.append(subp.pid)
256 # If this fails, the pid will be left in self.pids and cleaned up
256 # If this fails, the pid will be left in self.pids and cleaned up
257 # later, but if the wait call succeeds, then we can clear the
257 # later, but if the wait call succeeds, then we can clear the
258 # stored pid.
258 # stored pid.
259 retcode = subp.wait()
259 retcode = subp.wait()
260 self.pids.pop()
260 self.pids.pop()
261 return retcode
261 return retcode
262
262
263 def run(self):
263 def run(self):
264 """Run the stored commands"""
264 """Run the stored commands"""
265 try:
265 try:
266 return self._run_cmd()
266 return self._run_cmd()
267 except:
267 except:
268 import traceback
268 import traceback
269 traceback.print_exc()
269 traceback.print_exc()
270 return 1 # signal failure
270 return 1 # signal failure
271
271
272 def __del__(self):
272 def __del__(self):
273 """Cleanup on exit by killing any leftover processes."""
273 """Cleanup on exit by killing any leftover processes."""
274
274
275 if not hasattr(os, 'kill'):
275 if not hasattr(os, 'kill'):
276 return
276 return
277
277
278 for pid in self.pids:
278 for pid in self.pids:
279 try:
279 try:
280 print 'Cleaning stale PID:', pid
280 print 'Cleaning stale PID:', pid
281 os.kill(pid, signal.SIGKILL)
281 os.kill(pid, signal.SIGKILL)
282 except OSError:
282 except OSError:
283 # This is just a best effort, if we fail or the process was
283 # This is just a best effort, if we fail or the process was
284 # really gone, ignore it.
284 # really gone, ignore it.
285 pass
285 pass
286
286
287
287
288 def make_runners():
288 def make_runners():
289 """Define the top-level packages that need to be tested.
289 """Define the top-level packages that need to be tested.
290 """
290 """
291
291
292 # Packages to be tested via nose, that only depend on the stdlib
292 # Packages to be tested via nose, that only depend on the stdlib
293 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
293 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
294 'scripts', 'testing', 'utils' ]
294 'scripts', 'testing', 'utils' ]
295 # The machinery in kernel needs twisted for real testing
295 # The machinery in kernel needs twisted for real testing
296 trial_pkg_names = []
296 trial_pkg_names = []
297
297
298 # And add twisted ones if conditions are met
298 # And add twisted ones if conditions are met
299 if have['zope.interface'] and have['twisted'] and have['foolscap']:
299 if have['zope.interface'] and have['twisted'] and have['foolscap']:
300 # We only list IPython.kernel for testing using twisted.trial as
300 # We only list IPython.kernel for testing using twisted.trial as
301 # nose and twisted.trial have conflicts that make the testing system
301 # nose and twisted.trial have conflicts that make the testing system
302 # unstable.
302 # unstable.
303 trial_pkg_names.append('kernel')
303 trial_pkg_names.append('kernel')
304
304
305 # For debugging this code, only load quick stuff
305 # For debugging this code, only load quick stuff
306 #nose_pkg_names = ['core', 'extensions'] # dbg
306 #nose_pkg_names = ['core', 'extensions'] # dbg
307 #trial_pkg_names = [] # dbg
307 #trial_pkg_names = [] # dbg
308
308
309 # Make fully qualified package names prepending 'IPython.' to our name lists
309 # Make fully qualified package names prepending 'IPython.' to our name lists
310 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
310 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
311 trial_packages = ['IPython.%s' % m for m in trial_pkg_names ]
311 trial_packages = ['IPython.%s' % m for m in trial_pkg_names ]
312
312
313 # Make runners
313 # Make runners
314 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
314 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
315 runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ])
315 runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ])
316
316
317 return runners
317 return runners
318
318
319
319
320 def run_iptest():
320 def run_iptest():
321 """Run the IPython test suite using nose.
321 """Run the IPython test suite using nose.
322
322
323 This function is called when this script is **not** called with the form
323 This function is called when this script is **not** called with the form
324 `iptest all`. It simply calls nose with appropriate command line flags
324 `iptest all`. It simply calls nose with appropriate command line flags
325 and accepts all of the standard nose arguments.
325 and accepts all of the standard nose arguments.
326 """
326 """
327
327
328 warnings.filterwarnings('ignore',
328 warnings.filterwarnings('ignore',
329 'This will be removed soon. Use IPython.testing.util instead')
329 'This will be removed soon. Use IPython.testing.util instead')
330
330
331 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
331 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
332
332
333 # Loading ipdoctest causes problems with Twisted, but
333 # Loading ipdoctest causes problems with Twisted, but
334 # our test suite runner now separates things and runs
334 # our test suite runner now separates things and runs
335 # all Twisted tests with trial.
335 # all Twisted tests with trial.
336 '--with-ipdoctest',
336 '--with-ipdoctest',
337 '--ipdoctest-tests','--ipdoctest-extension=txt',
337 '--ipdoctest-tests','--ipdoctest-extension=txt',
338
338
339 # We add --exe because of setuptools' imbecility (it
339 # We add --exe because of setuptools' imbecility (it
340 # blindly does chmod +x on ALL files). Nose does the
340 # blindly does chmod +x on ALL files). Nose does the
341 # right thing and it tries to avoid executables,
341 # right thing and it tries to avoid executables,
342 # setuptools unfortunately forces our hand here. This
342 # setuptools unfortunately forces our hand here. This
343 # has been discussed on the distutils list and the
343 # has been discussed on the distutils list and the
344 # setuptools devs refuse to fix this problem!
344 # setuptools devs refuse to fix this problem!
345 '--exe',
345 '--exe',
346 ]
346 ]
347
347
348 if nose.__version__ >= '0.11':
348 if nose.__version__ >= '0.11':
349 # I don't fully understand why we need this one, but depending on what
349 # I don't fully understand why we need this one, but depending on what
350 # directory the test suite is run from, if we don't give it, 0 tests
350 # directory the test suite is run from, if we don't give it, 0 tests
351 # get run. Specifically, if the test suite is run from the source dir
351 # get run. Specifically, if the test suite is run from the source dir
352 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
352 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
353 # even if the same call done in this directory works fine). It appears
353 # even if the same call done in this directory works fine). It appears
354 # that if the requested package is in the current dir, nose bails early
354 # that if the requested package is in the current dir, nose bails early
355 # by default. Since it's otherwise harmless, leave it in by default
355 # by default. Since it's otherwise harmless, leave it in by default
356 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
356 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
357 argv.append('--traverse-namespace')
357 argv.append('--traverse-namespace')
358
358
359 # Construct list of plugins, omitting the existing doctest plugin, which
359 # Construct list of plugins, omitting the existing doctest plugin, which
360 # ours replaces (and extends).
360 # ours replaces (and extends).
361 plugins = [IPythonDoctest(make_exclude())]
361 plugins = [IPythonDoctest(make_exclude())]
362 for p in nose.plugins.builtin.plugins:
362 for p in nose.plugins.builtin.plugins:
363 plug = p()
363 plug = p()
364 if plug.name == 'doctest':
364 if plug.name == 'doctest':
365 continue
365 continue
366 plugins.append(plug)
366 plugins.append(plug)
367
367
368 # We need a global ipython running in this process
368 # We need a global ipython running in this process
369 globalipapp.start_ipython()
369 globalipapp.start_ipython()
370 # Now nose can run
370 # Now nose can run
371 TestProgram(argv=argv, plugins=plugins)
371 TestProgram(argv=argv, plugins=plugins)
372
372
373
373
374 def run_iptestall():
374 def run_iptestall():
375 """Run the entire IPython test suite by calling nose and trial.
375 """Run the entire IPython test suite by calling nose and trial.
376
376
377 This function constructs :class:`IPTester` instances for all IPython
377 This function constructs :class:`IPTester` instances for all IPython
378 modules and package and then runs each of them. This causes the modules
378 modules and package and then runs each of them. This causes the modules
379 and packages of IPython to be tested each in their own subprocess using
379 and packages of IPython to be tested each in their own subprocess using
380 nose or twisted.trial appropriately.
380 nose or twisted.trial appropriately.
381 """
381 """
382
382
383 runners = make_runners()
383 runners = make_runners()
384
384
385 # Run the test runners in a temporary dir so we can nuke it when finished
385 # Run the test runners in a temporary dir so we can nuke it when finished
386 # to clean up any junk files left over by accident. This also makes it
386 # to clean up any junk files left over by accident. This also makes it
387 # robust against being run in non-writeable directories by mistake, as the
387 # robust against being run in non-writeable directories by mistake, as the
388 # temp dir will always be user-writeable.
388 # temp dir will always be user-writeable.
389 curdir = os.getcwd()
389 curdir = os.getcwd()
390 testdir = tempfile.gettempdir()
390 testdir = tempfile.gettempdir()
391 os.chdir(testdir)
391 os.chdir(testdir)
392
392
393 # Run all test runners, tracking execution time
393 # Run all test runners, tracking execution time
394 failed = []
394 failed = []
395 t_start = time.time()
395 t_start = time.time()
396 try:
396 try:
397 for (name, runner) in runners:
397 for (name, runner) in runners:
398 print '*'*70
398 print '*'*70
399 print 'IPython test group:',name
399 print 'IPython test group:',name
400 res = runner.run()
400 res = runner.run()
401 if res:
401 if res:
402 failed.append( (name, runner) )
402 failed.append( (name, runner) )
403 finally:
403 finally:
404 os.chdir(curdir)
404 os.chdir(curdir)
405 t_end = time.time()
405 t_end = time.time()
406 t_tests = t_end - t_start
406 t_tests = t_end - t_start
407 nrunners = len(runners)
407 nrunners = len(runners)
408 nfail = len(failed)
408 nfail = len(failed)
409 # summarize results
409 # summarize results
410 print
410 print
411 print '*'*70
411 print '*'*70
412 print 'Test suite completed for system with the following information:'
412 print 'Test suite completed for system with the following information:'
413 print report()
413 print report()
414 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
414 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
415 print
415 print
416 print 'Status:'
416 print 'Status:'
417 if not failed:
417 if not failed:
418 print 'OK'
418 print 'OK'
419 else:
419 else:
420 # If anything went wrong, point out what command to rerun manually to
420 # If anything went wrong, point out what command to rerun manually to
421 # see the actual errors and individual summary
421 # see the actual errors and individual summary
422 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
422 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
423 for name, failed_runner in failed:
423 for name, failed_runner in failed:
424 print '-'*40
424 print '-'*40
425 print 'Runner failed:',name
425 print 'Runner failed:',name
426 print 'You may wish to rerun this one individually, with:'
426 print 'You may wish to rerun this one individually, with:'
427 print ' '.join(failed_runner.call_args)
427 print ' '.join(failed_runner.call_args)
428 print
428 print
429
429
430
430
431 def main():
431 def main():
432 for arg in sys.argv[1:]:
432 for arg in sys.argv[1:]:
433 if arg.startswith('IPython'):
433 if arg.startswith('IPython'):
434 # This is in-process
434 # This is in-process
435 run_iptest()
435 run_iptest()
436 else:
436 else:
437 # This starts subprocesses
437 # This starts subprocesses
438 run_iptestall()
438 run_iptestall()
439
439
440
440
441 if __name__ == '__main__':
441 if __name__ == '__main__':
442 main()
442 main()
@@ -1,100 +1,185
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for getting information about a system.
3 Utilities for getting information about IPython and the system it's running in.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import platform
18 import platform
19 import pprint
19 import sys
20 import sys
20 import subprocess
21 import subprocess
21
22
23 from ConfigParser import ConfigParser
24
22 from IPython.core import release
25 from IPython.core import release
23
26
24 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Globals
29 #-----------------------------------------------------------------------------
30 COMMIT_INFO_FNAME = '.git_commit_info.ini'
31
32 #-----------------------------------------------------------------------------
25 # Code
33 # Code
26 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
27
35
36 def pkg_commit_hash(pkg_path):
37 """Get short form of commit hash given directory `pkg_path`
38
39 There should be a file called 'COMMIT_INFO.txt' in `pkg_path`. This is a
40 file in INI file format, with at least one section: ``commit hash``, and two
41 variables ``archive_subst_hash`` and ``install_hash``. The first has a
42 substitution pattern in it which may have been filled by the execution of
43 ``git archive`` if this is an archive generated that way. The second is
44 filled in by the installation, if the installation is from a git archive.
45
46 We get the commit hash from (in order of preference):
47
48 * A substituted value in ``archive_subst_hash``
49 * A written commit hash value in ``install_hash`
50 * git output, if we are in a git repository
51
52 If all these fail, we return a not-found placeholder tuple
53
54 Parameters
55 ----------
56 pkg_path : str
57 directory containing package
58
59 Returns
60 -------
61 hash_from : str
62 Where we got the hash from - description
63 hash_str : str
64 short form of hash
65 """
66 # Try and get commit from written commit text file
67 pth = os.path.join(pkg_path, COMMIT_INFO_FNAME)
68 if not os.path.isfile(pth):
69 raise IOError('Missing commit info file %s' % pth)
70 cfg_parser = ConfigParser()
71 cfg_parser.read(pth)
72 archive_subst = cfg_parser.get('commit hash', 'archive_subst_hash')
73 if not archive_subst.startswith('$Format'): # it has been substituted
74 return 'archive substitution', archive_subst
75 install_subst = cfg_parser.get('commit hash', 'install_hash')
76 if install_subst != '':
77 return 'installation', install_subst
78 # maybe we are in a repository
79 proc = subprocess.Popen('git rev-parse --short HEAD',
80 stdout=subprocess.PIPE,
81 stderr=subprocess.PIPE,
82 cwd=pkg_path, shell=True)
83 repo_commit, _ = proc.communicate()
84 if repo_commit:
85 return 'repository', repo_commit.strip()
86 return '(none found)', '<not found>'
87
88
89 def pkg_info(pkg_path):
90 """Return dict describing the context of this package
91
92 Parameters
93 ----------
94 pkg_path : str
95 path containing __init__.py for package
96
97 Returns
98 -------
99 context : dict
100 with named parameters of interest
101 """
102 src, hsh = pkg_commit_hash(pkg_path)
103 return dict(
104 ipython_version=release.version,
105 ipython_path=pkg_path,
106 commit_source=src,
107 commit_hash=hsh,
108 sys_version=sys.version,
109 sys_executable=sys.executable,
110 sys_platform=sys.platform,
111 platform=platform.platform(),
112 os_name=os.name,
113 )
114
115
28 def sys_info():
116 def sys_info():
29 """Return useful information about IPython and the system, as a string.
117 """Return useful information about IPython and the system, as a string.
30
118
31 Examples
119 Example
32 --------
120 -------
33 In [1]: print(sys_info())
121 In [2]: print sys_info()
34 IPython version: 0.11.bzr.r1340 # random
122 {'commit_hash': '144fdae', # random
35 BZR revision : 1340
123 'commit_source': 'repository',
36 Platform info : os.name -> posix, sys.platform -> linux2
124 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
37 : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic
125 'ipython_version': '0.11.dev',
38 Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15)
126 'os_name': 'posix',
39 [GCC 4.4.1]
127 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
40 """
128 'sys_executable': '/usr/bin/python',
41 out = []
129 'sys_platform': 'linux2',
42 out.append('IPython version: %s' % release.version)
130 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \\n[GCC 4.4.5]'}
43 out.append('BZR revision : %s' % release.revision)
131 """
44 out.append('Platform info : os.name -> %s, sys.platform -> %s' %
132 p = os.path
45 (os.name,sys.platform) )
133 path = p.dirname(p.abspath(p.join(__file__, '..')))
46 out.append(' : %s' % platform.platform())
134 return pprint.pformat(pkg_info(path))
47 out.append('Python info : %s' % sys.version)
48 out.append('') # ensure closing newline
49 return '\n'.join(out)
50
135
51
136
52 def _num_cpus_unix():
137 def _num_cpus_unix():
53 """Return the number of active CPUs on a Unix system."""
138 """Return the number of active CPUs on a Unix system."""
54 return os.sysconf("SC_NPROCESSORS_ONLN")
139 return os.sysconf("SC_NPROCESSORS_ONLN")
55
140
56
141
57 def _num_cpus_darwin():
142 def _num_cpus_darwin():
58 """Return the number of active CPUs on a Darwin system."""
143 """Return the number of active CPUs on a Darwin system."""
59 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
144 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
60 return p.stdout.read()
145 return p.stdout.read()
61
146
62
147
63 def _num_cpus_windows():
148 def _num_cpus_windows():
64 """Return the number of active CPUs on a Windows system."""
149 """Return the number of active CPUs on a Windows system."""
65 return os.environ.get("NUMBER_OF_PROCESSORS")
150 return os.environ.get("NUMBER_OF_PROCESSORS")
66
151
67
152
68 def num_cpus():
153 def num_cpus():
69 """Return the effective number of CPUs in the system as an integer.
154 """Return the effective number of CPUs in the system as an integer.
70
155
71 This cross-platform function makes an attempt at finding the total number of
156 This cross-platform function makes an attempt at finding the total number of
72 available CPUs in the system, as returned by various underlying system and
157 available CPUs in the system, as returned by various underlying system and
73 python calls.
158 python calls.
74
159
75 If it can't find a sensible answer, it returns 1 (though an error *may* make
160 If it can't find a sensible answer, it returns 1 (though an error *may* make
76 it return a large positive number that's actually incorrect).
161 it return a large positive number that's actually incorrect).
77 """
162 """
78
163
79 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
164 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
80 # for the names of the keys we needed to look up for this function. This
165 # for the names of the keys we needed to look up for this function. This
81 # code was inspired by their equivalent function.
166 # code was inspired by their equivalent function.
82
167
83 ncpufuncs = {'Linux':_num_cpus_unix,
168 ncpufuncs = {'Linux':_num_cpus_unix,
84 'Darwin':_num_cpus_darwin,
169 'Darwin':_num_cpus_darwin,
85 'Windows':_num_cpus_windows,
170 'Windows':_num_cpus_windows,
86 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
171 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
87 # See http://bugs.python.org/issue1082 for details.
172 # See http://bugs.python.org/issue1082 for details.
88 'Microsoft':_num_cpus_windows,
173 'Microsoft':_num_cpus_windows,
89 }
174 }
90
175
91 ncpufunc = ncpufuncs.get(platform.system(),
176 ncpufunc = ncpufuncs.get(platform.system(),
92 # default to unix version (Solaris, AIX, etc)
177 # default to unix version (Solaris, AIX, etc)
93 _num_cpus_unix)
178 _num_cpus_unix)
94
179
95 try:
180 try:
96 ncpus = max(1,int(ncpufunc()))
181 ncpus = max(1,int(ncpufunc()))
97 except:
182 except:
98 ncpus = 1
183 ncpus = 1
99 return ncpus
184 return ncpus
100
185
@@ -1,36 +1,37
1 include ipython.py
1 include ipython.py
2 include setupbase.py
2 include setupbase.py
3 include setupegg.py
3 include setupegg.py
4
4
5 graft setupext
5 graft setupext
6
6
7 graft scripts
7 graft scripts
8 graft IPython/kernel
8 graft IPython/kernel
9 graft IPython/config
9 graft IPython/config
10 graft IPython/core
10 graft IPython/core
11 # graft IPython/deathrow
11 # graft IPython/deathrow
12 graft IPython/external
12 graft IPython/external
13 graft IPython/frontend
13 graft IPython/frontend
14 graft IPython/gui
14 graft IPython/gui
15 graft IPython/lib
15 graft IPython/lib
16 graft IPython/quarantine
16 graft IPython/quarantine
17 graft IPython/scripts
17 graft IPython/scripts
18 graft IPython/testing
18 graft IPython/testing
19 graft IPython/utils
19 graft IPython/utils
20
20
21 include IPython/.git_commit_info.ini
21
22
22 graft docs
23 graft docs
23 exclude docs/\#*
24 exclude docs/\#*
24 exclude docs/man/*.1
25 exclude docs/man/*.1
25
26
26 # docs subdirs we want to skip
27 # docs subdirs we want to skip
27 prune docs/attic
28 prune docs/attic
28 prune docs/build
29 prune docs/build
29
30
30 global-exclude *~
31 global-exclude *~
31 global-exclude *.flc
32 global-exclude *.flc
32 global-exclude *.pyc
33 global-exclude *.pyc
33 global-exclude .dircopy.log
34 global-exclude .dircopy.log
34 global-exclude .svn
35 global-exclude .svn
35 global-exclude .bzr
36 global-exclude .bzr
36 global-exclude .hgignore
37 global-exclude .hgignore
@@ -1,40 +1,35
1 ==============
1 ==============
2 IPython README
2 IPython README
3 ==============
3 ==============
4
4
5 Overview
5 Overview
6 ========
6 ========
7
7
8 Welcome to IPython. Our full documentation can be found in the ``docs/dist``
8 Welcome to IPython. Our full documentation can be found in the ``docs/dist``
9 subdirectory in ``.html`` and ``.pdf`` formats, also available online at our
9 subdirectory in ``.html`` and ``.pdf`` formats, also available online at our
10 `website <http://ipython.scipy.org>`_. The ``docs/source`` directory contains
10 `website <http://ipython.scipy.org>`_. The ``docs/source`` directory contains
11 the plaintext version of these manuals.
11 the plaintext version of these manuals.
12
12
13
13
14 Dependencies and supported Python versions
14 Dependencies and supported Python versions
15 ==========================================
15 ==========================================
16
16
17 For full details, see the installation section of the manual. The basic parts
17 For full details, see the installation section of the manual. The basic parts
18 of IPython only need the Python standard library, but much of its more advanced
18 of IPython only need the Python standard library, but much of its more advanced
19 functionality requires extra packages.
19 functionality requires extra packages.
20
20
21 Officially, IPython requires Python version 2.5 or 2.6. We have *not* yet
21 Officially, IPython requires Python version 2.6 or 2.7. An experimental port
22 started to port IPython to Python 3.0.
22 of IPython to Python 3.x has been sarted, and is available at
23
23 http://github.com/takowl/ipython/tree/ipython-py3k.
24 .. warning::
25
26 IPython 0.10 has only been well tested with Python 2.5 and 2.6. Parts of
27 it may work with Python 2.4, but we do not officially support Python 2.4
28 anymore. If you need to use 2.4, you can still run IPython 0.9.
29
24
30
25
31 Instant running
26 Instant running
32 ===============
27 ===============
33
28
34 You can run IPython from this directory without even installing it system-wide
29 You can run IPython from this directory without even installing it system-wide
35 by typing at the terminal:
30 by typing at the terminal:
36
31
37 .. code-block:: bash
32 .. code-block:: bash
38
33
39 python ipython.py
34 python ipython.py
40
35
@@ -1,388 +1,391
1 .. _testing:
1 .. _testing:
2
2
3 ==========================================
3 ==========================================
4 Testing IPython for users and developers
4 Testing IPython for users and developers
5 ==========================================
5 ==========================================
6
6
7 Overview
7 Overview
8 ========
8 ========
9
9
10 It is extremely important that all code contributed to IPython has tests.
10 It is extremely important that all code contributed to IPython has tests.
11 Tests should be written as unittests, doctests or other entities that the
11 Tests should be written as unittests, doctests or other entities that the
12 IPython test system can detect. See below for more details on this.
12 IPython test system can detect. See below for more details on this.
13
13
14 Each subpackage in IPython should have its own :file:`tests` directory that
14 Each subpackage in IPython should have its own :file:`tests` directory that
15 contains all of the tests for that subpackage. All of the files in the
15 contains all of the tests for that subpackage. All of the files in the
16 :file:`tests` directory should have the word "tests" in them to enable
16 :file:`tests` directory should have the word "tests" in them to enable
17 the testing framework to find them.
17 the testing framework to find them.
18
18
19 In docstrings, examples (either using IPython prompts like ``In [1]:`` or
19 In docstrings, examples (either using IPython prompts like ``In [1]:`` or
20 'classic' python ``>>>`` ones) can and should be included. The testing system
20 'classic' python ``>>>`` ones) can and should be included. The testing system
21 will detect them as doctests and will run them; it offers control to skip parts
21 will detect them as doctests and will run them; it offers control to skip parts
22 or all of a specific doctest if the example is meant to be informative but
22 or all of a specific doctest if the example is meant to be informative but
23 shows non-reproducible information (like filesystem data).
23 shows non-reproducible information (like filesystem data).
24
24
25 If a subpackage has any dependencies beyond the Python standard library, the
25 If a subpackage has any dependencies beyond the Python standard library, the
26 tests for that subpackage should be skipped if the dependencies are not found.
26 tests for that subpackage should be skipped if the dependencies are not found.
27 This is very important so users don't get tests failing simply because they
27 This is very important so users don't get tests failing simply because they
28 don't have dependencies.
28 don't have dependencies.
29
29
30 The testing system we use is a hybrid of nose_ and Twisted's trial_ test runner.
30 The testing system we use is a hybrid of nose_ and Twisted's trial_ test runner.
31 We use both because nose detects more things than Twisted and allows for more
31 We use both because nose detects more things than Twisted and allows for more
32 flexible (and lighter-weight) ways of writing tests; in particular we've
32 flexible (and lighter-weight) ways of writing tests; in particular we've
33 developed a nose plugin that allows us to paste verbatim IPython sessions and
33 developed a nose plugin that allows us to paste verbatim IPython sessions and
34 test them as doctests, which is extremely important for us. But the parts of
34 test them as doctests, which is extremely important for us. But the parts of
35 IPython that depend on Twisted must be tested using trial, because only trial
35 IPython that depend on Twisted must be tested using trial, because only trial
36 manages the Twisted reactor correctly.
36 manages the Twisted reactor correctly.
37
37
38 .. _nose: http://code.google.com/p/python-nose
38 .. _nose: http://code.google.com/p/python-nose
39 .. _trial: http://twistedmatrix.com/trac/wiki/TwistedTrial
39 .. _trial: http://twistedmatrix.com/trac/wiki/TwistedTrial
40
40
41
41
42 For the impatient: running the tests
42 For the impatient: running the tests
43 ====================================
43 ====================================
44
44
45 You can run IPython from the source download directory without even installing
45 You can run IPython from the source download directory without even installing
46 it system-wide or having configure anything, by typing at the terminal:
46 it system-wide or having configure anything, by typing at the terminal:
47
47
48 .. code-block:: bash
48 .. code-block:: bash
49
49
50 python ipython.py
50 python ipython.py
51
51
52 and similarly, you can execute the built-in test suite with:
52 In order to run the test suite, you must at least be able to import IPython,
53
53 even if you haven't fully installed the user-facing scripts yet (common in a
54 .. code-block:: bash
54 development environment). You can then run the tests with:
55
56 python iptest.py
57
55
56 .. code-block:: bash
58
57
59 This script manages intelligently both nose and trial, choosing the correct
58 python -c "import IPython; IPython.test()"
60 test system for each of IPython's components.
61
59
62 Once you have either installed it or at least configured your system to be
60 Once you have installed IPython either via a full install or using:
63 able to import IPython, you can run the tests with:
64
61
65 .. code-block:: bash
62 .. code-block:: bash
66
63
67 python -c "import IPython; IPython.test()"
64 python setup.py develop
68
65
69 This should work as long as IPython can be imported, even if you haven't fully
66 you will have available a system-wide script called :file:`iptest` that runs
70 installed the user-facing scripts yet (common in a development environment).
67 the full test suite. You can then run the suite with:
71 Once you have installed IPython, you will have available system-wide a script
72 called :file:`iptest` that does the exact same as the :file:`iptest.py` script
73 in the source directory, so you can then test simply with:
74
68
75 .. code-block:: bash
69 .. code-block:: bash
76
70
77 iptest [args]
71 iptest [args]
78
72
79
73
80 Regardless of how you run things, you should eventually see something like:
74 Regardless of how you run things, you should eventually see something like:
81
75
82 .. code-block:: bash
76 .. code-block:: bash
83
77
84 **********************************************************************
78 **********************************************************************
85 Test suite completed for system with the following information:
79 Test suite completed for system with the following information:
86 IPython version: 0.11.bzr.r1340
80 {'commit_hash': '144fdae',
87 BZR revision : 1340
81 'commit_source': 'repository',
88 Platform info : os.name -> posix, sys.platform -> linux2
82 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
89 : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic
83 'ipython_version': '0.11.dev',
90 Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15)
84 'os_name': 'posix',
91 [GCC 4.4.1]
85 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
92
86 'sys_executable': '/usr/bin/python',
93 Running from an installed IPython: True
87 'sys_platform': 'linux2',
88 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \n[GCC 4.4.5]'}
94
89
95 Tools and libraries available at test time:
90 Tools and libraries available at test time:
96 curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface
91 curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface
97
92
98 Tools and libraries NOT available at test time:
93 Ran 9 test groups in 67.213s
99 objc
100
101 Ran 11 test groups in 36.244s
102
94
103 Status:
95 Status:
104 OK
96 OK
105
97
98
106 If not, there will be a message indicating which test group failed and how to
99 If not, there will be a message indicating which test group failed and how to
107 rerun that group individually. For example, this tests the
100 rerun that group individually. For example, this tests the
108 :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress
101 :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress
109 indicators:
102 indicators:
110
103
111 .. code-block:: bash
104 .. code-block:: bash
112
105
113 $ python iptest.py -v IPython.utils
106 $ iptest -v IPython.utils
114 ..........................SS..SSS............................S.S...
107 ..........................SS..SSS............................S.S...
115 .........................................................
108 .........................................................
116 ----------------------------------------------------------------------
109 ----------------------------------------------------------------------
117 Ran 125 tests in 0.119s
110 Ran 125 tests in 0.119s
118
111
119 OK (SKIP=7)
112 OK (SKIP=7)
120
113
121
114
122 Because the IPython test machinery is based on nose, you can use all nose
115 Because the IPython test machinery is based on nose, you can use all nose
123 options and syntax, typing ``iptest -h`` shows all available options. For
116 options and syntax, typing ``iptest -h`` shows all available options. For
124 example, this lets you run the specific test :func:`test_rehashx` inside the
117 example, this lets you run the specific test :func:`test_rehashx` inside the
125 :mod:`test_magic` module:
118 :mod:`test_magic` module:
126
119
127 .. code-block:: bash
120 .. code-block:: bash
128
121
129 $ python iptest.py -vv IPython.core.tests.test_magic:test_rehashx
122 $ iptest -vv IPython.core.tests.test_magic:test_rehashx
130 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
123 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
131 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
124 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
132
125
133 ----------------------------------------------------------------------
126 ----------------------------------------------------------------------
134 Ran 2 tests in 0.100s
127 Ran 2 tests in 0.100s
135
128
136 OK
129 OK
137
130
138 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
131 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
139 particularly useful, these drop you into an interactive pdb session at the
132 particularly useful, these drop you into an interactive pdb session at the
140 point of the error or failure respectively.
133 point of the error or failure respectively.
141
134
142 To run Twisted-using tests, use the :command:`trial` command on a per file or
135 To run Twisted-using tests, use the :command:`trial` command on a per file or
143 package basis:
136 package basis:
144
137
145 .. code-block:: bash
138 .. code-block:: bash
146
139
147 trial IPython.kernel
140 trial IPython.kernel
148
141
142 .. note::
143
144 The system information summary printed above is accessible from the top
145 level package. If you encounter a problem with IPython, it's useful to
146 include this information when reporting on the mailing list; use::
147
148 from IPython import sys_info
149 print sys_info()
150
151 and include the resulting information in your query.
149
152
150 For developers: writing tests
153 For developers: writing tests
151 =============================
154 =============================
152
155
153 By now IPython has a reasonable test suite, so the best way to see what's
156 By now IPython has a reasonable test suite, so the best way to see what's
154 available is to look at the :file:`tests` directory in most subpackages. But
157 available is to look at the :file:`tests` directory in most subpackages. But
155 here are a few pointers to make the process easier.
158 here are a few pointers to make the process easier.
156
159
157
160
158 Main tools: :mod:`IPython.testing`
161 Main tools: :mod:`IPython.testing`
159 ----------------------------------
162 ----------------------------------
160
163
161 The :mod:`IPython.testing` package is where all of the machinery to test
164 The :mod:`IPython.testing` package is where all of the machinery to test
162 IPython (rather than the tests for its various parts) lives. In particular,
165 IPython (rather than the tests for its various parts) lives. In particular,
163 the :mod:`iptest` module in there has all the smarts to control the test
166 the :mod:`iptest` module in there has all the smarts to control the test
164 process. In there, the :func:`make_exclude` function is used to build a
167 process. In there, the :func:`make_exclude` function is used to build a
165 blacklist of exclusions, these are modules that do not get even imported for
168 blacklist of exclusions, these are modules that do not get even imported for
166 tests. This is important so that things that would fail to even import because
169 tests. This is important so that things that would fail to even import because
167 of missing dependencies don't give errors to end users, as we stated above.
170 of missing dependencies don't give errors to end users, as we stated above.
168
171
169 The :mod:`decorators` module contains a lot of useful decorators, especially
172 The :mod:`decorators` module contains a lot of useful decorators, especially
170 useful to mark individual tests that should be skipped under certain conditions
173 useful to mark individual tests that should be skipped under certain conditions
171 (rather than blacklisting the package altogether because of a missing major
174 (rather than blacklisting the package altogether because of a missing major
172 dependency).
175 dependency).
173
176
174 Our nose plugin for doctests
177 Our nose plugin for doctests
175 ----------------------------
178 ----------------------------
176
179
177 The :mod:`plugin` subpackage in testing contains a nose plugin called
180 The :mod:`plugin` subpackage in testing contains a nose plugin called
178 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
181 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
179 doctests with IPython prompts. You can also mark doctest output with ``#
182 doctests with IPython prompts. You can also mark doctest output with ``#
180 random`` for the output corresponding to a single input to be ignored (stronger
183 random`` for the output corresponding to a single input to be ignored (stronger
181 than using ellipsis and useful to keep it as an example). If you want the
184 than using ellipsis and useful to keep it as an example). If you want the
182 entire docstring to be executed but none of the output from any input to be
185 entire docstring to be executed but none of the output from any input to be
183 checked, you can use the ``# all-random`` marker. The
186 checked, you can use the ``# all-random`` marker. The
184 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
187 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
185 these; for reference here is how to use ``# random``::
188 these; for reference here is how to use ``# random``::
186
189
187 def ranfunc():
190 def ranfunc():
188 """A function with some random output.
191 """A function with some random output.
189
192
190 Normal examples are verified as usual:
193 Normal examples are verified as usual:
191 >>> 1+3
194 >>> 1+3
192 4
195 4
193
196
194 But if you put '# random' in the output, it is ignored:
197 But if you put '# random' in the output, it is ignored:
195 >>> 1+3
198 >>> 1+3
196 junk goes here... # random
199 junk goes here... # random
197
200
198 >>> 1+2
201 >>> 1+2
199 again, anything goes #random
202 again, anything goes #random
200 if multiline, the random mark is only needed once.
203 if multiline, the random mark is only needed once.
201
204
202 >>> 1+2
205 >>> 1+2
203 You can also put the random marker at the end:
206 You can also put the random marker at the end:
204 # random
207 # random
205
208
206 >>> 1+2
209 >>> 1+2
207 # random
210 # random
208 .. or at the beginning.
211 .. or at the beginning.
209
212
210 More correct input is properly verified:
213 More correct input is properly verified:
211 >>> ranfunc()
214 >>> ranfunc()
212 'ranfunc'
215 'ranfunc'
213 """
216 """
214 return 'ranfunc'
217 return 'ranfunc'
215
218
216 and an example of ``# all-random``::
219 and an example of ``# all-random``::
217
220
218 def random_all():
221 def random_all():
219 """A function where we ignore the output of ALL examples.
222 """A function where we ignore the output of ALL examples.
220
223
221 Examples:
224 Examples:
222
225
223 # all-random
226 # all-random
224
227
225 This mark tells the testing machinery that all subsequent examples
228 This mark tells the testing machinery that all subsequent examples
226 should be treated as random (ignoring their output). They are still
229 should be treated as random (ignoring their output). They are still
227 executed, so if a they raise an error, it will be detected as such,
230 executed, so if a they raise an error, it will be detected as such,
228 but their output is completely ignored.
231 but their output is completely ignored.
229
232
230 >>> 1+3
233 >>> 1+3
231 junk goes here...
234 junk goes here...
232
235
233 >>> 1+3
236 >>> 1+3
234 klasdfj;
237 klasdfj;
235
238
236 In [8]: print 'hello'
239 In [8]: print 'hello'
237 world # random
240 world # random
238
241
239 In [9]: iprand()
242 In [9]: iprand()
240 Out[9]: 'iprand'
243 Out[9]: 'iprand'
241 """
244 """
242 return 'iprand'
245 return 'iprand'
243
246
244
247
245 When writing docstrings, you can use the ``@skip_doctest`` decorator to
248 When writing docstrings, you can use the ``@skip_doctest`` decorator to
246 indicate that a docstring should *not* be treated as a doctest at all. The
249 indicate that a docstring should *not* be treated as a doctest at all. The
247 difference between ``# all-random`` and ``@skip_doctest`` is that the former
250 difference between ``# all-random`` and ``@skip_doctest`` is that the former
248 executes the example but ignores output, while the latter doesn't execute any
251 executes the example but ignores output, while the latter doesn't execute any
249 code. ``@skip_doctest`` should be used for docstrings whose examples are
252 code. ``@skip_doctest`` should be used for docstrings whose examples are
250 purely informational.
253 purely informational.
251
254
252 If a given docstring fails under certain conditions but otherwise is a good
255 If a given docstring fails under certain conditions but otherwise is a good
253 doctest, you can use code like the following, that relies on the 'null'
256 doctest, you can use code like the following, that relies on the 'null'
254 decorator to leave the docstring intact where it works as a test::
257 decorator to leave the docstring intact where it works as a test::
255
258
256 # The docstring for full_path doctests differently on win32 (different path
259 # The docstring for full_path doctests differently on win32 (different path
257 # separator) so just skip the doctest there, and use a null decorator
260 # separator) so just skip the doctest there, and use a null decorator
258 # elsewhere:
261 # elsewhere:
259
262
260 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
263 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
261
264
262 @doctest_deco
265 @doctest_deco
263 def full_path(startPath,files):
266 def full_path(startPath,files):
264 """Make full paths for all the listed files, based on startPath..."""
267 """Make full paths for all the listed files, based on startPath..."""
265
268
266 # function body follows...
269 # function body follows...
267
270
268 With our nose plugin that understands IPython syntax, an extremely effective
271 With our nose plugin that understands IPython syntax, an extremely effective
269 way to write tests is to simply copy and paste an interactive session into a
272 way to write tests is to simply copy and paste an interactive session into a
270 docstring. You can writing this type of test, where your docstring is meant
273 docstring. You can writing this type of test, where your docstring is meant
271 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
274 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
272 its body *absolutely empty* other than the docstring. In
275 its body *absolutely empty* other than the docstring. In
273 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
276 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
274 for completeness sake, your code should look like this (a simple case)::
277 for completeness sake, your code should look like this (a simple case)::
275
278
276 def doctest_time():
279 def doctest_time():
277 """
280 """
278 In [10]: %time None
281 In [10]: %time None
279 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
282 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
280 Wall time: 0.00 s
283 Wall time: 0.00 s
281 """
284 """
282
285
283 This function is only analyzed for its docstring but it is not considered a
286 This function is only analyzed for its docstring but it is not considered a
284 separate test, which is why its body should be empty.
287 separate test, which is why its body should be empty.
285
288
286
289
287 Parametric tests done right
290 Parametric tests done right
288 ---------------------------
291 ---------------------------
289
292
290 If you need to run multiple tests inside the same standalone function or method
293 If you need to run multiple tests inside the same standalone function or method
291 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
294 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
292 decorator for this purpose. This is superior to how test generators work in
295 decorator for this purpose. This is superior to how test generators work in
293 nose, because IPython's keeps intact your stack, which makes debugging vastly
296 nose, because IPython's keeps intact your stack, which makes debugging vastly
294 easier. For example, these are some parametric tests both in class form and as
297 easier. For example, these are some parametric tests both in class form and as
295 a standalone function (choose in each situation the style that best fits the
298 a standalone function (choose in each situation the style that best fits the
296 problem at hand, since both work)::
299 problem at hand, since both work)::
297
300
298 from IPython.testing import decorators as dec
301 from IPython.testing import decorators as dec
299
302
300 def is_smaller(i,j):
303 def is_smaller(i,j):
301 assert i<j,"%s !< %s" % (i,j)
304 assert i<j,"%s !< %s" % (i,j)
302
305
303 class Tester(ParametricTestCase):
306 class Tester(ParametricTestCase):
304
307
305 def test_parametric(self):
308 def test_parametric(self):
306 yield is_smaller(3, 4)
309 yield is_smaller(3, 4)
307 x, y = 1, 2
310 x, y = 1, 2
308 yield is_smaller(x, y)
311 yield is_smaller(x, y)
309
312
310 @dec.parametric
313 @dec.parametric
311 def test_par_standalone():
314 def test_par_standalone():
312 yield is_smaller(3, 4)
315 yield is_smaller(3, 4)
313 x, y = 1, 2
316 x, y = 1, 2
314 yield is_smaller(x, y)
317 yield is_smaller(x, y)
315
318
316
319
317 Writing tests for Twisted-using code
320 Writing tests for Twisted-using code
318 ------------------------------------
321 ------------------------------------
319
322
320 Tests of Twisted [Twisted]_ using code should be written by subclassing the
323 Tests of Twisted [Twisted]_ using code should be written by subclassing the
321 ``TestCase`` class that comes with ``twisted.trial.unittest``. Furthermore, all
324 ``TestCase`` class that comes with ``twisted.trial.unittest``. Furthermore, all
322 :class:`Deferred` instances that are created in the test must be properly
325 :class:`Deferred` instances that are created in the test must be properly
323 chained and the final one *must* be the return value of the test method.
326 chained and the final one *must* be the return value of the test method.
324
327
325 .. note::
328 .. note::
326
329
327 The best place to see how to use the testing tools, are the tests for these
330 The best place to see how to use the testing tools, are the tests for these
328 tools themselves, which live in :mod:`IPython.testing.tests`.
331 tools themselves, which live in :mod:`IPython.testing.tests`.
329
332
330
333
331 Design requirements
334 Design requirements
332 ===================
335 ===================
333
336
334 This section is a set of notes on the key points of the IPython testing needs,
337 This section is a set of notes on the key points of the IPython testing needs,
335 that were used when writing the system and should be kept for reference as it
338 that were used when writing the system and should be kept for reference as it
336 eveolves.
339 eveolves.
337
340
338 Testing IPython in full requires modifications to the default behavior of nose
341 Testing IPython in full requires modifications to the default behavior of nose
339 and doctest, because the IPython prompt is not recognized to determine Python
342 and doctest, because the IPython prompt is not recognized to determine Python
340 input, and because IPython admits user input that is not valid Python (things
343 input, and because IPython admits user input that is not valid Python (things
341 like ``%magics`` and ``!system commands``.
344 like ``%magics`` and ``!system commands``.
342
345
343 We basically need to be able to test the following types of code:
346 We basically need to be able to test the following types of code:
344
347
345 1. Pure Python files containing normal tests. These are not a problem, since
348 1. Pure Python files containing normal tests. These are not a problem, since
346 Nose will pick them up as long as they conform to the (flexible) conventions
349 Nose will pick them up as long as they conform to the (flexible) conventions
347 used by nose to recognize tests.
350 used by nose to recognize tests.
348
351
349 2. Python files containing doctests. Here, we have two possibilities:
352 2. Python files containing doctests. Here, we have two possibilities:
350 - The prompts are the usual ``>>>`` and the input is pure Python.
353 - The prompts are the usual ``>>>`` and the input is pure Python.
351 - The prompts are of the form ``In [1]:`` and the input can contain extended
354 - The prompts are of the form ``In [1]:`` and the input can contain extended
352 IPython expressions.
355 IPython expressions.
353
356
354 In the first case, Nose will recognize the doctests as long as it is called
357 In the first case, Nose will recognize the doctests as long as it is called
355 with the ``--with-doctest`` flag. But the second case will likely require
358 with the ``--with-doctest`` flag. But the second case will likely require
356 modifications or the writing of a new doctest plugin for Nose that is
359 modifications or the writing of a new doctest plugin for Nose that is
357 IPython-aware.
360 IPython-aware.
358
361
359 3. ReStructuredText files that contain code blocks. For this type of file, we
362 3. ReStructuredText files that contain code blocks. For this type of file, we
360 have three distinct possibilities for the code blocks:
363 have three distinct possibilities for the code blocks:
361 - They use ``>>>`` prompts.
364 - They use ``>>>`` prompts.
362 - They use ``In [1]:`` prompts.
365 - They use ``In [1]:`` prompts.
363 - They are standalone blocks of pure Python code without any prompts.
366 - They are standalone blocks of pure Python code without any prompts.
364
367
365 The first two cases are similar to the situation #2 above, except that in
368 The first two cases are similar to the situation #2 above, except that in
366 this case the doctests must be extracted from input code blocks using
369 this case the doctests must be extracted from input code blocks using
367 docutils instead of from the Python docstrings.
370 docutils instead of from the Python docstrings.
368
371
369 In the third case, we must have a convention for distinguishing code blocks
372 In the third case, we must have a convention for distinguishing code blocks
370 that are meant for execution from others that may be snippets of shell code
373 that are meant for execution from others that may be snippets of shell code
371 or other examples not meant to be run. One possibility is to assume that
374 or other examples not meant to be run. One possibility is to assume that
372 all indented code blocks are meant for execution, but to have a special
375 all indented code blocks are meant for execution, but to have a special
373 docutils directive for input that should not be executed.
376 docutils directive for input that should not be executed.
374
377
375 For those code blocks that we will execute, the convention used will simply
378 For those code blocks that we will execute, the convention used will simply
376 be that they get called and are considered successful if they run to
379 be that they get called and are considered successful if they run to
377 completion without raising errors. This is similar to what Nose does for
380 completion without raising errors. This is similar to what Nose does for
378 standalone test functions, and by putting asserts or other forms of
381 standalone test functions, and by putting asserts or other forms of
379 exception-raising statements it becomes possible to have literate examples
382 exception-raising statements it becomes possible to have literate examples
380 that double as lightweight tests.
383 that double as lightweight tests.
381
384
382 4. Extension modules with doctests in function and method docstrings.
385 4. Extension modules with doctests in function and method docstrings.
383 Currently Nose simply can't find these docstrings correctly, because the
386 Currently Nose simply can't find these docstrings correctly, because the
384 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
387 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
385 the docstrings could have either pure python or IPython prompts.
388 the docstrings could have either pure python or IPython prompts.
386
389
387 Of these, only 3-c (reST with standalone code blocks) is not implemented at
390 Of these, only 3-c (reST with standalone code blocks) is not implemented at
388 this point.
391 this point.
@@ -1,251 +1,257
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 The IPython Development Team
10 # Copyright (c) 2008-2010, IPython Development Team.
11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
11 #
14 #
12 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the Modified BSD License.
13 # the file COPYING, distributed as part of this software.
16 #
14 #-------------------------------------------------------------------------------
17 # The full license is in the file COPYING.txt, distributed with this software.
18 #-----------------------------------------------------------------------------
15
19
16 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
17 # Minimal Python version sanity check
21 # Minimal Python version sanity check
18 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
19
23
20 import sys
24 import sys
21
25
22 # 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
23 # changing Python version requirements.
27 # changing Python version requirements.
24 if sys.version[0:3] < '2.6':
28 if sys.version[0:3] < '2.6':
25 error = """\
29 error = """\
26 ERROR: 'IPython requires Python Version 2.6 or above.'
30 ERROR: 'IPython requires Python Version 2.6 or above.'
27 Exiting."""
31 Exiting."""
28 print >> sys.stderr, error
32 print >> sys.stderr, error
29 sys.exit(1)
33 sys.exit(1)
30
34
31 # 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.
32
36
33 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
34 # Imports
38 # Imports
35 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
36
40
37 # Stdlib imports
41 # Stdlib imports
38 import os
42 import os
39 import shutil
43 import shutil
40
44
41 from glob import glob
45 from glob import glob
42
46
43 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
47 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
44 # update it when the contents of directories change.
48 # update it when the contents of directories change.
45 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
49 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
46
50
47 from distutils.core import setup
51 from distutils.core import setup
48
52
49 # Our own imports
53 # Our own imports
50 from IPython.utils.path import target_update
54 from IPython.utils.path import target_update
51
55
52 from setupbase import (
56 from setupbase import (
53 setup_args,
57 setup_args,
54 find_packages,
58 find_packages,
55 find_package_data,
59 find_package_data,
56 find_scripts,
60 find_scripts,
57 find_data_files,
61 find_data_files,
58 check_for_dependencies
62 check_for_dependencies,
63 record_commit_info,
59 )
64 )
60
65
61 isfile = os.path.isfile
66 isfile = os.path.isfile
62 pjoin = os.path.join
67 pjoin = os.path.join
63
68
64 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
65 # Function definitions
70 # Function definitions
66 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
67
72
68 def cleanup():
73 def cleanup():
69 """Clean up the junk left around by the build process"""
74 """Clean up the junk left around by the build process"""
70 if "develop" not in sys.argv:
75 if "develop" not in sys.argv:
71 try:
76 try:
72 shutil.rmtree('ipython.egg-info')
77 shutil.rmtree('ipython.egg-info')
73 except:
78 except:
74 try:
79 try:
75 os.unlink('ipython.egg-info')
80 os.unlink('ipython.egg-info')
76 except:
81 except:
77 pass
82 pass
78
83
79 #-------------------------------------------------------------------------------
84 #-------------------------------------------------------------------------------
80 # Handle OS specific things
85 # Handle OS specific things
81 #-------------------------------------------------------------------------------
86 #-------------------------------------------------------------------------------
82
87
83 if os.name == 'posix':
88 if os.name == 'posix':
84 os_name = 'posix'
89 os_name = 'posix'
85 elif os.name in ['nt','dos']:
90 elif os.name in ['nt','dos']:
86 os_name = 'windows'
91 os_name = 'windows'
87 else:
92 else:
88 print 'Unsupported operating system:',os.name
93 print 'Unsupported operating system:',os.name
89 sys.exit(1)
94 sys.exit(1)
90
95
91 # 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
92 # 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
93 # actually works.
98 # actually works.
94 if os_name == 'windows' and 'sdist' in sys.argv:
99 if os_name == 'windows' and 'sdist' in sys.argv:
95 print 'The sdist command is not available under Windows. Exiting.'
100 print 'The sdist command is not available under Windows. Exiting.'
96 sys.exit(1)
101 sys.exit(1)
97
102
98 #-------------------------------------------------------------------------------
103 #-------------------------------------------------------------------------------
99 # Things related to the IPython documentation
104 # Things related to the IPython documentation
100 #-------------------------------------------------------------------------------
105 #-------------------------------------------------------------------------------
101
106
102 # update the manuals when building a source dist
107 # update the manuals when building a source dist
103 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'):
104 import textwrap
109 import textwrap
105
110
106 # 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
107 # target_update()
112 # target_update()
108 to_update = [
113 to_update = [
109 # FIXME - Disabled for now: we need to redo an automatic way
114 # FIXME - Disabled for now: we need to redo an automatic way
110 # of generating the magic info inside the rst.
115 # of generating the magic info inside the rst.
111 #('docs/magic.tex',
116 #('docs/magic.tex',
112 #['IPython/Magic.py'],
117 #['IPython/Magic.py'],
113 #"cd doc && ./update_magic.sh" ),
118 #"cd doc && ./update_magic.sh" ),
114
119
115 ('docs/man/ipcluster.1.gz',
120 ('docs/man/ipcluster.1.gz',
116 ['docs/man/ipcluster.1'],
121 ['docs/man/ipcluster.1'],
117 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
122 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
118
123
119 ('docs/man/ipcontroller.1.gz',
124 ('docs/man/ipcontroller.1.gz',
120 ['docs/man/ipcontroller.1'],
125 ['docs/man/ipcontroller.1'],
121 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
126 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
122
127
123 ('docs/man/ipengine.1.gz',
128 ('docs/man/ipengine.1.gz',
124 ['docs/man/ipengine.1'],
129 ['docs/man/ipengine.1'],
125 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
130 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
126
131
127 ('docs/man/ipython.1.gz',
132 ('docs/man/ipython.1.gz',
128 ['docs/man/ipython.1'],
133 ['docs/man/ipython.1'],
129 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
134 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
130
135
131 ('docs/man/ipython-wx.1.gz',
136 ('docs/man/ipython-wx.1.gz',
132 ['docs/man/ipython-wx.1'],
137 ['docs/man/ipython-wx.1'],
133 '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'),
134
139
135 ('docs/man/ipythonx.1.gz',
140 ('docs/man/ipythonx.1.gz',
136 ['docs/man/ipythonx.1'],
141 ['docs/man/ipythonx.1'],
137 'cd docs/man && gzip -9c ipythonx.1 > ipythonx.1.gz'),
142 'cd docs/man && gzip -9c ipythonx.1 > ipythonx.1.gz'),
138
143
139 ('docs/man/irunner.1.gz',
144 ('docs/man/irunner.1.gz',
140 ['docs/man/irunner.1'],
145 ['docs/man/irunner.1'],
141 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
146 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
142
147
143 ('docs/man/pycolor.1.gz',
148 ('docs/man/pycolor.1.gz',
144 ['docs/man/pycolor.1'],
149 ['docs/man/pycolor.1'],
145 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
150 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
146 ]
151 ]
147
152
148 # Only build the docs if sphinx is present
153 # Only build the docs if sphinx is present
149 try:
154 try:
150 import sphinx
155 import sphinx
151 except ImportError:
156 except ImportError:
152 pass
157 pass
153 else:
158 else:
154 # 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
155 # just one target is enough to cover all manual generation
160 # just one target is enough to cover all manual generation
156
161
157 # 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
158 # docs. Start with the main release file that contains metadata
163 # docs. Start with the main release file that contains metadata
159 docdeps = ['IPython/core/release.py']
164 docdeps = ['IPython/core/release.py']
160 # Inculde all the reST sources
165 # Inculde all the reST sources
161 pjoin = os.path.join
166 pjoin = os.path.join
162 for dirpath,dirnames,filenames in os.walk('docs/source'):
167 for dirpath,dirnames,filenames in os.walk('docs/source'):
163 if dirpath in ['_static','_templates']:
168 if dirpath in ['_static','_templates']:
164 continue
169 continue
165 docdeps += [ pjoin(dirpath,f) for f in filenames
170 docdeps += [ pjoin(dirpath,f) for f in filenames
166 if f.endswith('.txt') ]
171 if f.endswith('.txt') ]
167 # and the examples
172 # and the examples
168 for dirpath,dirnames,filenames in os.walk('docs/example'):
173 for dirpath,dirnames,filenames in os.walk('docs/example'):
169 docdeps += [ pjoin(dirpath,f) for f in filenames
174 docdeps += [ pjoin(dirpath,f) for f in filenames
170 if not f.endswith('~') ]
175 if not f.endswith('~') ]
171 # 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
172 # auto-generated as well).
177 # auto-generated as well).
173 to_update.append(
178 to_update.append(
174 ('docs/dist/ipython.pdf',
179 ('docs/dist/ipython.pdf',
175 docdeps,
180 docdeps,
176 "cd docs && make dist")
181 "cd docs && make dist")
177 )
182 )
178
183
179 [ target_update(*t) for t in to_update ]
184 [ target_update(*t) for t in to_update ]
180
185
181 #---------------------------------------------------------------------------
186 #---------------------------------------------------------------------------
182 # Find all the packages, package data, scripts and data_files
187 # Find all the packages, package data, scripts and data_files
183 #---------------------------------------------------------------------------
188 #---------------------------------------------------------------------------
184
189
185 packages = find_packages()
190 packages = find_packages()
186 package_data = find_package_data()
191 package_data = find_package_data()
187 scripts = find_scripts()
192 scripts = find_scripts()
188 data_files = find_data_files()
193 data_files = find_data_files()
189
194
190 #---------------------------------------------------------------------------
195 #---------------------------------------------------------------------------
191 # Handle dependencies and setuptools specific things
196 # Handle dependencies and setuptools specific things
192 #---------------------------------------------------------------------------
197 #---------------------------------------------------------------------------
193
198
194 # 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!
195 # 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'
196 if len(set(('develop', 'sdist', 'release', 'bdist_egg', 'bdist_rpm',
201 if len(set(('develop', 'sdist', 'release', 'bdist_egg', 'bdist_rpm',
197 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
202 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
198 'build_sphinx', 'egg_info', 'easy_install', 'upload',
203 'build_sphinx', 'egg_info', 'easy_install', 'upload',
199 )).intersection(sys.argv)) > 0:
204 )).intersection(sys.argv)) > 0:
200 import setuptools
205 import setuptools
201
206
202 # This dict is used for passing extra arguments that are setuptools
207 # This dict is used for passing extra arguments that are setuptools
203 # specific to setup
208 # specific to setup
204 setuptools_extra_args = {}
209 setuptools_extra_args = {}
205
210
206 if 'setuptools' in sys.modules:
211 if 'setuptools' in sys.modules:
207 setuptools_extra_args['zip_safe'] = False
212 setuptools_extra_args['zip_safe'] = False
208 setuptools_extra_args['entry_points'] = {
213 setuptools_extra_args['entry_points'] = {
209 'console_scripts': [
214 'console_scripts': [
210 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
215 'ipython = IPython.frontend.terminal.ipapp:launch_new_instance',
211 'ipython-qtconsole = IPython.frontend.qt.console.ipythonqt:main',
216 'ipython-qtconsole = IPython.frontend.qt.console.ipythonqt:main',
212 'pycolor = IPython.utils.PyColorize:main',
217 'pycolor = IPython.utils.PyColorize:main',
213 'ipcontroller = IPython.kernel.ipcontrollerapp:launch_new_instance',
218 'ipcontroller = IPython.kernel.ipcontrollerapp:launch_new_instance',
214 'ipengine = IPython.kernel.ipengineapp:launch_new_instance',
219 'ipengine = IPython.kernel.ipengineapp:launch_new_instance',
215 'ipcluster = IPython.kernel.ipclusterapp:launch_new_instance',
220 'ipcluster = IPython.kernel.ipclusterapp:launch_new_instance',
216 'iptest = IPython.testing.iptest:main',
221 'iptest = IPython.testing.iptest:main',
217 'irunner = IPython.lib.irunner:main'
222 'irunner = IPython.lib.irunner:main'
218 ]
223 ]
219 }
224 }
220 setup_args['extras_require'] = dict(
225 setup_args['extras_require'] = dict(
221 kernel = [
226 kernel = [
222 'zope.interface>=3.4.1',
227 'zope.interface>=3.4.1',
223 'Twisted>=8.0.1',
228 'Twisted>=8.0.1',
224 'foolscap>=0.2.6'
229 'foolscap>=0.2.6'
225 ],
230 ],
226 doc='Sphinx>=0.3',
231 doc='Sphinx>=0.3',
227 test='nose>=0.10.1',
232 test='nose>=0.10.1',
228 security='pyOpenSSL>=0.6'
233 security='pyOpenSSL>=0.6'
229 )
234 )
230 # Allow setuptools to handle the scripts
235 # Allow setuptools to handle the scripts
231 scripts = []
236 scripts = []
232 else:
237 else:
233 # If we are running without setuptools, call this function which will
238 # If we are running without setuptools, call this function which will
234 # check for dependencies an inform the user what is needed. This is
239 # check for dependencies an inform the user what is needed. This is
235 # just to make life easy for users.
240 # just to make life easy for users.
236 check_for_dependencies()
241 check_for_dependencies()
237
242
238 #---------------------------------------------------------------------------
243 #---------------------------------------------------------------------------
239 # Do the actual setup now
244 # Do the actual setup now
240 #---------------------------------------------------------------------------
245 #---------------------------------------------------------------------------
241
246
247 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython')}
242 setup_args['packages'] = packages
248 setup_args['packages'] = packages
243 setup_args['package_data'] = package_data
249 setup_args['package_data'] = package_data
244 setup_args['scripts'] = scripts
250 setup_args['scripts'] = scripts
245 setup_args['data_files'] = data_files
251 setup_args['data_files'] = data_files
246 setup_args.update(setuptools_extra_args)
252 setup_args.update(setuptools_extra_args)
247
253
248
254
249 if __name__ == '__main__':
255 if __name__ == '__main__':
250 setup(**setup_args)
256 setup(**setup_args)
251 cleanup()
257 cleanup()
@@ -1,314 +1,375
1 # encoding: utf-8
1 # encoding: utf-8
2
3 """
2 """
4 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
5
4
6 This includes:
5 This includes:
7
6
8 * The basic arguments to setup
7 * The basic arguments to setup
9 * Functions for finding things like packages, package data, etc.
8 * Functions for finding things like packages, package data, etc.
10 * A function for checking dependencies.
9 * A function for checking dependencies.
11 """
10 """
12
11 from __future__ import print_function
13 __docformat__ = "restructuredtext en"
14
12
15 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
16 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
17 #
15 #
18 # 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
19 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
20 #-------------------------------------------------------------------------------
18 #-------------------------------------------------------------------------------
21
19
22 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
23 # Imports
21 # Imports
24 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 import os
24 import sys
25
25
26 import os, sys
26 from ConfigParser import ConfigParser
27
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, 'frontend')
111 add_package(packages, 'frontend')
112 add_package(packages, 'frontend.qt')
112 add_package(packages, 'frontend.qt')
113 add_package(packages, 'frontend.qt.console', tests=True)
113 add_package(packages, 'frontend.qt.console', tests=True)
114 add_package(packages, 'frontend.terminal', tests=True)
114 add_package(packages, 'frontend.terminal', tests=True)
115 add_package(packages, 'kernel', config=False, tests=True, scripts=True)
115 add_package(packages, 'kernel', config=False, tests=True, scripts=True)
116 add_package(packages, 'kernel.core', config=False, tests=True)
116 add_package(packages, 'kernel.core', config=False, tests=True)
117 add_package(packages, 'lib', tests=True)
117 add_package(packages, 'lib', tests=True)
118 add_package(packages, 'quarantine', tests=True)
118 add_package(packages, 'quarantine', tests=True)
119 add_package(packages, 'scripts')
119 add_package(packages, 'scripts')
120 add_package(packages, 'testing', tests=True)
120 add_package(packages, 'testing', tests=True)
121 add_package(packages, 'testing.plugin', tests=False)
121 add_package(packages, 'testing.plugin', tests=False)
122 add_package(packages, 'utils', tests=True)
122 add_package(packages, 'utils', tests=True)
123 add_package(packages, 'zmq')
123 add_package(packages, 'zmq')
124 add_package(packages, 'zmq.pylab')
124 add_package(packages, 'zmq.pylab')
125 return packages
125 return packages
126
126
127 #---------------------------------------------------------------------------
127 #---------------------------------------------------------------------------
128 # Find package data
128 # Find package data
129 #---------------------------------------------------------------------------
129 #---------------------------------------------------------------------------
130
130
131 def find_package_data():
131 def find_package_data():
132 """
132 """
133 Find IPython's package_data.
133 Find IPython's package_data.
134 """
134 """
135 # This is not enough for these things to appear in an sdist.
135 # This is not enough for these things to appear in an sdist.
136 # We need to muck with the MANIFEST to get this to work
136 # We need to muck with the MANIFEST to get this to work
137 package_data = {
137 package_data = {
138 'IPython.config.userconfig' : ['*'],
138 'IPython.config.userconfig' : ['*'],
139 'IPython.testing' : ['*.txt']
139 'IPython.testing' : ['*.txt']
140 }
140 }
141 return package_data
141 return package_data
142
142
143
143
144 #---------------------------------------------------------------------------
144 #---------------------------------------------------------------------------
145 # Find data files
145 # Find data files
146 #---------------------------------------------------------------------------
146 #---------------------------------------------------------------------------
147
147
148 def make_dir_struct(tag,base,out_base):
148 def make_dir_struct(tag,base,out_base):
149 """Make the directory structure of all files below a starting dir.
149 """Make the directory structure of all files below a starting dir.
150
150
151 This is just a convenience routine to help build a nested directory
151 This is just a convenience routine to help build a nested directory
152 hierarchy because distutils is too stupid to do this by itself.
152 hierarchy because distutils is too stupid to do this by itself.
153
153
154 XXX - this needs a proper docstring!
154 XXX - this needs a proper docstring!
155 """
155 """
156
156
157 # we'll use these a lot below
157 # we'll use these a lot below
158 lbase = len(base)
158 lbase = len(base)
159 pathsep = os.path.sep
159 pathsep = os.path.sep
160 lpathsep = len(pathsep)
160 lpathsep = len(pathsep)
161
161
162 out = []
162 out = []
163 for (dirpath,dirnames,filenames) in os.walk(base):
163 for (dirpath,dirnames,filenames) in os.walk(base):
164 # we need to strip out the dirpath from the base to map it to the
164 # we need to strip out the dirpath from the base to map it to the
165 # output (installation) path. This requires possibly stripping the
165 # output (installation) path. This requires possibly stripping the
166 # path separator, because otherwise pjoin will not work correctly
166 # path separator, because otherwise pjoin will not work correctly
167 # (pjoin('foo/','/bar') returns '/bar').
167 # (pjoin('foo/','/bar') returns '/bar').
168
168
169 dp_eff = dirpath[lbase:]
169 dp_eff = dirpath[lbase:]
170 if dp_eff.startswith(pathsep):
170 if dp_eff.startswith(pathsep):
171 dp_eff = dp_eff[lpathsep:]
171 dp_eff = dp_eff[lpathsep:]
172 # The output path must be anchored at the out_base marker
172 # The output path must be anchored at the out_base marker
173 out_path = pjoin(out_base,dp_eff)
173 out_path = pjoin(out_base,dp_eff)
174 # Now we can generate the final filenames. Since os.walk only produces
174 # Now we can generate the final filenames. Since os.walk only produces
175 # filenames, we must join back with the dirpath to get full valid file
175 # filenames, we must join back with the dirpath to get full valid file
176 # paths:
176 # paths:
177 pfiles = [pjoin(dirpath,f) for f in filenames]
177 pfiles = [pjoin(dirpath,f) for f in filenames]
178 # Finally, generate the entry we need, which is a triple of (tag,output
178 # Finally, generate the entry we need, which is a pari of (output
179 # path, files) for use as a data_files parameter in install_data.
179 # path, files) for use as a data_files parameter in install_data.
180 out.append((tag,out_path,pfiles))
180 out.append((out_path, pfiles))
181
181
182 return out
182 return out
183
183
184
184
185 def find_data_files():
185 def find_data_files():
186 """
186 """
187 Find IPython's data_files.
187 Find IPython's data_files.
188
188
189 Most of these are docs.
189 Most of these are docs.
190 """
190 """
191
191
192 docdirbase = pjoin('share', 'doc', 'ipython')
192 docdirbase = pjoin('share', 'doc', 'ipython')
193 manpagebase = pjoin('share', 'man', 'man1')
193 manpagebase = pjoin('share', 'man', 'man1')
194
194
195 # Simple file lists can be made by hand
195 # Simple file lists can be made by hand
196 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
196 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
197 igridhelpfiles = filter(isfile, glob(pjoin('IPython','extensions','igrid_help.*')))
197 igridhelpfiles = filter(isfile,
198 glob(pjoin('IPython','extensions','igrid_help.*')))
198
199
199 # For nested structures, use the utility above
200 # For nested structures, use the utility above
200 example_files = make_dir_struct(
201 example_files = make_dir_struct(
201 'data',
202 'data',
202 pjoin('docs','examples'),
203 pjoin('docs','examples'),
203 pjoin(docdirbase,'examples')
204 pjoin(docdirbase,'examples')
204 )
205 )
205 manual_files = make_dir_struct(
206 manual_files = make_dir_struct(
206 'data',
207 'data',
207 pjoin('docs','dist'),
208 pjoin('docs','dist'),
208 pjoin(docdirbase,'manual')
209 pjoin(docdirbase,'manual')
209 )
210 )
210
211
211 # And assemble the entire output list
212 # And assemble the entire output list
212 data_files = [ ('data',manpagebase, manpages),
213 data_files = [ (manpagebase, manpages),
213 ('data',pjoin(docdirbase,'extensions'),igridhelpfiles),
214 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
214 ] + manual_files + example_files
215 ] + manual_files + example_files
215
216
216 ## import pprint # dbg
217 ## import pprint # dbg
217 ## print '*'*80
218 ## print('*'*80)
218 ## print 'data files'
219 ## print('data files')
219 ## pprint.pprint(data_files)
220 ## pprint.pprint(data_files)
220 ## print '*'*80
221 ## print('*'*80)
221
222
222 return data_files
223 return data_files
223
224
224
225
225 def make_man_update_target(manpage):
226 def make_man_update_target(manpage):
226 """Return a target_update-compliant tuple for the given manpage.
227 """Return a target_update-compliant tuple for the given manpage.
227
228
228 Parameters
229 Parameters
229 ----------
230 ----------
230 manpage : string
231 manpage : string
231 Name of the manpage, must include the section number (trailing number).
232 Name of the manpage, must include the section number (trailing number).
232
233
233 Example
234 Example
234 -------
235 -------
235
236
236 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
237 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
237 ('docs/man/ipython.1.gz',
238 ('docs/man/ipython.1.gz',
238 ['docs/man/ipython.1'],
239 ['docs/man/ipython.1'],
239 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
240 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
240 """
241 """
241 man_dir = pjoin('docs', 'man')
242 man_dir = pjoin('docs', 'man')
242 manpage_gz = manpage + '.gz'
243 manpage_gz = manpage + '.gz'
243 manpath = pjoin(man_dir, manpage)
244 manpath = pjoin(man_dir, manpage)
244 manpath_gz = pjoin(man_dir, manpage_gz)
245 manpath_gz = pjoin(man_dir, manpage_gz)
245 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
246 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
246 locals() )
247 locals() )
247 return (manpath_gz, [manpath], gz_cmd)
248 return (manpath_gz, [manpath], gz_cmd)
248
249
249 #---------------------------------------------------------------------------
250 #---------------------------------------------------------------------------
250 # Find scripts
251 # Find scripts
251 #---------------------------------------------------------------------------
252 #---------------------------------------------------------------------------
252
253
253 def find_scripts():
254 def find_scripts():
254 """
255 """
255 Find IPython's scripts.
256 Find IPython's scripts.
256 """
257 """
257 kernel_scripts = pjoin('IPython','kernel','scripts')
258 kernel_scripts = pjoin('IPython','kernel','scripts')
258 main_scripts = pjoin('IPython','scripts')
259 main_scripts = pjoin('IPython','scripts')
259 scripts = [pjoin(kernel_scripts, 'ipengine'),
260 scripts = [pjoin(kernel_scripts, 'ipengine'),
260 pjoin(kernel_scripts, 'ipcontroller'),
261 pjoin(kernel_scripts, 'ipcontroller'),
261 pjoin(kernel_scripts, 'ipcluster'),
262 pjoin(kernel_scripts, 'ipcluster'),
262 pjoin(main_scripts, 'ipython'),
263 pjoin(main_scripts, 'ipython'),
263 pjoin(main_scripts, 'ipython-qtconsole'),
264 pjoin(main_scripts, 'ipython-qtconsole'),
264 pjoin(main_scripts, 'pycolor'),
265 pjoin(main_scripts, 'pycolor'),
265 pjoin(main_scripts, 'irunner'),
266 pjoin(main_scripts, 'irunner'),
266 pjoin(main_scripts, 'iptest')
267 pjoin(main_scripts, 'iptest')
267 ]
268 ]
268
269
269 # Script to be run by the windows binary installer after the default setup
270 # Script to be run by the windows binary installer after the default setup
270 # routine, to add shortcuts and similar windows-only things. Windows
271 # routine, to add shortcuts and similar windows-only things. Windows
271 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
272 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
272 # doesn't find them.
273 # doesn't find them.
273 if 'bdist_wininst' in sys.argv:
274 if 'bdist_wininst' in sys.argv:
274 if len(sys.argv) > 2 and ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
275 if len(sys.argv) > 2 and \
275 print >> sys.stderr,"ERROR: bdist_wininst must be run alone. Exiting."
276 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
277 print("ERROR: bdist_wininst must be run alone. Exiting.",
278 file=sys.stderr)
276 sys.exit(1)
279 sys.exit(1)
277 scripts.append(pjoin('scripts','ipython_win_post_install.py'))
280 scripts.append(pjoin('scripts','ipython_win_post_install.py'))
278
281
279 return scripts
282 return scripts
280
283
281 #---------------------------------------------------------------------------
284 #---------------------------------------------------------------------------
282 # Verify all dependencies
285 # Verify all dependencies
283 #---------------------------------------------------------------------------
286 #---------------------------------------------------------------------------
284
287
285 def check_for_dependencies():
288 def check_for_dependencies():
286 """Check for IPython's dependencies.
289 """Check for IPython's dependencies.
287
290
288 This function should NOT be called if running under setuptools!
291 This function should NOT be called if running under setuptools!
289 """
292 """
290 from setupext.setupext import (
293 from setupext.setupext import (
291 print_line, print_raw, print_status, print_message,
294 print_line, print_raw, print_status,
292 check_for_zopeinterface, check_for_twisted,
295 check_for_zopeinterface, check_for_twisted,
293 check_for_foolscap, check_for_pyopenssl,
296 check_for_foolscap, check_for_pyopenssl,
294 check_for_sphinx, check_for_pygments,
297 check_for_sphinx, check_for_pygments,
295 check_for_nose, check_for_pexpect
298 check_for_nose, check_for_pexpect
296 )
299 )
297 print_line()
300 print_line()
298 print_raw("BUILDING IPYTHON")
301 print_raw("BUILDING IPYTHON")
299 print_status('python', sys.version)
302 print_status('python', sys.version)
300 print_status('platform', sys.platform)
303 print_status('platform', sys.platform)
301 if sys.platform == 'win32':
304 if sys.platform == 'win32':
302 print_status('Windows version', sys.getwindowsversion())
305 print_status('Windows version', sys.getwindowsversion())
303
306
304 print_raw("")
307 print_raw("")
305 print_raw("OPTIONAL DEPENDENCIES")
308 print_raw("OPTIONAL DEPENDENCIES")
306
309
307 check_for_zopeinterface()
310 check_for_zopeinterface()
308 check_for_twisted()
311 check_for_twisted()
309 check_for_foolscap()
312 check_for_foolscap()
310 check_for_pyopenssl()
313 check_for_pyopenssl()
311 check_for_sphinx()
314 check_for_sphinx()
312 check_for_pygments()
315 check_for_pygments()
313 check_for_nose()
316 check_for_nose()
314 check_for_pexpect()
317 check_for_pexpect()
318
319
320 def record_commit_info(pkg_dir, build_cmd=build_py):
321 """ Return extended build command class for recording commit
322
323 The extended command tries to run git to find the current commit, getting
324 the empty string if it fails. It then writes the commit hash into a file
325 in the `pkg_dir` path, named ``.git_commit_info.ini``.
326
327 In due course this information can be used by the package after it is
328 installed, to tell you what commit it was installed from if known.
329
330 To make use of this system, you need a package with a .git_commit_info.ini
331 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
332 this::
333
334 # This is an ini file that may contain information about the code state
335 [commit hash]
336 # The line below may contain a valid hash if it has been substituted
337 # during 'git archive'
338 archive_subst_hash=$Format:%h$
339 # This line may be modified by the install process
340 install_hash=
341
342 The .git_commit_info file above is also designed to be used with git
343 substitution - so you probably also want a ``.gitattributes`` file in the
344 root directory of your working tree that contains something like this::
345
346 myproject/.git_commit_info.ini export-subst
347
348 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
349 archive`` - useful in case someone makes such an archive - for example with
350 via the github 'download source' button.
351
352 Although all the above will work as is, you might consider having something
353 like a ``get_info()`` function in your package to display the commit
354 information at the terminal. See the ``pkg_info.py`` module in the nipy
355 package for an example.
356 """
357 class MyBuildPy(build_cmd):
358 ''' Subclass to write commit data into installation tree '''
359 def run(self):
360 build_py.run(self)
361 import subprocess
362 proc = subprocess.Popen('git rev-parse --short HEAD',
363 stdout=subprocess.PIPE,
364 stderr=subprocess.PIPE,
365 shell=True)
366 repo_commit, _ = proc.communicate()
367 # We write the installation commit even if it's empty
368 cfg_parser = ConfigParser()
369 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
370 cfg_parser.set('commit hash', 'install_hash', repo_commit)
371 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
372 out_file = open(out_pth, 'wt')
373 cfg_parser.write(out_file)
374 out_file.close()
375 return MyBuildPy
@@ -1,35 +1,35
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """IPython release build script.
2 """IPython release build script.
3 """
3 """
4 from toollib import *
4 from toollib import *
5
5
6 # Get main ipython dir, this will raise if it doesn't pass some checks
6 # Get main ipython dir, this will raise if it doesn't pass some checks
7 ipdir = get_ipdir()
7 ipdir = get_ipdir()
8 cd(ipdir)
8 cd(ipdir)
9
9
10 # Load release info
10 # Load release info
11 execfile(pjoin('IPython','core','release.py'))
11 execfile(pjoin('IPython','core','release.py'))
12
12
13 # Check that everything compiles
13 # Check that everything compiles
14 compile_tree()
14 compile_tree()
15
15
16 # Cleanup
16 # Cleanup
17 for d in ['build','dist',pjoin('docs','build'),pjoin('docs','dist'),
17 for d in ['build','dist',pjoin('docs','build'),pjoin('docs','dist'),
18 pjoin('docs','source','api','generated')]:
18 pjoin('docs','source','api','generated')]:
19 if os.path.isdir(d):
19 if os.path.isdir(d):
20 remove_tree(d)
20 remove_tree(d)
21
21
22 # Build source and binary distros
22 # Build source and binary distros
23 c('./setup.py sdist --formats=gztar,zip')
23 sh('./setup.py sdist --formats=gztar,zip')
24
24
25 # Build eggs
25 # Build eggs
26 c('python2.6 ./setupegg.py bdist_egg')
26 sh('python2.6 ./setupegg.py bdist_egg')
27
27
28 # Call the windows build separately, so that the extra Windows scripts don't
28 # Call the windows build separately, so that the extra Windows scripts don't
29 # get pulled into Unix builds (setup.py has code which checks for
29 # get pulled into Unix builds (setup.py has code which checks for
30 # bdist_wininst)
30 # bdist_wininst)
31 c("python setup.py bdist_wininst --install-script=ipython_win_post_install.py")
31 sh("python setup.py bdist_wininst --install-script=ipython_win_post_install.py")
32
32
33 # Change name so retarded Vista runs the installer correctly
33 # Change name so retarded Vista runs the installer correctly
34 c("rename 's/linux-i686/win32-setup/' dist/*.exe")
34 sh("rename 's/linux-i686/win32-setup/' dist/*.exe")
35 c("rename 's/linux-x86_64/win32-setup/' dist/*.exe")
35 sh("rename 's/linux-x86_64/win32-setup/' dist/*.exe")
@@ -1,25 +1,25
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """Simple script to create a tarball with proper git info.
2 """Simple script to create a tarball with proper git info.
3 """
3 """
4
4
5 import commands
5 import commands
6 import os
6 import os
7 import sys
7 import sys
8 import shutil
8 import shutil
9
9
10 from toollib import *
10 from toollib import *
11
11
12 tag = commands.getoutput('git describe')
12 tag = commands.getoutput('git describe --tags')
13 base_name = 'ipython-%s' % tag
13 base_name = 'ipython-%s' % tag
14 tar_name = '%s.tgz' % base_name
14 tar_name = '%s.tgz' % base_name
15
15
16 # git archive is weird: Even if I give it a specific path, it still won't
16 # git archive is weird: Even if I give it a specific path, it still won't
17 # archive the whole tree. It seems the only way to get the whole tree is to cd
17 # archive the whole tree. It seems the only way to get the whole tree is to cd
18 # to the top of the tree. There are long threads (since 2007) on the git list
18 # to the top of the tree. There are long threads (since 2007) on the git list
19 # about this and it still doesn't work in a sensible way...
19 # about this and it still doesn't work in a sensible way...
20
20
21 start_dir = os.getcwd()
21 start_dir = os.getcwd()
22 cd('..')
22 cd('..')
23 git_tpl = 'git archive --format=tar --prefix={0}/ HEAD | gzip > {1}'
23 git_tpl = 'git archive --format=tar --prefix={0}/ HEAD | gzip > {1}'
24 c(git_tpl.format(base_name, tar_name))
24 sh(git_tpl.format(base_name, tar_name))
25 c('mv {0} tools/'.format(tar_name))
25 sh('mv {0} tools/'.format(tar_name))
@@ -1,55 +1,48
1 """Various utilities common to IPython release and maintenance tools.
1 """Various utilities common to IPython release and maintenance tools.
2 """
2 """
3 # Library imports
3 # Library imports
4 import os
4 import os
5 import sys
5 import sys
6
6
7 from distutils.dir_util import remove_tree
7 from distutils.dir_util import remove_tree
8
8
9 # Useful shorthands
9 # Useful shorthands
10 pjoin = os.path.join
10 pjoin = os.path.join
11 cd = os.chdir
11 cd = os.chdir
12
12
13 # Utility functions
13 # Utility functions
14 def c(cmd):
14 def sh(cmd):
15 """Run system command, raise SystemExit if it returns an error."""
15 """Run system command in shell, raise SystemExit if it returns an error."""
16 print "$",cmd
16 print "$",cmd
17 stat = os.system(cmd)
17 stat = os.system(cmd)
18 #stat = 0 # Uncomment this and comment previous to run in debug mode
18 #stat = 0 # Uncomment this and comment previous to run in debug mode
19 if stat:
19 if stat:
20 raise SystemExit("Command %s failed with code: %s" % (cmd, stat))
20 raise SystemExit("Command %s failed with code: %s" % (cmd, stat))
21
21
22 # Backwards compatibility
23 c = sh
22
24
23 def get_ipdir():
25 def get_ipdir():
24 """Get IPython directory from command line, or assume it's the one above."""
26 """Get IPython directory from command line, or assume it's the one above."""
25
27
26 # Initialize arguments and check location
28 # Initialize arguments and check location
27 try:
29 try:
28 ipdir = sys.argv[1]
30 ipdir = sys.argv[1]
29 except IndexError:
31 except IndexError:
30 ipdir = '..'
32 ipdir = '..'
31
33
32 ipdir = os.path.abspath(ipdir)
34 ipdir = os.path.abspath(ipdir)
33
35
34 cd(ipdir)
36 cd(ipdir)
35 if not os.path.isdir('IPython') and os.path.isfile('setup.py'):
37 if not os.path.isdir('IPython') and os.path.isfile('setup.py'):
36 raise SystemExit('Invalid ipython directory: %s' % ipdir)
38 raise SystemExit('Invalid ipython directory: %s' % ipdir)
37 return ipdir
39 return ipdir
38
40
39
41
40 def compile_tree():
42 def compile_tree():
41 """Compile all Python files below current directory."""
43 """Compile all Python files below current directory."""
42 vstr = '.'.join(map(str,sys.version_info[:2]))
44 stat = os.system('python -m compileall .')
43 stat = os.system('python %s/lib/python%s/compileall.py .' %
44 (sys.prefix,vstr))
45 if stat:
45 if stat:
46 msg = '*** ERROR: Some Python files in tree do NOT compile! ***\n'
46 msg = '*** ERROR: Some Python files in tree do NOT compile! ***\n'
47 msg += 'See messages above for the actual file that produced it.\n'
47 msg += 'See messages above for the actual file that produced it.\n'
48 raise SystemExit(msg)
48 raise SystemExit(msg)
49
50
51 def version_info():
52 """Return bzr version info as a dict."""
53 out = os.popen('bzr version-info')
54 pairs = (l.split(':',1) for l in out)
55 return dict(((k,v.strip()) for (k,v) in pairs))
1 NO CONTENT: file was removed
NO CONTENT: file was removed
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