nodes: 0, module; 1, function_definition; 2, function_name:hash_nanopub; 3, parameters; 4, type; 5, block; 6, typed_parameter; 7, identifier:str; 8, expression_statement; 9, expression_statement; 10, comment:# Type; 11, expression_statement; 12, expression_statement; 13, comment:# Citation; 14, if_statement; 15, comment:# Assertions; 16, expression_statement; 17, for_statement; 18, expression_statement; 19, expression_statement; 20, comment:# Annotations; 21, expression_statement; 22, for_statement; 23, expression_statement; 24, expression_statement; 25, expression_statement; 26, return_statement; 27, identifier:nanopub; 28, type; 29, comment:"""Create CityHash64 from nanopub for duplicate check
  
      TODO - check that this hash value is consistent between C# and Python running on
      laptop and server
  
      Build string to hash
  
      Collect flat array of (all values.strip()):
          nanopub.type.name
          nanopub.type.version
  
          One of:
              nanopub.citation.database.name
              nanopub.citation.database.id
  
              OR
  
              nanopub.citation.database.uri
  
              OR
  
              nanopub.citation.database.reference
  
          Extend with sorted list of assertions (SRO as single string with space between S, R and O)
  
          Extend with sorted list of annotations (nanopub.annotations.type + ' ' + nanopub.annotations.id)
  
      Convert array to string by joining array elements separated by a space
  
      Create CityHash64(str) and return
  
      """; 30, assignment; 31, call; 32, call; 33, call; 34, block; 35, elif_clause; 36, elif_clause; 37, assignment; 38, identifier:assertion; 39, subscript; 40, block; 41, assignment; 42, call; 43, assignment; 44, identifier:anno; 45, subscript; 46, block; 47, assignment; 48, call; 49, assignment; 50, call; 51, generic_type; 52, identifier:hash_list; 53, list; 54, attribute; 55, argument_list; 56, attribute; 57, argument_list; 58, attribute; 59, argument_list; 60, expression_statement; 61, expression_statement; 62, call; 63, block; 64, call; 65, block; 66, identifier:assertions; 67, list; 68, subscript; 69, string:"assertions"; 70, if_statement; 71, if_statement; 72, expression_statement; 73, identifier:assertions; 74, call; 75, attribute; 76, argument_list; 77, identifier:annotations; 78, list; 79, subscript; 80, string:"annotations"; 81, expression_statement; 82, identifier:annotations; 83, call; 84, attribute; 85, argument_list; 86, identifier:np_string; 87, call; 88, attribute; 89, argument_list; 90, identifier:Mapping; 91, type_parameter; 92, identifier:hash_list; 93, identifier:append; 94, call; 95, identifier:hash_list; 96, identifier:append; 97, call; 98, subscript; 99, identifier:get; 100, string:"database"; 101, False; 102, call; 103, call; 104, attribute; 105, argument_list; 106, expression_statement; 107, attribute; 108, argument_list; 109, expression_statement; 110, identifier:nanopub; 111, string:"nanopub"; 112, comparison_operator:assertion.get("relation") is None; 113, block; 114, comparison_operator:assertion.get("object") is None; 115, block; 116, call; 117, identifier:sorted; 118, argument_list; 119, identifier:hash_list; 120, identifier:extend; 121, identifier:assertions; 122, identifier:nanopub; 123, string:"nanopub"; 124, call; 125, identifier:sorted; 126, argument_list; 127, identifier:hash_list; 128, identifier:extend; 129, identifier:annotations; 130, attribute; 131, argument_list; 132, string:"{:x}"; 133, identifier:format; 134, call; 135, type; 136, type; 137, attribute; 138, argument_list; 139, attribute; 140, argument_list; 141, subscript; 142, string:"citation"; 143, attribute; 144, argument_list; 145, attribute; 146, argument_list; 147, subscript; 148, identifier:get; 149, string:"uri"; 150, False; 151, call; 152, subscript; 153, identifier:get; 154, string:"reference"; 155, False; 156, call; 157, call; 158, None; 159, expression_statement; 160, call; 161, None; 162, expression_statement; 163, attribute; 164, argument_list; 165, identifier:assertions; 166, attribute; 167, argument_list; 168, identifier:annotations; 169, string:" "; 170, identifier:join; 171, list_comprehension; 172, identifier:CityHash64; 173, argument_list; 174, identifier:str; 175, identifier:Any; 176, call; 177, identifier:strip; 178, call; 179, identifier:strip; 180, identifier:nanopub; 181, string:"nanopub"; 182, identifier:hash_list; 183, identifier:append; 184, call; 185, identifier:hash_list; 186, identifier:append; 187, call; 188, subscript; 189, string:"citation"; 190, attribute; 191, argument_list; 192, subscript; 193, string:"citation"; 194, attribute; 195, argument_list; 196, attribute; 197, argument_list; 198, assignment; 199, attribute; 200, argument_list; 201, assignment; 202, identifier:assertions; 203, identifier:append; 204, call; 205, identifier:annotations; 206, identifier:append; 207, call; 208, call; 209, for_in_clause; 210, identifier:np_string; 211, attribute; 212, argument_list; 213, attribute; 214, argument_list; 215, attribute; 216, argument_list; 217, attribute; 218, argument_list; 219, identifier:nanopub; 220, string:"nanopub"; 221, identifier:hash_list; 222, identifier:append; 223, call; 224, identifier:nanopub; 225, string:"nanopub"; 226, identifier:hash_list; 227, identifier:append; 228, call; 229, identifier:assertion; 230, identifier:get; 231, string:"relation"; 232, subscript; 233, string:""; 234, identifier:assertion; 235, identifier:get; 236, string:"object"; 237, subscript; 238, string:""; 239, attribute; 240, argument_list; 241, attribute; 242, argument_list; 243, attribute; 244, argument_list; 245, identifier:l; 246, identifier:hash_list; 247, subscript; 248, identifier:get; 249, string:"name"; 250, string:""; 251, subscript; 252, identifier:get; 253, string:"version"; 254, string:""; 255, call; 256, identifier:strip; 257, call; 258, identifier:strip; 259, attribute; 260, argument_list; 261, attribute; 262, argument_list; 263, identifier:assertion; 264, string:"relation"; 265, identifier:assertion; 266, string:"object"; 267, call; 268, identifier:strip; 269, call; 270, identifier:strip; 271, identifier:l; 272, identifier:lower; 273, subscript; 274, string:"type"; 275, subscript; 276, string:"type"; 277, attribute; 278, argument_list; 279, attribute; 280, argument_list; 281, call; 282, identifier:strip; 283, call; 284, identifier:strip; 285, attribute; 286, argument_list; 287, attribute; 288, argument_list; 289, identifier:nanopub; 290, string:"nanopub"; 291, identifier:nanopub; 292, string:"nanopub"; 293, subscript; 294, identifier:get; 295, string:"name"; 296, string:""; 297, subscript; 298, identifier:get; 299, string:"id"; 300, string:""; 301, attribute; 302, argument_list; 303, attribute; 304, argument_list; 305, string:" "; 306, identifier:join; 307, tuple; 308, string:" "; 309, identifier:join; 310, tuple; 311, subscript; 312, string:"database"; 313, subscript; 314, string:"database"; 315, subscript; 316, identifier:get; 317, string:"uri"; 318, string:""; 319, subscript; 320, identifier:get; 321, string:"reference"; 322, string:""; 323, call; 324, call; 325, call; 326, call; 327, call; 328, subscript; 329, string:"citation"; 330, subscript; 331, string:"citation"; 332, subscript; 333, string:"citation"; 334, subscript; 335, string:"citation"; 336, attribute; 337, argument_list; 338, attribute; 339, argument_list; 340, attribute; 341, argument_list; 342, attribute; 343, argument_list; 344, attribute; 345, argument_list; 346, identifier:nanopub; 347, string:"nanopub"; 348, identifier:nanopub; 349, string:"nanopub"; 350, identifier:nanopub; 351, string:"nanopub"; 352, identifier:nanopub; 353, string:"nanopub"; 354, subscript; 355, identifier:strip; 356, call; 357, identifier:strip; 358, call; 359, identifier:strip; 360, call; 361, identifier:strip; 362, call; 363, identifier:strip; 364, identifier:assertion; 365, string:"subject"; 366, attribute; 367, argument_list; 368, attribute; 369, argument_list; 370, attribute; 371, argument_list; 372, attribute; 373, argument_list; 374, identifier:assertion; 375, identifier:get; 376, string:"relation"; 377, string:""; 378, identifier:assertion; 379, identifier:get; 380, string:"object"; 381, string:""; 382, identifier:anno; 383, identifier:get; 384, string:"type"; 385, string:""; 386, identifier:anno; 387, identifier:get; 388, string:"id"; 389, string:""
code: def hash_nanopub(nanopub: Mapping[str, Any]) -> str:
      """Create CityHash64 from nanopub for duplicate check
  
      TODO - check that this hash value is consistent between C# and Python running on
      laptop and server
  
      Build string to hash
  
      Collect flat array of (all values.strip()):
          nanopub.type.name
          nanopub.type.version
  
          One of:
              nanopub.citation.database.name
              nanopub.citation.database.id
  
              OR
  
              nanopub.citation.database.uri
  
              OR
  
              nanopub.citation.database.reference
  
          Extend with sorted list of assertions (SRO as single string with space between S, R and O)
  
          Extend with sorted list of annotations (nanopub.annotations.type + ' ' + nanopub.annotations.id)
  
      Convert array to string by joining array elements separated by a space
  
      Create CityHash64(str) and return
  
      """
  
      hash_list = []
  
      # Type
      hash_list.append(nanopub["nanopub"]["type"].get("name", "").strip())
      hash_list.append(nanopub["nanopub"]["type"].get("version", "").strip())
  
      # Citation
      if nanopub["nanopub"]["citation"].get("database", False):
          hash_list.append(
              nanopub["nanopub"]["citation"]["database"].get("name", "").strip()
          )
          hash_list.append(
              nanopub["nanopub"]["citation"]["database"].get("id", "").strip()
          )
      elif nanopub["nanopub"]["citation"].get("uri", False):
          hash_list.append(nanopub["nanopub"]["citation"].get("uri", "").strip())
      elif nanopub["nanopub"]["citation"].get("reference", False):
          hash_list.append(nanopub["nanopub"]["citation"].get("reference", "").strip())
  
      # Assertions
      assertions = []
      for assertion in nanopub["nanopub"]["assertions"]:
          if assertion.get("relation") is None:
              assertion["relation"] = ""
          if assertion.get("object") is None:
              assertion["object"] = ""
          assertions.append(
              " ".join(
                  (
                      assertion["subject"].strip(),
                      assertion.get("relation", "").strip(),
                      assertion.get("object", "").strip(),
                  )
              ).strip()
          )
      assertions = sorted(assertions)
      hash_list.extend(assertions)
  
      # Annotations
      annotations = []
  
      for anno in nanopub["nanopub"]["annotations"]:
          annotations.append(
              " ".join((anno.get("type", "").strip(), anno.get("id", "").strip())).strip()
          )
  
      annotations = sorted(annotations)
      hash_list.extend(annotations)
  
      np_string = " ".join([l.lower() for l in hash_list])
  
      return "{:x}".format(CityHash64(np_string))