code: def update_mwts_and_special_cases(
      original_tree, dep_sentence, mwt_map, tsurgeon_processor
  ):
      """
      Replace MWT structures with their UD equivalents, along with some other minor tsurgeon based edits
  
      original_tree: the tree as read from VIT
      dep_sentence: the UD dependency dataset version of this sentence
      """
      updated_tree = original_tree
  
      operations = []
  
      # first, remove titles or testo from the start of a sentence
      con_words = updated_tree.leaf_labels()
      if con_words[0] == "Tit'":
          operations.append(["/^Tit'$/=prune !, __", "prune prune"])
      elif con_words[0] == "TESTO":
          operations.append(["/^TESTO$/=prune !, __", "prune prune"])
      elif con_words[0] == "testo":
          operations.append(
              ["/^testo$/ !, __ . /^:$/=prune", "prune prune"]
          )
          operations.append(["/^testo$/=prune !, __", "prune prune"])
  
      if (
          len(con_words) >= 2
          and con_words[-2] == "..."
          and con_words[-1] == "."
      ):
          # the most recent VIT constituency has some sentence final . after a ...
          # the UD dataset has a more typical ... ending instead
          # these lines used to say "riempire" which was rather odd
          operations.append(
              ["/^[.][.][.]$/ . /^[.]$/=prune", "prune prune"]
          )
  
      # a few constituent tags are simply errors which need to be fixed
      if original_tree.children[0].label == "p":
          # 'p' shouldn't be at root
          operations.append(["_ROOT_ < p=p", "relabel p cp"])
      # fix one specific tree if it has an s_top in it
      operations.append(
          [
              "s_top=stop < (in=in < più=piu)",
              "replace piu (q più)",
              "relabel in sq",
              "relabel stop sa",
          ]
      )
      # sect doesn't exist as a constituent.  replace it with sa
      operations.append(["sect=sect < num", "relabel sect sa"])
      # ppas as an internal node gets removed
      operations.append(["ppas=ppas < (__ < __)", "excise ppas ppas"])
  
      # now assemble a bunch of regex to split and otherwise manipulate
      # the MWT in the trees
      for token in dep_sentence.tokens:
          if len(token.words) == 1:
              continue
          if token.text in mwt_map:
              mwt_pieces = mwt_map[token.text]
              if len(mwt_pieces) != 2:
                  raise NotImplementedError(
                      "Expected exactly 2 pieces of mwt for %s"
                      % token.text
                  )
              # the MWT words in the UD version will have ' when needed,
              # but the corresponding ' is skipped in the con version of VIT,
              # hence the replace("'", "")
              # however, all' has the ' included, because this is a
              # constituent treebank, not a consistent treebank
              search_regex = "/^(?i:%s(?:')?)$/" % token.text.replace(
                  "'", ""
              )
              # tags which seem to be relevant:
              # avvl|ccom|php|part|partd|partda
              tregex = (
                  "__ !> __ <<<%d (%s=child > (__=parent $+ sn=sn))"
                  % (token.id[0], search_regex)
              )
              tsurgeons = [
                  "insert (art %s) >0 sn" % mwt_pieces[1],
                  "relabel child %s" % mwt_pieces[0],
              ]
              operations.append([tregex] + tsurgeons)
  
              tregex = (
                  "__ !> __ <<<%d (%s=child > (__=parent !$+ sn !$+ (art < %s)))"
                  % (token.id[0], search_regex, mwt_pieces[1])
              )
              tsurgeons = [
                  "insert (art %s) $- parent" % mwt_pieces[1],
                  "relabel child %s" % mwt_pieces[0],
              ]
              operations.append([tregex] + tsurgeons)
          elif len(token.words) == 2:
              # print("{} not in mwt_map".format(token.text))
              # apparently some trees like sent_00381 and sent_05070
              # have the clitic in a non-projective manner
              #   [vcl-essersi, vppin-sparato, compt-[clitdat-si
              #   intj-figurarsi, fs-[cosu-quando, f-[ibar-[clit-si
              # and before you ask, there are also clitics which are
              # simply not there at all, rather than always attached
              # in a non-projective manner
              tregex = (
                  "__=parent < (/^(?i:%s)$/=child . (__=np !< __ . (/^clit/=clit < %s)))"
                  % (token.text, token.words[1].text)
              )
              tsurgeon = "moveprune clit $- parent"
              operations.append([tregex, tsurgeon])
  
              # there are also some trees which don't have clitics
              # for example, trees should look like this:
              #   [ibar-[vsup-poteva, vcl-rivelarsi], compc-[clit-si, sn-[...]]]
              # however, at least one such example for rivelarsi instead
              # looks like this, with no corresponding clit
              #   [... vcl-rivelarsi], compc-[sn-[in-ancora]]
              # note that is the actual tag, not just me being pissed off
              # breaking down the tregex:
              # the child is the original MWT, not split
              # !. clit verifies that it is not split (and stops the tsurgeon once fixed)
              # !$+ checks that the parent of the MWT is the last element under parent
              # note that !. can leave the immediate parent to touch the clit
              # neighbor will be the place the new clit will be sticking out
              tregex = (
                  "__=parent < (/^(?i:%s)$/=child !. /^clit/) !$+ __ > (__=gp $+ __=neighbor)"
                  % token.text
              )
              tsurgeon = (
                  "insert (clit %s) >0 neighbor" % token.words[1].text
              )
              operations.append([tregex, tsurgeon])
  
              # secondary option: while most trees are like the above,
              # with an outer bracket around the MWT and another verb,
              # some go straight into the next phrase
              #   sent_05076
              #   sv5-[vcl-adeguandosi, compin-[sp-[part-alle, ...
              tregex = (
                  "__=parent < (/^(?i:%s)$/=child !. /^clit/) $+ __"
                  % token.text
              )
              tsurgeon = (
                  "insert (clit %s) $- parent" % token.words[1].text
              )
              operations.append([tregex, tsurgeon])
          else:
              pass
      if len(operations) > 0:
          updated_tree = tsurgeon_processor.process(
              updated_tree, *operations
          )[0]
      return updated_tree, operations
  
imports: from collections import defaultdict, deque, namedtuple
  import itertools
  import os
  import re
  import sys
  from tqdm import tqdm
  from stanza.models.constituency.tree_reader import read_trees, UnclosedTreeError, ExtraCloseTreeError
  from stanza.server import tsurgeon
  from stanza.utils.conll import CoNLL
  from stanza.utils.datasets.constituency.utils import SHARDS, write_dataset
  import stanza.utils.default_paths
label_desc: Use image node_id 9 for calling a global function with example usage: update_mwts_and_special_cases(original_tree, dep_sentence, mwt_map, tsurgeon_processor) and returns: updated_tree,  operations