Commits

Richo Healey committed 6897227

Have doko use strategies in order, configurably

This also should complete the changes needed to make it do reasonable
things on windows and linux

  • Participants
  • Parent commits cb1bf7e

Comments (0)

Files changed (1)

File doko/__init__.py

 
 import sys
 import optparse
+from optparse import OptionValueError
 import time
 from collections import namedtuple
+from collections import OrderedDict
 import webbrowser
 
 try:
 DEFAULT_TIMEOUT = 3
 DEFAULT_RETRIES = 10
 
+LOCATION_STRATEGIES = OrderedDict()
+
+# Important, define strategies in default resolution order
+def location_strategy(name):
+    def _(fn):
+        LOCATION_STRATEGIES[name] = fn
+    return _
 
 class LocationServiceException(Exception):
     pass
 
 
-def location(timeout=DEFAULT_TIMEOUT):
-    """
-    Fetch and return a Location from OS X Core Location, or throw
-    a LocationServiceException trying.
-    """
-    if not CoreLocation:
-        raise LocationServiceException('CoreLocation not available')
-
-    m = CoreLocation.CLLocationManager.new()
-
-    if not m.locationServicesEnabled():
-        raise LocationServiceException(
-                'location services not enabled -- check privacy settings in System Preferences'  # noqa
-            )
+if CoreLocation:
+    @location_strategy("corelocation")
+    def corelocation_location(timeout=DEFAULT_TIMEOUT):
+        """
+        Fetch and return a Location from OS X Core Location, or throw
+        a LocationServiceException trying.
+        """
 
-    if not m.locationServicesAvailable():
-        raise LocationServiceException('location services not available')
+        m = CoreLocation.CLLocationManager.new()
 
-    m.startUpdatingLocation()
-    CoreLocation.CFRunLoopStop(CoreLocation.CFRunLoopGetCurrent())
-    l = m.location()
+        if not m.locationServicesEnabled():
+            raise LocationServiceException(
+                    'location services not enabled -- check privacy settings in System Preferences'  # noqa
+                )
 
-    # retry up to ten times, possibly sleeping between tries
-    for i in xrange(DEFAULT_RETRIES):
-        if l:
-            break
+        if not m.locationServicesAvailable():
+            raise LocationServiceException('location services not available')
 
-        time.sleep(float(timeout) / DEFAULT_RETRIES)
+        m.startUpdatingLocation()
         CoreLocation.CFRunLoopStop(CoreLocation.CFRunLoopGetCurrent())
         l = m.location()
 
-    if not l:
-        raise LocationServiceException(
-                'location could not be found -- is wifi enabled?'
-            )
+        # retry up to ten times, possibly sleeping between tries
+        for i in xrange(DEFAULT_RETRIES):
+            if l:
+                break
 
-    c = l.coordinate()
-    return Location(c.latitude, c.longitude)
+            time.sleep(float(timeout) / DEFAULT_RETRIES)
+            CoreLocation.CFRunLoopStop(CoreLocation.CFRunLoopGetCurrent())
+            l = m.location()
 
+        if not l:
+            raise LocationServiceException(
+                    'location could not be found -- is wifi enabled?'
+                )
+
+        c = l.coordinate()
+        return Location(c.latitude, c.longitude)
+
+@location_strategy("geoip")
 def geobytes_location(timeout=DEFAULT_TIMEOUT):
     external_ip = requests.get('http://jsonip.com/').json['ip']
     try:
             help='Suppress any error messages.')
     parser.add_option('--show', action='store_true',
             help='Show result on Google Maps in a browser.')
-    parser.add_option('--approx', action='store_true',
-            help='Use a GeoIP service if Core Location fails.')
+    parser.add_option('-f', '--force', action='store_true', dest='force',
+            help='Continue trying strategies if the first should fail')
+    parser.add_option('--strategy', action='store', dest='strategy',
+            help='Strategy for location lookup (corelocation|geoip)', default=LOCATION_STRATEGIES.keys()[0])
 
     return parser
 
         parser.print_help()
         sys.exit(1)
 
+    if options.strategy not in LOCATION_STRATEGIES:
+        raise OptionValueError("%s is not a valid strategy" % options.strategy)
+
     l = None
     error = None
+
+    strategy = LOCATION_STRATEGIES.pop(options.strategy)
+
     try:
-        l = location(options.timeout)
+        l = strategy(options.timeout)
     except LocationServiceException, e:
         error = e.message
 
-    if not l and options.approx:
-        try:
-            l = geobytes_location()
-        except LocationServiceException, e:
-            error = e.message
+    if not l and options.force:
+        for _, strategy in LOCATION_STRATEGIES:
+            try:
+                l = geobytes_location()
+            except LocationServiceException, e:
+                error = e.message
 
     if not l:
         if not options.quiet: