Properly Implement Shutil.Error in Python - python-3.x

I'm learning Python 3 and trying to write a script that will copy a directory. I'm using shutil.copytree. From the Python documentation it says:
If exception(s) occur, an Error is raised with a list of reasons.
This exception collects exceptions that are raised during a multi-file
operation. For copytree(), the exception argument is a list of
3-tuples (srcname, dstname, exception).
In the example they do this:
except Error as err:
errors.extend(err.args[0])
Here is my script:
def copyDirectory(src, dest):
errors = []
try:
shutil.copytree(src, dest)
except Error as err:
errors.extend(err.args[0])
source="C:/Users/MrRobot/Desktop/Copy"
destination="C:/Users/MrRobot/Desktop/Destination"
copyDirectory(source, destination)
moveDirectory(destination,"I:/")
Questions:
How do you properly catch an exception that might occur when using shutil.copytree (assuming my above script is incorrect)?
How then would you view the errors that occurred, would I loop through the errors array?

You need to either include the module name when you catch the exception:
except shutil.Error as err:
Or import it explicitly:
from shutil import copytree, Error
# the rest of your code...
try:
copytree(src, dest)
except Error as err:
errors.extend(err.args[0])
To view the traceback and exception information, you have a few options:
Don't catch the exception. Your script will be halted and all the error information will be printed.
If you want the script to continue, then you're really asking a duplicate of this SO question. I would reference that question; the accepted answer is written very well.
And by the way, you should avoid calling it an array. This particular exception object has a list of tuples, and arrays are an entirely different data structure.

You can use OSError to handle it :
import shutil
def removeDirectory(directory):
try:
shutil.rmtree(directory)
except OSError as err:
print(err)
removeDirectory('PathOfDirectoryThatDoesntExist')
OUTPUT :
[Errno 2] No such file or directory:
'./PathOfDirectoryThatDoesntExist'

Related

How to handle different types of OSErros in Python

So I was coding in a little personal project and I got this problem.
In my code I'm using the basic to open a file.
try:
open(file_name, mode="r", encoding="utf-8")
except Exception as error:
print("Error while opening/reading the file")
sys.exit(1)
But i want to be able to know if the error is because the file doesn't exists or if I don't have permission to read the file, I don't want to use any string comparison to know that and just wanted to use the Python exceptions to do it.
Looking in the documentation I was able to find that the exception type thrown by open() is a OSError and with that you can have multiple exceptions inside this exception (https://docs.python.org/3/library/exceptions.html#OSError), and here is my question, how can I define it inside a try/except if the error is due to low permission or if the file doesn't exists.
You can handle multiple different exceptions by adding additional except blocks:
try:
with open(file_name, mode="r", encoding="utf-8") as handle:
handle.read()
except FileNotFoundError:
print("file not found")
except PermissionError:
print("insufficient permissions to open file")
except Exception as ex:
print("something else went wrong", ex)
On a general note, you should use the with statement when opening a file to make sure the handle gets released when you're done.

I am unable to catch a ValueError exception, tried everything I know and still failing

I am trying to cast a user input into an integer value in a try-block. If a ValueError is raised then print an error message and retry the while loop to get a new input. If a valid input is received then a break kicks the user our of the while loop and the value is returned.
However, every time I run the code in any variation, a ValueError is raised and the program stops. Literally, the exact exception I am catching is being raised and causing the program to crash.
def size_chooser(self):
while True:
cprint("Enter page size", color='red')
user_input_value = input("---> ")
if user_input_value == 'quit':
val = None
break
else:
try:
val = int(user_input_value)
break
except ValueError:
print("this exception block is working, try again")
return val
The exact error message I get is:
Exception has occurred: ValueError
invalid literal for int() with base 10: 'w'
What am I doing wrong, please help. Could it be a Visual Studio problem? I am using Visual Studio and everything works great in it except a niggling issue of importing outside the current folder failing. Only way around is to manually append to sys.path, which is not ideal but that's the only way I was able to import from across my sibling folders.

Python: Passing exceptions out of a contextmanager into a higher-level try/except block

I'm using the output suppression contextmanager described in charleslparker's answer to this question: How to suppress console output in Python? - this works beautifully, but it's nested in a larger block of code (snippet below) dedicated to downloading files from a specific website, which utilizes a higher-level try/except block to catch connection errors. This should be simple, as described in a_guest's beautiful answer to this similar question: Catching an exception while using a Python 'with' statement - however, my problem is that I have an extra block of code (specifically, checking for matching file sizes locally and on the website) that needs to execute upon successful completion of the download, which is getting called every time the ConnectionError exception is raised. Basically, the exception registered within the contextmanager does not propagate upwards correctly, and the code deletes the partial files before restarting the process. I want the exception encountered by the download within the context manager to skip straight to the explicit exception block, and I am totally stuck on how to force that.
#contextmanager
def suppress_stdout():
with open(os.devnull, "w") as devnull:
old_stdout = sys.stdout
sys.stdout = devnull
try:
yield
except (ConnectionErrorType1, ConnectionErrorType2):
raise ConnectionError()
finally:
sys.stdout = old_stdout
while True:
try:
with suppress_stdout():
<download from the website>
if check_file_sizes:
<get target file size>
if download_size != target_size:
<delete files and try again>
except ConnectionErrorType1:
<print error-specific message>
raise ConnectionError()
except ConnectionErrorType2:
<print error-specific message>
raise ConnectionError()
except:
print("Something happened but I don't know what")
raise ConnectionError()
Any and all insight is appreciated, and I'm happy to provide further context or clarification as needed.

How do I handle an error despite the code is in a try block

I put my block of code that I know is generating the error in a try block but I still keep getting a KeyError error. I know the reason for getting this error is that sometimes the dataframe is empty
try:
df = df.groupby(by='col1')['col2'].agg(total = 'sum').reset_index()
except KeyError:
raise Exception from None
Why am I still getting an error message when I have already put my code in a try block. How do I get around this?
Change:
except KeyError:
raise Exception from None
to:
except KeyError as e:
print(e)
See what happens. Problem could be you have an exception within an exception.

get function call stack from exception

When a python function fails, we get a traceback listing filenames, lines, and function calls.
Is there anyway, within an except block, to pull out only these function names? I would just like a list of the successive calls that lead to the failure.
I have looked at the traceback library and have run dir() on my exception, but I don't see anything.
I took one last look at the traceback documentation and figured it out.
First, use traceback.extract_tb() to get the StackSummary. This is a list of FrameSummary objects, which themselves are tuples whose third value is the function name. In full:
try:
some_function()
except Exception as e:
tb = traceback.extract_tb(e.__traceback__)
for frame in tb:
print(frame[2])
output will be something like
<module>
some_function
another_func_called_by_some_function
...

Resources