Applied Programming/Lists and Tuples/Python3
lists.py
editThis is the lists.py program using csv(comma separated values):
"""This program demonstrates file, list, and tuple processing.
It creates a temporary file, adds data to the file, and reads the file
into a list of tuples. It then provides a menu of options for displaying
and searching the file data.
It will not run if the file already exists.
Input:
None
Output:
A temporary file and file contents.
References:
https://www.tutorialspoint.com/python/python_tuples.htm
"""
import os
import sys
import csv
def create_file(filename):
"""Creates filename and adds temperature data to the file.
Args:
filename (string): Filename to create.
Returns:
None
"""
with open(filename, 'w') as file:
file.write('"C","F"\n')
for c in range(0, 101, 10):
f = c * 9 / 5 + 32
file.write('"%.1f","%.1f"\n' % (c, f))
def read_file(filename):
"""Reads filename and returns a list of temperature tuples.
Args:
filename (string): Filename to open and read.
Returns:
A list of temperature tuples.
Raises:
ValueError: Invalid header format.
ValueError: Invalid record format.
ValueError: No data found.
"""
with open(filename, 'r') as file:
line = file.readline()
if line.strip() != '"C","F"':
raise ValueError("Invalid header format found in %s: %s" %
(filename, line))
temperatures = []
reader= csv.reader(file)
array = list(reader)
for row in array:
if 'C' in row:
continue
row[0] = float(row[0])
row[1] = float(row[1])
temperatures.append(row)
if len(row) != 2:
raise ValueError("Invalid record format found in %s: %s" %
(filename, row))
if len(temperatures) == 0:
raise ValueError("No data found in %s" % filename)
return temperatures
def delete_file(filename):
"""Deletes filename.
Args:
filename (string): Filename to delete.
Returns:
None
"""
os.remove(filename)
def get_choice():
"""Displays menu and gets choice.
Args:
None
Returns:
choice (int) or None
"""
while True:
try:
print("Select from the following options or press <Enter> to quit:")
print("1. Display table sorted by Celsius temperature.")
print("2. Display table sorted by Fahrenheit temperature.")
print("3. Search for Celsius temperature.")
print("4. Search for Fahrenheit temperature.")
choice = input()
choice = int(choice)
if 1 <= choice <= 4:
print()
return choice
print("%s is not a valid choice.\n" % choice)
except ValueError:
if choice == "":
return None
print("%s is not a valid choice.\n" % choice)
def display_temperatures(temperatures, scale):
"""Displays temperatures sorted in scale order.
Args:
temperatures (list of Celsius, Fahrenheit tuples)
scale (string): "Celsius" or "Fahrenheit"
Returns:
None
"""
if scale == "Celsius":
data = sorted(temperatures, key=lambda record: record[0])
print("C\tF")
first_column = 0
second_column = 1
elif scale == "Fahrenheit":
data = sorted(temperatures, key=lambda record: record[1])
print("F\tC")
first_column = 1
second_column = 0
else:
raise ValueError("scale must be Celsius or Fahrenheit")
for record in data:
print("%s\t%s" % (record[first_column], record[second_column]))
print()
def get_temperature(scale):
"""Gets Fahrenheit or Celsius temperature.
Args:
scale (string): "Celsius" or "Fahrenheit"
Returns:
temperature (float) or None
"""
assert scale == "Celsius" or scale == "Fahrenheit"
while True:
try:
print("Enter %s temperature:" % scale)
temperature = input()
temperature = float(temperature)
print()
return temperature
except ValueError:
print("%s is not a valid %s temperature\n" %
(temperature, scale))
return None
def search_temperatures(temperatures, scale):
"""Search temperatures for a scale temperature and display the nearest match.
Args:
temperatures (list of Celsius, Fahrenheit tuples)
scale (string): "Celsius" or "Fahrenheit"
Returns:
None
Raises:
ValueError: If temperatures list is empty
ValueError: If scale is invalid
"""
if len(temperatures) <= 0:
raise ValueError("temperatures list is empty")
temperature = get_temperature(scale)
if temperature == None:
return
if scale == "Celsius":
search_element = 0
display_element = 1
other_scale = "Fahrenheit"
elif scale == "Fahrenheit":
search_element = 1
display_element = 0
other_scale = "Celsius"
else:
raise ValueError("scale must be Celsius or Fahrenheit")
data = sorted(temperatures, key=lambda record: record[search_element])
last = data[0]
for record in data:
if temperature < record[search_element]:
break
last = record
if temperature < last[search_element]:
print("%.1f° %s is less than %.1f° %s\n" %
(temperature, scale, last[display_element], other_scale))
elif temperature == last[search_element]:
print("%.1f° %s is %.1f° %s\n" %
(temperature, scale, last[display_element], other_scale))
elif temperature > record[search_element]:
print("%.1f° %s is greater than %.1f° %s\n" %
(temperature, scale, last[display_element], other_scale))
else:
print("%.1f° %s is between %.1f° %s and %.1f° %s\n" %
(temperature, scale,
last[display_element], other_scale,
record[display_element], other_scale))
def main():
"""Runs the main program logic."""
try:
filename = "~temperatures.txt"
if os.path.isfile(filename):
print("File '%s' already exists." % filename)
os.remove(filename)
exit(1)
create_file(filename)
temperatures = read_file(filename)
delete_file(filename)
while True:
choice = get_choice()
if choice == None:
break
elif choice == 1:
display_temperatures(temperatures, "Celsius")
elif choice == 2:
display_temperatures(temperatures, "Fahrenheit")
elif choice == 3:
search_temperatures(temperatures, "Celsius")
elif choice == 4:
search_temperatures(temperatures, "Fahrenheit")
else:
raise ValueError("Invalid option selected")
except:
print("Unexpected error.")
print("Error:", sys.exc_info()[1])
print("File: ", sys.exc_info()[2].tb_frame.f_code.co_filename)
print("Line: ", sys.exc_info()[2].tb_lineno)
main()
And is the lists.py program using regex:
"""This program demonstrates file, list, and tuple processing.
It creates a temporary file, adds data to the file, and reads the file
into a list of tuples. It then provides a menu of options for displaying
and searching the file data.
It will not run if the file already exists.
Input:
None
Output:
A temporary file and file contents.
References:
https://www.tutorialspoint.com/python/python_tuples.htm
"""
import os
import re
import sys
def create_file(filename):
"""Creates filename and adds temperature data to the file.
Args:
filename (string): Filename to create.
Returns:
None
"""
with open(filename, 'w') as file:
file.write('"C","F"\n')
for c in range(0, 101, 10):
f = c * 9 / 5 + 32
file.write('"%.1f","%.1f"\n' % (c, f))
def read_file(filename):
"""Reads filename and returns a list of temperature tuples.
Args:
filename (string): Filename to open and read.
Returns:
A list of temperature tuples.
Raises:
ValueError: Invalid header format.
ValueError: Invalid record format.
ValueError: No data found.
"""
with open(filename, 'r') as file:
line = file.readline()
if line.strip() != '"C","F"':
raise ValueError("Invalid header format found in %s: %s" %
(filename, line))
temperatures = []
for line in file:
if 'C' in line:
continue
record = re.findall('"(.*?)"', line)
if len(record) != 2:
raise ValueError("Invalid record format found in %s: %s" %
(filename, line))
record[0] = float(record[0])
record[1] = float(record[1])
temperatures.append(record)
if len(temperatures) == 0:
raise ValueError("No data found in %s" % filename)
return temperatures
def delete_file(filename):
"""Deletes filename.
Args:
filename (string): Filename to delete.
Returns:
None
"""
os.remove(filename)
def get_choice():
"""Displays menu and gets choice.
Args:
None
Returns:
choice (int) or None
"""
while True:
try:
print("Select from the following options or press <Enter> to quit:")
print("1. Display table sorted by Celsius temperature.")
print("2. Display table sorted by Fahrenheit temperature.")
print("3. Search for Celsius temperature.")
print("4. Search for Fahrenheit temperature.")
choice = input()
choice = int(choice)
if 1 <= choice <= 4:
print()
return choice
print("%s is not a valid choice.\n" % choice)
except ValueError:
if choice == "":
return None
print("%s is not a valid choice.\n" % choice)
def display_temperatures(temperatures, scale):
"""Displays temperatures sorted in scale order.
Args:
temperatures (list of Celsius, Fahrenheit tuples)
scale (string): "Celsius" or "Fahrenheit"
Returns:
None
"""
if scale == "Celsius":
data = sorted(temperatures, key=lambda record: record[0])
print("C\tF")
first_column = 0
second_column = 1
elif scale == "Fahrenheit":
data = sorted(temperatures, key=lambda record: record[1])
print("F\tC")
first_column = 1
second_column = 0
else:
raise ValueError("scale must be Celsius or Fahrenheit")
for record in data:
print("%s\t%s" % (record[first_column], record[second_column]))
print()
def get_temperature(scale):
"""Gets Fahrenheit or Celsius temperature.
Args:
scale (string): "Celsius" or "Fahrenheit"
Returns:
temperature (float) or None
"""
assert scale == "Celsius" or scale == "Fahrenheit"
while True:
try:
print("Enter %s temperature:" % scale)
temperature = input()
temperature = float(temperature)
print()
return temperature
except ValueError:
print("%s is not a valid %s temperature\n" %
(temperature, scale))
return None
def search_temperatures(temperatures, scale):
"""Search temperatures for a scale temperature and display the nearest match.
Args:
temperatures (list of Celsius, Fahrenheit tuples)
scale (string): "Celsius" or "Fahrenheit"
Returns:
None
Raises:
ValueError: If temperatures list is empty
ValueError: If scale is invalid
"""
if len(temperatures) <= 0:
raise ValueError("temperatures list is empty")
temperature = get_temperature(scale)
if temperature == None:
return
if scale == "Celsius":
search_element = 0
display_element = 1
other_scale = "Fahrenheit"
elif scale == "Fahrenheit":
search_element = 1
display_element = 0
other_scale = "Celsius"
else:
raise ValueError("scale must be Celsius or Fahrenheit")
data = sorted(temperatures, key=lambda record: record[search_element])
last = data[0]
for record in data:
if temperature < record[search_element]:
break
last = record
if temperature < last[search_element]:
print("%.1f° %s is less than %.1f° %s\n" %
(temperature, scale, last[display_element], other_scale))
elif temperature == last[search_element]:
print("%.1f° %s is %.1f° %s\n" %
(temperature, scale, last[display_element], other_scale))
elif temperature > record[search_element]:
print("%.1f° %s is greater than %.1f° %s\n" %
(temperature, scale, last[display_element], other_scale))
else:
print("%.1f° %s is between %.1f° %s and %.1f° %s\n" %
(temperature, scale,
last[display_element], other_scale,
record[display_element], other_scale))
def main():
"""Runs the main program logic."""
try:
filename = "~temperatures.txt"
if os.path.isfile(filename):
print("File '%s' already exists." % filename)
exit(1)
create_file(filename)
temperatures = read_file(filename)
delete_file(filename)
while True:
choice = get_choice()
if choice == None:
break
elif choice == 1:
display_temperatures(temperatures, "Celsius")
elif choice == 2:
display_temperatures(temperatures, "Fahrenheit")
elif choice == 3:
search_temperatures(temperatures, "Celsius")
elif choice == 4:
search_temperatures(temperatures, "Fahrenheit")
else:
raise ValueError("Invalid option selected")
except:
print("Unexpected error.")
print("Error:", sys.exc_info()[1])
print("File: ", sys.exc_info()[2].tb_frame.f_code.co_filename)
print("Line: ", sys.exc_info()[2].tb_lineno)
main()
test_lists.py
edit"""This file tests the lists example program using PyTest.
Run "pytest" in this folder to automatically run these tests.
Expected output:
x passed in 0.xx seconds
References:
* https://realpython.com/python-testing/
* http://docs.pytest.org/en/latest/getting-started.html
"""
import pytest
import lists
def test_get_choice_returns_valid_input():
input_values = ['1']
def input():
return input_values.pop()
lists.input = input
assert lists.get_choice() == 1
def test_get_choice_returns_ignores_non_input():
input_values = [1, True, '1']
def input():
return input_values.pop()
lists.input = input
assert lists.get_choice() == 1
def test_display_temperatures_displays_valid_input_c(capsys):
input_table = [[0.0, 32.0], [10.0, 50.0], [20.0, 68.0], [30.0, 86.0], [40.0, 104.0], [50.0, 122.0], [60.0, 140.0], [70.0, 158.0], [80.0, 176.0], [90.0, 194.0], [100.0, 212.0]]
lists.display_temperatures(input_table, "Celsius")
captured = capsys.readouterr()
assert "0.0\t32.0" in captured.out
def test_display_temperatures_displays_valid_input_f(capsys):
input_table = [[0.0, 32.0], [10.0, 50.0], [20.0, 68.0], [30.0, 86.0], [40.0, 104.0], [50.0, 122.0], [60.0, 140.0], [70.0, 158.0], [80.0, 176.0], [90.0, 194.0], [100.0, 212.0]]
lists.display_temperatures(input_table, "Fahrenheit")
captured = capsys.readouterr()
assert "32.0\t0.0" in captured.out
def test_search_temperatures_returns_valid_output_c(capsys):
input_table = [[0.0, 32.0], [10.0, 50.0], [20.0, 68.0], [30.0, 86.0], [40.0, 104.0], [50.0, 122.0], [60.0, 140.0], [70.0, 158.0], [80.0, 176.0], [90.0, 194.0], [100.0, 212.0]]
lists.search_temperatures(input_table, "Celsius")
captured = capsys.readouterr()
assert "1.0° Celsius is between 32.0° Fahrenheit and 50.0° Fahrenheit" in captured.out
def test_search_temperatures_returns_valid_output_f(capsys):
input_table = [[0.0, 32.0], [10.0, 50.0], [20.0, 68.0], [30.0, 86.0], [40.0, 104.0], [50.0, 122.0], [60.0, 140.0], [70.0, 158.0], [80.0, 176.0], [90.0, 194.0], [100.0, 212.0]]
lists.search_temperatures(input_table, "Fahrenheit")
captured = capsys.readouterr()
assert "1.0° Fahrenheit is less than 0.0° Celsius" in captured.out
Try It
editCopy and paste the code above into one of the following free online development environments or use your own Python3 compiler / interpreter / IDE.