[Twisted-Python] config interface
I've been working a whole lot on the config interface, and I don't like how things are working right now. configurable objects are organized in a tree. Every object defines these methods: #ContainableTypes should return a list of classes that #it can hold. def configContainableTypes(self): pass #Type should return the type of the current object def configType(self): pass #GetContents should return a dict of children of this object. {"name": obj} def configGetChildren(self): pass #AddItem should add a child to this object def configAddItem(self, id, item): pass #RemoveItem should remove a child from this object. def configRemoveItem(self, id): pass I'd like to change this API somewhat to allow different paramaters to add and remove item methods. Not all objects need ids to add an object, and it's not natural for some objects to represent their contents as a dict (selectors, for instance). I was thinking about a solution similar to the improper-state trick that glyph described to me, only it would just look at the arguments that a method needs rather than a constructor of a class. So, maybe there could be standardized names for paramaters of AddItem or RemoveItem so that a front-end would know what exactly to get from the user to add or remove an item. GetChildren could also just return either a list or a dict, and the front-end would handle it appropriately. This is not a developed idea at all, and I just wanna run it by anyone who cares. Standardizing names of paramaters doesn't seem very clean to me, but I can't think of much else.. -- Chris Armstrong http://twistedmatrix.com/~carmstro carmstro@dynup.net There is a 90% chance that this message was written when the author's been awake longer than he should have. Please disregard any senseless drivel.
On Sunday 08 April 2001 20:04, you wrote:
configurable objects are organized in a tree. Every object defines these methods:
#ContainableTypes should return a list of classes that #it can hold. def configContainableTypes(self): pass
This seems fine...
#Type should return the type of the current object def configType(self): pass
I don't think this is necessary though. Can't you just use the Python class?
#GetContents should return a dict of children of this object. {"name": obj} def configGetChildren(self): pass
Seems like a list of tuples (.items() style) might be more appropriate than a dict, considering that this really isn't mutable.
#AddItem should add a child to this object def configAddItem(self, id, item): pass
Also fine...
#RemoveItem should remove a child from this object. def configRemoveItem(self, id): pass
I'd like to change this API somewhat to allow different paramaters to add and remove item methods. Not all objects need ids to add an object, and it's not natural for some objects to represent their contents as a dict (selectors, for instance). I was thinking about a solution similar to the improper-state trick that glyph described to me, only it would just look at the arguments that a method needs rather than a constructor of a class.
That trick is a necessary addition to the API in any case -- these functions aren't enough. However, you might want to have ConfigurableDictionary, ConfigurableItem, and ConfigurableSequence types which have different ideas about how things get added to them. In order for new configurable things to be instantiatable, you'll need API additions like: def configGetRequiredInitArgs(self) This returns a 2-tuple of a sequence and a hash. The first sequence is a list of types/classes of the required arguments, in order, and the second is a hash of name:type/class of optional argument. These arguments get filled in by your configuration interface code, and passed to: def configCheckInitArgs(self, args, kw) This to separate preconditions of the init from the init itself -- if this indicates there's something wrong with the arguments (for example, an integer is outside of its acceptable range) then this message can be displayed to the user for them to try again. def configDoInit(self, args, kw) This will most likely be a passthru to self.__init__, probably frequently enough to make that the default implementation, but since configGetRequiredInitArgs may want to do some pre-initialization, things could be different. Note that if something returned by configGetRequiredInitArgs is a class, that class be configurable as well -- that, and your interface may need to be somewhat recursive in order to allow you to pass configurable elements to the initializers of other configurable elements... I'd recommend trying to get something work only supporting basic types at first. Also, what are you planning on doing for configuring an object's attributes? It seems like that should behave differently from configuring the objects it contains. -- ______ __ __ _____ _ _ | ____ | \_/ |_____] |_____| |_____| |_____ | | | | @ t w i s t e d m a t r i x . c o m http://twistedmatrix.com/users/glyph
On Wed, Apr 11, 2001 at 06:31:32AM -0500, Glyph Lefkowitz wrote:
#Type should return the type of the current object def configType(self): pass
I don't think this is necessary though. Can't you just use the Python class?
You're right. I was switching to classes for the type system, anyway.
#GetContents should return a dict of children of this object. {"name": obj} def configGetChildren(self): pass
Seems like a list of tuples (.items() style) might be more appropriate than a dict, considering that this really isn't mutable.
Ok, makes sense.
I'd like to change this API somewhat to allow different paramaters to add and remove item methods. Not all objects need ids to add an object, and it's not natural for some objects to represent their contents as a dict (selectors, for instance). I was thinking about a solution similar to the improper-state trick that glyph described to me, only it would just look at the arguments that a method needs rather than a constructor of a class.
That trick is a necessary addition to the API in any case -- these functions aren't enough. However, you might want to have ConfigurableDictionary, ConfigurableItem, and ConfigurableSequence types which have different ideas about how things get added to them.
I don't understand what those methods should do. Could you explain a bit more? The main thing I was confused about was what exact paramaters might configAddItem and configRemoveItem need. Not all containers will have an 'id' for each of their children, but I suppose they could be somehow generated. For instance, for Selector, I was starting to implement the ids for each server as 'str(serverObj)', but this didn't seem very nice to me. I guess now that I think of it again, it doesn't seem all that bad. I might need to add id(Obj) onto that, though, in some cases. The following you described to me on IRC, but I appreciate you organizing it for my benefit. :)
In order for new configurable things to be instantiatable, you'll need API additions like:
def configGetRequiredInitArgs(self)
This returns a 2-tuple of a sequence and a hash. The first sequence is a ... Note that if something returned by configGetRequiredInitArgs is a class, that class be configurable as well -- that, and your interface may need to be somewhat recursive in order to allow you to pass configurable elements to the initializers of other configurable elements... I'd recommend trying to get something work only supporting basic types at first.
That sounds pretty neat. Recursion is such fun. :)
Also, what are you planning on doing for configuring an object's attributes? It seems like that should behave differently from configuring the objects it contains.
I already have that implemented. Remember config_strings and config_callbacks? Thanks for the reply -- Chris Armstrong carmstro@twistedmatrix.com http://twistedmatrix.com/~carmstro carmstro@dynup.net
On Wednesday 11 April 2001 10:42, you wrote:
That trick is a necessary addition to the API in any case -- these functions aren't enough. However, you might want to have ConfigurableDictionary, ConfigurableItem, and ConfigurableSequence types which have different ideas about how things get added to them.
I don't understand what those methods should do. Could you explain a bit more?
class Configurable class ConfigurableDict(UserDict.UserDict, Configurable) class ConfigurableSequence(UserList.UserList, Configurable) Rather than adding a whole new interface (configAddItem etc) why not just use the built-in list/dictionary interfaces for the two kinds of collection you have?
The main thing I was confused about was what exact paramaters might configAddItem and configRemoveItem need. Not all containers will have an 'id' for each of their children, but I suppose they could be somehow generated. For instance, for Selector, I was starting to implement the ids for each server as 'str(serverObj)', but this didn't seem very nice to me. I guess now that I think of it again, it doesn't seem all that bad. I might need to add id(Obj) onto that, though, in some cases.
I don't really understand why this is relevant; why would you need IDs for servers? Aren't they just added in some order (a list)?
Also, what are you planning on doing for configuring an object's attributes? It seems like that should behave differently from configuring the objects it contains.
I already have that implemented. Remember config_strings and config_callbacks?
I'm still not 100% comfortable with that implementation, but I suppose it can be refactored later. -- ______ __ __ _____ _ _ | ____ | \_/ |_____] |_____| |_____| |_____ | | | | @ t w i s t e d m a t r i x . c o m http://twistedmatrix.com/users/glyph
On Wed, Apr 11, 2001 at 11:31:12AM -0500, Glyph Lefkowitz wrote:
I don't understand what those methods should do. Could you explain a bit more?
class Configurable class ConfigurableDict(UserDict.UserDict, Configurable) class ConfigurableSequence(UserList.UserList, Configurable)
Rather than adding a whole new interface (configAddItem etc) why not just use the built-in list/dictionary interfaces for the two kinds of collection you have?
Ok, I get you know. Good idea. :)
The main thing I was confused about was what exact paramaters might configAddItem and configRemoveItem need. Not all containers will have an 'id' for each of their children, but I suppose they could be somehow generated. For instance, for Selector, I was starting to implement the ids for each server as 'str(serverObj)', but this didn't seem very nice to me. I guess now that I think of it again, it doesn't seem all that bad. I might need to add id(Obj) onto that, though, in some cases.
I don't really understand why this is relevant; why would you need IDs for servers? Aren't they just added in some order (a list)?
Exactly, servers really don't have IDs. But other things do. That's why I was confused in the first place. But it is useful to have them for the UI. str(serverObj) may not be that user friendly, but it has to be unique. Also the ID is needed for deleting things from the selector. Now that I think of it, with your dict and list overriding ideas, I don't think IDs would even be needed. Or maybe they would. I'll work on it. :)
I already have that implemented. Remember config_strings and config_callbacks?
I'm still not 100% comfortable with that implementation, but I suppose it can be refactored later.
Okie dokie. -- Chris Armstrong carmstro@twistedmatrix.com http://twistedmatrix.com/~carmstro carmstro@dynup.net
participants (2)
-
Chris Armstrong
-
Glyph Lefkowitz