Skip to content
Closed
12 changes: 12 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"python.testing.pytestArgs": [
"Work",
"--rootdir=Work",
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.formatting.provider": "none"
}
2 changes: 1 addition & 1 deletion Notes/03_Program_organization/02_More_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ For example:
```python
>>> portfolio = parse_csv('Data/portfolio.dat', types=[str, int, float], delimiter=' ')
>>> portfolio
[{'price': '32.20', 'name': 'AA', 'shares': '100'}, {'price': '91.10', 'name': 'IBM', 'shares': '50'}, {'price': '83.44', 'name': 'CAT', 'shares': '150'}, {'price': '51.23', 'name': 'MSFT', 'shares': '200'}, {'price': '40.37', 'name': 'GE', 'shares': '95'}, {'price': '65.10', 'name': 'MSFT', 'shares': '50'}, {'price': '70.44', 'name': 'IBM', 'shares': '100'}]
[{'name': 'AA', 'shares': 100, 'price': 32.2}, {'name': 'IBM', 'shares': 50, 'price': 91.1}, {'name': 'CAT', 'shares': 150, 'price': 83.44}, {'name': 'MSFT', 'shares': 200, 'price': 51.23}, {'name': 'GE', 'shares': 95, 'price': 40.37}, {'name': 'MSFT', 'shares': 50, 'price': 65.1}, {'name': 'IBM', 'shares': 100, 'price': 70.44}]
>>>
```

Expand Down
16 changes: 13 additions & 3 deletions Work/Data/stocksim.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,23 @@ def update(self):
def incr(self,dt):
self.time += dt
if self.index < (len(self.history) - 2):
while self.index < (len(self.history) - 2) and self.time >= self.history[self.index+1][3]:
while self.index < (len(self.history) - 2) and \
self.time >= self.history[self.index+1][3]:
self.index += 1
self.update()

def make_record(self):
return [self.name,round(self.price,2),self.date,minutes_to_str(self.time),round(self.change,2),self.open,round(self.high,2),
round(self.low,2),self.volume]
return [
self.name,
round(self.price, 2),
self.date,
minutes_to_str(self.time),
round(self.change, 2),
self.open,
round(self.high, 2),
round(self.low, 2),
self.volume
]

class MarketSimulator(object):
def __init__(self):
Expand Down
10 changes: 10 additions & 0 deletions Work/bounce.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# bounce.py
#
# Exercise 1.5

def bounce():
current_height = 100 # meters
fall_fraction = 3 / 5 # fraction of from_height

for i in range(1, 11):
current_height *= fall_fraction
print(i, round(current_height, 4))

bounce()
17 changes: 17 additions & 0 deletions Work/bounce_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from bounce import bounce

def test_main(capfd):
bounce()

out, err = capfd.readouterr()
assert out == """1 60.0
2 36.0
3 21.6
4 12.96
5 7.776
6 4.6656
7 2.7994
8 1.6796
9 1.0078
10 0.6047
"""
4 changes: 4 additions & 0 deletions Work/currency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def usd(value: float) -> str:
"""Format a number as USD."""
neg = '-' if value < 0 else ''
return f"{neg}${abs(value):,.2f}"
13 changes: 13 additions & 0 deletions Work/currency_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import pytest
from currency import usd

@pytest.mark.parametrize("input,output", [
(1, "$1.00"),
(11.5, "$11.50"),
(1.75, "$1.75"),
(1200.751, "$1,200.75"),
(-1245.758, "-$1,245.76"),
(-1.754, "-$1.75")
])
def test_usd(input, output):
assert usd(input) == output
20 changes: 20 additions & 0 deletions Work/dowstocks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import csv

def date_tuple(s):
return tuple(str(s).split('/'))

def main():
with open('Data/dowstocks.csv') as f:
rows = csv.reader(f)
headers = next(rows)
print(headers)
types = [str, float, date_tuple, str, float, float, float, float, int]
dow_stocks = [
{ key: func(val) for key, func, val in zip(headers, types, row) }
for row in rows
]
print(dow_stocks[0]['date'])
print(len(dow_stocks))

if __name__ == '__main__':
main()
29 changes: 29 additions & 0 deletions Work/fileparse.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
# fileparse.py
#
# Exercise 3.3
import csv


def parse_csv(
filename: str,
select: list = [],
types: list = [],
has_headers: bool = True,
delimiter: str = ",",
) -> list:
"""
Parse a CSV file into a list of records
"""
with open(filename) as f:
rows = csv.reader(f, delimiter=delimiter)
if has_headers:
orig_headers = next(rows)
headers = select if select else orig_headers
indices = [headers.index(name) for name in headers]
records = []
for orig_row in rows:
if not orig_row:
continue
row = [orig_row[i] for i in indices] if has_headers else orig_row
if types:
row = [func(field) for func, field in zip(types, row)]
record = dict(zip(headers, row)) if has_headers else tuple(row)
records.append(record)
return records
84 changes: 84 additions & 0 deletions Work/fileparse_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from fileparse import parse_csv


def test_parse_csv_select_3_4():
assert parse_csv("Data/portfolio.csv", select=["name", "shares"]) == [
{"name": "AA", "shares": "100"},
{"name": "IBM", "shares": "50"},
{"name": "CAT", "shares": "150"},
{"name": "MSFT", "shares": "200"},
{"name": "GE", "shares": "95"},
{"name": "MSFT", "shares": "50"},
{"name": "IBM", "shares": "100"},
]


