Skip to content

Instantly share code, notes, and snippets.

@proguy914629bot
Last active December 18, 2021 18:39
Show Gist options
  • Save proguy914629bot/55c5d3d8a0c18787cdc8ae6bffcf1a2a to your computer and use it in GitHub Desktop.
Save proguy914629bot/55c5d3d8a0c18787cdc8ae6bffcf1a2a to your computer and use it in GitHub Desktop.
Black for specific line from a specific file.
# How to invoke this file would be to run something like this in your terminal:
# python3 black_selection.py /path/to/black/executable /path/to/file LineStart LineEnd
#
# Make sure to install black with the current running python version.
# To enable debug/verbose, check for BLACK-SELECTION-DEBUG environment and make sure it is set to True.
#
# To get the executable path, run the following command in your terminal:
# - Windows: where black
# - Linux/macOS: which black
import os
import sys
import random
import string
import subprocess
debug = os.environ.get('BLACK-SELECTION-DEBUG', 'False').lower() == 'true'
try:
if debug:
print('Trying to import black...')
import black
except ImportError:
raise ImportError(
"Please install black with the current running python version before running this script.") from None
try:
if debug:
print('Trying to get black executable...')
black_executable = sys.argv[0]
subprocess.call([black_executable, '--version'])
except Exception: # (IndexError, Exception)
raise IndexError("Please provide the path to the black executable.") from None
try:
if debug:
print('Trying to get file to run black on...')
input_file = sys.argv[1]
except IndexError:
raise IndexError("Please provide the path to the file to be formatted.") from None
try:
if debug:
print('Trying to get start line number to format...')
start_line = sys.argv[2]
except IndexError:
raise IndexError("Please provide the line number to start formatting from.") from None
try:
if debug:
print('Trying to get end line number to format...')
end_line = sys.argv[3]
except IndexError:
raise IndexError("Please provide the line number to end formatting at.") from None
code = []
# Read selected lines and write to tmpfile
if debug:
print('Reading input file...')
with open(input_file, 'r') as f:
lines = f.readlines()
if debug:
print('Getting selected lines to format...')
for i in range(int(start_line), int(end_line) + 1):
code.append(lines[i])
code = '\n'.join(code)
# Create our tmpfile and write our code to it
if debug:
print('Making tmpfile...')
tmpfile = ''.join(random.choices(string.ascii_letters + string.digits, k=15)) + '.py'
with open(tmpfile, 'w') as f:
f.write(code)
# Storing how many indents per line we have in our code
line_indent = []
# Un-indent the tmpfile for black to work properly
if debug:
print('Un-indenting tmpfile\'s code...')
with open(tmpfile, 'r+') as f:
lines = f.readlines()
for line in lines:
line_indent.append(len(line) - len(line.lstrip()))
f.write(line.lstrip())
# Apply Black formatting to tmpfile
if debug:
print('Running black on tmpfile...')
subprocess.call([black_executeable, tmpfile])
# Write back to tmpfile with correct indentation
if debug:
print('Indenting tmpfile\'s code according to black\'s code formatting suggestions...')
with open(tmpfile, 'r+') as f:
lines = f.readlines()
for i, line in enumerate(lines):
f.write(' ' * line_indent[i] + line)
# Delete original lines from file and insert newly formatted lines
if debug:
print('Writing back to input file...')
with open(input_file, 'r+') as f:
lines = f.readlines()
with open(tmpfile, 'r') as f2:
tmp_lines = f2.readlines()
for i in range(int(start_line), int(end_line) + 1):
lines[i] = tmp_lines[i - int(start_line)]
f.write('\n'.join(lines))
# Finally, remove the tmp file
if debug:
print('Removing tmpfile...')
os.remove(tmpfile)
if debug:
print('Process Finished.')
# Now the black formatting has been published to the file.
# Make sure to report to https://gist.github.com/proguy914629bot/55c5d3d8a0c18787cdc8ae6bffcf1a2a for issues that you faced.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment