discover_files.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. """Functions related to discovering paths."""
  2. from __future__ import annotations
  3. import logging
  4. import os.path
  5. from typing import Callable
  6. from typing import Generator
  7. from typing import Sequence
  8. from flake8 import utils
  9. LOG = logging.getLogger(__name__)
  10. def _filenames_from(
  11. arg: str,
  12. *,
  13. predicate: Callable[[str], bool],
  14. ) -> Generator[str, None, None]:
  15. """Generate filenames from an argument.
  16. :param arg:
  17. Parameter from the command-line.
  18. :param predicate:
  19. Predicate to use to filter out filenames. If the predicate
  20. returns ``True`` we will exclude the filename, otherwise we
  21. will yield it. By default, we include every filename
  22. generated.
  23. :returns:
  24. Generator of paths
  25. """
  26. if predicate(arg):
  27. return
  28. if os.path.isdir(arg):
  29. for root, sub_directories, files in os.walk(arg):
  30. # NOTE(sigmavirus24): os.walk() will skip a directory if you
  31. # remove it from the list of sub-directories.
  32. for directory in tuple(sub_directories):
  33. joined = os.path.join(root, directory)
  34. if predicate(joined):
  35. sub_directories.remove(directory)
  36. for filename in files:
  37. joined = os.path.join(root, filename)
  38. if not predicate(joined):
  39. yield joined
  40. else:
  41. yield arg
  42. def expand_paths(
  43. *,
  44. paths: Sequence[str],
  45. stdin_display_name: str,
  46. filename_patterns: Sequence[str],
  47. exclude: Sequence[str],
  48. ) -> Generator[str, None, None]:
  49. """Expand out ``paths`` from commandline to the lintable files."""
  50. if not paths:
  51. paths = ["."]
  52. def is_excluded(arg: str) -> bool:
  53. if arg == "-":
  54. # if the stdin_display_name is the default, always include it
  55. if stdin_display_name == "stdin":
  56. return False
  57. arg = stdin_display_name
  58. return utils.matches_filename(
  59. arg,
  60. patterns=exclude,
  61. log_message='"%(path)s" has %(whether)sbeen excluded',
  62. logger=LOG,
  63. )
  64. return (
  65. filename
  66. for path in paths
  67. for filename in _filenames_from(path, predicate=is_excluded)
  68. if (
  69. # always lint `-`
  70. filename == "-"
  71. # always lint explicitly passed (even if not matching filter)
  72. or path == filename
  73. # otherwise, check the file against filtered patterns
  74. or utils.fnmatch(filename, filename_patterns)
  75. )
  76. )