def test_parse_csv_select_3_5():
assert parse_csv("Data/portfolio.csv", types=[str, int, float]) == [
{"price": 32.2, "name": "AA", "shares": 100},
{"price": 91.1, "name": "IBM", "shares": 50},
{"price": 83.44, "name": "CAT", "shares": 150},
{"price": 51.23, "name": "MSFT", "shares": 200},
{"price": 40.37, "name": "GE", "shares": 95},
{"price": 65.1, "name": "MSFT", "shares": 50},
{"price": 70.44, "name": "IBM", "shares": 100},
]

assert parse_csv(
"Data/portfolio.csv", select=["name", "shares"], types=[str, int]
) == [
{"name": "AA", "shares": 100},
{"name": "IBM", "shares": 50},
{"name": "CAT", "shares": 150},
{"name": "MSFT", "shares": 200},
{"name": "GE", "shares": 95},
{"name": "MSFT", "shares": 50},
{"name": "IBM", "shares": 100},
]


def test_parse_csv_no_headers_3_6():
assert parse_csv("Data/prices.csv", types=[str, float], has_headers=False) == [
("AA", 9.22),
("AXP", 24.85),
("BA", 44.85),
("BAC", 11.27),
("C", 3.72),
("CAT", 35.46),
("CVX", 66.67),
("DD", 28.47),
("DIS", 24.22),
("GE", 13.48),
("GM", 0.75),
("HD", 23.16),
("HPQ", 34.35),
("IBM", 106.28),
("INTC", 15.72),
("JNJ", 55.16),
("JPM", 36.9),
("KFT", 26.11),
("KO", 49.16),
("MCD", 58.99),
("MMM", 57.1),
("MRK", 27.58),
("MSFT", 20.89),
("PFE", 15.19),
("PG", 51.94),
("T", 24.79),
("UTX", 52.61),
("VZ", 29.26),
("WMT", 49.74),
("XOM", 69.35),
]


def test_parse_csv_delimiter_3_7():
assert parse_csv("Data/portfolio.dat", types=[str, int, float], delimiter=" ") == [
{ "name": "AA", "shares": 100, "price": 32.2 },
{ "name": "IBM", "shares": 50, "price": 91.1 },
{ "name": "CAT", "shares": 150, "price": 83.44 },
{ "name": "MSFT", "shares": 200, "price": 51.23 },
{ "name": "GE", "shares": 95, "price": 40.37 },
{ "name": "MSFT", "shares": 50, "price": 65.1 },
{ "name": "IBM", "shares": 100, "price": 70.44 },
]
1 change: 1 addition & 0 deletions Work/hello.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print('Suh, Dude?')
34 changes: 34 additions & 0 deletions Work/mortgage.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
# mortgage.py
#
# Exercise 1.7

def mortgage(extra_payment_start_month=0,
extra_payment_end_month=0,
extra_payment=0.0):
principal = 500000.0
rate = 0.05
default_payment = 2684.11
paid = 0.0
month = 0

print(f'{"Mo":>3} {"Paid":>11} {"Principal":>11}')
while principal > 0:
month += 1
payment = default_payment

if month >= extra_payment_start_month and month <= extra_payment_end_month:
payment += extra_payment

if payment > principal:
payment = principal
principal = 0
else:
principal = principal * (1 + rate / 12) - payment

paid = paid + payment
print(f'{month:>3} {f"${paid:,.2f}":>11} {f"${principal:,.2f}":>11}')

print('------------------')
print(f'Total paid: ${round(paid, 2):,.2f}')
print('Months: ', month)
print('------------------')
return round(paid, 2)

mortgage(61, 108, 1000)
7 changes: 7 additions & 0 deletions Work/mortgage_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from mortgage import mortgage

def test_mortgage_1_7():
assert round(mortgage(), 1) == 966266.9

def test_mortgage_1_8():
assert round(mortgage(1, 12, 1000), 2) == 927989.46
18 changes: 18 additions & 0 deletions Work/pcost.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# pcost.py
#
# Exercise 1.27
import csv

def pcost(filename):
'''Returns the total cost of the portfolio'''
with open(filename, 'rt') as f:
lines = csv.reader(f)
cost = 0.0
header_line = next(lines)
print(header_line)
for line_no, line in enumerate(lines):
record = dict(zip(header_line, line))
try:
shares = int(record['shares'])
price = float(record['price'])
cost += shares * price
except ValueError:
print(f'Could not parse line {line_no} with data: {line}')
return cost
15 changes: 15 additions & 0 deletions Work/pcost_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Excersize 1.33

from pcost import pcost
import sys

print(sys.argv)
print()

if len(sys.argv) > 1:
filename = sys.argv[1]
else:
filename = 'Data/portfolio.csv'

cost = pcost(filename)
print(f'Total cost ${cost:,.2f}')
13 changes: 13 additions & 0 deletions Work/pcost_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pcost import pcost
from os import path

data_dir = path.join(path.dirname(__file__), 'Data')

def test_pcost_1_27():
assert pcost(path.join(data_dir, 'portfolio.csv')) == 44671.15

def test_pcost_1_31():
assert pcost(path.join(data_dir, 'missing.csv')) == 27381.15

def test_pcost_2_16():
assert pcost(path.join(data_dir, 'portfoliodate.csv')) == 44671.15
Loading