Skip to content
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

jread-39 #857

Open
wants to merge 9 commits into
base: community
Choose a base branch
from
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
6 changes: 6 additions & 0 deletions 01/jread/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DICTIONARY = '../dictionary.txt'

scrabble_scores = [(1, "E A O I N R T L S U"), (2, "D G"), (3, "B C M P"),
(4, "F H V W Y"), (5, "K"), (8, "J X"), (10, "Q Z")]
LETTER_SCORES = {letter: score for score, letters in scrabble_scores
for letter in letters.split()}
29 changes: 29 additions & 0 deletions 01/jread/test_wordvalue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import unittest

from data import DICTIONARY, LETTER_SCORES
from wordvalue import load_words, calc_word_value, max_word_value

TEST_WORDS = ('bob', 'julian', 'pybites', 'quit', 'barbeque')

class TestWordValue(unittest.TestCase):

def test_load_words(self):
words = load_words()
self.assertEqual(len(words), 235886)
self.assertEqual(words[0], 'A')
self.assertEqual(words[-1], 'Zyzzogeton')
self.assertNotIn(' ', ''.join(words))

def test_calc_word_value(self):
self.assertEqual(calc_word_value('bob'), 7)
self.assertEqual(calc_word_value('JuliaN'), 13)
self.assertEqual(calc_word_value('PyBites'), 14)
self.assertEqual(calc_word_value('benzalphenylhydrazone'), 56)

def test_max_word_value(self):
self.assertEqual(max_word_value(TEST_WORDS), 'barbeque')
self.assertEqual(max_word_value(), 'benzalphenylhydrazone')

if __name__ == "__main__":
unittest.main()

51 changes: 51 additions & 0 deletions 01/jread/wordvalue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import re

from data import DICTIONARY, LETTER_SCORES

CHARS_REGEX = re.compile('[a-zA-Z]+')


def load_words() -> list:
"""
Loads words from the file designated by the DICTIONARY constant into a list
(trailing newline characters are stripped)
@return: the words in DICTIONARY as a list
"""
words: list
with open(DICTIONARY) as f:
words = [line.rstrip('\n') for line in f]
return words


def calc_word_value(word: str) -> int:
"""
Calculates the scabble value of the word specified
@param word: the word value to calculate the scabble value for
@return: the scrabble value (an integer)
"""
value: int = 0
for c in ''.join(CHARS_REGEX.findall(word)):
value += LETTER_SCORES[c.upper()]
return value


def max_word_value(dictionary: list = None) -> str:
"""
Determine the word in dictionary which provides the highest scrabble score
@param dictionary: an optional list of alternate words to check. If not specified, load_words() will be used
@return: the word in dictionary providing the highest scrabble score
"""
dictionary = load_words() if dictionary is None else dictionary
word: str = ''
value: int = 0
for check_word in dictionary:
check_word_value = calc_word_value(check_word)
if check_word_value > value:
word = check_word
value = check_word_value
return word


if __name__ == "__main__":
print(max_word_value())

53 changes: 53 additions & 0 deletions 13/jread/directors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import csv
from collections import defaultdict, namedtuple

MOVIE_DATA = '../movie_metadata.csv'
NUM_TOP_DIRECTORS = 20
MIN_MOVIES = 4
MIN_YEAR = 1960

Director = namedtuple('Director', 'name avg_score movies')
Movie = namedtuple('Movie', 'title year score')


def get_movies_by_director():
movies = defaultdict(list)
with open(MOVIE_DATA) as f:
for rec in csv.DictReader(f):
try:
name = rec['director_name']
if int(rec['title_year']) >= MIN_YEAR:
movies[name].append(Movie(title=rec['movie_title'].replace('\xa0', ''),
year=int(rec['title_year']), score=float(rec['imdb_score'])))
except ValueError:
continue

directors = {}
for name in movies:
if len(movies[name]) >= MIN_MOVIES:
directors[name] = (Director(name=name, avg_score=_calc_mean(movies[name]), movies=movies[name]))

return directors


def _calc_mean(movies):
return round(sum(movie.score for movie in movies) / len(movies), 1)


def print_results(directors):
for i, director in zip(range(20), sorted(directors.items(), key=lambda x: float(x[1].avg_score), reverse=True)):
print()
print(f'{i+1:02d}. {director[0]:<52} {director[1].avg_score}')
print('-' * 60)
for movie in sorted(director[1].movies, key=lambda x: float(x.score), reverse=True):
print(f'{movie.year}] {movie.title:<50} {movie.score}')


def main():
directors = get_movies_by_director()
print_results(directors)


if __name__ == '__main__':
main()

31 changes: 31 additions & 0 deletions 13/jread/test_directors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from directors import get_movies_by_director, _calc_mean

def test():
directors = get_movies_by_director()

assert 'Sergio Leone' in directors
assert len(directors['Sergio Leone'].movies) == 4
assert len(directors['Peter Jackson'].movies) == 12

