def union(self, other): if other is None: return self if not isinstance(other, type(self)): raise TypeError("Cannot merge %s with %s" % (type(self), type(other))) merged_fields = [] for i, x in enumerate(self._contents): y = other[i] merged_fields.append(superposition.meld(x, y)) return type(self)(*merged_fields)
def testCreation(self): """Test that creation is reasonable.""" # Providing the same object twice will still build a superposition. s = superposition.superposition("foo", "foo") # This object is a superposition type... self.assertIsInstance(s, superposition.ISuperposition) # ...but it is not IN superposition. self.assertFalse(superposition.insuperposition(s)) # Using meld is sometimes more convenient for this. s = superposition.meld("foo", "foo") # This object is actually a string. self.assertIsInstance(s, six.string_types) # It can still be manipulated with the superposition-aware protocol, # as can any scalar. self.assertEqual(s, superposition.getstate(s))
def testCreation(self): """Test that creation is reasonable.""" # Providing the same object twice will still build a superposition. s = superposition.superposition("foo", "foo") # This object is a superposition type... self.assertIsInstance(s, superposition.ISuperposition) # ...but it is not IN superposition. self.assertFalse(superposition.insuperposition(s)) # Using meld is sometimes more convenient for this. s = superposition.meld("foo", "foo") # This object is actually a string. self.assertIsInstance(s, basestring) # It can still be manipulated with the superposition-aware protocol, # as can any scalar. self.assertEqual(s, superposition.getstate(s))
def get(self, key, complete=False): """Returns value of the key, or a superposition thereof. Out of the get_ functions, this is almost always the one you want. Getting a basic value: ====================== Use key in form of Component.attribute. For example, "Process/pid" or "User/username". Same as calling entity[key]: entity["Process/pid"] # PID of the process. What if the value is an entity: =============================== This method automatically recognizes attributes that reference other entities, looks them up and returns them. For example: entity["Process/parent"] # Returns the parent process entity. entity["Process/parent"]["Process/pid"] # PID of the parent. What if I want all the child processes (Inverse Lookup): ======================================================== You can call entity.get_referencing_entities if you want to be explicit. Alternatively, prepend the key with a '&' for inverse lookup of a N:1 assocation. For example: entity["&Process/parent"] # Returns processes of which this process is # (Child processes). entity["&Handle/process"] # Returns all handles this process has open. In most cases, this is unnecessary and aliases can be used instead. For example: entity["&Handle/process"] # Is already aliased in definitions as: entity["Process/handles"] entity["&Process/parent"] # Is already aliased in definitions as: entity["Process/children"] When does this return more than one value: ========================================== 1) When doing an inverse lookup. 2) When the value we find is a superposition. In both cases, a superposition is returned. Remember that superpositions proxy the [] operator, returning more superpositions. For example: # To return the pids of all child processes: entity["&Process/parent"]["Process/pid"] You can request more than one key in a single call: =================================================== This is identical to the behavior of [] on python dictionaries: entity["Process/pid", "Process/command"] # is the same as calling: (entity["Process/pid"], entity["Process/command"]) You can also request a multi-level path into the object: ======================================================== The path separator is '->' and is used as follows: entity["Process/handles"]["Handle/resource"] # Is the same as: entity["Process/handles->Handle/resource] This is merely syntax sugar to make specifying rendering output easier. """ # If we get called with [x, y] python will pass us the keys as a tuple # of (x, y). The following behaves identically to dict. if isinstance(key, tuple): return [self.get(_key, complete) for _key in key] # If we get called with a Component/attribute->Component/attribute # we treat -> as path separator and the whole key as path into the # object. if "->" in key: # This works recursively. key, rest = key.split("->", 1) subresult = self.get(key=key, complete=complete) if not subresult: return None return superposition.state_apply( subresult, lambda x: x.get(key=rest, complete=complete)) # The & sigil denotes reverse lookup. if key.startswith("&"): entities = self.get_referencing_entities(key[1:], complete=complete) return superposition.meld(*list(entities)) # The raw result could be None, a superposition or just a scalar. value = self.get_raw(key) if value is None: return obj.NoneObject( "Entity '%s' has no results for key '%s'." % (self, key)) # Redirection. if isinstance(value, entity_component.Alias): return self.get(value.alias, complete=complete) typedesc = self.reflect_type(key) if typedesc.type_name == "Entity": entities = self.manager.find_by_identity(value, complete=complete) return superposition.meld(*list(entities)) return value
def get(self, key, complete=False): """Returns value of the key, or a superposition thereof. Out of the get_ functions, this is almost always the one you want. Getting a basic value: ====================== Use key in form of Component.attribute. For example, "Process/pid" or "User/username". Same as calling entity[key]: entity["Process/pid"] # PID of the process. What if the value is an entity: =============================== This method automatically recognizes attributes that reference other entities, looks them up and returns them. For example: entity["Process/parent"] # Returns the parent process entity. entity["Process/parent"]["Process/pid"] # PID of the parent. What if I want all the child processes (Inverse Lookup): ======================================================== You can call entity.get_referencing_entities if you want to be explicit. Alternatively, prepend the key with a '&' for inverse lookup of a N:1 assocation. For example: entity["&Process/parent"] # Returns processes of which this process is # (Child processes). entity["&Handle/process"] # Returns all handles this process has open. In most cases, this is unnecessary and aliases can be used instead. For example: entity["&Handle/process"] # Is already aliased in definitions as: entity["Process/handles"] entity["&Process/parent"] # Is already aliased in definitions as: entity["Process/children"] When does this return more than one value: ========================================== 1) When doing an inverse lookup. 2) When the value we find is a superposition. In both cases, a superposition is returned. Remember that superpositions proxy the [] operator, returning more superpositions. For example: # To return the pids of all child processes: entity["&Process/parent"]["Process/pid"] You can request more than one key in a single call: =================================================== This is identical to the behavior of [] on python dictionaries: entity["Process/pid", "Process/command"] # is the same as calling: (entity["Process/pid"], entity["Process/command"]) You can also request a multi-level path into the object: ======================================================== The path separator is '->' and is used as follows: entity["Process/handles"]["Handle/resource"] # Is the same as: entity["Process/handles->Handle/resource] This is merely syntax sugar to make specifying rendering output easier. """ # If we get called with [x, y] python will pass us the keys as a tuple # of (x, y). The following behaves identically to dict. if isinstance(key, tuple): return [self.get(_key, complete) for _key in key] # If we get called with a Component/attribute->Component/attribute # we treat -> as path separator and the whole key as path into the # object. if "->" in key: # This works recursively. key, rest = key.split("->", 1) subresult = self.get(key=key, complete=complete) if not subresult: return None return superposition.state_apply( subresult, lambda x: x.get(key=rest, complete=complete)) # The & sigil denotes reverse lookup. if key.startswith("&"): entities = self.get_referencing_entities(key[1:], complete=complete) return superposition.meld(*list(entities)) # The raw result could be None, a superposition or just a scalar. value = self.get_raw(key) if value is None: return obj.NoneObject("Entity '%s' has no results for key '%s'." % (self, key)) # Redirection. if isinstance(value, entity_component.Alias): return self.get(value.alias, complete=complete) if isinstance(value, entity_component.Component): return CurriedComponent(self, value) typedesc = self.reflect_type(key) if typedesc.type_name == "Entity": entities = self.manager.find_by_identity(value, complete=complete) return superposition.meld(*list(entities)) return value