almost 4 years ago

今天在使用 pip bundle 的時候,發現 pip 1.5 將會廢除 pip bundle

###############################################

##                                           ##

##  Due to lack of interest and maintenance, ##

##  'pip bundle' and support for installing  ##

##  from *.pybundle files is now deprecated, ##

##  and will be removed in pip v1.5.         ##

##                                           ##

###############################################

查看了一些討論串,似乎一直有廢除的聲浪,但一直沒有真的執行。許多潛水很久的人會冒出來說自動化部屬時大量依賴 pip bundle,希望不要廢除。事實上,我們在部屬上也大多是使用 pip bundle 只是因為在打包上相當方便。

大家覺得要廢除的原因主要是覺得這個指令很多餘。因為這個功能基本上形同用 tar 製作一個包含 source code 的 archive。

wheel 是一個 python 的打包工具,我覺得他最大的特色就是打包出來的 package 是 pre-compiled。因此,拿到新的環境就不需要重新 build。也因此要小心不要把編好的 package 拿到不同的平台使用。

在 pip 1.4,wheel 被正式的納入指令中。

今天稍微試玩了一下,其實並不難。

安裝

首先,要確認你的 pip >= 1.4

pip install -U pip>=1.4

接著,安裝 wheel

pip install wheel

使用方式

  • 打包 (以 django 為例)

    pip wheel django
    

    這時一個新的資料夾 wheelhouse 會被建立。裡面就放著剛 build 好的 django binary。

  • 安裝

    pip install --use-wheel --no-index --find-links=wheelhouse/ django
    

    這時就算沒有連外網路一樣會把 django 裝好。

參考資料

  1. remove pip's bundle support?
  2. Replacing “pip bundle”
  3. Wheel
 
almost 4 years ago

自從去年開始幫忙維護 PyConTW 網站的 Backend 之後,就開始愛上了 supervisor

理由

  1. Suitable for all Unix-like OS
    相容於所有 Unix-Like 系統。這讓你的 script 更有移植性。

  2. Don't need to write your script as a daemon
    你只需要顧好自己的程式邏輯,而不需要考慮 Daemonize 需要 Fork 一次還是二次的問題。supervisor 會為你打理好這一切,同時也會在程式異常終止,替你重新叫起程式。

  3. Well-defined logging mechanism
    透過設定就可以將 script 的 stdout, stderr 導到對應的 log 檔。簡單的說,任何你 print 的字串,都會被紀錄。大大的減輕 debug 時的負擔。雖然,這樣很方便,但還是建議好好規劃自己 script 的 logging strategy。

  4. Flexible - Provide privilege drop, such as changing user or directory
    透過簡單的設定,就能切換工作目錄、使用者,甚至是環境變數。如果是使用 upstart,這些都必須在自己的 script 裡面完成。

參考資料

  1. Herd UNIX processes with Supervisor
  2. What to Use Upstart (and Other Supervisors) For
  3. Make supervisor work on upstart
  4. Add a group for supervisorctl without sudo
 
almost 4 years ago

起因

一開始想做的事情,其實是自動化的佈署好 nginx + supervisor + uwsgi + python webserver(whatever)。因為實在有太多設定檔,讓我覺得很囉唆。一開始想過直接寫 shell 就好啦!但是,想要透過變數控制安裝路徑,Server 的 Port,就必需不斷的使用 sed 之類的指令,又醜又煩。

一提到自動化佈署腦袋中出現的工具是 puppet,因為有聽同事提起過。看了幾個 Demo 不得不說這真的是強大的工具。但是,寫習慣 Python 的我,看到 Ruby 的一大堆箭頭,實在是頭暈、不舒服。這時突然有個念頭:像這種自動化工具難道 Python 沒有?經過了一番搜尋,發現了 Saltstack

特色

  1. Python 生產。
  2. 使用者只需專注在 Depoly Script。
  3. Script 格式令人感到親切的 yaml, json。

角色

在 SaltStack 中,角色區分為 Master 以及 Minion。Master 可以對已經接受 (Accepted) 的 Minion 下達指令。

安裝

