KeyError: 'getpwuid(): uid not found: 381206' - python

I'm running the following code to get owner of all files:
try:
st=os.stat(file_path)
uid=st.st_uid
userinfo=pwd.getpwuid(st.st_uid)
owner=pwd.getpwuid(st.st_uid).pw_name
file_info.append((size,file_path,owner))
except OSError as e:
pass
However, in the middle of the processing, it throws up the following error:
KeyError: 'getpwuid(): uid not found: 381206'
Do anyone know about this error? Are there any known issues with pwd in Python 2.6 ?
Please notice that this is just the part of the code I considered relevant, I can provide more if required.

The error happens in my python ver 3.5 as well in Linux.
In my case, once a person leaves the company, his/her UID is replaced with a number and pwd.getpwuid(st.st_uid) fails with the error.
I replaced it with sh.stat('-c', '%U', <path>).stdout.decode('utf-8').strip(), which returns UNKNOWN.

Related

Python: Assert a UserWarning

I created my own python script script.py in which I define my own class (e.g. myclass). The class reads a csv file as a dataframe. One of the checks that I established is for making sure that a specific column exists in the dataset. The check is:
if ("column" not in self.df.columns): warnings.warn("column is not available in the input file.")
This actually works fine and when the "column" is not included in the dataset, the warning error is produced:
UserWarning: column is not available in the input file.
if ("column" not in self.df.columns): warnings.warn("column is not available in the input file.")
I am trying to verify/assert the issue of the warning message by running the following unit test:
import script
...
...
...
def test_if_error_is_issued ():
with pytest.raises(UserWarning) as warn:
script.myclass(path)
I think that the latter code chunk is not correct as I keep receiving the following error message ( path actually leads to a csv without the "column"):
E Failed: DID NOT RAISE <class 'UserWarning'>
MrBean Bremen answered this question.
The solution is to change pytest.raises to pytest.warns.

Python still throwing exception I've explicitly excepted

I've got some code that I know will fail in the edge case where the list is empty so I added exception handling for IndexError.
But, despite handling the exception, it's still getting raised.
~/Code/foo.py in decode_tokens(tokens)
196 new_toks.append(new_tok)
197 else:
--> 198 try: new_toks[-1] += new_tok
199 except IndexError: pass
200 new_elem = True
IndexError: list index out of range
I don't understand how if I'm explicitly excepting IndexError why it's still getting raised and aborting script execution.
Edit: adding that this is Python 3.6 running in a Jupyter notebook. As it looked like a python error I didn't think that was relevant (but it sounds like it might be.)
Editors that support IPython, which include Jupyter, do not always reload modules even after they have been edited. I think this might be an unfortunate coincidence; the line that the error is thrown happens to coincide with the line of your exception handler after an edit. Likely the code that threw the error isn't what's at that line now. You may wish to force a reload of imported modules each time you run a script, or at least restart the underlying IPython kernel for now.

'ToastNotifier' object has no attribute 'classAtom'

