from collections import namedtuple

class Sentence(namedtuple('Sentence', 'type start end words')):
    def __repr__(self):
        return 'Sentence({0.type}, {0.start}-{0.end})'.format(self)

priorityOrder = ['sky', 'FG', 'precip', 'TS', 'w', 'H']

precip = Sentence('precip', 12, 24, 'Isolated showers from midday, becoming widespread in the evening')
winds = Sentence('w', 12, 24, 'Gusty winds in the early afternoon')
ts = Sentence('TS', 9, 24, 'Scattered thunderstorms from the late morning')
hail = Sentence('H', 15, 21, 'Thunderstorms possibly severe in the afternoon with large hail')
sky = Sentence('sky', 0, 0, 'Partly cloudy')

sentences = set([winds, ts, hail, precip, sky])

expected = [sky, precip, ts, hail, winds]

def byTime(sentence):
    return (sentence.start, sentence.end)

# Or more briefly:
byTime = lambda s: (s.start, s.end)

from pprint import pprint
pprint(sorted(sentences, key=byTime))

byTime(precip) < byTime(winds)

def byTimeAndPriority(sentence):
    priority = priorityOrder.index(sentence.type)
    return (sentence.start, sentence.end, priority)

pprint(sorted(sentences, key=byTimeAndPriority))

byTimeAndPriority(precip) < byTimeAndPriority(winds)

for item in sorted(sentences, key=byTimeAndPriority):
    print byTimeAndPriority(item), "<=", item

def generateKeyFn(items):
    precipStart = None
    precipEnd = None
    precipPriority = priorityOrder.index('precip')
    precipSentences = [item for item in items if item.type == 'precip']
    if precipSentences:
        precipStart = min(item.start for item in precipSentences)
        precipEnd = max(item.end for item in precipSentences)
        
    mustFollowPrecip = ('TS', 'H')
    
    def keyFn(item):
        if precipStart and item.type in mustFollowPrecip:
            return (precipStart, precipEnd, precipPriority)
        priority = priorityOrder.index(item.type)
        return (item.start, item.end, priority)

    return keyFn


bySpecialTime = generateKeyFn(sentences)
for item in sorted(sentences, key=bySpecialTime):
    print bySpecialTime(item), "<=", item

def generateKeyFn(items):
    precipStart, precipEnd = None, None
    precipPriority = priorityOrder.index('precip')
    precipSentences = [item for item in items if item.type == 'precip']
    if precipSentences:
        precipStart = min(item.start for item in precipSentences)
        precipEnd = max(item.end for item in precipSentences)
    
    mustFollowPrecip = ('TS', 'H')
    
    def keyFn(item):
        start, end = item.start, item.end
        priority = priorityOrder.index(item.type)
        mustFollow = item.type in mustFollowPrecip
        if precipStart and mustFollow:
            start, end, priority = precipStart, precipEnd, precipPriority
        return (start, end, priority, mustFollow)

    return keyFn


bySpecialTime = generateKeyFn(sentences)
for item in sorted(sentences, key=bySpecialTime):
    print bySpecialTime(item), "<=", item

def generateKeyFn(items):
    precipStart, precipEnd = None, None
    precipPriority = priorityOrder.index('precip')
    precipSentences = [item for item in items if item.type == 'precip']
    if precipSentences:
        precipStart = min(item.start for item in precipSentences)
        precipEnd = max(item.end for item in precipSentences)
    
    typesMustFollowPrecip = ('TS', 'H')
    typesMustFollowTS = ('H',)
    
    def keyFn(item):
        start, end = item.start, item.end
        priority = priorityOrder.index(item.type)
        mustFollowTS = item.type in typesMustFollowTS
        mustFollowPrecip = item.type in typesMustFollowPrecip
        if precipStart and mustFollowPrecip:
            start, end, priority = precipStart, precipEnd, precipPriority
        return (start, end, priority, mustFollowPrecip, mustFollowTS)

    return keyFn


bySpecialTime = generateKeyFn(sentences)
for item in sorted(sentences, key=bySpecialTime):
    print bySpecialTime(item), "<=", item

sorted(sentences, key=bySpecialTime) == expected

sentencesNoPrecip = set([winds, ts, hail, sky])
sortKey = generateKeyFn(sentencesNoPrecip)
for item in sorted(sentencesNoPrecip, key=sortKey):
    print sortKey(item), "<=", item

import py


def test_sortingTime():
    input = [
        Sentence('precip', 0, 12, 'rain in the morning'),
        Sentence('sky', 12, 24, 'sunny afternoon'),
        ]
    expected = ['precip', 'sky']
    sortKey = generateKeyFn(input)
    assert [s.type for s in sorted(input, key=sortKey)] == expected


def test_sortingPriority():
    input = [
        Sentence('sky', 0, 24, 'cloudy'),
        Sentence('precip', 0, 24, 'rain'),
        ]
    expected = ['precip', 'sky']
    sortKey = generateKeyFn(input)
    assert [s.type for s in sorted(input, key=sortKey)] == expected


def test_sortingTSAfterPrecip():
    input = [
        Sentence('TS', 0, 12, 'thunderstorms'),
        Sentence('precip', 12, 24, 'rain'),
        ]
    expected = ['precip', 'TS']
    sortKey = generateKeyFn(input)
    assert [s.type for s in sorted(input, key=sortKey)] == expected

    
def test_sortingHailAfterTSWithPrecip():
    input = [
        Sentence('precip', 12, 24, 'rain'),
        Sentence('TS', 0, 12, 'thunderstorms'),
        Sentence('H', 0, 6, 'hail'),
        ]
    expected = ['precip', 'TS', 'H']
    sortKey = generateKeyFn(input)
    assert [s.type for s in sorted(input, key=sortKey)] == expected


def test_sortingHailAfterTSNoPrecip():
    input = [
        Sentence('TS', 0, 12, 'thunderstorms'),
        Sentence('H', 0, 6, 'hail'),
        ]
    expected = ['TS', 'H']
    sortKey = generateKeyFn(input)
    assert [s.type for s in sorted(input, key=sortKey)] == expected



$py.test test_sort.py -v
=============================================== test session starts ===============================================
platform linux2 -- Python 2.7.5 -- pytest-2.3.5 -- /usr/bin/python
plugins: xdist, cov
collected 5 items 

test_sort.py:34: test_sortingTime PASSED
test_sort.py:44: test_sortingPriority PASSED
test_sort.py:54: test_sortingTSAfterPrecip PASSED
test_sort.py:64: test_sortingHailAfterTSWithPrecip PASSED
test_sort.py:75: test_sortingHailAfterTSNoPrecip FAILED

==================================================== FAILURES =====================================================
_________________________________________ test_sortingHailAfterTSNoPrecip _________________________________________
test_sort.py:82: in test_sortingHailAfterTSNoPrecip
>       assert [s.type for s in sorted(input, key=sortKey)] == expected
E       assert ['H', 'TS'] == ['TS', 'H']
E         At index 0 diff: 'H' != 'TS'
======================================= 1 failed, 4 passed in 0.02 seconds =======================================