diff --git a/.gitignore b/.gitignore index 8ad2da6..0ac5ad4 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ index.rst make.bat martapy/__pycache__/ tests/tests/__pycache__/ +*.pyc \ No newline at end of file diff --git a/README.rst b/README.rst index c36fb2d..88155d9 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,21 @@ ======= MARTApy ======= +<<<<<<< HEAD Python wrapper for MARTA realtime rail and bus APIs: http://www.itsmarta.com/app-developer-resources.aspx +======= +A Python-based library for accessing the MARTA API. + +More: http://www.itsmarta.com/app-developer-resources.aspx +>>>>>>> 90724ea658651aa7b74b2a5097b9984f194078a9 + +Quickstart ============ Installation -============ +------------ To install via *pip*, just: .. code-block:: bash @@ -20,9 +28,16 @@ Or, locally from the same directory as ``setup.py``: $ python setup.py install +<<<<<<< HEAD ==== Rail ==== +======= + +Example use +----------- + +>>>>>>> 90724ea658651aa7b74b2a5097b9984f194078a9 To get a list of train arrivals: .. code-block:: python @@ -55,6 +70,10 @@ With output that would look something like:: Filters ------- +<<<<<<< HEAD +======= + +>>>>>>> 90724ea658651aa7b74b2a5097b9984f194078a9 To narrow results, ``martapy.rail.Arrivals(list)`` has a number of properties/methods: @@ -89,6 +108,10 @@ get all arrivals for the red line which are heading southbound: rail_client = RailClient(api_key="your_api_key") arrivals = rail_client.arrivals().red_line.southbound +<<<<<<< HEAD +======= + +>>>>>>> 90724ea658651aa7b74b2a5097b9984f194078a9 Other properties ---------------- Each ``Arrivals`` instance returned is just a list of diff --git a/docs/martapy.rst b/docs/martapy.rst new file mode 100644 index 0000000..bdcf2aa --- /dev/null +++ b/docs/martapy.rst @@ -0,0 +1,19 @@ +martapy package +=============== + +martapy.rail module +-------------------- + +.. automodule:: martapy.rail + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: martapy + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 0000000..6f004c2 --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,7 @@ +martapy +======= + +.. toctree:: + :maxdepth: 4 + + martapy diff --git a/docs/readme.rst b/docs/readme.rst new file mode 100644 index 0000000..6b2b3ec --- /dev/null +++ b/docs/readme.rst @@ -0,0 +1 @@ +.. include:: ../README.rst \ No newline at end of file diff --git a/martapy/rail.py b/martapy/rail.py index ac83ad0..12f1a9b 100644 --- a/martapy/rail.py +++ b/martapy/rail.py @@ -1,11 +1,17 @@ +""" +API client library for the MARTA Rail Realtime RESTful API + +More info: http://www.itsmarta.com/app-developer-resources.aspx + +""" + import json import requests from datetime import datetime from warnings import warn from collections import OrderedDict, defaultdict -URL = ("http://developer.itsmarta.com/RealtimeTrain/RestServiceNextTrain" - "/GetRealtimeArrivals?apikey={api_key}") + station_list = [ 'AIRPORT STATION', 'ARTS CENTER STATION', @@ -51,58 +57,70 @@ class RailClient: """Client for the MARTA rail API to retrieve pending arrivals. - API returns an arrival in a dict like: - { - 'DESTINATION': 'North Springs', - 'DIRECTION': 'N', - 'EVENT_TIME': '12/31/2017 4:09:10 PM', - 'LINE': 'BLUE', - 'NEXT_ARR': '04:12:10 PM', - 'STATION': 'NORTH SPRINGS STATION', - 'TRAIN_ID': '104026', - 'WAITING_SECONDS': '-45', - 'WAITING_TIME': 'Boarding' - } + The API returns an 'arrival' in a dict like: + + .. code-block:: json + + { + "DESTINATION": "North Springs", + "DIRECTION": "N", + "EVENT_TIME": "12/31/2017 4:09:10 PM", + "LINE": "BLUE", + "NEXT_ARR": "04:12:10 PM", + "STATION": "NORTH SPRINGS STATION", + "TRAIN_ID": "104026", + "WAITING_SECONDS": "-45", + "WAITING_TIME": "Boarding" + } + """ + base_url = "http://developer.itsmarta.com/RealtimeTrain" \ + "/RestServiceNextTrain/GetRealtimeArrivals?apikey={api_key}" + def __init__(self, api_key): """Initialize client - :param api_key: Your MARTA API key + :param api_key: MARTA API key :type api_key: str """ - self.url = URL.format(api_key=api_key) + self.api_key = api_key self._trains = None def arrivals(self): - """Retrieves current train arrivals. + """Retrieves and returns current arrivals as ``Arrivals(list)`` :return: A list of current train arrivals (events) - :rtype: ``martapy.rail.Arrivals`` + :rtype: ``martapy.rail.Arrivals(list)`` """ arrivals = requests.get(self.url).json() # Copy each dict to a new one with lowercase keys to pass to Arrival() return Arrivals(arrivals) + @property + def url(self): + """``RailClient.base_url`` formatted with API key""" + return self.base_url.format(self.api_key) + class Arrivals(list): + """A list of ``Arrival`` objects returned from the API""" def __init__(self, arrivals): """ - - :param arrivals: List of arrivals retrieved from - :type arrivals: + :param arrivals: List of ``Arrival`` objects + :type arrivals: ``martapy.rail.Arrival`` """ self._arrivals = None self.arrivals = arrivals super().__init__(self._arrivals) - # All arrivals - @property def arrivals(self): + """All ``Arrival`` objects""" return self._arrivals @arrivals.setter def arrivals(self, arrivals): + # Transforms JSON objects to a list of ``Arrival`` objects arrival_list = [] for arrival in arrivals: a = Arrival(**dict((k.lower(), v) for (k, v) in arrival.items())) @@ -116,56 +134,70 @@ def arrivals(self, arrivals): @property def blue_line(self): + """Arrivals for the blue line""" return self._filter('line', 'BLUE') @property def gold_line(self): + """Arrivals for the gold line""" return self._filter('line', 'GOLD') @property def green_line(self): + """Arrivals for the green line""" return self._filter('line', 'GREEN') @property def red_line(self): + """Arrivals for the red line""" return self._filter('line', 'RED') # Directional filters @property def northbound(self): + """Northbound arrivals""" return self._filter('direction', 'N') @property def eastbound(self): + """Eastbound arrivals""" return self._filter('direction', 'E') @property def westbound(self): + """Westbound arrivals""" return self._filter('direction', 'W') @property def southbound(self): + """Southbound arrivals""" return self._filter('direction', 'S') - # Waiting time filters - @property def boarding(self): + """Arrivals that are currently boarding""" return self._filter('waiting_time', 'Boarding') @property def arriving(self): + """Arrivals that are... arriving""" return self._filter('waiting_time', 'Arriving') @property def arrived(self): + """Arrivals that have arrived""" return self._filter('waiting_time', 'Arrived') # Misc filters @property def trains(self): + """Arrivals grouped by train ID + + :return: *OrderedDict*, train IDs as keys and each train's + associated arrivals as lists + """ trains = defaultdict(list) for a in self._arrivals: trains[a.train_id].append(a) @@ -176,6 +208,11 @@ def trains(self): @property def stations(self): + """Arrivals grouped by station name + + :return: *OrderedDict* with station names as keys and associated + arrivals as values + """ station_arrivals = defaultdict(list) for a in self._arrivals: station_arrivals[a.station].append(a) @@ -236,7 +273,7 @@ def _filter(self, attribute_name, value): class Arrival: def __init__(self, station, line, destination, direction, next_arr, waiting_time, waiting_seconds, event_time, train_id): - """Arrival event. + """Arrival event :param station: Station name (uppercase) :param line: Line (BLUE, GREEN, RED, GOLD) @@ -254,19 +291,29 @@ def __init__(self, station, line, destination, direction, next_arr, self._json = None self._next_arr = None - self.destination = destination self.direction = direction self.event_time = event_time - self.line = line + self.train_id = train_id self.next_arr = next_arr + + #: Destination (station name sans '*STATION*') + self.destination = destination + + #: *RED*, *GREEN*, *BLUE*, or *GOLD* line + self.line = line + + #: Station name (current list: ``martapy.rail.station_list``) self.station = station.upper() - self.train_id = train_id + + #: Positive or negative integer (ex '*-45*' seconds) self.waiting_seconds = waiting_seconds + + #: *Arriving*, *Arrived*, *Boarding*, *1 min*, *2 min*... self.waiting_time = waiting_time @property def direction(self): - """"Direction of travel as N, E, W or S""" + """Direction of travel as one of: *N, E, W, S*""" return self._direction @direction.setter @@ -292,13 +339,13 @@ def event_time(self): @event_time.setter def event_time(self, event_time): - """Set the event time as MM/DD/YYYY HH:MM:SS AM/PM""" + """Set the event time as *MM/DD/YYYY HH:MM:SS AM/PM*""" self._event_time = datetime.strptime(event_time, "%m/%d/%Y %I:%M:%S %p") @property def next_arr(self): - """Time of the train's next arrival as HH:MM:SS AM/PM""" + """Time of the train's next arrival as *HH:MM:SS AM/PM*""" return self._next_arr @property