import asyncio
-import pickle
from asyncio.base_events import BaseEventLoop
from concurrent.futures import Executor, ProcessPoolExecutor
+from datetime import datetime
from enum import Enum, Flag
from functools import partial, wraps
import io
from multiprocessing import Manager
import os
from pathlib import Path
+import pickle
import re
-import tokenize
import signal
import sys
+import tokenize
from typing import (
Any,
Callable,
# types
FileContent = str
Encoding = str
+NewLine = str
Depth = int
NodeType = int
LeafID = int
if src.suffix == ".pyi":
mode |= FileMode.PYI
+ then = datetime.utcfromtimestamp(src.stat().st_mtime)
with open(src, "rb") as buf:
- newline, encoding, src_contents = prepare_input(buf.read())
+ src_contents, encoding, newline = decode_bytes(buf.read())
try:
dst_contents = format_file_contents(
src_contents, line_length=line_length, fast=fast, mode=mode
with open(src, "w", encoding=encoding, newline=newline) as f:
f.write(dst_contents)
elif write_back == write_back.DIFF:
- src_name = f"{src} (original)"
- dst_name = f"{src} (formatted)"
+ now = datetime.utcnow()
+ src_name = f"{src}\t{then} +0000"
+ dst_name = f"{src}\t{now} +0000"
diff_contents = diff(src_contents, dst_contents, src_name, dst_name)
if lock:
lock.acquire()
`line_length`, `fast`, `is_pyi`, and `force_py36` arguments are passed to
:func:`format_file_contents`.
"""
- newline, encoding, src = prepare_input(sys.stdin.buffer.read())
+ then = datetime.utcnow()
+ src, encoding, newline = decode_bytes(sys.stdin.buffer.read())
dst = src
try:
dst = format_file_contents(src, line_length=line_length, fast=fast, mode=mode)
return False
finally:
+ f = io.TextIOWrapper(
+ sys.stdout.buffer, encoding=encoding, newline=newline, write_through=True
+ )
if write_back == WriteBack.YES:
- f = io.TextIOWrapper(
- sys.stdout.buffer,
- encoding=encoding,
- newline=newline,
- write_through=True,
- )
f.write(dst)
- f.detach()
elif write_back == WriteBack.DIFF:
- src_name = "<stdin> (original)"
- dst_name = "<stdin> (formatted)"
- f = io.TextIOWrapper(
- sys.stdout.buffer,
- encoding=encoding,
- newline=newline,
- write_through=True,
- )
+ now = datetime.utcnow()
+ src_name = f"STDIN\t{then} +0000"
+ dst_name = f"STDOUT\t{now} +0000"
f.write(diff(src, dst, src_name, dst_name))
- f.detach()
+ f.detach()
def format_file_contents(
return dst_contents
-def prepare_input(src: bytes) -> Tuple[str, str, str]:
- """Analyze `src` and return a tuple of (newline, encoding, decoded_contents)
+def decode_bytes(src: bytes) -> Tuple[FileContent, Encoding, NewLine]:
+ """Return a tuple of (decoded_contents, encoding, newline).
- Where `newline` is either CRLF or LF, and `decoded_contents` is decoded with
- universal newlines (i.e. only LF).
+ `newline` is either CRLF or LF but `decoded_contents` is decoded with
+ universal newlines (i.e. only contains LF).
"""
srcbuf = io.BytesIO(src)
encoding, lines = tokenize.detect_encoding(srcbuf.readline)
+ if not lines:
+ return "", encoding, "\n"
+
newline = "\r\n" if b"\r\n" == lines[0][-2:] else "\n"
srcbuf.seek(0)
- return newline, encoding, io.TextIOWrapper(srcbuf, encoding).read()
+ with io.TextIOWrapper(srcbuf, encoding) as tiow:
+ return tiow.read(), encoding, newline
GRAMMARS = [
def lib2to3_parse(src_txt: str) -> Node:
"""Given a string with source, return the lib2to3 Node."""
grammar = pygram.python_grammar_no_print_statement
- if src_txt[-1] != "\n":
+ if src_txt[-1:] != "\n":
src_txt += "\n"
for grammar in GRAMMARS:
drv = driver.Driver(grammar, pytree.convert)
syms.dictsetmaker,
syms.listmaker,
syms.testlist_gexp,
+ syms.testlist_star_expr,
}
TEST_DESCENDANTS = {
syms.test,