ofek / userpath

Cross-platform tool for adding locations to the user PATH, no elevated privileges required!
MIT License
151 stars 20 forks source link

ctypes.wintypes is not always automatically loaded #55

Closed kristjanvalur closed 4 months ago

kristjanvalur commented 5 months ago

In some situations, I have observed pipx ensurepath fail with "module ctypes has no attribute wintypes".

wintypes.py is a submodule of ctypes and needs to be explicitly imported. Otherwise your the success of WindowsInterface.put() depends on what else has executed.

You need to add

import ctypes
import ctypes.wintypes

to interface.py for the WindowsInterface.

ofek commented 5 months ago

This has been working forever so I am hesitant to change anything. Can you please provide a traceback showing the error?

kristjanvalur commented 5 months ago

No I cannot. This happened in the context of installing pipx via scoop in a sandbox windows installation. The upshot is that pipx cannot set the path via pipx ensurepath. The output is simply:

> pipx ensurepath
AttributeError: module 'ctypes' has no attribute 'wintypes'

However, the code is clearly wrong. Submodules must be explicitly imported, unless there is a __main__.py in the package which automatically does it. Which is not the case for ctypes.

python -c "import ctypes; foo = ctypes; bar = ctypes.wintypes.DWORD()"

vs

python -c "import ctypes; import ctypes.wintypes; foo=ctypes; bar = ctypes.wintypes.DWORD()"

The fact that it works is due to the fact that someone else has already done the import by the time your code runs under normal circumstances. However, I seem to have triggered a case where that hasn't happened yet.

kristjanvalur commented 5 months ago

In case you still aren't convinced, I'll try to repro this directly on windows.

kristjanvalur commented 5 months ago

Here you go:

import userpath
from userpath.interface import WindowsInterface

WindowsInterface().put(r'C:\Users\user\Downloads\test', front=True, app_name='userpath', check=False)

results in

Traceback (most recent call last):
  File "E:\git\userpath\tests\wintypes.py", line 4, in <module>
    WindowsInterface().put(r'C:\Users\user\Downloads\test', front=True, app_name='userpath', check=False)       
  File "C:\Users\kristjan\AppData\Roaming\Python\Python311\site-packages\userpath\interface.py", line 60, in put
    ctypes.wintypes.DWORD(),
    ^^^^^^^^^^^^^^^
AttributeError: module 'ctypes' has no attribute 'wintypes'
kristjanvalur commented 5 months ago

Note that this is not widely documented, not mentioned explicitly in the python docs and no linter appears to check for this. However, it is self evident from the way the language is designed. From this link:

https://stackoverflow.com/a/44913709

If you want to use a module, import it to guarantee it will be there. If you don't import it explicitly, it might still exist if it gets imported somewhere else, but it's not reliable.

rosscoleman commented 4 months ago

I got this same error on Windows 10 after installing Python and pipx using scoop. Then doing pipx ensurepath.

Gitznik commented 4 months ago

Explicitly importing wintypes seems like a pretty low-danger fix.

@ofek do you plan to look into this? We've closed the issue on pipx side for now, as there's not much we can do about it. But would be great to fix this for the windows users encountering this.

ofek commented 4 months ago

https://github.com/ofek/userpath/releases/tag/v1.9.2

I simply lost track of this, thanks for the reminder!

Gitznik commented 4 months ago

Great, thank you for the quick release :pray: And developing this library of course.