UNC Path With Python Subprocess_checkCall - python

I have a python program which in turn calls an R script for doing some calculations. This worked great till I switched over to UNC. I am on Windows and I tried all that has been suggested on StackOverflow but I still keep getting an error saying "base package can't be opened"
I have tried with backward slashes meaning on the lines of \\server/abc/a.exe etc as well as \\server\abc\a.exe
What am I missing? It seems the problem is that the executable can't have a UNC path , in this case the variable rscriptpath. I really need that to be a UNC as the caller program would not in the same server. Thanks in advance.
import subprocess
Date='2018-03-01'
env='PROD'
main_dir=r'\\sandbox0968\QRMPortfolioRisk\QRMPortfolioRisk'
rscriptpath = r'\\sandbox0968\bin\Rscript.exe'
dailymain = r'\\sandbox0968\QRMPortfolioRisk\QRMPortfolioRisk\src\daily\DailyMain_cmd.R'
dailymainstatic = r'\\sandbox0968\QRMPortfolioRisk\QRMPortfolioRisk\src\daily\DailyMainStatic.R'
cxo_script = r'\\sandbox0968\QRMPortfolioRisk\QRMPortfolioRisk\src\daily\CXOdump.R'
calc_dir = r'\\sandbox0968\QRMPortfolioRisk\QRMPortfolioRisk\data\calculations'
reestimate = r'\\sandbox0968\QRMPortfolioRisk\QRMPortfolioRisk\src\estimation\EstimationMain_cmd.R'
#
subprocess.check_call([rscriptpath, '--vanilla', dailymain, str(Date), str(main_dir), env])

Related

ReceivedTime of the mail is not showing in python

I am trying to read my mail and see the received time in outlook 2016 using MAPI.
I am able to see the subject of the mail not able to see the receivedTime of the mail. I know that "Receivedtime" is there to get the received time of the mail, but while the program is executed,
a popup is coming, telling that python has stopped working
I know it is not due to any machine problem rather some problem in my code.
Here is my code.
def arrange(mailbox):
global spam
timeperiod() # stores required date in spam[] list
msgs=mailbox.Items
msgs.Sort("[ReceivedTime]", True)
p=msgs.restrict(" [ReceivedTime] >= '"+spam[2]+"'") #and [ReceivedTime] >= '" +spam[1]+"'
print(len(p))
'''
for m in list1:
if m.Unread:
m.Unread=False
'''
return p
#Calling it
ctm1=arrange(ctm)
print(len(ctm1)) #Working fine
for message in ctm1:
print (message.subject) #Also works good
print (message.receivedTime) # Here is the problem, it's not showing
]1
i have tried Senton property as well, but it's not working . So any guesses why the senton or receivedTime properties are not working???
updated code :
def printlist(box1) :
print(len(box1))
for message in box1:
if message.Class==43 :
# print('true')
print (message)
#.senderEmailAddress) #working
#print(message.SentOn.strftime("%d-%m-%y")) #not working
#print(message.body)
#print(message.UnRead)
#print (message.receivedTime) #not working
#print('-----------')
I was also having trouble with the .ReceivedTime breaking the program when I compile the .py script to an .exe using auto-py-to-exe.
Here's where the error occurs underneath this try: statement
try:
received_year = str(email.ReceivedTime)[0:4]
received_month = str(email.ReceivedTime)[5:7]
received_day = str(email.ReceivedTime)[8:10]
This works PERFECTLY well inside of my IDE (PyCharm), but once I've compiled it to .exe, it breaks here.
I've updated pywin32 to the most up-to-date version (228) and also tried using 224 to see if it was a version issue (it wasn't).
BUT!! Going through this, I FOUND THE BUG! When you compile to .exe with auto-py-to-exe, it does not include the package "win32timezone" which the .ReceivedTime portion needs to run correctly. So you need to import this package for it to work.
All you have to do to fix this is include this at the top of your .py script before compiling to .exe:
import win32timezone
Let me know if this works for anyone else facing this issue!
Most likely you run into an item other than MailItem - you can also have ReportItem and MeetingItem objects in your Inbox; none of them expose the ReceivedTime property.
Check that message.Class property == 43 (olMail) before accessing any other MailItem specific properties.
Please try the below:
print([x.ReceivedTime for x in messages])

Get full computer name from a network drive letter in python

I am using python to populate a table with the file pathways of a number of stored files. However the pathway needs to have the full network drive computer name not just the drive letter, ie
//ComputerName/folder/subfolder/file
not
P:/folder/subfolder/file
I have investigated using the win32api, win32file, and os.path modules but nothing is looking like its able to do it. I need something like win32api.GetComputerName() but with the ability to drop in a known drive letter as an argument and it return the computer name that is mapped to the letter.
So is there anyway in python to look up a drive letter and get back the computer name?
Network drives are mapped using the Windows Networking API that's exported by mpr.dll (multiple provider router). You can create a network drive via WNetAddConnection2. To get the remote path that's associated with a local device, call WNetGetConnection. You can do this using ctypes as follows:
import ctypes
from ctypes import wintypes
mpr = ctypes.WinDLL('mpr')
ERROR_SUCCESS = 0x0000
ERROR_MORE_DATA = 0x00EA
wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
mpr.WNetGetConnectionW.restype = wintypes.DWORD
mpr.WNetGetConnectionW.argtypes = (wintypes.LPCWSTR,
wintypes.LPWSTR,
wintypes.LPDWORD)
def get_connection(local_name):
length = (wintypes.DWORD * 1)()
result = mpr.WNetGetConnectionW(local_name, None, length)
if result != ERROR_MORE_DATA:
raise ctypes.WinError(result)
remote_name = (wintypes.WCHAR * length[0])()
result = mpr.WNetGetConnectionW(local_name, remote_name, length)
if result != ERROR_SUCCESS:
raise ctypes.WinError(result)
return remote_name.value
For example:
>>> subprocess.call(r'net use Y: \\live.sysinternals.com\tools')
The command completed successfully.
0
>>> print(get_connection('Y:'))
\\live.sysinternals.com\tools
I think you just need to look at more of pywin32... As you can see here, there is already an API that converts local drive names to full UNC paths.
For completeness, here is some code that works for me.
import win32wnet
import sys
print(win32wnet.WNetGetUniversalName(sys.argv[1], 1))
And this gives me something like this when I run it:
C:\test>python get_unc.py i:\some\path
\\machine\test_share\some\path
you could run net use and parse the output.
i am posting this from my mobile but i am going to improve this answer when i am in front of a real computer.
here are some links, that can help in the meantime:
https://docs.python.org/2/library/subprocess.html#module-subprocess.
https://technet.microsoft.com/en-us/library/gg651155.aspx.
My answer to a similar question:
Here's how to do it in python ≥ 3.4, with no dependencies!*
from pathlib import Path
def unc_drive(file_path):
return str(Path(file_path).resolve())
*Note: I just found a situation in which this method fails. One of my company's network shares has permissions setup such that this method raises a PermissionError. In this case, win32wnet.WNetGetUniversalName is a suitable fallback.
If you just need the hostname, you can use the socket module:
socket.gethostname()
or you may want to use the os module:
os.uname()[1]
os.uname() returns a 5 tuple that contains (sysname, nodename, release, version, machine)

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.

why does python's win32gui.SendMessageTimeout fail and delete most of my Environment Variables?

This code snippet is very standard: (you'll find it on many sites)
rc, dwReturnValue = win32gui.SendMessageTimeout(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, "Environment", win32con.SMTO_ABORTIFHUNG, 5000 )
On one machine it deletes MOST, but not all, environment variables:
these variables get deleted : (and others)
Path
PYTHONPATH
VS100COMNTOOLS
windir
XEDK
When I say deleted, what I mean is that the originating shell has an intact environment, but all subsequent environment shells do NOT have these environment variables, which to say the least, is 'somewhat' bothersome.
I have tried this code on at least 4 other machines, and there are no problems. The code works perfectly.
On the one problematic machine, a log off/log on seems to solve the problem, (and reinstate the missing env vars)
I have researched a lot on the almighty google and found nothing on errors with the method win32gui.SendMessageTimeout
Only found threads on people not invoking the method correctly. (perhaps this thread will join those ranks! :) )
I have been running spy++ (I'm a spy++ noob) and can see that the WM_SETTINGCHANGE Message is being received correctly by a few different windows on the problematic machine.
print str(rc),"<- return code"
print str(dwReturnValue), "<- return value"
yields
1 <- return code
0 <- return value
Here is my setup:
OS - Windows 7
python 2.7.1
cywin 19.5
process is a
batch file (install.bat) (this sets %CYGWIN_ROOT%)
(...)
:BASH_INSTALL_SCRIPT
::write paths file that will be used to modify system paths
set PATH=%CYGWIN_ROOT%\bin;%PATH%
::call bash install sequence
"%BASH_EXE%" install.sh %CYGWIN_ROOT%\bin %*
install.sh snippet:
function setCygwinPath {
# Install script of Cygwin set CYGWIN_ROOT in current env variables.
setEnvVar "CYGWIN_PATH" $CYGWIN_ROOT
}
function setEnvVar {
"$PythonRoot/python.exe" ../utils/${project}/setEnvVar.py $1 $2
(...) }
setEnvVar.py
from install.installUtils import *
setUserEnvVar( sys.argv[1], sys.argv[2])
installUtils.py
def setUserEnvVar( varName, content, type=wreg.REG_EXPAND_SZ, override=0 ):
""" Set the specified environment variable """
setEnvVarAndBroadcast( wreg.HKEY_CURRENT_USER, getUserEnvKey(), varName, content, type, override )
def setEnvVarAndBroadcast( domain, regKey, varName, content, type=wreg.REG_EXPAND_SZ, override=0 ):
""" Set an environment variable and broadcast to opened application """
if override == 0 :
# If the variable exist reuse its current type
varInfo = getEnvVarEx( domain, regKey, varName )
if varInfo[0] <> "" :
type = varInfo[1]
key = wreg.OpenKey(domain, regKey, 0, wreg.KEY_WRITE )
wreg.SetValueEx( key, varName, 0, type, content)
wreg.CloseKey( key )
HWND_BROADCAST = 0xffff
WM_SETTINGCHANGE = 0x001A
SMTO_ABORTIFHUNG = 0x0002
rc, dwReturnValue = win32gui.SendMessageTimeout(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, "Environment", win32con.SMTO_ABORTIFHUNG, 5000 )
I have isolated absolutely that the call win32gui.SendMessageTimeout is what disrupts the machine's environment variables.
This code was previously working on this machine, until a week ago (no idea what has changed; I would say nothing,
questions:
This seems like a bit of an exploit...... am i wrong?
I'm not really sure what to investigate anymore, so I would welcome a solution (obviously) but even an idea for investigation would be welcome. I have only win32gui.pyd (no sources) on the machine in question.
The machine goes from having 73 Environment Variables to 46 ( c:> set ). A lot of them are user installed applications, but some are System (like PATH, windir).

In Python, how do I check if a drive exists w/o throwing an error for removable drives?

Here's what I have so far:
import os.path as op
for d in map(chr, range(98, 123)): #drives b-z
if not op.isdir(d + ':/'): continue
The problem is that it pops up a "No Disk" error box in Windows:
maya.exe - No Disk: There is no disk in
the drive. Please insert a disk into
drive \Device\Harddisk1\DR1 [Cancel, Try Again, Continue]
I can't catch the exception because it doesn't actually throw a Python error.
Apparently, this only happens on removable drives where there is a letter assigned, but no drive inserted.
Is there a way to get around this issue without specifically telling the script which drives to skip?
In my scenario, I'm at the school labs where the drive letters change depending on which lab computer I'm at. Also, I have zero security privileges to access disk management.
Use the ctypes package to access the GetLogicalDrives function. This does not require external libraries such as pywin32, so it's portable, although it is a little clunkier to work with. For example:
import ctypes
import itertools
import os
import string
import platform
def get_available_drives():
if 'Windows' not in platform.system():
return []
drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
return list(itertools.compress(string.ascii_uppercase,
map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
itertools.compress was added in Python 2.7 and 3.1; if you need to support <2.7 or <3.1, here's an implementation of that function:
def compress(data, selectors):
for d, s in zip(data, selectors):
if s:
yield d
Here's a way that works both on Windows and Linux, for both Python 2 and 3:
import platform,os
def hasdrive(letter):
return "Windows" in platform.system() and os.system("vol %s: 2>nul>nul" % (letter)) == 0
If you have the win32file module, you can call GetLogicalDrives():
def does_drive_exist(letter):
import win32file
return (win32file.GetLogicalDrives() >> (ord(letter.upper()) - 65) & 1) != 0
To disable the error popup, you need to set the SEM_FAILCRITICALERRORS Windows error flag using pywin:
old_mode = win32api.SetErrorMode(0)
SEM_FAILCRITICALERRORS = 1 # not provided by PyWin, last I checked
win32api.SetErrorMode(old_mode & 1)
This tells Win32 not to show the retry dialog; when an error happens, it's returned to the application immediately.
Note that this is what Python calls are supposed to do. In principle, Python should be setting this flag for you. Unfortunately, since Python may be embedded in another program, it can't change process-wide flags like that, and Win32 has no way to specify this flag in a way that only affects Python and not the rest of the code.
As long as a little parsing is acceptable, this is one way to do it without installing win32api and without iterating through all possible drive letters.
from subprocess import check_output
def getDriveLetters():
args = [
'wmic',
'logicaldisk',
'get',
'caption,description,providername',
'/format:csv'
]
output = check_output(args)
results = list()
for line in output.split('\n'):
if line:
lineSplit = line.split(',')
if len(lineSplit) == 4 and lineSplit[1][1] == ':':
results.append(lineSplit[1][0])
return results
You could also parse for specific drive types, such as "Network Connection" to get a list of all network mounted drive letters by adding and lineSplit[2] == 'Network Connection' for example.
Alternatively, rather than returning a list, you could return a dictionary, where keys are drive letters and values are unc paths (lineSplit[3]). Or whatever other info you want to pull from wmic. To see more options: wmic logicaldisk get /?
import os
possible_drives_list = [chr(97 + num).upper() for num in range(26)]
for drive in possible_drives_list:
print(drive + ' exists :' + str(os.path.exists(drive + ':\\')))
import os
def IsDriveExists(drive):
return os.path.exists(drive + ':\\')
print(IsDriveExists('c'))
print(IsDriveExists('d'))
print(IsDriveExists('e'))
print(IsDriveExists('x'))
print(IsDriveExists('v'))
this works in any os

Categories