Issue #151 resolved

0.6.12 FAIL on Windows: AttributeError: 'module' object has no attribute '__file__'

Sridhar Ratnakumar
created an issue

From http://pypm-free.activestate.com/2.6/win32-x86/pool/d/di/distribute-0.6.12_win32-x86_2.6_1.pypm.d/log

{{{ Traceback (most recent call last): File "setup.py", line 177, in <module> scripts = scripts, File "c:\ActivePython32Python26\lib\distutils\core.py", line 152, in setup dist.run_commands() File "c:\ActivePython32Python26\lib\distutils\dist.py", line 975, in run_commands self.run_command(cmd) File "c:\ActivePython32Python26\lib\distutils\dist.py", line 995, in run_command cmd_obj.run() File "c:\docume~1\apy\locals~1\temp\tmpicsrcz\distribute-0.6.12\setuptools\command\install.py", line 53, in run return _install.run(self) File "c:\ActivePython32Python26\lib\distutils\command\install.py", line 589, in run self.run_command(cmd_name) File "c:\ActivePython32Python26\lib\distutils\cmd.py", line 333, in run_command self.distribution.run_command(command) File "c:\ActivePython32Python26\lib\distutils\dist.py", line 995, in run_command cmd_obj.run() File "c:\docume~1\apy\locals~1\temp\tmpicsrcz\distribute-0.6.12\setuptools\command\install_scripts.py", line 15, in run from setuptools.command.easy_install import get_script_args File "c:\docume~1\apy\locals~1\temp\tmpicsrcz\distribute-0.6.12\setuptools\command\easy_install.py", line 16, in <module> from setuptools.sandbox import run_setup File "c:\docume~1\apy\locals~1\temp\tmpicsrcz\distribute-0.6.12\setuptools\sandbox.py", line 163, in <module> fromlist=['name']).file) AttributeError: 'module' object has no attribute 'file' }}}

I did use the latest tarball .. as of the time I am reporting this issue.

