source: find_problematic_code.py

Last change on this file was 2007:c49235b09a67, checked in by Stefan Schwarzer <sschwarzer@…>, 11 months ago
Run Black on `find_problematic_code.py`
  • Property exe set to *
File size: 3.8 KB
Line 
1#! /usr/bin/env python3
2# Copyright (C) 2008-2020, Stefan Schwarzer <sschwarzer@sschwarzer.net>
3# and ftputil contributors (see `doc/contributors.txt`)
4# See the file LICENSE for licensing terms.
5
6# pylint: disable=redefined-builtin
7
8"""\
9This script scans a directory tree for files which contain code which
10may cause problems in ftputil %s and above. The script uses simple
11heuristics, so it may miss occurrences of problematic usage or print
12some harmless lines of your files.
13
14Usage: %s start_dir
15
16where 'start_dir' is the starting directory which will be scanned
17recursively for potentially problematic code.
18"""
19
20import os
21import re
22import sys
23
24import ftputil.version
25
26
27__doc__ = __doc__ % (ftputil.version.__version__, os.path.basename(sys.argv[0]))
28
29
30class InvalidFeature:
31    """
32    Store message, regex and locations of a single now invalid
33    feature.
34    """
35
36    # pylint: disable=too-few-public-methods
37    def __init__(self, message, regex):
38        self.message = message
39        if not isinstance(regex, re.compile("").__class__):
40            regex = re.compile(regex)
41        self.regex = regex
42        # Map file name to a list of line numbers (starting at 1).
43        self.locations = {}
44
45
46HOST_REGEX = r"\b(h|host|ftp|ftphost|ftp_host)\b"
47
48invalid_features = [
49    InvalidFeature(
50        "Definition of time shift has changed in ftputil 4.0.0",
51        r"\.(time_shift\(\)|set_time_shift\()",
52    ),
53    InvalidFeature(
54        "Behavior of `FTPHost.makedirs` has changed in ftputil 4.0.0", r"\.makedirs\("
55    ),
56]
57
58
59def scan_file(file_name):
60    """
61    Scan a file with name `file_name` for code deprecated in
62    ftputil usage and collect the offending data in the dictionary
63    `features.locations`.
64    """
65    with open(file_name) as fobj:
66        for index, line in enumerate(fobj, start=1):
67            for feature in invalid_features:
68                if feature.regex.search(line):
69                    locations = feature.locations
70                    locations.setdefault(file_name, [])
71                    locations[file_name].append((index, line.rstrip()))
72
73
74def print_results():
75    """
76    Print statistics of deprecated code after the directory has been
77    scanned.
78    """
79    last_message = ""
80    for feature in invalid_features:
81        if feature.message != last_message:
82            print()
83            print(70 * "-")
84            print(feature.message, "...")
85            print()
86            last_message = feature.message
87        locations = feature.locations
88        if not locations:
89            print("   no problematic code found")
90            continue
91        for file_name in sorted(locations.keys()):
92            print(file_name)
93            for line_number, line in locations[file_name]:
94                print("%5d: %s" % (line_number, line))
95    print()
96    print("===========================================")
97    print("Please check your code also by other means!")
98    print("===========================================")
99
100
101def main(start_dir):
102    """
103    Scan a directory tree starting at `start_dir` and print uses
104    of deprecated features, if any were found.
105    """
106    # Deliberately shadow global `start_dir`.
107    # pylint: disable=redefined-outer-name
108    for dir_path, _dirnames, file_names in os.walk(start_dir):
109        for file_name in file_names:
110            abs_name = os.path.abspath(os.path.join(dir_path, file_name))
111            if file_name.endswith(".py"):
112                scan_file(abs_name)
113    print_results()
114
115
116if __name__ == "__main__":
117    if len(sys.argv) == 2:
118        if sys.argv[1] in ("-h", "--help"):
119            print(__doc__)
120            sys.exit(0)
121        start_dir = sys.argv[1]
122        if not os.path.isdir(start_dir):
123            print("Directory %s not found." % start_dir, file=sys.stderr)
124            sys.exit()
125    else:
126        print("Usage: %s start_dir" % sys.argv[0], file=sys.stderr)
127        sys.exit()
128    main(start_dir)
Note: See TracBrowser for help on using the repository browser.