I ran the code below;
from win10toast import ToastNotifier
toaster = ToastNotifier()
toaster.show_toast("Hello World!!!",
"Python is 10 seconds awsm!",
icon_path="custom.ico",
duration=10)
I am getting below error :
File "C:\Users\jnp\AppData\Local\Continuum\anaconda3\lib\site-packages\win10toast\__init__.py", line 83, in _show_toast
self.hwnd = CreateWindow(self.classAtom, "Taskbar", style,
AttributeError: 'ToastNotifier' object has no attribute 'classAtom'
What was causing this for me was creating multiple instances of ToastNotifier(). Reusing the same instance fixed the error.
As mentioned by #InAFlash, The classAtom is returning nothing and the reason is because there is already a registered notification. Messing with the source, I added an exception print to the except block as below:
try:
self.classAtom = RegisterClass(self.wc)
except Exception as e:
print(e)
I am running my notifications in threads and when the code comes across this point it prints out the below error:
(1410, 'RegisterClass', 'Class already exists.')
Looking through it I think I found a solution, though it kind of takes away from the idea of "spamming" the notifications. By adding to the self.wc.lpszClassName variable the title, it makes it a different notification. So overall the code should look something like this:
self.wc = WNDCLASS()
self.hinst = self.wc.hInstance = GetModuleHandle(None)
self.wc.lpszClassName = str(f"PythonTaskbar{title}") # must be a string
self.wc.lpfnWndProc = message_map # could also specify a wndproc.
try:
self.classAtom = RegisterClass(self.wc)
except Exception as e:
print(e)
This solution worked for my scenario so not sure if this is the best fix but I'm rolling with it.
Hope this helps.
Looks like the problem is with the source code itself.
if you see the image, if there is an exception happening at self.classAtom = RegisterClass(self.wc) they did not handle it which will leave classAtom variable not declared. That is the cause of your problem. So, to fix it, just make classAtom = "" or some thing. But, this wont actually fix it.
Considering the accepted answer might break more things down the line, I'll post this.
It is, as inAFlash mentioned in his comment, a dependency issue. Updating setuptools will fix the problem.
To do so, simply run: python -m pip install setuptools --upgrade

Python win32com CallNotImplementedError instead of AccessDenied?

This code:
import os
from win32com.shell import shell, shellcon
tempFile = os.path.join(os.path.abspath(os.path.curdir), u'_tempfile.tmp')
# print tempFile
dest = os.path.join('C:\Program Files', '_tempfile.tmp')
with open(tempFile, 'wb'): pass # create the file
try: # to move it into C:\Program Files
result, aborted = shell.SHFileOperation(
(None, # parent window
shellcon.FO_MOVE, tempFile, dest,
# 0,
shellcon.FOF_SILENT, # replace this with 0 to get a UAC prompt
None, None))
print result, aborted
except: # no exception raised
import traceback
traceback.print_exc()
Prints 120 False - 120 being CallNotImplementedError. If the flags are set to 0 then you get a UAC prompt as expected. Now why is not the result 5 (AccessDeniedError) ? Is something not implemented indeed or is it a bug or what do I not get ?
Needless to say that this was hard to debug - I was expecting an access denied and I had to look very closely to see what was wrong.
You're misreading the error code. SHFileOperation uses its own set of error codes separate from the system error codes; in this case, 0x78/120 is:
DE_ACCESSDENIEDSRC: Security settings denied access to the source.
That doesn't seem like it's the likely error (the destination is the problem), but this function is deprecated (replaced in Vista by IFileOperation) and while it still exists in Vista+, they may not have been particularly careful about returning entirely accurate error codes for situations (like UAC) that didn't exist pre-Vista.
Per the docs:
These are pre-Win32 error codes and are no longer supported or defined in any public header file. To use them, you must either define them yourself or compare against the numerical value.
These error codes are subject to change and have historically done so.
These values are provided only as an aid in debugging. They should not be regarded as definitive.

Is there a way to decode numerical COM error-codes in pywin32

Here is part of a stack-trace from a recent run of an unreliable application written in Python which controls another application written in Excel:
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)
Obviously something has gone wrong ... but what?[1] These COM error codes seem to be excessively cryptic.
How can I decode this error message? Is there a table somewhere that allows me to convert this numerical error code into something more meaningful?
[1] I actually know what went wrong in this case, it was attempting to access a Name prperty on a Range object which did not have a Name property... not all bugs are this easy to find!
You are not doing anything wrong. The first item in your stack trace (the number) is the error code returned by the COM object. The second item is the description associated with the error code which in this case is "Exception Occurred". pywintypes.com_error already called the equivalent of win32api.FormatMessage(errCode) for you. We'll look at the second number in a minute.
By the way, you can use the "Error Lookup" utility that comes in Visual Studio (C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\ErrLook.exe) as a quick launching pad to check COM error codes. That utility also calls FormatMessage for you and displays the result. Not all error codes will work with this mechanism, but many will. That's usually my first stop.
Error handling and reporting in COM is a bit messy. I'll try to give you some background.
All COM method calls will return a numeric code called an HRESULT that can indicate success or failure. All forms of error reporting in COM build on top of that.
The codes are commonly expressed in hex, although sometimes you will see them as large 32-bit numbers, like in your stack trace. There are all kinds of predefined return codes for common results and problems, or the object can return custom numeric codes for special situations. For example, the value 0 (called S_OK) universally means "No error" and 0x80000002 is E_OUTOFMEMORY. Sometimes the HRESULT codes are returned by the object, sometimes by the COM infrastructure.
A COM object can also choose to provide much richer error information by implementing an interface called IErrorInfo. When an object implements IErrorInfo, it can provide all kinds of detail about what happened, such as a detailed custom error message and even the name of a help file that describes the problem. In VB6 and VBA. the Err object allows you to access all that information (Err.Description, etc).
To complicate matters, late bound COM objects (which use a mechanism called COM Automation or IDispatch) add some layers that need to be peeled off to get information out. Excel is usually manipulated via late binding.
Now let's look at your situation again. What you are getting as the first number is a fairly generic error code: DISP_E_EXCEPTION. Note: you can usually figure out the official name of an HRESULT by googling the number, although sometimes you will have to use the hex version to find anything useful.
Errors that begin with DISP_ are IDISPATCH error codes. The error loosely means "There was a COM exception thrown by the object", with more information packed elsewhere (although I don't quite know where; I'll have to look it up).
From what I understand of pywintypes.com_error, the last number in your message is the actual error code that was returned by the object during the exception. It's the actual numeric code that you would get out of VBA's Err.Number.
Unfortunately, that second code -2146788248 (0x800A9C68) is in the range reserved for custom application-defined error messages (in VBA: VbObjectError + someCustomErrorNumber), so there is no centralized meaning. The same number can mean entirely different things for different programs.
In this case, we have reached a dead end:
The error code is "custom", and the application needs to document what it is, except that Excel doesn't. Also, Excel (or the actual source of the error) doesn't seem to be providing any more information via IErrorInfo.
Excel is notorious (to me at least) for cryptic error codes from automation and obscure situations that cause them. This is especially so for errors that one could consider "design-time errors" ("you should have known better than calling a method that doesn't exist in the object"). Instead of a nice "Could not read the Name property", you get "Run-time error '1004': Application defined or object-defined error" (which I just got by trying to access a Name property on a Range, from VBA in Excel). That is NOT very helpful.
The problem is not routed on Python or it's interface to Excel. Excel itself doesn't explain what happened, even to VBA.
However, the general procedure above remains valid. If you get an error from Excel in the future, you might get a better error message that you can track the same way.
Good luck!
Do it like this:
try:
[whatever code]
except pythoncom.com_error as error:
print(win32api.FormatMessage(error.excepinfo[5]))
More information on digesting the pythoncom.com_error object here: https://web.archive.org/web/20170831073447/http://docs.activestate.com/activepython/3.2/pywin32/com_error.html
Yes try the win32api module:
import win32api
e_msg = win32api.FormatMessage(-2147352567)
You can grab any codes returned from the exception and pass them to FormatMessage. Your example had 2 error codes.
Specifically for pythoncom, the errors codes that result are more than cryptic. This is because pythoncom represents them internally as a 32bit signed integer, when the correct representation is a 32bit unsigned integer. As a result, the conversion that you end up seeing in the stack trace is incorrect.
In particular, your exception, according to pythoncom, is -2147352567, and your (for lack of a better word) Err.Number is -2146788248.
This however causes some issues when watching for specific errors, like below:
DISP_E_EXCEPTION = 0x80020009
#...
#except pywintypes.com_error as e:
# print repr(e)
# #pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)
# hr = e.hresult
hr = -2147352567
if hr == DISP_E_EXCEPTION:
pass #This never occurs
else:
raise
To see why this has issues, lets look into these error codes:
>>> DISP_E_EXCEPTION = 0x80020009
>>> DISP_E_EXCEPTION
2147614729L
>>> my_hr = -2147352567
>>> my_hr == DISP_E_EXCEPTION
False
Again, this is because python sees the constant declared as positive, and pythoncom's incorrect declaration interpreted it as negative. Of course, the most obvious solution fails:
>>> hex(my_hr)
'-0x7ffdfff7'
The solution is to properly interpret the number. Luckily, pythoncom's representation is reversible. We need to interpret the negative number as a 32 bit signed integer, then interpret that as an unsigned integer:
def fix_com_hresult(hr):
import struct
return struct.unpack("L", struct.pack("l", hr))[0]
>>> DISP_E_EXCEPTION = 0x80020009
>>> my_hr = -2147352567
>>> my_hr == DISP_E_EXCEPTION
False
>>> fixed_hr = fix_com_hresult(my_hr)
>>> fixed_hr
2147614729L
>>> fixed_hr == DISP_E_EXCEPTION
True
So, putting it all together, you need to run fix_com_hresult() on that result from pythoncom, essentially all the time.
Since normally you need to do this when checking for exceptions, I created these functions:
def fix_com_exception(e):
e.hresult = fix_com_hresult(e.hresult)
e.args = [e.hresult] + list(e.args[1:])
return e
def fix_com_hresult(hr):
import struct
return struct.unpack("L", struct.pack("l", hr))[0]
which can then be used how you expect:
DISP_E_EXCEPTION = 0x80020009
try:
#failing call
except pywintypes.com_error as e:
print repr(e)
#pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)
fix_com_exception(e)
print repr(e)
#pywintypes.com_error: (2147614729L, 'Exception occurred.', (0, None, None, None, 0, -2146788248), None)
if e.hresult == DISP_E_EXCEPTION:
print "Got expected failure"
else:
raise
I was unable to find a MSDN document listing all HRESULTs, but I found this: http://www.megos.ch/support/doserrors_e.txt
Also, since you have it, fix_com_hresult() should also be run on your extended error code (-2146788248), but as Euro Micelli said, it doesn't help you in this particular instance :)
No-one has yet mentioned the strerror attribute of the pywintypes.com_error Exception. This returns the result of FormatMessage for the error code. So instead of doing it yourself like this
try:
[whatever code]
except pythoncom.com_error as error:
print(win32api.FormatMessage(error.excepinfo[5]))
You can just do this:
try:
[whatever code]
except pythoncom.com_error as error:
print(error.strerror)
Note it will return None if you have a non-standard HRESULT :(

Categories