【问题标题】:For Python2 to Python3 code conversion, Which version of Python & Django best suited?对于 Python2 到 Python3 的代码转换,哪个版本的 Python 和 Django 最适合?
【发布时间】:2020-03-30 00:23:28
【问题描述】:

目前我在大公司工作,我们需要将 python2 旧的大 Django 项目转换为 python3 版本,所以我做了很多相关的研究,但仍然找不到与哪个版本的 Python 和 Django 最适合的完美答案用于转换。

目前我在旧版本中使用 Python:2.7.16 和 Django:1.9.13。

任何人都可以建议我最适合的 Python 和 Django 版本,用于上述旧版本的 python2 到 python3 转换。

【问题讨论】:

  • python3的当前版本是Python 3.8,Django的最新版本是Django 3.0。 Django's website recommends the latest version of python 3,即 3.8。您不想将 python 和 django 都加速到它们的最新版本有什么特别的原因吗?
  • 有趣的是,几天前我才意识到,我已经维护了几年的基于 Django 的网站现在实际上运行在使用 python2.7 托管的服务器上,而我一直在使用 python3.7 在本地运行它。我发现的唯一区别是当我第一次尝试在某处使用 f-strings 并且网络服务器的版本崩溃时;否则,出于测试和功能添加的目的,它在本地和远程完全按照预期(完全相同)运行。我的完全轶事结论是 Django 通常与大多数东西兼容。
  • 对于最新版本,我发现有些人不推荐,因为在最新版本中如果有任何与新更新相关的问题,那么有时很难找到解决方案,所以在当前项目中我不想要冒着这样的风险,也为了测试目的,我已经开始将我的项目转换为带有最新 django 的 python 3.7.3 最新版本,并且已经发现了 30 种问题。
  • 应该注意 - 这个问题是在我的审查审计中提出的。 “是否有任何文件或参考”显然是题外话(要求场外资源)。但是,我相信可以对问题进行编辑,以便更好地引导到下面接受的答案。

标签: python django python-3.x python-2to3


【解决方案1】:

我想我会为 Wim 的回答所倡导的策略添加一些内容 - 首先让适当版本的 Django 在 2.7 和 3.x 上工作 - 并概述一些策略 对我有用。

Python 2.7 是你的逃生舱,直到你在 3.x 上扣动扳机

  • 您的测试应该在两者上运行
  • 不要使用任何 3.x 特定功能,例如 f-strings
  • 首先是 Python 3.x,然后是不能在 2.7 上运行的后来的 Django 2.x
  • 尽早开始,不要过度分析,但要避免大爆炸式的方法
    • 首先逐个文件。
    • 从您拥有测试套件的最低级别代码开始,例如实用程序库。
    • 如果可能,请尝试逐步将您的更改合并到 2.7 生产分支中,并使您的 3.x 移植代码与产品更改保持同步。

从哪个小版本的 Django 开始?

我的标准是 Django 迁移可以相当参与(实际上需要更多的思考而不是 2=>3 的工作)。所以我会转向最新最好的 1.11,这样你就已经为你的 2.7 用户提供了一些价值。 1.11 上可能有大量 2.x 之前的兼容性填充程序并且您将收到 2.x 弃用警告。

从哪个次要版本的 Python 3.x 开始?

最好从各个角度考虑,例如您的第 3 方库的可用性、CI/devops 套件的支持以及您选择的服务器操作系统映像的可用性。例如,您始终可以安装 3.8 并尝试单独安装您的 requirements.txt。

利用 git(或您使用的任何 scm)和 virtualenv

  • 单独的requirement.txt 文件,但是...
  • 如果您有一个基于文件的 git 存储库,您可以使用 pip install -e <your directory> 将每个 venv 指向 相同的代码行。这意味着,在 2 个不同的终端中,您可以针对相同的单元测试运行 2.7 和 3.x。
  • 您甚至可以在不同的端口上并行运行 2.7 和 3.x Django 服务器,然后将 Firefox 和 Chrome 指向它们。
  • 经常提交(至少在移植分支上)并了解 git bisect

利用2to3

是的,如果你允许它,它将破坏 2.7 代码和 Django。所以...

  • 在预览模式下或针对单个文件运行它。看看它破坏了什么,也看看它做对了什么。

  • 将其限制为仅破坏 2.7 或 Django 的某些转换。 print x=> print (x)except(Exception) as e 是 2 无脑的。

这就是我的节流命令的样子:

2to3 $tgt -w -f except -f raise -f next -f funcattrs -f print
  • 逐个文件运行,直到您真正有信心为止。

使用 sedawk 而不是您的编辑器进行批量转换。

优势在于,随着您对应用程序的具体问题越来越了解,您可以构建一套可以在一个文件或多个文件上运行的更改,并在不破坏 2.7 或 Django 的情况下完成大部分工作。 您适当节流的 2to3 通行证后应用此方法。这会让您在编辑器中进行剩余清理,并让您的测试通过。

(可选)在 2.7 代码上开始运行 black

black 是一种代码格式化程序,它使用 Python 3 AST 来运行其分析。它不会尝试运行代码,但会标记阻止其进入 AST 阶段的语法错误。但是,您必须使用一些 pip install 全局魔法才能到达那里,并且您必须相信黑色的有用性。

其他人已经做到了 - 向他们学习。

收听#155 Practical steps for moving to Python 3 应该会给你一些关于工作的想法。查看它的显示链接。他们喜欢谈论 Instagram(?)的举动,该举动涉及在通用代码库和同一 git 分支上逐步调整运行 2.7 代码到 3.x 语法,直到触发日。

另见The Conservative Python 3 Porting Guide

Instagram Makes a Smooth Move to Python 3 - 新堆栈

结论

您到 Django 1.11 EOL(2020 年 4 月)的时间很短,所以如果您有 2 个以上的开发资源可以投入使用,我会考虑并行执行以下操作:

  • DEV#1:从 Django 1.11 开始(理论上 Django 1.11 可能最适合作为 Django 2.x 的起点),使用 2.7。

  • DEV#2:开始使用 Python 3.6/3.7 的非 Django 实用程序代码。由于此时代码与 2.7 兼容,因此请随时将其合并到 #1 中。

看看这两个任务是如何进行的,评估与 Django 相关的项目风险是什么以及 Python 3 的痛苦是什么样的。您已经错过了 Python 2.7 EOL,但过时的 Web 框架可能比传统的 Python 2.7 更危险,至少在几个月内是这样。所以我不会等太久就开始从 Django 1.9 迁移,你这样做的工作不会被浪费。随着您看到进展,您将开始更好地看到项目风险。

您最初的 2to3 进度会很慢,但工具和指导已经足够好,您会很快加快速度,因此在开始积累经验之前不要想太多。 Django 方面取决于您的 暴露于框架中的重大变化,这就是为什么我认为最好尽早开始。

附注(有争议/个人意见)我没有使用 six 或其他罐装 2-to-3 桥接库。

不是,因为我不信任它——它对于 3rd 方库来说非常棒——而是我不想添加复杂的永久依赖项(而且我懒得阅读它文档)。很长一段时间以来,我一直在用 3.x 兼容的语法编写 2.7 代码,所以我真的觉得没有必要使用它们。 您的里程可能会有所不同,如果看起来工作量很大,请不要走这条路

相反,我创建了一个包含此类内容的 py223.py(57 LOC,包括 cmets),其中大部分内容涉及标准库中弃用和名称更改的变通方法。 p>

try:
    basestring_ = basestring
except (NameError,) as e:
    basestring_ = str

try:
    cmp_ = cmp
except (NameError,) as e:
    # from http://portingguide.readthedocs.io/en/latest/comparisons.html
    def cmp_(x, y):
        """
        Replacement for built-in function cmp that was removed in Python 3
        """
        return (x > y) - (x < y)

然后从该 py223 导入以解决这些特定问题。稍后我将放弃导入并将那些奇怪的 isinstance(x, basestr_) 移动到 isinstance(x, str) 但我事先知道没什么好担心的。

【讨论】:

  • 好建议。请注意,Django本身已经使用six作为兼容层,所以如果你想在过渡期间在Django项目中使用它,那么这不是“添加复杂的永久依赖”。
  • @wim。我同意你的看法。六,不过要看观点。我已经注意到它带有 3rd 方库,因此在需求和整体依赖方面它不会“花费”。但是我——也许是错误地——认为它是 my 代码中间的一个大 black box/wart。如果您所做的只是测试实例字符串/unicode/basestring 之类的事情,并且如果您自己知道如何执行此操作,那么您确切知道如何在不再需要垫片时将其备份。不过,我会把它移到最后。
  • pip install -e ...-e小写)对吧?
【解决方案2】:

我的建议是首先升级到Django==1.11.26,这是支持 Python 2 和 Python 3 的最新版本的 Django。暂时使用当前版本的 Python 2.7。

仔细阅读 1.10.x 和 1.11.x 的发行说明,检查弃用情况并修复从 1.9.x 代码中停止工作的任何内容。事情会破裂。 Django 动作很快。对于大型 Django 项目,可能需要进行许多代码更改,如果您使用大量 3rd-party 插件或库,您可能不得不调整它们的版本。您的一些第 3 方依赖项可能已被完全放弃,因此您必须寻找替代品或删除这些功能。

要查找每个版本升级的发行说明,只需 google “What's new in Django”。命中将精心记录所有弃用和更改:

一旦 webapp 在 Django 1.11 上运行良好,并且所有测试都通过了(您确实有一个测试套件,对吗?),那么您可以进行 Python 3 转换,同时保留 Django版本相同。 Django 1.11 最多支持 Python 3.7,因此这将是一个很好的目标版本。期待 unicode 无处不在,因为字节和文本之间的隐式转换现在已经消失,许多 Python 2 webapps 都依赖于此。

