Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions sprint-5-stretch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Sprint 5 Stretch - Radio Control App

This is part of an app that can be used to control an online radio station

Your task is to:
1. Upgrade everything use dataclasses
1. Observe how the given `__str__` method works, and add one to the other classes
1. When the `__str__` method is called, have it print the duration in formatted mm:ss rather than just seconds
1. Add a new class of `Person` - you can use your imagination what this includes, but it should have at least a string name
1. Turn the fields for _artists_, _host_, and _guest_ into `Person` classes
1. Make a new class `Podcast` that _extends_ the `TalkShow` class, with an extra string field for _sponsor_
1. Finish implementing the class `Playlist`, and set it to takes a generic, e.g. either `Song` or `TalkShow` or `Podcast`

As you implement, make sure to keep checking with mypy and add your own code at the end to test it works correctly
1 change: 1 addition & 0 deletions sprint-5-stretch/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mypy
43 changes: 43 additions & 0 deletions sprint-5-stretch/stretch-radio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
class Song:
def __init__(self, artist, duration, title):
self.artist = artist # should be a string
self.duration = duration # should be an integer in seconds
self.title = title # should be a string

def __str__(self):
return f"{self.artist} - {self.title} ({self.duration})"

class TalkShow:
def __init__(self, host, guests, duration, title):
self.host = host # should be a string
self.guests = guests # should be a list of strings
self.duration = duration # should be an integer in seconds
self.title = title # should be a string

class Playlist:
def __init__(self, items):
self.items = items # A list of Song or TalkShow
self.currently_playing_index = 0

def play_next(self):
pass
# TODO: increment the currently_playing_index, when you get to the end loop back to 0

def get_currently_playing(self):
return "todo"
# TODO: return a string representation of whatever is playing at the current index
# See the __str__ method in Song for an example of how to make a string representation of a class

def get_total_duration(self):
return 0
# TODO: return

song_a = Song("Rick Astley", 210, "Never Gonna Give You Up")
print(song_a)

song_b = Song("Psy", 219, "Gangnam Style")
funny_songs = Playlist([song_a, song_b])
print(funny_songs.get_currently_playing())

show_a = TalkShow("Melvyn Bragg", ["Jim Al-Khalili", "Sheila Rowan", "Carolin Crawford"], 2700, "Gravitational Waves")

41 changes: 41 additions & 0 deletions sprint-5/01-predict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
def half(value):
return value / 2

def double(value):
return value * 2

def second(value):
return value[1]

# TASK 1:
# 1. Predict what you think will happen with each of the following functions
# 2. Then, test it, and explain in your own words what is actually happening and why
# (feel free to comment out lines if you think they cause errors or crashes while testing)

print(half(22))
# Prediction:
# What actually happens and why:

print(half("22"))
# Prediction:
# What actually happens and why:

print(double(22))
# Prediction:
# What actually happens and why:

print(double("22"))
# Prediction:
# What actually happens and why:

print(second(22))
# Prediction:
# What actually happens and why:

print(second(0x16))
# Prediction:
# What actually happens and why:

print(second("22"))
# Prediction:
# What actually happens and why:
29 changes: 29 additions & 0 deletions sprint-5/02-playcomputer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import process from "node:process";
import readline from "node:readline";

const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

rl.question("What URL should we fetch?\n> ", async (url) => {
const response = await fetch(url);
if (!response.ok) {
if (response.body.toLowerCase().includes("permission")) {
console.error("You didn't have permission to get that URL");
} else {
console.error(`The request failed - body: ${response.body}`);
}
process.exit(1);
}

const contents = await response.json();

console.log(contents);

rl.close();
});

// TASK 2
// Read through this file and predict what it does.
// Leave a comment on any lines if you spot any errors, offering an explanation of the problem.
9 changes: 9 additions & 0 deletions sprint-5/03-fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
def double(number):
return number * 3

print(double(10))

# TASK 3:
# Read the code and see if you can find any bugs.
# Write down what the bug is, and how would you fix it?
# Are there multiple ways you could fix it?
37 changes: 37 additions & 0 deletions sprint-5/04-addmypy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
def open_account(balances, name, amount):
balances[name] = amount

def sum_balances(accounts):
total = 0
for name, pence in accounts.items():
print(f"{name} had balance {pence}")
total += pence
return total

def format_pence_as_string(total_pence):
if total_pence < 100:
return f"{total_pence}p"
pounds = int(total_pence / 100)
pence = total_pence % 100
return f"£{pounds}.{pence:02d}"

balances = {
"Sima": 700,
"Linn": 545,
"Georg": 831,
}

open_account("Tobi", 9.13)
open_account("Olya", "£7.13")

total_pence = sum_balances(balances)
total_string = format_pence_as_str(total_pence)

print(f"The bank accounts total {total_string}")

# TASK 4
# This code contains bugs related to types. They are bugs mypy can catch.
# Read this code to understand what it's trying to do.
# Add type annotations to the method parameters and return types of this code.
# Run the code through mypy, and fix all of the bugs that show up.
# When you're confident all of the type annotations are correct, and the bugs are fixed, run the code and check it works.
24 changes: 24 additions & 0 deletions sprint-5/05-predict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
imran = {
"name": "Imran",
"age": 22,
"preferred_operating_system": "Ubuntu",
}

