format.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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 = [
  51. "black",
  52. "--line-length", "200",
  53. "--extend-exclude", exclude_patterns,
  54. target
  55. ]
  56. subprocess.run(command, check=True)
  57. def format_files(target):
  58. if os.path.isfile(target):
  59. files = [target] if not should_ignore(target) else []
  60. elif os.path.isdir(target):
  61. files = []
  62. for root, _, filenames in os.walk(target):
  63. for filename in filenames:
  64. if filename.endswith('.py'):
  65. file_path = os.path.join(root, filename)
  66. if not should_ignore(file_path):
  67. files.append(file_path)
  68. else:
  69. print(f"Error: {target} is not a valid file or directory")
  70. return
  71. # Preserve debug lines
  72. for file in files:
  73. process_file(file, preserve_debug_lines)
  74. # Run Black
  75. run_black(target)
  76. # Adjust indentation and restore debug lines
  77. for file in files:
  78. process_file(file, adjust_indentation)
  79. process_file(file, restore_debug_lines)
  80. def main():
  81. if len(sys.argv) < 2:
  82. print("Usage: python format.py <directory_or_file>")
  83. sys.exit(1)
  84. target = sys.argv[1]
  85. format_files(target)
  86. print("Formatting completed.")
  87. if __name__ == "__main__":
  88. main()