3 # Copyright (c) 2017 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 """This script renames the given robot keywords in the given directory
21 ./rename_robot_keywords.py -i kws.csv -s ";" -d ~/ws/vpp/git/csit/ -vvv
23 Input file "kws.csv" is CSV file exported from e.g. MS Excel. Its structure
26 <Old keyword name><separator><New keyword name>
35 from os import walk, rename
36 from os.path import join
39 def time_interval(func):
40 """Decorator function to measure the time spent by the decorated function.
42 :param func: Decorated function.
43 :type func: Callable object.
44 :returns: Wrapper function.
45 :rtype: Callable object.
50 def wrapper(*args, **kwargs):
52 result = func(*args, **kwargs)
54 print("\nRenaming done in {:.5g} seconds\n".
60 def get_files(path, extension):
61 """Generates the list of files to process.
63 :param path: Path to files.
64 :param extension: Extension of files to process. If it is the empty string,
65 all files will be processed.
68 :returns: List of files to process.
73 for root, dirs, files in walk(path):
74 for filename in files:
76 if filename.endswith(extension):
77 file_list.append(join(root, filename))
79 file_list.append(join(root, filename))
84 def read_keywords(args):
85 """This function reads the keywords from the input file and creates:
87 - a dictionary where the key is the old name and the value is the new name,
88 these keywords will be further processed.
89 - a list of keywords which will not be processed, typically keywords with
90 argument(s) in its names.
91 - a list of duplicates - duplicated keyword names or names which are parts
92 of another keyword name, they will not be processed.
94 :param args: Parsed arguments.
95 :type args: ArgumentParser
96 :returns: keyword names - dictionary where the key is the old name and the
97 value is the new name; ignored keyword names - list of keywords which will
98 not be processed; duplicates - duplicated keyword names or names which are
99 parts of another keyword name, they will not be processed.
100 :rtype: tuple(dict, list, list)
104 ignored_kw_names = list()
107 for line in args.input:
108 old_name, new_name = line.split(args.separator)
110 ignored_kw_names.append((old_name, new_name[:-1]))
111 elif old_name in kw_names.keys():
112 duplicates.append((old_name, new_name[:-1]))
114 kw_names[old_name] = new_name[:-1]
117 for old_name, _ in duplicates:
118 new_name = kw_names.pop(old_name, None)
120 duplicates.append((old_name, new_name))
122 # Find KW names which are parts of other KW names:
123 for old_name in kw_names.keys():
125 for key in kw_names.keys():
128 if old_name in kw_names[key]:
132 duplicates.append((old_name, kw_names[old_name]))
133 kw_names.pop(old_name)
135 return kw_names, ignored_kw_names, duplicates
138 def rename_keywords(file_list, kw_names, args):
139 """Rename the keywords in specified files.
141 :param file_list: List of files to be processed.
142 :param kw_names: Dictionary where the key is the old name and the value is
144 :type file_list: list
148 kw_not_found = list()
150 for old_name, new_name in kw_names.items():
152 if args.verbosity > 0:
153 print("\nFrom: {}\n To: {}\n".format(old_name, new_name))
154 for file_name in file_list:
155 tmp_file_name = file_name + ".new"
156 with open(file_name) as file_read:
157 file_write = open(tmp_file_name, 'w')
159 for line in file_read:
160 new_line = re.sub(old_name, new_name, line)
161 file_write.write(new_line)
166 if args.verbosity > 1:
167 print(" {:3d}: {}".format(occurrences, file_name))
169 rename(tmp_file_name, file_name)
171 kw_not_found.append(old_name)
173 if args.verbosity > 0:
174 print("\nKeywords not found:")
175 for item in kw_not_found:
176 print(" {}".format(item))
180 """Parse arguments from command line.
182 :returns: Parsed arguments.
183 :rtype: ArgumentParser
186 parser = argparse.ArgumentParser(description=__doc__,
187 formatter_class=argparse.
188 RawDescriptionHelpFormatter)
189 parser.add_argument("-i", "--input",
191 type=argparse.FileType('r'),
192 help="Text file with the old keyword name and the new "
193 "keyword name separated by separator per line.")
194 parser.add_argument("-s", "--separator",
197 help="Separator which separates the old and the new "
199 parser.add_argument("-d", "--dir",
202 help="Directory with robot files where the keywords "
203 "should be recursively searched.")
204 parser.add_argument("-v", "--verbosity", action="count",
205 help="Set the output verbosity.")
206 return parser.parse_args()
215 kw_names, ignored_kw_names, duplicates = read_keywords(args)
217 file_list = get_files(args.dir, "robot")
219 if args.verbosity > 2:
220 print("\nList of files to be processed:")
221 for item in file_list:
222 print(" {}".format(item))
223 print("\n{} files to be processed.\n".format(len(file_list)))
225 print("\nList of keywords to be renamed:")
226 for item in kw_names:
227 print(" {}".format(item))
228 print("\n{} keywords to be renamed.\n".format(len(kw_names)))
230 rename_keywords(file_list, kw_names, args)
232 if args.verbosity >= 0:
233 print("\nIgnored keywords: ({})".format(len(ignored_kw_names)))
234 for old, new in ignored_kw_names:
235 print(" From: {}\n To: {}\n".format(old, new))
237 print("\nIgnored duplicates ({}):".format(len(duplicates)))
238 for old, new in duplicates:
239 print(" From: {}\n To: {}\n".format(old, new))
242 if __name__ == "__main__":