Skip to content

Instantly share code, notes, and snippets.

@olymk2
Created July 15, 2015 17:59
Show Gist options
  • Save olymk2/2adb60b250b16cfc0c03 to your computer and use it in GitHub Desktop.
Save olymk2/2adb60b250b16cfc0c03 to your computer and use it in GitHub Desktop.
order by age
import os
import json
import uuid
import random
import unittest
import numpy as np
from flask import Flask, jsonify
app = Flask(__name__)
# run the tests with
# python -m unittest age_sort_example.OrderDataTestCase
# launch the server with python age_sort_example.py
# example urls
# http://127.0.0.1:5000/api/v1.0/artists
# http://127.0.0.1:5000/api/v1.0/artists/age/30/to/35
def load_data_from_file(filename):
"""check the file exists and return the results or an empty dictonary"""
if os.path.isfile(filename):
with open(filename) as fp:
return json.load(fp)
return {'artists': []}
def generate_test_age_data(ages):
"""function to generate data for tests but with fixed ages"""
return {'artists': [
{'uuid': str(uuid.uuid4()), 'age': age} for age in ages]}
def load_data_into_array(artist_source_data):
"""load data into a packed array and pre sort the results sequentially"""
search_data_type = np.dtype([('uuid', np.str_, 73), ('age', np.int8, 1)])
artist_array = np.array([
(artist.get('uuid'), artist.get('age'))
for artist in artist_source_data.get('artists')], dtype=search_data_type)
artist_array.sort(order='age')
return artist_array
def artists_aged_between(artists, age_range_start, age_range_end):
"""filter artists between specified age"""
return artists[
np.where(
(artists['age'] > age_range_start) &
(artists['age'] < age_range_end))]
def artists_aged_between_and_ordered(artists, age_range_start, age_range_end):
"""return artists between specified age and ordered"""
return sort_middle_to_edge(
artists_aged_between(artists, age_range_start, age_range_end))
def sort_middle_to_edge(data):
"""start in the middle and work out to the range edges"""
size = len(data)
if size is 0:
return
offset = 1 # offset from center increment as we loop
mid_point = size / 2 # get a starting point
forward_pos = mid_point # step forwards start point
reverse_pos = mid_point # step to beginning end point
yield data[mid_point] # return the first central item
# increment and step in both directions until we reach the limits of the range
while forward_pos < size and reverse_pos > -1:
forward_pos = mid_point + offset
reverse_pos = mid_point - offset
if reverse_pos >= 0:
yield data[reverse_pos]
if forward_pos <= size - 1:
yield data[forward_pos]
offset += 1
# this will run without the .json file by uncommenting the lines below in place of
# load data from file
#~ artists = load_data_into_array(
#~ generate_test_age_data([random.randint(18, 98) for i in range(0, 10000)]))
artists = load_data_into_array(
load_data_from_file('artists.json'))
@app.route('/api/v1.0/artists', methods=['GET'])
def get_artists():
"""return all artists that exist"""
results = [{'uuid': artist['uuid'], 'age': str(artist['age'])} for artist in artists]
return jsonify({
'artists': results})
@app.route('/api/v1.0/artists/age/<int:lower_age>/to/<int:upper_age>', methods=['GET'])
def get_artists_age_ranged(lower_age, upper_age):
"""return all artists whose age is with in the range"""
results = [{
'uuid': artist['uuid'],
'age': str(artist['age'])}
for artist in artists_aged_between_and_ordered(artists, lower_age, upper_age)]
return jsonify({
'artists': results})
class OrderDataTestCase(unittest.TestCase):
artists_fixed_ages_odd_unordered = [20, 21, 25, 29, 30]
artists_fixed_ages_odd_ordered = [25, 21, 29, 20, 30]
artists_fixed_ages_odd_sorted = [20, 21, 25, 29, 30]
artists_fixed_ages_even_unordered = [20, 21, 25, 29, 30, 31]
artists_fixed_ages_even_ordered = [29, 25, 30, 21, 31, 20]
artists_fixed_ages_odd = load_data_into_array(
generate_test_age_data(artists_fixed_ages_odd_unordered))
artists_fixed_ages_even = load_data_into_array(
generate_test_age_data(artists_fixed_ages_even_unordered))
def test_sort_middle_to_edge_size_odd(self):
"""test we get the expected number of results when we have an odd number of artists"""
ordered_data = [artist for artist in sort_middle_to_edge(self.artists_fixed_ages_odd)]
self.assertNotEqual(len(ordered_data) == 5, "Missing data.")
def test_sort_middle_to_edge_size_even(self):
"""test we get the expected number of results when we have an even number of artists"""
ordered_data = [artist for artist in sort_middle_to_edge(self.artists_fixed_ages_even)]
self.assertNotEqual(len(ordered_data) == 6, "Missing data.")
def test_sort_middle_to_edge_size_empty(self):
"""make sure our sort handles empty lists"""
ordered_data = [artist for artist in sort_middle_to_edge([])]
self.assertNotEqual(len(ordered_data) == 0, "Did not return empty list.")
def test_sort_middle_to_edge_order_odd(self):
"""test the order is returned as expected when we have an add number or artists"""
ages_ordered = sort_middle_to_edge(self.artists_fixed_ages_odd)
ordered_data = [artist['age'] for artist in ages_ordered]
self.assertSequenceEqual(ordered_data, self.artists_fixed_ages_odd_ordered, "Order incorrect. %s %s " % (ordered_data, self.artists_fixed_ages_odd_ordered))
def test_sort_middle_to_edge_order_even(self):
"""test the order is returned as expected when we have an even number or artists"""
ages_ordered = sort_middle_to_edge(self.artists_fixed_ages_even)
ordered_data = [artist['age'] for artist in ages_ordered]
self.assertSequenceEqual(list(ordered_data), list(self.artists_fixed_ages_even_ordered), "Order incorrect. %s %s " % (ordered_data, self.artists_fixed_ages_even_ordered))
def test_results_are_ordered(self):
"""test that loaded data is stored in sequential order"""
ordered_data = [artist['age'] for artist in self.artists_fixed_ages_odd]
self.assertSequenceEqual(ordered_data, self.artists_fixed_ages_odd_sorted, "Data is not sorted")
def test_filter_between(self):
"""test that the result is between our range"""
result = artists_aged_between(self.artists_fixed_ages_odd, 21, 29)
self.assertNotEqual(result['age'] == 25, "Results outside requested range")
if __name__ == "__main__":
#~ unittest.main()
app.run(debug=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment