diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..171a6a93 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12.1 diff --git a/grep b/grep new file mode 100644 index 00000000..e69de29b diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..590cdaf5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,28 @@ +[project] +name = "python-mastery" +version = "0.1.0" +description = "Advanced python coursework." +authors = [ + { name = "bitmole", email = "robert@idea-loop.com" } +] +dependencies = [] +readme = "README.md" +requires-python = ">= 3.8" + +[project.scripts] +hello = "python_mastery:hello" +pcost = "python_mastery:pcost" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.rye] +managed = true +dev-dependencies = [] + +[tool.hatch.metadata] +allow-direct-references = true + +[tool.hatch.build.targets.wheel] +packages = ["src/python_mastery"] diff --git a/requirements-dev.lock b/requirements-dev.lock new file mode 100644 index 00000000..8f230963 --- /dev/null +++ b/requirements-dev.lock @@ -0,0 +1,10 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: false +# with-sources: false + +-e file:. diff --git a/requirements.lock b/requirements.lock new file mode 100644 index 00000000..8f230963 --- /dev/null +++ b/requirements.lock @@ -0,0 +1,10 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: false +# with-sources: false + +-e file:. diff --git a/src/python_mastery/__init__.py b/src/python_mastery/__init__.py new file mode 100644 index 00000000..a2ba189e --- /dev/null +++ b/src/python_mastery/__init__.py @@ -0,0 +1,6 @@ +def hello(): + return "Hello from python-mastery!" + +def pcost(): + from .pcost import portfolio_cost + print('Total: ', portfolio_cost('Data/portfolio.dat')) diff --git a/src/python_mastery/art.py b/src/python_mastery/art.py new file mode 100644 index 00000000..dc9d9c13 --- /dev/null +++ b/src/python_mastery/art.py @@ -0,0 +1,15 @@ +# art.py + +import sys +import random + +chars = '\|/' + +def draw(rows, columns): + for r in range(rows): + print(''.join(random.choice(chars) for _ in range(columns))) + +if __name__ == "__main__": + if len(sys.argv) != 3: + raise SystemExit('Usage: art.py rows columns') + draw(int(sys.argv[1]), int(sys.argv[2])) diff --git a/src/python_mastery/pcost.py b/src/python_mastery/pcost.py new file mode 100644 index 00000000..19dd80ba --- /dev/null +++ b/src/python_mastery/pcost.py @@ -0,0 +1,26 @@ +# pcost.py + +import sys + +def portfolio_cost(path): + stockdicts = [] + with open(path) as f: + for row in f: + name, shares, price = row.split() + try: + shares = int(shares) + price = float(price) + d = dict(zip(['name', 'shares', 'price'], (name, shares, price))) + print(d) + stockdicts.append(d) + except ValueError as e: + print('Could not parse: ', row, end='') + print('Reason: ', e) + + return sum(s['shares'] * s['price'] for s in stockdicts) + + +if __name__ == "__main__": + if len(sys.argv) != 2: + raise SystemExit('Usage: pcost portfile') + print('Total cost:', portfolio_cost(sys.argv[1])) diff --git a/src/python_mastery/readport.py b/src/python_mastery/readport.py new file mode 100644 index 00000000..6ca985a3 --- /dev/null +++ b/src/python_mastery/readport.py @@ -0,0 +1,23 @@ +# readport.py + +import csv + +def read_portfolio(filename): + """Reads a file into a list of dicts representing stock holdings + + :filename: TODO + :returns: TODO + + """ + portfolio = [] + with open(filename) as f: + rows = csv.reader(f) + headers = next(rows) # skip headers + for row in rows: + holding = { + 'name': row[0], + 'shares': int(row[1]), + 'price': float(row[2]), + } + portfolio.append(holding) + return portfolio diff --git a/src/python_mastery/readrides.py b/src/python_mastery/readrides.py new file mode 100644 index 00000000..01ff1440 --- /dev/null +++ b/src/python_mastery/readrides.py @@ -0,0 +1,152 @@ +# readrides.py + +import csv +from collections import namedtuple + +class Ride(object): + def __init__(self, route, date, daytype, rides): + self._route = route + self._date = date + self._daytype = daytype + self._rides = rides + +class SlotRide(object): + __slots__ = ['_route', '_date', '_daytype', '_rides'] + def __init__(self, route, date, daytype, rides): + self._route = route + self._date = date + self._daytype = daytype + self._rides = rides + +TupRide = namedtuple('TupRide', ['route', 'date', 'daytype', 'rides']) + + +def read_rides_as_strings(filename): + """ + Read the bus ride data as a list of strings + """ + records = [] + with open(filename) as f: + for row in f: + records.append(row) + return records + +def read_rides_as_tuples(filename): + """ + Read the bus ride data as a list of tuples + """ + records = [] + with open(filename) as f: + rows = csv.reader(f) + headings = next(rows) # skip headers + for row in rows: + route, date, daytype, rides = row + rides = int(rides) + records.append((route, date, daytype, rides)) + return records + +def read_rides_as_namedtuples(filename): + """ + Read the bus ride data as a list of named tuples + """ + records = [] + with open(filename) as f: + rows = csv.reader(f) + headings = next(rows) # skip headers + for row in rows: + route, date, daytype, rides = row + rides = int(rides) + records.append(TupRide(route, date, daytype, rides)) + return records + +def read_rides_as_dicts(filename): + """ + Read the bus ride data as a list of dictionaries + """ + records = [] + with open(filename) as f: + rows = csv.reader(f) + headings = next(rows) # skip headers + for row in rows: + route, date, daytype, rides = row + record = dict( + zip( + ('route', 'date', 'daytype', 'rides'), + (route, date, daytype, int(rides)))) + records.append(record) + return records + +def read_rides_as_objects(filename): + """ + Read the bus ride data as a list of objects + """ + records = [] + with open(filename) as f: + rows = csv.reader(f) + headings = next(rows) # skip headers + for row in rows: + route, date, daytype, rides = row + records.append(Ride(route, date, daytype, int(rides))) + return records + +def read_rides_as_slobjects(filename): + """ + Read the bus ride data as a list of objects with slots + """ + records = [] + with open(filename) as f: + rows = csv.reader(f) + headings = next(rows) # skip headers + for row in rows: + route, date, daytype, rides = row + records.append(SlotRide(route, date, daytype, int(rides))) + return records + +def anal(dicts): + + # how many bus routes exist in Chicago + routes = {d['route'] for d in dicts} + print('Number of bus routes: ', len(routes)) + + # how many people rode the number 22 bus on February 2, 2011? + rides = [d['rides'] for d in dicts if d['route']=='22' and d['date']=='02/02/2011'] + print('Riders on a given day: ', sum(rides)) + + # what's the total number of rides taken on each bus route? + from collections import Counter + totals = Counter() + for d in dicts: + totals[d['route']] += d['rides'] + print('Total rides by route: ', totals.most_common(5)) + + # what five bus routes had the greatest ten-year increase in ridershiop from 2001 to 2011? + old = {d['route']: d['rides'] for d in dicts if d['date'].endswith('2001')} + new = {d['route']: d['rides'] for d in dicts if d['date'].endswith('2011')} + increases = Counter() + for route, rides in new.items(): + increases[route] += rides - old.get(route, 0) + print('Top five increases: ', increases.most_common(5)) + + +if __name__ == "__main__": + import sys + import tracemalloc + if len(sys.argv) != 3: + raise SystemExit('usage: readrides filename datastructure[strings, tuples, namedtupes, dicts, objects, slots]') + + callmap = { + "strings": read_rides_as_strings, + "tuples": read_rides_as_tuples, + "namedtuples": read_rides_as_namedtuples, + "dicts": read_rides_as_dicts, + "obs": read_rides_as_objects, + "slobs": read_rides_as_slobjects, + } + + reader, filename = callmap[sys.argv[2]], sys.argv[1] + tracemalloc.start() + recs = reader(filename) + print('Memory Use: Current %d, Peak %d' % tracemalloc.get_traced_memory()) + + if sys.argv[2] == 'dicts': + anal(recs) diff --git a/src/python_mastery/stock.py b/src/python_mastery/stock.py new file mode 100644 index 00000000..b1a4341a --- /dev/null +++ b/src/python_mastery/stock.py @@ -0,0 +1,11 @@ +# stock.py + +class Stock(object): + """Represents a stock""" + def __init__(self, name, shares, price): + self._name = name + self._shares = shares + self._price = price + + def cost(self): + return self._shares * self._price