def __init__(self, topicNameTuple, providers): if providers: msg = ("No topic specification for topic '%s' " % stringize(topicNameTuple) + "found from registered providers (%s)." % providers) else: msg = "No topic specification for topic '%s'." % stringize(topicNameTuple) RuntimeError.__init__(self, msg + " See pub.newTopic(), pub.addTopicDefnProvider(), and/or pubsubconf.setTopicUnspecifiedFatal()")
def validateNameHierarchy(topicTuple): '''Check that names in topicTuple are valid: no spaces, not empty. Raise ValueError if fails check. E.g. ('',) and ('a',' ') would both fail, but ('a','b') would be ok. ''' if not topicTuple: topicName = stringize(topicTuple) errMsg = 'empty topic name' raise TopicNameInvalid(topicName, errMsg) for indx, topic in enumerate(topicTuple): errMsg = None if topic is None: topicName = list(topicTuple) topicName[indx] = 'None' errMsg = 'None at level #%s' elif not topic: topicName = stringize(topicTuple) errMsg = 'empty element at level #%s' elif topic.isspace(): topicName = stringize(topicTuple) errMsg = 'blank element at level #%s' if errMsg: raise TopicNameInvalid(topicName, errMsg % indx)
def getTopic(self, name, okIfNone=False): '''Get the Topic instance that corresponds to the given topic name path. By default, raises an UndefinedTopic or UndefinedSubtopic exception if a topic with given name doesn't exist. If okIfNone=True, returns None instead of raising an exception.''' topicNameDotted = stringize(name) #if not name: # raise TopicNameInvalid(name, 'Empty topic name not allowed') obj = self._topicsMap.get(topicNameDotted, None) if obj is not None: return obj if okIfNone: return None # NOT FOUND! Determine what problem is and raise accordingly: # find the closest parent up chain that does exists: parentObj, subtopicNames = self.__getClosestParent(topicNameDotted) assert subtopicNames subtopicName = subtopicNames[0] if parentObj is self.__allTopics: raise UndefinedTopic(subtopicName) raise UndefinedSubtopic(parentObj.getName(), subtopicName)
def __init__(self, getArgsSpec, topicNameTuple, parent, argsDocs, reqdArgs, argsSpec): argsDocs = argsDocs or {} reqdArgs = tuple(reqdArgs or ()) # check that all args marked as required are in argsDocs missingArgs = set(reqdArgs).difference(argsDocs.keys()) if missingArgs: msg = 'The argsDocs dict doesn\'t contain keys (%s) given in reqdArgs' raise InvalidArgsSpec(msg, missingArgs) self.allOptional = None # list of topic message optional argument names self.allRequired = None # list of topic message required argument names self.subArgsDocs = None # documentation for each subtopic arg (dict) self.subArgsReqd = None # which keys in subArgsDocs repr. required args (tuple) self.argsSpec = self.SPEC_NONE topicName = stringize(topicNameTuple) if argsSpec == self.SPEC_NONE: # other self.all* members will be updated when our sub args get set assert not argsDocs assert not reqdArgs assert self.argsSpec == self.SPEC_NONE subArgsDocs, subArgsReqd = getArgsSpec(topicNameTuple) if subArgsDocs is not None: self.__setSubArgs(subArgsDocs, subArgsReqd, parent, topicName) elif argsSpec == self.SPEC_SUBONLY: self.__setSubArgs(argsDocs.copy(), reqdArgs, parent, topicName) else: assert argsSpec == self.SPEC_ALL self.__setAllArgs(getArgsSpec, topicNameTuple, parent, argsDocs.copy(), reqdArgs)
def __init__(self, topicNameTuple): msg = "No topic specification for topic '%s'." \ % stringize(topicNameTuple) RuntimeError.__init__( self, msg + " See pub.getOrCreateTopic(), pub.addTopicDefnProvider(), and/or pub.setTopicUnspecifiedFatal()" )
def __createParentTopics(self, topicName): '''This will find which parents need to be created such that topicName can be created (but doesn't create given topic), and creates them. Returns the parent object.''' assert self.getTopic(topicName, okIfNone=True) is None parentObj, subtopicNames = self.__getClosestParent( stringize(topicName)) # will create subtopics of parentObj one by one from subtopicNames if parentObj is self.__allTopics: nextTopicNameList = [] else: nextTopicNameList = list(parentObj.getNameTuple()) for name in subtopicNames[:-1]: nextTopicNameList.append(name) desc, specGiven = self.__defnProvider.getDefn( tuple(nextTopicNameList)) if desc is None: desc = 'UNDOCUMENTED: created as parent without specification' parentObj = self.__createTopic(tuple(nextTopicNameList), desc, specGiven=specGiven, parent=parentObj) return parentObj
def __validateArgsToParent(self): # validate relative to parent arg spec closestParentAI = self.parentAI().getCompleteAI() if closestParentAI is not None: # verify that parent args is a subset of spec given: topicName = stringize(self.topicNameTuple) verifySubset(self.getArgs(), closestParentAI.getArgs(), topicName) verifySubset(self.allRequired, closestParentAI.getReqdArgs(), topicName, " required args")
def __setAllArgs(self, getArgsSpec, topicNameTuple, parent, argsDocs, reqdArgs): self.argsSpec = self.SPEC_NONE subArgsDocs, subArgsReqd = getArgsSpec(topicNameTuple) topicName = stringize(topicNameTuple) if subArgsDocs is None: # no user spec available, create spec from args given: allOptional = set( argsDocs.keys() ).difference( reqdArgs ) self.allOptional = tuple(allOptional) self.allRequired = reqdArgs self.argsSpec = self.SPEC_COMPLETE if parent is None: self.subArgsDocs = argsDocs.copy() self.subArgsReqd = reqdArgs self.argsSpec = self.SPEC_COMPLETE_FINAL elif parent.argsSpecComplete(): # verify that parent args is a subset of spec given: parentReqd, parentOpt, dummySpec = parent.getArgs() verifySubset(argsDocs.keys(), parentReqd+parentOpt, topicName) verifySubset(reqdArgs, parentReqd, topicName, 'list of required args for ') # ok, good to go: subArgsOpt = allOptional.difference(parentOpt) subArgsReqd = set(reqdArgs).difference(parentReqd) self.subArgsReqd = tuple(subArgsReqd) subArgs = tuple(subArgsOpt)+self.subArgsReqd self.subArgsDocs = dict( (k,argsDocs[k]) for k in subArgs ) else: # user spec available, takes precedence if parent is None: if set(argsDocs) != set(subArgsDocs): raise ValueError("bad listener due to args") if set(reqdArgs) != set(subArgsReqd): raise ValueError("bad listener due to reqd args") elif parent.argsSpecComplete(): # then arg spec given must be equal to parent spec + user def parentReqd, parentOpt, dummySpec = parent.getArgs() if set(argsDocs) != set(subArgsDocs).union(parentReqd+parentOpt): raise ValueError("bad listener due to args") allReqd = set(subArgsReqd).union(parentReqd) if set(reqdArgs) != allReqd: print 'all, sub', allReqd, reqdArgs raise ValueError("bad listener due to reqd args") self.__setSubArgs(subArgsDocs, subArgsReqd, parent, topicName) if self.argsSpec == self.SPEC_SUBONLY: # then parent spec incomplete assert (parent is not None) and not parent.argsSpecComplete() allOptional = set( argsDocs.keys() ).difference( reqdArgs ) verifySubset(allOptional, subArgsDocs.keys(), topicName) verifySubset(reqdArgs, subArgsReqd, topicName, 'list of required args for ') self.allOptional = tuple(allOptional) self.allRequired = reqdArgs self.argsSpec = self.SPEC_COMPLETE
def __validateArgsToParent(self): # validate relative to parent arg spec closestParentAI = self.parentAI().getCompleteAI() if closestParentAI is not None: # verify that parent args is a subset of spec given: topicName = stringize(self.topicNameTuple) verifySubset(self.getArgs(), closestParentAI.getArgs(), topicName) verifySubset(self.allRequired, closestParentAI.getReqdArgs(), topicName, ' required args')
def __createParentTopics(self, topicName): assert self.getTopicOrNone(topicName) is None parentObj, subtopicNames = self.__getClosestParent(stringize(topicName)) # will create subtopics of parentObj one by one from subtopicNames if parentObj is self._rootTopic: nextTopicNameList = [] else: nextTopicNameList = list(parentObj.getNameTuple()) desc = 'Defined from listener of subtopic "%s"' % stringize(topicName) for name in subtopicNames[:-1]: nextTopicNameList.append(name) parentObj = self.__createTopic( tuple(nextTopicNameList), desc = desc, parent = parentObj, argsSpec = ARGS_SPEC_NONE) return parentObj
def newTopic(self, _name, _desc, _required=(), _argsSpec=ARGS_SPEC_SUBONLY, **args): '''Create a new topic of given _name, with description desc explaining the topic (for documentation purposes). The **args defines the data that can be given as part of messages of this topic: the keys define what arguments names must be present for listeners of this topic, whereas the values describe each argument (for documentation purposes). Returns True only if a new topic was created, False if it already existed identically (same description, same args -- in which case the operation is a no-op). Otherwise raises ValueError. ''' # check _name topicTuple = tupleize(_name) # create only if doesn't exist: nameDotted = stringize(_name) #print 'Checking for "%s"' % nameDotted if self._topicsMap.has_key(nameDotted): msg = 'Topic "%s" already exists' % nameDotted raise TopicAlreadyDefined(msg) # get parent in which to create topic path = topicTuple[:-1] if path: pathDotted = stringize(path) parent = self._topicsMap.get(pathDotted, None) if parent is None: msg = 'Parent topic "%s" does not exist, cannot create' raise UndefinedTopic(pathDotted) else: parent = self._rootTopic # ok to create! newTopicObj = self.__createTopic( topicTuple, desc=_desc, parent=parent, argsSpec=_argsSpec, argsDocs=args, reqdArgs=_required) return newTopicObj
def _newTopicFromTemplate_(self, topicName, desc, usingCallable=None): '''Return a new topic object created from protocol of callable referenced by usingCallable. Creates missing parents.''' assert not self._topicsMap.has_key( stringize(topicName) ) topicNameTuple = tupleize(topicName) parentObj = self.__createParentTopics(topicName) # now the final topic object, args from listener if provided allArgsDocs, required, argsSpec = None, None, ARGS_SPEC_NONE if usingCallable is not None: allArgsDocs, required = topicArgsFromCallable(usingCallable) argsSpec=ARGS_SPEC_ALL # if user description exists, use it rather than desc: desc = self.__defnProvider.getDescription(topicNameTuple) or desc return self.__createTopic( topicNameTuple, desc, parent=parentObj, argsSpec=argsSpec, argsDocs=allArgsDocs, reqdArgs=required)
def delTopic(self, name): '''Undefines the named topic. Returns True if the subtopic was removed, false otherwise (ie the topic doesn't exist). Also unsubscribes any listeners of topic. Note that it must undefine all subtopics to all depths, and unsubscribe their listeners. ''' # find from which parent the topic object should be removed dottedName = stringize(name) try: obj = weakref( self._topicsMap[dottedName] ) except KeyError: return False assert obj().getName() == dottedName # notification must be before deletion in case if self.__notifyOnDelTopic: Policies._notificationHandler.notifyDelTopic(dottedName) obj()._undefineSelf_(self._topicsMap) assert obj() is None return True
def getTopic(self, name): '''Get the Topic instance that corresponds to the given topic name path. Raises an UndefinedTopic or UndefinedSubtopic error if the path cannot be resolved. ''' if not name: raise TopicNameInvalid(name, 'Empty topic name not allowed') topicNameDotted = stringize(name) obj = self._topicsMap.get(topicNameDotted, None) if obj is not None: return obj # NOT FOUND! Determine what problem is and raise accordingly: # find the closest parent up chain that does exists: parentObj, subtopicNames = self.__getClosestParent(topicNameDotted) assert subtopicNames subtopicName = subtopicNames[0] if parentObj is self._rootTopic: raise UndefinedTopic(subtopicName) raise UndefinedSubtopic(parentObj.getName(), subtopicName)
def __createParentTopics(self, topicName): '''This will find which parents need to be created such that topicName can be created (but doesn't create given topic), and creates them. Returns the parent object.''' assert self.getTopic(topicName, okIfNone=True) is None parentObj, subtopicNames = self.__getClosestParent(stringize(topicName)) # will create subtopics of parentObj one by one from subtopicNames if parentObj is self.__allTopics: nextTopicNameList = [] else: nextTopicNameList = list(parentObj.getNameTuple()) for name in subtopicNames[:-1]: nextTopicNameList.append(name) desc, specGiven = self.__defnProvider.getDefn( tuple(nextTopicNameList) ) if desc is None: desc = 'UNDOCUMENTED: created as parent without specification' parentObj = self.__createTopic( tuple(nextTopicNameList), desc, specGiven = specGiven, parent = parentObj) return parentObj
def delTopic(self, name): '''Undefines the named topic. Returns True if the subtopic was removed, false otherwise (ie the topic doesn't exist). Also unsubscribes any listeners of topic. Note that it must undefine all subtopics to all depths, and unsubscribe their listeners. ''' # find from which parent the topic object should be removed dottedName = stringize(name) try: #obj = weakref( self._topicsMap[dottedName] ) obj = self._topicsMap[dottedName] except KeyError: return False #assert obj().getName() == dottedName assert obj.getName() == dottedName # notification must be before deletion in case self.__treeConfig.notificationMgr.notifyDelTopic(dottedName) #obj()._undefineSelf_(self._topicsMap) obj._undefineSelf_(self._topicsMap) #assert obj() is None return True
def __init__(self, topicNameTuple): msg = "No topic specification for topic '%s'." \ % stringize(topicNameTuple) RuntimeError.__init__(self, msg + " See pub.getOrCreateTopic(), pub.addTopicDefnProvider(), and/or pub.setTopicUnspecifiedFatal()")
def getTopicOrNone(self, name): '''Get the named topic, or None if doesn't exist''' name = stringize(name) obj = self._topicsMap.get(name, None) return obj
def getName(self): '''Return dotted form of full topic name''' return stringize(self.__tupleName)