Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ Depends on requests and lxml
Route(1-California)
```

### predictions
```python
>>> predictions = nextbus.predictions(agency='sf-muni', route='1', stop_id='13896')
>>> predictions[0]
Vehicle in 2 minutes
```



Expand Down
26 changes: 26 additions & 0 deletions example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import nextbus

# get a list of agencies
agencies = nextbus.agency_list()

# grab the SF Muni agency object
sfmuni = [a for a in agencies if a.title=='San Francisco Muni'][0]

# get a list of route objects on the SF Muni
routes = nextbus.route_list(agency=sfmuni.tag)

# grab a specific route object, in this case "1-California"
r = [r for r in routes if r.title=='1-California'][0]

# get more info on that route
route = nextbus.route_config(agency=sfmuni.tag, route=r.tag)

# grab a stop on that route
stop = [s for s in route.stops if s.title=='California St & Spruce St'][0]

# get the prediction objects for that route and stop
predictions = nextbus.predictions(agency=sfmuni.tag, route=route.tag, stop_id=stop.stop_id)
print 'Vehicles arrive in ' + ', '.join([p.minutes for p in predictions]) + ' minutes'



2 changes: 1 addition & 1 deletion nextbus/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .api import agency_list, route_list, route_config
from .api import agency_list, route_list, route_config, predictions

__title__ = 'python-nextbus'
__version__ = '0.1b'
Expand Down
2 changes: 1 addition & 1 deletion nextbus/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def route_config(agency=None, route=None, **kwargs):

def predictions(agency=None, route=None, stop_id=None, **kwargs):
"""prediction"""
result = __api_call('predictions', agency=agency, route=route, stop_id=stop_id, **kwargs) or []
result = __api_call('predictions', agency=agency, route=route, stopId=stop_id, **kwargs) or []
return result

def set_defaults(defaults):
Expand Down
45 changes: 45 additions & 0 deletions nextbus/model.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from lxml import etree


class UnknownCommandError(Exception):
pass


def parse_command(command, xml):
"""parses the xml document based on the command used. returns the object structure
associated with that xml"""
Expand All @@ -10,6 +15,10 @@ def parse_command(command, xml):
result = __parse_routeList(xml)
elif command == 'routeConfig':
result = __parse_routeConfig(xml)
elif command == 'predictions':
result = __parse_predictions(xml)
else:
raise UnknownCommandError("Command {0} is not recognized or not implemented".format(command))

return result

Expand Down Expand Up @@ -44,6 +53,16 @@ def __parse_routeConfig(xml):

return result

def __parse_predictions(xml):
"""takes in nextbus xml element and returns a list of prediction objects"""

#get the list of predictions
predictions = xml.xpath('//prediction')

predictions = [Prediction.from_element(p) for p in predictions]

return predictions

class Model(object):

@classmethod
Expand Down Expand Up @@ -210,3 +229,29 @@ def hydrate(self, element):
self.lat = element.get('lat')
self.lon = element.get('lon')
self.stop_id = element.get('stopId')

class Prediction(Model):
"""class for predictions"""
def __init__(self):
self.epochTime = None
self.seconds = None
self.minutes = None
self.isDeparture = None
self.dirTag = None
self.vehicle = None
self.block = None
self.tripTag = None

def __repr__(self):
return 'Vehicle in %s minutes' % self.minutes

def hydrate(self, element):
self.epochTime = element.get('epochTime')
self.seconds = element.get('seconds')
self.minutes = element.get('minutes')
self.isDeparture = element.get('isDeparture')
self.dirTag = element.get('dirTag')
self.vehicle = element.get('vehicle')
self.block = element.get('block')
self.tripTag = element.get('tripTag')

37 changes: 25 additions & 12 deletions nextbus/test_nextbus.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,32 @@

import unittest

def test_agencyList():
#agency list should always return a list of agencies
agencies = nextbus.agency_list()
assert len(agencies) > 0 and type(agencies[0]) == Agency
class AgencyListTest(unittest.TestCase):
def test_agencyList(self):
#agency list should always return a list of agencies
agencies = nextbus.agency_list()
self.assertTrue(len(agencies) > 0, "Agencies list should not be empty")
self.assertTrue(isinstance(agencies[0], Agency), "agency_list not returning a list of Agencies")
# if willing to break 2.6, can use assertIsInstance instead

def test_routeList():
#route list should always return a list of routes filtered by agency.
routes = nextbus.route_list(agency='sf-muni')
assert len(routes) > 0 and type(routes[0]) == Route and routes[0].title == 'F-Market & Wharves'
def test_routeList(self):
#route list should always return a list of routes filtered by agency.
routes = nextbus.route_list(agency='sf-muni')
self.assertTrue(len(routes) > 0,
"Routes list should not be empty")
self.assertTrue(isinstance(routes[0], Route),
"route_list not returning a list of Routes")
self.assertTrue("F-Market & Wharves" in [route.title for route in routes],
"A route is missing from the route list")
self.assertFalse("Sandwich" in [route.title for route in routes],
"route_list is including multiple agencies")

def test_routeConfig():
#route config should return a route object by the given route tag
route = nextbus.route_config(agency='sf-muni', route='1')
assert route and type(route) == Route and route.title == '1-California'
def test_routeConfig(self):
#route config should return a route object by the given route tag
route = nextbus.route_config(agency='sf-muni', route='1')
self.assertTrue(route, "Route is empty")
self.assertTrue(isinstance(route, Route), "route_config is not returning a Route")
self.assertEqual(route.title, "1-California",
"Route title is not right (expected '{0}', got '{1}'".format("1-California", route.title))


4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
requests==2.0.1
lxml==3.2.4
requests>=2.0.1
lxml>=3.2.4
14 changes: 6 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import os
import sys

import nextbus

try:
from setuptools import setup
except ImportError:
Expand All @@ -18,19 +16,19 @@
'nextbus',
]

requires = []
requires = ['requests>=2.0.1', 'lxml>=3.2.4']

readme =''
history =''

setup(
name='python-nextbus',
version=nextbus.__version__,
version='0.1b',
description='python client for nextbus api',
long_description=readme + '\n\n' + history,
author='Sam Bolgert',
author_email='sbolgert@gmail.com',
url='http://python.org',
url='https://github.com/linuxlewis/python-nextbus',
packages=packages,
package_data={'': ['LICENSE', 'NOTICE']},
package_dir={'nextbus': 'nextbus'},
Expand All @@ -39,14 +37,14 @@
license=license,
zip_safe=False,
classifiers=(
'Development Status :: 3 - Alpha',
'Development Status :: 6 - Mature',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',

'Programming Language :: Python :: 3.5'
),
)
)