2017年9月27日 星期三

[lxml] 換成 python3 之後的 tostring 問題

原本在 python2 的時候,lxml 要序列化,只要呼叫 tostring,就可以交給檔案物件寫進檔案,像是這樣:

f = open('test.xml', 'w')
f.write(etree.tostring(root))

換到在 python3 的時候,就會發生:

f.write(etree.tostring(root))
TypeError: write() argument must be str, not bytes

原因是 lxml 回傳的是 python3 的新型態 bytes,其實就是以前的 str 型態。
要解決有兩個方法。
一個是 tostring 成 unicode,像這樣

f = open('test.xml', 'w')
f.write(etree.tostring(root,encoding='unicode'))

另一個方法是

f = open('test.xml', 'wb')
f.write(etree.tostring(root))

以我們有中文需求的話,我比較喜歡第一種。

2017年9月13日 星期三

[python] 用 requests 出現 InsecureRequestWarning,自己加上認證檔

在換到 requests 之後,因為他使用 urllib3,就會對 https 的網址出現以下警告:

InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings

通常找到的解決方法是關閉這個警告,如下:

import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()

在官網上提供另一個方法就是加上認證,但是,認證檔要去哪兒找?

這真的要感謝 stackoverflow 的網友以及 certifiio 網站提供可用的認證檔。

所以先到 http://certifiio.readthedocs.io/en/latest/ 下載 Raw CA Bundle,放在你知道的地方。
然後在使用 requests 的時候,verify 參數後面接那個檔案的路徑。問題解決!

[超譯] 微服務怎麼溝通?

# 微服務怎麼溝通?

我們在工作上做過一些分散式的開發與服務間的溝通。有些是透過開放 HTTP 服務。對於系統間的非同步訊息傳送,我公司使用 FubuMVC 與它的 .Net Core 取代物 "Jasper" 做為 service bus (translate "Jasper" to "MassTransit" or "NServiceBus" when you read this). 此格文是給我們團隊的架構的建議的草案,讓我們團隊為產品選擇何者做為微服務架構的一部份時有個參考。如果我同事看到這篇而有不同意的話,不用擔心。這份文件是活的,總是能討論的。

微服務通常需要傳送訊息給別人或處理別人的訊息,也許是微服務或客戶端。因此,為服務間通訊好好思考是值得的。

我們通常使用 HTTP 或 Jasper/FubuMVC service bus 做為服務間溝通。在思考如何選擇服務間溝通的工具之前,先要想想你的訊息的要求是什麼。服務間溝通約略是以下幾個分類:

1. Publish/Subscribe 非同步廣播一個訊息到所有的訂閱者,不預期一個立即的回應。它與「射後不理」的差異是隱含「保證送達」,也就是訊息會持續保留,直到它被發布出去。Jasper/FubuMVC service bus 有做到「保證送達」,它透過在 LightingQueue 的持續式 "store and forward" 機制,而且最後我們把 RabbitMQ 放進 Docker'ized hosting。

2. Request/Reply 呼叫另一個服務且期待一個回應。從 web service 查詢資料是一個例子。透過 service bus 送訊息且期待一個回應也是一個例子。query handler 就是 request/reply 的範例。

3. Fire and Forget 送出一個 request,然後不管任何回應,不在乎回應是否有來。這種模式多用在效能優先且訊息不是很要緊的情況。Jasper/FubuMVC 使用在 node 內通訊,用以協調訂閱與健康檢查,這是透過 LightningQueue 在 "fire and forget" 的模式來做。

## 以下情況使用 HTTP Service:
* 你的服務要開放 API 給外部使用者。
* 你的服務要給網頁瀏覽器使用。
* 你要開放查詢端點( query endpoint) 給其他服務,它們需要拿到資料馬上使用的方式。
* 你不需要「保證送達」。
* 你在前期不清楚未來你的服務的客戶端會是什麼其他的機制。目前 HTTP 普通存在於所有平台。
* 你需要開放你的服務給「非.Net」客戶端。用現存其他平台的 service bus 是完全可能的,但在這個情況,用 HTTP 端點會比較少阻力。

## 以下情況使用 Service Bus:
* 你需要耐用的 publish/subscribe 的模式。如果你的服務不需要等待下家系統的回應,你需要的可能是 publish/subscribe。
* 如果你會同一個訊息給不同的訂閱者。
* 如果你需要支援「動態訂閱」。也就是讓其他服務可以到你的服務註冊,然後從你的服務接收訊息。
* 如果你要「射後不理」的訊息方式,使用 service bus 在 LightningQueue 的 non-persistent mode。(參考 ZeroMQ)
* 你也許需要 Jasper/FubuMVC 裡的 "delayed message" 的好處。
* 你需要實作長命服務,例如 saga workflow
* 雖然可利用限縮 HTTP request 來控制,但透過 servcie bus 後面的 message queue 來處理大量負載會更簡單有效。
* 如果 message 處理順序很重要,你需要在 servcie bus 排隊。

