diff --git a/.gitignore b/.gitignore index 88b03d4..70dc3de 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,10 @@ __pycache__/ # Distribution / packaging .Python +.idea +test*.py +*.zip +.mypy_cache env/ build/ develop-eggs/ diff --git a/students/navidbahadoran/Lesson01/Monkey_Trouble.py b/students/navidbahadoran/Lesson01/Monkey_Trouble.py new file mode 100644 index 0000000..ee1e580 --- /dev/null +++ b/students/navidbahadoran/Lesson01/Monkey_Trouble.py @@ -0,0 +1,18 @@ +""" +title: Monkey_Trouble +change log: +NBahadoran, 1/13/2018, Created Monkey_Trouble.py +""" + +def monkey_trouble(a_smile, b_smile): + """ + We have two monkeys, a and b, and the parameters a_smile and b_smile indicate + if each is smiling. We are in trouble if they are both smiling or if neither + of them is smiling. Return True if we are in trouble. + monkey_trouble(True, True) → True + monkey_trouble(False, False) → True + monkey_trouble(True, False) → False + """ + return(a_smile == b_smile ) + +print(monkey_trouble(False,False)) \ No newline at end of file diff --git a/students/navidbahadoran/Lesson01/Sleep_in.py b/students/navidbahadoran/Lesson01/Sleep_in.py new file mode 100644 index 0000000..c8f1e61 --- /dev/null +++ b/students/navidbahadoran/Lesson01/Sleep_in.py @@ -0,0 +1,19 @@ +""" +title: Sleep_in +change log: +NBahadoran, 1/13/2018, Created Sleep_in.py +""" + +def sleep_in(weekday, vacation): + """ + The parameter weekday is True if it is a weekday, and the parameter vacation is True + if we are on vacation. We sleep in if it is not a weekday or we're on vacation. + Return True if we sleep in. + sleep_in(False, False) → True + sleep_in(True, False) → False + sleep_in(False, True) → True + """ + return(vacation or(not weekday)) + + +print(sleep_in(False,False)) diff --git a/students/navidbahadoran/Lesson01/break_me.py b/students/navidbahadoran/Lesson01/break_me.py new file mode 100644 index 0000000..b7b3b07 --- /dev/null +++ b/students/navidbahadoran/Lesson01/break_me.py @@ -0,0 +1,13 @@ +import sys +def name_error(): + raise NameError +def type_error(): + raise TypeError +def syntax_error(): + raise SyntaxError +def attribute_error(): + raise AttributeError +name_error() +type_error() +syntax_error() +attribute_error() diff --git a/students/navidbahadoran/Lesson01/def_21.py b/students/navidbahadoran/Lesson01/def_21.py new file mode 100644 index 0000000..e226904 --- /dev/null +++ b/students/navidbahadoran/Lesson01/def_21.py @@ -0,0 +1,17 @@ +""" +title: def_21 +change log: +NBahadoran, 1/13/2018, Created def_21.py +""" +def diff21(n): + """ + Given an int n, return the absolute difference between n and 21, + except return double the absolute difference if n is over 21. + diff21(19) → 2 + diff21(10) → 11 + diff21(21) → 0 + """ + return(abs(n-21) if n<21 else 2*abs(n-21)) + + +print(diff21(23)) \ No newline at end of file diff --git a/students/navidbahadoran/Lesson01/sum_double.py b/students/navidbahadoran/Lesson01/sum_double.py new file mode 100644 index 0000000..7c989c4 --- /dev/null +++ b/students/navidbahadoran/Lesson01/sum_double.py @@ -0,0 +1,19 @@ +""" +title: Sum_double +change log: +NBahadoran, 1/13/2018, Created sum_double.py +""" + +def sum_double(a, b): + """ + Given two int values, return their sum. + Unless the two values are the same, then return double their sum. + sum_double(1, 2) → 3 + sum_double(3, 2) → 5 + sum_double(2, 2) → 8 + """ + return(a+b if a!=b else (a+b)*2) + +print(sum_double(1,1)) +print(sum_double(1,2)) +# \ No newline at end of file diff --git a/students/navidbahadoran/Lesson01/test.txt b/students/navidbahadoran/Lesson01/test.txt new file mode 100644 index 0000000..69a022c --- /dev/null +++ b/students/navidbahadoran/Lesson01/test.txt @@ -0,0 +1 @@ +This is the folder I will use for assignment 01 \ No newline at end of file diff --git a/students/navidbahadoran/Lesson02/Fizz_Buzz.py b/students/navidbahadoran/Lesson02/Fizz_Buzz.py new file mode 100644 index 0000000..e857bdd --- /dev/null +++ b/students/navidbahadoran/Lesson02/Fizz_Buzz.py @@ -0,0 +1,32 @@ +""" +title: Fizz_Buzz +Desc: for the number in the range of 1 to n: + print “Fizz” instead of the number for multiples of three + print “Buzz” instead of the number for the multiples of five . + For numbers which are multiples of both three and five print “FizzBuzz” instead. +change log: +NBahadoran, 1/20/2018, Created Fizz_Buzz.py +""" + +def fizz_buzz(n): + """ + for the number in the range of 1 to n: + print “Fizz” instead of the number for multiples of three + print “Buzz” instead of the number for the multiples of five . + For numbers which are multiples of both three and five print “FizzBuzz” instead. + else print number. + :param n: the input from user that need to be printed + :return: + """ + for num in range(1,n+1): + + if (num % 3 == 0) and (num % 5 == 0): + print("FizzBuzz") + elif num % 3 == 0: + print("Fizz") + elif num % 5 == 0: + print("Buzz") + else: + print(num) + + diff --git a/students/navidbahadoran/Lesson02/front3.py b/students/navidbahadoran/Lesson02/front3.py new file mode 100644 index 0000000..d8cb602 --- /dev/null +++ b/students/navidbahadoran/Lesson02/front3.py @@ -0,0 +1,19 @@ +""" +title: front3 +change log: +NBahadoran, 1/19/2018,Created front3.py +""" + + +def front3(str): + """ + Given a string, we'll say that the front is the first 3 chars of the string. + If the string length is less than 3, the front is whatever is there. Return + a new string which is 3 copies of the front. + front3('Java') → 'JavJavJav' + front3('Chocolate') → 'ChoChoCho' + front3('abc') → 'abcabcabc' + """ + if len(str)<3: + return str*3 + return str[0:3]*3 diff --git a/students/navidbahadoran/Lesson02/front_back.py b/students/navidbahadoran/Lesson02/front_back.py new file mode 100644 index 0000000..9c2857e --- /dev/null +++ b/students/navidbahadoran/Lesson02/front_back.py @@ -0,0 +1,15 @@ +""" +title: front_back +change log: +NBahadoran, 1/19/2018,Created front_back.py +""" +def front_back(str): + """ + Given a string, return a new string where the first and last chars have been exchanged. + front_back('code') → 'eodc' + front_back('a') → 'a' + front_back('ab') → 'ba' + """ + if len(str)<=1: return str + return str[-1]+str[1:len(str)-1]+str[0] + diff --git a/students/navidbahadoran/Lesson02/grid_printer.py b/students/navidbahadoran/Lesson02/grid_printer.py new file mode 100644 index 0000000..f86c79f --- /dev/null +++ b/students/navidbahadoran/Lesson02/grid_printer.py @@ -0,0 +1,67 @@ +""" +title: grid_printer +Desc: print a grid with the same row and column number and each cell has the + size based on the user's input for the size +change log: +NBahadoran, 1/20/2018, Created grid_printer.py +""" + +def grid(row,size): + """ + print the grid based on the size and the row input + :param row: No of row and column of the grid + :param size: size of each cells + :return: print the grid + """ + print_row(row, size) + + for grid_row in range(row): + + for cell_size in range(size): + print_beam(row,size) + + print_row(row, size) + + + +def print_beam(row,size): + """ + print the beam of the grid + :param row: No of | in the row minus 1 + :param size: half of No of blank in the row + :return: print row which includes beams + """ + post = "|" + blank = " " + for i in range(row): + print(post, end=blank) + for j in range(size): + print(blank + blank, end="") + else: + print(post) + +def print_row(row,size): + """ + print the row of the grid + :param row: No of + in the row minus 1 + :param size: half of No of - in the row + :return: print row which includes + - + """ + plus = "+" + blank= " " + minus= "-" + for i in range(row): + print(plus, end=blank) + for j in range(size): + print(minus + blank, end="") + else: + print(plus) + +try: + row=int(input("Enter the integer No of row of your grid: ")) + size=int(input("Enter the integer No of size of your grid: ")) + grid(row,size) +except Exception: + print("You entered the wrong input!") + print("Your input should be integer.") + diff --git a/students/navidbahadoran/Lesson02/makes10.py b/students/navidbahadoran/Lesson02/makes10.py new file mode 100644 index 0000000..77e1c29 --- /dev/null +++ b/students/navidbahadoran/Lesson02/makes10.py @@ -0,0 +1,16 @@ +""" +title: makes10 +change log: +NBahadoran, 1/19/2018, Created makes10.py +""" + +def makes10(a, b): + """ + Given 2 ints, a and b, return True if one if them is 10 or if their sum is 10. + + + makes10(9, 10) → True + makes10(9, 9) → False + makes10(1, 9) → True + """ + return (a + b == 10 or a == 10 or b == 10) diff --git a/students/navidbahadoran/Lesson02/missing_char.py b/students/navidbahadoran/Lesson02/missing_char.py new file mode 100644 index 0000000..b7b9f37 --- /dev/null +++ b/students/navidbahadoran/Lesson02/missing_char.py @@ -0,0 +1,13 @@ + + + +def missing_char(str, n): + """ + Given a non-empty string and an int n, return a new string where the + char at index n has been removed. The value of n will be a valid + index of a char in the original string (i.e. n will be in the range 0..len(str)-1 inclusive). + missing_char('kitten', 1) → 'ktten' + missing_char('kitten', 0) → 'itten' + missing_char('kitten', 4) → 'kittn' + """ + return str[:n]+str[n+1:] \ No newline at end of file diff --git a/students/navidbahadoran/Lesson02/near100.py b/students/navidbahadoran/Lesson02/near100.py new file mode 100644 index 0000000..f67fc9b --- /dev/null +++ b/students/navidbahadoran/Lesson02/near100.py @@ -0,0 +1,17 @@ +""" +title: near100 +change log: +NBahadoran, 1/19/2018, Created near100.py +""" + + +def near_hundred(n): + """ + Given an int n, return True if it is within 10 of 100 or 200. + Note: abs(num) computes the absolute value of a number. + near_hundred(93) → True + near_hundred(90) → True + near_hundred(89) → False + """ + + return (abs(n-100)<=10 or abs(n-200)<=10) \ No newline at end of file diff --git a/students/navidbahadoran/Lesson02/not_string.py b/students/navidbahadoran/Lesson02/not_string.py new file mode 100644 index 0000000..c4d01c6 --- /dev/null +++ b/students/navidbahadoran/Lesson02/not_string.py @@ -0,0 +1,19 @@ +""" +title: not_string +change log: +NBahadoran, 1/19/2018, Created not_string.py +""" +def not_string(str): + """ + Given a string, return a new string where "not " has been added to the front. + However, if the string already begins with "not", return the string unchanged. + not_string('candy') → 'not candy' + not_string('x') → 'not x' + not_string('not bad') → 'not bad' + """ + if "not".lower() in str[0:3]: + return str + return "not "+str + +print(not_string("hello")) + diff --git a/students/navidbahadoran/Lesson02/pos_neg.py b/students/navidbahadoran/Lesson02/pos_neg.py new file mode 100644 index 0000000..858f4b5 --- /dev/null +++ b/students/navidbahadoran/Lesson02/pos_neg.py @@ -0,0 +1,18 @@ +""" +title: pos_neg +change log: +NBahadoran, 1/19/2018, Created pos_neg.py +""" +def pos_neg(a, b, negative): + """ + Given 2 int values, return True if one is negative and one is positive. + Except if the parameter "negative" is True, then return True only if both are negative. + pos_neg(1, -1, False) → True + pos_neg(-1, 1, False) → True + pos_neg(-4, -5, True) → True + """ + if negative: + return (a<0 and b<0) + else: + return (a*b<0) + return False diff --git a/students/navidbahadoran/Lesson02/series.py b/students/navidbahadoran/Lesson02/series.py new file mode 100644 index 0000000..5801cc9 --- /dev/null +++ b/students/navidbahadoran/Lesson02/series.py @@ -0,0 +1,92 @@ +""" +title: Fibonacci and lucas series +Desc: for the number n it returns the nth elements of fibonacci and lucas series +change log: +NBahadoran, 1/20/2018, Created series.py +""" +def fibonacci(n): + """ + The function should return the nth value in the fibonacci series (starting with zero index). + :param n: the number of element in the series + :return:nth value of fibonacci series + """ + if n == 0: + return 0 + elif n == 1: + return 1 + else: + return fibonacci(n - 1) + fibonacci(n - 2) + +def lucas(n): + """ + The function should return the nth value in the lucas series (starting with zero index). + :param n: the number of element in the series + :return: nth value of lucas series + """ + if n == 0: + return 2 + elif n == 1: + return 1 + else: + return lucas(n - 1) + lucas(n - 2) + +def sum_series(n,first_element=0,second_element=1): + """ + This function should generalize the fibonacci() and the lucas(), + so that this function works for any first two numbers for a sum series. + Once generalized that way, sum_series(n, 0, 1) should be equivalent to fibonacci(n). + And sum_series(n, 2, 1) should be equivalent to lucas(n). + :param n: the number of element in the series + :param first_element: determine the first element of the series + :param second_element: determine the second element of the series + :return: nth value of series which is the adding of n-1th and n-2th elements. + """ + if n == 0: + return first_element + elif n == 1: + return second_element + else: + return sum_series(n - 1,first_element,second_element) + sum_series(n - 2,first_element,second_element) + +try: + number=int(input("Enter the integer No of element of the fibonacci and lucas that you want to print:")) + + print(fibonacci(number)) + print(lucas(number)) + + first_element=int(input("Enter the value of the first element of series:")) + second_element = int(input("Enter the value of the second element of series:")) + + print(sum_series(number,first_element,second_element)) + + """Block of test: in this test we check if our functions generate the + right numbers + """ + assert fibonacci(0) == 0 + assert fibonacci(1) == 1 + assert fibonacci(2) == 1 + assert fibonacci(3) == 2 + assert fibonacci(4) == 3 + assert fibonacci(5) == 5 + assert fibonacci(6) == 8 + assert fibonacci(7) == 13 + + assert lucas(0) == 2 + assert lucas(1) == 1 + + assert lucas(4) == 7 + # test if sum_series matched fibonacci + assert sum_series(5) == fibonacci(5) + + # test if sum_series matched lucas + assert sum_series(5, 2, 1) == lucas(5) + + print("tests passed") + +except AssertionError as e: + print("test is not passed",e) + +except Exception: + print("You entered the wrong input!") + print("Your input should be integer.") + diff --git a/students/navidbahadoran/Lesson03/List_Lab.py b/students/navidbahadoran/Lesson03/List_Lab.py new file mode 100644 index 0000000..db8c887 --- /dev/null +++ b/students/navidbahadoran/Lesson03/List_Lab.py @@ -0,0 +1,136 @@ +""" +title: Slicing Lab +Desc: List manipulation + +change log: +NBahadoran, 1/27/2018, Created List_Lab.py +""" +# ---------------------Series 1--------------------- +""" +Create a list that contains “Apples”, “Pears”, “Oranges” and “Peaches”. +Display the list (plain old print() is fine…). +""" +print("---------------------Series 1---------------------") +main_fruit_list = ["Apple", "Pear", "Orange", "Peaches"] +fruit_list = main_fruit_list[:] +print(fruit_list) + +""" +Ask the user for another fruit and add it to the end of the list. +Display the list. +""" +fruit = input("Enter new fruit to add to your list:") +fruit_list.append(fruit) +print(fruit_list) + +""" +Ask the user for a number and display the number back to the user and the fruit +corresponding to that number (on a 1-is-first basis). Remember that Python uses + zero-based indexing, so you will need to correct. +""" +print("Enter the number of item in the list you want to display(1-", len(fruit_list), end="):") +number = int(input()) +if type(number) == int and number <= len(fruit_list): + print("The fruit number ", number, " of you list is:", fruit_list[number-1]) +else: + raise Exception("You enterd wrong input or the number is above the range") + +# Add another fruit to the beginning of the list using “+” and display the list. +fruit = input("Enter new fruit to add to the begining of your list:") +fruit_list = [fruit]+fruit_list +print("After adding a new fruit at the beginning of your list:") +print(fruit_list) + +# Add another fruit to the beginning of the list using insert() and display the list. +fruit = input("Enter new fruit to add to the begining of your list:") +print("After adding a new fruit at the beginning of your list:") +fruit_list.insert(0, fruit) +print(fruit_list) + +# Display all the fruits that begin with “P”, using a for loop. +print("Displaying all the fruits that begin with 'P':") +for i in fruit_list: + if i[0] == "P": + print(i) + +# ----------------Series 2--------------------------- +print("---------------------Series 2---------------------") +# display the list +print("Display the fruit list:") +fruit_list = main_fruit_list[:] +print(fruit_list) + +""" +Remove the last fruit from the list. +Display the list. +""" +fruit_list.pop() +print("Remove the last fruit from the list:") +print(fruit_list) + +# Ask the user for a fruit to delete, find it and delete it. + +rem_fruit = input("Enter the fruit you want to remove:") +while True: + try: + fruit_list.remove(rem_fruit) + except ValueError: + break + +print("Remove the fruit,", rem_fruit, " from the list:") +print(fruit_list) + +# (Bonus: Multiply the list times two. Keep asking until a match is found. Once found, delete all occurrences.) +fruit_list = fruit_list*2 +print("Displaying Multiplying list times two:") +print(fruit_list) +rem_fruit = input("Enter the fruit you want to remove:") +while True: + try: + fruit_list.remove(rem_fruit) + except ValueError: + break +print("Remove the fruit,", rem_fruit, " from the list:") +print(fruit_list) + +# ------------------Series 3----------------------- +print("---------------------Series 3---------------------") +""" +Ask the user for input displaying a line like “Do you like apples?” for each fruit in the list +(making the fruit all lowercase). +For each “no”, delete that fruit from the list. +For any answer that is not “yes” or “no”, prompt the user to answer with one of those two values +(a while loop is good here) +Display the list. +""" +print("Fruit list") +print(main_fruit_list) +fruit_list = main_fruit_list[:] +for i in fruit_list[:]: + answer = None + while answer not in ["yes", "no"]: + answer = input("Do you like " + i.lower() + "(yes/no):").lower() + if answer == "no": + while True: + try: + fruit_list.remove(i) + except ValueError: + break + + +print(fruit_list) + +# ------------------Series 4----------------------- +""" +Make a new list with the contents of the original, but with all the letters in each item reversed. +Delete the last item of the original list. Display the original list and the copy. +""" +print("---------------------Series 4---------------------") +fruit_list = main_fruit_list[:] +new_fruit_list = [] +for i in fruit_list: + new_fruit_list.append(i[::-1]) +print(new_fruit_list) +print(main_fruit_list) +fruit_list.pop() +print(fruit_list) diff --git a/students/navidbahadoran/Lesson03/Slicing_Lab.py b/students/navidbahadoran/Lesson03/Slicing_Lab.py new file mode 100644 index 0000000..8bd7dcf --- /dev/null +++ b/students/navidbahadoran/Lesson03/Slicing_Lab.py @@ -0,0 +1,61 @@ +""" +title: Slicing Lab +Desc: Write some functions that take a sequence as an argument, and return a copy of that sequence: + +with the first and last items exchanged. +with every other item removed. +with the first 4 and the last 4 items removed, and then every other item in the remaining sequence. +with the elements reversed (just with slicing). +with the last third, then first third, then the middle third in the new order. + +change log: +NBahadoran, 1/27/2018, Created Slicing_lab.py +""" + + +def exchange_first_last(sequence): + """return a sequence with the first and last items exchanged""" + return sequence[-1:] + sequence[1:len(sequence)-1] + sequence[0:1] + + +def remove_every_other(sequence): + """"return a sequence with every other item removed""" + return sequence[0: len(sequence): 2] + + +def remove_firstfour_lastfour_everyother(sequence): + """return a sequence with the first 4 and the last 4 items removed, + and then every other item in the remaining sequence.""" + return sequence[4:len(sequence)-4:2] + + +def reverse(sequence): + """return a sequence with the elements reversed.""" + return sequence[::-1] + + +def lastthird_firstthird_middlethird(sequence): + """return a sequence with the last third, then first third, then the middle third in the new order.""" + return sequence[len(sequence)-3:len(sequence)] + sequence[0:3] + sequence[len(sequence)//2-1:len(sequence)//2+2] + + +x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] +print(exchange_first_last(x)) +print(remove_every_other(x)) +print(remove_firstfour_lastfour_everyother(x)) +print(reverse(x)) +print(lastthird_firstthird_middlethird(x)) + +y = "this is a string" +print(exchange_first_last(y)) +print(remove_every_other(y)) +print(remove_firstfour_lastfour_everyother(y)) +print(reverse(y)) +print(lastthird_firstthird_middlethird(x)) + +z = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) +print(exchange_first_last(z)) +print(remove_firstfour_lastfour_everyother(z)) +print(remove_every_other(z)) +print(reverse(z)) +print(lastthird_firstthird_middlethird(x)) diff --git a/students/navidbahadoran/Lesson03/Strfromat_Lab.py b/students/navidbahadoran/Lesson03/Strfromat_Lab.py new file mode 100644 index 0000000..0329b71 --- /dev/null +++ b/students/navidbahadoran/Lesson03/Strfromat_Lab.py @@ -0,0 +1,93 @@ +""" +title: string format lab +Desc: string manipulation + +change log: +NBahadoran, 1/27/2018, Created Strformat_Lab.py +""" +# ----------------Task 1------------------ +print("------------Task 1------------") +""" +Write a format string that will take the following four element tuple: +( 2, 123.4567, 10000, 12345.67) +and produce: +'file_002 : 123.46, 1.00e+04, 1.23e+04' +""" + +tpl = (2, 123.4567, 10000, 12345.67) +print("file_{0:03d}: {1:6.2f}, {2:6.2e}, {3:6.2e}".format(*tpl)) + +# ------------------Task 2-------------- +print("------------Task 2------------") +""" +Using your results from Task One, repeat the exercise, but this time using an alternate type of format string + (hint: think about alternative ways to use .format() (keywords anyone?), and also consider f-strings + if you’ve not used them already). +""" +print(f"file_{tpl[0]:03d}: {tpl[1]:6.2f}, {tpl[2]:6.2e}, {tpl[3]:6.2e}") + +# ------------------Task 3-------------- +""" +Dynamically Building up format strings +formatter((2,3,5)) +'the 3 numbers are: 2, 3, 5' + +formatter((2,3,5,7,9)) +'the 5 numbers are: 2, 3, 5, 7, 9' +""" +print("------------Task 3------------") + + +def formatter(in_tuple): + """return string including enough {} to operate in format method""" + form_string = "the " + str(len(in_tuple)) + " numbers are:" + for i in range(len(in_tuple)): + form_string += " {}" + return form_string.format(*in_tuple) + + +tpl = (2, 3, 5) +print(formatter(tpl)) +tpl = (2, 3, 5, 7, 9) +print(formatter(tpl)) + +# ------------------Task 4-------------- +""" +Given a 5 element tuple: +( 4, 30, 2017, 2, 27) +use string formating to print: +'02 27 2017 04 30' +Hint: use index numbers to specify positions. +""" +print("------------Task 4------------") +tpl = (4, 30, 2017, 2, 27) +print("{3:02d},{4:02d},{2:02d},{0:02d},{1:02d}".format(*tpl)) + +# ------------------Task 5-------------- +""" +Here’s a task for you: Given the following four element list: +['oranges', 1.3, 'lemons', 1.1] +Write an f-string that will display: +The weight of an orange is 1.3 and the weight of a lemon is 1.1 +Now see if you can change the f-string so that it displays the names of the fruit +in upper case, and the weight 20% higher (that is 1.2 times higher). +""" +print("------------Task 5------------") +lst = ['oranges', 1.3, 'lemons', 1.1] +print(f"The weight of {lst[0].upper()} is {lst[1]*1.2} and the weight of {lst[2].upper()} is {lst[3]*1.2}") + +# ------------------Task 6-------------- +""" +Write some Python code to print a table of several rows, each with a name, an age and a cost. +Make sure some of the costs are in the hundreds and thousands to test your alignment specifiers. +And for an extra task, given a tuple with 10 consecutive numbers, can you work how to quickly +print the tuple in columns that are 5 characters wide? It can be done on one short line! +""" +print("------------Task 6------------") +lst = [["lamp", 12, 1099.98], ["rug", 18, 134.88], ["sofa", 2, 2049.99]] + +for i in lst: + print("{:<10s}{:<10.2f}${:<7,.2f}".format(*i)) + +tpl = (1, 2, 3, 4, 5, 6, 7, 8, 10) +print("{:<5d}{:<5d}{:<5d}{:<5d}{:<5d}".format(*tpl)) diff --git a/students/navidbahadoran/Lesson03/front_times.py b/students/navidbahadoran/Lesson03/front_times.py new file mode 100644 index 0000000..34a51e7 --- /dev/null +++ b/students/navidbahadoran/Lesson03/front_times.py @@ -0,0 +1,18 @@ +""" +title: front_times +Desc:Given a string and a non-negative int n, we'll say that the front of the string is the first 3 chars, +or whatever is there if the string is less than length 3. Return n copies of the front; +change log: +NBahadoran, 1/27/2018, Created front_times.py +""" + + +def front_times(string, n): + """ + Given a string and a non-negative int n, we'll say that the front of the string is the first 3 chars, + or whatever is there if the string is less than length 3. Return n copies of the front; + front_times('Chocolate', 2) → 'ChoCho' + front_times('Chocolate', 3) → 'ChoChoCho' + front_times('Abc', 3) → 'AbcAbcAbc' + """ + return string[:3]*n diff --git a/students/navidbahadoran/Lesson03/mailroom.py b/students/navidbahadoran/Lesson03/mailroom.py new file mode 100644 index 0000000..7acac2a --- /dev/null +++ b/students/navidbahadoran/Lesson03/mailroom.py @@ -0,0 +1,119 @@ +""" +title: mailroom +Desc: Keep the data of donor and donation amount in charity organization + generate thanking email to donors, report of the donors list +change log: +NBahadoran, 1/27/2018, Created mailroom.py +""" + +import sys + +prompt = "\n".join(("Please choose from below options:", + "1 - Send a Thank You", + "2 - Create a Report", + "3 - quit", + ">>> ")) + +donor_db = [("William Gates, III", [653772.32, 12.17]), + ("Jeff Bezos", [877.33]), + ("Paul Allen", [663.23, 43.87, 1.32]), + ("Mark Zuckerberg", [1663.23, 4300.87, 10432.0]), + ("Warren Buffett", [323232, 4345.11, 122.28]) + ] + + +def send_thank_you(): + """ + -if the user (you) selects “Send a Thank You” option, prompt for a Full Name. + If the user types list show them a list of the donor names and re-prompt. + If the user types a name not in the list, add that name to the data structure and use it. + If the user types a name in the list, use it. + -Once a name has been selected, prompt for a donation amount. + Convert the amount into a number; it is OK at this point for the program to crash if + someone types a bogus amount. + Add that amount to the donation history of the selected user. + -Finally, use string formatting to compose an email thanking the donor for their generous donation. + Print the email to the terminal and return to the original prompt. + """ + while True: + name = input("Enter the full name of the donor(type 'list' to display list of donors):") + if name.lower() == "list": + max_length: int = 0 + for i in donor_db: + if max_length <= len(i[1]): + max_length = len(i[1]) + print("\n{:<30s}| ".format("Donor Name"), end="") + for i in range(max_length): + print("{:<9s}{:d}| ".format("Donation ", i + 1), end="") + print("\n", "-" * (32+12*max_length)) + for i in donor_db: + string = "{:<30s} " + for j in range(len(i[1])): + string += "${:>10,.2f} " + string += "\n" + print(string.format(i[0], *i[1])) + continue + break + for i in donor_db: + if name == i[0]: + try: + donation_amount = float(input("Enter the amount of donation:")) + i[1].append(donation_amount) + except Exception: + print("You enter wrong entry, please enter float number.") + break + else: + try: + donation_amount = float(input("Enter the amount of donation:")) + new_donor = (name, [donation_amount]) + donor_db.append(new_donor) + except Exception: + print("You enter wrong entry, please enter float number.") + print("Dear {},\n Thanks for your generous donation.\n".format(name.title())) + + +def create_report(): + """ + -If the user (you) selected “Create a Report,” print a list of your donors, sorted by total + historical donation amount. + Include Donor Name, total donated, number of donations, and average donation amount as + values in each row. You do not need to print out all of each donor’s donations, just the summary info. + Using string formatting, format the output rows as nicely as possible. The end result should be + tabular (values in each column should align with those above and below). + After printing this report, return to the original prompt. + -At any point, the user should be able to quit their current task and return to the original prompt. + -From the original prompt, the user should be able to quit the script cleanly. + """ + print("{:<30s}| {:<12s}| {:<10s}| {:<12s}".format("Donor Name", "Total Given", "Num Gifts", "Average Gift")) + print("-"*70) + + def sort_key(sequence): + return sum(sequence[1]) + for i in sorted(donor_db, key=sort_key, reverse=True): + print("{:<31s}${:>11,.2f}{:>12,d} ${:>12,.2f}\n".format(i[0], sum(i[1]), len(i[1]), sum(i[1])/len(i[1]))) + + +def exit_program(): + """Exit the program""" + print("Bye!") + sys.exit() # exit the interactive script + + +def main(): + while True: + response = input(prompt) # continuously collect user selection + # now redirect to feature functions based on the user selection + if response == "1": + send_thank_you() + elif response == "2": + create_report() + elif response == "3": + exit_program() + else: + print("Not a valid option!") + + +if __name__ == '__main__': + main() +else: + print("This script designed to run as a main") diff --git a/students/navidbahadoran/Lesson03/string_bits.py b/students/navidbahadoran/Lesson03/string_bits.py new file mode 100644 index 0000000..43df0eb --- /dev/null +++ b/students/navidbahadoran/Lesson03/string_bits.py @@ -0,0 +1,16 @@ +""" +title: string_bits +Desc: Given a string, return a new string made of every other char starting with the first, so "Hello" yields "Hlo". +change log: +NBahadoran, 1/27/2018, Created string_bits.py +""" + + +def string_bits(string): + """ + Given a string, return a new string made of every other char starting with the first, so "Hello" yields "Hlo". + string_bits('Hello') → 'Hlo' + string_bits('Hi') → 'H' + string_bits('Heeololeo') → 'Hello' + """ + return string[0::2] diff --git a/students/navidbahadoran/Lesson03/string_splosion.py b/students/navidbahadoran/Lesson03/string_splosion.py new file mode 100644 index 0000000..e29a680 --- /dev/null +++ b/students/navidbahadoran/Lesson03/string_splosion.py @@ -0,0 +1,21 @@ +""" +title: string_splosion +Desc: Given a string, return a new string made of every other char starting with the first, so "Hello" yields "Hlo". +change log: +NBahadoran, 1/27/2018, Created string_splosion.py +""" + + +def string_splosion(string): + """ + Given a non-empty string like "Code" return a string like "CCoCodCode". + string_splosion('Code') → 'CCoCodCode' + string_splosion('abc') → 'aababc' + string_splosion('ab') → 'aab' + """ + new_string="" + for i in range(len(string)): + new_string += string[0:i+1] + return new_string +string="navid" +print(string_splosion(string)) \ No newline at end of file diff --git a/students/navidbahadoran/Lesson03/string_times.py b/students/navidbahadoran/Lesson03/string_times.py new file mode 100644 index 0000000..8d76908 --- /dev/null +++ b/students/navidbahadoran/Lesson03/string_times.py @@ -0,0 +1,16 @@ +""" +title: string_times +Desc:Given a string and a non-negative int n, return a larger string that is n copies of the original string. +change log: +NBahadoran, 1/27/2018, Created string_times.py +""" + + +def string_times(string, n): + """ + Given a string and a non-negative int n, return a larger string that is n copies of the original string. + string_times('Hi', 2) → 'HiHi' + string_times('Hi', 3) → 'HiHiHi' + string_times('Hi', 1) → 'Hi' + """ + return string * n diff --git a/students/navidbahadoran/Lesson04/Exceptions_Lab.py b/students/navidbahadoran/Lesson04/Exceptions_Lab.py new file mode 100644 index 0000000..34214e8 --- /dev/null +++ b/students/navidbahadoran/Lesson04/Exceptions_Lab.py @@ -0,0 +1,9 @@ +def safe_input(): + return None + + +try: + a = input() +except (KeyboardInterrupt, EOFError): + safe_input() + diff --git a/students/navidbahadoran/Lesson04/dict_lab.py b/students/navidbahadoran/Lesson04/dict_lab.py new file mode 100644 index 0000000..7f01f7d --- /dev/null +++ b/students/navidbahadoran/Lesson04/dict_lab.py @@ -0,0 +1,81 @@ +#!/python37 +""" +title: Dict_Lab +Desc: Dict and Set manipulation +change log: +NBahadoran, 2/3/2018, Created dict_lab.py +""" +# ------------------Dictionaries 1--------------- +""" +Create a dictionary containing “name”, “city”, and “cake” for “Chris” from “Seattle” who likes “Chocolate” + (so the keys should be: “name”, etc, and values: “Chris”, etc.) +Display the dictionary. +Delete the entry for “cake”. +Display the dictionary. +Add an entry for “fruit” with “Mango” and display the dictionary. +Display the dictionary keys. +Display the dictionary values. +Display whether or not “cake” is a key in the dictionary (i.e. False) (now). +Display whether or not “Mango” is a value in the dictionary (i.e. True). +""" +print("-" * 20, "Dictionaries 1", "-" * 20) +dict1 = {"name": "Chris", "city": "Seattle", "cake": "Chocolate"} +print(dict1) +dict1.pop("cake") +print(dict1) +dict1["fruit"] = "Mango" +print(dict1) +print(dict1.keys()) +print(list(dict1.keys())) +print(dict1.values()) +print(list(dict1.values())) +print("cake" in dict1.keys()) +print("Mango" in dict1.values()) +""" +Dictionaries 2 +Using the dictionary from item 1: Make a dictionary using the same keys but with the number +of ‘t’s in each value as the value (consider upper and lower case?). +""" +print("-" * 20, "Dictionaries 1", "-" * 20) +dict1 = {"name": "Chris", "city": "Seattle", "cake": "Chocolate"} +dict2 = {} +for i in dict1: + dict2[i] = dict1[i].count("t") + dict1[i].count("T") +print(dict2) +""" +Sets +Create sets s2, s3 and s4 that contain numbers from zero through twenty, divisible by 2, 3 and 4. +Display the sets. +Display if s3 is a subset of s2 (False) +and if s4 is a subset of s2 (True). +""" +print("-" * 20, "Sets", "-" * 20) +s2 = set() +s3 = set() +s4 = set() +for i in range(21): + if i % 2 == 0: + s2.add(i) + if i % 3 == 0: + s3.add(i) + if i % 4 == 0: + s4.add(i) +print("s1={}\ns2={}\ns3={}".format(s2, s3, s4)) +print(s3.issubset(s2)) +print(s4.issubset(s2)) + +""" +Sets 2 +Create a set with the letters in ‘Python’ and add ‘i’ to the set. +Create a frozenset with the letters in ‘marathon’. +display the union and intersection of the two sets. +""" +print("-" * 20, "Sets 2", "-" * 20) +s5 = set("Python") +print(s5) +s5.add("i") +print(s5) +s6=frozenset("marathon") +print(s6) +print(s5|s6) +print(s5 & s6) diff --git a/students/navidbahadoran/Lesson04/file_exercise.py b/students/navidbahadoran/Lesson04/file_exercise.py new file mode 100644 index 0000000..1e42b82 --- /dev/null +++ b/students/navidbahadoran/Lesson04/file_exercise.py @@ -0,0 +1,63 @@ +import pathlib + +""" +title: File_Exercise +Desc: Get a little bit of practice with handling files and parsing simple text. +change log: +NBahadoran, 2/3/2018, Created file_exercise.py +""" +""" +Paths and File Processing +Write a program which prints the full path for all files in the current directory, one per line +Write a program which copies a file from a source, to a destination (without using shutil, or the OS copy command). +Advanced: make it work for any size file: i.e. don’t read the entire contents of the file into memory at once. +This should work for any kind of file, so you need to open the files in binary mode: open(filename, 'rb') + (or 'wb' for writing). Note that for binary files, you can’t use readline() + – lines don’t have any meaning for binary files. +Test it with both text and binary files (maybe jpeg or something of your choosing). +""" + +pth = pathlib.Path('./') +for f in pth.iterdir(): + print(f, ":", pathlib.Path(f).resolve()) + +source_pth = input("Enter Source file name and it's path to copy from(Ex.:c:\\user\\abc.txt):") +destination_pth = input("Enter Destination file name and it's path to copy into(Ex.:c:\\users\\abc.txt):") +try: + with open(source_pth, "rb") as infile, open(destination_pth, "wb") as outfile: + size = 10 + while True: + buffer = infile.read(size) + if buffer != b"": + outfile.write(buffer) + else: + break +except Exception: + print("There is issue with your file") + +""" +File reading and parsing +Download this text file: +students.txt +In it, you will find a list of names and what programming languages they have used in the past. +This may be similar to a list generated at the beginning of this class. +Write a little script that reads that file, and generates a list of all the languages that have been used. +""" +print("-" * 20, "File reading and parsing", "-" * 20) +fh = open("students.txt", "r") +next(fh) # remove header +lines = fh.readlines() +print(lines) +language = set() +for i in lines: + for j in i.split(":")[1].strip().split(", "): + if j: + language.add(j.strip(",")) +print("List of all languages that have benn used is:\n{}".format(language)) +# Extra challenge: keep track of how many students specified each language. +for i in language: + student_no = 0 + for j in lines: + if i in j.split(":")[1].strip().split(", "): + student_no += 1 + print("{} of students has been using {}".format(student_no, i)) diff --git a/students/navidbahadoran/Lesson04/mailroom_part_2.py b/students/navidbahadoran/Lesson04/mailroom_part_2.py new file mode 100644 index 0000000..0d723cc --- /dev/null +++ b/students/navidbahadoran/Lesson04/mailroom_part_2.py @@ -0,0 +1,151 @@ +""" +title: mailroom +Desc: Keep the data of donor and donation amount in charity organization + generate thanking email to donors, report of the donors list +change log: +NBahadoran, 2/03/2018, Created mailroom.py +""" + +main_prompt = "\n".join(("Please choose from below options:", + "1 - Send a Thank You to a single donor", + "2 - Create a Report", + "3 - Send letters to all donors", + "4- quit", + ">>> ")) +donor_db = [("William Gates, III", [653772.32, 12.17]), + ("Jeff Bezos", [877.33]), + ("Paul Allen", [663.23, 43.87, 1.32]), + ("Mark Zuckerberg", [1663.23, 4300.87, 10432.0]), + ("Warren Buffett", [323232, 4345.11, 122.28]) + ] +# convert our old data base to dictionary +key = ("first_name", "last_name", "donation") +donor_db_dict = [] +for i in donor_db: + new_tuple = tuple(i[0].split(" ", 1)) + (i[1],) + donor_db_dict += [dict(zip(key, new_tuple))] + + +def send_thank_you(): + """ + -if the user (you) selects “Send a Thank You” option, prompt for a Full Name. + If the user types list show them a list of the donor names and re-prompt. + If the user types a name not in the list, add that name to the data structure and use it. + If the user types a name in the list, use it. + -Once a name has been selected, prompt for a donation amount. + Convert the amount into a number; it is OK at this point for the program to crash if + someone types a bogus amount. + Add that amount to the donation history of the selected user. + -Finally, use string formatting to compose an email thanking the donor for their generous donation. + Print the email to the terminal and return to the original prompt. + """ + while True: + first_name = input("Enter the first name of the donor(type 'list' to display list of donors):") + if first_name.lower() == "list": + max_length: int = 0 + for i in donor_db_dict: + if max_length <= len(i["donation"]): + max_length = len(i["donation"]) + print("\n{:<30s}| ".format("Donor Name"), end="") + for i in range(max_length): + print("{:<9s}{:d}| ".format("Donation ", i + 1), end="") + print("\n", "-" * (32 + 12 * max_length)) + for i in donor_db_dict: + string = "{first_name:<10s}" + "{last_name:<20s} " + for j in range(len(i["donation"])): + string += "${:>10,.2f} " + string += "\n" + print(string.format(*i["donation"], **i)) + continue + break + last_name = input("Enter the last name of the donor:") + for i in donor_db_dict: + if first_name.lower() == i["first_name"].lower() and last_name.lower() == i["last_name"].lower(): + try: + donation_amount = float(input("Enter the amount of donation:")) + i["donation"].append(donation_amount) + print("Dear {first_name} {last_name},\nThanks for your generous donation.\n".format(**i)) + except Exception: + print("You enter wrong entry, please enter float number.") + break + else: + new_entry = {} + try: + donation_amount = float(input("Enter the amount of donation:")) + new_entry["first_name"] = first_name.title() + new_entry["last_name"] = last_name.title() + new_entry["donation"] = [donation_amount] + donor_db_dict.append(new_entry) + print("Dear {first_name} {last_name},\nThanks for your generous donation.\n".format(**new_entry)) + except Exception: + print("You enter wrong entry, please enter float number.") + + +def create_report(): + """ + -If the user (you) selected “Create a Report,” print a list of your donors, sorted by total + historical donation amount. + Include Donor Name, total donated, number of donations, and average donation amount as + values in each row. You do not need to print out all of each donor’s donations, just the summary info. + Using string formatting, format the output rows as nicely as possible. The end result should be + tabular (values in each column should align with those above and below). + After printing this report, return to the original prompt. + -At any point, the user should be able to quit their current task and return to the original prompt. + -From the original prompt, the user should be able to quit the script cleanly. + """ + print("{:<30s}| {:<12s}| {:<10s}| {:<12s}".format("Donor Name", "Total Given", "Num Gifts", "Average Gift")) + print("-" * 70) + + def sort_key(sequence): + return sum(list(sequence.values())[2]) + + for i in sorted(donor_db_dict, key=sort_key, reverse=True): + i["total_give"] = sum(i["donation"]) + i["num_gift"] = len(i["donation"]) + i["avg_gift"] = i["total_give"] / i["num_gift"] + print("{first_name:<11s}{last_name:<20s}${total_give:>11,.2f}{num_gift:>12,d} ${avg_gift:>12,.2f}\n" + .format(**i)) + + +def send_letters(): + for i in donor_db_dict: + letter = "Dear {first_name} {last_name},\nThank you for your very kind donation of {:8.2f}.\ + \rIt will be put to very good use.\nSincerely,\n-The Team".format(sum(i["donation"]), **i) + file_name = i["first_name"] + "_" + i["last_name"].replace(",", "_").replace("__", "_") + "." + "txt" + write_to_file(letter, file_name) + + +def write_to_file(text_letter, file_name): + with open(file_name, "w") as fh: + fh.write(text_letter) + + +def exit_program(): + """Exit the program""" + print("Quiting program") + return "exit_menu" + + +def menu_selection(prompt, dispatch_dict): + while True: + response = input(prompt) + if dispatch_dict[response]() == "exit_menu": + break + + +main_dispatch = {"1": send_thank_you, + "2": create_report, + "3": send_letters, + "4": exit_program + } + + +def main(): + menu_selection(main_prompt, main_dispatch) + print("Bye!") + + +if __name__ == '__main__': + main() +else: + print("This script designed to run as a main") diff --git a/students/navidbahadoran/Lesson04/students.txt b/students/navidbahadoran/Lesson04/students.txt new file mode 100644 index 0000000..dc8508d --- /dev/null +++ b/students/navidbahadoran/Lesson04/students.txt @@ -0,0 +1,31 @@ +Name: Nickname, languages +Swift, Taylor: python, java, perl +Swift, Samuel: Sam +Brooks, Garth: fortran, java, matlab, bash +Buble, Michael: python, powershell +Stefani, Gwen: c#, javascript, python, typescript +Gaye, Marvin: c++, java +Jagger, Michael: Mick, shell, python +Lennon, John: +Nelson, Willy: python, java +McCartney, Paul: nothing +Dylan, Bob: java, python, ruby +Springsteen, Bruce: c++, python +Jackson, Michael: java, c#, python +Berry, Charles: Chuck c++, matlab, +Wonder, Steven: Stevie, c, perl, java, erlang, python +Nicks, Stevie: java, perl, c#, c++, python +Turner, Tina: bash, python +Plant, Robert: Bob, bash, python, ansible +Townshend, Peter: Pete, c#, powershell, python, sql +Moon, Keith: python, r, visualbasic +Mitchell, Joni: php, mysql, python +Ramone, John: Johnny, rex, db +King, Carol: r +Waters, Muddy: perl, python +Star, Richard: Ringo, Tom, shell, python, vb +Smith, Patricia: Patti, Gene, python +Morrison, Jim: fortran, perl, sql, python +Marley, Robert: Bob, c, c++, lisp +Simon, Paul: bash, python, sql +Charles, Ray: Chuck, java, python diff --git a/students/navidbahadoran/Lesson04/test.txt b/students/navidbahadoran/Lesson04/test.txt new file mode 100644 index 0000000..a893eee --- /dev/null +++ b/students/navidbahadoran/Lesson04/test.txt @@ -0,0 +1 @@ +I wish I may I wish I might \ No newline at end of file diff --git a/students/navidbahadoran/Lesson04/trigrams.py b/students/navidbahadoran/Lesson04/trigrams.py new file mode 100644 index 0000000..af638b6 --- /dev/null +++ b/students/navidbahadoran/Lesson04/trigrams.py @@ -0,0 +1,40 @@ +import random + + +def build_trigrams(words_text): + trigrams = {} + for i in range(len(words_text) - 2): + pair = tuple(words_text[i:i + 2]) + follower = [words_text[i + 2]] + trigrams[pair] = trigrams.get(pair, []) + follower + return trigrams + + +def build_text(trigrams, start_words): + text = list(start_words) + while trigrams.get(start_words): + text = text + [trigrams[start_words].pop(0)] + start_words = tuple(text[-2:]) + return text + + +def read_in_data(filename): + try: + with open(filename, "r") as fh: + text = fh.read() + return text + except IOError as e: + print("There is issue with your file", e) + + +def make_words(text): + return text.split() + + +if __name__ == "__main__": + in_data = read_in_data("test.txt") + words = make_words(in_data) + word_pairs = build_trigrams(words) + random_pair = random.choice(list(word_pairs.keys())) + new_text = build_text(word_pairs, random_pair) + print(" ".join(new_text).capitalize()) diff --git a/students/navidbahadoran/Lesson05/except_exercise.py b/students/navidbahadoran/Lesson05/except_exercise.py new file mode 100644 index 0000000..2748790 --- /dev/null +++ b/students/navidbahadoran/Lesson05/except_exercise.py @@ -0,0 +1,60 @@ +#!/usr/bin/python + +""" +An exercise in playing with Exceptions. +Make lots of try/except blocks for fun and profit. + +Make sure to catch specifically the error you find, rather than all errors. +""" + +from except_test import fun, more_fun, last_fun + +# Figure out what the exception is, catch it and while still +# in that catch block, try again with the second item in the list +first_try = ['spam', 'cheese', 'mr death'] +try: + joke = fun(first_try[0]) +except NameError as e: + pass +finally: + try: + joke = fun(first_try[1]) + except Exception: + print('Something is wrong!') + +# Here is a try/except block. Add an else that prints not_joke +try: + not_joke = fun(first_try[2]) +except SyntaxError: + print('Run Away!') +else: + print(not_joke) + +# What did that do? You can think of else in this context, as well as in +# loops as meaning: "else if nothing went wrong" +# (no breaks in loops, no exceptions in try blocks) + +# Figure out what the exception is, catch it and in that same block +# +# try calling the more_fun function with the 2nd language in the list, +# again assigning it to more_joke. +# +# If there are no exceptions, call the more_fun function with the last +# language in the list + +# Finally, while still in the try/except block and regardless of whether +# there were any exceptions, call the function last_fun with no +# parameters. (pun intended) + +langs = ['java', 'c', 'python'] +try: + for i in langs: + try: + more_joke = more_fun(i) + except IndexError: + continue +except Exception as e: + print(e) +finally: + last_fun() + diff --git a/students/navidbahadoran/Lesson05/except_test.py b/students/navidbahadoran/Lesson05/except_test.py new file mode 100644 index 0000000..905dd67 --- /dev/null +++ b/students/navidbahadoran/Lesson05/except_test.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +""" +silly little test module that is designed to trigger Exceptions when +run from the except_exercise.py file +""" + +import time + +conclude = "And what leads you to that conclusion?" +district = "Finest in the district, sir." +cheese = "It's certainly uncontaminated by cheese." +clean = "Well, it's so clean." +shop = "Not much of a cheese shop really, is it?" +cust = "Customer: " +clerk = "Shopkeeper: " + + +def fun(reaper): + if reaper == 'spam': + print(s) + elif reaper == 'cheese': + print() + print('Spam, Spam, Spam, Spam, Beautiful Spam') + elif reaper == 'mr death': + print() + return('{}{}\n{}{}'.format(cust, shop, clerk, district)) + + +def more_fun(language): + if language == 'java': + test = [1, 2, 3] + test[5] = language + elif language == 'c': + print('{}{}\n{}{}'.format(cust, conclude, clerk, clean)) + + +def last_fun(): + print(cust, cheese) + time.sleep(1) + import antigravity diff --git a/students/navidbahadoran/Lesson05/mailroom_part_3.py b/students/navidbahadoran/Lesson05/mailroom_part_3.py new file mode 100644 index 0000000..e9335a5 --- /dev/null +++ b/students/navidbahadoran/Lesson05/mailroom_part_3.py @@ -0,0 +1,199 @@ +""" +title: mailroom3 +Desc: Keep the data of donor and donation amount in charity organization + generate thanking email to donors, report of the donors list +change log: +NBahadoran, 2/10/2018, Created mailroom_part_3.py +""" +from textwrap import dedent + +main_prompt = "\n".join(("Please choose from below options:", + "(Any other choice quit the program)", + "1 - Send a Thank You to a single donor", + "2 - Create a Report", + "3 - Send letters to all donors", + "4- quit", + ">>> ")) +donor_db = [("William Gates, III", [653772.32, 12.17]), + ("Jeff Bezos", [877.33]), + ("Paul Allen", [663.23, 43.87, 1.32]), + ("Mark Zuckerberg", [1663.23, 4300.87, 10432.0]), + ("Warren Buffett", [323232, 4345.11, 122.28]) + ] +# convert our old data base to dictionary +key = ("first_name", "last_name", "donation") +new_tpl = ((i[0].split(" ", 1)[0], i[0].split(" ", 1)[1], i[1]) for i in donor_db) +donor_db_dict = [dict(zip(key, i)) for i in new_tpl] + + +def find_donor(first_name, last_name): + """ + :param first_name: first name of donor + :param last_name: last name of donor + :return: either donors dict if the donor is already in the list or empty dict + """ + for donor in donor_db_dict: + if first_name == donor["first_name"] and last_name == donor["last_name"]: + return donor + return dict() + + +def print_donors(): + """ this function print the list of donors with all their donation + if the user ask for the list of donors, """ + max_length: int = 0 + for i in donor_db_dict: + if max_length <= len(i["donation"]): + max_length = len(i["donation"]) + print("\n{:<30s}| ".format("Donor Name"), end="") + for i in range(max_length): + print("{:<9s}{:d}| ".format("Donation ", i + 1), end="") + print("\n", "-" * (32 + 12 * max_length)) + for i in donor_db_dict: + string = "{first_name:<10s}" + "{last_name:<20s} " + for j in range(len(i["donation"])): + string += "${:>10,.2f} " + string += "\n" + print(string.format(*i["donation"], **i)) + + +def send_thank_you(): + """ + -if the user (you) selects “Send a Thank You” option, prompt for a Full Name. + If the user types list show them a list of the donor names and re-prompt. + if user types menu it is going to main menu + If the user types a name not in the list, add that name to the data structure and use it. + If the user types a name in the list, use it. + -Once a name has been selected, prompt for a donation amount. + Convert the amount into a number; + Add that amount to the donation history of the selected user. + """ + while True: + first_name = input("Enter the donor's first name" + "(or 'list' to see all donors or 'menu' to exit)> :").strip().title() + if first_name.lower() == "list": + print_donors() + elif first_name.lower() == "menu": + return + else: + break + while True: + last_name = input("Enter the donor's last name" + "(or 'menu' to exit)> :").strip().title() + if last_name.lower() == "menu": + return + else: + break + while True: + amount_str = input("Enter a donation amount (or 'menu' to exit) > ").strip() + if amount_str == "menu": + return + # Make sure amount is a valid amount before leaving the input loop + try: + amount = float(amount_str) + except Exception: + continue + else: + break + donor = find_donor(first_name, last_name) + if not donor: + donor["first_name"] = first_name.title() + donor["last_name"] = last_name.title() + donor["donation"] = [] + donor_db_dict.append(donor) + donor["donation"].append(amount) + print(send_letters(donor, "single")) + + +def create_report(): + """ + -If the user (you) selected “Create a Report,” print a list of your donors, sorted by total + historical donation amount. + Include Donor Name, total donated, number of donations, and average donation amount as + values in each row. + -At any point, the user should be able to quit their current task and return to the original prompt. + -From the original prompt, the user should be able to quit the script cleanly. + """ + print("{:<30s}| {:<12s}| {:<10s}| {:<12s}".format("Donor Name", "Total Given", "Num Gifts", "Average Gift")) + print("-" * 70) + + def sort_key(sequence): + return sum(list(sequence.values())[2]) + + for i in sorted(donor_db_dict, key=sort_key, reverse=True): + i["total_give"] = sum(i["donation"]) + i["num_gift"] = len(i["donation"]) + i["avg_gift"] = i["total_give"] / i["num_gift"] + print("{first_name:<11s}{last_name:<20s}${total_give:>11,.2f}{num_gift:>12,d} ${avg_gift:>12,.2f}\n" + .format(**i)) + + +def send_letters(donor, flag="all"): + """ + it create an email either for one single or all donors + :param donor: it includes donors info + :param flag: could be "single" or "all" + :return: Composed email for single donor or for all donors + """ + donation_amount = sum(donor["donation"]) + if flag == "single": + donation_amount = donor["donation"][-1] + + letter = dedent("""Dear {first_name} {last_name}. + +Thank you for your very kind donation of ${:.2f}. +It will be put to very good use. + + Sincerely, + -The Team + """.format(donation_amount, **donor)) + return letter + + +def write_letter_to_file(): + """ + Write the created letter into the text file with the name the same as donor's name + :return: None + """ + for donor in donor_db_dict: + file_name = donor["first_name"] + "_" + donor["last_name"].replace(",", "_").replace("__", "_") \ + + "." + "txt" + with open(file_name, "w") as fh: + fh.write(send_letters(donor, "all")) + + +def exit_program(): + """Exit the program""" + print("Quiting program") + return "exit_menu" + + +def repeat_menu(): + menu_selection(main_prompt, main_dispatch) + + +def menu_selection(prompt, dispatch_dict): + response = input(prompt) + if dispatch_dict.get(response, repeat_menu)() == "exit_menu": + return False + return True + + +main_dispatch = {"1": send_thank_you, + "2": create_report, + "3": write_letter_to_file, + "4": exit_program + } + + +def main(): + running = True + while running: + running = menu_selection(main_prompt, main_dispatch) + print("Bye!") + + +if __name__ == '__main__': + main() +else: + print("This script designed to run as a main") diff --git a/students/navidbahadoran/Lesson06/mailroom_part_4.py b/students/navidbahadoran/Lesson06/mailroom_part_4.py new file mode 100644 index 0000000..49193cb --- /dev/null +++ b/students/navidbahadoran/Lesson06/mailroom_part_4.py @@ -0,0 +1,167 @@ +""" +title: mailroom4 +Desc: Keep the data of donor and donation amount in charity organization + generate thanking email to donors, report of the donors list +change log: +NBahadoran, 2/17/2018, Created mailroom_part_4.py +""" +from textwrap import dedent +import pickle + + +def print_usage(): + print("\n".join(("Please choose from below options:", + "(Any other choice quit the program)", + "1 - Send a thank you", + "2 - Help (Print Menu)", + "3 - List donors", + "4 - print Report", + "5 - Show database", + "6 - Thank donors", + "7 - quit"))) + + +def load_donordb(): + try: + with open('mailroom_db.pickle', 'rb') as db_handle: + donor_db = pickle.load(db_handle) + except IOError: + donor_db = {"William Gates, III": [653772.32, 12.17], + "Jeff Bezos": [877.33], + "Paul Allen": [663.23, 43.87, 1.32], + "Mark Zuckerberg": [1663.23, 4300.87, 10432.0], + "Warren Buffett": [323232, 4345.11, 122.28] + } + return donor_db + + +def save_donordb(db): + try: + with open('mailroom_db.pickle', 'wb') as db_handle: + pickle.dump(db, db_handle) + except IOError: + print("Error: Unable to save donor database.") + + +def ask_for_info(db): + donor = input("mailroom: What is the name of the donor" + "(or 'list' to see all donors or 'menu' to show menu)>") + if donor.lower() == "list": + print_list(db) + return None + elif donor.lower() == "menu": + print_usage() + return None + contribution_amount = input("mailroom>> How much is {} contributing? ".format(donor)) + if add_donation(db, donor, contribution_amount): + print(send_thank_you(donor.title(), float(contribution_amount))) + + +def add_donation(db, donor, contribution): + # Validate user input as numeric + try: + float(contribution) + except ValueError as my_except: + print("mailroom>> Input validation error: {}".format(my_except)) + return None + + # Catch embezzlement + try: + assert float(contribution) >= 0.0 + except AssertionError as my_except: + print("mailroom>> Donations must be greater than $0.00: {}".format(my_except)) + return None + + db.setdefault(donor, []) + db[donor].append(float(contribution)) + return db + + +def print_db(db): + for name, donations in db.items(): + print(name, donations) + + +def tally_report(values): + donation_total = sum(values) + num_gifts = len(values) + average_gift = donation_total / num_gifts + return donation_total, num_gifts, average_gift + + +def print_report(db): + # Print a header + print("Donor Name | Total Given | Num Gifts | Average Gift") + + # Print each row + for names, values in sorted(db.items(), key=lambda x: sum(x[1])): + donation_total, num_gifts, average_gift = tally_report(values) + + print("{} | {:11,.2f} | {} | ${:11,.2f}".format( + names.ljust(25), + donation_total, + str(num_gifts).rjust(9), + average_gift, + )) + + +def send_thank_you(donor, contribution): + letter = dedent("""Dear {:s}, + + Thank you for your very kind donation of ${:.2f}. + It will be put to very good use. + + Sincerely, + -The Mailroom Team + """.format(donor, contribution)) + return letter + + +def print_list(db): + print(sorted(set(db.keys()))) + + +def thank_donor(donor, amount): + with open('mailroom-thankyou-{}.txt'.format(donor), 'w') as f: + f.write(send_thank_you(donor.title(), amount)) + + +def thank_donors(db): + for name, values in db.items(): + thank_donor(name, sum(values)) + + +def main(): + # Handle user interaction in the main event loop + + donor_db = load_donordb() + + while True: + user_input = input("mailroom>> ") + + if user_input == '7': + save_donordb(donor_db) + break + + elif user_input == '1': + ask_for_info(donor_db) + + elif user_input == '2': + print_usage() + + elif user_input == '3': + print_list(donor_db) + + elif user_input == '4': + print_report(donor_db) + + elif user_input == '5': + print_db(donor_db) + + elif user_input == '6': + thank_donors(donor_db) + + +if __name__ == '__main__': + print_usage() + main() diff --git a/students/navidbahadoran/Lesson06/test_mailroom.py b/students/navidbahadoran/Lesson06/test_mailroom.py new file mode 100644 index 0000000..169639f --- /dev/null +++ b/students/navidbahadoran/Lesson06/test_mailroom.py @@ -0,0 +1,38 @@ +from mailroom_part_4 import tally_report, send_thank_you, add_donation, thank_donor +from textwrap import dedent +import pickle +import os + + +def test_talley_report(): + assert tally_report([1, 2, 3]) == (6, 3, 2) + + +def test_thank_donor(): + thank_donor("Navid", 123.25) + pth = os.getcwd() + file_name = 'mailroom-thankyou-{}.txt'.format("Navid") + pth += "\\" + file_name + assert os.path.lexists(pth) is True + + +def test_send_thank_you(): + letter = dedent("""Dear {:s}, + + Thank you for your very kind donation of ${:.2f}. + It will be put to very good use. + + Sincerely, + -The Mailroom Team + """.format("Navid", 123.25)) + assert letter == send_thank_you("Navid", 123.25) + + +def test_add_donation(): + with open('mailroom_db.pickle', 'rb') as db_handle: + donor_db = pickle.load(db_handle) + new = {} + a = "tyu" + new.setdefault(a, [676.55]) + new.update(donor_db) + assert add_donation(donor_db, a, 676.55) == new diff --git a/students/navidbahadoran/Lesson07/html_render.py b/students/navidbahadoran/Lesson07/html_render.py new file mode 100644 index 0000000..b971d06 --- /dev/null +++ b/students/navidbahadoran/Lesson07/html_render.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 + +""" +A class-based system for rendering html. +""" + + +# This is the framework for the base class +class Element(object): + tag = 'html' + indent = ' ' + + def __init__(self, content=None, **kwargs): + self.content = content + self.attributes = kwargs + + @property + def content(self): + return self.__content + + @content.setter + def content(self, val): + if val: + self.__content = [val] + else: + self.__content = [] + + def append(self, new_content): + self.content.append(new_content) + + def _open_tag(self): + open_tag = list("<{}".format(self.tag)) + for k, v in self.attributes.items(): + open_tag.append(' {}="{}"'.format(k, v)) + open_tag.append(">") + return "".join(open_tag) + + def _close_tag(self): + return ''.format(self.tag) + + def render(self, out_file, cur_ind=''): + # cur_ind += self.indent + out_file.write(cur_ind + self._open_tag()) + out_file.write("\n") + for content in self.__content: + if hasattr(content, 'render'): + content.render(out_file, cur_ind + self.indent) + else: + out_file.write(cur_ind + self.indent + content) + out_file.write("\n") + out_file.write(cur_ind + self._close_tag()) + out_file.write("\n") + + +class Html(Element): + tag = 'html' + + def render(self, out_file, cur_ind=''): + out_file.write(cur_ind + '') + out_file.write('\n') + super().render(out_file, cur_ind) + + +class Body(Element): + tag = 'body' + + +class P(Element): + tag = 'p' + + +class OneLineTag(Element): + + def render(self, out_file, cur_ind=''): + tag = cur_ind + self._open_tag() + self.content[0] + self._close_tag() + out_file.write(tag) + out_file.write("\n") + + def append(self, new_content): + raise NotImplementedError + + +class Title(OneLineTag): + tag = 'title' + + +class Head(Element): + tag = 'head' + + +class SelfClosingTag(Element): + + def __init__(self, content=None, **kwargs): + if content is not None: + raise TypeError("SelfClosingTag can not contain any content") + super().__init__(content=content, **kwargs) + + def append(self, *args): + raise TypeError("You can not add content to a SelfClosingTag") + + def render(self, outfile, cur_ind=''): + tag = cur_ind + self._open_tag()[:-1] + " />\n" + outfile.write(tag) + + +class Hr(SelfClosingTag): + tag = "hr" + + +class Br(SelfClosingTag): + tag = "br" + + +class A(OneLineTag): + tag = 'a' + + def __init__(self, link, content=None, **kwargs): + kwargs['href'] = link + super().__init__(content, **kwargs) + + +class H(OneLineTag): + def __init__(self, the_new_tag_value, content=None, **kwargs): + self.tag = 'h{}'.format(the_new_tag_value) + super().__init__(content, **kwargs) + + +class Ul(Element): + tag = 'ul' + + +class Li(Element): + tag = 'li' + + +class Meta(SelfClosingTag): + tag = 'meta' diff --git a/students/navidbahadoran/Lesson07/run_html_render.py b/students/navidbahadoran/Lesson07/run_html_render.py new file mode 100644 index 0000000..b218a47 --- /dev/null +++ b/students/navidbahadoran/Lesson07/run_html_render.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 + +""" +a simple script can run and test your html rendering classes. + +Uncomment the steps as you add to your rendering. + +""" + +from io import StringIO + +# importing the html_rendering code with a short name for easy typing. +import html_render as hr + + +# writing the file out: +def render_page(page, filename, indent=None): + """ + render the tree of elements + + This uses StringIO to render to memory, then dump to console and + write to file -- very handy! + """ + + f = StringIO() + if indent is None: + page.render(f) + else: + page.render(f, indent) + + # print(f.getvalue()) + with open(filename, 'w') as outfile: + outfile.write(f.getvalue()) + + +# Step 1 +######### + +page = hr.Element() + +page.append("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text") + +page.append("And here is another piece of text -- you should be able to add any number") + +render_page(page, "test_html_output1.html") + +# out_file.write(cur_ind + self.indent + content) +# out_file.write("\n") + +## Step 2 +########## + +page = hr.Html() + +body = hr.Body() + +body.append(hr.P("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text")) + +body.append(hr.P("And here is another piece of text -- you should be able to add any number")) + +page.append(body) + +render_page(page, "test_html_output2.html") + +# Step 3 +########## + +page = hr.Html() + +head = hr.Head() +head.append(hr.Title("PythonClass = Revision 1087:")) + +page.append(head) + +body = hr.Body() + +body.append(hr.P("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text")) +body.append(hr.P("And here is another piece of text -- you should be able to add any number")) + +page.append(body) + +render_page(page, "test_html_output3.html") + +# Step 4 +########## + +page = hr.Html() + +head = hr.Head() +head.append(hr.Title("PythonClass = Revision 1087:")) + +page.append(head) + +body = hr.Body() + +body.append(hr.P("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text", + style="text-align: center; font-style: oblique;")) + +page.append(body) + +render_page(page, "test_html_output4.html") + +# Step 5 +######### + +page = hr.Html() + +head = hr.Head() +head.append(hr.Title("PythonClass = Revision 1087:")) + +page.append(head) + +body = hr.Body() + +body.append(hr.P("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text", + style="text-align: center; font-style: oblique;")) + +body.append(hr.Hr()) + +page.append(body) + +render_page(page, "test_html_output5.html") + +# Step 6 +######### + +page = hr.Html() + +head = hr.Head() +head.append(hr.Title("PythonClass = Revision 1087:")) + +page.append(head) + +body = hr.Body() + +body.append(hr.P("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text", + style="text-align: center; font-style: oblique;")) + +body.append(hr.Hr()) + +body.append("And this is a ") +body.append( hr.A("http://google.com", "link") ) +body.append("to google") + +page.append(body) + +render_page(page, "test_html_output6.html") + +# Step 7 +# ######## + +page = hr.Html() + +head = hr.Head() +head.append(hr.Title("PythonClass = Revision 1087:")) + +page.append(head) + +body = hr.Body() + +body.append( hr.H(2, "PythonClass - Class 6 example") ) + +body.append(hr.P("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text", + style="text-align: center; font-style: oblique;")) + +body.append(hr.Hr()) + +list = hr.Ul(id="TheList", style="line-height:200%") + +list.append( hr.Li("The first item in a list") ) +list.append( hr.Li("This is the second item", style="color: red") ) + +item = hr.Li() +item.append("And this is a ") +item.append( hr.A("http://google.com", "link") ) +item.append("to google") + +list.append(item) + +body.append(list) + +page.append(body) + +render_page(page, "test_html_output7.html") + +# Step 8 and 9 +############## + +page = hr.Html() + + +head = hr.Head() +head.append(hr.Meta(charset="UTF-8")) +head.append(hr.Title("PythonClass = Revision 1087:")) + +page.append(head) + +body = hr.Body() + +body.append(hr.H(2, "PythonClass - Example")) + +body.append(hr.P("Here is a paragraph of text -- there could be more of them, " + "but this is enough to show that we can do some text", + style="text-align: center; font-style: oblique;")) + +body.append(hr.Hr()) + +list = hr.Ul(id="TheList", style="line-height:200%") + +list.append(hr.Li("The first item in a list")) +list.append(hr.Li("This is the second item", style="color: red")) + +item = hr.Li() +item.append("And this is a ") +item.append(hr.A("http://google.com", "link")) +item.append("to google") + +list.append(item) + +body.append(list) + +page.append(body) + +render_page(page, "test_html_output8.html") diff --git a/students/navidbahadoran/Lesson07/sample_html.html b/students/navidbahadoran/Lesson07/sample_html.html new file mode 100644 index 0000000..9c2e675 --- /dev/null +++ b/students/navidbahadoran/Lesson07/sample_html.html @@ -0,0 +1,27 @@ + + + + + Python Class Sample page + + +