Comments (17)

  1. Jason R. Coombs
    • changed status to open

    Upon further investigation, I have found that a clean install of pywin32 creates an empty gen_py directory. This was a surprise to me, as I would have thought that an empty gen_py directory would not be importable as __init__.py is not present. According to the Python 2.6.5 docs: "The __init__.py files are required to make Python treat the directories as containing packages" [1]. I'm guessing the __init__.py for gen_py isn't required either because it's already in a package or because win32com does some trickery to make the package visible even when there is no __init__.py.

    Even so, because __init__.py doesn't exist, gen_py has no __file__ attribute.

    Python 2.7b2 (r27b2:81019, May  9 2010, 11:33:14) [MSC v.1500 32 bit (Intel)] on win32
    >>> win32com = __import__('win32com')
    >>> win32com.gen_py
    <module 'win32com.gen_py' (built-in)>
    >>> dir(win32com.gen_py)
    ['__doc__', '__name__', '__package__', '__path__']
    >>> win32com.gen_py.__package__
    >>> win32com.gen_py.__doc__
    >>> win32com.gen_py.__name__
    'win32com.gen_py'
    >>> win32com.gen_py.__path__
    ['C:\\Python\\lib\\site-packages\\win32com\\gen_py']
    

    So, it appears we have a few choices for resolving the location of gen_py (for the purposes of excluding it from the sandbox).

    1. Use win32com.gen_py.__path__[0]. Will this always refer to the location of gen_py?
    2. Use join(dirname(win32com.__file__), 'gen_py').
    3. Just exclude dirname(win32com.__file__), and disable the sandbox protection for the higher level package win32com.

    I think I'm going to go with 2.

    [1]: http://docs.python.org/tutorial/modules.html#packages

  2. Tarek Ziadé repo owner

    I think you should also:

    • check you are under win32 before doing this (sys.platform=='win32')
    • check if the result you have calculated is really a dir (os.path.isdir) before adding it
  3. Jason R. Coombs

    My instinct is to not add the additional checks - the existing implementation is already somewhat cluttered... and adding more checks would likely make it harder to infer the behavior. Specifically-

    I would rather not test for sys.platform - since the import of win32com should be sufficient for testing for the expected environment. It's conceivable (though unlikely) that win32com would run on other platforms, in which case this exclusion could still be valid.

    It seems unnecessary to add a check for is_dir - if win32com exists and specifies a gen_py directory, that directory probably already exists. If it doesn't exist or is a file, it doesn't hurt to have it in the list of exclusions, as it won't be possible to write content to it anyway.

    If you still feel the checks are necessary, or omitting them will violate a design convention of distribute, then let's add them. I won't be offended.

  4. Jason R. Coombs

    To work around this problem with distribute 0.6.12, you can force win32com to initialize the gen_py directory by issuing the following command:

    python -c "from win32com.client.gencache import GetGeneratePath; GetGeneratePath()"
    

    This creates the __init__.py file which distribute 0.6.12 expects.

    Thereafter, you should be able to install distribute 0.6.12 without problems. I tested this locally and was able to install distribute 0.6.12 from PyPI.

  5. Sridhar Ratnakumar reporter

    The `GetGeneratePath` workaround didn't work for me. Also please note the following:

    > python27 -c "import win32com; print win32com.gen_py.__path__"
    ['C:\\DOCUME~1\\apy\\LOCALS~1\\Temp\\gen_py\\2.7']
    
    > python26 -c "import win32com; print win32com.gen_py.__path__"
    ['C:\\DOCUME~1\\apy\\LOCALS~1\\Temp\\gen_py\\2.6']
    

    Hmm, gen_py is inside the Temp directory on my machine (WinXP 64-bit). Both of them have a init.py inside. Still distribute won't install.

    Curiously, gen_py is found to be a builtin module:

    >python27
    ActivePython 2.7.0b2.dev44712-eaeebf8cda33.0 (ActiveState Software Inc.) based on
    Python 2.7b2+ (trunk, May 14 2010, 09:32:22) [MSC v.1500 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import win32com.gen_py as m
    >>> m
    <module 'win32com.gen_py' (built-in)>
    

    This corresponds to PyWin32 CVS checkout made on 2009/11/10.

    For this reason, I'm afraid that this fix http://bitbucket.org/tarek/distribute/changeset/a54bfca32dff is incorrect as the variable "gen_py_pkg" refers to a path that does not actually exist.

    But this fix http://bitbucket.org/tarek/distribute/changeset/b7d3dbc9aa22 seems to be correct.

    The workaround is painful: I first had to install distribute-0.6.10 using an old distribute_setup.py, apply the above patch to sandbox.py manually and then run "python27 c:\python27\scripts\easy_install-2.7-script.py -U distribute".

    A new release would be very helpful.

  6. Jason R. Coombs

    Sridhar, thanks for all of the useful information. I'm unsure why the workaround is not working for you. I guess it's because init.py doesn't get created when running in a non-admin python shell (and thus gen_py is created in %TEMP%). ...either that, or it gets removed when the workaround process exits, and thus it isn't there when distribute later runs.

    As far as I know, I don't have access to cut a release, and I don't feel comfortable cutting a release until I'm more assured the fix is working properly.

    I have built a source distribution of distribute, which should be easy_installable, and posted it to my dropbox, so would you test that you're able to easy_install from that site?

    easy_install-script.py http://dl.dropbox.com/u/54081/distribute-0.6.13dev.zip
    

    (I suggest using -script to avoid access conflicts updating easy_install.exe)

    If it installs correctly in your environment, I'll update the CHANGELOG to indicate the fix and suggest Tarek cut a release.

  7. Sridhar Ratnakumar reporter

    Thanks for bundling up a dev release, but I just realized that "easy_install -U distribute==dev" (using -script) worked fine too, on both my Windows machines. So this verifies it, no?

    As for the release, we have an ActivePython-2.7 release planned by end of month (along with core 2.7rc1). Even if there isn't going to be a distribute release, I think we can simply use an older version.

  8. Log in to comment