The modification is triggered by the unicode
fixer. This fixer will interpret the content of every string literals, and tries to re-escape the invalid Unicode sequences, and remove the u/U string prefix:
def transform(self, node, results):
...
elif node.type == token.STRING:
# 1. Replace the invalid \u sequences.
val = node.value
if not self.unicode_literals and val[0] in '\'"' and '\\' in val:
val = r'\\'.join([
v.replace('\\u', r'\\u').replace('\\U', r'\\U')
for v in val.split(r'\\')
])
# 2. Strip the leading `u` in u"...."
if val[0] in 'uU':
val = val[1:]
# 3. If the whole string is the same, return the original node.
if val == node.value:
return node # <--------------
# 4. Otherwise, create a new node.
new = node.clone()
new.value = val
return new
For some unknown reason (bug?), even if the original node is returned in step 3, lib2to3 still interpreted that as the token tree being changed, so it says "Files that need to be modified". However, the actual source code is the same, so there are "No changes to foo.py".
If step 3 returns None instead, it will truly say "No files need to be modified".
The affected files will just be rewritten with the original input. So the bug is harmless.