code: def python_linter(src, fix=False):
      """Run Python linters on python/pyarrow, python/examples, setup.py
      and dev/."""
      setup_py = os.path.join(src.python, "setup.py")
      setup_cfg = os.path.join(src.python, "setup.cfg")
  
      logger.info("Running Python formatter (autopep8)")
  
      autopep8 = Autopep8()
      if not autopep8.available:
          logger.error(
              "Python formatter requested but autopep8 binary not found. "
              f"{_archery_install_msg}"
          )
          return
  
      # Gather files for autopep8
      patterns = [
          "python/pyarrow/**/*.py",
          "python/pyarrow/**/*.pyx",
          "python/pyarrow/**/*.pxd",
          "python/pyarrow/**/*.pxi",
          "python/examples/**/*.py",
          "dev/*.py",
          "dev/archery/**/*.py",
          "dev/release/**/*.py",
      ]
      files = [setup_py]
      for pattern in patterns:
          files += list(map(str, Path(src.path).glob(pattern)))
  
      args = ["--global-config", setup_cfg, "--ignore-local-config"]
      if fix:
          args += ["-j0", "--in-place"]
          args += sorted(files)
          yield LintResult.from_cmd(autopep8(*args))
      else:
          # XXX `-j0` doesn't work well with `--exit-code`, so instead
          # we capture the diff and check whether it's empty
          # (https://github.com/hhatto/autopep8/issues/543)
          args += ["-j0", "--diff"]
          args += sorted(files)
          diff = autopep8.run_captured(*args)
          if diff:
              print(diff.decode("utf8"))
              yield LintResult(success=False)
          else:
              yield LintResult(success=True)
  
      # Run flake8 after autopep8 (the latter may have modified some files)
      logger.info("Running Python linter (flake8)")
  
      flake8 = Flake8()
      if not flake8.available:
          logger.error(
              "Python linter requested but flake8 binary not found. "
              f"{_archery_install_msg}"
          )
          return
  
      flake8_exclude = [".venv*", "vendored"]
  
      yield LintResult.from_cmd(
          flake8(
              "--extend-exclude=" + ",".join(flake8_exclude),
              "--config=" + os.path.join(src.python, "setup.cfg"),
              setup_py,
              src.pyarrow,
              os.path.join(src.python, "examples"),
              src.dev,
              check=False,
          )
      )
  
      logger.info("Running Cython linter (cython-lint)")
  
      cython_lint = CythonLint()
      if not cython_lint.available:
          logger.error(
              "Cython linter requested but cython-lint binary not found. "
              f"{_archery_install_msg}"
          )
          return
  
      # Gather files for cython-lint
      patterns = [
          "python/pyarrow/**/*.pyx",
          "python/pyarrow/**/*.pxd",
          "python/pyarrow/**/*.pxi",
          "python/examples/**/*.pyx",
          "python/examples/**/*.pxd",
          "python/examples/**/*.pxi",
      ]
      files = []
      for pattern in patterns:
          files += list(map(str, Path(src.path).glob(pattern)))
      args = ["--no-pycodestyle"]
      args += sorted(files)
      yield LintResult.from_cmd(cython_lint(*args))
  
imports: import fnmatch
  import gzip
  import os
  from pathlib import Path
  import click
  from .command import Bash, Command, default_bin
  from ..compat import _get_module
  from .cmake import CMake
  from .git import git
  from .logger import logger
  from ..lang.cpp import CppCMakeDefinition, CppConfiguration
  from ..lang.python import Autopep8, Flake8, CythonLint, NumpyDoc, PythonCommand
  from .rat import Rat, exclusion_from_globs
  from .tmpdir import tmpdir
label_desc: Use image node_id 3 for calling a global function with example usage: python_linter(src, fix) without return types