## 灰色地帶
比較 HTTP 與 service bus 不是完全黑與白的選擇。service bus 也支援 request/reply 模式,你也可以用 HTTP 來做射而不理。兩個招數可以與我們現存的技術堆疊水平擴展。Jasper 最終會支援 HTTP 傳輸以及更有效率的 request/reply,這讓情況更混亂。如果你感覺不是很清楚哪個方向才對,那你的團隊所熟悉的方法會是較可接受的選擇。很可能,這意謂著,使用常見的 ASP.NET Core 堆疊給 HTTP Service 使用,而不是我們今天定做的 service bus 技術。

## 避免以下整合的方式
因為外部客戶端的關係,我們會必須使用下列的方式。但是非常強烈建議不要這麼做:
* publish 檔案到檔案系統及監控目錄
* publish 檔案到 FTP server
* 使用共享資料庫。關聯式資料庫的排隊機制不是很有效率,而且我們也不想要服務之間藉著共享資料庫而有太硬的耦合。
不同意嗎?還有什麼要加的?不用客氣,請幫我讓這個列表更圓滿,可以在下方留言。
原文連結:https://jeremydmiller.com/2017/05/24/how-should-microservices-communicate/

[windows] python 幫忙打開檔名太長限制

不知道你是否有遇到,在windows複製/移動檔案的時候發生路徑太長以致於無法複製/移動的情況?

我大概每年發生個四、五次,在備份自己的電腦檔案時就一定會發生。然後就有些檔案就無法備份或是要改短名字,搬完再改回來。有次發現用 node.js 寫程式複製檔案可以不被限制,後來就自己寫個程式來複製。

今天在裝 python3.6.2 的時候發現它的安裝程式會好心問你要不要關閉這個選項,若是要的話,它會用 winreg 幫你改個 registry。

import winreg; winreg.SetValueEx(winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, r'SYSTEM\CurrentControlSet\Control\FileSystem'), 'LongPathsEnabled', None, winreg.REG_DWORD, 1)

如果有需要的話,也有 python 的話,執行這句就有同樣效果。
當筆記。

[python] 徒手把自己的程式從 py2 改成 py3

# 1
想親身體會一下從 py2 升到 py3 會有多痛苦,決定把自己來一遍。遇到以下的事情,其實感覺還好。

# 2
我最常遇到的是 print 後面要加括號,用手動改久了真的很想用 regexp 之類的直接取代

# 3
urllib 被拆成幾個部份,我有用到的:

urllib.urlencode ---> urllib.parse.urlencode
urllib.urlopen ---> urllib.request.urlopen

# 4
文字編碼的問題會在幾個地方遇到

在檔案讀寫,改用 codecs 的 open 並指定 encoding。
urlopen,得到的內容要 decode(encoding)
csv.reader 改用 codecs 的 open 並指定 encoding。

# 5
dict1.keys() 回傳的東西不是單純的 list,所以沒辦法做到 dict1.keys().sort()。解決方法是 sorted(dict1.keys())

從這樣:
dict1.keys().sort()
變這樣:
sorted(dict1.keys())

# 6
sort 原先有 cmp function 的,現在只能 key function,兩者概念相差甚大。現在 py3 提供 wrapper 從 cmp function 轉成 key function。

從這樣:
sorted(cursor,key=cmpbyyear, reverse=True)
變這樣:
sorted(cursor,key=functools.cmp_to_key(cmpbyyear), reverse=True)

# 7
dict1.has_key('skey') 現在不能用,改成 'skey' in dict1

從這樣:
dict1.has_key('skey')
變這樣:
'skey' in dict1
# 8
map 現在回傳是個 map 物件,是一種 iter,如果沒有執行 iter 動作的話,就不會真的開動。最簡單的方法就是包一層 list。

從這樣:
map(func, seq)
變這樣:
list(map(func, seq))

2017年9月10日 星期日

[electron] 入 jQuery 之類的問題。

Electron (atom.io) 引入 jQuery 之類的問題。

在使用 electron (.atom.io) 的時候,如果是在 render process 的 js 裡面要使用 jquery,是另外一回事。如果是像我一樣,把原來是網頁程式改成 electron,在 html 裡面要引入 jquery 一樣會有符號問題,因為 electron 有去修改 DOM 裡面的變數。所以得要修正回來才行。
在網頁程式裡的最前面加入修正:
<head>
<script>
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
<script type="text/javascript" src="jquery.js">
</script>
</head>

在 main process 的 nodeIntegration 不關掉好像也沒有關係。現在我還沒有遇到問題。
參考:
https://electron.atom.io/docs/faq/…

2017.09.11 更新:
還有另外一種做法,我也比較喜歡。我就是不想去動原來網頁程式的內容的情況下,在 main.js (有寫的人應該知道這是什麼)裡面,createWindow 的地方,創建新的 BrowserWindow 時,加入新的選項 nodeIntegration: false,如下:

function createWindow () {
  // Create the browser window.
  win = new BrowserWindow(
{width: 800, height: 600,
webPreferences: { //https://electron.atom.io/docs/faq/#i-can-not-use-jqueryrequirejsmeteorangularjs-in-electron
nodeIntegration: false
}
})
  // and load the index.html of the app. 
  win.loadURL('http://127.0.0.1:10001/')
  // Open the DevTools.
  ////win.webContents.openDevTools()
  // Emitted when the window is closed.
  win.on('closed', () => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null
  })
}

這樣原來網頁程式就不用動了。