I am trying to delete a collection of folders on my drive. These directories are not empty. I have come up with a solution as follows:
import shutil
import os
path = "main/"
folderList = ['Blah', 'Blah', 'Blah'];
print ("Cleaning Project at %s" % path)
for c in folderList:
strippedPath = (path + c).strip("\n")
print ("Cleaning path " + strippedPath)
if os.path.exists(strippedPath):
try:
shutil.rmtree(strippedPath)
except OSError as why:
pass
print ("Done Cleaning Project")
The problem is that without the try / catch I get a error that says
PermissionError: [WinError 5] Access is denied: 'PathToFileHere'
Pressing the delete key on windows will work fine. Can someone provide me a command that will remove this directory without errors?
First you should avoid to silently swallow an Exception, but at least print or log it. But many thing can happen to a file, they may have Hidden, System or ReadOnly attributes. The current user may not have permissions on files but only on the containing folder. As Python is multi-platform its high-level commands can be less optimized for a particular OS (Windows in your case) than native ones.
You should first try to confirm that in a cmd window, the command rd /s folder correctly remove the folder that shutil.rmtree fails to delete, and if yes ask python so execute it vie the subprocess module :
subprocess.call("rd /s/q " + strippedPath)
Related
I am using shutil to move a folder that contains a bunch of stuff my program was using right before I give the move command. Everything I care about has been unloaded from memory at this point so every single file is successfully moved to the target folder as expected. Cryptically, a problematic subfolder remains behind (even though one like it is created at the target location) and the program throws the following error:
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process:
'C:\\Users\\Ze\\PycharmProjects\\Ploutos\\ProductList\\Unedited\\1005001769427465\\Images'
The folder I am moving is the number ID one, which contains the problematic 'Images' folder.
Edit: As far as I can tell no program other than my own and Pycharm is using the folder. Could it be Pycharm when it attempts to re-index the file?
Relevant code:
def move_product_to_edited(product_id):
global products_edited_during_session_counter
unedited_products_path = application_path + '\\ProductList\\Unedited\\'
edited_products_path = application_path + '\\ProductList\\Edited\\'
# if the product has not yet been moved, move it
if os.path.exists(unedited_products_path + str(product_id)):
shutil.move(unedited_products_path + str(product_id), edited_products_path + str(product_id))
How can I try to further debug this? I have no idea how to check why the folder is still in use.
I'm trying to copy the entire folder config under c:\windows\system32 and it copies some of the files that are not being used by another process and the rest get failed due to permission as it says. I run the code under admin privileges but still not copying SAM,SYSTEM,SECURITY ..etc.
It isn't a windows thing as I have applied this code on 3 machines with admin privileges and all of them have the same issues. is there any way to get around this issue?
Here is the code:
def copyDirectory():
try:
path = "C:\\Windows\\System32\\config"
dest = "Event"
shutil.copytree(path, dest)
except shutil.Error as e:
print('Directory not copied. Error: %s' % e)
except OSError as e:
print('Directory not copied. Error: %s' % e)
I would try to right click the parent folder, chose properties, go to Security tab, then make sure the user account you are trying to use to make changes has the write permissions. May as well just try giving your user account all of the available permissions while there.
As I have read somewhere else, you may need to also verify under General tab of properties that the folder is not 'read-only'.
If it is a shared folder, then under Sharing tab of properties, click "Advanced Sharing", the "Permissions", then add proper user account permissions there.
I'm writing a code in Python, in which I check if a certain folder exists; if it does, I remove it and create a new one (with the same name). The code is as follows:
if os.path.exists(output_folder):
shutil.rmtree(output_folder)
os.makedirs(output_folder)
This code works fine, accept for when I have that specific output_folder open with the windows explorer. When it's open, I get the following error in my code:
WindowsError: [Error 5] Access is denied: [foldername]
Simultaneously, windows explorer switches itself to foldername's parent directory, and throws an error.
Is there a way to make python ignore the error and continue running, or am I asking for something that is impossible due to the system?
I tried using shutil.rmtree(output_folder, ignore_errors=True) but it didn't change anything.
You can use Python's exception handling to catch the error. You would also probably benefit from a short delay before creating the folder again to give Windows Explorer a chance to close:
import shutil
import time
try:
shutil.rmtree(output_folder)
except WindowsError as e:
print("Failed to delete") # Or just pass
time.sleep(0.5)
os.makedirs(output_folder)
I've figured out how to use call() to get my python script to run a command:
import subprocess
mycommandline = ['lumberjack', '-sleep all night', '-work all day']
subprocess.call(mycommandline)
This works but there's a problem, what if users don't have lumberjack in their command path? It would work if lumberjack was put in the same directory as the python script, but how does the script know it should look for lumberjack? I figured if there was a command-not-found error then lumberjack wouldn't be in the command path, the script could try to figure out what its directory is and look for lumberjack there and finally warn the user to copy lumberjack into one of those two places if it wasn't found in either one. How do I find out what the error message is? I read that check_call() can return an error message and something about a returncode attribute. I couldn't find examples on how to use check_call() and returncode, what the message would be or how I could tell if the message is command-not-found.
Am I even going about this the right way?
A simple snippet:
try:
subprocess.check_call(['executable'])
except subprocess.CalledProcessError:
pass # handle errors in the called executable
except OSError:
pass # executable not found
subprocess will raise an exception, OSError, when a command is not found.
When the command is found, and subprocess runs the command for you, the result code is returned from the command. The standard is that code 0 means success, and any failure is some non-zero error code (which varies; check the documentation for the specific command you are running).
So, if you catch OSError you can handle the non-existent command, and if you check the result code you can find out whether the command succeeded or not.
The great thing about subprocess is that you can make it collect all the text from stdout and stderr, and you can then discard it or return it or log it or display it as you like. I often use a wrapper that discards all output from a command, unless the command fails in which case the text from stderr is output.
I agree that you shouldn't be asking users to copy executables around. Programs should be in a directory listed in the PATH variable; if a program is missing it should be installed, or if it is installed in a directory not on the PATH the user should update the PATH to include that directory.
Note that you do have the option of trying subprocess multiple times with various hard-coded paths to executables:
import os
import subprocess as sp
def _run_cmd(s_cmd, tup_args):
lst_cmd = [s_cmd]
lst_cmd.extend(tup_args)
result = sp.call(lst_cmd)
return result
def run_lumberjack(*tup_args):
try:
# try to run from /usr/local/bin
return _run_cmd("/usr/local/bin/lumberjack", tup_args)
except OSError:
pass
try:
# try to run from /opt/forest/bin
return _run_cmd("/opt/forest/bin/lumberjack", tup_args)
except OSError:
pass
try:
# try to run from "bin" directory in user's home directory
home = os.getenv("HOME", ".")
s_cmd = home + "/bin/lumberjack"
return _run_cmd(s_cmd, tup_args)
except OSError:
pass
# Python 3.x syntax for raising an exception
# for Python 2.x, use: raise OSError, "could not find lumberjack in the standard places"
raise OSError("could not find lumberjack in the standard places")
run_lumberjack("-j")
EDIT: After thinking about it a little bit, I decided to completely rewrite the above. It's much cleaner to just pass a list of locations, and have a loop try the alternative locations until one works. But I didn't want to build the string for the user's home directory if it wasn't needed, so I just made it legal to put a callable into the list of alternatives. If you have any questions about this, just ask.
import os
import subprocess as sp
def try_alternatives(cmd, locations, args):
"""
Try to run a command that might be in any one of multiple locations.
Takes a single string argument for the command to run, a sequence
of locations, and a sequence of arguments to the command. Tries
to run the command in each location, in order, until the command
is found (does not raise OSError on the attempt).
"""
# build a list to pass to subprocess
lst_cmd = [None] # dummy arg to reserve position 0 in the list
lst_cmd.extend(args) # arguments come after position 0
for path in locations:
# It's legal to put a callable in the list of locations.
# When this happens, we should call it and use its return
# value for the path. It should always return a string.
if callable(path):
path = path()
# put full pathname of cmd into position 0 of list
lst_cmd[0] = os.path.join(path, cmd)
try:
return sp.call(lst_cmd)
except OSError:
pass
raise OSError('command "{}" not found in locations list'.format(cmd))
def _home_bin():
home = os.getenv("HOME", ".")
return os.path.join(home, "bin")
def run_lumberjack(*args):
locations = [
"/usr/local/bin",
"/opt/forest/bin",
_home_bin, # specify callable that returns user's home directory
]
return try_alternatives("lumberjack", locations, args)
run_lumberjack("-j")
Wow, that was fast! I combined Theodros Zelleke's simple example and steveha's use of functions with abarnert comment about OSError and Lattyware's comment about moving files:
import os, sys, subprocess
def nameandpath():
try:
subprocess.call([os.getcwd() + '/lumberjack'])
# change the word lumberjack on the line above to get an error
except OSError:
print('\nCould not find lumberjack, please reinstall.\n')
# if you're using python 2.x, change the () to spaces on the line above
try:
subprocess.call(['lumberjack'])
# change the word lumberjack on the line above to get an error
except OSError:
nameandpath()
I tested it on Mac OS-X (6.8/Snow Leopard), Debian (Squeeze) and Windows (7). It seemed to work the way I wanted it to on all three operating systems. I tried using check_call and CalledProcessError but no matter what I did, I seemed to get an error every time and I couldn't get the script to handle the errors. To test the script I changed the name from 'lumberjack' to 'deadparrot', since I had lumberjack in the directory with my script.
Do you see any problems with this script the way it's written?
This question already has answers here:
Deleting read-only directory in Python
(7 answers)
Closed 3 years ago.
I'm trying to have python delete some directories and I get access errors on them. I think its that the python user account doesn't have rights?
WindowsError: [Error 5] Access is denied: 'path'
is what I get when I run the script.
I've tried
shutil.rmtree
os.remove
os.rmdir
they all return the same error.
We've had issues removing files and directories on Windows, even if we had just copied them, if they were set to 'readonly'. shutil.rmtree() offers you sort of exception handlers to handle this situation. You call it and provide an exception handler like this:
import errno, os, stat, shutil
def handleRemoveReadonly(func, path, exc):
excvalue = exc[1]
if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
func(path)
else:
raise
shutil.rmtree(filename, ignore_errors=False, onerror=handleRemoveReadonly)
You might want to try that.
I've never used Python, but I would assume it runs as whatever user executes the script.
The scripts have no special user, they just run under the currently logged-in user which executed the script.
Have you tried checking that:
you are trying to delete a valid path? and that
the path has no locked files?
How are you running the script? From an interactive console session? If so, just open up a DOS command window (using cmd) and type 'whoami'. That is who you are running the scripts interactively.
Ok I saw your edits just now...why don't you print the path and check the properties to see if the user account running the scripts has the required privileges?
If whoami does not work on your version of Windows, you may use the environment variables like SET USERNAME and SET DOMAINNAME from your command window.
#ThomasH : another brick to the wall.
On unix systems, you have to ensure that parent directory is writeable too.
Here is another version :
def remove_readonly(func, path, exc):
excvalue = exc[1]
if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
# ensure parent directory is writeable too
pardir = os.path.abspath(os.path.join(path, os.path.pardir))
if not os.access(pardir, os.W_OK):
os.chmod(pardir, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO)
os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
func(path)
else:
raise
If the script is being run as a scheduled task (which seems likely for a cleanup script), it will probably run as SYSTEM. It's (unwise, but) possible to set permissions on directories so that SYSTEM has no access.
Simple solution after searching for hours is to check first if that folder actually exist!
GIT_DIR="C:/Users/...."
if os.path.exists(GIT_DIR):
shutil.rmtree(GIT_DIR)
This did the trick for me.