把uliweb項目變成可安裝的python包

這是目前個人一個嘗試。隨着uliweb的項目多起來(爲了便於管理和隔離,咱們會考慮將不一樣的功能拆分爲不一樣的項目),須要有時複用其它項目的模塊,好比:用戶管理等。uliweb項目是能夠將一個知足條件的python包(使用 uliweb makeapp appname)做爲外部的app在INSTALLED_APPS中配置的。可是對於使用 uliweb makeproject projectname 生成的項目,卻缺省不是一個能夠處理的python包,所以直接是沒法在另外一個項目中導入的,爲了實現這一點,我對uliweb進行了優化。python

設計安裝方法和結構

爲了讓一個目錄是能夠導入的,咱們通常會使用setup.py來編寫一個安裝腳本,在其中寫上對應要安裝的包和目錄。一個uliweb的project是什麼結構呢?linux

project/
    apps/
        settings.ini
        app1/
        app2/
    wsgi_handler.py

咱們全部的app都是放在apps目錄下,因此它是一個重要的目錄。好比咱們的項目目錄是project,所以對於app1這個app來講,我但願能夠在安裝後使用 import project.app1 來導入。那麼咱們會發現,但願導入的包名和實際的目錄是不對應的。那麼如何處理呢?git

在寫setup.py時,有兩個變量很重要:packages和package_dir,它一個是用來表示安裝後將出現的包名,能夠是多個,另外一個是一個配置,用來表示安裝包與實際目錄的關係。所以,咱們能夠這樣寫:github

setup(packages=['project'], package_dir={'project':'apps'})

這樣就告訴安裝程序,在安裝時建立包爲project,可是它實際的文件是來自當前目錄的apps下的內容。web

考慮好這一點,我就開始改造uliweb。windows

改造uliweb

修改makeproject和項目模板

首先是考慮在執行makeproject時自動拷貝一個setup.py文件到新建的項目目錄下。它的內容是:app

import uliweb
from uliweb.utils.setup import setup
import apps

__doc__ = """doc"""

setup(name='{{=project_name}}',
    version=apps.__version__,
    description="Description of your project",
    package_dir = {'{{=project_name}}':'apps'},
    packages = ['{{=project_name}}'],
    include_package_data=True,
    zip_safe=False,
)

能夠看到,它裏面有一個變量 {{=project_name}} ,表示這個值將用實際的項目路徑名進行替換。所以,若是咱們執行 uliweb makeproject project 會在當前目錄下生成 project 目錄,在其中會有一個setup.py文件,makeproject命令會自動將模板中的 {{=project_name}} 替換爲 project函數

而後咱們還須要在apps下添加一個 __init__.py,它定義了 __version__ 變量值,這個值會用在 setup.py中。用來表示項目的版本。工具

改造安裝腳本

使用setup.py來安裝模塊時主要有兩種方式:install和develop。注意develop是setuptools中特有的。所以須要在你的環境中安裝setuptools,同時還建議把pip也安裝。最好的方式是使用virtualenv,它會自動安裝這兩個包。優化

對於install,它會把對應的文件所有拷貝到python的site-packages下,對於develop,它只會在site-packages下的easy_install.pth中加一個路徑,不會真正拷貝。

對於install,由於會拷貝文件,因此不會有太大的問題。只不過若是你的項目常常更新,須要不停地執行install來更新。

所以,不少時候我會使用develop來安裝。可是在實際處理過程當中發現develop是存在問題的。主要問題就是不會進行實際文件的拷貝。由於咱們的包結構和實際的目錄結構不一樣,而拷貝的方式會建立這種結構,可是develop方式沒法實現這種包結構。因此有問題。

那麼怎麼解決呢?我在網上搜了半天,終於找到一種辦法,那就是建立: 符號鏈接 。符號鏈接是在linux下經常使用的一種方法。其實這種方法在windows下也是能夠用的。有這麼幾個方法可使用:

  • os.symlink(src, linkname) #建立src爲linkname
  • os.path.islink(path) #檢查path是事是一個link
  • os.unlink(path) #刪除一個link或文件

可是,在windows平臺下,這些方法除了unlink之外,都存在問題。看到網上說在python 3.2以後就能夠了。可是我運行的環境主要是python 2.6和2.7。因此須要不升級就能解決的方法。

找來找去,有兩個參考:

  1. http://stackoverflow.com/questions/1447575/symlinks-on-windows 這個討論(其它的地方也看到有相同的代碼)中有一段使用ctypes寫的symlink的函數實現,用它能夠在windows下建立符號鏈接。
  2. https://github.com/juntalis/ntfslink-python 這個項目實現了好幾種windows下鏈接的支持,其中有symlink的支持(具體有哪些請自行研究吧)。這裏面實現了上面的幾個函數。

那麼個人實現是寫在 uliweb/utils/setup.py 中的,對原來的setuptools中的develop命令的幾個方法進行了特殊處理,如:

  • install_for_development 我在它以後添加了根據setup中的packages和package_dir來建立符號鏈接的處理。它支持包和子包。所以你可使用象

    setup(packages=['project', 'project.batch'], package_dir={'project':'apps', 'project.batch':'batch'})

這樣的方式,將不一樣的目錄處理到一個包結構之下。

  • uninstall_link 我在它以後増加了刪除symlink的處理。原來的處理只會刪除原來建立的文件,而不會刪除新建立的鏈接。

所以,若是你要使用uliweb的develop方式,而且在windows下,你須要安裝 ntfslink 這個包。爲何呢?

由於我發現,直接執行unlink去刪除一個symlink會報 [Error 5] 的錯誤。而 ntfslink.symlink 中的unlink方法能夠正確刪除。可是我又發現,ntfslink.symlink 中的create好象沒法建立正確的symlink,因此我仍是使用了stackoverflow中的建立symlink的方法。

使用

其實前面已經寫了:

  1. 執行 uliweb makeproject <projectname> 會在生成的 projectname 目錄下建立一個setup.py文件。你能夠打開修改它的內容以知足你的須要
  2. 執行 python setup.py installpython setup.py develop 來安裝你的項目,這樣就能夠在其它的項目中使用了。使用方式是 import project.app,若是想反安裝,若是是使用develop安裝的話,能夠這樣 python setup.py develop -u 。可是使用install的話,報歉,沒戲了。因此這時可使用pip來作這事: pip uninstall <projectname> 。這也是我建議你兩個都安裝的緣由,這兩個工具互補仍是不錯的。
相關文章
相關標籤/搜索