service.py

changeset 109
88a5110b66ba
parent 105
5bb61c2b037d
child 114
b736478416d4
equal deleted inserted replaced
108:4b09d8a597f8 109:88a5110b66ba
208 'imminent': imminent(schedule_entry), 208 'imminent': imminent(schedule_entry),
209 }) 209 })
210 return render_template( 210 return render_template(
211 'stop.html', 211 'stop.html',
212 schedule = schedule, 212 schedule = schedule,
213 ref = bus_stop.code,
213 name = bus_stop.code + ' ' + tr(bus_stop.name, 'bus-stops'), 214 name = bus_stop.code + ' ' + tr(bus_stop.name, 'bus-stops'),
214 link_to_map = bus_stop.location.link_to_map, 215 link_to_map = bus_stop.location.link_to_map,
215 region = hasattr(bus_stop, 'region_name') and bus_stop.region or None, 216 region = hasattr(bus_stop, 'region_name') and bus_stop.region or None,
216 location = bus_stop.location, 217 location = bus_stop.location,
217 cluster = bus_stop.cluster.url_name if len(bus_stop.cluster.stops) > 1 else None, 218 cluster = bus_stop.cluster.url_name if len(bus_stop.cluster.stops) > 1 else None,
219 typename = bus_stop.typename, 220 typename = bus_stop.typename,
220 service = min(bus_stop.services), 221 service = min(bus_stop.services),
221 ) 222 )
222 223
223 def week_schedule(bus_stop, start_date = today(), **kwargs): 224 def week_schedule(bus_stop, start_date = today(), **kwargs):
224 for i in range(-1, 7): 225 for i in range(7):
225 try: 226 try:
226 yield from bus_stop.schedule_for_day(start_date + timedelta(i), **kwargs) 227 yield from bus_stop.schedule_for_day(start_date + timedelta(i), **kwargs)
227 except ValueError: 228 except ValueError:
228 # went outside bounds 229 # went outside bounds
229 return 230 return
322 for schedule_entry in week_schedule: 323 for schedule_entry in week_schedule:
323 from busroute import greatly_simplify_name 324 from busroute import greatly_simplify_name
324 sign_tuple = tuple(sign_elements(schedule_entry, format = 'short')) 325 sign_tuple = tuple(sign_elements(schedule_entry, format = 'short'))
325 sign_tuple = tuple(greatly_simplify_name(k) for k in sign_tuple) 326 sign_tuple = tuple(greatly_simplify_name(k) for k in sign_tuple)
326 route = schedule_entry['trip'].route.reference 327 route = schedule_entry['trip'].route.reference
327 night_routes[route] &= is_weekend_night(schedule_entry['time']) 328 night_routes[route] &= is_night_time(schedule_entry['time'])
328 destinations_per_route[route][sign_tuple] += 1 329 destinations_per_route[route][sign_tuple] += 1
329 trip_mapping[schedule_entry_hash(schedule_entry)] = (route, sign_tuple) 330 trip_mapping[schedule_entry_hash(schedule_entry)] = (route, sign_tuple)
330 num_leaves += 1 331 num_leaves += 1
331 night_routes = {key for key, value in night_routes.items() if value} 332 night_routes = {key for key, value in night_routes.items() if value}
332 routes_per_destination = defaultdict(set) 333 routes_per_destination = defaultdict(set)
573 return time.strftime('%-a %H:%M').replace(' ', '\xa0') 574 return time.strftime('%-a %H:%M').replace(' ', '\xa0')
574 else: 575 else:
575 with activate_locale(): 576 with activate_locale():
576 return time.strftime('%-d.%-m. %H:%M').replace(' ', '\xa0') 577 return time.strftime('%-d.%-m. %H:%M').replace(' ', '\xa0')
577 578
578 @app.route('/stop_cluster/<cluster_name>') 579 def make_cluster(cluster):
579 def cluster_schedule(cluster_name): 580 schedule = list({
580 from buses import bus_stops, clusters_by_name 581 'time': time_representation(schedule_entry['time']),
581 schedule = [] 582 'route': schedule_entry['trip'].route.reference,
582 try: 583 'route-splice': split_route_ref(schedule_entry['trip'].route.reference),
583 cluster = clusters_by_name[cluster_name] 584 'sign': sign(schedule_entry),
584 except KeyError: 585 'trip': schedule_entry['stop'].trip.name,
585 abort(404) 586 'night': is_night_time(schedule_entry['time']),
586 for schedule_entry in cluster.schedule(max_amount = 100): 587 'stop': schedule_entry['stop'].stop,
587 schedule.append({ 588 'stop_id': schedule_entry['stop'].stop.reference,
588 'time': time_representation(schedule_entry['time']), 589 'stop_code': schedule_entry['stop'].stop.code,
589 'route': schedule_entry['trip'].route.reference, 590 'stop_name': tr(schedule_entry['stop'].stop.name, 'bus-stops', 'places'),
590 'route-splice': split_route_ref(schedule_entry['trip'].route.reference), 591 'imminent': imminent(schedule_entry),
591 'sign': sign(schedule_entry), 592 'typename': schedule_entry['stop'].stop.typename,
592 'trip': schedule_entry['stop'].trip.name, 593 } for schedule_entry in cluster.schedule(max_amount = 100))
593 'night': is_night_time(schedule_entry['time']),
594 'stop_id': schedule_entry['stop'].stop.reference,
595 'stop_code': schedule_entry['stop'].stop.code,
596 'stop_name': tr(schedule_entry['stop'].stop.name, 'bus-stops', 'places'),
597 'imminent': imminent(schedule_entry),
598 'typename': schedule_entry['stop'].stop.typename,
599 })
600 stops_in_cluster = sorted( 594 stops_in_cluster = sorted(
601 ({ 595 ({
602 'id': stop.reference, 596 'id': stop.reference,
603 'code': stop.code, 597 'code': stop.code,
604 'name': tr(stop.name, 'bus-stops'), 598 'name': tr(stop.name, 'bus-stops'),
615 amount_of_stops_in_cluster = len(stops_in_cluster), 609 amount_of_stops_in_cluster = len(stops_in_cluster),
616 tr = tr, 610 tr = tr,
617 service = min(set.union(*[bus_stop.services for bus_stop in cluster.stops])), 611 service = min(set.union(*[bus_stop.services for bus_stop in cluster.stops])),
618 ) 612 )
619 613
614 @app.route('/stop_cluster/<cluster_name>')
615 def cluster_schedule(cluster_name):
616 from buses import bus_stops, clusters_by_name
617 try:
618 cluster = clusters_by_name[cluster_name]
619 except KeyError:
620 abort(404)
621 else:
622 return make_cluster(cluster)
623
624 @app.route('/custom')
625 def custom_cluster():
626 from flask import request
627 from buses import bus_stops, CustomBusStopCluster
628 if 'stops' in request.args:
629 cluster = CustomBusStopCluster(
630 name = request.args.get('name', 'Aikataulu'),
631 stops = {bus_stops[stop_code] for stop_code in str.split(request.args['stops'], ';')},
632 )
633 return make_cluster(cluster)
634 else:
635 return render_template('custom_cluster.html')
636
620 def day_class(weekday): 637 def day_class(weekday):
621 if weekday < 5: 638 if weekday < 5:
622 return 'working-day' 639 return 'working-day'
623 elif weekday == 5: 640 elif weekday == 5:
624 return 'saturday' 641 return 'saturday'
626 assert weekday == 6 643 assert weekday == 6
627 return 'sunday' 644 return 'sunday'
628 645
629 class Week: 646 class Week:
630 def __init__(self, year, weeknumber): 647 def __init__(self, year, weeknumber):
631 self.year, self.weeknumber = year, weeknumber 648 self.year, self.weeknumber = int(year), int(weeknumber)
632 def normalize(self): 649 def normalize(self):
633 while self.weeknumber > 52: 650 while self.weeknumber > 52:
634 self.weeknumber -= 52 651 self.weeknumber -= 52
635 self.year += 1 652 self.year += 1
636 while self.weeknumber < 1: 653 while self.weeknumber < 1:
663 try: 680 try:
664 year, weeknumber = string.split('W', 1) 681 year, weeknumber = string.split('W', 1)
665 return Week(year = int(year), weeknumber = int(weeknumber)) 682 return Week(year = int(year), weeknumber = int(weeknumber))
666 except ValueError: 683 except ValueError:
667 raise ValueError('bad week string: ' + repr(string)) 684 raise ValueError('bad week string: ' + repr(string))
685 def __str__(self):
686 return str(self.year) + 'W' + str(self.weeknumber)
668 @staticmethod 687 @staticmethod
669 def now(): 688 def now():
670 from datetime import date 689 from datetime import date
671 cal = date.today().isocalendar() 690 cal = date.today().isocalendar()
672 return Week(year = cal[0], weeknumber = cal[1]) 691 return Week(year = cal[0], weeknumber = cal[1])
698 try: 717 try:
699 bus_stop = bus_stops[stop_reference] 718 bus_stop = bus_stops[stop_reference]
700 except KeyError: 719 except KeyError:
701 abort(404) 720 abort(404)
702 week_model = {} 721 week_model = {}
703 bus_stop_schedule = list(week_schedule(bus_stop, start_date = week.monday(), arrivals = True)) 722 bus_stop_schedule = list(week_schedule(bus_stop, start_date = week.monday(), arrivals = True, allow_gone = True))
704 description = describe(bus_stop, bus_stop_schedule) 723 description = describe(bus_stop, bus_stop_schedule)
705 for schedule_entry in bus_stop_schedule: 724 for schedule_entry in bus_stop_schedule:
706 route_ref = schedule_entry['trip'].route.reference 725 route_ref = schedule_entry['trip'].route.reference
707 if route_filter(route_ref) and dest_filter(schedule_entry['trip']): 726 if route_filter(route_ref) and dest_filter(schedule_entry['trip']):
708 time = schedule_entry['time'] 727 time = schedule_entry['time']
709 date = schedule_entry['date'] 728 date = schedule_entry['date']
710 if date not in week_model: 729 if date not in week_model:
711 week_model[date] = {} 730 week_model[date] = dict()
712 day_model = week_model[date] 731 day_model = week_model[date]
713 if time.hour not in day_model: 732 if time.hour not in day_model:
714 day_model[time.hour] = [] 733 day_model[time.hour] = list()
715 hour_model = day_model[time.hour] 734 hour_model = day_model[time.hour]
716 hour_model.append({ 735 list.append(hour_model, {
717 'route': description['variant-map'][schedule_entry_hash(schedule_entry)], 736 'route': description['variant-map'][schedule_entry_hash(schedule_entry)],
718 'route-splice': split_route_ref(route_ref), 737 'route-splice': split_route_ref(route_ref),
719 'trip': schedule_entry['stop'].trip.name, 738 'trip': schedule_entry['stop'].trip.name,
720 'night': is_night_time(schedule_entry['time']), 739 'night': is_night_time(schedule_entry['time']),
721 'minute': time.minute, 740 'minute': time.minute,
728 except KeyError: 747 except KeyError:
729 week_model[day] = {} 748 week_model[day] = {}
730 else: 749 else:
731 def hour_key(x): 750 def hour_key(x):
732 return (x - 5) % 24 751 return (x - 5) % 24
733 # Fill in missing hours from 5am to last active hour 752 # Fill in missing hours
734 hours = set(day_model.keys()) | {5} 753 hours = set(dict.keys(day_model))
735 sorted_hours = sorted(hours, key = hour_key) 754 sorted_hours = sorted(hours, key = hour_key)
736 start_hour = sorted_hours[0] 755 start_hour = sorted_hours[0]
737 end_hour = sorted_hours[-1] + 1 756 end_hour = sorted_hours[-1] + 1
738 for hour in range(start_hour, end_hour): 757 for hour in range(start_hour, end_hour):
739 hour_start = datetime(day.year, day.month, day.day, hour, 0) 758 hour_start = datetime(day.year, day.month, day.day, hour, 0)
762 tr = tr, 781 tr = tr,
763 week = week_model, 782 week = week_model,
764 description = description, 783 description = description,
765 typename = bus_stop.typename, 784 typename = bus_stop.typename,
766 curweek = week, 785 curweek = week,
786 next_week = week + 1,
787 previous_week = week - 1,
767 ) 788 )
768 789
769 @app.route('/trip/<trip_reference>') 790 @app.route('/trip/<trip_reference>')
770 def trip(trip_reference): 791 def trip(trip_reference):
771 from flask import request 792 from flask import request
820 tr = tr, 841 tr = tr,
821 length = trip.length / 1000, 842 length = trip.length / 1000,
822 service = trip.route.service, 843 service = trip.route.service,
823 ) 844 )
824 845
825 @app.route('/route/<name>') 846 @app.route('/route/<names>')
826 def route_page(name): 847 def route_page(names):
827 from buses import routes 848 from buses import routes
828 from collections import defaultdict 849 from collections import defaultdict
829 from busroute import greatly_simplify_name 850 from busroute import greatly_simplify_name
830 route = routes[name.upper()] 851 routes = {routes[name.upper()] for name in names.split(';')}
831 schedules = defaultdict(list) 852 schedules = defaultdict(list)
832 for trip in route.trips: 853 for route in routes:
833 if trip.is_served_at(today()): 854 for trip in route.trips:
834 schedules[trip.schedule[0].stop].append({ 855 if trip.is_served_at(today()):
835 'name': trip.reference, 856 schedules[trip.schedule[0].stop].append({
836 'from': trip.from_place, 857 'name': trip.reference,
837 'to': trip.to_place, 858 'from': trip.from_place,
838 'description': ' - '.join( 859 'to': trip.to_place,
839 greatly_simplify_name(place) 860 'description': ' - '.join(
840 for place in trip_description(trip) 861 greatly_simplify_name(place)
841 ), 862 for place in trip_description(trip)
842 'gone': datetime.combine(today(), time()) + trip.schedule[-1].arrival_time < now(), 863 ),
843 'time': time_representation(datetime.combine(today(), time()) + trip.schedule[0].departure_time), 864 'gone': datetime.combine(today(), time()) + trip.schedule[-1].arrival_time < now(),
844 }) 865 'time': time_representation(datetime.combine(today(), time()) + trip.schedule[0].departure_time),
845 return render_template('route.html', 866 'route': route.reference,
846 name = route.reference + ' ' + route.description, 867 })
847 tr = tr, 868 return render_template('route.html',
848 schedules = schedules, 869 name = route.reference + ' ' + route.description,
849 ) 870 tr = tr,
871 schedules = schedules,
872 )
850 873
851 @app.route('/interesting') 874 @app.route('/interesting')
852 def interesting(): 875 def interesting():
853 from buses import all_trips, services_for_day 876 from buses import all_trips, services_for_day
854 from busroute import simplify_name 877 from busroute import simplify_name

mercurial