Skip to content

Commit 1402af0

Browse files
author
Shehab Abdel-Salam
committed
Fix remaining exercises till e100
1 parent 85dd229 commit 1402af0

File tree

17 files changed

+280
-104
lines changed

17 files changed

+280
-104
lines changed

chapters/chapter10_oop/exercises/exercise_71.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
# 2. NonFiction
1919
# 3. Biography
2020
# 4. History
21-
21+
from __future__ import annotations
2222
from dataclasses import dataclass
2323

2424

chapters/chapter10_oop/exercises/exercise_75.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from .exercise_74 import Account, Card, Customer
1717

1818

19-
class Customer:
19+
class BankCustomer(Customer):
2020
def __init__(self, first_name: str, last_name: str):
2121
self.first_name = first_name
2222
self.last_name = last_name
Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,54 @@
1-
# Exercise 78 - Protocol
1+
# Exercise 78 - Simple University System
2+
# Given the following
3+
from __future__ import annotations
4+
5+
6+
class Course:
7+
def __init__(self, course_name: str, course_code: str):
8+
self.course_name = course_name
9+
self.course_code = course_code
10+
self.professor = None
11+
self.students = []
12+
13+
def add_student(self, student: Student):
14+
self.students.append(student)
15+
16+
def assign_professor(self, professor: Professor):
17+
self.professor = professor
18+
19+
def list_students(self):
20+
return [student.name for student in self.students]
21+
22+
23+
class Person:
24+
def __init__(self, name: str, email: str):
25+
self.name = name
26+
self.email = email
27+
28+
29+
class Student(Person):
30+
def __init__(self, name: str, email: str, student_id: str):
31+
super().__init__(name, email)
32+
self.student_id = student_id
33+
self.enrolled_courses: list[Course] = []
34+
35+
def enroll(self, course: Course):
36+
self.enrolled_courses.append(course)
37+
course.add_student(self)
38+
39+
def list_courses(self):
40+
return [course.course_name for course in self.enrolled_courses]
41+
42+
43+
class Professor(Person):
44+
def __init__(self, name: str, email: str, professor_id: str):
45+
super().__init__(name, email)
46+
self.professor_id = professor_id
47+
self.taught_courses: list[Course] = []
48+
49+
def assign_course(self, course: Course):
50+
self.taught_courses.append(course)
51+
course.assign_professor(self)
52+
53+
def list_courses(self):
54+
return [course.course_name for course in self.taught_courses]

chapters/chapter10_oop/tests/test_ch10.py

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
from ..exercises.exercise_75 import BankCustomer
1010
from ..exercises.exercise_76 import Box
1111
from ..exercises.exercise_77 import create_content, Blogger, Vlogger
12-
13-
# from ..exercises.exercise_78 import
12+
from ..exercises.exercise_78 import Course, Student, Professor
1413

1514

1615
def test_e68():
@@ -118,8 +117,9 @@ def test_e74():
118117
customer = Customer("John", "Doe")
119118
card = Card(
120119
card_number="1234",
121-
customer=customer,
122-
expiry_date="2024-12-31",
120+
card_holder="John Doe",
121+
account_number="1234",
122+
expiration_date="2024-12-31",
123123
pin="1234",
124124
)
125125
assert isinstance(card, Card)
@@ -130,10 +130,13 @@ def test_e74():
130130

131131
def test_e75():
132132
customer = BankCustomer("John", "Doe")
133-
card1 = Card("1234", customer, "2024-12-31", "1234")
134-
card2 = Card("5678", customer, "2024-12-31", "5678")
135-
account1 = Account("acc-1234", customer, 1000, [card1])
136-
account2 = Account("acc-5678", customer, 2000, [card2])
133+
account1 = Account("acc-1234", customer, 1000)
134+
card1 = Card("1234", "John Doe", "acc-1234", "2024-12-31", "1234")
135+
account1.add_card(card1)
136+
137+
account2 = Account("acc-5678", customer, 2000)
138+
card2 = Card("5678", "John Doe", "acc-5678", "2024-12-31", "5678")
139+
account2.add_card(card2)
137140

