Last active
February 1, 2021 11:40
-
-
Save vvzen/b024fc1a98ba906b48f3b5c5eb0d5bac to your computer and use it in GitHub Desktop.
Convert a python camelCase code base to snake_case
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This is currently highly experimental!! | |
Please make a backup before testing it.. | |
""" | |
from __future__ import print_function | |
import os | |
import re | |
import sys | |
import json | |
import datetime | |
FUNCTION_REGEX = re.compile(r"( |\t)*def (?P<funcname>[_A-Za-z-0-9]*)") | |
def find_all_python_files(target_dir): | |
files_list = [] | |
for root, folder, files in os.walk(target_dir): | |
for file in files: | |
if file.endswith(".py"): | |
files_list.append(os.path.join(root, file)) | |
return files_list | |
def find_words_in_function_name(value): | |
current_word = [] | |
words = [] | |
for c in value: | |
# We have reached a new word | |
if c == "_" or c.upper() == c: | |
current_word = "".join(current_word) | |
if current_word: | |
words.append(current_word) | |
if c != "_": | |
current_word = [c] | |
else: | |
current_word = [] | |
else: | |
if c and c != "_": | |
current_word.append(c) | |
current_word = "".join(current_word) | |
words.append(current_word) | |
return words | |
def get_all_functions(file_path, functions_map): | |
if not os.access(file_path, os.R_OK): | |
sys.stderr.write("Cannot read file %s\n" % file_path) | |
return | |
with open(file_path, "r") as f: | |
file_content = f.readlines() | |
for line in file_content: | |
matches = FUNCTION_REGEX.match(line.lstrip()) | |
if not matches: | |
continue | |
function_name = matches.groupdict("funcname")["funcname"] | |
all_lower = function_name.lower() | |
if function_name == all_lower: | |
continue | |
words = find_words_in_function_name(function_name) | |
function_name = "%s(" % function_name | |
functions_map[function_name] = ("_".join(words)).lower() + "(" | |
def replace_functions_in_file(file_path, functions_map, dry_run=True): | |
current_file_content = [] | |
# Search... | |
with open(file_path, "r") as f: | |
file_content = f.readlines() | |
fix_all_header = False | |
for line in file_content: | |
for old_name, new_name in functions_map.iteritems(): | |
# Deal with the top level __all__ "mask" that is used to | |
# only make some functions public | |
if "__all__" in line: | |
fix_all_header = True | |
# end of the __all__ (which can be potentially multiline) | |
if "]" in line and fix_all_header: | |
fix_all_header = False | |
if fix_all_header: | |
old_name_without_parenthesis = old_name.replace("(", "") | |
new_name_without_parenthesis = new_name.replace("(", "") | |
if old_name_without_parenthesis in line: | |
func_regex_pattern = r"\b%s\b" % old_name_without_parenthesis | |
for item in re.findall(func_regex_pattern, line): | |
line = line.replace( | |
item, | |
new_name_without_parenthesis | |
) | |
# Body of module.. nothing to worry about in theory | |
elif old_name in line: | |
line = line.replace(old_name, new_name) | |
current_file_content.append(line) | |
# ...and replace | |
if not dry_run: | |
with open(file_path, "w") as f: | |
f.write("".join(current_file_content)) | |
def generate_report(functions_map): | |
timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%s") | |
report_file_name = "camelCase_to_snakeCase_%s.json" % timestamp | |
report_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), report_file_name) | |
with open(report_file_path, "w") as f: | |
json.dump(functions_map, f, indent=4) | |
def main(): | |
functions_map = {} | |
dry_run = False | |
# target_file = "/Users/vvzen/Documents/code/pipeline/framestore/commsfcurve/commsfcurve/math/easing/filters.py" | |
# get_all_functions(target_file, functions_map) | |
# replace_functions_in_file(target_file, functions_map, dry_run=dry_run) | |
# target_file = "/Users/vvzen/Documents/code/pipeline/framestore/commsfcurve/commsfcurve/FCurve.py" | |
# get_all_functions(target_file, functions_map) | |
# replace_functions_in_file(target_file, functions_map, dry_run=dry_run) | |
target_dir = "/Users/vvzen/Documents/code/pipeline/framestore/commsfcurve" | |
python_files = find_all_python_files(target_dir) | |
# 1. Build a list of all the functions | |
for f in python_files: | |
get_all_functions(f, functions_map) | |
# 2. Convert to snake_case | |
for f in python_files: | |
replace_functions_in_file(f, functions_map, dry_run=dry_run) | |
generate_report(functions_map) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment