手把手教你將一個(gè)舊的大型項(xiàng)目遷移到Python3

一年半前,我們就決定使用 Python 3 了。我們已經(jīng)討論了很長(zhǎng)時(shí)間,現(xiàn)在是時(shí)候使用了!現(xiàn)在這個(gè)過(guò)程已經(jīng)結(jié)束了,我們已經(jīng)把生產(chǎn)環(huán)境的最后部署都遷移到了 Python 3

創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都做網(wǎng)站、成都網(wǎng)站建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、岳陽(yáng)網(wǎng)絡(luò)推廣、重慶小程序開(kāi)發(fā)、岳陽(yáng)網(wǎng)絡(luò)營(yíng)銷、岳陽(yáng)企業(yè)策劃、岳陽(yáng)品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供岳陽(yáng)建站搭建服務(wù),24小時(shí)服務(wù)熱線:028-86922220,官方網(wǎng)址:muchs.cn

  • 整個(gè)代碼庫(kù)大約有 240 k 行,不包括空行和注解。

  • 這是一個(gè)基于 Web 的批處理任務(wù)系統(tǒng)。并且只有一個(gè)生產(chǎn),部署環(huán)境。

  • 代碼庫(kù)大約有 15 年的歷史了。

  • 雖然這是一個(gè) Django 應(yīng)用程序,但部分代碼是先于 Django 公布之前寫(xiě)的。

關(guān)于修改 Python 3 的一些基本統(tǒng)計(jì)數(shù)據(jù),是基于對(duì) git 提交歷史的粗略過(guò)濾產(chǎn)生的:

  • 275 次提交

  • 4080 次添加代碼行

  • 3432 次刪除代碼行

我發(fā)現(xiàn)有 109 個(gè) jira 問(wèn)題與這個(gè)項(xiàng)目相關(guān)。

Py2 → six → py3

我們的理念一直是 py2 ?py2/py3 ? py3 因?yàn)槲覀儗?shí)在無(wú)法在實(shí)際生產(chǎn)中實(shí)現(xiàn)巨變,這種直覺(jué)也以令人驚訝的方式被證明是正確的。這意味著 2 到 3 是不可能的,我認(rèn)為這很常見(jiàn)。我們嘗試過(guò)使用 2 to 3 來(lái)檢測(cè) Python 3 的兼容性問(wèn)題,但很快這也被發(fā)現(xiàn)無(wú)法成立?;旧希@樣的更改意味著在 Python 2 中的代碼將被破壞。這樣的改變不可行。

結(jié)論是使用 six, 這是一個(gè)庫(kù),可以方便的構(gòu)建一個(gè)在 Python 2 和 3 中都有效的代碼庫(kù)。

首當(dāng)其沖的就是更新之前的依賴關(guān)系。這項(xiàng)工作需要立刻啟動(dòng),因?yàn)橹髸?huì)有更多的內(nèi)容要更新。

現(xiàn)代化

Python-modernize 是我們選擇進(jìn)行遷移的工具。它是一個(gè)可以自動(dòng)將 Py 2 代碼庫(kù)轉(zhuǎn)換為可兼容 six 代碼庫(kù)的工具。我們首先引入一個(gè)測(cè)試,作為 CI 的一部分,來(lái)檢查基于 modernize 的新代碼是否已經(jīng)準(zhǔn)備好兼容 py3 了。這樣做最大的效果的是讓那些仍使用 Py 2 語(yǔ)法的人意識(shí)到新的處理方法,但這顯然對(duì)將現(xiàn)有的 240 k 行代碼轉(zhuǎn)化到 six 作用不大。我們都有使用舊語(yǔ)法的壞習(xí)慣,這可以說(shuō)是教學(xué)上的成功了,即使它對(duì)代碼行的計(jì)數(shù)沒(méi)有什么不同,它也被我們用于實(shí)驗(yàn)分支:

實(shí)驗(yàn)分支

我新建了一個(gè)名為“Python 3 ”的分支,并做了以下操作:

  • 在整個(gè)代碼庫(kù)上運(yùn)行“python-modernize -n -w” 。它會(huì)在合適的地方修改代碼。我經(jīng)常做完這步后沒(méi)有進(jìn)行第一次提交就開(kāi)始修復(fù)代碼。這個(gè)錯(cuò)誤步驟總是讓我后悔,不止一次地迫使我重新開(kāi)始做整件事情。即使這個(gè)階段出錯(cuò),最好還是先把它提交。因此將機(jī)器和人要做的事情分開(kāi)顯得尤為重要。

  • 將所有用于函數(shù)體的依賴項(xiàng)導(dǎo)入到我們還沒(méi)有修復(fù)的 py3。