138141
assert customer.get_total_balance() == 0.0
139142
customer.add_account(account1)
@@ -172,5 +175,44 @@ def test_e76():
172175

173176

174177
def test_e77():
175-
assert create_content(Blogger()) == "Blogger is creating content"
176-
assert create_content(Vlogger()) == "Vlogger is creating content"
178+
assert create_content(Blogger(), "New Post") == "Creating a new post: New Post"
179+
assert (
180+
create_content(Vlogger(), "New Video")
181+
== "Creating a new video: New Video with path: /videos/New Video.mp4"
182+
)
183+
184+
class NotAContentCreator:
185+
pass
186+
187+
with pytest.raises(AttributeError):
188+
create_content(NotAContentCreator(), "New Content")
189+
190+
191+
def test_e78():
192+
course = Course("Python Programming", "CS101")
193+
assert course.course_name == "Python Programming"
194+
assert course.course_code == "CS101"
195+
assert course.professor is None
196+
assert course.students == []
197+
198+
professor = Professor("Dr. Clark", "clark@uni.edu", "1234")
199+
course.assign_professor(professor)
200+
201+
student_names = ["Alice", "Bob", "Charlie"]
202+
students = [
203+
Student(name, f"{name.lower()}@uni.edu", f"{name.lower()}1234")
204+
for name in student_names
205+
]
206+
for student in students:
207+
student.enroll(course)
208+
209+
assert course.professor == professor
210+
assert set(course.list_students()) == set(student_names)
211+
212+
course2 = Course("Mathematics", "MATH101")
213+
assert course2.professor is None
214+
assert course2.students == []
215+
professor2 = Professor("Dr. Smith", "smith@uni.edu", "5678")
216+
course2.assign_professor(professor2)
217+
assert course2.professor == professor2
218+
assert course2.students == []

chapters/chapter11_standard_library/exercises/exercise_81.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Exercise 81 - Functools
22
# Write a function that uses `functools.partial` to create a function that always multiplies by 10.
3+
from functools import partial
4+
5+
6+
def multiply(x, y):
7+
return x * y
38

49

510
def multiply(): ...

chapters/chapter11_standard_library/exercises/exercise_82.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# Exercise 82 - Flatten a List of Lists
22
# Write a function that flattens a list of lists using `itertools.chain`.
33
# The function should take a list of lists and return a single flattened list.
4+
from itertools import chain
5+
6+
# Example:
7+
# flatten_list_of_lists([[1, 2, 3], [4, 5], [6, 7, 8, 9]]) == [1, 2, 3, 4, 5, 6, 7, 8, 9]
48

59

610
def flatten_list_of_lists(list_of_lists: list[list[int]]) -> list[int]:

chapters/chapter11_standard_library/exercises/exercise_83.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Exercise 83 - Cached Fibonacci
22
# Given this fibonacci function, we want to cache the results using `functools.lru`.
3+
from functools import lru_cache
34

45

56
def compute_fibonacci(n: int) -> int:

chapters/chapter11_standard_library/exercises/exercise_84.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
# Can you fix this?
77

8+
import logging
9+
810

911
class RateInterestCalculator:
1012
def __init__(self) -> None:

chapters/chapter11_standard_library/exercises/exercise_85.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
# The timestamp should be converted to a `datetime` object.
55
#
66
from dataclasses import dataclass
7+
from datetime import datetime
8+
9+
# Example:
10+
# 2024-09-01,Sold 100 shares of AAPL
11+
# 2024-10-01,Bought 200 shares of MSFT
12+
# should return:
13+
# [ Transaction(datetime(2024, 9, 1), "Sold 100 shares of AAPL"),
14+
# Transaction(datetime(2024, 10, 1), "Bought 200 shares of MSFT") ]
715

816

917
@dataclass

chapters/chapter11_standard_library/tests/test_ch11.py

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import textwrap
23
from pathlib import Path
34
import pytest
@@ -13,19 +14,9 @@
1314

1415

1516
def test_e79():
16-
assert (
17-
days_until_next_birthday(birthday=date(2021, 1, 1), now=date(2021, 1, 1)) == 364
18-
)
19-
assert (
20-
days_until_next_birthday(birthday=date(1994, 12, 18), now=date(2024, 8, 15))
21-
== 120
22-
)
23-
assert (
24-
days_until_next_birthday(birthday=date(1990, 1, 15), now=date(2025, 1, 1)) == 14
25-
)
26-
assert (
27-
days_until_next_birthday(birthday=date(1992, 1, 2), now=date(2025, 1, 2)) == 0
28-
)
17+
assert days_until_next_birthday(date(2024, 1, 1), date(2024, 1, 1)) == 0
18+
assert days_until_next_birthday(date(2024, 1, 1), date(2024, 1, 2)) == 365
19+
assert days_until_next_birthday(date(2024, 1, 1), date(2024, 12, 31)) == 1
2920

3021

3122
def test_e80():
@@ -78,15 +69,40 @@ def test_e82():
7869

7970

8071
def test_e83():
81-
assert compute_fibonacci(3) == 2
82-
assert compute_fibonacci(4) == 3
83-
assert compute_fibonacci(5) == 5
84-
assert compute_fibonacci(6) == 8
85-
assert compute_fibonacci(7) == 13
72+
assert compute_fibonacci.cache_info().hits == 0, "Cache hits should be 0 initially"
73+
assert compute_fibonacci(2) == 1, "First call should not be cached"
74+
assert compute_fibonacci(2) == 1, "Second call should use cache"
75+
assert (
76+
compute_fibonacci.cache_info().hits == 1
77+
), "Cache hits should be 1 after second call"
78+
assert compute_fibonacci(3) == 2, "Third call should not be cached"
79+
assert compute_fibonacci(10) == 55
8680

8781

88-
def test_e84():
89-
assert RateInterestCalculator().calculate_total() == 0
82+
@pytest.fixture
83+
def caplog_setup(caplog):
84+
# Set up the logger to capture log messages
85+
caplog.set_level(logging.INFO)
86+
return caplog
87+
88+
89+
def test_e84(caplog_setup):
90+
calculator = RateInterestCalculator()
91+
calculator.calculate_rate()
92+
assert any(
93+
record.levelname == "INFO" and "Calculating rate" in record.message
94+
for record in caplog_setup.records
95+
)
96+
assert any(
97+
record.levelname == "ERROR" and "An error occurred" in record.message
98+
for record in caplog_setup.records
99+
)
100+
101+
calculator.calculate_interest()
102+
assert any(
103+
record.levelname == "INFO" and "Calculating interest" in record.message
104+
for record in caplog_setup.records
105+
)
90106

91107

92108
@pytest.fixture
@@ -102,10 +118,9 @@ def source(file_content):
102118
[
103119
(
104120
textwrap.dedent(
105-
"""
106-
2021-01-01, Sold 100 shares of AAPL
107-
2021-01-02, Bought 200 shares of MSFT
108-
2021-01-03, Sold 50 shares of AAPL
121+
"""2021-01-01,Sold 100 shares of AAPL
122+
2021-01-02,Bought 200 shares of MSFT
123+
2021-01-03,Sold 50 shares of AAPL
109124
"""
110125
),
111126
[
@@ -124,11 +139,10 @@ def source(file_content):
124139
),
125140
(
126141
textwrap.dedent(
127-
"""
128-
2024-09-01, Sold 100 shares of AAPL
129-
2024-10-01, Bought 200 shares of MSFT
130-
2024-11-01, Sold 50 shares of AAPL
131-
2024-12-01, Bought 100 shares of TSLA
142+
"""2024-09-01,Sold 100 shares of AAPL
143+
2024-10-01,Bought 200 shares of MSFT
144+
2024-11-01,Sold 50 shares of AAPL
145+
2024-12-01,Bought 100 shares of TSLA
132146
"""
133147
),
134148
[

0 commit comments

Comments
 (0)