Browse Source

Merge branch 'master' of marty.website:olivier/projet_wdm_m2

Shendan JIN 8 years ago
parent
commit
77a1d0a22a
3 changed files with 138 additions and 49 deletions
  1. 28 0
      geocoding.py
  2. 1 1
      notification.py
  3. 109 48
      source.py

+ 28 - 0
geocoding.py

@@ -0,0 +1,28 @@
+from geopy.geocoders import Nominatim
+from geopy.distance import vincenty
+
+
+geolocator = Nominatim()
+
+
+def position_of_location(location):
+    """returns a pair (latitude, longitude) from an adress
+    or None if not possible"""
+    try:
+      pos = geolocator.geocode(location)
+      return (pos.latitude, pos.longitude)
+    except:
+      return None
+
+def dist(posa, posb):
+    """compute the distance between two position (pair latitude, longitude)
+    in kilometers
+    or None if one of the argument is None"""
+    if not posa or not posb:
+        return None
+    else:
+        return vincenty(posa, posb).km
+
+p1 = position_of_location("22 rue Henri Barbusse VILLEJUIF")
+p2 = position_of_location("Université paris diderot")
+print(p1, p2, dist(p1, p2))

+ 1 - 1
notification.py

@@ -18,6 +18,6 @@ def notify(message):
      elif method == 'sendmail':
         run(['mail', '-s', conf['sendmail']['object'], conf['sendmail']['to']], input=message.encode(), check=True)
      elif method == 'print':
-        print(message)
+        print("[NOTIFICATION] " + message)
      else:
         raise NotImplementedError('notification method = ' + method + ' not known !')

+ 109 - 48
source.py

@@ -8,6 +8,18 @@ from itertools import chain
 class Source:
   pass
 
+class SourceProvider:
+  def dic_of_name(self):
+    """Returns a dictionnary mapping ids to name (for find.py)"""
+    return []
+
+  def dic_of_positions(self):
+    """Returns a disctionnary mapping ids to position (for geocoding.py)"""
+    return []
+
+  def sources_of_ids(self, ids):
+    """Returns a generator of Source these ids"""
+    return []
 
 class Source_ratp(Source):
   def __init__(self, ident, status, message):
@@ -19,6 +31,31 @@ class Source_ratp(Source):
   def problem(self):
     return self.status != 'normal'
 
+class SourceProvider_ratp(SourceProvider):
+  def __init__(self):
+    self.names = None
+    self.positions = None
+
+  def get_names(self):
+    if not self.names:
+      print('Téléchargement de la liste des lignes ratp...')
+      xml = XML(url='http://www.ratp.fr/meteo/', lang='html')
+      self.names = {tag['id']: tag['id'].replace('_', ' ') for tag in xml.data.select('.encadre_ligne')}
+    return self.names
+
+  def dic_of_name(self):
+    return get_names()
+
+  def dic_of_positions(self):
+    return {} # TODO API ratp
+
+  def sources_of_ids(self, ids):
+    for tag in XML(url="http://www.ratp.fr/meteo/", lang="html").data.select('div.encadre_ligne'):
+      if tag['id'] in ids:
+        yield Source_ratp(tag['id'], tag.img['alt'],\
+          tag['id'].replace('_', ' ') + ' : ' + tag.select('span.perturb_message')[0].string)
+
+
 class Source_jcdecaux_vls(Source):
   def __init__(self, ident, nom, timestamp, status):
     self.source = 'jcdecaux_vls'
@@ -69,51 +106,71 @@ class Source_jcdecaux_vls_empty(Source_jcdecaux_vls):
     return super(Source_jcdecaux_vls_empty, self).problem() or self.bikes <= config.sources_params['jcdecaux_vls']['limit_empty']
 
 
-class Source_transilien(Source):
-  def __init__(self, ident, message):
-    self.source = 'transilien'
-    self.id = ident
-    self.message = message
-
-  def problem(self):
-    return self.message != 'Trafic normal'
-
-
-# SOURCES GENERATORS
-
-def ratp_trafic():
-  for tag in XML(url="http://www.ratp.fr/meteo/", lang="html").data.select('div.encadre_ligne'):
-    yield Source_ratp(tag['id'], tag.img['alt'],\
-      tag['id'].replace('_', ' ') + ' : ' + tag.select('span.perturb_message')[0].string)
-
-
-def jcdecaux_vls(ids):
-  ids = set(map(lambda s : s.rsplit('_', 1)[0], ids))
-  for station in ids:
-    (contract, number) = list(station.split('_'))
-    xml = XML(url="https://api.jcdecaux.com/vls/v1/stations/" + number + "?contract=" + contract + "&apiKey="+config.api_key['jcdecaux_vls'], lang="json")
-    tag = xml.data.json
-    yield Source_jcdecaux_vls_full(contract + '_' + number, tag.find('name').string, tag.last_update.string, tag.available_bike_stands.string, tag.status.string)
-    yield Source_jcdecaux_vls_empty(contract + '_' + number, tag.find('name').string, tag.last_update.string, tag.available_bikes.string, tag.status.string)
-
-
-def transilien():
-  xml = XML(url="http://www.transilien.com/info-trafic/temps-reel", lang="html").data
-  container = xml.select('div.b_info_trafic')[0]
-  for line in container.find_all('div', recursive=False):
-    id = line.select('.picto-transport')[1].get_text()
-    message = ""
-    for c in line.select_one('.title').children:
-      if c.name: # a tag
-        if 'picto-transport' not in c.attrs.get('class', ''):
-          message += c.get_text()
-      else: # a string
-        message += c
-    for det in line.select('.item-disruption'):
-      message += det.get_text()
-    message = " ".join(message.split()) # delete multiple spaces
-    yield Source_transilien(id, message)
-
+class SourceProvider_jcdecaux_vls(SourceProvider):
+  def __init__(self):
+    pass
+
+  def dic_of_name(self):
+    return {} # TODO
+
+  def dic_of_positions(self):
+    return {} # TODO
+
+  def sources_of_ids(self, ids):
+    ids_set = set(map(lambda s : s.rsplit('_', 1)[0], ids))
+    for station in ids_set:
+      (contract, number) = list(station.split('_'))
+      xml = XML(url="https://api.jcdecaux.com/vls/v1/stations/" + number + "?contract=" + contract + "&apiKey="+config.api_key['jcdecaux_vls'], lang="json")
+      tag = xml.data.json
+      if contract + '_' + number + '_full' in ids:
+        yield Source_jcdecaux_vls_full(contract + '_' + number, tag.find('name').string, tag.last_update.string, tag.available_bike_stands.string, tag.status.string)
+      if contract + '_' + number + '_empty' in ids:
+        yield Source_jcdecaux_vls_empty(contract + '_' + number, tag.find('name').string, tag.last_update.string, tag.available_bikes.string, tag.status.string)
+
+class SourceProvider_transilien(SourceProvider):
+  class Source_transilien(Source):
+    def __init__(self, ident, message):
+      self.source = 'transilien'
+      self.id = ident
+      self.message = message
+
+    def problem(self):
+      return self.message != 'Trafic normal'
+
+  def __init__(self):
+    self.names = None
+    self.positions = None
+
+  def get_names(self):
+    if not self.names:
+      print('Téléchargement de la liste des lignes ratp...')
+      xml = XML(url='http://www.ratp.fr/meteo/', lang='html')
+      self.names = {tag['id']: tag['id'].replace('_', ' ') for tag in xml.data.select('.encadre_ligne')}
+    return self.names
+
+  def dic_of_name(self):
+    return get_names()
+
+  def dic_of_positions(self):
+    return {} # TODO API ratp
+
+  def sources_of_ids(self, ids):
+    xml = XML(url="http://www.transilien.com/info-trafic/temps-reel", lang="html").data
+    container = xml.select('div.b_info_trafic')[0]
+    for line in container.find_all('div', recursive=False):
+      id = line.select('.picto-transport')[1].get_text()
+      if id in ids:
+        message = ""
+        for c in line.select_one('.title').children:
+          if c.name: # a tag
+            if 'picto-transport' not in c.attrs.get('class', ''):
+              message += c.get_text()
+          else: # a string
+            message += c
+        for det in line.select('.item-disruption'):
+          message += det.get_text()
+        message = " ".join(message.split()) # delete multiple spaces
+        yield self.Source_transilien(id, message)
 
 
 # interface functions
@@ -123,7 +180,11 @@ def from_location(location):
     TODO : for the moment returns the whole config.sources"""
     return config.sources
 
+sp_ratp = SourceProvider_ratp()
+sp_jcdecaux_vls = SourceProvider_jcdecaux_vls()
+sp_transilien = SourceProvider_transilien()
+
 def gen_sources(ids):
-  return chain(ratp_trafic(),\
-      transilien(),\
-      jcdecaux_vls(ids.get('jcdecaux_vls', [])))
+  return chain(sp_ratp.sources_of_ids(ids.get('ratp_trafic', [])),\
+      sp_transilien.sources_of_ids(ids.get('transilien', [])),\
+      sp_jcdecaux_vls.sources_of_ids(ids.get('jcdecaux_vls', [])))