nodes: 0, module; 1, function_definition; 2, function_name:revdocs2reverts; 3, parameters; 4, block; 5, identifier:rev_docs; 6, default_parameter; 7, default_parameter; 8, default_parameter; 9, default_parameter; 10, expression_statement; 11, expression_statement; 12, for_statement; 13, identifier:radius; 14, attribute; 15, identifier:use_sha1; 16, False; 17, identifier:resort; 18, False; 19, identifier:verbose; 20, False; 21, comment:"""
      Converts a sequence of page-partitioned revision documents into a sequence
      of reverts.
  
      :Params:
          rev_docs : `iterable` ( `dict` )
              a page-partitioned sequence of revision documents
          radius : `int`
              The maximum number of revisions that a revert can reference.
          use_sha1 : `bool`
              Use the sha1 field as the checksum for comparison.
          resort : `bool`
              If True, re-sort the revisions of each page.
          verbose : `bool`
              Print dots and stuff
      """; 22, assignment; 23, pattern_list; 24, identifier:page_rev_docs; 25, block; 26, identifier:defaults; 27, identifier:RADIUS; 28, identifier:page_rev_docs; 29, call; 30, identifier:page_doc; 31, identifier:rev_docs; 32, if_statement; 33, if_statement; 34, expression_statement; 35, for_statement; 36, if_statement; 37, identifier:groupby; 38, argument_list; 39, identifier:verbose; 40, block; 41, identifier:resort; 42, block; 43, assignment; 44, identifier:rev_doc; 45, identifier:rev_docs; 46, block; 47, identifier:verbose; 48, block; 49, identifier:rev_docs; 50, lambda; 51, expression_statement; 52, expression_statement; 53, if_statement; 54, expression_statement; 55, identifier:detector; 56, call; 57, if_statement; 58, if_statement; 59, expression_statement; 60, if_statement; 61, expression_statement; 62, expression_statement; 63, lambda_parameters; 64, call; 65, call; 66, call; 67, identifier:verbose; 68, block; 69, assignment; 70, identifier:Detector; 71, argument_list; 72, boolean_operator; 73, block; 74, identifier:use_sha1; 75, block; 76, elif_clause; 77, assignment; 78, identifier:revert; 79, block; 80, else_clause; 81, call; 82, call; 83, identifier:rd; 84, attribute; 85, argument_list; 86, attribute; 87, argument_list; 88, attribute; 89, argument_list; 90, expression_statement; 91, expression_statement; 92, identifier:rev_docs; 93, call; 94, keyword_argument; 95, not_operator; 96, comparison_operator:'text' not in rev_doc; 97, expression_statement; 98, continue_statement; 99, expression_statement; 100, comparison_operator:'text' in rev_doc; 101, block; 102, identifier:revert; 103, call; 104, expression_statement; 105, if_statement; 106, block; 107, attribute; 108, argument_list; 109, attribute; 110, argument_list; 111, identifier:rd; 112, identifier:get; 113, string; 114, attribute; 115, identifier:write; 116, binary_operator:page_doc.get('title') + ": "; 117, attribute; 118, identifier:flush; 119, call; 120, call; 121, identifier:sorted; 122, argument_list; 123, identifier:radius; 124, identifier:radius; 125, identifier:use_sha1; 126, string; 127, identifier:rev_doc; 128, call; 129, assignment; 130, string; 131, identifier:rev_doc; 132, expression_statement; 133, expression_statement; 134, attribute; 135, argument_list; 136, yield; 137, identifier:verbose; 138, block; 139, if_statement; 140, attribute; 141, identifier:write; 142, string:"\n"; 143, attribute; 144, identifier:flush; 145, string_content:page; 146, identifier:sys; 147, identifier:stderr; 148, call; 149, string:": "; 150, identifier:sys; 151, identifier:stderr; 152, attribute; 153, argument_list; 154, attribute; 155, argument_list; 156, identifier:rev_docs; 157, keyword_argument; 158, string_content:text; 159, attribute; 160, argument_list; 161, identifier:checksum; 162, boolean_operator; 163, string_content:text; 164, assignment; 165, assignment; 166, identifier:detector; 167, identifier:process; 168, identifier:checksum; 169, identifier:rev_doc; 170, call; 171, expression_statement; 172, expression_statement; 173, identifier:verbose; 174, block; 175, identifier:sys; 176, identifier:stderr; 177, identifier:sys; 178, identifier:stderr; 179, attribute; 180, argument_list; 181, attribute; 182, identifier:write; 183, string:"(sorting) "; 184, attribute; 185, identifier:flush; 186, identifier:key; 187, lambda; 188, identifier:logger; 189, identifier:warn; 190, call; 191, call; 192, call; 193, identifier:text_bytes; 194, call; 195, identifier:checksum; 196, call; 197, attribute; 198, argument_list; 199, call; 200, call; 201, expression_statement; 202, expression_statement; 203, identifier:page_doc; 204, identifier:get; 205, string; 206, identifier:sys; 207, identifier:stderr; 208, identifier:sys; 209, identifier:stderr; 210, lambda_parameters; 211, tuple; 212, attribute; 213, argument_list; 214, attribute; 215, argument_list; 216, identifier:DummyChecksum; 217, argument_list; 218, identifier:bytes; 219, argument_list; 220, attribute; 221, argument_list; 222, identifier:revert; 223, identifier:to_json; 224, attribute; 225, argument_list; 226, attribute; 227, argument_list; 228, call; 229, call; 230, string_content:title; 231, identifier:r; 232, call; 233, call; 234, string:"Skipping {0}: 'text' field not found in {0}"; 235, identifier:format; 236, subscript; 237, identifier:rev_doc; 238, identifier:rev_doc; 239, identifier:get; 240, string; 241, subscript; 242, string; 243, string; 244, call; 245, identifier:digest; 246, attribute; 247, identifier:write; 248, string:"r"; 249, attribute; 250, identifier:flush; 251, attribute; 252, argument_list; 253, attribute; 254, argument_list; 255, attribute; 256, argument_list; 257, attribute; 258, argument_list; 259, identifier:rev_doc; 260, string; 261, string_content:sha1; 262, identifier:rev_doc; 263, string; 264, string_content:utf8; 265, string_content:replace; 266, attribute; 267, argument_list; 268, identifier:sys; 269, identifier:stderr; 270, identifier:sys; 271, identifier:stderr; 272, attribute; 273, identifier:write; 274, string:"."; 275, attribute; 276, identifier:flush; 277, identifier:r; 278, identifier:get; 279, string; 280, identifier:r; 281, identifier:get; 282, string; 283, string_content:id; 284, string_content:text; 285, identifier:hashlib; 286, identifier:sha1; 287, identifier:text_bytes; 288, identifier:sys; 289, identifier:stderr; 290, identifier:sys; 291, identifier:stderr; 292, string_content:timestamp; 293, string_content:id
