diff --git a/IPython/config/application.py b/IPython/config/application.py index 3b848c3..bb05472 100644 --- a/IPython/config/application.py +++ b/IPython/config/application.py @@ -118,6 +118,9 @@ class Application(SingletonConfigurable): option_description = Unicode(option_description) keyvalue_description = Unicode(keyvalue_description) subcommand_description = Unicode(subcommand_description) + + python_config_loader_class = PyFileConfigLoader + json_config_loader_class = JSONFileConfigLoader # The usage and example string that goes at the end of the help string. examples = Unicode() @@ -507,8 +510,8 @@ class Application(SingletonConfigurable): path = [path] for path in path[::-1]: # path list is in descending priority order, so load files backwards: - pyloader = PyFileConfigLoader(basefilename+'.py', path=path, log=log) - jsonloader = JSONFileConfigLoader(basefilename+'.json', path=path, log=log) + pyloader = cls.python_config_loader_class(basefilename+'.py', path=path, log=log) + jsonloader = cls.json_config_loader_class(basefilename+'.json', path=path, log=log) config = None for loader in [pyloader, jsonloader]: try: @@ -551,9 +554,7 @@ class Application(SingletonConfigurable): def generate_config_file(self): """generate default config file from Configurables""" - lines = ["# Configuration file for %s."%self.name] - lines.append('') - lines.append('c = get_config()') + lines = ["# Configuration file for %s." % self.name] lines.append('') for cls in self._config_classes: lines.append(cls.class_config_section()) diff --git a/IPython/config/loader.py b/IPython/config/loader.py index e57cc7e..cdd0367 100644 --- a/IPython/config/loader.py +++ b/IPython/config/loader.py @@ -436,52 +436,31 @@ class PyFileConfigLoader(FileConfigLoader): raise ConfigFileNotFound(str(e)) self._read_file_as_dict() return self.config - - + + def load_subconfig(self, fname, path=None): + """Injected into config file namespace as load_subconfig""" + if path is None: + path = self.path + + loader = self.__class__(fname, path) + try: + sub_config = loader.load_config() + except ConfigFileNotFound: + # Pass silently if the sub config is not there, + # treat it as an empty config file. + pass + else: + self.config.merge(sub_config) + def _read_file_as_dict(self): """Load the config file into self.config, with recursive loading.""" - # This closure is made available in the namespace that is used - # to exec the config file. It allows users to call - # load_subconfig('myconfig.py') to load config files recursively. - # It needs to be a closure because it has references to self.path - # and self.config. The sub-config is loaded with the same path - # as the parent, but it uses an empty config which is then merged - # with the parents. - - # If a profile is specified, the config file will be loaded - # from that profile - - def load_subconfig(fname, profile=None): - # import here to prevent circular imports - from IPython.core.profiledir import ProfileDir, ProfileDirError - if profile is not None: - try: - profile_dir = ProfileDir.find_profile_dir_by_name( - get_ipython_dir(), - profile, - ) - except ProfileDirError: - return - path = profile_dir.location - else: - path = self.path - loader = PyFileConfigLoader(fname, path) - try: - sub_config = loader.load_config() - except ConfigFileNotFound: - # Pass silently if the sub config is not there. This happens - # when a user s using a profile, but not the default config. - pass - else: - self.config.merge(sub_config) - - # Again, this needs to be a closure and should be used in config - # files to get the config being loaded. def get_config(): + """Unnecessary now, but a deprecation warning is more trouble than it's worth.""" return self.config - + namespace = dict( - load_subconfig=load_subconfig, + c=self.config, + load_subconfig=self.load_subconfig, get_config=get_config, __file__=self.full_filename, ) diff --git a/IPython/config/manager.py b/IPython/config/manager.py index 429bfaa..9f7f2f5 100644 --- a/IPython/config/manager.py +++ b/IPython/config/manager.py @@ -8,7 +8,6 @@ import json import os from IPython.config import LoggingConfigurable -from IPython.utils.path import locate_profile from IPython.utils.py3compat import PY3 from IPython.utils.traitlets import Unicode @@ -35,22 +34,12 @@ def recursive_update(target, new): class BaseJSONConfigManager(LoggingConfigurable): - """General config manager + """General JSON config manager Deals with persisting/storing config in a json file - in IPython profile """ - profile_dir = Unicode() - def _profile_dir_default(self): - return locate_profile() - - @property - def config_dir(self): - return self._config_dir() - - def _config_dir(self): - return self.profile_dir + config_dir = Unicode('.') def ensure_config_dir_exists(self): try: diff --git a/IPython/config/profile/README b/IPython/config/profile/README deleted file mode 100644 index f8f2f7f..0000000 --- a/IPython/config/profile/README +++ /dev/null @@ -1,10 +0,0 @@ -This is the IPython directory. - -For more information on configuring IPython, do: - -ipython -h - -or to create an empty default profile, populated with default config files: - -ipython profile create - diff --git a/IPython/config/profile/__init__.py b/IPython/config/profile/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/IPython/config/profile/__init__.py +++ /dev/null diff --git a/IPython/config/profile/cluster/ipython_config.py b/IPython/config/profile/cluster/ipython_config.py deleted file mode 100644 index eb4b3fc..0000000 --- a/IPython/config/profile/cluster/ipython_config.py +++ /dev/null @@ -1,13 +0,0 @@ -c = get_config() -app = c.InteractiveShellApp - -# This can be used at any point in a config file to load a sub config -# and merge it into the current one. -load_subconfig('ipython_config.py', profile='default') - -lines = """ -from IPython.parallel import * -""" - -app.exec_lines.append(lines) - diff --git a/IPython/config/profile/math/ipython_config.py b/IPython/config/profile/math/ipython_config.py deleted file mode 100644 index 39c5ca7..0000000 --- a/IPython/config/profile/math/ipython_config.py +++ /dev/null @@ -1,13 +0,0 @@ -c = get_config() -app = c.InteractiveShellApp - -# This can be used at any point in a config file to load a sub config -# and merge it into the current one. -load_subconfig('ipython_config.py', profile='default') - -lines = """ -import cmath -from math import * -""" - -app.exec_lines.append(lines) diff --git a/IPython/config/profile/pysh/ipython_config.py b/IPython/config/profile/pysh/ipython_config.py deleted file mode 100644 index 0f3bf6e..0000000 --- a/IPython/config/profile/pysh/ipython_config.py +++ /dev/null @@ -1,24 +0,0 @@ -c = get_config() -app = c.InteractiveShellApp - -# This can be used at any point in a config file to load a sub config -# and merge it into the current one. -load_subconfig('ipython_config.py', profile='default') - -c.PromptManager.in_template = r'{color.LightGreen}\u@\h{color.LightBlue}[{color.LightCyan}\Y1{color.LightBlue}]{color.Green}|\#> ' -c.PromptManager.in2_template = r'{color.Green}|{color.LightGreen}\D{color.Green}> ' -c.PromptManager.out_template = r'<\#> ' - -c.PromptManager.justify = True - -c.InteractiveShell.separate_in = '' -c.InteractiveShell.separate_out = '' -c.InteractiveShell.separate_out2 = '' - -c.PrefilterManager.multi_line_specials = True - -lines = """ -%rehashx -""" - -app.exec_lines.append(lines) diff --git a/IPython/config/profile/sympy/ipython_config.py b/IPython/config/profile/sympy/ipython_config.py deleted file mode 100644 index 6004cf1..0000000 --- a/IPython/config/profile/sympy/ipython_config.py +++ /dev/null @@ -1,20 +0,0 @@ -c = get_config() -app = c.InteractiveShellApp - -# This can be used at any point in a config file to load a sub config -# and merge it into the current one. -load_subconfig('ipython_config.py', profile='default') - -lines = """ -from __future__ import division -from sympy import * -x, y, z, t = symbols('x y z t') -k, m, n = symbols('k m n', integer=True) -f, g, h = symbols('f g h', cls=Function) -""" - -app.exec_lines.append(lines) - -# Load the sympy_printing extension to enable nice printing of sympy expr's. -app.extensions.append('sympy.interactive.ipythonprinting') - diff --git a/IPython/core/application.py b/IPython/core/application.py index 9741baa..87999d7 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -20,7 +20,7 @@ import shutil import sys from IPython.config.application import Application, catch_config_error -from IPython.config.loader import ConfigFileNotFound +from IPython.config.loader import ConfigFileNotFound, PyFileConfigLoader from IPython.core import release, crashhandler from IPython.core.profiledir import ProfileDir, ProfileDirError from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists @@ -63,6 +63,19 @@ base_flags = dict( """) ) +class ProfileAwareConfigLoader(PyFileConfigLoader): + """A Python file config loader that is aware of IPython profiles.""" + def load_subconfig(self, fname, path=None, profile=None): + if profile is not None: + try: + profile_dir = ProfileDir.find_profile_dir_by_name( + get_ipython_dir(), + profile, + ) + except ProfileDirError: + return + path = profile_dir.location + return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path) class BaseIPythonApplication(Application): @@ -73,6 +86,9 @@ class BaseIPythonApplication(Application): aliases = Dict(base_aliases) flags = Dict(base_flags) classes = List([ProfileDir]) + + # enable `load_subconfig('cfg.py', profile='name')` + python_config_loader_class = ProfileAwareConfigLoader # Track whether the config_file has changed, # because some logic happens only if we aren't using the default. diff --git a/IPython/config/profile/README_STARTUP b/IPython/core/profile/README_STARTUP similarity index 100% rename from IPython/config/profile/README_STARTUP rename to IPython/core/profile/README_STARTUP diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index b5b2fdc..38d8ba7 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -112,7 +112,7 @@ def list_profiles_in(path): def list_bundled_profiles(): """list profiles that are bundled with IPython.""" - path = os.path.join(get_ipython_package_dir(), u'config', u'profile') + path = os.path.join(get_ipython_package_dir(), u'core', u'profile') files = os.listdir(path) profiles = [] for profile in files: diff --git a/IPython/core/profiledir.py b/IPython/core/profiledir.py index bff81e2..515fad9 100644 --- a/IPython/core/profiledir.py +++ b/IPython/core/profiledir.py @@ -114,7 +114,7 @@ class ProfileDir(LoggingConfigurable): self._mkdir(self.startup_dir) readme = os.path.join(self.startup_dir, 'README') - src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP') + src = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'README_STARTUP') if not os.path.exists(src): self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src) @@ -169,7 +169,7 @@ class ProfileDir(LoggingConfigurable): if os.path.isfile(dst) and not overwrite: return False if path is None: - path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default') + path = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'default') src = os.path.join(path, config_file) shutil.copy(src, dst) return True diff --git a/IPython/core/tests/test_profile.py b/IPython/core/tests/test_profile.py index 1939e6d..b20aa0c 100644 --- a/IPython/core/tests/test_profile.py +++ b/IPython/core/tests/test_profile.py @@ -149,9 +149,8 @@ def test_list_profiles_in(): def test_list_bundled_profiles(): # This variable will need to be updated when a new profile gets bundled - bundled_true = [u'cluster', u'math', u'pysh', u'sympy'] bundled = sorted(list_bundled_profiles()) - nt.assert_equal(bundled, bundled_true) + nt.assert_equal(bundled, []) def test_profile_create_ipython_dir(): diff --git a/IPython/html/services/config/manager.py b/IPython/html/services/config/manager.py index c268284..534d095 100644 --- a/IPython/html/services/config/manager.py +++ b/IPython/html/services/config/manager.py @@ -3,12 +3,19 @@ # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. -import os - from IPython.config.manager import BaseJSONConfigManager +from IPython.utils.path import locate_profile +from IPython.utils.traitlets import Unicode class ConfigManager(BaseJSONConfigManager): """Config Manager used for storing notebook frontend config""" + + profile = Unicode('default', config=True) + + profile_dir = Unicode(config=True) + + def _profile_dir_default(self): + return locate_profile(self.profile) - def _config_dir(self): - return os.path.join(self.profile_dir, 'nbconfig') + def _config_dir_default(self): + return self.profile_dir diff --git a/setupbase.py b/setupbase.py index e7a9c7a..382510a 100644 --- a/setupbase.py +++ b/setupbase.py @@ -183,7 +183,7 @@ def find_package_data(): os.chdir(cwd) package_data = { - 'IPython.config.profile' : ['README*', '*/*.py'], + 'IPython.core' : ['profile/README*'], 'IPython.core.tests' : ['*.png', '*.jpg'], 'IPython.lib.tests' : ['*.wav'], 'IPython.testing.plugin' : ['*.txt'],