From 45904ceebfb65e54e8cfa1d8839558f0507ebe99 2010-10-27 06:19:36 From: Fernando Perez Date: 2010-10-27 06:19:36 Subject: [PATCH] Complete support of git commit info with IPython.sys_info(). This will give us an easy way for users to report platform details, without trying to cram lots of data into the version string. Now, the version information in release.py is simple and doesn't attempt to read version control data at runtime. We expose sys_info() as a top-level function so it's very easy to remember/direct for new users. Minor doc/copyright notices updates in the same files. --- diff --git a/IPython/__init__.py b/IPython/__init__.py index 8dcab7c..c2573af 100755 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -6,10 +6,14 @@ IPython. IPython is a set of tools for interactive and exploratory computing in Python. """ #----------------------------------------------------------------------------- -# Copyright (C) 2008-2009 The IPython Development Team +# Copyright (c) 2008-2010, IPython Development Team. +# Copyright (c) 2001-2007, Fernando Perez +# Copyright (c) 2001, Janko Hauser +# Copyright (c) 2001, Nathaniel Gray # -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- @@ -45,6 +49,7 @@ from .frontend.terminal.embed import embed from .core.error import TryNext from .core.interactiveshell import InteractiveShell from .testing import test +from .utils.sysinfo import sys_info # Release data __author__ = '' @@ -52,4 +57,3 @@ for author, email in release.authors.itervalues(): __author__ += author + ' <' + email + '>\n' __license__ = release.license __version__ = release.version -__revision__ = release.revision diff --git a/IPython/core/release.py b/IPython/core/release.py index 5f9a306..0f7d422 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -1,39 +1,40 @@ # -*- coding: utf-8 -*- """Release data for the IPython project.""" -#***************************************************************************** -# Copyright (C) 2008-2009 The IPython Development Team -# Copyright (C) 2001-2008 Fernando Perez -# Copyright (c) 2001 Janko Hauser and Nathaniel Gray -# +#----------------------------------------------------------------------------- +# Copyright (c) 2008-2010, IPython Development Team. +# Copyright (c) 2001-2007, Fernando Perez +# Copyright (c) 2001, Janko Hauser +# Copyright (c) 2001, Nathaniel Gray # -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#***************************************************************************** +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- # Name of the package for release purposes. This is the name which labels # the tarballs and RPMs made by distutils, so it's best to lowercase it. name = 'ipython' -# For versions with substrings (like 0.6.16.svn), use an extra . to separate -# the new substring. We have to avoid using either dashes or underscores, -# because bdist_rpm does not accept dashes (an RPM) convention, and -# bdist_deb does not accept underscores (a Debian convention). +# IPython version information. An empty _version_extra corresponds to a full +# release. 'dev' as a _version_extra string means this is a development +# version +_version_major = 0 +_version_minor = 11 +_version_micro = '' # use '' for first of series, number for 1 and above +_version_extra = 'dev' +#_version_extra = '' # Uncomment this for full releases -development = True # change this to False to do a release -version_base = '0.11.alpha1' -branch = 'ipython' -# This needs to be updated to something that is meaningful for git -revision = '0' +# Construct full version string from these. +_ver = [_version_major, _version_minor] +if _version_micro: + _ver.append(_version_micro) +if _version_extra: + _ver.append(_version_extra) -if development: - if branch == 'ipython': - version = '%s.git' % (version_base) - else: - version = '%s.git.%s' % (version_base, branch) -else: - version = version_base +__version__ = '.'.join(map(str, _ver)) +version = __version__ # backwards compatibility name description = "An interactive computing environment for Python" @@ -95,8 +96,8 @@ The parallel computing architecture has the following main features: * Robust error handling in parallel code. -The latest development version is always available from IPython's `Launchpad -site `_. +The latest development version is always available from IPython's `GitHub +site `_. """ license = 'BSD' diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index db139b1..cfccb8e 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -115,7 +115,7 @@ have['gobject'] = test_for('gobject') def report(): """Return a string with a summary report of test-related variables.""" - out = [ sys_info() ] + out = [ sys_info(), '\n'] avail = [] not_avail = [] diff --git a/IPython/utils/sysinfo.py b/IPython/utils/sysinfo.py index 974c956..7aa7077 100644 --- a/IPython/utils/sysinfo.py +++ b/IPython/utils/sysinfo.py @@ -1,6 +1,6 @@ # encoding: utf-8 """ -Utilities for getting information about a system. +Utilities for getting information about IPython and the system it's running in. """ #----------------------------------------------------------------------------- @@ -16,37 +16,122 @@ Utilities for getting information about a system. import os import platform +import pprint import sys import subprocess +from ConfigParser import ConfigParser + from IPython.core import release #----------------------------------------------------------------------------- +# Globals +#----------------------------------------------------------------------------- +COMMIT_INFO_FNAME = '.git_commit_info.ini' + +#----------------------------------------------------------------------------- # Code #----------------------------------------------------------------------------- +def pkg_commit_hash(pkg_path): + """Get short form of commit hash given directory `pkg_path` + + There should be a file called 'COMMIT_INFO.txt' in `pkg_path`. This is a + file in INI file format, with at least one section: ``commit hash``, and two + variables ``archive_subst_hash`` and ``install_hash``. The first has a + substitution pattern in it which may have been filled by the execution of + ``git archive`` if this is an archive generated that way. The second is + filled in by the installation, if the installation is from a git archive. + + We get the commit hash from (in order of preference): + + * A substituted value in ``archive_subst_hash`` + * A written commit hash value in ``install_hash` + * git output, if we are in a git repository + + If all these fail, we return a not-found placeholder tuple + + Parameters + ---------- + pkg_path : str + directory containing package + + Returns + ------- + hash_from : str + Where we got the hash from - description + hash_str : str + short form of hash + """ + # Try and get commit from written commit text file + pth = os.path.join(pkg_path, COMMIT_INFO_FNAME) + if not os.path.isfile(pth): + raise IOError('Missing commit info file %s' % pth) + cfg_parser = ConfigParser() + cfg_parser.read(pth) + archive_subst = cfg_parser.get('commit hash', 'archive_subst_hash') + if not archive_subst.startswith('$Format'): # it has been substituted + return 'archive substitution', archive_subst + install_subst = cfg_parser.get('commit hash', 'install_hash') + if install_subst != '': + return 'installation', install_subst + # maybe we are in a repository + proc = subprocess.Popen('git rev-parse --short HEAD', + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=pkg_path, shell=True) + repo_commit, _ = proc.communicate() + if repo_commit: + return 'repository', repo_commit.strip() + return '(none found)', '' + + +def pkg_info(pkg_path): + """Return dict describing the context of this package + + Parameters + ---------- + pkg_path : str + path containing __init__.py for package + + Returns + ------- + context : dict + with named parameters of interest + """ + src, hsh = pkg_commit_hash(pkg_path) + return dict( + ipython_version=release.version, + ipython_path=pkg_path, + commit_source=src, + commit_hash=hsh, + sys_version=sys.version, + sys_executable=sys.executable, + sys_platform=sys.platform, + platform=platform.platform(), + os_name=os.name, + ) + + def sys_info(): """Return useful information about IPython and the system, as a string. - Examples - -------- - In [1]: print(sys_info()) - IPython version: 0.11.bzr.r1340 # random - BZR revision : 1340 - Platform info : os.name -> posix, sys.platform -> linux2 - : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic - Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15) - [GCC 4.4.1] - """ - out = [] - out.append('IPython version: %s' % release.version) - out.append('BZR revision : %s' % release.revision) - out.append('Platform info : os.name -> %s, sys.platform -> %s' % - (os.name,sys.platform) ) - out.append(' : %s' % platform.platform()) - out.append('Python info : %s' % sys.version) - out.append('') # ensure closing newline - return '\n'.join(out) + Example + ------- + In [2]: print sys_info() + {'commit_hash': '144fdae', # random + 'commit_source': 'repository', + 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython', + 'ipython_version': '0.11.dev', + 'os_name': 'posix', + 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick', + 'sys_executable': '/usr/bin/python', + 'sys_platform': 'linux2', + 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \\n[GCC 4.4.5]'} + """ + p = os.path + path = p.dirname(p.abspath(p.join(__file__, '..'))) + return pprint.pformat(pkg_info(path)) def _num_cpus_unix(): diff --git a/docs/source/development/testing.txt b/docs/source/development/testing.txt index 51dfa48..abda16a 100644 --- a/docs/source/development/testing.txt +++ b/docs/source/development/testing.txt @@ -49,28 +49,22 @@ it system-wide or having configure anything, by typing at the terminal: python ipython.py -and similarly, you can execute the built-in test suite with: - -.. code-block:: bash - - python iptest.py +In order to run the test suite, you must at least be able to import IPython, +even if you haven't fully installed the user-facing scripts yet (common in a +development environment). You can then run the tests with: +.. code-block:: bash -This script manages intelligently both nose and trial, choosing the correct -test system for each of IPython's components. + python -c "import IPython; IPython.test()" -Once you have either installed it or at least configured your system to be -able to import IPython, you can run the tests with: +Once you have installed IPython either via a full install or using: .. code-block:: bash - python -c "import IPython; IPython.test()" + python setup.py develop -This should work as long as IPython can be imported, even if you haven't fully -installed the user-facing scripts yet (common in a development environment). -Once you have installed IPython, you will have available system-wide a script -called :file:`iptest` that does the exact same as the :file:`iptest.py` script -in the source directory, so you can then test simply with: +you will have available a system-wide script called :file:`iptest` that runs +the full test suite. You can then run the suite with: .. code-block:: bash @@ -83,26 +77,25 @@ Regardless of how you run things, you should eventually see something like: ********************************************************************** Test suite completed for system with the following information: - IPython version: 0.11.bzr.r1340 - BZR revision : 1340 - Platform info : os.name -> posix, sys.platform -> linux2 - : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic - Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15) - [GCC 4.4.1] - - Running from an installed IPython: True + {'commit_hash': '144fdae', + 'commit_source': 'repository', + 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython', + 'ipython_version': '0.11.dev', + 'os_name': 'posix', + 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick', + 'sys_executable': '/usr/bin/python', + 'sys_platform': 'linux2', + 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \n[GCC 4.4.5]'} Tools and libraries available at test time: curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface - Tools and libraries NOT available at test time: - objc - - Ran 11 test groups in 36.244s + Ran 9 test groups in 67.213s Status: OK + If not, there will be a message indicating which test group failed and how to rerun that group individually. For example, this tests the :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress @@ -110,7 +103,7 @@ indicators: .. code-block:: bash - $ python iptest.py -v IPython.utils + $ iptest -v IPython.utils ..........................SS..SSS............................S.S... ......................................................... ---------------------------------------------------------------------- @@ -126,7 +119,7 @@ example, this lets you run the specific test :func:`test_rehashx` inside the .. code-block:: bash - $ python iptest.py -vv IPython.core.tests.test_magic:test_rehashx + $ iptest -vv IPython.core.tests.test_magic:test_rehashx IPython.core.tests.test_magic.test_rehashx(True,) ... ok IPython.core.tests.test_magic.test_rehashx(True,) ... ok @@ -146,6 +139,16 @@ package basis: trial IPython.kernel +.. note:: + + The system information summary printed above is accessible from the top + level package. If you encounter a problem with IPython, it's useful to + include this information when reporting on the mailing list; use:: + + from IPython import sys_info + print sys_info() + + and include the resulting information in your query. For developers: writing tests =============================