Example #1
0
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
Example #2
0
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
Example #3
0
  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
Example #4
0
  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()
Example #5
0
    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
Example #6
0
  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
Example #7
0
 def setUp(self):
     self.nextbus = NextBus()
     self.nextbus.get = MagicMock(side_effect=Exception(
         "There should be no get calls in these tests!"))
Example #8
0
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')
Example #9
0
 def setUp(self):
     self.nextbus = NextBus()
Example #10
0
 def setUp(self):
     self.nextbus = NextBus()
     self.nextbus.log.error = MagicMock()
Example #11
0
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,
Example #13
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