code: def update_args_with_paths(
      paths: List[str],
      keywords: Optional[Tuple[str]],
      args: List[str],
  ) -> List[str]:
      """Appends valid paths and flags to the args `list` passed to `pytest.main`.
  
      The are three different types of "path" that a user may pass to the `paths`
      positional arguments, all of which need to be handled slightly differently:
  
      1. Nothing is passed
          The paths to the `testpaths` defined in `pytest.ini` need to be appended
          to the arguments list.
      2. Full, valid paths are passed
          These paths need to be validated but can then be directly appended to
          the arguments list.
      3. Partial paths are passed.
          The `testpaths` defined in `pytest.ini` need to be recursed and any
          matches be appended to the arguments list.
  
      """
  
      def find_paths_matching_partial(partial_paths):
          partial_path_file_patterns = []
          for partial_path in partial_paths:
              if len(partial_path) >= 4:
                  has_test_prefix = partial_path[:4] == "test"
                  has_py_suffix = partial_path[-3:] == ".py"
              elif len(partial_path) >= 3:
                  has_test_prefix = False
                  has_py_suffix = partial_path[-3:] == ".py"
              else:
                  has_test_prefix = False
                  has_py_suffix = False
              if has_test_prefix and has_py_suffix:
                  partial_path_file_patterns.append(partial_path)
              elif has_test_prefix:
                  partial_path_file_patterns.append(
                      f"{partial_path}*.py"
                  )
              elif has_py_suffix:
                  partial_path_file_patterns.append(
                      f"test*{partial_path}"
                  )
              else:
                  partial_path_file_patterns.append(
                      f"test*{partial_path}*.py"
                  )
          matches = []
          for testpath in valid_testpaths_default:
              for path, dirs, files in os.walk(testpath, topdown=True):
                  zipped = zip(
                      partial_paths, partial_path_file_patterns
                  )
                  for partial_path, partial_path_file in zipped:
                      if fnmatch(path, f"*{partial_path}*"):
                          matches.append(str(pathlib.Path(path)))
                          dirs[:] = []
                      else:
                          for file in files:
                              if fnmatch(file, partial_path_file):
                                  matches.append(
                                      str(pathlib.Path(path, file))
                                  )
          return matches
  
      def is_tests_file(filepath: str) -> bool:
          path = pathlib.Path(filepath)
          if not path.is_file():
              return False
          if not path.parts[-1].startswith("test_"):
              return False
          if not path.suffix == ".py":
              return False
          return True
  
      def find_tests_matching_keywords(keywords, filepath):
          matches = []
          with open(filepath, encoding="utf-8") as tests_file:
              source = tests_file.read()
              for line in source.splitlines():
                  if line.lstrip().startswith("def "):
                      for kw in keywords:
                          if line.lower().find(kw.lower()) != -1:
                              test_name = line.split(" ")[1].split("(")[
                                  0
                              ]
                              full_test_path = (
                                  filepath + "::" + test_name
                              )
                              matches.append(full_test_path)
          return matches
  
      valid_testpaths_default = []
      for testpath in TESTPATHS_DEFAULT:
          absolute_testpath = pathlib.Path(sympy_dir(), testpath)
          if absolute_testpath.exists():
              valid_testpaths_default.append(str(absolute_testpath))
  
      candidate_paths = []
      if paths:
          full_paths = []
          partial_paths = []
          for path in paths:
              if pathlib.Path(path).exists():
                  full_paths.append(
                      str(pathlib.Path(sympy_dir(), path))
                  )
              else:
                  partial_paths.append(path)
          matched_paths = find_paths_matching_partial(partial_paths)
          candidate_paths.extend(full_paths)
          candidate_paths.extend(matched_paths)
      else:
          candidate_paths.extend(valid_testpaths_default)
  
      if keywords is not None and keywords != ():
          matches = []
          for path in candidate_paths:
              if is_tests_file(path):
                  test_matches = find_tests_matching_keywords(
                      keywords, path
                  )
                  matches.extend(test_matches)
              else:
                  for root, dirnames, filenames in os.walk(path):
                      for filename in filenames:
                          absolute_filepath = str(
                              pathlib.Path(root, filename)
                          )
                          if is_tests_file(absolute_filepath):
                              test_matches = (
                                  find_tests_matching_keywords(
                                      keywords,
                                      absolute_filepath,
                                  )
                              )
                              matches.extend(test_matches)
          args.extend(matches)
      else:
          args.extend(candidate_paths)
  
      return args
  
imports: import functools
  import importlib.util
  import os
  import pathlib
  import re
  from fnmatch import fnmatch
  from typing import List, Optional, Tuple
  from sympy.testing.runtests import test
label_desc: Use image node_id 3 for calling a global function with example usage: update_args_with_paths(paths, keywords, args) and returns: args, matches, True, matches, False, False, False