format.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/env python
  2. import re
  3. import subprocess
  4. import sys
  5. import os
  6. import fnmatch
  7. DEBUG_PATTERN = re.compile(r'^(\s*)(if\s+DEBUG\s*>=?\s*\d+\s*:.+)$', re.MULTILINE)
  8. PLACEHOLDER = "###DEBUG_PLACEHOLDER###"
  9. # Add ignore patterns here
  10. IGNORE_PATTERNS = [
  11. '.venv/*',
  12. 'setup.py',
  13. '*helpers.py',
  14. '*node_service_pb2.py',
  15. '*node_service_pb2_grpc.py',
  16. ]
  17. def should_ignore(file_path):
  18. for pattern in IGNORE_PATTERNS:
  19. if fnmatch.fnmatch(file_path, pattern):
  20. return True
  21. return False
  22. def preserve_debug_lines(content):
  23. def replace(match):
  24. indent, line = match.groups()
  25. return f"{indent}{PLACEHOLDER}{line.strip()}"
  26. return DEBUG_PATTERN.sub(replace, content)
  27. def restore_debug_lines(content):
  28. return re.sub(f"^(\\s*){PLACEHOLDER}(.+)$", r"\1\2", content, flags=re.MULTILINE)
  29. def adjust_indentation(content):
  30. lines = content.split('\n')
  31. adjusted_lines = []
  32. for line in lines:
  33. if line.strip() and not line.startswith(PLACEHOLDER):
  34. indent = len(line) - len(line.lstrip())
  35. new_indent = ' ' * (indent // 2)
  36. adjusted_lines.append(new_indent + line.lstrip())
  37. else:
  38. adjusted_lines.append(line)
  39. return '\n'.join(adjusted_lines)
  40. def process_file(file_path, process_func):
  41. with open(file_path, 'r') as file:
  42. content = file.read()
  43. modified_content = process_func(content)
  44. if content != modified_content:
  45. with open(file_path, 'w') as file:
  46. file.write(modified_content)
  47. def run_black(target):
  48. # Convert ignore patterns to Black's --extend-exclude format
  49. exclude_patterns = '|'.join(f'({pattern.replace("*", ".*")})' for pattern in IGNORE_PATTERNS)
  50. command = ["black", "--line-length", "200", "--extend-exclude", exclude_patterns, target]
  51. subprocess.run(command, check=True)
  52. def format_files(target):
  53. if os.path.isfile(target):
  54. files = [target] if not should_ignore(target) else []
  55. elif os.path.isdir(target):
  56. files = []
  57. for root, _, filenames in os.walk(target):
  58. for filename in filenames:
  59. if filename.endswith('.py'):
  60. file_path = os.path.join(root, filename)
  61. if not should_ignore(file_path):
  62. files.append(file_path)
  63. else:
  64. print(f"Error: {target} is not a valid file or directory")
  65. return
  66. # Preserve debug lines
  67. for file in files:
  68. process_file(file, preserve_debug_lines)
  69. # Run Black
  70. run_black(target)
  71. # Adjust indentation and restore debug lines
  72. for file in files:
  73. process_file(file, adjust_indentation)
  74. process_file(file, restore_debug_lines)
  75. def main():
  76. if len(sys.argv) < 2:
  77. print("Usage: python format.py <directory_or_file>")
  78. sys.exit(1)
  79. target = sys.argv[1]
  80. format_files(target)
  81. print("Formatting completed.")
  82. if __name__ == "__main__":
  83. main()