Skip to content

Commit

Permalink
Merge branch 'master' of github.com:arcward/martapy
Browse files Browse the repository at this point in the history
  • Loading branch information
arcward committed Apr 18, 2017
2 parents bc33d48 + 90724ea commit 6e7c053
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 33 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ index.rst
make.bat
martapy/__pycache__/
tests/tests/__pycache__/
*.pyc
25 changes: 24 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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
Expand Down
19 changes: 19 additions & 0 deletions docs/martapy.rst
Original file line number Diff line number Diff line change
@@ -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:
7 changes: 7 additions & 0 deletions docs/modules.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
martapy
=======

.. toctree::
:maxdepth: 4

martapy
1 change: 1 addition & 0 deletions docs/readme.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. include:: ../README.rst
111 changes: 79 additions & 32 deletions martapy/rail.py
Original file line number Diff line number Diff line change
@@ -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',
Expand Down Expand Up @@ -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()))
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 6e7c053

Please sign in to comment.