這里的想法是“run ahead”,即看看如果我們沒(méi)有使用過(guò)時(shí)的依賴項(xiàng),我們會(huì)遇到什么問(wèn)題。這個(gè)分支允許我在超級(jí)中斷狀態(tài)下可以非??焖俚貑?dòng)應(yīng)用程序,至少可以運(yùn)行一些單元測(cè)試。 這個(gè)分支有很大的不同,但我還是找到了把它應(yīng)用在適當(dāng)場(chǎng)景的方法。我使用優(yōu)秀的 GitUp 來(lái)拆分、組合和提交。當(dāng)一個(gè)提交看起來(lái)不錯(cuò)的時(shí)候,我會(huì)把它挑選到一個(gè)新的分支,然后發(fā)給代碼審查。

沒(méi)有人可以在這個(gè)分支上工作,因?yàn)樗徊粩嗟?rebase ,強(qiáng)制推送,濫用,但是它確實(shí)讓項(xiàng)目向前推進(jìn)了,而不用等待所有的依賴項(xiàng)被更新。我強(qiáng)烈推薦使用這種方法!

靜態(tài)分析

我們添加了預(yù)提交鉤子,所以如果您編輯了一個(gè)文件,就會(huì)收到建議將 Python 3 全部進(jìn)行 modernize 更新的提示。

quote_plus 的手動(dòng)靜態(tài)分析: 在處理 quote_plus 和 six 上有一些細(xì)微差別。最后,我們創(chuàng)建了自己的包裝器,默認(rèn)代碼強(qiáng)制執(zhí)行使用這個(gè)包裝器,而不是使用標(biāo)準(zhǔn)庫(kù)中的包裝器,也不使用 six 中包裝器。我們還靜態(tài)檢查了您從未給 quote_plus 發(fā)送過(guò)的字節(jié)。

我們修復(fù)了每個(gè) diango 應(yīng)用程序中所有的 python 3 問(wèn)題,并在 CI 環(huán)境中使用一個(gè)白名單強(qiáng)制執(zhí)行了這一點(diǎn),所以您無(wú)法破壞一個(gè)曾經(jīng)修復(fù)過(guò)的應(yīng)用程序。

依賴

對(duì)于我們來(lái)說(shuō),解決依賴是最困難的部分。我們有很多依賴,所以花了很多時(shí)間,其中有兩個(gè)依賴關(guān)系比較棘手:

  • splunk-lib. 我們依賴于 splunk,但是直到今天,他們?nèi)匀缓雎运幸鬄榭蛻舳嗽黾?py3 兼容性的憤怒的客戶。我們團(tuán)隊(duì)中的一個(gè)人 最后自己親自動(dòng)手來(lái)解決這個(gè)問(wèn)題。Splunk 處理得真的很糟糕,它甚至把這個(gè)評(píng)論區(qū)的這個(gè)問(wèn)題鎖上了!這簡(jiǎn)直讓人無(wú)法接受。

  • Cassandra. 我們的整個(gè)產(chǎn)品都在使用這個(gè)數(shù)據(jù)庫(kù),但是我們使用了一個(gè)有以前 API 模塊的舊的驅(qū)動(dòng)程序。對(duì)于我們來(lái)說(shuō),py3 的遷移過(guò)程中,這占據(jù)了很大的一部分,因此我們必須逐段重寫(xiě)所有的這些代碼。

測(cè)試

我們的代碼測(cè)試覆蓋率大約有 65% 包括:?jiǎn)卧⒓? 以及 UI 合并。 我們確實(shí)編寫(xiě)了更多的測(cè)試,但總體數(shù)量并沒(méi)有發(fā)生太大的變化??紤]將覆蓋率從 65% 提高到 66% ,意味著編寫(xiě)將近2000 行代碼的測(cè)試,這一點(diǎn)也不奇怪。

我們必須跳過(guò)需要 Cassandra 的測(cè)試,同時(shí)修復(fù)這個(gè)依賴項(xiàng)。 我發(fā)明了一個(gè)有趣的小 hack 來(lái)使它發(fā)揮作用, 并寫(xiě)了這方面的文章.

代碼更改

關(guān)于代碼更改的說(shuō)明,在如何將 py2 遷移到 six 的文檔中并未提及 (也許是我們錯(cuò)過(guò)了):

StringIO

我們?cè)诖a中大量使用 StringIO 。第一反應(yīng)就是使用 six。但對(duì)于 StringIO 來(lái)說(shuō),這在幾乎所有情況下 (但不是全部!)都被證明是錯(cuò)?;旧希覀儽仨毞浅W屑?xì)地考慮每一個(gè)我們使用 StringIO 的地方,并試圖弄清楚我們是否應(yīng)該用 io.StringIO, io.BytesIO 或者 six.StringIO 來(lái)替代它。這里犯錯(cuò)的表現(xiàn)通常為看起來(lái)像兼容 py3 的代碼準(zhǔn)備好了,在 py2 中可以正常運(yùn)行,卻實(shí)際上在 py3 中是失效的。

從 future 中導(dǎo)入unicode_literals

這是一件好壞參半的事情。您可以通過(guò)將它添加到許多文件中來(lái)發(fā)現(xiàn) bug,但是有時(shí)會(huì)在 py2 中引入 bug。 當(dāng)日志突然在奇怪的地方,比如在字符串前寫(xiě)"u"時(shí),它也會(huì)變得令人困擾??偟膩?lái)說(shuō),這顯然不是我所期望的效果。

str/bytes/unicode

這在很大程度上是您所期望的。我感到驚訝的是,在 py2 和 py3 中需要 str 。如果將來(lái)您使用 unicode_literals 導(dǎo)入,那么一些字符串需要從 'foo' 修改為 str('foo')。

six.moves

six.moves 的實(shí)現(xiàn)是一個(gè)非常奇怪的***行為,因此它不像它假裝的普通 Python 模塊那樣運(yùn)行。 我也不同意他們?cè)?six.moves 中不包含 mock 的選擇。我們必須使用他們的 API 來(lái)自己添加它,但這讓我們很難開(kāi)始工作,而且它要求我們將 from mock import patch 改為 from six.moves import mock 這也意味著 patch 現(xiàn)在變成了 mock.patch 。

CSV 的解析是不同的

如果你使用 csv 模塊,你需要了解 csv342。在我看來(lái),這應(yīng)該是 six 的一部分。否則就意味著你沒(méi)有意識(shí)到有問(wèn)題。不過(guò)我們?cè)谠S多地方都沒(méi)有使用 csv342,所以您這里要做的工作可能會(huì)有所不同。

發(fā)布順序

我們首先進(jìn)行測(cè)試:

  • 在 CI 中進(jìn)行單元測(cè)試

  • 在 CI 中進(jìn)行集成和UI測(cè)試(不包括 Cassandra)

  • 在 CI 中進(jìn)行 Cassandra 測(cè)試 (這要晚于之前的步驟!)

接下來(lái)就是產(chǎn)品本身了。我們建立一臺(tái)擁有能一次性切換到 py3 的能力的批處理機(jī)器,并且至關(guān)重要地是將其切換回來(lái)。當(dāng)在 py3 上發(fā)生中斷時(shí),這一點(diǎn)就顯得很重要了。這對(duì)我們來(lái)說(shuō)是很好的,因?yàn)槲覀兛梢灾匦屡抨?duì)那些中斷的任務(wù),但是我們不能中斷太多或者任何實(shí)際上是很關(guān)鍵的任務(wù)。我們使用 Sentry 來(lái)收集奔潰日志,所以很容易查看遷移到 py3 時(shí)遇到的所有問(wèn)題,而且當(dāng)我們修復(fù)了所有的問(wèn)題時(shí),我們需要再次遷移到 py3,直到我們得到一些問(wèn)題,如此反復(fù)。

我們有如下環(huán)境:

  • Devtest: 開(kāi)發(fā)人員在內(nèi)部使用,所以大多數(shù)情況下,這只是用來(lái)測(cè)試數(shù)據(jù)庫(kù)遷移。這個(gè)環(huán)境非常容易使用,所以這里不經(jīng)常出問(wèn)題。

  • IAT (內(nèi)部驗(yàn)收測(cè)試):用于驗(yàn)證更改,并在我們將更改推送到生產(chǎn)之前執(zhí)行回歸測(cè)試。

  • UAT (用戶接受度測(cè)試): 客戶可以訪問(wèn)的測(cè)試環(huán)境。用于需要準(zhǔn)備客戶系統(tǒng)的變更,或者讓客戶在上線前查看變更。這個(gè)環(huán)境在數(shù)據(jù)庫(kù)遷移前幾天才會(huì)遷移。

  • 生產(chǎn)環(huán)境

