Skip to content

Update Notes/03_Program_organization/02_More_functions.md #166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
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