一旦项目似乎在 Django 1.11 和 Python 3.7 上运行良好,那么您可以考虑升级到 Django 3.0,按照与以前相同的过程 - 阅读发行说明,进行必要的更改,运行测试套件,并在开发服务器中手动签出 webapp。

【讨论】:

  • 绝对是要走的路。让您的测试代码在 2.7 和 3.x 上运行。您可以使用pip install -E 让 2 个不同的 virtualenvs 指向同一个 git 存储库。一旦单元测试运行,开始测试使用 Django-on-3x 并再次保持代码在 2 和 3 中工作。通过一些仔细的编码并注意不要烧毁你的 2.7 桥 - 例如没有 f 字符串 - 切换将是很虎头蛇尾。一旦 3.x 完全稳定,就开始使用仅 3.x 的代码。优点是生产 2.7 在切换之前始终保持同步。
【解决方案3】:

我会先升级到 py3。您需要查看 stable/1.9.x 分支 (https://github.com/django/django/blob/stable/1.9.x/setup.py) 上 Django 存储库中的 setup.py,以确定支持的 py3 版本是 3.4(死)和 3.5。

一旦你使用 py3.5 和 Django 1.9,你可以一次升级一个,直到你到达你想要结束的版本。例如。 Django 1.11 支持 py3.5 和 py3.7,所以

py27/dj19 -> py35/dj19 -> py35/dj1.11 -> py37/dj1.11 ... -> py37/dj2.2

dj2.2 是第一个支持 py3.8 的版本,但如果您在通常保守的环境中工作,我可能会停留在 py37/dj2.2。

如果您有其他软件包,则需要找到可以在每个步骤中协同工作的版本组合。制定计划是关键,一次只升级一个组件通常最终会节省您的时间。

未来的库 (https://python-future.org/) 将帮助您解决许多棘手的情况,同时您需要在 py27 和 3.x 上运行代码。六也不错。我会避免滚动你自己的兼容层(为什么要重新发明轮子?)

如果可能,请在开始之前尝试将您的单元测试覆盖率提高到 75-85%,并为每个升级步骤明确设置“从”和“到”版本的自动测试。确保在升级到下一个版本之前阅读并修复来自 Django 的所有警告——Django 很少关心向后兼容性,所以我通常建议在升级路径上点击每个次要版本(或者至少确保你阅读“向后不兼容性”和每个次要版本的弃用列表)。

祝你好运(我们现在正在从 py27/dj1.7 升级 300+Kloc 代码库,所以我感受到你的痛苦 ;-)

【讨论】:

  • +1 测试覆盖率。这是一个关键指标,无论最终采取何种方法。在尝试进行普遍的代码更改时,它确实很有帮助,我说这是一个完全不是 TDD Red/Green 测试爱好者的人。找出一种方法来为您的 2.7 结果设置基准,升级变得容易得多。
【解决方案4】:

我的项目也有同样的问题,我尝试了 python 3.7.5 和 Django 版本 2.2.7。

您不应该使用 python 最新版本 3.8 或 Django 最新版本 3.0,因为对于任何类型的错误,您都可能无法获得最新版本的正确解决方案。

【讨论】:

  • 这应该是一条评论
【解决方案5】:

您应该尝试为当前版本拍摄。 Python 3.8 和 Django 3.0。Six 库将有助于进行一些约定更改。无论哪种方式,您都将不得不进行一些重构,因此您不妨使其成为最新版本。

【讨论】:

  • 你做过 Django 升级吗?这只是一厢情愿。从 2.7 / 1.9 直接转到 Python 3.8 和 Django 3.0 几乎是不可能的。即使将 Django 1.9 等次要版本升级到 1.10 也可能是一个困难的过程,需要进行许多代码更改。
  • 是的,我有,因为我有足够的时间和精力进行完整的重构并使应用程序保持最新状态。同样,应用程序大小、逻辑和时间限制对大多数人来说都是一个大问题,但他们从未提及应用程序大小或时间限制,所以我推荐了我的“最佳解决方案”或“一厢情愿”的意见;)
  • 此外,如果您还必须担心 Ansible 以及在 LTS Ubuntu 上运行的问题,您会发现 Ubuntu 18.04 甚至缺少 3.7 支持。我收听的安全播客建议让 3.8 稍微稳定一点,直到发布或 2.-1 来表示不必要的风险。
  • 对于 Python sec,listennotes.com/podcasts/talk-python-to-me/… 但我认为 beware-of-3.8-for-a-while 是较新的。 Risky Business 是一个很好且有趣的安全播客,尤其是如果您关注国际关系。为downvote道歉,但是是的,在你的情况下有效的方法可能会在不同的情况下影响其他人。对于 2 到 3 的转换,请参阅 listennotes.com/podcasts/talk-python-to-me/…
  • 我明白,我们只能通过创造性的批评让彼此变得更好。感谢您的播客推荐!
猜你喜欢
  • 1970-01-01
  • 2017-01-24
  • 2021-07-10
  • 2019-09-06
  • 1970-01-01
  • 2018-11-18
  • 2014-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多