SaltStack 提供了安裝腳本,大大的降低了進入的門檻。

  • Master

    $ curl -L http://bootstrap.saltstack.org | sudo sh -s -- -M -N git v0.17.2
    
  • Minion

    $ curl -L http://bootstrap.saltstack.org | sudo sh -s -- git v0.17.2
    

利用上面 2 個指令,即可分別安裝好 Master 及 Minion。

設定檔

SaltStack 的設定檔,預設是放在 /etc/salt/
在開始使用之前,需先設定 master 綁定的 IP。並在 minion 設定 master 的位置。

/etc/salt/master
interface: 10.10.100.125
/etc/salt/minion
master: 10.10.100.125

設定完記得要重新啟動 SaltStack 的 Service。

Key

當服務正常啟動之後,minion 會拿著一把 key 去跟 master 登記。這時只要在 master 利用 salt-key 就可以管理這些登記的機器。

$ salt-key -L # 列出所有的 Key

Accepted Keys:
Unaccepted Keys:
Salt-Minion
Rejected Keys:

如要啟用特定的機器,就下達 salt-key -a [key_name] 本例為:

$ salt-key -a Salt-Minion

到此,一台 master 與一台 minion 應該已經正常的連線了。

參考文件

SaltStack Document

 
almost 4 years ago

前言

最近,在使用 jinja2 渲染 html 時,遇到了多國語言 (i18n) 的問題。jinja2 本身很完善,對於 i18n 的支援也沒有問題,只是沒有標準的翻譯檔建立機制。後來發現 pocoo 其實也有提供建立翻譯檔的 Solution,叫做 Babel,只是當初我只專注在 Template Syntax,而沒有仔細的去看文件。

安裝

只需要使用 pip 即可完成安裝。

pip install babel

如何使用

在使用 babel 之前,當然要先準備好需要翻譯的 Template 檔 。除此之外,還需要在 babel 的執行路徑建立一個名為 babel.config 的檔案。此檔案的用意在於告訴 babel 需要檢查的路徑,以及要使用何種的翻譯模式。以 jinja2 為例,babel 會自動搜尋 Template 中,使用 _ 或是 gettext 包覆的字串,如:{{ _("Translate Me.") }}

babel 設定檔範例

babel.config
[ignore: .venv/**]
[ignore: test/**]

[python: **.py]

[jinja2: **/templates/**.html]
encoding = utf-8

指令 (Command line tool)

在翻譯過程中,會使用的指令主要有四個。

  1. 從 Template 產生 POT 檔

    $ pybabel extract -F babel.config . -o i18n/messages.pot
    
  2. 從 POT 檔產生各個語言的翻譯檔 (PO 檔)

    $ pybabel init(update) -l zh_TW -d ./i18n -i ./i18n/messages.pot
    
  3. 從 POT 檔產生各個語言的翻譯檔 (PO 檔)

    $ pybabel init(update) -l zh_TW -d ./i18n -i ./i18n/messages.pot
    
  4. 編譯翻譯好的 PO 檔。

    $ pybabel compile -f -d ./i18n
    

延伸閱讀

  1. Differences Between POT and PO Files
  2. gettext syntax of jinja2 template
 
about 5 years ago

Today, I build a login system in django where the user is not in my server. There is lots of works before I start handling login service in django. After I finish all preliminary works, I try to login by the single username. Here is my code:

user, created = User.objects.get_or_create(username="username")  
auth.login(request, user)

Everything looks good for me. However, it's not work. I  meet the error code:

'User' object has no attribute 'backend'

It is because that the user you obtain from the User model does not contain the information of session backend. Thus, django can not record you login status and it's failed.

After tracing codes in "django.contrib.auth", I find that there is a ModelBackend called "RemoteUserBackend". It is used for cases like mine. According to the document in Django official site, all you have to do is to place the django.contrib.auth.middleware.RemoteUserMiddleware after the django.contrib.auth.middleware.AuthenticationMiddleware in the MIDDLEWARE_CLASSES in settings.py. And then replace AUTHENTICATION_BACKENDS by

AUTHENTICATION_BACKENDS = (  
    'django.contrib.auth.backends.RemoteUserBackend',  
)

You login code will look like this:

user = auth.authenticate(remote_user="username")  
auth.login(request, user)

Then, you can process all other works as it has been.