code: def revdocs2reverts(rev_docs, radius=defaults.RADIUS, use_sha1=False,
                      resort=False, verbose=False):
      """
      Converts a sequence of page-partitioned revision documents into a sequence
      of reverts.
  
      :Params:
          rev_docs : `iterable` ( `dict` )
              a page-partitioned sequence of revision documents
          radius : `int`
              The maximum number of revisions that a revert can reference.
          use_sha1 : `bool`
              Use the sha1 field as the checksum for comparison.
          resort : `bool`
              If True, re-sort the revisions of each page.
          verbose : `bool`
              Print dots and stuff
      """
  
      page_rev_docs = groupby(rev_docs, lambda rd: rd.get('page'))
  
      for page_doc, rev_docs in page_rev_docs:
          if verbose:
              sys.stderr.write(page_doc.get('title') + ": ")
              sys.stderr.flush()
  
          if resort:
              if verbose:
                  sys.stderr.write("(sorting) ")
                  sys.stderr.flush()
              rev_docs = sorted(
                  rev_docs, key=lambda r: (r.get('timestamp'), r.get('id')))
  
          detector = Detector(radius=radius)
          for rev_doc in rev_docs:
              if not use_sha1 and 'text' not in rev_doc:
                  logger.warn("Skipping {0}: 'text' field not found in {0}"
                              .format(rev_doc['id'], rev_doc))
                  continue
  
              if use_sha1:
                  checksum = rev_doc.get('sha1') or DummyChecksum()
              elif 'text' in rev_doc:
                  text_bytes = bytes(rev_doc['text'], 'utf8', 'replace')
                  checksum = hashlib.sha1(text_bytes).digest()
  
              revert = detector.process(checksum, rev_doc)
  
              if revert:
                  yield revert.to_json()
                  if verbose:
                      sys.stderr.write("r")
                      sys.stderr.flush()
              else:
                  if verbose:
                      sys.stderr.write(".")
                      sys.stderr.flush()
  
          if verbose:
              sys.stderr.write("\n")
              sys.stderr.flush()