Python Class - Html rendering example

+

+ Here is a paragraph of text -- there could be more of them, but this is enough to show that we can do some text +

+
+ + + \ No newline at end of file diff --git a/students/navidbahadoran/Lesson07/test_html_render.py b/students/navidbahadoran/Lesson07/test_html_render.py new file mode 100644 index 0000000..a6223c8 --- /dev/null +++ b/students/navidbahadoran/Lesson07/test_html_render.py @@ -0,0 +1,385 @@ +""" +test code for html_render.py + +This is just a start -- you will need more tests! +""" + +import io +import pytest + +# import * is often bad form, but makes it easier to test everything in a module. +from html_render import * + + +# utility function for testing render methods +# needs to be used in multiple tests, so we write it once here. +def render_result(element, ind=""): + """ + calls the element's render method, and returns what got rendered as a + string + """ + # the StringIO object is a "file-like" object -- something that + # provides the methods of a file, but keeps everything in memory + # so it can be used to test code that writes to a file, without + # having to actually write to disk. + outfile = io.StringIO() + # this so the tests will work before we tackle indentation + if ind: + element.render(outfile, ind) + else: + element.render(outfile) + return outfile.getvalue() + + +######## +# Step 1 +######## + +def test_init(): + """ + This only tests that it can be initialized with and without + some content -- but it's a start + """ + e = Element() + + e = Element("this is some text") + + +def test_append(): + """ + This tests that you can append text + + It doesn't test if it works -- + that will be covered by the render test later + """ + e = Element("this is some text") + e.append("some more text") + + +def test_render_element(): + """ + Tests whether the Element can render two pieces of text + So it is also testing that the append method works correctly. + + It is not testing whether indentation or line feeds are correct. + """ + e = Element("this is some text") + e.append("and this is some more text") + + # This uses the render_results utility above + file_contents = render_result(e).strip() + + # making sure the content got in there. + assert "this is some text" in file_contents + assert "and this is some more text" in file_contents + + # make sure it's in the right order + assert file_contents.index("this is") < file_contents.index("and this") + + # making sure the opening and closing tags are right. + assert file_contents.startswith("") + assert file_contents.endswith("") + + +# Uncomment this one after you get the one above to pass +# Does it pass right away? +def test_render_element2(): + """ + Tests whether the Element can render two pieces of text + So it is also testing that the append method works correctly. + + It is not testing whether indentation or line feeds are correct. + """ + e = Element() + e.append("this is some text") + e.append("and this is some more text") + + # This uses the render_results utility above + file_contents = render_result(e).strip() + + # making sure the content got in there. + assert "this is some text" in file_contents + assert "and this is some more text" in file_contents + + # make sure it's in the right order + assert file_contents.index("this is") < file_contents.index("and this") + + # making sure the opening and closing tags are right. + assert file_contents.startswith("") + assert file_contents.endswith("") + + +# ######## +# # Step 2 +# ######## + +# tests for the new tags +def test_html(): + e = Html("this is some text") + e.append("and this is some more text") + + file_contents = render_result(e).strip() + + assert "this is some text" in file_contents + assert "and this is some more text" in file_contents + print(file_contents) + assert file_contents.endswith("") + + +def test_body(): + e = Body("this is some text") + e.append("and this is some more text") + + file_contents = render_result(e).strip() + + assert "this is some text" in file_contents + assert "and this is some more text" in file_contents + + assert file_contents.startswith("") + assert file_contents.endswith("") + + +def test_p(): + e = P("this is some text") + e.append("and this is some more text") + + file_contents = render_result(e).strip() + + assert "this is some text" in file_contents + assert "and this is some more text" in file_contents + + assert file_contents.startswith("

") + assert file_contents.endswith("

") + + +def test_sub_element(): + """ + tests that you can add another element and still render properly + """ + page = Html() + page.append("some plain text.") + page.append(P("A simple paragraph of text")) + page.append("Some more plain text.") + + file_contents = render_result(page) + print(file_contents) # so we can see it if the test fails + + # note: The previous tests should make sure that the tags are getting + # properly rendered, so we don't need to test that here. + assert "some plain text" in file_contents + assert "A simple paragraph of text" in file_contents + assert "Some more plain text." in file_contents + assert "some plain text" in file_contents + # but make sure the embedded element's tags get rendered! + assert "

" in file_contents + assert "

" in file_contents + + +######## +# Step 3 +######## +def test_head(): + e = Head("this is some text") + e.append("and this is some more text") + + file_contents = render_result(e).strip() + + assert "this is some text" in file_contents + assert "and this is some more text" in file_contents + + assert file_contents.startswith("") + assert file_contents.endswith("") + + +def test_title(): + e = Title("this is some text") + + file_contents = render_result(e).strip() + + assert "this is some text" in file_contents + assert "\n" not in file_contents + print(file_contents) + assert file_contents.startswith("") + assert file_contents.endswith("") + + +# Add your tests here! + +def test_one_line_tag_append(): + """ + You should not be able to append content to a OneLineTag + """ + e = OneLineTag("the initial content") + with pytest.raises(NotImplementedError): + e.append("some more content") + + file_contents = render_result(e).strip() + print(file_contents) + + +def test_attributes(): + e = P("A paragraph of text", style="text-align: center", id="intro") + + file_contents = render_result(e).strip() + print(file_contents) # so we can see it if the test fails + + # note: The previous tests should make sure that the tags are getting + # properly rendered, so we don't need to test that here. + # so using only a "P" tag is fine + assert "A paragraph of text" in file_contents + # but make sure the embedded element's tags get rendered! + # first test the end tag is there -- same as always: + assert file_contents.endswith("

") + + # but now the opening tag is far more complex + # but it starts the same: + assert file_contents.startswith("

") > file_contents.index('id="intro"') + assert file_contents[:file_contents.index(">")].count(" ") == 3 + + +def test_hr(): + """a simple horizontal rule with no attributes""" + hr = Hr() + file_contents = render_result(hr) + print(file_contents) + assert file_contents == '


\n' + + +def test_hr_attr(): + """a horizontal rule with an attribute""" + hr = Hr(width=400) + file_contents = render_result(hr) + print(file_contents) + assert file_contents == '
\n' + + +def test_br(): + br = Br() + file_contents = render_result(br) + print(file_contents) + assert file_contents == "
\n" + + +def test_br_attr(): + """a horizontal rule with an attribute""" + br = Br(width=400) + file_contents = render_result(br) + print(file_contents) + assert file_contents == '
\n' + + +def test_content_in_br(): + with pytest.raises(TypeError): + br = Br("some content") + + +def test_append_content_in_br(): + with pytest.raises(TypeError): + br = Br() + br.append("some content") + + +def test_anchor(): + a = A("http://google.com", "link to google") + file_contents = render_result(a) + print(file_contents) + assert file_contents.startswith('link to google' in file_contents + + +def test_header(): + h = H(2, "PythonClass - Class 6 example") + file_contents = render_result(h) + print(file_contents) + assert file_contents.startswith('

') + assert 'PythonClass - Class 6 example' in file_contents + + +##################### +# indentation testing +# Uncomment for Step 9 -- adding indentation +##################### + + +def test_indent(): + """ + Tests that the indentation gets passed through to the renderer + """ + html = Html("some content") + file_contents = render_result(html, ind=" ").rstrip() # remove the end newline + print(file_contents) + lines = file_contents.split("\n") + assert lines[0].startswith(" <") + print(repr(lines[-1])) + assert lines[-1].startswith(" <") + + +def test_indent_contents(): + """ + The contents in a element should be indented more than the tag + by the amount in the indent class attribute + """ + html = Element("some content") + file_contents = render_result(html, ind="") + + print(file_contents) + lines = file_contents.split("\n") + assert lines[1].startswith(Element.indent) + + +def test_multiple_indent(): + """ + make sure multiple levels get indented fully + """ + body = Body() + body.append(P("some text")) + html = Html(body) + + file_contents = render_result(html) + + print(file_contents) + lines = file_contents.split("\n") + for i in range(3): # this needed to be adapted to the tag + assert lines[i + 1].startswith(i * Element.indent + "<") + + assert lines[4].startswith(3 * Element.indent + "some") + + +def test_element_indent1(): + """ + Tests whether the Element indents at least simple content + + we are expecting to to look like this: + + + this is some text + + + More complex indentation should be tested later. + """ + e = Element("this is some text") + + # This uses the render_results utility above + file_contents = render_result(e).strip() + + # making sure the content got in there. + assert "this is some text" in file_contents + + # break into lines to check indentation + lines = file_contents.split('\n') + # making sure the opening and closing tags are right. + assert lines[0] == "" + # this line should be indented by the amount specified + # by the class attribute: "indent" + assert lines[1].startswith(Element.indent + "thi") + assert lines[2] == "" + assert file_contents.endswith("")