movies_sergio = directors['Sergio Leone'].movies
movies_nolan = directors['Christopher Nolan'].movies
assert _calc_mean(movies_sergio) == 8.5
assert _calc_mean(movies_nolan) == 8.4

assert 'Andrew Stanton' not in directors

expected_directors = ['Sergio Leone', 'Christopher Nolan', 'Quentin Tarantino',
'Hayao Miyazaki', 'Frank Darabont', 'Stanley Kubrick']
expected_avg_scores = [8.5, 8.4, 8.2, 8.2, 8.0, 8.0]
expected_num_movies = [4, 8, 8, 4, 4, 7]
report = sorted(directors.items(), key=lambda x: float(x[1].avg_score), reverse=True)
for counter, (i, j, k) in enumerate(zip(expected_directors, expected_avg_scores, expected_num_movies)):
assert (report[counter][0], report[counter][1].avg_score) == (i, j)
assert len(report[counter][1].movies) == k
assert _calc_mean(report[counter][1].movies) == j

return "tests pass"


if __name__ == '__main__':
print(test())
101 changes: 101 additions & 0 deletions 39/jread/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from flask import Flask, jsonify, abort, make_response, request

NOT_FOUND = 'Not found'
BAD_REQUEST = 'Bad request'

app = Flask(__name__)

items = [
{
'id': 1,
'name': 'laptop',
'value': 1000
},
{
'id': 2,
'name': 'chair',
'value': 300,
},
{
'id': 3,
'name': 'book',
'value': 20,
},
]


def _get_item(id):
return [item for item in items if item['id'] == id]


def _record_exists(name):
return [item for item in items if item["name"] == name]


@app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'error': NOT_FOUND}), 404)


@app.errorhandler(400)
def bad_request(error):
return make_response(jsonify({'error': BAD_REQUEST}), 400)


@app.route('/api/v1.0/items', methods=['GET'])
def get_items():
return jsonify({'items': items})


@app.route('/api/v1.0/items/<int:id>', methods=['GET'])
def get_item(id):
item = _get_item(id)
if not item:
abort(404)
return jsonify({'items': item})


@app.route('/api/v1.0/items', methods=['POST'])
def create_item():
if not request.json or 'name' not in request.json or 'value' not in request.json:
abort(400)
item_id = items[-1].get("id") + 1
name = request.json.get('name')
if _record_exists(name):
abort(400)
value = request.json.get('value')
if type(value) is not int:
abort(400)
item = {"id": item_id, "name": name,
"value": value}
items.append(item)
return jsonify({'item': item}), 201


@app.route('/api/v1.0/items/<int:id>', methods=['PUT'])
def update_item(id):
item = _get_item(id)
if len(item) == 0:
abort(404)
if not request.json:
abort(400)
name = request.json.get('name', item[0]['name'])
value = request.json.get('value', item[0]['value'])
if type(value) is not int:
abort(400)
item[0]['name'] = name
item[0]['value'] = value
return jsonify({'item': item[0]}), 200


@app.route('/api/v1.0/items/<int:id>', methods=['DELETE'])
def delete_item(id):
item = _get_item(id)
if len(item) == 0:
abort(404)
items.remove(item[0])
return jsonify({}), 204


if __name__ == '__main__':
app.run(debug=True)
53 changes: 53 additions & 0 deletions 39/jread/test_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import app
import json
import pytest

CLIENT = app.app.test_client()


@pytest.mark.parametrize('item_id', [1, 2, 3])
def test_get_item(item_id: int):
response = CLIENT.get(f'/api/v1.0/items/{item_id}')
assert json.loads(response.data)['items'][0] == app.items[item_id - 1]


def test_get_item_not_found():
response = CLIENT.get('/api/v1.0/items/100')
assert response.status_code == 404


def test_get_items():
response = CLIENT.get('/api/v1.0/items')
assert json.loads(response.data)['items'] == app.items


@pytest.mark.parametrize('name, value', [
('monitor', 500),
('desk', 1000),
('keyboard', 100)
])
def test_create_item(name: str, value: int):
item = {'name': name, 'value': value}
response = CLIENT.post('/api/v1.0/items', data=json.dumps(item), content_type='application/json')
assert response.status_code == 201
assert json.loads(response.data)['item'] == app.items[-1]


@pytest.mark.parametrize('value, item_id', [
(500, 1),
(1000, 2)
])
def test_update_item(value: int, item_id: int):
item = json.loads(CLIENT.get(f'/api/v1.0/items/{item_id}').data)['items'][0]
item['value'] = value
response = CLIENT.put(f'/api/v1.0/items/{item_id}', data=json.dumps(item), content_type='application/json')
assert json.loads(response.data)['item'] == item


@pytest.mark.parametrize('item_id, status_code', [
(1, 204),
(1, 404)
])
def test_delete_item(item_id: int, status_code: int):
response = CLIENT.delete(f'/api/v1.0/items/{item_id}')
assert response.status_code == status_code