New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Config5 #400
Config5 #400
Conversation
At this point, I am mostly testing out various approaches, but: * class_traits and class_trait_names added. * appconfig example created for testing new config ideas. * InteractiveShell traits updated. * shortname handling added to command line config loader.
I have added a singleton configurable class for objects that should have only a single instance, such as InteractiveShell and the main application objects. For these classes the .instance() method should be used to create/retrieve the instance.
I have moved the instance method to a new subclass of Configurable so we can use it on other configurable classes, like Application. InteractiveShell now just inherits from this class.
* Application now subclasses SingletonConfigurable. * Added logging support.
I have to say that I really dislike that InteractiveShell is currently a singleton. I don't think it's necessary, and it introduces artificial limitations. I would like to remove that, but it gets harder if we keep adding features that use it. |
I am not attached to InteractiveShell being a singleton. The only class that absolutely need to be a singleton is the main Application object, which represents the entire process. In fact, two summers ago, I spent quite a bit making changes to move us in that direction. But there are still a few things we would need to figure out before we can remove this restriction entirely.
I think that fixing these things would improve the core greatly. Just out of curiosity, what usage cases do you have for multiple InteractiveShell instances? |
We would have to register/unregister these overrides/redirections before/after every execution.
Are any of these methods not called from inside the user_ns?
This is less clear to me I would be interested in an example of having multiple simultaneous InteractiveShells in one process, because I can't think of any. |
As for use cases, we have a CodeEditor in Traits UI that provides a shell widget that lets you run commands in a namespace. There can be any number of these in the GUI each editing different namespaces. We can use our own hacked up shell using Cmd, but IPython would be infinitely better. And before you ask, yes, IPython's Qt frontend does work just fine in-process (with some hacks around 0MQ). The only thing interfering with an IPython implementation of CodeEditor is the singleton nature of InteractiveShell. |
SingletonConfigurable does not enforce uniqueness, it just has a notion of a 'current instance'. You can create as many as you want, but saved_instance = InteractiveShell.select_instance(self)
...
InteractiveShell.select_instance(saved_instance) That way, Can we gather the singleton-requiring code here, so we know what needs to change? As I understand it, there are:
What other code assumes |
|
Is it possible to have in the config (and traitlets) for collections of a type, along the lines of argparse's nargs. For instance, I have many Traits that are pairs of ints, but that just means I have to use a list. It would be nice if I could have something like: class C(HasTraits):
n = Int(n=2) # this results in a length-2 list, or 2-tuple or something
ns = Int(n='?') # extendable list of ints Where I would still get type checking, etc. |
enthoughts.traits actually subclasses the fundamental containers (list, tuple, dict) to provide typed and traited containers for this type of thing. When I wrote traitlets, Fernando and I talked about this and decided that it is overkill for ipython and that we didn't like the idea of having to use special list/tuple/dict subclasses everywhere. I know this doesn't help your situation though. Maybe a simple way of handling it is this: set the type to List and then define an _on_foo_changed method that will get called when the trait is set. You can do the type checking at that point. |
Note that you could still let the List and Tuple traits take type arguments (e.g. List(Int) is a list of integers and Tuple(Str, Int) is a 2-tuple of a string and an integer) that only type-check on assignment. It's not quite as thorough as being able to type-check what you append to that list, but it solves most of the configuration use cases. |
That is a good idea and would cover most of our usage cases. On Thu, May 5, 2011 at 10:12 PM, rkern
Brian E. Granger |
@ellisonbg The old Application had a crash_handler_class. Do we not want this to be part of the top-level Application anymore? |
I left out attributes and capabilities in config.application.Application that are IPython specific. In IPython.core.application, we can have a subclass with those things still there. I imagine that IPython.config could be useful outside of IPython, so I am trying to keep it clean of IPython specific logic. |
This code review has gotten off topic to the issue of InteractiveShell being a singleton. I am wondering if there are other comments related to the actual config changes in this branch. |
I know, sorry about that. I'm currently working on adapting the parallel applications to the new config branch (that's where the crash handler question came from). So far, it looks very nice and clean! I am having some issues with init_logging. What is the right model for logging that requires other objects to be constructed first? A separate 'reinit_logging', so logging gets initialized twice? Yes, I imagine we will want IPython.core.application that includes crash_handler, and various general-IPython bits. |
I see that you manually call Otherwise, code that wants to construct an app needs to know about all the init methods. Or should we expect the |
On logging: good point. Possibly not have init call init_logging? Either that or your reinit logging (or maybe config_logging). On calling init_foo, init_bar by hand. We want the main init method to only instantiate the app with the defaults. So init should not read the command line or config files. The reason for this is that in many cases third parties want to customize the app and not do all of the logic. An example is sympy, which may want to start ipython with command line args, but no config files. We want to have Application methods with that type of granularity. Now that doesn't mean we can't also have something like init_all() as a shorthand for "call all the init methods" |
"""Parse the command line arguments.""" | ||
argv = sys.argv[1:] if argv is None else argv | ||
|
||
if '-h' in argv or '--h' in argv: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'--help' should probably trigger here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is, it should probably be '-h', '--help'. I don't think anyone expects '--' with abbreviated names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep
The logging bit is tricky, because you want some kind of logging ready as soon as I'm fine with having a custom 'really_init_logging' in my App, or pulling init_logging out of Re: init_stages, I understand the desire for breaking it up into steps, that makes sense. I am just thinking that maybe a simplest-case where there is one method that calls the steps in the right order could be part of the official API. |
Yes, the logging stuff is tricky. Can we build a traitlets based API that when some attribute is set, the logging is immediately updated? Sort of like we do with the log_level. Yes, I think we do want a single method (something other than init) that does all of the init stuff. As an aside. Previously, the individual steps in the init logic had to be done in a very specific order. Now, that is not the case. I think the traits machinery will simplify this and allow any thing to be called in a more flexible order. |
Collision detection on shortnames probably shouldn't catch inherited Traits. For instance, with: class A(Configurable):
a = Int(1, config=True, shortname='a')
class B(A):
b = Int(2, config=True)
class C(A):
c = Int(3, config=True) No two of those classes can be used together in an Application due to a conflict on 'a'. This is a pretty big problem in the parallel code, since most objects inherit from a It seems like a safe assumption that if I set 'a=5', I want that set in the parent class that defines it. |
Good catch. So the collision detection code needs to see if the collision is in a parent/child class relationship and let it pass. |
Not just parent/child, but also siblings - B&C should work together. If that's too complicated, it's probably okay to require that A (the mutual ancestor) be in the class list as well, though inspecting What precisely should the resolution be? Case 1: A&B
Case 2: B&C
The effect of all of these is going to be the same in almost all cases. However, if there is also a If we require that A be included in the class list, then case 2 is irrelevant. |
I would recommend against configuring the shortnames in the trait declarations themselves. The abbreviations should not be under the control of the individual components. It requires coordination between components to contribute to the global shortname namespace. Subclassing just adds more problems. Instead, the shortname abbreviations should be owned by a top-level object, maybe the Application (I've only taken a brief look at the diffs; I'm not sure I have a complete picture, yet). For example, it could have a dictionary mapping shortnames to their full "addresses": This also allows the Application writer greater control rather than the component author. For example, you may write the component |
I think I agree about the shortnames. A simple dict of the form @rkern suggested: This comes up a lot in the parallel code, which has 4 scripts, all of which involve some overlap in Configurables, but have dramatically different priorities of what to configure. The shortname dict would also allow you to organize the help output by placing the options with a shortname in a higher priority location than those without. This is possible with the current code but doesn't make any sense to do because, as Robert pointed out, the component shouldn't dictate trait prominence to the Application. |
I think this makes sense as well. It will also help the design in the following way. Currently, we have to track all of the Configurables for an app and pass those to the command line parser to handle the shortnames. With this change we won't have to track all of that. Instead, we can just pass the dict. The only thing we will loose is the ability to have the auto-generated help strings for each component include the shortnames. But we can probably figure out a way of handling that without addiing to much complexity. I am in the middle of midterms through the end of next week, so I am not sure I will have much time to devote to making these changes immediately. |
Can you have the Application construct a first-priority section with just the shortname-aliased configurables? I think it would be helpful to have the shortname options (which are presumably the high priority ones) get their own first section, followed by everything else with their full names (the current output). It's great that we now expose every configurable, but having more options makes it significantly harder for users to actually find what they are looking for. Allowing the Application to define a first-priority section with the shortnames will help alleviate that. Is there an easy mechanism for traditional |
Yes, I was thinking the same thing that the shortnames doc info could go beforehand. In terms of the |
I strongly disagree on |
@ellisonbg see my macro branch for what the flags/config look like. |
Min, I thought the values in the macros dict were going to be Config On Wed, May 11, 2011 at 11:22 PM, minrk
Brian E. Granger |
They can be Config objects. There are two valid types:
The reason I allowed the strings is that probably the most common case is setting a single value (e.g. Bool traits). And it's cleaner to write I can remove it, so there's only one valid type if you prefer. |
OK, thanks for clarifying this. I guess I like to "one way of doing something" idea, but I don't feel too strongly about this. |
I made the decision I was thinking it was Config or nothing - and adding |
OK, I think that is fine. On Thu, May 12, 2011 at 12:48 PM, minrk
Brian E. Granger |
I added a short summary explanation for each section, and removed the string alias, so the macros are strictly config objects or the corresponding dicts. The current output of the appconfig example help:
Should I do a PR against your Config5 branch? What's preventing us merging this code into master now? I already have ipcontroller and ipengine working with the new config system in a local branch. ipcontroller especially can be cleaner after merging #423. The resulting application scripts are so much cleaner now, thanks for the great work! |
Great work! Yes, let's do a PR against config5. Once that is done, On Tue, May 17, 2011 at 9:41 AM, minrk
Brian E. Granger |
PR issued. I should be available pretty much any time (except for the next ~60 minutes because I will be in transit). |
OK, I will ping @fperez about an IRC session, but I know he has a lot On Tue, May 17, 2011 at 10:02 AM, minrk
Brian E. Granger |
The first stage of updating our configuration system. I have added a new command line option parser that integrates with our config system. To see how all of this works, look at docs/examples/core/appconfig.py and run it like this:
Options can be set using the syntax:
This branch should be reviewed and merged into trunk and then we all can start to work on updating IPython's main apps to use this new API.