Repository: ipython/ipython

Issue:
Cannot set custom mathjax url, crash notebook server.
Basically the mathjax path traits is trying to be set before soem other traits that need to be initialised first...

```
$ ipython notebook --NotebookApp.mathjax_url='foo'
Traceback (most recent call last):
  File "/usr/local/share/python/ipython", line 9, in <module>
    load_entry_point('ipython==1.0.dev', 'console_scripts', 'ipython')()
  File "/Users/bussonniermatthias/ipython/IPython/__init__.py", line 118, in start_ipython
    return launch_new_instance(argv=argv, **kwargs)
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 538, in launch_instance
    app.initialize(argv)
  File "<string>", line 2, in initialize
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 89, in catch_config_error
    return method(app, *args, **kwargs)
  File "/Users/bussonniermatthias/ipython/IPython/terminal/ipapp.py", line 316, in initialize
    super(TerminalIPythonApp, self).initialize(argv)
  File "<string>", line 2, in initialize
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 89, in catch_config_error
    return method(app, *args, **kwargs)
  File "/Users/bussonniermatthias/ipython/IPython/core/application.py", line 347, in initialize
    self.parse_command_line(argv)
  File "/Users/bussonniermatthias/ipython/IPython/terminal/ipapp.py", line 311, in parse_command_line
    return super(TerminalIPythonApp, self).parse_command_line(argv)
  File "<string>", line 2, in parse_command_line
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 89, in catch_config_error
    return method(app, *args, **kwargs)
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 468, in parse_command_line
    return self.initialize_subcommand(subc, subargv)
  File "<string>", line 2, in initialize_subcommand
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 89, in catch_config_error
    return method(app, *args, **kwargs)
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 407, in initialize_subcommand
    self.subapp.initialize(argv)
  File "<string>", line 2, in initialize
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 89, in catch_config_error
    return method(app, *args, **kwargs)
  File "/Users/bussonniermatthias/ipython/IPython/html/notebookapp.py", line 661, in initialize
    super(NotebookApp, self).initialize(argv)
  File "<string>", line 2, in initialize
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 89, in catch_config_error
    return method(app, *args, **kwargs)
  File "/Users/bussonniermatthias/ipython/IPython/core/application.py", line 347, in initialize
    self.parse_command_line(argv)
  File "/Users/bussonniermatthias/ipython/IPython/html/notebookapp.py", line 478, in parse_command_line
    super(NotebookApp, self).parse_command_line(argv)
  File "<string>", line 2, in parse_command_line
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 89, in catch_config_error
    return method(app, *args, **kwargs)
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 493, in parse_command_line
    self.update_config(config)
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 392, in update_config
    self.config = newconfig
  File "/Users/bussonniermatthias/ipython/IPython/utils/traitlets.py", line 319, in __set__
    obj._notify_trait(self.name, old_value, new_value)
  File "/Users/bussonniermatthias/ipython/IPython/utils/traitlets.py", line 470, in _notify_trait
    c(name, old_value, new_value)
  File "/Users/bussonniermatthias/ipython/IPython/config/application.py", line 241, in _config_changed
    SingletonConfigurable._config_changed(self, name, old, new)
  File "/Users/bussonniermatthias/ipython/IPython/config/configurable.py", line 171, in _config_changed
    self._load_config(new, traits=traits, section_names=section_names)
  File "/Users/bussonniermatthias/ipython/IPython/config/configurable.py", line 155, in _load_config
    setattr(self, name, deepcopy(config_value))
  File "/Users/bussonniermatthias/ipython/IPython/utils/traitlets.py", line 316, in __set__
    old_value = self.__get__(obj)
  File "/Users/bussonniermatthias/ipython/IPython/utils/traitlets.py", line 297, in __get__
    value = obj._trait_dyn_inits[self.name](obj)
  File "/Users/bussonniermatthias/ipython/IPython/html/notebookapp.py", line 446, in _mathjax_url_default
    mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), self.static_file_path)
  File "/Users/bussonniermatthias/ipython/IPython/html/notebookapp.py", line 434, in static_file_path
    return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH]
  File "/Users/bussonniermatthias/ipython/IPython/utils/traitlets.py", line 297, in __get__
    value = obj._trait_dyn_inits[self.name](obj)
  File "/Users/bussonniermatthias/ipython/IPython/html/notebookapp.py", line 429, in _extra_static_paths_default
    return [os.path.join(self.profile_dir.location, 'static')]
```



Discussion:

Resolving patch:
diff --git a/IPython/core/application.py b/IPython/core/application.py
--- a/IPython/core/application.py
+++ b/IPython/core/application.py
@@ -39,7 +39,7 @@
 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
-from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set
+from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict, Set, Instance
 
 #-----------------------------------------------------------------------------
 # Classes and functions
@@ -133,6 +133,15 @@ def _profile_changed(self, name, old, new):
         the environment variable IPYTHONDIR.
         """
     )
+    _in_init_profile_dir = False
+    profile_dir = Instance(ProfileDir)
+    def _profile_dir_default(self):
+        # avoid recursion
+        if self._in_init_profile_dir:
+            return
+        # profile_dir requested early, force initialization
+        self.init_profile_dir()
+        return self.profile_dir
 
     overwrite = Bool(False, config=True,
         help="""Whether to overwrite existing config files when copying""")
@@ -258,6 +267,10 @@ def load_config_file(self, suppress_errors=True):
 
     def init_profile_dir(self):
         """initialize the profile dir"""
+        self._in_init_profile_dir = True
+        if self.profile_dir is not None:
+            # already ran
+            return
         try:
             # location explicitly specified:
             location = self.config.ProfileDir.location
@@ -302,6 +315,7 @@ def init_profile_dir(self):
 
         self.profile_dir = p
         self.config_file_paths.append(p.location)
+        self._in_init_profile_dir = False
 
     def init_config_files(self):
         """[optionally] copy default config files into profile dir."""


Test patch: