kopia lustrzana https://github.com/n1ywb/python-hamtools
Refactor georeferencing to make it more modular
rodzic
15fa9ecfd3
commit
d22e31a26e
|
@ -29,8 +29,8 @@ import re
|
||||||
import pdb
|
import pdb
|
||||||
|
|
||||||
|
|
||||||
class InvalidDxcc(Exception):
|
class InvalidDxcc(Exception): pass
|
||||||
pass
|
class InvalidCallsign(Exception): pass
|
||||||
|
|
||||||
|
|
||||||
class CtyDat(object):
|
class CtyDat(object):
|
||||||
|
@ -70,7 +70,7 @@ class CtyDat(object):
|
||||||
a = None
|
a = None
|
||||||
|
|
||||||
if b.isdigit():
|
if b.isdigit():
|
||||||
raise Exception("invalid callsign %s" % call)
|
raise InvalidCallsign(call)
|
||||||
|
|
||||||
if a is None and c is None:
|
if a is None and c is None:
|
||||||
if re.search('\d', b) is not None:
|
if re.search('\d', b) is not None:
|
||||||
|
|
|
@ -28,7 +28,7 @@ from pkg_resources import resource_stream
|
||||||
import geojson as gj
|
import geojson as gj
|
||||||
|
|
||||||
import adif
|
import adif
|
||||||
from ctydat import CtyDat, InvalidDxcc
|
from ctydat import CtyDat, InvalidDxcc, InvalidCallsign
|
||||||
import kml
|
import kml
|
||||||
import qrz
|
import qrz
|
||||||
|
|
||||||
|
@ -46,7 +46,51 @@ CABRILLO_FIELDS = ['header', 'freq', 'mode', 'date', 'time',
|
||||||
|
|
||||||
CACHEPATH = os.path.join(os.environ['HOME'], '.qrz_cache')
|
CACHEPATH = os.path.join(os.environ['HOME'], '.qrz_cache')
|
||||||
|
|
||||||
class NullLoc(Exception): pass
|
|
||||||
|
class OperatorGeoRefFail(Exception): pass
|
||||||
|
|
||||||
|
class GeoRefFail(Exception): pass
|
||||||
|
|
||||||
|
class GeoRefError(Exception): pass
|
||||||
|
class NullLoc(GeoRefError): pass
|
||||||
|
class NotFound(GeoRefError): pass
|
||||||
|
|
||||||
|
|
||||||
|
class QrzReferencer(object):
|
||||||
|
def __init__(self, session):
|
||||||
|
self.session = session
|
||||||
|
|
||||||
|
def reference(self, callsign):
|
||||||
|
"""Returns lon, lat from QRZ"""
|
||||||
|
try:
|
||||||
|
rec = self.session.qrz(callsign)
|
||||||
|
if None in (rec['lat'], rec['lon']):
|
||||||
|
raise NullLoc(callsign)
|
||||||
|
lat, lon = rec['lat'], rec['lon']
|
||||||
|
log.debug("qrz rec %s" % rec)
|
||||||
|
except qrz.NotFound, e:
|
||||||
|
raise NotFound(callsign)
|
||||||
|
except qrz.CallMismatch, e:
|
||||||
|
raise GeoRefError(*e.args)
|
||||||
|
return lon, lat
|
||||||
|
|
||||||
|
|
||||||
|
class CtyDatReferencer(object):
|
||||||
|
def __init__(self, ctydat):
|
||||||
|
self.ctydat = ctydat
|
||||||
|
|
||||||
|
def reference(self, callsign):
|
||||||
|
"""Returns lon, lat from ctydat"""
|
||||||
|
try:
|
||||||
|
dxcc = self.ctydat.getdxcc(callsign)
|
||||||
|
except (InvalidDxcc, InvalidCallsign):
|
||||||
|
raise GeoRefError()
|
||||||
|
lat = float(dxcc['lat'])
|
||||||
|
lon = float(dxcc['lon']) * -1
|
||||||
|
return lon, lat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Log(object):
|
class Log(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -86,47 +130,33 @@ class Log(object):
|
||||||
self.callsign = qso['operator']
|
self.callsign = qso['operator']
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def _georef(self, callsign):
|
||||||
|
for d in self.drivers:
|
||||||
|
try:
|
||||||
|
return d.reference(callsign)
|
||||||
|
except GeoRefError, e:
|
||||||
|
log.warning("%r failed" % d, exc_info=True)
|
||||||
|
else:
|
||||||
|
raise GeoRefFail(callsign)
|
||||||
|
|
||||||
def georeference(self, sess, ctydat):
|
def georeference(self, sess, ctydat):
|
||||||
|
drivers = self.drivers = []
|
||||||
|
sess and drivers.append(QrzReferencer(sess))
|
||||||
|
ctydat and drivers.append(CtyDatReferencer(ctydat))
|
||||||
|
|
||||||
|
if not drivers:
|
||||||
|
raise Exception("No georef drivers")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rec = sess.qrz(self.callsign)
|
self.lon, self.lat = self._georef(self.callsign)
|
||||||
if None in (rec['lat'], rec['lon']):
|
except GeoRefFail:
|
||||||
raise NullLoc()
|
raise OperatorGeoRefFail("Failed to georeference operator callsign", self.callsign)
|
||||||
self.lat, self.lon = rec['lat'], rec['lon']
|
|
||||||
log.debug("qrz rec %s" % rec)
|
|
||||||
except NullLoc:
|
|
||||||
log.warning("QRZ lookup failed for %s, no location data" % self.callsign)
|
|
||||||
raise
|
|
||||||
except qrz.NotFound, e:
|
|
||||||
log.warning("QRZ lookup failed for %s, not found" % self.callsign)
|
|
||||||
raise
|
|
||||||
except Exception, e:
|
|
||||||
log.warning("QRZ lookup failed for %s" % self.callsign, exc_info=True)
|
|
||||||
raise
|
|
||||||
|
|
||||||
for qso in self.qsos:
|
for qso in self.qsos:
|
||||||
qso['lat'], qso['lon'] = None, None
|
|
||||||
try:
|
try:
|
||||||
rec = sess.qrz(qso['call'])
|
qso['lon'], qso['lat'] = self._georef(qso['call'])
|
||||||
log.debug("qrz rec %s" % rec)
|
except GeoRefFail:
|
||||||
if rec['call'] != qso['call']:
|
log.warning("Failed to georef call", qso['call'])
|
||||||
log.warning("qrz %s != %s" % (rec['call'],
|
|
||||||
qso['call']))
|
|
||||||
if None in (rec['lat'], rec['lon']):
|
|
||||||
raise NullLoc()
|
|
||||||
qso['lat'], qso['lon'] = rec['lat'], rec['lon']
|
|
||||||
except Exception, e:
|
|
||||||
if isinstance(e, qrz.NotFound):
|
|
||||||
log.warning("QRZ lookup failed for %s, not found" % qso['call'])
|
|
||||||
elif isinstance(e, NullLoc):
|
|
||||||
log.warning("QRZ lookup failed for %s, no location data" % qso['call'])
|
|
||||||
else:
|
|
||||||
log.warning("QRZ lookup failed for %s" % qso['call'], exc_info=True)
|
|
||||||
try:
|
|
||||||
dxcc = ctydat.getdxcc(qso['call'])
|
|
||||||
qso['lat'] = float(dxcc['lat'])
|
|
||||||
qso['lon'] = float(dxcc['lon']) * -1
|
|
||||||
except Exception:
|
|
||||||
log.warning("cty.dat lookup failed for %s" % qso['call'], exc_info=True)
|
|
||||||
|
|
||||||
def geojson_dumps(self, *args, **kwargs):
|
def geojson_dumps(self, *args, **kwargs):
|
||||||
pointsFC, linesFC = self.geojson()
|
pointsFC, linesFC = self.geojson()
|
||||||
|
@ -142,7 +172,7 @@ class Log(object):
|
||||||
lines = []
|
lines = []
|
||||||
for qso in self.qsos:
|
for qso in self.qsos:
|
||||||
point, line = None, None
|
point, line = None, None
|
||||||
coords = qso['lon'], qso['lat']
|
coords = qso.get('lon', None), qso.get('lat', None)
|
||||||
if None not in coords:
|
if None not in coords:
|
||||||
point = gj.Point(coords)
|
point = gj.Point(coords)
|
||||||
line = gj.LineString([
|
line = gj.LineString([
|
||||||
|
|
|
@ -40,6 +40,9 @@ testSessionXML = """\
|
||||||
class NotFound(Exception):
|
class NotFound(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class CallMismatch(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class Callsign(object):
|
class Callsign(object):
|
||||||
conversions = dict(
|
conversions = dict(
|
||||||
lat=float,
|
lat=float,
|
||||||
|
@ -141,7 +144,7 @@ class Session(object):
|
||||||
callnode = dom.getElementsByTagName("Callsign")[0]
|
callnode = dom.getElementsByTagName("Callsign")[0]
|
||||||
data = Callsign(callnode)
|
data = Callsign(callnode)
|
||||||
if data['call'].lower() != callsign.lower():
|
if data['call'].lower() != callsign.lower():
|
||||||
raise Exception("qrz callsign mismatch")
|
raise CallMismatch("Calls do not match", data['call'], callsign)
|
||||||
return data
|
return data
|
||||||
except Exception:
|
except Exception:
|
||||||
log.debug(xml)
|
log.debug(xml)
|
||||||
|
|
Ładowanie…
Reference in New Issue