我們按照以下順序?qū)?Python 3 發(fā)布到這些環(huán)境中:

  • Devtest 環(huán)境

  • 短期 IAT 環(huán)境

  • 長(zhǎng)期 IAT 環(huán)境

  • 一臺(tái)短期的批處理生產(chǎn)機(jī)器

  • 在工作期間使用的一臺(tái)批處理生產(chǎn)機(jī)器

  • 生產(chǎn) SFTP

  • 占一半生產(chǎn)的批處理機(jī)器

  • 生產(chǎn)批次

  • 生產(chǎn) Web (在測(cè)試環(huán)境的長(zhǎng)時(shí)間手動(dòng)測(cè)試運(yùn)行之后)

  • 生產(chǎn)負(fù)載機(jī)器。這是批處理的一個(gè)特殊子集。它完成了我們產(chǎn)品中 CUP 和內(nèi)存最多的部分。

負(fù)載機(jī)器暴露了與 Python 3 不兼容的客戶數(shù)據(jù)配置,因此我們必須在 Python 2 中實(shí)現(xiàn)對(duì)這些情況的警告,并確保再次打開(kāi) Python 3 之前已經(jīng)修復(fù)了它們。這花了幾天時(shí)間,因?yàn)槲覀兠刻於紩?huì)收到客戶數(shù)據(jù),所以每次都會(huì)有一個(gè)警告,這又讓我們不得不再等一天。

生產(chǎn)中的驚喜

  • '?'.upper() 在 py2 中是 '?' 但是在 py3 中是 'SS' 。當(dāng)產(chǎn)品的最后一部分遷移到 py3 時(shí),最終導(dǎo)致了產(chǎn)品的崩潰!

  • 在 py2 中對(duì)不同類型的對(duì)象進(jìn)行比較和排序是有效的,但這隱藏了大量的 bug 。我們得到了一些令人討厭的驚喜,因?yàn)檫@種行為以一些不明顯的方式從堆棧中泄露出來(lái),特別是在一些排序列表中存在 None 的時(shí)候??偟膩?lái)說(shuō),這是一個(gè)勝利,因?yàn)槲覀儼l(fā)現(xiàn)了相當(dāng)多的 bug 。 None 在 py2 的列表中排在第一位,這可能會(huì)讓人感到驚訝(您可能會(huì)期望它被排序到接近于零的地方!), 現(xiàn)在我們只需要來(lái)處理它們。

  • '{}'.format(b'asd') 在 Python 2 中是 'asd' , 但是在 Python 3 中是 "b'asd'" 。在 Python 3 中,這里幾乎任何其他行為都會(huì)更好: 輸出為十六進(jìn)制 ( 結(jié)果明顯更不一樣 ) ,舊的行為 (之前的代碼運(yùn)行),或者拋出異常 (最好的行為!)。

  • int('1_0') 在 py 3 中結(jié)果是 10 , 但是在 py2 中無(wú)效。這甚至在切換到 py3 之前就困擾了我們。因?yàn)檫@種錯(cuò)配導(dǎo)致了另一個(gè)在我們之前使用 py3 的團(tuán)隊(duì)給我們發(fā)送了我們認(rèn)為無(wú)效而他們認(rèn)為有效的有效值。我個(gè)人認(rèn)為這個(gè)決定是錯(cuò)誤的:非常嚴(yán)格的解析是更好的默認(rèn)方式,我擔(dān)心這將在未來(lái)幾年會(huì)繼續(xù)以微妙的方式困擾我們。

結(jié)論

最后,我們覺(jué)得在這件事上我們真的別無(wú)選擇: Python 2 的維護(hù)將在某個(gè)時(shí)刻停止,我們的依賴項(xiàng)僅限于 py3,最明顯的就是 Django。但是,無(wú)論如何,我們還是想要進(jìn)行這種轉(zhuǎn)換,因?yàn)槲覀兘?jīng)常會(huì)被 bytes/Unicode 問(wèn)題困擾,并且Python 3 僅僅是修復(fù)了 Python 2 中的許多小麻煩。這次遷移過(guò)程,我們已經(jīng)在生產(chǎn)過(guò)程中發(fā)現(xiàn)了一些實(shí)際的漏洞/錯(cuò)誤配置。我們也期待在任何地方都可以使用 f-string 和有序字典。

網(wǎng)頁(yè)題目:手把手教你將一個(gè)舊的大型項(xiàng)目遷移到Python3
文章起源:http://muchs.cn/article30/ghsoso.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、App設(shè)計(jì)定制開(kāi)發(fā)、網(wǎng)站建設(shè)、搜索引擎優(yōu)化、軟件開(kāi)發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)