3131import io
3232import signal
3333import sys
34+ from typing import Tuple
3435
3536import autoflake
3637import autopep8
@@ -76,16 +77,43 @@ def format_code(source, aggressive=False, apply_config=False, filename='',
7677 return formatted_source
7778
7879
80+ def detect_io_encoding (input_file : io .BytesIO , limit_byte_check = - 1 ):
81+ """Return file encoding."""
82+ try :
83+ from lib2to3 .pgen2 import tokenize as lib2to3_tokenize
84+ encoding : str = lib2to3_tokenize .detect_encoding (input_file .readline )[
85+ 0 ]
86+
87+ input_file .read (limit_byte_check ).decode (encoding )
88+
89+ return encoding
90+ except (LookupError , SyntaxError , UnicodeDecodeError ):
91+ return 'latin-1'
92+
93+
94+ def read_file (filename : str ) -> Tuple [str , str ]:
95+ """Read file from filesystem or from stdin when `-` is given."""
96+
97+ if is_stdin (filename ):
98+ data = sys .stdin .buffer .read ()
99+ else :
100+ with open (filename , 'rb' ) as fp :
101+ data = fp .read ()
102+ input_file = io .BytesIO (data )
103+ encoding = detect_io_encoding (input_file )
104+ return data .decode (encoding ), encoding
105+
106+
107+ def is_stdin (filename : str ):
108+ return filename == '-'
109+
110+
79111def format_file (filename , args , standard_out ):
80112 """Run format_code() on a file.
81113
82114 Return True if the new formatting differs from the original.
83-
84115 """
85- encoding = autopep8 .detect_encoding (filename )
86- with autopep8 .open_with_encoding (filename ,
87- encoding = encoding ) as input_file :
88- source = input_file .read ()
116+ source , encoding = read_file (filename )
89117
90118 if not source :
91119 return False
@@ -98,6 +126,12 @@ def format_file(filename, args, standard_out):
98126 remove_all_unused_imports = args .remove_all_unused_imports ,
99127 remove_unused_variables = args .remove_unused_variables )
100128
129+ # Always write to stdout (even when no changes were made) when working with
130+ # in-place stdin. This is what most tools (editors) expect.
131+ if args .in_place and is_stdin (filename ):
132+ standard_out .write (formatted_source )
133+ return True
134+
101135 if source != formatted_source :
102136 if args .in_place :
103137 with autopep8 .open_with_encoding (filename , mode = 'w' ,
@@ -142,7 +176,6 @@ def format_multiple_files(filenames, args, standard_out, standard_error):
142176 """Format files and return booleans (any_changes, any_errors).
143177
144178 Optionally format files recursively.
145-
146179 """
147180 filenames = autopep8 .find_files (list (filenames ),
148181 args .recursive ,
@@ -211,7 +244,6 @@ def _main(argv, standard_out, standard_error):
211244 """Internal main entry point.
212245
213246 Return exit status. 0 means no error.
214-
215247 """
216248 args = parse_args (argv )
217249
0 commit comments