feat(curriculum): add email simulator workshop (#62100)

Co-authored-by: Ilenia <26656284+ilenia-magoni@users.noreply.github.com>
Co-authored-by: Ilenia M <nethleen@gmail.com>
This commit is contained in:
Zaira
2025-10-13 16:23:43 +05:00
committed by GitHub
parent c005816748
commit baffca7ce7
55 changed files with 4741 additions and 0 deletions
+6
View File
@@ -4590,6 +4590,12 @@
"In this workshop, you will learn about classes, objects, and methods in Python by building a simple musical instrument inventory."
]
},
"workshop-email-simulator": {
"title": "Build an Email Simulator",
"intro": [
"In this workshop you will implement classes and objects by building an email simulator that simulates sending, receiving, and managing emails between different users."
]
},
"lab-budget-app": {
"title": "Build a Budget App",
"intro": [
@@ -0,0 +1,9 @@
---
title: Introduction to the Build an Email Simulator
block: workshop-email-simulator
superBlock: full-stack-developer
---
## Introduction to the Build an Email Simulator
In this workshop you will implement classes and objects by building an email simulator that simulates sending, receiving, and managing emails between different users.
@@ -0,0 +1,36 @@
---
id: 6852ea0c3cadb54e897acdac
title: Step 1
challengeType: 20
dashedName: step-1
---
# --description--
In this workshop, you are going to build an *Email Simulator* that simulates sending, receiving, and managing emails between different users. You'll learn about classes, objects, and how to organize code in an object-oriented way.
Begin by creating a class named `Email` using the `class` keyword.
# --hints--
You should create a class named `Email`.
```js
({
test: () =>
{
assert(runPython(`(_Node(_code).has_class("Email"))`))
}
})
```
# --seed--
## --seed-contents--
```py
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,49 @@
---
id: 6852ef95ccc27660275692cd
title: Step 2
challengeType: 20
dashedName: step-2
---
# --description--
Your `Email` class needs to store information about each email when it's created.
Inside your `Email` class, remove the existing `pass` keyword and create the `__init__` method that takes `self`, `sender`, `receiver`, `subject`, and `body` as parameters.
# --hints--
You should define an `__init__` method inside the `Email` class.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").has_function("__init__")`))
}
})
```
Your `__init__` method should have parameters: `self`, `sender`, `receiver`, `subject`, and `body`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").find_function("__init__").has_args("self, sender, receiver, subject, body")`))
}
})
```
# --seed--
## --seed-contents--
```py
--fcc-editable-region--
class Email:
pass
--fcc-editable-region--
```
@@ -0,0 +1,74 @@
---
id: 6852f01116912861c7d1b0e6
title: Step 3
challengeType: 20
dashedName: step-3
---
# --description--
Inside the `__init__` method, you need to assign the parameter values to the object's attributes so each email can store its information.
Inside your `__init__` method, remove the `pass` keyword and assign the parameters to `self.sender`, `self.receiver`, `self.subject`, and `self.body`.
# --hints--
You should assign the `sender` parameter to `self.sender`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").find_function("__init__").find_variable("self.sender").is_equivalent("self.sender = sender")`))
}
})
```
You should assign the `receiver` parameter to `self.receiver`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").find_function("__init__").find_variable("self.receiver").is_equivalent("self.receiver = receiver")`))
}
})
```
You should assign the `subject` parameter to `self.subject`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").find_function("__init__").find_variable("self.subject").is_equivalent("self.subject = subject")`))
}
})
```
You should assign the `body` parameter to `self.body`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").find_function("__init__").find_variable("self.body").is_equivalent("self.body = body")`))
}
})
```
# --seed--
## --seed-contents--
```py
--fcc-editable-region--
class Email:
def __init__(self, sender, receiver, subject, body):
pass
--fcc-editable-region--
```
@@ -0,0 +1,67 @@
---
id: 6852f06fdde1b4634a263f03
title: Step 4
challengeType: 20
dashedName: step-4
---
# --description--
Now let's test the `Email` class by creating an email object and checking that it stores information correctly. You'll print a couple of attributes to verify everything works.
Create an email object named `email_obj` with `alice@example.com` as the sender, `bob@example.com` as the receiver, `Hello` as the subject, and `Hi Bob!` as the body. Then print the `sender` and `subject` attributes as separate print statements to verify they are stored correctly.
# --hints--
You should create an email object named `email_obj` with the specified parameters.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_variable("email_obj").is_equivalent("email_obj = Email('alice@example.com', 'bob@example.com', 'Hello', 'Hi Bob!')")`))
}
})
```
You should print `email_obj.sender`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).has_call("print(email_obj.sender)")`))
}
})
```
You should print `email_obj.subject`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).has_call("print(email_obj.subject)")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,43 @@
---
id: 6852f0c3fcedb964ab959921
title: Step 6
challengeType: 20
dashedName: step-6
---
# --description--
Now let's test that the `read` attribute was added correctly to your `Email` class. Since you already have an email object from the previous steps, print the `read` attribute to see that it's now `False` by default.
# --hints--
You should print `email_obj.read` to test the read attribute.
```js
({
test: () => {
assert(runPython(`_Node(_code).has_call("print(email_obj.read)")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
--fcc-editable-region--
email_obj = Email('alice@example.com', 'bob@example.com', 'Hello', 'Hi Bob!')
print(email_obj.sender)
print(email_obj.subject)
--fcc-editable-region--
```
@@ -0,0 +1,50 @@
---
id: 6852f11d412c29665985a915
title: Step 12
challengeType: 20
dashedName: step-12
---
# --description--
Now that users can send emails, they need a way to store emails they receive. Each user should have an inbox to collect their emails.
Add an `inbox` attribute to the `User` class `__init__` method and initialize it as an empty list `[]`. This will store all emails that the user receives.
# --hints--
You should add `self.inbox = []` to the `User` class `__init__` method.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("User").find_function("__init__").find_variable("self.inbox").is_equivalent("self.inbox = []")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
--fcc-editable-region--
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
```
@@ -0,0 +1,76 @@
---
id: 6853f2da9b8ed891e9fdc5fc
title: Step 23
challengeType: 20
dashedName: step-23
---
# --description--
Now let's display the sender and receiver information. To show who sent and received the email, add two print statements to the `display_full_email` method in this format:
- `From: sender` where `sender` is replaced with the sender's name
- `To: receiver` where `receiver` is replaced with the receiver's name
# --hints--
You should use f-strings to print the sender's name using `From: {self.sender.name}`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_call("print(f'From: {self.sender.name}')")`));
}
})
```
You should use f-strings to print the receiver's name using `To: {self.receiver.name}`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_call("print(f'To: {self.receiver.name}')")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,71 @@
---
id: 6853f34ff93594934f6636d9
title: Step 27
challengeType: 20
dashedName: step-27
---
# --description--
Let's add a string representation to our `Email` class so we can display brief email summaries.
Add a `__str__` method to the `Email` class that takes `self` as a parameter.
# --hints--
You should define a `__str__` method in the `Email` class.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").has_function("__str__")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
--fcc-editable-region--
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,109 @@
---
id: 6853f4584f508e95cc7a9f4d
title: Step 30
challengeType: 20
dashedName: step-30
---
# --description--
Now you'll create a method to list all emails in the inbox. This method should handle the case where the inbox is empty and display a numbered list of emails when there are emails present.
Add a method called `list_emails` to your `Inbox` class that takes `self` as a parameter. First, create an `if` statement to check if the inbox is empty by testing the `emails` list. If it's empty, print the message `Your inbox is empty.\n`. Add a `return` statement to exit the method.
# --hints--
You should define a method named `list_emails` in the `Inbox` class that takes `self` as a parameter.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("list_emails").has_args("self")`))
}
})
```
You should check if `self.emails` is empty using `if not self.emails`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("list_emails").find_ifs()[0].find_conditions()[0].is_equivalent("not self.emails")`))
}
})
```
You should print the message `Your inbox is empty.\n` if there are no emails.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("list_emails").find_ifs()[0].find_body()[0].is_equivalent("print('Your inbox is empty.\\\\n')")`))
}
})
```
You should have a `return` statement at the end of the `if` statement.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("list_emails").find_ifs()[0].find_body()[1].is_equivalent("return")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,124 @@
---
id: 6853f4ded9f84896ff182dd8
title: Step 31
challengeType: 20
dashedName: step-31
---
# --description--
After the empty inbox check, print the message `\nYour Emails:`. After that, iterate over all emails in the inbox using a `for` loop with enumeration. This is the syntax for enumeration with a starting number: `enumerate(iterable, start=start_number)`.
Use enumeration to number the emails starting from `1`. Use `i` (the index) and `email` (the email object) as the iteration variables.
Inside the loop, print an f-string with the iteration index followed by a `.`, then a space and the string representation of the email object in this format:
```md
i. string_representation
```
Where `i` is the index and `string_representation` is the representation of the email object.
# --hints--
You should print the header `\nYour Emails:` outside the `if` statement.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("list_emails").find_body()[1].is_equivalent("print('\\\\nYour Emails:')")`))
}
})
```
You should have a `for` loop that iterates over `enumerate(self.emails, start=1)`.
```js
({
test: () =>
{
runPython(`
_iter = _Node(_code).find_class("Inbox").find_function("list_emails").find_for_loops()[0].find_for_iter()
assert _iter.is_equivalent("enumerate(self.emails, start=1)") or _iter.is_equivalent("enumerate(self.emails, 1)")
`)
}
})
```
Your `for` loop should use `i` and `email` to iterate over `enumerate(self.emails, start=1)`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("list_emails").find_for_loops()[0].find_for_vars().is_equivalent("i, email")`))
}
})
```
Inside the loop, you should print each email summary with a numbered prefix followed by the formatted string from the `__str__` method. Don't forget to add a `.` after the number.
```js
({
test: () =>
{
assert(runPython(`
cond = _Node(_code).find_class("Inbox").find_function("list_emails").find_for_loops()[0].find_body()
cond.is_equivalent("print(f'{i}. {str(email)}')") or cond.is_equivalent("print(f'{i}. {email}')")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
--fcc-editable-region--
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
--fcc-editable-region--
```
@@ -0,0 +1,103 @@
---
id: 6853f553d90a2f9874ff9d0e
title: Step 39
challengeType: 20
dashedName: step-39
---
# --description--
Now we're ready to add timestamps to our emails to track when they were sent and received.
First, import the `datetime` module at the top of your file.
# --hints--
You should import the datetime module at the top of the file using `import datetime`.
```js
({
test: () => {
assert(runPython(`_Node(_code).has_import("import datetime")`));
}
})
```
# --seed--
## --seed-contents--
```py
--fcc-editable-region--
--fcc-editable-region--
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
```
@@ -0,0 +1,113 @@
---
id: 6853f68dd3affa9adb2e6d99
title: Step 41
challengeType: 20
dashedName: step-41
---
# --description--
Great! Now that you've practiced datetime formatting, remove the `current_time` variable and the print statement from the bottom of your code. We'll integrate timestamps into the `Email` class in the next step.
# --hints--
You should not have the the statement `current_time = datetime.datetime.now()")` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_stmt("current_time = datetime.datetime.now()")`));
}
})
```
You should not have the practice print statement with `strftime()` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_call("print(current_time.strftime('%H:%M:%S'))")`));
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
--fcc-editable-region--
current_time = datetime.datetime.now()
print(current_time.strftime('%H:%M:%S'))
--fcc-editable-region--
```
@@ -0,0 +1,113 @@
---
id: 6853f70470f45d9c280af659
title: Step 43
challengeType: 20
dashedName: step-43
---
# --description--
Now let's show the timestamp when displaying the full email.
Below the subject, print the received timestamp using `strftime` to format it as `'%Y-%m-%d %H:%M'`. Use the following format:
```py
Received: date
```
Where `date` is formatted as `'%Y-%m-%d %H:%M'`.
# --hints--
You should print the formatted timestamp using `self.timestamp.strftime('%Y-%m-%d %H:%M')`. Add `Received:` followed by a space before it.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_call('print(f"Received: {self.timestamp.strftime(\\'%Y-%m-%d %H:%M\\')}")')`))
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
--fcc-editable-region--
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
```
@@ -0,0 +1,138 @@
---
id: 6853f90fd03acc9fd75ff860
title: Step 46
challengeType: 20
dashedName: step-46
---
# --description--
Users should be able to check their inbox, read emails, and delete emails directly through their User object.
For checking the inbox, add a method called `check_inbox` to the `User` class. This method should print a personalized header with the user's name and then display all their emails.
The header should be formatted as: `\nName's Inbox:`, where `Name` is replaced with the name of the user.
After printing the header, call the `list_emails()` method on the user's inbox.
# --hints--
You should define a method named `check_inbox` in the `User` class that takes `self` as a parameter.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("User").find_function("check_inbox").has_args("self")`))
}
})
```
Within `check_inbox`, you should print a header that includes the user's name in the format `\n[user]'s Inbox:`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("User").find_function("check_inbox").find_body()[0].is_equivalent('print(f"\\\\n{self.name}\\\'s Inbox:")')`))
}
})
```
Within `check_inbox`, you should call `self.inbox.list_emails()` to display the emails.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("User").find_function("check_inbox").find_body()[1].is_equivalent("self.inbox.list_emails()")`))
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
print(f'Email sent from {self.name} to {receiver.name}!\n')
--fcc-editable-region--
--fcc-editable-region--
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
```
@@ -0,0 +1,141 @@
---
id: 6853f996671e63a0b4fbf143
title: Step 47
challengeType: 20
dashedName: step-47
---
# --description--
For reading and deleting emails, add two methods to your `User` class: `read_email` and `delete_email`. Both should take an `index` parameter and call the corresponding method on `self.inbox`.
# --hints--
You should define a method named `read_email` in the `User` class that takes `self` and `index` as parameters.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("User").find_function("read_email").has_args("self, index")`));
}
})
```
The `read_email` method should call `self.inbox.read_email(index)`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("User").find_function("read_email").has_call("self.inbox.read_email(index)")`));
}
})
```
You should define a method named `delete_email` in the `User` class that takes `self` and `index` as parameters.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("User").find_function("delete_email").has_args("self, index")`));
}
})
```
The `delete_email` method should call `self.inbox.delete_email(index)`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("User").find_function("delete_email").has_call("self.inbox.delete_email(index)")`));
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
print(f'Email sent from {self.name} to {receiver.name}!\n')
def check_inbox(self):
print(f'\n{self.name}\'s Inbox:')
self.inbox.list_emails()
--fcc-editable-region--
--fcc-editable-region--
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
```
@@ -0,0 +1,134 @@
---
id: 685409f3f6c765aa4cd44a26
title: Step 49
challengeType: 20
dashedName: step-49
---
# --description--
Before sending the emails, add the standard Python idiom `if __name__ == '__main__':` followed by a call to `main()`. This ensures that the main function only runs when the script is executed directly, not when it's imported as a module.
# --hints--
You should add the `if __name__ == '__main__':` check outside the `main` function.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_ifs()[0].find_conditions()[0].is_equivalent("__name__ == '__main__'")`))
}
})
```
You should call `main()` inside the `if __name__ == '__main__':` block.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_ifs()[0].find_body().is_equivalent("main()")`))
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
print(f'Email sent from {self.name} to {receiver.name}!\n')
def check_inbox(self):
print(f"\n{self.name}'s Inbox:")
self.inbox.list_emails()
def read_email(self, index):
self.inbox.read_email(index)
def delete_email(self, index):
self.inbox.delete_email(index)
def main():
tory = User('Tory')
ramy = User('Ramy')
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,140 @@
---
id: 68540a534c56aeabae6afd58
title: Step 50
challengeType: 20
dashedName: step-50
---
# --description--
Now you'll simulate sending some emails between the users.
In your `main` function, after creating the users, use the `send_email` method to:
- Have Tory send an email to the `ramy` user object with subject `Hello` and body `Hi Ramy, just saying hello!`.
- Have Ramy send an email to the `tory` user object with subject `Re: Hello` and body `Hi Tory, hope you are fine.`.
# --hints--
You should have Tory send an email to `ramy`, subject `Hello`, and body `Hi Ramy, just saying hello!`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_function("main").find_body()[2].is_equivalent("tory.send_email(ramy, 'Hello', 'Hi Ramy, just saying hello!')")`))
}
})
```
You should have Ramy send an email to `tory`, subject `Re: Hello`, and body `Hi Tory, hope you are fine.`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_function("main").find_body()[3].is_equivalent("ramy.send_email(tory, 'Re: Hello', 'Hi Tory, hope you are fine.')")`))
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
print(f'Email sent from {self.name} to {receiver.name}!\n')
def check_inbox(self):
print(f"\n{self.name}'s Inbox:")
self.inbox.list_emails()
def read_email(self, index):
self.inbox.read_email(index)
def delete_email(self, index):
self.inbox.delete_email(index)
--fcc-editable-region--
def main():
tory = User('Tory')
ramy = User('Ramy')
--fcc-editable-region--
if __name__ == '__main__':
main()
```
@@ -0,0 +1,287 @@
---
id: 68540aa7dfd449ad074c285c
title: Step 51
challengeType: 20
dashedName: step-51
---
# --description--
Now you'll demonstrate the inbox functionality. Ramy will check his inbox, read the first email, delete the second email, and then check his inbox again to see the changes.
In your `main` function, after sending the emails, add code to:
- Have Ramy check his inbox using the `check_inbox` method.
- Have Ramy read the first email.
- Have Ramy delete the first email.
- Have Ramy check his inbox again.
With this, you have completed the email simulator!
# --hints--
You should call `ramy.check_inbox()` to show Ramy's emails.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_function("main").find_body().has_stmt("ramy.check_inbox()")`))
}
})
```
You should call `ramy.read_email(1)` to read the first email.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_function("main").find_body().has_stmt("ramy.read_email(1)")`))
}
})
```
You should call `ramy.delete_email(1)` to delete the first email.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_function("main").find_body().has_stmt("ramy.delete_email(1)")`))
}
})
```
You should call `ramy.check_inbox()` again to show the updated inbox.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_function("main").find_body().is_ordered("ramy.delete_email(1)", "ramy.check_inbox()")`))
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
print(f'Email sent from {self.name} to {receiver.name}!\n')
def check_inbox(self):
print(f"\n{self.name}'s Inbox:")
self.inbox.list_emails()
def read_email(self, index):
self.inbox.read_email(index)
def delete_email(self, index):
self.inbox.delete_email(index)
--fcc-editable-region--
def main():
tory = User('Tory')
ramy = User('Ramy')
tory.send_email(ramy, 'Hello', 'Hi Ramy, just saying hello!')
ramy.send_email(tory, 'Re: Hello', 'Hi Tory, hope you are fine.')
--fcc-editable-region--
if __name__ == '__main__':
main()
```
# --solutions--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
print(f'Email sent from {self.name} to {receiver.name}!\n')
def check_inbox(self):
print(f"\n{self.name}'s Inbox:")
self.inbox.list_emails()
def read_email(self, index):
self.inbox.read_email(index)
def delete_email(self, index):
self.inbox.delete_email(index)
def main():
# Create users
tory = User('Tory')
ramy = User('Ramy')
# Send emails
tory.send_email(ramy, 'Hello', 'Hi Ramy, just saying hello!')
ramy.send_email(tory, 'Re: Hello', 'Hi Tory, hope you are fine.')
# Ramy checks inbox
ramy.check_inbox()
# Ramy reads first email (now uses 1-based indexing)
ramy.read_email(1)
# Ramy deletes first email (now uses 1-based indexing)
ramy.delete_email(1)
# Ramy checks inbox again
ramy.check_inbox()
if __name__ == '__main__':
main()
```
@@ -0,0 +1,42 @@
---
id: 68593ea22eac7e228ed585ce
title: Step 5
challengeType: 20
dashedName: step-5
---
# --description--
Emails should track whether they've been read or not. Add a `read` attribute to the `__init__` method and set it to `False` by default, since new emails start as unread.
# --hints--
You should assign `False` to ``self.read` in the `__init__` method.
```js
({
test: () => runPython(`
assert _Node(_code).find_class("Email").find_function("__init__").find_variable("self.read").is_equivalent("self.read = False")
`)
})
```
# --seed--
## --seed-contents--
```py
--fcc-editable-region--
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
--fcc-editable-region--
email_obj = Email('alice@example.com', 'bob@example.com', 'Hello', 'Hi Bob!')
print(email_obj.sender)
print(email_obj.subject)
```
@@ -0,0 +1,82 @@
---
id: 6859400f8f7f872e50e1238c
title: Step 11
challengeType: 20
dashedName: step-11
---
# --description--
The `User` class needs a method to send emails to other users. When sending an email, you'll create a new `Email` object and add it to the receiver's inbox.
Create a method called `send_email` in your `User` class. This method should take parameters for `receiver`, `subject`, and `body`.
Inside the method, create a new `Email` object with the following parameter values and assign it to a variable named `email`:
- `sender`: `self` (the current user)
- `receiver`: `receiver` (the user receiving the email)
- `subject`: `subject` (the subject of the email)
- `body`: `body` (the body of the email)
# --hints--
You should define a `send_email` method in the `User` class.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("User").has_function("send_email")`))
}
})
```
The `send_email` method should have parameters: `self`, `receiver`, `subject`, and `body`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("User").find_function("send_email").has_args("self, receiver, subject, body")`))
}
})
```
The method should create an `Email` object named `email` with the correct parameters.
```js
({
test: () => {
assert(runPython(`
cond = _Node(_code).find_class("User").find_function("send_email").find_body()[0]
cond.is_equivalent("email = Email(sender=self, receiver=receiver, subject=subject, body=body)") or cond.is_equivalent("email = Email(self, receiver, subject, body)")
`));
}
});
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
--fcc-editable-region--
```
@@ -0,0 +1,62 @@
---
id: 685941422c30cd3dc41b1d0a
title: Step 22
challengeType: 20
dashedName: step-22
---
# --description--
Now let's add a header to the email display. In the `display_full_email` method, after calling `mark_as_read()`, print `\n--- Email ---` to start the email display with a clear header.
# --hints--
You should print the header `\n--- Email ---` in the `display_full_email` method.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_call("print('\\\\n--- Email ---')")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
def display_full_email(self):
self.mark_as_read()
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,102 @@
---
id: 68594df7779a164e6a61e8ae
title: Step 32
challengeType: 20
dashedName: step-32
---
# --description--
The inbox needs a method to read a specific email. When a user wants to read an email, they'll specify which email number (starting from index 0) they want to see, and the method will display the full email content.
Add a method called `read_email` to your `Inbox` class that takes an `index` parameter. First, check if the inbox is empty and print the message `Inbox is empty.\n` if it is. Add a `return` statement after that to exit the method.
# --hints--
You should define a method named `read_email` in the `Inbox` class that takes `self` and `index` as parameters.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").has_args("self, index")`));
}
})
```
You should check if `self.emails` is empty using `if not self.emails`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").find_ifs()[0].find_conditions()[0].is_equivalent("not self.emails")`));
}
})
```
You should print `Inbox is empty.\n` if there are no emails and return.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").find_ifs()[0].find_body()[0].is_equivalent("print('Inbox is empty.\\\\n')")`));
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").find_ifs()[0].find_body()[1].is_equivalent("return")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,103 @@
---
id: 6859523c793377706e19e9a0
title: Step 42
challengeType: 20
dashedName: step-42
---
# --description--
Now let's add timestamps to our emails. In the Email class `__init__` method, create a `timestamp` attribute and assign the current time to it to automatically set a timestamp for when the email was created.
This is helpful for tracking when messages were sent and received.
# --hints--
You should have a `self.timestamp` in the Email `__init__` method and assign `datetime.datetime.now()` to it.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("__init__").has_stmt("self.timestamp = datetime.datetime.now()")`));
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
--fcc-editable-region--
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
--fcc-editable-region--
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
```
@@ -0,0 +1,145 @@
---
id: 685a82a54950823ef954276a
title: Step 48
challengeType: 20
dashedName: step-48
---
# --description--
Now you'll create the main function that demonstrates your email simulator.
Create the `main` function and inside it, using the `User` class, create two users: `Tory` and `Ramy` and assign them to variables `tory` and `ramy`, respectively.
# --hints--
You should define a function named `main`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).has_function("main")`))
}
})
```
You should create a user named `Tory` and assign it to a variable called `tory`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_function("main").find_variable("tory").is_equivalent("tory = User('Tory')")`))
}
})
```
You should create a user named `Ramy` and assign it to a variable called `ramy`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_function("main").find_variable("ramy").is_equivalent("ramy = User('Ramy')")`))
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
print(f'Email sent from {self.name} to {receiver.name}!\n')
def check_inbox(self):
print(f"\n{self.name}'s Inbox:")
self.inbox.list_emails()
def read_email(self, index):
self.inbox.read_email(index)
def delete_email(self, index):
self.inbox.delete_email(index)
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,71 @@
---
id: 685c1e32254e5993a5c8823e
title: Step 10
challengeType: 20
dashedName: step-10
---
# --description--
Now that you have an initial setup of the `Email` class, it's time to create users who can send and receive emails. Each user will have a name and will be able to perform email operations.
Create a `User` class with an `__init__` method that takes `self` and `name` as parameters. Within the class, assign the `name` parameter to `self.name`.
# --hints--
You should create a `User` class.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).has_class("User")`))
}
})
```
The `User` class should have an `__init__` method that takes `self` and `name` as parameters.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("User").find_function("__init__").has_args("self, name")`))
}
})
```
You should assign the `name` parameter to `self.name`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("User").find_function("__init__").find_variable("self.name").is_equivalent("self.name = name")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,75 @@
---
id: 685c1eba966c6396850736ea
title: Step 13
challengeType: 20
dashedName: step-13
---
# --description--
While users can send emails and have inboxes, we need a dedicated class to manage inbox operations efficiently.
The `Inbox` class will store a list of emails and provide methods to add new emails, list all emails, and manage them.
Create a new class called `Inbox` with an `__init__` method that initializes an empty list called `emails`.
# --hints--
You should create an `Inbox` class.
```js
({
test: () => {
assert(runPython(`_Node(_code).has_class("Inbox")`));
}
})
```
The `Inbox` class should have an `__init__` method that takes `self` as a parameter.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Inbox").find_function("__init__").has_args("self")`));
}
})
```
You should initialize `self.emails = []` in the `Inbox` class `__init__` method.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Inbox").find_function("__init__").find_variable("self.emails").is_equivalent("self.emails = []")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
class User:
def __init__(self, name):
self.name = name
self.inbox = []
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,67 @@
---
id: 685cdabd4cded3b340193f72
title: Step 24
challengeType: 20
dashedName: step-24
---
# --description--
Now add the subject line to the email display. In the `display_full_email` method, add a print statement to show the email's subject in this format:
- `Subject: subject` where `subject` is replaced with the subject of the email
# --hints--
You should use f-strings to print the subject using `Subject: {self.subject}`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_call("print(f'Subject: {self.subject}')")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,91 @@
---
id: 685cdfd1932d8ac6ad986813
title: Step 28
challengeType: 20
dashedName: step-28
---
# --description--
Within the `__str__` method, you'll show whether an email has been read or not.
Conditional expressions allow you to assign a value based on a condition in a single line.
Here is an example:
```py
x = 10
y = 'Even' if x % 2 == 0 else 'Odd' # y will be even
```
Within the method, before, use conditional expression to assign the string `Read` to a variable `status` if the email is read and `Unread` if it is not.
# --hints--
The `__str__` method should create a `status` variable that uses a conditional expression.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("__str__").has_stmt("status = 'Read' if self.read else 'Unread'")`));
}
})
```
The `__str__` method should return the email information with the status included.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("__str__").has_variable("status")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
--fcc-editable-region--
def __str__(self):
pass
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,125 @@
---
id: 685d2fd1f309b9191f257c55
title: Step 40
challengeType: 20
dashedName: step-40
---
# --description--
Before integrating timestamps into our email system, let's practice working with datetime formatting. The `datetime.datetime.now()` function gives us the current date and time, and we can use the `strftime()` method to format it in different ways.
Here's how `strftime()` works with format codes:
```python
now = datetime.datetime.now()
print(now.strftime("%Y-%m-%d")) # Output: 2024-03-15 (year-month-day with - separator)
```
The format codes like `%Y` (year), `%m` (month), `%d` (day) tell `strftime()` what to include, and you can add separators like `-` between them.
At the bottom of your code, create a variable called `current_time` and assign it `datetime.datetime.now()`. Then use `strftime()` to print the time in hours:minutes:seconds format using `:` as the separator.
Use these format codes: `%H` for hours (24-hour format), `%M` for minutes, and `%S` for seconds.
# --hints--
You should create a variable called `current_time` and assign it `datetime.datetime.now()`.
```js
({
test: () => {
assert(runPython(`_Node(_code).has_stmt("current_time = datetime.datetime.now()")`));
}
})
```
You should use `strftime()` to print the time in `%H:%M:%S` format.
```js
({
test: () => {
assert(runPython(`_Node(_code).has_call("print(current_time.strftime('%H:%M:%S'))")`));
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,107 @@
---
id: 685d53b5e4f5784562a12d1b
title: Step 45
challengeType: 20
dashedName: step-45
---
# --description--
Users should get confirmation when they successfully send an email. Let's improve the user experience by adding feedback to the `send_email` method.
In the `send_email` method of the `User` class, add a print statement after the email is sent that shows confirmation. The message should include both the sender's name and the receiver's name in this format: `Email sent from [sender_name] to [receiver_name]!\n`
# --hints--
You should add a print statement in the `send_email` method that confirms the email was sent.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("User").find_function("send_email").has_call("print(f'Email sent from {self.name} to {receiver.name}!\\\\n')")`));
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
--fcc-editable-region--
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
--fcc-editable-region--
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
```
@@ -0,0 +1,113 @@
---
id: 685d53ec88a16a4643c2437b
title: Step 44
challengeType: 20
dashedName: step-44
---
# --description--
Now let's also show timestamps in the email listing. Update the `__str__` method in the `Email` class to include the timestamp after the subject.
Modify the return statement to include the timestamp formatted as `'%Y-%m-%d %H:%M'` at the end, separated by ` | Time: `.
The complete format should be:
```py
[status] From: sender | Subject: subject | Time: time
```
Where `status` is the status of the email, `sender` is the sender's name, `subject` is the subject of the email, and `time` is in the format `'%Y-%m-%d %H:%M'`.
# --hints--
You should update the `__str__` method to include the formatted timestamp.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("__str__").has_stmt("return f\\"[{status}] From: {self.sender.name} | Subject: {self.subject} | Time: {self.timestamp.strftime('%Y-%m-%d %H:%M')}\\"")`));
}
})
```
# --seed--
## --seed-contents--
```py
import datetime
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.timestamp = datetime.datetime.now()
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f"Received: {self.timestamp.strftime('%Y-%m-%d %H:%M')}")
print(f'Body: {self.body}')
print('------------\n')
--fcc-editable-region--
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
del self.emails[actual_index]
print('Email deleted.\n')
```
@@ -0,0 +1,58 @@
---
id: 688754d6d59578df1313cb3c
title: Step 14
challengeType: 20
dashedName: step-14
---
# --description--
Now it's time to connect the User and Inbox classes so that emails can actually be delivered!
Users need to have proper Inbox objects instead of simple lists, and the `send_email` method should deliver emails to the receiver's inbox.
Update the `User` class `__init__` in a way that each user gets an actual Inbox object instead of an empty list created earlier.
# --hints--
You should update the User class to initialize `self.inbox = Inbox()`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("User").find_function("__init__").find_variable("self.inbox").is_equivalent("self.inbox = Inbox()")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = []
--fcc-editable-region--
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
class Inbox:
def __init__(self):
self.emails = []
```
@@ -0,0 +1,71 @@
---
id: 688754f3494b17e0b352d67d
title: Step 17
challengeType: 20
dashedName: step-17
---
# --description--
Now it's time to test our complete email system! Let's create some users and see the email functionality in action.
Create two User objects: `alice` with name `"Alice"` and `bob` with name `"Bob"`. This will demonstrate how users can be created and interact with each other.
# --hints--
You should create a User object named `alice` with name `"Alice"`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_variable("alice").is_equivalent('alice = User("Alice")')`));
}
})
```
You should create a User object named `bob` with name `"Bob"`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_variable("bob").is_equivalent('bob = User("Bob")')`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,63 @@
---
id: 6887550fe36f64e27074475a
title: Step 18
challengeType: 20
dashedName: step-18
---
# --description--
Have Alice send an email to Bob to see if the email delivery works correctly.
Use Alice's `send_email` method to send Bob an email with subject `"Hello"` and body `"Hi Bob, how are you?"`.
# --hints--
You should call `alice.send_email()` with the correct parameters.
```js
({
test: () => {
assert(runPython(`_Node(_code).has_call('alice.send_email(bob, "Hello", "Hi Bob, how are you?")')`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
--fcc-editable-region--
alice = User("Alice")
bob = User("Bob")
--fcc-editable-region--
```
@@ -0,0 +1,63 @@
---
id: 68875521efc1a4e3f0c570e3
title: Step 19
challengeType: 20
dashedName: step-19
---
# --description--
Now let's verify that the email was delivered successfully by printing the length of Bob's inbox emails.
# --hints--
You should print the length of Bob's inbox emails using `len(bob.inbox.emails)`
```js
({
test: () => {
assert(runPython(`_Node(_code).has_call("print(len(bob.inbox.emails))")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
--fcc-editable-region--
alice = User("Alice")
bob = User("Bob")
alice.send_email(bob, "Hello", "Hi Bob, how are you?")
--fcc-editable-region--
```
@@ -0,0 +1,83 @@
---
id: 68875554c6c32de788afc64e
title: Step 21
challengeType: 20
dashedName: step-21
---
# --description--
Users need a way to read their emails properly.
Add a `display_full_email` method to the `Email` class that takes only `self` as a parameter. Inside this method, call `mark_as_read()` method to mark the email as read when someone views it.
This method would be used to display the email's full content in a nicely formatted way.
# --hints--
You should define a `display_full_email` method in the `Email` class.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").has_function("display_full_email")`));
}
})
```
The `display_full_email` method should take only `self` as a parameter.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_args("self")`));
}
})
```
The method should call `self.mark_as_read()` to mark the email as read.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_call("self.mark_as_read()")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,90 @@
---
id: 688798fccea91f522d1f245e
title: Step 33
challengeType: 20
dashedName: step-33
---
# --description--
When the inbox is not empty, you'll try to access the email at the given index and display it.
Remember in the `list_emails` method, you displayed email numbers starting from 1, but list indices in Python start from 0. So, you'll need to convert the 1-based index to a 0-based index by subtracting 1.
Within the `read_email` method, subtract 1 from the `index` parameter and store it in a variable called `actual_index`.
# --hints--
You should subtract 1 from the `index` parameter and store it in a variable called `actual_index`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").find_body().find_variable("actual_index").is_equivalent("actual_index = index - 1")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
--fcc-editable-region--
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
--fcc-editable-region--
```
@@ -0,0 +1,67 @@
---
id: 68879d0a2aeb368e26559635
title: Step 26
challengeType: 20
dashedName: step-26
---
# --description--
Finally, let's add a footer to complete the email display format. Add a final print statement: `print('------------\n')` to close off the email display with a nice separator line.
# --hints--
You should print the footer `------------\n` at the end of the `display_full_email` method.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_call("print('------------\\\\n')")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,66 @@
---
id: 68879d6de6398893be8c4b7b
title: Step 25
challengeType: 20
dashedName: step-25
---
# --description--
Now add the email body to complete the main content. In the `display_full_email` method, add another print statement in the format `Body: body` (where `body` is the content of the email) to show the email's content.
# --hints--
You should print the email body using `f'Body: {self.body}'`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("display_full_email").has_call("print(f'Body: {self.body}')")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,60 @@
---
id: 68b930ee0e7b8fb81895e59a
title: Step 7
challengeType: 20
dashedName: step-7
---
# --description--
Now you'll add a method to mark an email as read. When someone opens an email, you want to change its status from unread to read. This method will be simple - it just needs to set the `read` attribute to `True`.
Add a method called `mark_as_read` to your `Email` class. This method should take only `self` as a parameter and set the `read` attribute to `True`.
# --hints--
You should define a method named `mark_as_read` in the `Email` class.
that should only take `self` as a parameter.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").find_function("mark_as_read").has_args("self")`))
}
})
```
The method should set `self.read` to `True`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Email").find_function("mark_as_read").find_variable("self.read").is_equivalent("self.read = True")`))
}
})
```
# --seed--
## --seed-contents--
```py
--fcc-editable-region--
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
--fcc-editable-region--
email_obj = Email('alice@example.com', 'bob@example.com', 'Hello', 'Hi Bob!')
print(email_obj.sender)
print(email_obj.subject)
print(email_obj.read)
```
@@ -0,0 +1,61 @@
---
id: 68b9350183ff05bd106c79e4
title: Step 8
challengeType: 20
dashedName: step-8
---
# --description--
Now, test the `mark_as_read` method you created in the `Email` class. Use the method on the existing `Email` object `email_obj` to change the status. After marking the email as read, print the `read` attribute of `email_obj` to confirm the change.
# --hints--
You should call the `mark_as_read` method on the `email_obj` to mark the email as read.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).has_call("email_obj.mark_as_read()")`))
}
})
```
You should print the `read` attribute of the `email_obj` after calling the `mark_as_read` method.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).is_ordered("email_obj.mark_as_read()", "print(email_obj.read)")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
email_obj = Email('alice@example.com', 'bob@example.com', 'Hello', 'Hi Bob!')
print(email_obj.sender)
print(email_obj.subject)
print(email_obj.read)
--fcc-editable-region--
```
@@ -0,0 +1,69 @@
---
id: 68b9366fae8b13c1278761b1
title: Step 15
challengeType: 20
dashedName: step-15
---
# --description--
Your inbox needs a way to receive new emails. When someone sends an email to a user, it should be added to their inbox.
Add a method called `receive_email` to your `Inbox` class. that takes `self` and an email object `email` as a parameter. Within the method body, add the `email` to the `emails` list using the `append` method.
# --hints--
You should define a method named `receive_email` in the `Inbox` class that takes `self` and `email` as parameters.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("receive_email").has_args("self, email")`))
}
})
```
You should append the `email` to `self.emails`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("receive_email").has_stmt("self.emails.append(email)")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
--fcc-editable-region--
class Inbox:
def __init__(self):
self.emails = []
--fcc-editable-region--
```
@@ -0,0 +1,57 @@
---
id: 68b936bf4f47d6c29a669f99
title: Step 16
challengeType: 20
dashedName: step-16
---
# --description--
Modify the `send_email` method to add the email to the receiver's inbox by calling the `receive_email` method of the `Inbox` class.
# --hints--
You should add `receiver.inbox.receive_email(email)` to the `send_email` method.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("User").find_function("send_email").has_stmt("receiver.inbox.receive_email(email)")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
--fcc-editable-region--
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
--fcc-editable-region--
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,88 @@
---
id: 68b96d6a290d52d5e57a7485
title: Step 9
challengeType: 20
dashedName: step-9
---
# --description--
Remove the `email_obj` and the following print statements.
# --hints--
You should not have the `email_obj` creation line in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_stmt("email_obj = Email('alice@example.com', 'bob@example.com', 'Hello', 'Hi Bob!')")`));
}
})
```
You should not have `print(email_obj.sender)` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_call("print(email_obj.sender)")`));
}
})
```
You should not have `print(email_obj.subject)` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_call("print(email_obj.subject)")`));
}
})
```
You should not have `print(email_obj.read)` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_call("print(email_obj.read)")`));
}
})
```
You should not have `email_obj.mark_as_read()` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_call("email_obj.mark_as_read()")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
--fcc-editable-region--
email_obj = Email('alice@example.com', 'bob@example.com', 'Hello', 'Hi Bob!')
print(email_obj.sender)
print(email_obj.subject)
print(email_obj.read)
email_obj.mark_as_read()
print(email_obj.read)
--fcc-editable-region--
```
@@ -0,0 +1,94 @@
---
id: 68b9a011daf902ff1eba40a8
title: Step 20
challengeType: 20
dashedName: step-20
---
# --description--
Now that the email has been received, remove object creations, method calls, and print statements.
# --hints--
You should not have `alice = User("Alice")` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_stmt("alice = User(\\"Alice\\")")`));
}
})
```
You should not have `bob = User("Bob")` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_stmt("bob = User(\\"Bob\\")")`));
}
})
```
You should not have `alice.send_email(bob, "Hello", "Hi Bob, how are you?")` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_call("alice.send_email(bob, \\"Hello\\", \\"Hi Bob, how are you?\\")")`));
}
})
```
You should not have `print(len(bob.inbox.emails))` in your code.
```js
({
test: () => {
assert(!runPython(`_Node(_code).has_call("print(len(bob.inbox.emails))")`));
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
--fcc-editable-region--
alice = User("Alice")
bob = User("Bob")
alice.send_email(bob, "Hello", "Hi Bob, how are you?")
print(len(bob.inbox.emails))
--fcc-editable-region--
```
@@ -0,0 +1,119 @@
---
id: 68be6a4447e61c4395ef2359
title: Step 36
challengeType: 20
dashedName: step-36
---
# --description--
Your inbox also needs a way to delete emails.
Python's `del` keyword can be used to delete items from a list by their index.
Add a method called `delete_email` to your `Inbox` class. Like `read_email`, it should:
- Take an `index` parameter, check for an empty inbox, and print the message `Inbox is empty.\n` if it is. Use `return` to exit the method.
# --hints--
You should define a method named `delete_email` in the `Inbox` class that takes `self` and `index` as parameters.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").has_args("self,index")`))
}
})
```
You should check if the inbox is empty first using `if not self.emails:`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").find_ifs()[0].find_conditions()[0].is_equivalent("not self.emails")`))
}
})
```
If inbox is empty, you should print the message `Inbox is empty.\n` and use `return` to exit the method.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").find_ifs()[0].find_body().is_equivalent("print('Inbox is empty.\\\\n')\\nreturn")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
--fcc-editable-region--
--fcc-editable-region--
```
@@ -0,0 +1,125 @@
---
id: 68be6af1f43cc44541debe41
title: Step 37
challengeType: 20
dashedName: step-37
---
# --description--
You should handle the case where the user tries to delete an email using an invalid index just like you did in the `read_email` method.
Within the `delete_email` method:
- Convert the 1-based `index` parameter to a 0-based index by subtracting 1 and storing it in a variable called `actual_index`.
- Create an if statement to check if the `actual_index` is less than 0 or greater than or equal to the length of the `self.emails` list. If it is, print the message `Invalid email number.\n` and use `return` to exit the method.
# --hints--
You should subtract 1 from the `index` parameter and store it in a variable called `actual_index`.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").find_body().find_variable("actual_index").is_equivalent("actual_index = index - 1")`))
}
})
```
You should create an if statement to check if the `actual_index` is less than 0 or greater than or equal to the length of the `self.emails` list.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").find_ifs()[1].find_conditions()[0].is_equivalent("actual_index < 0 or actual_index >= len(self.emails)")`))
}
})
```
Within the `if` statememt, you should print the message `Invalid email number.\n` and use `return` to exit the method.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").find_ifs()[1].find_body()[0].is_equivalent("print('Invalid email number.\\\\n')")`))
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").find_ifs()[1].find_body()[1].is_equivalent("return")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
--fcc-editable-region--
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
--fcc-editable-region--
```
@@ -0,0 +1,76 @@
---
id: 68bf0f09b7ec33be465c0c35
title: Step 29
challengeType: 20
dashedName: step-29
---
# --description--
At the end of the `__str__` method, return the email summary in this format:
```py
[status] From: sender | Subject: subject.
```
Where `status` is the status of the email, `sender` is the sender's name and `subject` is the subject of the email.
# --hints--
The `__str__` method should return `f"[{status}] From: {self.sender.name} | Subject: {self.subject}"`.
```js
({
test: () => {
assert(runPython(`_Node(_code).find_class("Email").find_function("__str__").has_return("f\\"[{status}] From: {self.sender.name} | Subject: {self.subject}\\"")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
--fcc-editable-region--
def __str__(self):
status = 'Read' if self.read else 'Unread'
--fcc-editable-region--
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
```
@@ -0,0 +1,99 @@
---
id: 68dfc5082ea4b4cdcf09dd58
title: Step 34
challengeType: 20
dashedName: step-34
---
# --description--
After getting the actual index, create an if statement to check if the `actual_index` is less than 0 or greater than or equal to the length of the `self.emails` list. If it is, print the message `Invalid email number.\n` and use `return` to exit the method.
# --hints--
You should create an if statement to check if the `actual_index` is less than 0 or greater than or equal to the length of the `self.emails` list.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").find_ifs()[1].find_conditions()[0].is_equivalent("actual_index < 0 or actual_index >= len(self.emails)")`))
}
})
```
If the index is invalid, you should print the message `Invalid email number.\n` and use `return` to exit the method.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").find_ifs()[1].find_body()[0].is_equivalent("print('Invalid email number.\\\\n')")`))
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").find_ifs()[1].find_body()[1].is_equivalent("return")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
--fcc-editable-region--
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
--fcc-editable-region--
```
@@ -0,0 +1,89 @@
---
id: 68dfc5f71dc2a6d65091a39c
title: Step 35
challengeType: 20
dashedName: step-35
---
# --description--
When the email index is valid, access the email at `actual_index`, call its `display_full_email` method to show the email content.
# --hints--
You should access the email at `actual_index` in the `self.emails` list and call its `display_full_email` method.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("read_email").find_body().has_stmt("self.emails[actual_index].display_full_email()")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
--fcc-editable-region--
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
--fcc-editable-region--
```
@@ -0,0 +1,111 @@
---
id: 68dfc80941fa2ef744c64cd6
title: Step 38
challengeType: 20
dashedName: step-38
---
# --description--
When the inbox is not empty, and the email index is valid, delete the email at the given index using the `del` keyword and print a confirmation message `Email deleted.\n`.
# --hints--
You should use the `del` keyword to delete the email at `actual_index` in the `self.emails` list.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").find_body().has_stmt("del self.emails[actual_index]")`))
}
})
```
You should print the message `Email deleted.\n` after deleting the email.
```js
({
test: () =>
{
assert(runPython(`_Node(_code).find_class("Inbox").find_function("delete_email").find_body().has_call("print('Email deleted.\\\\n')")`))
}
})
```
# --seed--
## --seed-contents--
```py
class Email:
def __init__(self, sender, receiver, subject, body):
self.sender = sender
self.receiver = receiver
self.subject = subject
self.body = body
self.read = False
def mark_as_read(self):
self.read = True
def display_full_email(self):
self.mark_as_read()
print('\n--- Email ---')
print(f'From: {self.sender.name}')
print(f'To: {self.receiver.name}')
print(f'Subject: {self.subject}')
print(f'Body: {self.body}')
print('------------\n')
def __str__(self):
status = 'Read' if self.read else 'Unread'
return f"[{status}] From: {self.sender.name} | Subject: {self.subject}"
class User:
def __init__(self, name):
self.name = name
self.inbox = Inbox()
def send_email(self, receiver, subject, body):
email = Email(sender=self, receiver=receiver, subject=subject, body=body)
receiver.inbox.receive_email(email)
class Inbox:
def __init__(self):
self.emails = []
def receive_email(self, email):
self.emails.append(email)
def list_emails(self):
if not self.emails:
print('Your inbox is empty.\n')
return
print('\nYour Emails:')
for i, email in enumerate(self.emails, start=1):
print(f'{i}. {email}')
def read_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
self.emails[actual_index].display_full_email()
--fcc-editable-region--
def delete_email(self, index):
if not self.emails:
print('Inbox is empty.\n')
return
actual_index = index - 1
if actual_index < 0 or actual_index >= len(self.emails):
print('Invalid email number.\n')
return
--fcc-editable-region--
```
@@ -0,0 +1,63 @@
{
"name": "Build an Email Simulator",
"isUpcomingChange": true,
"dashedName": "workshop-email-simulator",
"helpCategory": "Python",
"blockLayout": "challenge-grid",
"blockType": "workshop",
"challengeOrder": [
{ "id": "6852ea0c3cadb54e897acdac", "title": "Step 1" },
{ "id": "6852ef95ccc27660275692cd", "title": "Step 2" },
{ "id": "6852f01116912861c7d1b0e6", "title": "Step 3" },
{ "id": "6852f06fdde1b4634a263f03", "title": "Step 4" },
{ "id": "68593ea22eac7e228ed585ce", "title": "Step 5" },
{ "id": "6852f0c3fcedb964ab959921", "title": "Step 6" },
{ "id": "68b930ee0e7b8fb81895e59a", "title": "Step 7" },
{ "id": "68b9350183ff05bd106c79e4", "title": "Step 8" },
{ "id": "68b96d6a290d52d5e57a7485", "title": "Step 9" },
{ "id": "685c1e32254e5993a5c8823e", "title": "Step 10" },
{ "id": "6859400f8f7f872e50e1238c", "title": "Step 11" },
{ "id": "6852f11d412c29665985a915", "title": "Step 12" },
{ "id": "685c1eba966c6396850736ea", "title": "Step 13" },
{ "id": "688754d6d59578df1313cb3c", "title": "Step 14" },
{ "id": "68b9366fae8b13c1278761b1", "title": "Step 15" },
{ "id": "68b936bf4f47d6c29a669f99", "title": "Step 16" },
{ "id": "688754f3494b17e0b352d67d", "title": "Step 17" },
{ "id": "6887550fe36f64e27074475a", "title": "Step 18" },
{ "id": "68875521efc1a4e3f0c570e3", "title": "Step 19" },
{ "id": "68b9a011daf902ff1eba40a8", "title": "Step 20" },
{ "id": "68875554c6c32de788afc64e", "title": "Step 21" },
{ "id": "685941422c30cd3dc41b1d0a", "title": "Step 22" },
{ "id": "6853f2da9b8ed891e9fdc5fc", "title": "Step 23" },
{ "id": "685cdabd4cded3b340193f72", "title": "Step 24" },
{ "id": "68879d6de6398893be8c4b7b", "title": "Step 25" },
{ "id": "68879d0a2aeb368e26559635", "title": "Step 26" },
{ "id": "6853f34ff93594934f6636d9", "title": "Step 27" },
{ "id": "685cdfd1932d8ac6ad986813", "title": "Step 28" },
{ "id": "68bf0f09b7ec33be465c0c35", "title": "Step 29" },
{ "id": "6853f4584f508e95cc7a9f4d", "title": "Step 30" },
{ "id": "6853f4ded9f84896ff182dd8", "title": "Step 31" },
{ "id": "68594df7779a164e6a61e8ae", "title": "Step 32" },
{ "id": "688798fccea91f522d1f245e", "title": "Step 33" },
{ "id": "68dfc5082ea4b4cdcf09dd58", "title": "Step 34" },
{ "id": "68dfc5f71dc2a6d65091a39c", "title": "Step 35" },
{ "id": "68be6a4447e61c4395ef2359", "title": "Step 36" },
{ "id": "68be6af1f43cc44541debe41", "title": "Step 37" },
{ "id": "68dfc80941fa2ef744c64cd6", "title": "Step 38" },
{ "id": "6853f553d90a2f9874ff9d0e", "title": "Step 39" },
{ "id": "685d2fd1f309b9191f257c55", "title": "Step 40" },
{ "id": "6853f68dd3affa9adb2e6d99", "title": "Step 41" },
{ "id": "6859523c793377706e19e9a0", "title": "Step 42" },
{ "id": "6853f70470f45d9c280af659", "title": "Step 43" },
{ "id": "685d53ec88a16a4643c2437b", "title": "Step 44" },
{ "id": "685d53b5e4f5784562a12d1b", "title": "Step 45" },
{ "id": "6853f90fd03acc9fd75ff860", "title": "Step 46" },
{ "id": "6853f996671e63a0b4fbf143", "title": "Step 47" },
{ "id": "685a82a54950823ef954276a", "title": "Step 48" },
{ "id": "685409f3f6c765aa4cd44a26", "title": "Step 49" },
{ "id": "68540a534c56aeabae6afd58", "title": "Step 50" },
{ "id": "68540aa7dfd449ad074c285c", "title": "Step 51" }
],
"usesMultifileEditor": true,
"hasEditableBoundaries": true
}
@@ -718,6 +718,7 @@
"blocks": [
"lecture-classes-and-objects",
"workshop-musical-instrument-inventory",
"workshop-email-simulator",
"lab-budget-app",
"review-classes-and-objects",
"quiz-classes-and-objects"