eliza = {
"name": "Eliza",
"age": 34,
"preferred_operating_system": "Arch Linux",
}


print(imran["name"])
print(imran["address"])

# TASK 5:
# This code contains some untyped objects.
# Try checking it with mypy before running the code and predict what you think will happen when you run the code.
#
# Prediction:
#
# Can you explain what actualy happens?
#
27 changes: 27 additions & 0 deletions sprint-5/06-classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Person:
def __init__(self, name: str, age: int, preferred_operating_system: str):
self.name = name
self.age = age
self.preferred_operating_system = preferred_operating_system

imran = Person("Imran", 22, "Ubuntu")
print(imran.name)
print(imran.address)

eliza = Person("Eliza", 34, "Arch Linux")
print(eliza.name)
print(eliza.address)

# TASK 6.1:
# Run mypy and fix any errors.

# TASK 6.2:
# Create a new function in this file called likes_apple
# It should take a person as parameter
# It returns true if the preferred operating system is "macOS" or "iOS"
# It should return false for any other preferred os
# Add all the appropriate type annotations and test it has no errors in mypy

# TASK 6.3:
# Compare objects and classes
# What are some advantages and disadvantages of each?
5 changes: 5 additions & 0 deletions sprint-5/07-methods.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
TASK 7:
Answer the following questions:
What is the difference between a method and a function?
Can you give some advantages of methods over functions?

28 changes: 28 additions & 0 deletions sprint-5/08-implement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Person:
def __init__(self, name: str, age: int, preferred_car_brand: str):
self.name = name
self.age = age
self.preferred_car_brand = preferred_car_brand

def drivers_license_check(person: Person):
if person.is_adult() == True:
return 'Valid drivers license'

return 'This person is underage!'

imran = Person("Imran", 22, "Mercedes")
print(drivers_license_check(imran)) # should return 'Valid drivers license'

# TASK 8:
#
# Add an `is_adult` method into the class, and make sure your code gives the expected output.
#
# Change the `Person` class to take a date of birth using
# the standard library's `datetime.date` class
# https://docs.python.org/3/library/datetime.html#datetime.date))
# and store the `date of birth` instead of `age`.
#
# Try to run your code now and observe how this change breaks your code.
# What kind of error do you get? Is it helpful in identifying where your next change needs to be?
#
# Now update only the `is_adult` method to fix the error and check everything works correctly.
33 changes: 33 additions & 0 deletions sprint-5/09-encapsulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# TASK 9
#
# Having done some research on encapsulation, think about the benefits.
#
# Think of some examples and in your own words write down some benefits and trade-offs of using encapsulation in classes:
#
#
#

# STRETCH TASK 9.1
#
# In the following class, make the name property private
# Add a `get_name()` method to allow read-only access.

class Person:
def __init__(self, name: str, age: int):
self.name = name
self.__age = age

def is_adult(self):
return self.__age >= 18

imran = Person("Imran", 22)
print(imran.name)
print(imran.age) # fails
print(imran.__age) # fails
print(imran.is_adult()) # works and prints True

eliza = Person("Eliza", 12)
print(eliza.name)
print(eliza.age) # fails
print(imran.__age) # fails
print(eliza.is_adult()) # works and prints False
14 changes: 14 additions & 0 deletions sprint-5/10-dataclass.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# TASK 10.1:
# Copy the code you have so far from task 08-implement.py
# Convert your existing `Person` class from task 8 into a value type using `@datatype`
# so you can print the class (and see it's type and properties)
# and compare class instances that are identical.
# Make sure your `is_adult` method and `drivers_license_check` free function both work as normal.

# TASK 10.2:
# Make a new method on your Person class - `greet()` which should return `"Hello <person name>!"` when used.

# TASK 10.3:
# Read the @datatype documentation here: https://docs.python.org/3/library/dataclasses.html
# Explain what `frozen=True` does to the class?
# What other options could you play around with and explore? Offer suggestions for any that would be useful here.
35 changes: 35 additions & 0 deletions sprint-5/11-predict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from dataclasses import dataclass

@dataclass(frozen=True)
class Animal:
name: str
species: str

@dataclass(frozen=True)
class Person:
name: str
age: int

@dataclass(frozen=True)
class FamilyTree:
parent: Person
members: list

pet = Animal(name="Gromit", species="Dog")
fatma = Person(name="Fatma", age=4)
aisha = Person(name="Aisha", age=6)
imran = Person(name="Imran", age=30)

family = FamilyTree(parent=imran, members=[fatma, aisha, pet])

def print_family_tree(family: FamilyTree):
print(family.parent.name)
for child in family.members:
print(f"{child.name} ({child.age} years old)")

print_family_tree(family)

# TASK 11
# There is a bug in this code. Can you spot it?
# Run your code through mypy. Does mypy spot it?
# Offer an explanation for what is happening.
Loading
Loading