def bus(): n = NextBus() data = n.get_times() res = make_response(json.dumps(data)) res.mimetype = 'application/json' res.headers['Access-Control-Allow-Origin'] = '*' return res
class NextBusGetTests(TestCase): def setUp(self): self.nextbus = NextBus() def test_get_request_exception(self): with patch('requests.get') as req_get: req_get.side_effect = requests.RequestException() routes = self.nextbus.get(self.nextbus.ALL_ROUTES_URL) assert not routes def test_get_json_exception(self): with patch('requests.get') as req_get: req_get.side_effect = json.decoder.JSONDecodeError( msg="Test", doc='{"name": "fake"}', pos=1) routes = self.nextbus.get(self.nextbus.ALL_ROUTES_URL) assert not routes
def directions(self): """Get paths followed by each direction this bus can travel A bus typically travels 2 directions: inbound and outbound. These paths need not be the same, however, and there may be alternative paths of travel. This function lets one enumerate all such paths. Returns ------- directions : [Direction] """ result = NextBus._fetch_xml({ 'command': 'routeConfig', 'a': self.agency, 'r': self.tag, }) stops = [Stop(route=self.tag, **e.attrs) for e in result[0].children if e.tag == 'stop'] stops = { stop.tag: stop for stop in stops } directions = [] for direction in [x for x in result[0].children if x.tag == 'direction']: directions.append(Direction( route=self.tag, stops=[stops[str(e.attrs.tag)] for e in direction.children], **direction.attrs )) return directions
def __init__(self): super(NextRoute, self).__init__() auth = tweepy.OAuthHandler(consumer_key, consumer_secret) auth.set_access_token(access_token, access_token_secret) # Open a handle to the REST API self.api = tweepy.API(auth) self.api.retry_count = 2 self.api.retry_delay = 5 me = self.api.me() self.my_id = me.id self.my_name = me.screen_name print 'Name: %s id: %s' % (self.my_name, self.my_id) # Open a handle to the UserStreams API self.stream = tweepy.Stream(auth, self, retry_count=2) # Open a handle to NextBus API self.next_bus = NextBus()
def routes(self): """All routes this agency serves Returns ------- routes : [Route] """ if (self._routes is None): result = NextBus._fetch_xml({ 'command': 'routeList', 'a': self.tag, }) self._routes = dict((r.tag, r) for r in [Route(agency=self.tag, **e.attrs) for e in result if e.tag == 'route']) return self._routes
def stops(self): """Get all bus stops served by this route Returns ------- stops : [Stop] """ result = NextBus._fetch_xml({ 'command': 'routeConfig', 'a': self.agency, 'r': self.tag, }) stops = [Stop(route=self.tag, **e.attrs) for e in result[0].children if e.tag == 'stop'] return stops
def setUp(self): self.nextbus = NextBus() self.nextbus.get = MagicMock(side_effect=Exception( "There should be no get calls in these tests!"))
class NextBusUnitTests(TestCase): def setUp(self): self.nextbus = NextBus() self.nextbus.get = MagicMock(side_effect=Exception( "There should be no get calls in these tests!")) # Run tests def setUpRunTests(self): self.valid_routes = [ { 'description': "Blue Line", 'number': 1 }, { 'description': "Green Line", 'number': 2 }, { 'description': "Red Line", 'number': 3 }, ] self.nextbus.get_valid_routes_for_name = MagicMock( return_value=[{ 'description': "Blue Line", 'number': 1 }]) self.nextbus.get_all_routes = MagicMock(return_value=self.valid_routes) self.nextbus.is_valid_direction = MagicMock(return_value=True) self.nextbus.get_valid_stops_for_route = MagicMock( return_value=[{ 'text': "Real Stop", 'value': '1337' }]) self.valid_stops = [{'Text': "Real Stop"}, {'Text': "Fake Stop"}] self.nextbus.get_route_stops = MagicMock(return_value=self.valid_stops) self.nextbus.get_time_remaining = MagicMock( return_value=datetime.timedelta(seconds=360)) def test_run_success(self): self.setUpRunTests() with patch('builtins.print') as print_mock: self.nextbus.run(['Blue', 'Real', 'north']) print_mock.assert_called_with("6.0 minutes") def test_run_invalid_route(self): self.setUpRunTests() self.nextbus.get_valid_routes_for_name = MagicMock(return_value=[]) with patch('builtins.print') as print_mock: self.nextbus.run(['Orange', 'Real', 'north']) print_mock.assert_not_called() def test_run_ambiguous_route(self): self.setUpRunTests() self.nextbus.get_valid_routes_for_name = MagicMock( return_value=self.valid_routes) with patch('builtins.print') as print_mock: self.nextbus.run(['Line', 'Real', 'north']) print_mock.assert_not_called() def test_run_invalid_direction(self): self.setUpRunTests() self.nextbus.is_valid_direction = MagicMock(return_value=False) with patch('builtins.print') as print_mock: self.nextbus.run(['Line', 'Real', 'no']) print_mock.assert_not_called() def test_run_invalid_stop(self): self.setUpRunTests() self.nextbus.get_valid_stops_for_route = MagicMock(return_value=[]) with patch('builtins.print') as print_mock: self.nextbus.run(['Line', 'Real', 'north']) print_mock.assert_not_called() def test_run_ambiguous_stop(self): self.setUpRunTests() self.nextbus.get_valid_stops_for_route = MagicMock( return_value=self.valid_stops) with patch('builtins.print') as print_mock: self.nextbus.run(['Line', 'Stop', 'north']) print_mock.assert_not_called() def test_run_bad_time(self): self.setUpRunTests() self.nextbus.get_time_remaining = MagicMock( return_value=datetime.timedelta(-1)) with patch('builtins.print') as print_mock: self.nextbus.run(['Line', 'Stop', 'north']) print_mock.assert_not_called() # Cache tests def test_cache_hit(self): self.nextbus.cache.update({'test': 'stuff'}) assert 'stuff' == self.nextbus._NextBus__cache('test', 'fakeurl') def test_cache_miss(self): self.nextbus.get = MagicMock(return_value="stuff") assert 'stuff' == self.nextbus._NextBus__cache('test', 'fakeurl') assert {'test': 'stuff'} == self.nextbus.cache def test_cache_force_reset(self): self.nextbus.cache.update({'test': 'stuff'}) self.nextbus.get = MagicMock(return_value="lol") assert 'lol' == self.nextbus._NextBus__cache('test', 'fakeurl', True) assert {'test': 'lol'} == self.nextbus.cache def test_cache_no_return(self): self.nextbus.get = MagicMock(return_value=[]) assert [] == self.nextbus._NextBus__cache('test', 'fakeurl') assert not self.nextbus.cache # is_valid_direction tests def test_is_valid_direction_true(self): self.nextbus.get_route_directions = MagicMock( return_value=[{ 'Value': '4' }, { 'Value': '1' }]) assert self.nextbus.is_valid_direction('north', '1') def test_is_valid_direction_not_direction(self): assert not self.nextbus.is_valid_direction('lol', '1') def test_is_valid_direction_not_for_route(self): self.nextbus.get_route_directions = MagicMock( return_value=[{ 'Value': '4' }, { 'Value': '1' }]) assert not self.nextbus.is_valid_direction('east', '1') # get_time_remaining test def test_get_time_remaining_no_data(self): self.nextbus.get_time_point_departures = MagicMock(return_value=[]) assert datetime.timedelta(-1) == self.nextbus.get_time_remaining( 'north', 'fake_stop', 'fake_route')
def setUp(self): self.nextbus = NextBus()
def setUp(self): self.nextbus = NextBus() self.nextbus.log.error = MagicMock()
class NextBusFunctionalTest(TestCase): def setUp(self): self.nextbus = NextBus() self.nextbus.log.error = MagicMock() def test_run_all_valid(self): with patch('builtins.print') as print_mock: self.nextbus.run( arguments=["5 - Brooklyn Ctr", "Mall of America", "north"]) print_mock.assert_called() self.nextbus.log.error.assert_not_called() def test_run_invalid_route(self): with patch('builtins.print') as print_mock: self.nextbus.run(arguments=["lol", "Mall of America", "north"]) print_mock.assert_not_called() self.nextbus.log.error.assert_called() call_args = self.nextbus.log.error.call_args_list assert "No valid route for lol. Valid routes are:" in call_args[0][ 0][0] def test_run_invalid_route_ambiguous(self): with patch('builtins.print') as print_mock: self.nextbus.run(arguments=["5", "Mall of America", "north"]) print_mock.assert_not_called() call_args = self.nextbus.log.error.call_args_list assert "Route 5 was ambiguous, matches:" in call_args[0][0][0] def test_run_invalid_direction(self): with patch('builtins.print') as print_mock: self.nextbus.run( arguments=["5 - Brooklyn Ctr", "Mall of America", "east"]) print_mock.assert_not_called() self.nextbus.log.error.assert_called_with( "east is not a valid direction. Valid directions for route 5 are: ['north', 'south']" ) def test_run_invalid_direction_wrong(self): with patch('builtins.print') as print_mock: self.nextbus.run( arguments=["5 - Brooklyn Ctr", "Mall of America", "lol"]) print_mock.assert_not_called() call_args = self.nextbus.log.error.call_args_list assert ("lol is not a valid direction. Valid directions are:" in call_args[0][0][0]) def test_run_invalid_stop(self): with patch('builtins.print') as print_mock: self.nextbus.run(arguments=["5 - Brooklyn Ctr", "adwds", "north"]) print_mock.assert_not_called() call_args = self.nextbus.log.error.call_args_list assert "No valid stop for adwds. Valid stops are:" in call_args[0][ 0][0] def test_run_invalid_stop_ambiguous(self): with patch('builtins.print') as print_mock: self.nextbus.run(arguments=["5 - Brooklyn Ctr", "a", "north"]) print_mock.assert_not_called() call_args = self.nextbus.log.error.call_args_list assert "Route a was ambiguous, matches: " in call_args[0][0][0]
BATT_BITMAP.height, 0)) BATT_GROUP.append(BATT_ICON_TILEGRID) except: # If load fails, fall back on text low-batt message TEXT = Label(FONT_MEDIUM, text='LOW BATTERY', color=0) TEXT.anchor_point = (0.5, 0.5) TEXT.anchored_position = (DISPLAY.width // 2, DISPLAY.height // 2) BATT_GROUP.append(TEXT) # Populate list of NextBus objects from STOPS[] and generate initial text # labels (these get positioned in a second pass later)... STOP_LIST = [] MAX_SIZE = (0, 0) # Pixel dimensions of largest route number for stop in STOPS: STOP_LIST.append( NextBus(NETWORK, stop[0], stop[1], stop[2], None, MAX_PREDICTIONS, MINIMUM_TIME)) TEXT = Label(FONT_LARGE, text=stop[1], color=0) # Keep track of the largest route label for positioning things later MAX_SIZE = (max(TEXT.width, MAX_SIZE[0]), max(TEXT.height, MAX_SIZE[1])) TEXT.anchor_point = (1.0, 1.0) # Bottom-right align route GROUP.append(TEXT) # Because text anchoring works from bounding rectangles rather than # the font baseline, we use a kludge here of upper-casing the route # description to eliminate descenders that would throw off alignment. TEXT = Label(FONT_SMALL, text=stop[3].upper(), color=0) TEXT.anchor_point = (0.0, 1.0) # Bottom-left align description GROUP.append(TEXT) INITIAL = 'No predictions' TEXT = Label(FONT_MEDIUM, text=INITIAL, color=0,
class NextRoute(StreamWatcher): def __init__(self): super(NextRoute, self).__init__() auth = tweepy.OAuthHandler(consumer_key, consumer_secret) auth.set_access_token(access_token, access_token_secret) # Open a handle to the REST API self.api = tweepy.API(auth) self.api.retry_count = 2 self.api.retry_delay = 5 me = self.api.me() self.my_id = me.id self.my_name = me.screen_name print 'Name: %s id: %s' % (self.my_name, self.my_id) # Open a handle to the UserStreams API self.stream = tweepy.Stream(auth, self, retry_count=2) # Open a handle to NextBus API self.next_bus = NextBus() def run(self): while True: print 'Connecting to the user stream' try: self.stream.userstream() except Exception as e: print 'Exception from userstream %s' % e time.sleep(5) def process_follow(self, source, target): # If target is me, follow the source if target == self.my_id: print 'Creating friendship with: %s' % source self.api.create_friendship(source) def send_info(self, user, text, reply_to_id=None): # If the recipient is a follower send a DM, else send a tweet if self.api.exists_friendship(user, self.my_name): self.send_dm(user, text) else: self.send_tweet(user, text, reply_to_id) def send_dm(self, user, text): print 'Sending DM to user: %s text: %s' % (user, text) try: text = text[:140] # truncate the message to 140 self.api.send_direct_message(user=user, text=text) except TweepError as e: print 'Exception sending DM: %s' % e.reason def send_tweet(self, user, text, reply_to_id): print 'Sending tweet @%s %s' % (user, text) try: text = '@%s %s' % (user, text) text = text[:140] # truncate the message to 140 self.api.update_status(status=text, in_reply_to_status_id=reply_to_id) except TweepError as e: print 'Exception sending tweet: %s' % e.reason def process_dm(self, dm): text = dm.direct_message['text'] user = dm.direct_message['sender']['screen_name'] if user.upper() == 'NEXTROUTE': print 'Ignoring sent DM: %s' % text return self.process_info(text, user) def process_status(self, status): text = status.text user = status.author.screen_name coordinates = status.coordinates tweet_id = status.id if not text.upper().startswith('@NEXTROUTE'): print 'Ignoring non reply tweet: %s' % text return text = ' '.join(text.split()[1:]) self.process_info(text, user, coordinates, tweet_id) def process_info(self, text, user, coordinates=None, tweet_id=None): print "Text: %s Coord: %s from user: %s" % (text, coordinates, user) if coordinates: coords = coordinates['coordinates'] coords.reverse() resp = self.arrival_time(text, coords) else: resp = self.arrival_time(text) if not resp: resp = 'No prediction data available! for %s' % text self.send_info(user, resp, tweet_id) def arrival_time(self, text, point=None): # Parse the text words = text.split() if len(words) < 1: return "Invalid format! Please include route: %s" % text # Get the route route = string.upper(words[0]) # Check if street information is provided if len(words[1:]) > 0: cross_street = ' '.join(words[1:]) return self.next_bus.get_arrival_time_xstreet(route, cross_street) elif point: # street info can be deduced from the tweet return self.next_bus.get_arrival_time(route, point) else: return "Cannot deduce location info: %s" % text