简体   繁体   English

Py2 到 Py3:添加未来的导入

[英]Py2 to Py3: Add future imports

I need to make a old code base compatible with Python3.我需要制作一个与 Python3 兼容的旧代码库。 The code needs to support Python2.7 and Python3 for some months.代码需要支持 Python2.7 和 Python3 几个月。

I would like to add this in very file:我想在非常文件中添加这个:

# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

I tried this:我试过这个:

futurize --both-stages --unicode-literals --write --nobackups .

But this adds the unicode-literals future import only.但这仅添加了 unicode-literals 未来导入。 Not the other future imports.不是其他未来的进口。

I would like to avoid to write my own script which adds this, since adding this blindly does not work, since some files already have this header.我想避免编写自己的脚本来添加它,因为盲目地添加它是行不通的,因为某些文件已经有这个 header。

If all you need is to ensure that the Source Code Encoding Heading and the 4 import statements are present, then the following script will recursively descend through a directory modifying all.py files ensuring that these the required statements are present.如果您只需要确保源代码编码标题和 4 个导入语句存在,那么以下脚本将递归地通过修改 all.py 文件的目录下降,以确保这些所需的语句存在。 The updates will be done in place, so it could be wise to make sure that you have a backup in case of a hardware failure in the middle of rewriting one of the files.更新将就地完成,因此明智的做法是确保您有备份,以防在重写其中一个文件时出现硬件故障。 Even if the code is rewritten to write to a temporary file and then do a final "move" to replace the old with the new, the same problem remains.即使重写代码以写入临时文件,然后进行最后的“移动”以用新文件替换旧文件,同样的问题仍然存在。

You should try this out on experimentally first in a test directory, and as always, USE AT YOUR OWN RISK.您应该首先在测试目录中进行实验性尝试,并且一如既往,使用风险自负。

from pathlib import Path
import re

root_path = 'absolute_or_releative_path_to_directory'

encoding_re = re.compile(r'^# -\*- coding: utf-8 -\*-(\r|\r?\n)')
import_re = re.compile(r'\bfrom\s+__future__\s+import\s+((?:absolute_import|division|print_function|unicode_literals))\b')
all_imports = ['absolute_import', 'division', 'print_function', 'unicode_literals']
all_imports_set = set(all_imports)

for path in Path(root_path).glob('**/*.py'):
    with open(path, 'r', encoding='utf-8') as f:
        source = f.read()

    # Look for source encoding header:
    m = encoding_re.search(source)
    # Look for the 4 imports:
    found_imports = set(import_re.findall(source))
    if m and len(found_imports) == 4:
        # Found encoding line and all 4 imports,
        # so there is nothing to do:
        continue

    # Else we need to write out a replacement file:
    with open(path, 'w', encoding='utf-8') as f:
        if not m or len(found_imports) < 4:
            # Did not find encoding line or we must write out
            # at least one import. In either case we must write
            # the encoding line to ensure it is the first line:
            print('# -*- coding: utf-8 -*-', file=f)

        if not found_imports:
            # Found no imports so write out all 4:
            missing_imports = all_imports
        else:
            # Found 1 to 4 import statement; compute the missing ones:
            missing_imports = all_imports_set - found_imports
        for import_name in missing_imports:
            print(f'from __future__ import {import_name}', file=f)

        # Print remaining source:
        print(source, end='', file=f)

From the docs :文档

Only those __future__ imports deemed necessary will be added unless the --all-imports command-line option is passed to futurize , in which case they are all added.除非将--all-imports命令行选项传递给futurize ,否则只会添加那些认为必要的__future__导入,在这种情况下它们都会被添加。

If you want futurize to add all those imports unconditionally, you need to pass it the --all-imports flag.如果您希望futurize无条件地添加所有这些导入,则需要将--all-imports标志传递给它。

First define a list of the imports you want to be each file.首先定义一个您希望成为每个文件的导入列表。

You can use the glob.glob() method with the recursive keyword argument set to True so that it recursively searches for .py files within a given path.您可以使用将recursive关键字参数设置为Trueglob.glob()方法,以便递归搜索给定路径中的.py文件。

For each filename returned, after reading in its content, you can use a filter to filter out the imports that already exist in the file, and only write those that don't:对于返回的每个文件名,在读取其内容后,您可以使用过滤器过滤掉文件中已经存在的导入,并且只写入那些不存在的导入:

import glob

lines = [
    "from __future__ import absolute_import",
    "from __future__ import division",
    "from __future__ import print_function",
    "from __future__ import unicode_literals"
]

for file in glob.glob('/project/**/*.py', recursive=True): # replace project with the path
    with open(file, 'r+') as f:
        content = f.read().splitlines() # Read into a list of lines
        f.seek(0, 0) # To the top of the file
        lines2 = [line for line in lines if line not in content] # Filter out existing imports
        f.write("\n".join(lines2 + content))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM