2015-06-05 48 views
5

Aşağıdaki proje yapısını düşününTest dizini __init__.py içeriyorsa, içe aktarma neden Python burnu ile çalışıyor? <code>test_a.py</code> modülünü <code>a</code> ithal ile</p> <pre><code>a.py test/ test_a.py </code></pre> <p>:

ithalat hata test dizin sonuçlarında nosetests çalışan Beklendiği gibi
import a 

: Ancak

ERROR: Failure: ImportError (No module named a) 

Boş birekleyerek fark ettim test dizininedosyası, nosetests (test_a.py Python ile çalıştırdığınızda değil) ile içe aktarma işi yapar. Nedenini açıklar mısınız?

__init__.py eklenmesi, test ürününü paket haline getirdiğini anlıyorum. Ancak, içe aktarma, paketteki aramayı içeren dizini içerdiği anlamına mı geliyor?

+0

http://stackoverflow.com/questions/448271/what-is-init-py-for – Mir

+3

@Mir ben ne için '__init __. py' anlama . Neden diğer modüllerin ithalatını etkilediğini anlamıyorum. – vitaut

+0

Çünkü orada olmasaydı, herhangi bir dizini kazayla alabilirdiniz, bu da işe yaramazın yanında olurdu. Onun bir programatik kontrolü. – Kris

cevap

5

Dizinde bir __init__.py dosyasının varlığı, test dosyasını yalnızca eski bir dizinden python package içine dönüştürür. Bunun sys.path üzerinde bir etkisi vardır.

bu gibi test_a.py modülünü değiştirin:

import sys 

def test_thing(): 
    for i, p in enumerate(sys.path): 
     print i, p 

try: 
    import a 
except ImportError: 
    print('caught import error') 

Sonra birlikte ve orada bir __init__.py olmadan test dizinden nosetests -s çalıştırmayı deneyin.

Not: sys.path numaralı mısraların çalıştırıldığı test koşucudur. Ve bu the second "Note" of this section here belgelenmiştir (teşekkürler @davidism). Paket yapılı ve paket yapısı olmadan sadece python test_a.py'u çalıştırarak herhangi bir değişiklik görmeyeceksiniz.

+3

Bunu anlıyorum, ancak içe aktarma aramasını nasıl etkiler? – vitaut

+0

Sağ. Daha fazla ayrıntı ekledim. – wim

+1

[py.test (hangi nosetests çatallı) de bunu açıklar] (http://pytest.org/latest/goodpractises.html#choosing-a-test-layout-import-rules) – davidism

2

Burun modülünün sosu kodunu inceledim ve neden burada. importFromDir importFromPath çağrılır Senin durumunda

def importFromPath(self, path, fqname): 
    """Import a dotted-name package whose tail is at path. In other words, 
    given foo.bar and path/to/foo/bar.py, import foo from path/to/foo then 
    bar from path/to/foo/bar, returning bar. 
    """ 
    # find the base dir of the package 
    path_parts = os.path.normpath(os.path.abspath(path)).split(os.sep) 
    name_parts = fqname.split('.') 
    if path_parts[-1] == '__init__.py': 
     path_parts.pop() 
    path_parts = path_parts[:-(len(name_parts))] 
    dir_path = os.sep.join(path_parts) 
    # then import fqname starting from that dir 
    return self.importFromDir(dir_path, fqname) 

def importFromDir(self, dir, fqname): 
    """Import a module *only* from path, ignoring sys.path and 
    reloading if the version in sys.modules is not the one we want. 
    """ 
    dir = os.path.normpath(os.path.abspath(dir)) 

, 'dir' bir seviye __init__.py dizinden yukarıda dizinidir. Testinize __init__.py ekleyerek çalışmalarını 'bir içe' yapar Yani bu yüzden