nodes: 0, module; 1, function_definition; 2, function_name:coercer; 3, parameters; 4, block; 5, identifier:self; 6, identifier:dataSets; 7, expression_statement; 8, comment:# Xxx - This does a slightly complex (hey, it's like 20 lines, how; 9, comment:# complex could it really be?) thing to figure out which elements are; 10, comment:# newly created, which elements were edited, and which elements no; 11, comment:# longer exist.  It might be simpler if the client kept track of this; 12, comment:# and passed a three-tuple of lists (or whatever - some separate data; 13, comment:# structures) to the server, so everything would be all figured out; 14, comment:# already.  This would require the client; 15, comment:# (Mantissa.LiveForm.RepeatableForm) to be more aware of what events; 16, comment:# the user is triggering in the browser so that it could keep state for; 17, comment:# adds/deletes/edits separately from DOM and widget objects.  This; 18, comment:# would remove the need for RepeatedLiveFormWrapper.; 19, function_definition; 20, expression_statement; 21, expression_statement; 22, expression_statement; 23, function_definition; 24, expression_statement; 25, return_statement; 26, comment:"""
          Coerce all of the repetitions and sort them into creations, edits and
          deletions.
  
          @rtype: L{ListChanges}
          @return: An object describing all of the creations, modifications, and
              deletions represented by C{dataSets}.
          """; 27, function_name:makeSetter; 28, parameters; 29, block; 30, assignment; 31, assignment; 32, assignment; 33, function_name:cbCoerced; 34, parameters; 35, block; 36, call; 37, identifier:coerceDeferred; 38, identifier:identifier; 39, identifier:values; 40, function_definition; 41, return_statement; 42, identifier:created; 43, call; 44, identifier:edited; 45, call; 46, identifier:coerceDeferred; 47, call; 48, tuple_pattern; 49, expression_statement; 50, expression_statement; 51, for_statement; 52, expression_statement; 53, for_statement; 54, expression_statement; 55, for_statement; 56, return_statement; 57, attribute; 58, argument_list; 59, function_name:setter; 60, parameters; 61, block; 62, identifier:setter; 63, attribute; 64, argument_list; 65, attribute; 66, argument_list; 67, identifier:gatherResults; 68, argument_list; 69, identifier:created; 70, identifier:edited; 71, assignment; 72, assignment; 73, tuple_pattern; 74, identifier:created; 75, block; 76, assignment; 77, tuple_pattern; 78, identifier:edited; 79, block; 80, assignment; 81, identifier:identifier; 82, binary_operator:set(self._idsToObjects) - receivedIdentifiers; 83, block; 84, call; 85, identifier:coerceDeferred; 86, identifier:addCallback; 87, identifier:cbCoerced; 88, identifier:defaultObject; 89, expression_statement; 90, expression_statement; 91, identifier:self; 92, identifier:_coerceAll; 93, call; 94, identifier:self; 95, identifier:_coerceAll; 96, call; 97, list; 98, identifier:receivedIdentifiers; 99, call; 100, identifier:createObjects; 101, list; 102, identifier:identifier; 103, identifier:dataSet; 104, expression_statement; 105, expression_statement; 106, identifier:editObjects; 107, list; 108, identifier:identifier; 109, identifier:dataSet; 110, expression_statement; 111, expression_statement; 112, if_statement; 113, identifier:deleted; 114, list; 115, call; 116, identifier:receivedIdentifiers; 117, expression_statement; 118, if_statement; 119, expression_statement; 120, identifier:ListChanges; 121, argument_list; 122, assignment; 123, assignment; 124, attribute; 125, argument_list; 126, attribute; 127, argument_list; 128, identifier:created; 129, identifier:edited; 130, identifier:set; 131, argument_list; 132, call; 133, call; 134, call; 135, assignment; 136, comparison_operator:dataSet != lastValues; 137, block; 138, identifier:set; 139, argument_list; 140, assignment; 141, comparison_operator:existing is not self._NO_OBJECT_MARKER; 142, block; 143, call; 144, identifier:createObjects; 145, identifier:editObjects; 146, identifier:deleted; 147, subscript; 148, identifier:defaultObject; 149, subscript; 150, identifier:values; 151, identifier:self; 152, identifier:_extractCreations; 153, identifier:dataSets; 154, identifier:self; 155, identifier:_extractEdits; 156, identifier:dataSets; 157, attribute; 158, argument_list; 159, attribute; 160, argument_list; 161, attribute; 162, argument_list; 163, identifier:lastValues; 164, subscript; 165, identifier:dataSet; 166, identifier:lastValues; 167, expression_statement; 168, expression_statement; 169, expression_statement; 170, attribute; 171, identifier:existing; 172, call; 173, identifier:existing; 174, attribute; 175, expression_statement; 176, attribute; 177, argument_list; 178, attribute; 179, identifier:identifier; 180, attribute; 181, identifier:identifier; 182, identifier:receivedIdentifiers; 183, identifier:add; 184, identifier:identifier; 185, identifier:createObjects; 186, identifier:append; 187, call; 188, identifier:receivedIdentifiers; 189, identifier:add; 190, identifier:identifier; 191, attribute; 192, identifier:identifier; 193, assignment; 194, call; 195, assignment; 196, identifier:self; 197, identifier:_idsToObjects; 198, attribute; 199, argument_list; 200, identifier:self; 201, identifier:_NO_OBJECT_MARKER; 202, call; 203, attribute; 204, identifier:pop; 205, identifier:identifier; 206, identifier:self; 207, identifier:_idsToObjects; 208, identifier:self; 209, identifier:_lastValues; 210, identifier:CreateObject; 211, argument_list; 212, identifier:self; 213, identifier:_lastValues; 214, identifier:modelObject; 215, call; 216, attribute; 217, argument_list; 218, subscript; 219, identifier:dataSet; 220, identifier:self; 221, identifier:_objectFromID; 222, identifier:identifier; 223, attribute; 224, argument_list; 225, identifier:self; 226, identifier:_idsToObjects; 227, identifier:dataSet; 228, call; 229, attribute; 230, argument_list; 231, identifier:editObjects; 232, identifier:append; 233, call; 234, attribute; 235, identifier:identifier; 236, identifier:deleted; 237, identifier:append; 238, identifier:existing; 239, identifier:makeSetter; 240, argument_list; 241, identifier:self; 242, identifier:_objectFromID; 243, identifier:identifier; 244, identifier:EditObject; 245, argument_list; 246, identifier:self; 247, identifier:_lastValues; 248, identifier:identifier; 249, identifier:dataSet; 250, identifier:modelObject; 251, identifier:dataSet
code: def coercer(self, dataSets):
          """
          Coerce all of the repetitions and sort them into creations, edits and
          deletions.
  
          @rtype: L{ListChanges}
          @return: An object describing all of the creations, modifications, and
              deletions represented by C{dataSets}.
          """
          # Xxx - This does a slightly complex (hey, it's like 20 lines, how
          # complex could it really be?) thing to figure out which elements are
          # newly created, which elements were edited, and which elements no
          # longer exist.  It might be simpler if the client kept track of this
          # and passed a three-tuple of lists (or whatever - some separate data
          # structures) to the server, so everything would be all figured out
          # already.  This would require the client
          # (Mantissa.LiveForm.RepeatableForm) to be more aware of what events
          # the user is triggering in the browser so that it could keep state for
          # adds/deletes/edits separately from DOM and widget objects.  This
          # would remove the need for RepeatedLiveFormWrapper.
          def makeSetter(identifier, values):
              def setter(defaultObject):
                  self._idsToObjects[identifier] = defaultObject
                  self._lastValues[identifier] = values
              return setter
  
          created = self._coerceAll(self._extractCreations(dataSets))
          edited = self._coerceAll(self._extractEdits(dataSets))
  
          coerceDeferred = gatherResults([created, edited])
          def cbCoerced((created, edited)):
              receivedIdentifiers = set()
  
              createObjects = []
              for (identifier, dataSet) in created:
                  receivedIdentifiers.add(identifier)
                  createObjects.append(
                      CreateObject(dataSet, makeSetter(identifier, dataSet)))
  
              editObjects = []
              for (identifier, dataSet) in edited:
                  receivedIdentifiers.add(identifier)
                  lastValues = self._lastValues[identifier]
                  if dataSet != lastValues:
                      modelObject = self._objectFromID(identifier)
                      editObjects.append(EditObject(modelObject, dataSet))
                      self._lastValues[identifier] = dataSet
  
              deleted = []
              for identifier in set(self._idsToObjects) - receivedIdentifiers:
                  existing = self._objectFromID(identifier)
                  if existing is not self._NO_OBJECT_MARKER:
                      deleted.append(existing)
                  self._idsToObjects.pop(identifier)
  
              return ListChanges(createObjects, editObjects, deleted)
  
          coerceDeferred.addCallback(cbCoerced)
          return coerceDeferred