python module 4
python module 4
The first shutil.copy() call copies the file at C:\spam.txt to the folder C:\delicious. The
return value is the path of the newly copied file. Note that since a folder was specified as
the destination, the original spam.txt filename is used for the new, copied file’s filename.
The second shutil.copy() call also copies the file at C:\eggs.txt to the folder C:\delicious
but gives the copied file the name eggs2.txt.
Assuming a folder named eggs already exists in the C:\ directory, this shutil.move() calls
says, “Move C:\bacon.txt into the folder C:\eggs.” If there had been a bacon.txt file
already in C:\eggs, it would have been overwritten. Since it’s easy to accidentally
overwrite files in this way, you should take some care when using move().destination
path can also specify a filename. In the following example, the source file is moved and
renamed.
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs\\new_bacon.txt')
'C:\\eggs\\new_bacon.txt'
This line says, “Move C:\bacon.txt into the folder C:\eggs, and while you’re at it, rename
that bacon.txt file to new_bacon.txt.” Both of the previous examples worked under the
assumption that there was a folder eggs in the C:\ directory. But if there is no eggs folder,
then move() will rename bacon.txt to a file named eggs.
>>> shutil.move('C:\\bacon.txt', 'C:\\eggs')
'C:\\eggs'
Here, move() can’t find a folder named eggs in the C:\ directory and so assumes that
destination must be specifying a filename, not a folder. So the bacon.txt text file is
renamed to eggs
Finally, the folders that make up the destination must already exist, or else Python will
throw an exception. Enter the following into the interactive shell:
>>> shutil.move('spam.txt', 'c:\\does_not_exist\\eggs\\ham')
Traceback (most recent call last):
File "C:\Python34\lib\shutil.py", line 521, in move
os.rename(src, real_dst)
FileNotFoundError: [WinError 3] The system cannot find the path specified:
'spam.txt' -> 'c:\\does_not_exist\\eggs\\ham'
Be careful when using these functions in your programs! It’s often a good idea to first
run your program with these calls commented out and with print() calls added to show
the files that would be deleted.
import os
for filename in os.listdir():
if filename.endswith('.rxt'):
os.unlink(filename)
If you had any important files ending with .rxt, they would have been accidentally,
permanently deleted. Instead, you should have first run the program like this:
import os
for filename in os.listdir():
if filename.endswith('.rxt'):
#os.unlink(filename)
print(filename)
Now the os.unlink() call is commented, so Python ignores it. Instead, you will print the
filename of the file that would have been deleted. Running this version of the program
first will show you that you’ve accidentally told the program to delete .rxt files instead
of .txt files.
Here is an example program that uses the os.walk() function on the directory tree from
Figure
import os
for folderName, subfolders, filenames in os.walk('C:\\delicious'):
print('The current folder is ' + folderName)
for subfolder in subfolders:
print('SUBFOLDER OF ' + folderName + ': ' + subfolder)
for filename in filenames:
print('FILE INSIDE ' + folderName + ': '+ filename)
print('')
The os.walk() function is passed a single string value: the path of a
folder. You can use os.walk() in a for loop statement to walk a directory tree, much like
how you can use the range() function to walk over a range of numbers. Unlike range(),
the os.walk() function will return three values on each iteration through the loop:
1. A string of the current folder’s name
2. A list of strings of the folders in the current folder
3. A list of strings of the files in the current folder
Just like you can choose the variable name i in the code for i in range(10):, you can also
choose the variable names for the three values listed earlier. I usually use the names
foldername, subfolders, and filenames. When you run this program, it will output the
following:
The current folder is C:\delicious
SUBFOLDER OF C:\delicious: cats
SUBFOLDER OF C:\delicious: walnut
FILE INSIDE C:\delicious: spam.txt
The current folder is C:\delicious\cats
FILE INSIDE C:\delicious\cats: catnames.txt
FILE INSIDE C:\delicious\cats: zophie.jpg
The current folder is C:\delicious\walnut
SUBFOLDER OF C:\delicious\walnut: waffles
The current folder is C:\delicious\walnut\waffles
FILE INSIDE C:\delicious\walnut\waffles: butter.txt.
A ZipFile object has a namelist() method that returns a list of strings for all the files and
folders contained in the ZIP file. These strings can be passed to the getinfo() ZipFile
method to return a ZipInfo object about that particular file. ZipInfo objects have their
own attributes, such as file_size and compress_size in bytes, which hold integers of the
original file size and compressed file size, respectively. While a ZipFile object represents
an entire archive file, a ZipInfo object holds useful information about a single file in the
archive.
After running this code, the contents of example.zip will be extracted to C:\. Optionally,
you can pass a folder name to extractall() to have it extract the files into a folder other
than the current working directory. If the folder passed to the extractall() method does
not exist, it will be created. For instance, if you replaced the call at u with
exampleZip.extractall('C:\\delicious'), the code would extract the files from example.zip
into a newly created C:\delicious folder.
The extract() method for ZipFile objects will extract a single file from the ZIP file.
Continue the interactive shell example:
>>> exampleZip.extract('spam.txt')
'C:\\spam.txt'
>>> exampleZip.extract('spam.txt', 'C:\\some\\new\\folders')
'C:\\some\\new\\folders\\spam.txt'
>>> exampleZip.close()
The string you pass to extract() must match one of the strings in the list returned by
namelist()
This code will create a new ZIP file named new.zip that has the compressed contents of
spam.txt. Keep in mind that, just as with writing to files, write mode will erase all
existing contents of a ZIP file. If you want to simply add files to an existing ZIP file, pass
'a' as the second argument to zipfile.ZipFile() to open the ZIP file in append mode.
import os
import sys
import pathlib
import zipfile
curDirectory = pathlib.Path(dirName)
with zipfile.ZipFile("myZip.zip", mode="w") as archive:
archive.write(file_path, arcname=file_path.relative_to(curDirectory))
if os.path.isfile("myZip.zip"):
print("Archive", "myZip.zip", "created successfully")
else:
print("Error in creating zip archive")
Output
Enter Directory name that you want to backup : zipDemo
Archive myZip.zip created successfully
Debugging
Raising Exceptions
Python raises an exception whenever it tries to execute invalid code. Python handle’s
exceptions with try and except statements so that your program can recover from
exceptions that you anticipated. But you can also raise your own exceptions in your code.
Raising an exception is a way of saying, “Stop running the code in this function and
move the program execution to the except statement.”
Exceptions are raised with a raise statement. In code, a raise statement consists of the
following:
• The raise keyword
• A call to the Exception() function
• A string with a helpful error message passed to the Exception() function
Here we’ve defined a boxPrint() function that takes a character, a width, and a height,
and uses the character to make a little picture of a box with that width and height. This
box shape is printed to the console.
Getting the Traceback as a String
When Python encounters an error, it produces a treasure trove of error information called
the traceback. The traceback includes the error message, the line number of the line that
caused the error, and the sequence of the function calls that led to the error. This
sequence of calls is called the call stack. Open a new file editor window in IDLE, enter
the following program, and save it as errorExample.py:
def spam():
bacon()
def bacon():
raise Exception('This is the error message.')
spam()
When you run errorExample.py, the output will look like this:
Traceback (most recent call last):
File "errorExample.py", line 7, in <module>
spam()
File "errorExample.py", line 2, in spam
bacon()
File "errorExample.py", line 5, in bacon
raise Exception('This is the error message.')
Exception: This is the error message.
From the traceback, you can see that the error happened on line 5, in the bacon() function.
This particular call to bacon() came from line 2, in the spam() function, which in turn
was called on line 7. In programs where functions can be called from multiple places, the
call stack can help you determine which call led to the error.
The traceback is displayed by Python whenever a raised exception goes unhandled. But
you can also obtain it as a string by calling traceback.format_exc(). This function is
useful if you want the information from an exception’s traceback but also want an except
statement to grace fully handle the exception. You will need to import Python’s
traceback module before calling this function.
For example, instead of crashing your program right when an exception occurs, you can
write the traceback information to a log file and keep your program running. You can
look at the log file later, when you’re ready to debug your program. Enter the following
into the interactive shell:
>>> import traceback
>>> try:
raise Exception('This is the error message.')
except:
errorFile = open('errorInfo.txt', 'w')
errorFile.write(traceback.format_exc())
errorFile.close()
print('The traceback info was written to errorInfo.txt.')
116
The traceback info was written to errorInfo.txt.
The 116 is the return value from the write() method, since 116 characters were written to
the file. The traceback text was written to errorInfo.txt.
Assertions
An assertion is a sanity check to make sure your code isn’t doing something obviously
wrong. These sanity checks are performed by assert statements. If the sanity check fails,
then an AssertionError exception is raised. In code, an assert statement consists of the
following:
• The assert keyword
• A condition (that is, an expression that evaluates to True or False)
• A comma
• A string to display when the condition is False
Here we’ve set podBayDoorStatus to 'open', so from now on, we fully expect the value
of this variable to be 'open'. In a program that uses this variable, we might have written a
lot of code under the assumption that the value is 'open'—code that depends on its being
'open' in order to work as we expect. So we add an assertion to make sure we’re right to
assume podBayDoorStatus is 'open'. Here, we include the message 'The pod bay doors
need to be "open".' so it’ll be easy to see what’s wrong if the assertion fails
Logging
If you’ve ever put a print() statement in your code to output some variable’s value while
your program is running, you’ve used a form of logging to debug your code. Logging is a
great way to understand what’s happening in your program and in what order its
happening. Python’s logging module makes it easy to create a record of custom messages
that you write. These log mes sages will describe when the program execution has
reached the logging function call and list any variables you have specified at that point in
time. On the other hand, a missing log message indicates a part of the code was
skipped and never executed.
import logging
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s
- %(message)s')
You don’t need to worry too much about how this works, but basically, when Python
logs an event, it creates a LogRecord object that holds information about that event. The
logging module’s basicConfig() function lets you specify what details about the
LogRecord object you want to see and how you want those details displayed.
Say you wrote a function to calculate the factorial of a number. In mathematics, factorial
4 is 1 × 2 × 3 × 4, or 24. Factorial 7 is 1 × 2 × 3 × 4 × 5 × 6 × 7, or 5,040. Open a new
file editor window and enter the following code. It has a bug in it, but you will also enter
several log messages to help yourself figure out what is going wrong.
import logging
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s
- %(message)s')
logging.debug('Start of program')
def factorial(n):
logging.debug('Start of factorial(%s%%)' % (n))
total = 1
for i in range(n + 1):
total *= i
logging.debug('i is ' + str(i) + ', total is ' + str(total))
logging.debug('End of factorial(%s%%)' % (n))
return total
print(factorial(5))
logging.debug('End of program')
Here, we use the logging.debug() function when we want to print login formation. This
debug() function will call basicConfig(), and a line of information will be printed. This
information will be in the format we specified in basicConfig() and will include the
messages we passed to debug(). The print(factorial(5)) call is part of the original program,
so the result is dis played even if logging messages are disabled.