Browse Source

Revamped search functionality to use per word edit distance. Added

custom exceptions
atexit v2.2
Raphael Roberts 7 years ago
parent
commit
bedee68d9d
  1. 1
      .gitignore
  2. 10
      ctabus/fetch.py
  3. 14
      ctabus/internal/exceptions.py
  4. 34
      ctabus/internal/search.py
  5. 2
      setup.py

1
.gitignore

@ -10,3 +10,4 @@ __pycache__
stderr.log
sensitive.py
*.egg-info
/ctabus_venv/*

10
ctabus/fetch.py

@ -2,6 +2,7 @@ import json
from urllib.parse import urlencode
from urllib.request import urlopen
from ctabus.internal.exceptions import CTABusError, NoArrivalTimesError
from ctabus.internal.config import API_KEY as api
from ctabus.internal.disk_cache import disk_cache
@ -18,13 +19,18 @@ def get_data(type, api_key=api, timeout=None, **args):
data = json.load(response)["bustime-response"]
try:
data["error"]
raise Exception(str(data["error"]))
raise CTABusError(data)
except KeyError:
return data
def get_times(stop_id, api_key=api, timeout=None):
return get_data("getpredictions", api_key, stpid=stop_id, timeout=timeout)
try:
result = get_data("getpredictions", api_key, stpid=stop_id, timeout=timeout)
return result
except CTABusError as e:
if e.data["error"]["msg"] == "No arrival times":
raise NoArrivalTimesError(e.data)
@disk_cache

14
ctabus/internal/exceptions.py

@ -0,0 +1,14 @@
class CTABusError(Exception):
"""Base error for ctabus module"""
def __init__(self, data):
self.data = data
class NoArrivalTimesError(CTABusError):
"""Error raised for when there are no bus times available"""
def __init__(self, data):
self.message = "No arrival times available for stop id {}".format[
data["error"]["stpid"]
]

34
ctabus/internal/search.py

@ -3,6 +3,8 @@ import re
import edlib
words_re = re.compile(r"[a-zA-Z0-9]+")
def editdistance(a, b):
return edlib.align(a, b)["editDistance"]
@ -26,21 +28,27 @@ class Search:
class StopSearch(Search):
def __init__(self, query):
super().__init__(query)
query = query.lower()
parts = re.split(r" ?(?:(?<!\w)and(?!\w)|&) ?", query)
self.query = " & ".join(parts)
self.query_reversed = " & ".join(reversed(parts))
no_ampersand = self.raw_lower.replace("&", "and")
self.parts = words_re.findall(no_ampersand)
def __call__(self, stop):
stop = stop.lower()
paren = re.search(r"\((?P<data>[^\)]+)\)", stop)
ret = [editdistance(self.query, stop), editdistance(self.query_reversed, stop)]
if paren:
paren = paren.group("data")
ret.append(editdistance(self.query, paren))
if self.raw_lower in stop:
ret = (item - 100 for item in ret)
return min(ret)
raw_lower = stop.lower()
no_ampersand = raw_lower.replace("&", "and")
parts = words_re.findall(no_ampersand)
replaceable_parts = self.parts.copy()
total_distance = 0
while len(parts) > 0 and len(replaceable_parts) > 0:
part = parts.pop()
lowest = max(map(len, replaceable_parts))
index = 0
for i in range(len(replaceable_parts)):
distance = editdistance(replaceable_parts[i], part)
if distance < lowest:
index = i
lowest = distance
total_distance += lowest
del replaceable_parts[index]
return total_distance
def __str__(self):
return "{}|{}".format(self.query, self.query_reversed)

2
setup.py

@ -5,7 +5,7 @@ with open("requirements.txt") as file:
setup(
name="ctabus",
version="2.1.3",
version="2.2",
description="Python package for tracking cta bus times",
install_requires=INSTALL_REQUIRES,
author="rlbr",

Loading…
Cancel
Save