2013-05-05 22 views
1

我試圖打包,包括它的依賴成可執行的zip文件的腳本,以下基本步驟如下:將zipfile作爲網站目錄的標準方法?

$ mkdir build 
$ pip install --target build -r requirements.txt 
$ cp -r mypackage build 
$ echo 'from mypackage import main; main()' > build/__main__.py 
$ cd build 
$ zip -r myscript-with-dependencies.zip * 
$ echo '#!/usr/bin/env python' | cat - myscript-with-dependencies.zip \ 
    >../dist/myscript 

這工作,一般來說,除了似乎.pth文件不被evaled :他們被site.addsitedir(zip_path)忽略(可能是因爲it doesn't seem to have been written to understand zip files)。

這是專門爲我一個問題,因爲我的一些依賴使用setuptools的namespace-packages,它的魔法發生大多在.pth文件。

我熄滅,喜歡寫東西addzipsitedir我想知道如果任何人有經驗,有這樣那樣的問題之前,我是明顯的東西?一般而言,zipimport docs並沒有超出「它正常工作!」的含義。 (再次,它主要做的,除了命名空間包和安裝到雞蛋的事情,等)

+0

你不能將namespaced egg合併到一個目錄結構中嗎? – 2013-05-05 20:44:33

+0

我確實可以,但我想要一個更通用的解決方案(並且每次我想要打包新項目或添加新的依賴項時都不需要*不同* Makefile黑客)。 – quodlibetor 2013-05-05 20:46:45

+0

這就是解決方法I在任何情況下都會考慮。 :-) – 2013-05-05 20:47:41

回答

1

事實上,addsitedir()不處理zip文件;但它應該很容易複製行爲。

參見site.addsitedir()源代碼;代碼只是試圖調用路徑上os.listdir()來然後發現.pth文件:

try: 
    names = os.listdir(sitedir) 
except os.error: 
    return 
dotpth = os.extsep + "pth" 
names = [name for name in names if name.endswith(dotpth)] 
for name in sorted(names): 
    addpackage(sitedir, name, known_paths) 

其中addpackage()只是site.addpackage()。您可以將上述names列表替換爲您的zip文件中的.pth文件列表。您還必須複製site.addpackage()行爲,該功能期望能夠讀取.pth文件。

簡化,該函數的作用:

with f: 
    for n, line in enumerate(f): 
     if line.startswith("#"): 
      continue 
     if line.startswith(("import ", "import\t")): 
      exec line 
      continue 
     line = line.rstrip() 
     dir, dircase = makepath(sitedir, line) 
     if not dircase in known_paths and os.path.exists(dir): 
      sys.path.append(dir) 
      known_paths.add(dircase) 

與例外處理混合makepath()site.makepath(),和known_paths確保找到的任何路徑僅加入一次。

因此,在本質上,通過.pth命名所有項目都添加到您的sys.path但執行任何開始import那裏,然後,給.pth文件勾入site.py裝載階段。

import掛鉤被基於setuptools的包使用來構建命名空間包;這裏是一個從zc命名空間的軟件包:

import sys,types,os; p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('zc',)); ie = os.path.exists(os.path.join(p,'__init__.py')); m = not ie and sys.modules.setdefault('zc',types.ModuleType('zc')); mp = (m or []) and m.__dict__.setdefault('__path__',[]); (p not in mp) and mp.append(p) 

它創建在sys.modules使用sitedir局部變量從addpackage()功能的空模塊對象。請注意撥打os.path.exists();對於壓縮的雞蛋來說,這會失敗(不會添加空模塊對象),因此您可能需要檢測命名空間包併爲其提供自己的版本。 zc名稱空間中的任何程序包只是確保有一個ModuleType()對象用於它關心的父命名空間,__path__屬性指向{sitedir}/{packagename}/__init__.py

另一種方法是將命名空間的包合併成一個目錄結構來代替。