From 51c4e56ba0ee2306f37fe4d4902c508792c7accc 2009-12-30 23:47:02 From: Fernando Perez Date: 2009-12-30 23:47:02 Subject: [PATCH] Improve pylab support, find profiles in IPython's own directory. - Support "ipython -pylab" with a single dash, as this is an extremely widely used option and documented in many places, including books. - Now ipython -p foo will find profile foo from IPython/config/profile if shipped. This lets users find profiles shipped by IPython itself without having to install them (though the IPython directory has lowest priority). --- diff --git a/IPython/core/application.py b/IPython/core/application.py old mode 100644 new mode 100755 index 7fa9e57..92a862c --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -34,7 +34,7 @@ import os import sys from IPython.core import release -from IPython.utils.genutils import get_ipython_dir +from IPython.utils.genutils import get_ipython_dir, get_ipython_package_dir from IPython.config.loader import ( PyFileConfigLoader, ArgParseConfigLoader, @@ -82,15 +82,22 @@ class Application(object): name = u'ipython' description = 'IPython: an enhanced interactive Python shell.' + config_file_name = u'ipython_config.py' + # Track the default and actual separately because some messages are + # only printed if we aren't using the default. + default_config_file_name = config_file_name default_log_level = logging.WARN + # Set by --profile option + profile_name = None + # User's ipython directory, typically ~/.ipython/ + ipython_dir = None + + # Private attributes + _exiting = False def __init__(self): - self._exiting = False self.init_logger() - # Track the default and actual separately because some messages are - # only printed if we aren't using the default. - self.default_config_file_name = self.config_file_name def init_logger(self): self.log = logging.getLogger(self.__class__.__name__) @@ -197,10 +204,10 @@ class Application(object): def find_ipython_dir(self): """Set the IPython directory. - This sets ``self.ipython_dir``, but the actual value that is passed - to the application is kept in either ``self.default_config`` or + This sets ``self.ipython_dir``, but the actual value that is passed to + the application is kept in either ``self.default_config`` or ``self.command_line_config``. This also adds ``self.ipython_dir`` to - ``sys.path`` so config files there can be references by other config + ``sys.path`` so config files there can be referenced by other config files. """ @@ -230,8 +237,7 @@ class Application(object): config file are set in :meth:`find_config_file_paths` and then passed to the config file loader where they are resolved to an absolute path. - If a profile has been set at the command line, this will resolve - it. + If a profile has been set at the command line, this will resolve it. """ try: @@ -241,11 +247,12 @@ class Application(object): try: self.profile_name = self.command_line_config.Global.profile + except AttributeError: + pass + else: name_parts = self.config_file_name.split('.') name_parts.insert(1, u'_' + self.profile_name + u'.') self.config_file_name = ''.join(name_parts) - except AttributeError: - pass def find_config_file_paths(self): """Set the search paths for resolving the config file. @@ -253,7 +260,11 @@ class Application(object): This must set ``self.config_file_paths`` to a sequence of search paths to pass to the config file loader. """ - self.config_file_paths = (os.getcwd(), self.ipython_dir) + # Include our own profiles directory last, so that users can still find + # our shipped copies of builtin profiles even if they don't have them + # in their local ipython directory. + prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile') + self.config_file_paths = (os.getcwd(), self.ipython_dir,prof_dir) def pre_load_file_config(self): """Do actions before the config file is loaded.""" @@ -266,7 +277,8 @@ class Application(object): ``CONFIG_FILE`` config variable is set to the resolved config file location. If not successful, an empty config is used. """ - self.log.debug("Attempting to load config file: %s" % self.config_file_name) + self.log.debug("Attempting to load config file: %s" % + self.config_file_name) loader = PyFileConfigLoader(self.config_file_name, path=self.config_file_paths) try: @@ -275,11 +287,11 @@ class Application(object): except IOError: # Only warn if the default config file was NOT being used. if not self.config_file_name==self.default_config_file_name: - self.log.warn("Config file not found, skipping: %s" % \ + self.log.warn("Config file not found, skipping: %s" % self.config_file_name, exc_info=True) self.file_config = Config() except: - self.log.warn("Error loading config file: %s" % \ + self.log.warn("Error loading config file: %s" % self.config_file_name, exc_info=True) self.file_config = Config() @@ -299,7 +311,8 @@ class Application(object): def log_file_config(self): if hasattr(self.file_config.Global, 'config_file'): - self.log.debug("Config file loaded: %s" % self.file_config.Global.config_file) + self.log.debug("Config file loaded: %s" % + self.file_config.Global.config_file) self.log.debug(repr(self.file_config)) def merge_configs(self): diff --git a/IPython/core/ipapp.py b/IPython/core/ipapp.py old mode 100644 new mode 100755 index 70d76ce..dae34e0 --- a/IPython/core/ipapp.py +++ b/IPython/core/ipapp.py @@ -292,6 +292,24 @@ class IPythonAppCLConfigLoader(BaseAppArgParseConfigLoader): arguments = cl_args + def load_config(self): + """Do actions just before loading the command line config.""" + + # Special hack: there are countless uses of 'ipython -pylab' (with one + # dash) in the wild, including in printed books. Since argparse does + # will interpret -pylab as '-p ylab', sending us in a search for a + # profile named 'ylab', instead we special-case here -pylab as the + # first or second option only (this is how old ipython used to work) + # and convert this use to --pylab. Ugly, but needed for this one + # very widely used case. + firstargs = sys.argv[:3] + try: + idx = firstargs.index('-pylab') + except ValueError: + pass + else: + sys.argv[idx] = '--pylab' + return super(IPythonAppCLConfigLoader, self).load_config() default_config_file_name = u'ipython_config.py' @@ -303,22 +321,25 @@ class IPythonApp(Application): def create_default_config(self): super(IPythonApp, self).create_default_config() - self.default_config.Global.display_banner = True + # Eliminate multiple lookups + Global = self.default_config.Global + # Set all default values + Global.display_banner = True # If the -c flag is given or a file is given to run at the cmd line # like "ipython foo.py", normally we exit without starting the main # loop. The force_interact config variable allows a user to override # this and interact. It is also set by the -i cmd line flag, just # like Python. - self.default_config.Global.force_interact = False + Global.force_interact = False # By default always interact by starting the IPython mainloop. - self.default_config.Global.interact = True + Global.interact = True # No GUI integration by default - self.default_config.Global.wthread = False - self.default_config.Global.q4thread = False - self.default_config.Global.gthread = False + Global.wthread = False + Global.q4thread = False + Global.gthread = False def create_command_line_config(self): """Create and return a command line config loader.""" diff --git a/IPython/utils/genutils.py b/IPython/utils/genutils.py index 0a81348..d0131e8 100644 --- a/IPython/utils/genutils.py +++ b/IPython/utils/genutils.py @@ -46,11 +46,6 @@ from IPython.utils import platutils from IPython.utils.generics import result_display from IPython.external.path import path -try: - set -except: - from sets import Set as set - #**************************************************************************** # Exceptions @@ -824,6 +819,12 @@ def get_ipython_dir(): return ipdir.decode(sys.getfilesystemencoding()) +def get_ipython_package_dir(): + """Get the base directory where IPython itself is installed.""" + ipdir = os.path.dirname(IPython.__file__) + return ipdir.decode(sys.getfilesystemencoding()) + + #**************************************************************************** # strings and text diff --git a/IPython/utils/tests/test_genutils.py b/IPython/utils/tests/test_genutils.py index b8f1995..44cce8b 100644 --- a/IPython/utils/tests/test_genutils.py +++ b/IPython/utils/tests/test_genutils.py @@ -304,3 +304,8 @@ def test_filefind(): alt_dirs = genutils.get_ipython_dir() t = genutils.filefind(f.name,alt_dirs) print 'found:',t + + +def test_get_ipython_package_dir(): + ipdir = genutils.get_ipython_package_dir() + nt.assert_true(os.path.isdir(ipdir))