code: def main():
      # for Windows, so that we aren't randomly printing garbage (or just failing to print)
      try:
          sys.stdout.reconfigure(encoding="utf-8")
      except AttributeError:
          # TODO: deprecate 3.6 support after the next release
          pass
  
      # The default semgrex detects sentences in the UD_English-Pronouns dataset which have both nsubj and csubj on the same word.
      # The default ssurgeon transforms the unwanted csubj to advcl
      # See https://github.com/UniversalDependencies/docs/issues/923
      parser = argparse.ArgumentParser()
      parser.add_argument(
          "--input_file",
          type=str,
          default=None,
          help="Input file to process (otherwise will process a sample text)",
      )
      parser.add_argument(
          "--output_file",
          type=str,
          default=None,
          help="Output file (otherwise will write to stdout)",
      )
      parser.add_argument(
          "--input_dir",
          type=str,
          default=None,
          help="Input dir to process instead of a single file.  Allows for reusing the Java program",
      )
      parser.add_argument(
          "--input_filter",
          type=str,
          default=".*[.]conllu",
          help="Only process files from the input_dir that match this filter - regex, not shell filter.  Default: %(default)s",
      )
      parser.add_argument(
          "--no_input_filter",
          action="store_const",
          const=None,
          help="Remove the default input filename filter",
      )
      parser.add_argument(
          "--output_dir",
          type=str,
          default=None,
          help="Output dir for writing files, necessary if using --input_dir",
      )
      parser.add_argument(
          "--edit_file",
          type=str,
          default=None,
          help="File to get semgrex and ssurgeon rules from",
      )
      parser.add_argument(
          "--semgrex",
          type=str,
          default="{}=source >nsubj {} >csubj=bad {}",
          help="Semgrex to apply to the text.  A default detects words which have both an nsubj and a csubj.  Default: %(default)s",
      )
      parser.add_argument(
          "ssurgeon",
          type=str,
          default=["relabelNamedEdge -edge bad -reln advcl"],
          nargs="*",
          help="Ssurgeon edits to apply based on the Semgrex.  Can have multiple edits in a row.  A default exists to transform csubj into advcl.  Default: %(default)s",
      )
      parser.add_argument(
          "--print_input",
          dest="print_input",
          action="store_true",
          default=False,
          help="Print the input alongside the output - gets kind of noisy.  Default: %(default)s",
      )
      parser.add_argument(
          "--no_print_input",
          dest="print_input",
          action="store_false",
          help="Don't print the input alongside the output - gets kind of noisy",
      )
      args = parser.parse_args()
  
      if args.edit_file:
          ssurgeon_edits = read_ssurgeon_edits(args.edit_file)
      else:
          ssurgeon_edits = [SsurgeonEdit(args.semgrex, args.ssurgeon)]
  
      if args.input_file:
          docs = [CoNLL.conll2doc(input_file=args.input_file)]
          outputs = [args.output_file]
          input_output = zip(docs, outputs)
      elif args.input_dir:
          if not args.output_dir:
              raise ValueError(
                  "Cannot process multiple files without knowing where to send them - please set --output_dir in order to use --input_dir"
              )
          if not os.path.exists(args.output_dir):
              os.makedirs(args.output_dir)
  
          def read_docs():
              for doc_filename in os.listdir(args.input_dir):
                  if args.input_filter:
                      if not re.match(args.input_filter, doc_filename):
                          continue
                  doc_path = os.path.join(args.input_dir, doc_filename)
                  output_path = os.path.join(
                      args.output_dir, doc_filename
                  )
                  print("Processing %s to %s" % (doc_path, output_path))
                  yield CoNLL.conll2doc(
                      input_file=doc_path
                  ), output_path
  
          input_output = read_docs()
      else:
          docs = [CoNLL.conll2doc(input_str=SAMPLE_DOC)]
          outputs = [None]
          input_output = zip(docs, outputs)
  
      for doc, output in input_output:
          if args.print_input:
              print("{:C}".format(doc))
          ssurgeon_request = build_request(doc, ssurgeon_edits)
          ssurgeon_response = send_ssurgeon_request(ssurgeon_request)
          updated_doc = convert_response_to_doc(doc, ssurgeon_response)
          if output is not None:
              with open(output, "w", encoding="utf-8") as fout:
                  fout.write("{:C}\n\n".format(updated_doc))
          else:
              print("{:C}\n".format(updated_doc))
  
imports: import argparse
  import copy
  import os
  import re
  import sys
  from stanza.models.common.utils import misc_to_space_after, space_after_to_misc
  from stanza.protobuf import SsurgeonRequest, SsurgeonResponse
  from stanza.server import java_protobuf_requests
  from stanza.utils.conll import CoNLL
  from stanza.models.common.doc import ID, TEXT, LEMMA, UPOS, XPOS, FEATS, HEAD, DEPREL, DEPS, MISC, START_CHAR, END_CHAR, NER, Word, Token, Sentence
label_desc: Use image node_id 10 for calling a global function with example usage: main() without return types