Ejemplo n.º 1
0
 def __get_trip_distances(self, trip):
     trip.od_distance = CommonHelper.point_distance(trip.origin, trip.destination)
     #TODO TEMP
     #if trip.od_distance == 0:
     #   print("WARNING!!! in __get_trip_distances(): od_distance is 0, for trip ID:",trip.id," OD:",trip.origin, trip.destination)
     trip.legs_without_points = []
     trip.distance = 0
     trip.distance_by_mode = {}
     for leg in trip.legs:            
         # distance by mode .....:
         # first calcualtes and SETs leg['distance'] values ... TODO!!! should be done elsewhere for example during leg-detection?
         if leg['is_moprim_leg']:
             pass #TODO: for legs retrieved from OTP, presumably, leg['distance'] is accurate enough (is point-to-point based)
         elif leg['is_otp_leg']:
             pass #TODO: for legs retrieved from OTP, presumably, leg['distance'] is accurate enough (is point-to-point based)
         else: #i.e: leg from original points recorded by user device
             leg['od_distance'] = CommonHelper.point_distance(CommonHelper.geoJSON_to_pointRow(leg['origin']), CommonHelper.geoJSON_to_pointRow(leg['destination'])) 
         
             # Calc travelled-distance, point to point based here, OR Write a plsql-like function that does so on DB server
             leg_points_rows = self.legs_dal.get_leg_points(leg)           
             leg['distance'] = self.__calculate_trajectory_distance(leg_points_rows)
             if leg_points_rows.rowcount == 0:
                 log(["Warning in __get_trip_distances()!: legs_dal.get_leg_points(leg) returned ZERO points. For leg ("+str(leg['user_id'])+' '+
                       str(trip.id)+" "+str(leg['id'])+ "; device_id="+str(leg['device_id'])+'; '+str(leg['time_start'])+', '+str(leg['time_end'])])
                 trip.legs_without_points.append(leg)
         # add up leg-distances to total trip.distance: 
         trip.add_travelled_distance(leg['mode'], leg['distance']) # NOTE: 'total distance' of trip is increased inside this function
Ejemplo n.º 2
0
    def send_http_get(self, apiurl, querystr=None, verify_certificate=False):
        # Notes for urllib2:
        #   GET request with urllib2: If you do not pass the data argument, urllib2 uses a GET request (you can encode the data in URL itself)
        #   POST request with urllib2: Just as easy as GET, simply passing (encoded) request data as an extra parameter
        #params = urllib.urlencode(querystr)

        apiurl_with_query = apiurl
        params = querystr
        if params is not None and params != '':
            apiurl_with_query += "?" + params
        #log(["params:", params])
        #log(["apiurl_with_query:", apiurl_with_query, "verify_certificate:", verify_certificate])

        response = None
        res = False
        e = None
        exception_type = ""
        try:
            #response = urllib2.urlopen(apiurl_with_query)
            log(["send_http_get():", apiurl_with_query])

            response = requests.get(
                apiurl_with_query, verify=verify_certificate
            )  # //TODO: possible security issue! verify=True works from python command line !!!!
            response.close()
            if response.status_code == 200:  #TODO: does it happen that status_code is NOT CHANGED??
                res = True
        except urllib.error.HTTPError as e:
            exception_type = "urllib.error.HTTPError"
        except requests.exceptions.ConnectionError as e:
            exception_type = "requests.exceptions.ConnectionError"
        except Exception as e:
            exception_type = "Exception"
        finally:
            pass  # TODO, don't like the idea of finally changing program exec and exception raise path (use later, maybe)

        if res:
            response_str = response.content
        elif e is not None:
            response_str = "(!) EXCEPTION catched (class_type: {}) in WebNetworking::send_http_get(): ".format(
                exception_type)
            if response is not None:
                logexc(response_str, e, [
                    ", apiurl_with_query: ", apiurl_with_query,
                    ", response content_type:",
                    response.headers['content-type']
                ])
            else:
                logexc(response_str, e,
                       [", apiurl_with_query: ", apiurl_with_query])
        else:
            response_str = "! error in send_http_get(), res=False, response.status_code={}".format(
                response.status_code)
            loge([
                "! error in send_http_get(), res=False, response.status_code="
            ], response.status_code)
            pass  #probably http error occured (eg status code != 200)

        return res, response_str
Ejemplo n.º 3
0
    def load_trips(self, ids_to_process, date_range_start, date_range_end,
                   timeofday_start, timeofday_end, timeofday_start2,
                   timeofday_end2, min_od_distance, od_d_diff_coeff):
        # TODO: refine more if needed here
        qstr = """SELECT user_id, device_id, id, plan_id, start_time, end_time, ST_AsGeoJSON(origin) as origin, ST_AsGeoJSON(destination) as destination, 
                        multimodal_summary, duration, cost, calories, emission, comfort, distance, 
                        time_by_mode, cost_by_mode, calories_by_mode, emission_by_mode, distance_by_mode,
                        mainmode, 
                        start_time_for_plan, notes, od_distance
                    FROM trips_alts  
                    WHERE (user_id, id) IN
                    ( SELECT user_id, id FROM trips_alts 
                      WHERE user_id IN({0}) AND plan_id = 0 
                      AND start_time >= '{1}' AND end_time <= '{2}'                       
                      AND ((start_time::time >= time {3} AND end_time::time <= time {4}) OR
                           (start_time::time >= time {5} AND end_time::time <= time {6}))
                      AND ST_Distance(origin, destination) > {7}
                      AND distance < {8} * ST_Distance(origin, destination)
                    )
                    ORDER BY user_id, id, plan_id;
                    """.format(ids_to_process,
                               DateTime_to_Text(date_range_start),
                               DateTime_to_Text(date_range_end),
                               DateTime_to_SqlText(timeofday_start),
                               DateTime_to_SqlText(timeofday_end),
                               DateTime_to_SqlText(timeofday_start2),
                               DateTime_to_SqlText(timeofday_end2),
                               min_od_distance, od_d_diff_coeff)
        log(["load_trips():: qstr:", qstr])
        log("")
        res, trip_rows = self.db_command.ExecuteSQL(qstr)

        total_trip_and_alt_count = trip_rows.rowcount

        trips = []
        if trip_rows.rowcount > 0:
            actualtrip = None
            for trip_row in trip_rows:
                trip = Trip(trip_row)
                # OLD Code : Parse JSON into an object with attributes corresponding to dict keys
                # TODO: WARNING!!: (?) only works well if names of DB table columns are same as names of our Python Class attributes
                #   trip.__dict__= json.loads(trip_row['trip_as_json'])

                # TODO: IMPORTANT !!!: load trip legs * Needed??
                # ...

                # build the nested structure of 'trips' list in our program:
                if trip.plan_id == 0:
                    actualtrip = Trip()
                    actualtrip = deepcopy(
                        trip)  # TODO: WARNING !!! is this neede?!!
                    trips.append(actualtrip)
                elif trip.plan_id > 0:
                    if actualtrip is not None:
                        actualtrip.alternative_trips.append(trip)
                # log(trip.user_id,  trip.id,  trip.plan_id,  trip.origin)

        return trips
Ejemplo n.º 4
0
 def find_same_journey_time_this_week(cls, original_date_time):
     # find date of the same weekday, but for current week (to avoid querying old dates that results in error from HSL)              
     if original_date_time.weekday() < datetime.today().weekday():
         reference_date = datetime.today() + timedelta(weeks = 1)
     else:
         reference_date = datetime.today()  
     date_thisweek = reference_date + timedelta(days = (original_date_time.weekday() - reference_date.weekday()))        
     time_thisweek = datetime.combine(date_thisweek.date(), original_date_time.time())
     log(["find_same_journey_time_this_week():: original_date_time:"+DateTime_to_Text(original_date_time)+
           " --> same journey time this or next week:" + DateTime_to_Text(time_thisweek) ])
     return time_thisweek            
Ejemplo n.º 5
0
    def ExecuteSQL(self, query_string, LOG_IMPORTANT_CUSTOM=True):
        qstr = query_string
        log(["DatabaseCommands::ExecuteSQL() qstr:", qstr])

        db_res = None
        res = False
        try:
            db_res = self.db_engine.execute(text(qstr))
            res = True
        except Exception as e:
            self._log_exception(
                "DatabaseCommandsNonTransactional::ExecuteSQL()", qstr, str(e))
        return res, db_res
Ejemplo n.º 6
0
    def find_trip_od_for_recorded_location(self, recorded_geoloc,
                                           distance_inaccuracy_threshold):
        qstr = """SELECT geoloc 
                    FROM trip_origin_destinations  
                    WHERE ST_Distance(geoloc, ST_GeomFromText('{0}')) <= {1}
                    """.format(pointRow_to_postgisPoint(recorded_geoloc),
                               distance_inaccuracy_threshold)
        log(["find_trip_od_for_recorded_location():: qstr:", qstr])
        log("")
        res, trip_od_rows = self.db_command.ExecuteSQL(qstr)

        if trip_od_rows.rowcount > 0:
            for trip_od_row in trip_od_rows:
                return trip_od_row['geoloc']

        return None
Ejemplo n.º 7
0
    def ExecuteSQL(self, query_string):
        qstr = query_string
        log(["DatabaseCommandsTransactional::ExecuteSQL() qstr:", qstr])

        db_res = None
        res = False
        try:
            db_res = self.session.execute(
                qstr)  # transaction starts here, if not started before
            res = True
        except Exception as e:
            self._log_exception("DatabaseCommandsTransactional::ExecuteSQL()",
                                qstr, str(e))
            raise e  #TODO NOTE! Crucial; So that it is passed eventually to BLL level that will call rollback() if needed
            # TODO: But, for an easier approach, shouldn't this function itself Rollback the transaction??

        return res, db_res
Ejemplo n.º 8
0
    def get_next_user_trip_id(self, user_id, date_range_start, date_range_end):
        qstr = """SELECT max(id) as max_id
                    FROM trips_alts  
                    WHERE user_id = {0} AND (user_id, id, plan_id) NOT IN
                    (SELECT user_id, id, plan_id FROM trips_alts
                     WHERE user_id = {0}
                     AND start_time >= '{1}' AND end_time <= '{2}');
                """.format(user_id,
                           CommonHelper.DateTime_to_Text(date_range_start),
                           CommonHelper.DateTime_to_Text(date_range_end))
        log(["get_next_user_trip_id():: qstr:", qstr])
        log("")
        res, maxid_rows = self.db_command.ExecuteSQL(qstr)

        if maxid_rows.rowcount > 0:
            for maxid_row in maxid_rows:
                if maxid_row['max_id'] == None:
                    return 0
                else:
                    return maxid_row['max_id']
        return 0
Ejemplo n.º 9
0
    def store_trip_od_location(self, recorded_geoloc,
                               distance_inaccuracy_threshold):
        qstr = """INSERT INTO trip_origin_destinations (geoloc, distance_inaccuracy_threshold)
                        VALUES (ST_GeomFromText('{0}'), {1})
                        """.format(pointRow_to_postgisPoint(recorded_geoloc),
                                   distance_inaccuracy_threshold)
        log(["store_trip_od_location:: qstr:", qstr])
        log("")

        res, db_res = self.db_command.ExecuteSQL(qstr)
        log(["result:", str(res)])
        return res
Ejemplo n.º 10
0
 def delete_trips_by_id(self, ids_to_process, trip_id_start, trip_id_end):
     qstr = """DELETE FROM trips_alts 
                 WHERE user_id IN ({0})
                 AND id >= '{1}' AND id <= '{2}';
             """.format(ids_to_process, trip_id_start, trip_id_end)
     log([
         "delete_trips():: qstr for removing old rows before storing new ones:",
         qstr
     ])
     res, db_res = self.db_command.ExecuteSQL(qstr)
     log(["result:", res])
     log("")
     return res
Ejemplo n.º 11
0
 def delete_trips_and_alternatives(self, date_range_start, date_range_end):
     qstr = """DELETE FROM trips_alts 
                 WHERE true
                 AND start_time >= '{}' AND end_time <= '{}';
             """.format(DateTime_to_Text(date_range_start),
                        DateTime_to_Text(date_range_end))
     log([
         "delete_trips_and_alternatives():: qstr for removing old rows before storing new ones:",
         qstr
     ])
     res, db_res = self.db_command.ExecuteSQL(qstr)
     log(["result:", res])
     log("")
     return res
Ejemplo n.º 12
0
 def delete_trips(self, ids_to_process, date_range_start, date_range_end):
     qstr = """DELETE FROM trips_alts 
                 WHERE user_id IN ({0})
                 AND start_time >= '{1}' AND end_time <= '{2}';
             """.format(ids_to_process, DateTime_to_Text(date_range_start),
                        DateTime_to_Text(date_range_end))
     log([
         "delete_trips():: qstr for removing old rows before storing new ones:",
         qstr
     ])
     res, db_res = self.db_command.ExecuteSQL(qstr)
     log(["result:", res])
     log("")
     return res
Ejemplo n.º 13
0
    def __increase_modalchoice_for_user(self, user_id, trip,
                                        user_modalchoice_list):
        log(["increase_modalchoice_for_user:: ..."])
        log(["trip.mainmode:", trip.mainmode])
        chosenmode = trip.mainmode
        if chosenmode in PublicTransportModesTemplate:
            chosenmode = 'PUBLIC_TRANSPORT'
        log(["chosenmode:", chosenmode])

        if user_id not in user_modalchoice_list:
            user_modalchoice_list[user_id] = deepcopy(UserModalChoiceTemplate)

        if chosenmode in user_modalchoice_list[user_id]:
            user_modalchoice_list[user_id][chosenmode] += 1
Ejemplo n.º 14
0
    def store_trip_to_leg(self, trip, leg):
        qstr = ""
        try:
            qstr = """INSERT INTO trips_to_legs (user_id, trip_id, plan_id, leg_id) 
                   VALUES ({0},{1},{2},{3})""".format(trip.user_id, trip.id,
                                                      trip.plan_id, leg['id'])

            log(["store_trip_to_leg():: qstr:", qstr])
            log("")

            res, db_res = self.db_command.ExecuteSQL(qstr)
            log(["result:", str(res)])
        except Exception as e:
            print("Exception in store_trip_to_leg():")
            print("exception:", e)
            print("qstr:", qstr)
            raise  #TODO NOTE critical .. so that BLL is able to rollback if needed *
Ejemplo n.º 15
0
    def _query_a_trip_plan(self, desired_trip, desired_transport_mode,
                           num_of_itineraries, max_walk_distance,
                           show_intermediate_stops):
        log("")
        log(["_query_a_trip_plan::Requesting to OTP journey planner:"])
        log([
            "Input desired_trip:", desired_trip.starttime, ",",
            desired_transport_mode
        ])

        # Send our query to OTP journey planner:
        # Example:
        #   querystr = "fromPlace=60.170718,24.930221&toPlace=60.250214,25.009566&date=2016/4/22&time=17:18:00&numItineraries=3&maxTransfers=3&maxWalkDistance=1500"

        if desired_transport_mode == 'PUBLIC_TRANSPORT' or desired_transport_mode in PublicTransportModesTemplate:
            querystr = """fromPlace={0}&toPlace={1}&date={2}&time={3}&numItineraries={4}&maxWalkDistance={5}&showIntermediateStops={6}""".format(
                pointRow_to_geoText(desired_trip.origin),
                pointRow_to_geoText(desired_trip.destination),
                desired_trip.starttime.date().isoformat(),
                desired_trip.starttime.time().isoformat(), num_of_itineraries,
                max_walk_distance, show_intermediate_stops)
        else:
            querystr = """fromPlace={0}&toPlace={1}&date={2}&time={3}&numItineraries={4}&mode={5}""".format(
                pointRow_to_geoText(desired_trip.origin),
                pointRow_to_geoText(desired_trip.destination),
                desired_trip.starttime.date().isoformat(),
                desired_trip.starttime.time().isoformat(), num_of_itineraries,
                desired_transport_mode)

        webres, response_content_str = self.webnet.send_http_get(
            self.api_url, querystr)

        if type(response_content_str) == bytes:
            response_content_str = response_content_str.decode()

        return self._parse_webnet_response(webres, response_content_str)
Ejemplo n.º 16
0
    def increase_pros_for_user(self, user_id, comparison_list,
                               cl_desired_template, best_modalchoice_by_param):
        log([""])
        log(["increase_pros_for_user ...:"])
        log(["cl_desired_template:", cl_desired_template])
        log(["best_modalchoice_by_param:", best_modalchoice_by_param])
        if user_id not in comparison_list:
            comparison_list[user_id] = deepcopy(cl_desired_template)
        log(["comparison_list before calcs:", comparison_list])

        for param, choice in best_modalchoice_by_param.iteritems():
            if choice['mode'] is not None:
                comparison_list[user_id][param][choice['mode']] += 1

        log(["comparison_list after calcs:", comparison_list])
Ejemplo n.º 17
0
    def get_best_modalchoice_by_param_for_trip(self, trip,
                                               desired_modes_template):
        # find the best modal-choice per trip depending on the target param (eg. 'time', 'cals', ...):
        mintime = None  # TODO: or compare with original trip?!
        mincost = None
        maxcals = None
        minemission = None
        maxcomfort = None
        pros = deepcopy(BestModalChoiceByParamTemplate)
        # pros_detailed = deepcopy(BestModalChoiceByParamTemplate) # TODO later
        modes_to_compare = []
        for mode, val in desired_modes_template.iteritems():
            #            if mode == 'PUBLIC_TRANSPORT':
            #                for public_transport_mode in PublicTransportModesTemplate:
            #                    modes_to_compare.append(mode)
            modes_to_compare.append(mode)

        log([""])
        log(["get_best_modalchoice_by_param_for_trip:: ...:"])
        log(["modes_to_compare:", modes_to_compare])

        #if trip.user_id not in comparison_list:
        #    comparison_list[trip.user_id] = desiredCLTemplate #TODO old code?! remove?

        # find the min val or max val depending on the target param
        # (eg. for 'cals' we should find the tripalt (modal-choice chain) with largest 'cals' val)
        for tripalt in trip.alternative_trips:
            log(["tripalt.mainmode:", tripalt.mainmode])
            mainmode = tripalt.mainmode
            if mainmode in PublicTransportModesTemplate:
                mainmode = 'PUBLIC_TRANSPORT'
            log(["mainmode:", mainmode])

            if mainmode in modes_to_compare:
                if mintime is None or tripalt.duration < mintime:  #TODO : what if == ???
                    mintime = tripalt.duration
                    pros['time'] = {
                        "plan_id": tripalt.plan_id,
                        "mode": mainmode
                    }
                if mincost is None or tripalt.cost < mincost:
                    mincost = tripalt.cost
                    pros['cost'] = {
                        "plan_id": tripalt.plan_id,
                        "mode": mainmode
                    }
                if maxcals is None or tripalt.calories > maxcals:
                    maxcals = tripalt.calories
                    pros['cals'] = {
                        "plan_id": tripalt.plan_id,
                        "mode": mainmode
                    }
                if minemission is None or tripalt.emission < minemission:
                    minemission = tripalt.emission
                    pros['emission'] = {
                        "plan_id": tripalt.plan_id,
                        "mode": mainmode
                    }
                if maxcomfort is None or tripalt.comfort > maxcomfort:
                    maxcomfort = tripalt.comfort
                    pros['comfort'] = {
                        "plan_id": tripalt.plan_id,
                        "mode": mainmode
                    }

        log([trip.user_id, trip.device_id, trip.id, ":", " pros:", pros])
        return pros
Ejemplo n.º 18
0
    def store_trip(self, trip):
        # NOTE: example INSERT: insert into mytest (name) VALUES ('{''car'', ''walk''}');
        res = ""
        qstr = ""

        try:
            qstr = """INSERT INTO trips_alts (user_id, device_id, id, plan_id, start_time, end_time, 
                   origin, destination, 
                   multimodal_summary, 
                   duration, cost, calories, emission, comfort, distance, time_by_mode, cost_by_mode, calories_by_mode, emission_by_mode, distance_by_mode, 
                   mainmode, start_time_for_plan, od_distance) 
                   VALUES ({0},{1},{2},{3},'{4}','{5}',
                   ST_GeomFromText('{6}'), ST_GeomFromText('{7}'),
                   '{8}',
                   '{9}',{10},{11},{12},{13},{14},
                   '{15}','{16}','{17}','{18}','{19}',
                   '{20}',
                   {21},{22})""".format(
                trip.user_id,
                trip.device_id,
                trip.id,
                trip.plan_id,
                DateTime_to_Text(trip.starttime),
                DateTime_to_Text(trip.endtime),
                pointRow_to_postgisPoint(trip.origin),
                pointRow_to_postgisPoint(trip.destination),
                trip.multimodal_summary,
                DateTimeDelta_to_Text(trip.duration),
                round(trip.cost, 2),
                int(round(trip.calories)),
                round(trip.emission,
                      1),  # TODO, old: round(trip.emission/1000.0, 1), 
                trip.comfort,
                round(trip.distance, 1),  # TODO
                json.dumps(dict_timedelta_to_text(trip.duration_by_mode)
                           ),  #TODO, test and verify all following
                json.dumps(round_dict_values(trip.cost_by_mode, 2)),
                json.dumps(round_dict_values(trip.calories_by_mode, 2)),
                json.dumps(round_dict_values(trip.emission_by_mode, 2)),
                json.dumps(round_dict_values(trip.distance_by_mode, 2)),
                trip.mainmode,
                DateTime_to_SqlText(
                    trip.shifted_starttime_for_publictransport_tripplan),
                trip.od_distance)
            #round_dict_values(trip.duration_by_mode, 2), \
            #round_dict_values(trip.cost_by_mode, 2),  round_dict_values(trip.calories_by_mode, 0), \
            #round_dict_values(trip.emission_by_mode, 0), round_dict_values(trip.distance_by_mode, 0),\
            #pointRow_to_geoText(trip.origin), pointRow_to_geoText(trip.destination)
        except Exception as e:
            print("")
            print(">> store_trip():: FAILED ------------------------------")
            print(">> trip to store:", trip)
            print("exception: ", e)
            print("")
            raise  #TODO NOTE critical .. so that BLL is able to rollback if needed *

        try:
            res, db_res = self.db_command.ExecuteSQL(qstr)
        except Exception as e:
            print("")
            print(">> store_trip():: FAILED ------------------------------")
            print(">> trip to store:", trip)
            print("exception: ", e)
            print("qstr: ", qstr)
            print("")
            raise  #TODO NOTE critical .. so that BLL is able to rollback if needed *
        log(["result:", str(res)])
        return res
Ejemplo n.º 19
0
    def plan_a_trip(self, reference_trip, desired_transport_mode,
                    num_of_itineraries, max_walk_distance,
                    show_intermediate_stops):
        log("")
        log(["plan_a_trip::Input reference trip: ", reference_trip.starttime, \
              ":  from ", pointRow_to_geoText(reference_trip.origin), "--> to", pointRow_to_geoText(reference_trip.destination)])

        desired_trip = deepcopy(
            reference_trip
        )  # keep a copy, in order to not change the input params in the caller's scope
        desired_trip.starttime = desired_trip.starttime.replace(microsecond=0)
        desired_trip.endtime = desired_trip.endtime.replace(microsecond=0)

        # query journey planner --------------:
        is_desired_trip_date_shifted = False
        shifted_starttime = None

        plan = None
        res = 0
        error = None
        planning_response = None
        restored_plan = StoredPlanLoadResult()

        # if such OTP plan is (requested and) stored before, just use it!
        if not self.config.RETRY_ON_ALL_STORED_PLANS:
            #TODO important, later, possible BUG: if 'itin_starttime' (planned) differs a bit from the stored 'desired_trip.starttime' (desired) ... some plans may get lost ??!
            # one solution: use the requestedParameters['date'] and ['time'] instead of values from itin ???
            restored_plan = self._restore_a_trip_plan_from_cache(
                desired_trip, desired_transport_mode, num_of_itineraries,
                max_walk_distance)
            res = restored_plan.res
            plan = restored_plan.plan
            error = restored_plan.error
            planning_response = restored_plan.planning_response
            is_desired_trip_date_shifted = restored_plan.date_was_shifted_forward
            shifted_starttime = restored_plan.shifted_starttime

        # depending on config flags and other conditions:
        # . if flag set: requery regardless of whether we already have the plan in cache
        # . if not loaded from previous plans
        #   . ....
        # send trip-planning query to OTP server:
        if self.config.RETRY_ON_ALL_STORED_PLANS or \
            (not restored_plan.plan_made_before and \
             ((not restored_plan.is_otp_error) or \
              (self.config.RETRY_ON_ALL_STORED_OTP_ERRORS) or\
              (self.config.RETRY_ON_STORED_OTP_ERROR_DATE_TOO_FAR and \
               (restored_plan.error['id'] == OTP_ERROR_CODE_DATE_TOO_FAR or restored_plan.error['id'] == OTP_ERROR_CODE_NO_PATH_POSSIBLE))\
             )\
            ):
            # TODO: important changes made to the above id condition during moprim (both 404 and 406 errors treated thesame)

            res, plan, error, all_response = self._query_a_trip_plan(
                desired_trip, desired_transport_mode, num_of_itineraries,
                max_walk_distance, show_intermediate_stops)
            # TODO: WARNING! dummy test only, to help regenerate the error: ValueError('No JSON object could be decoded',) is not JSON serializable
            #   error['id'] = OTP_ERROR_CODE_DATE_TOO_FAR

            if res == 0 \
                and (error['id'] == OTP_ERROR_CODE_DATE_TOO_FAR \
                     or error['id'] == OTP_ERROR_CODE_NO_PATH_POSSIBLE): #TODO: OTP_ERROR_CODE_NO_PATH_POSSIBLE added during MOprim data processing. Both 404 and 406 errors are now somehow synonyms
                # second try (adjust the old weekday to current week)
                #store this 'intermediate' error trip-plan response for later use ***
                self._store_planning_error(desired_trip,
                                           desired_transport_mode,
                                           num_of_itineraries,
                                           max_walk_distance, all_response)

                # shift the old weekday to current week, and call OTP planner again
                logi([
                    "plan_a_trip():: FAILED for trip (" +
                    str(desired_trip.user_id) + " " + str(desired_trip.id) +
                    ") -" + desired_transport_mode + ": OTP error code=",
                    error['id'] +
                    "; Trying a second time with shifted date to current week..."
                ])
                is_desired_trip_date_shifted = True  # ***
                desired_trip_with_shifted_date = self._shift_trip_to_current_week(
                    desired_trip
                )  # TODO: function algorithm has changed during Moprim ... probably suitable for other TrafficSense data sources too
                shifted_starttime = desired_trip_with_shifted_date.starttime
                #               OLD CODE:
                #                desired_trip_with_shifted_date = deepcopy(desired_trip)
                #                desired_trip_with_shifted_date.starttime = self.find_same_journey_time_this_week(desired_trip.starttime)
                #                desired_trip_with_shifted_date.endtime = self.find_same_journey_time_this_week(desired_trip.endtime)
                res, plan, error, all_response = self._query_a_trip_plan(
                    desired_trip_with_shifted_date, desired_transport_mode,
                    num_of_itineraries, max_walk_distance,
                    show_intermediate_stops)
                if res == 1:
                    #store this 'shifted' trip-plan-response for later use ***
                    self._store_planning_result(desired_trip_with_shifted_date,
                                                desired_transport_mode,
                                                num_of_itineraries,
                                                max_walk_distance,
                                                all_response)
                    log(["plan_a_trip() SUCCESS with shifted time"])
                elif res == 0 and self._has_trip_planning_error(
                        all_response
                ):  # only save errors related to trip planning, OTP and so on (NOT the network, exceptions, own custom etc. errors)
                    #store this error trip-plan response for later use ***
                    self._store_planning_error(desired_trip_with_shifted_date,
                                               desired_transport_mode,
                                               num_of_itineraries,
                                               max_walk_distance, all_response)
            elif res == 0 and self._has_trip_planning_error(all_response):
                #store this error trip-plan response for later use ***
                self._store_planning_error(desired_trip,
                                           desired_transport_mode,
                                           num_of_itineraries,
                                           max_walk_distance, all_response)
            elif res == 1:
                #store this trip-plan-response for later use ***
                self._store_planning_result(desired_trip,
                                            desired_transport_mode,
                                            num_of_itineraries,
                                            max_walk_distance, all_response)

        # summarize after trip planning is done: -------------------
        if res == 1 and (plan is None or 'itineraries' not in plan):
            if plan is not None:
                raise Exception("res == 1 but plan is: {}".format(
                    json.dumps(plan)))
            else:
                raise Exception('res == 1 but plan is None')

        trip_planning_res = TripPlanningResult()
        if res == 0:
            if error is not None:
                trip_planning_res.error_code = error['id']
                trip_planning_res.error_msg = error['msg']
                trip_planning_res.error_message = error['message']
                return 0, None, trip_planning_res
            else:
                return 0, None, trip_planning_res
        elif res == 1:
            if is_desired_trip_date_shifted:
                trip_planning_res.is_desired_trip_date_shifted = is_desired_trip_date_shifted
                trip_planning_res.desired_trip_shifted_starttime = shifted_starttime

        # build trip objects to return to caller: --------------------------
        # go through all trip-leg-chains suggested, to build a collection of Trip objects, and return it :
        log("")
        log([
            "Working on the itins (routes) suggested by otp journey planner ...:"
        ])
        itin_index = 0
        matchcount = 0
        plannedmatches = []  # TODO: choose which returned trip?
        # e.g. when 3 public transport trips are returned * order based on what?
        trips = []

        for itin in plan['itineraries']:
            trip = Trip()
            trip.update_from_otp_trip_plan(desired_trip,
                                           is_desired_trip_date_shifted, plan,
                                           itin)

            # TODO: WARNING!! unit/integrate test.
            # Is the diff in 'trips_alts' table because of following change?! ******************
            #            trip.user_id = desired_trip.user_id
            #            trip.device_id = desired_trip.device_id
            #            trip.id = desired_trip.id
            #            itin_starttime = OTPTimeStampToNormalDateTime(itin['startTime'])
            #            itin_endtime = OTPTimeStampToNormalDateTime(itin['endTime'])
            #            # trip.shifted_starttime_for_publictransport_tripplan = itin_starttime # no need to use this field for alternative plans? (plan_id > 0)
            #            if is_desired_trip_date_shifted:
            #                trip.starttime = shift_time_to_specific_date(itin_starttime,  desired_trip.starttime) # TODO: NOTE: starttime of plan may differ from desired trip start-time (???)
            #                trip.endtime = shift_time_to_specific_date(itin_endtime,  desired_trip.endtime)
            #            else:
            #                trip.starttime = itin_starttime # TODO: NOTE: starttime.time()/endtime of planned itinerary may differ *a bit* from desired trip start-time.time/endtime (???)
            #                trip.endtime = itin_endtime
            #            trip.origin = geoLoc_to_pointRow(plan['from']['lat'], plan['from']['lon']) # TODO: are there cases where plan's origin{lat,lon} differ a bit from desired trip origin?!
            #            trip.destination = geoLoc_to_pointRow(plan['to']['lat'], plan['to']['lon']) # TODO: are there cases where plan's destination{lat,lon} differ a bit from desired trip destination?!
            #            # trip.legs = itin['legs'] #TODO remove old code?
            #            trip.append_otp_legs(itin['legs'],  is_desired_trip_date_shifted, desired_trip.starttime,  desired_trip.endtime)

            trips.append(trip)

        return 1, trips, trip_planning_res
Ejemplo n.º 20
0
    def plan_a_trip_new(self, reference_trip, desired_transport_mode,
                        num_of_itineraries, max_walk_distance,
                        show_intermediate_stops):
        log("")
        log(["plan_a_trip::Input reference trip: ", reference_trip.starttime, \
              ":  from ", pointRow_to_geoText(reference_trip.origin), "--> to", pointRow_to_geoText(reference_trip.destination)])

        desired_trip = deepcopy(
            reference_trip
        )  # keep a copy, in order to not change the input params in the caller's scope

        # query journey planner --------------:
        is_desired_trip_date_shifted = False
        shifted_starttime = None

        plan = None
        res = 0
        error = None
        planning_response = None
        restored_plan = StoredPlanLoadResult()

        if self.config.PLAN_ONLY_WITH_SHIFTED_DATE:
            # shift the old weekday to current week, and call OTP planner again
            logi([
                "plan_a_trip_new() Force shifting date to current week, for trip ("
                + str(desired_trip.user_id) + " " + str(desired_trip.id) +
                ") -" + desired_transport_mode
            ])
            is_desired_trip_date_shifted = True  # ***
            desired_trip_with_shifted_date = self._shift_trip_to_current_week(
                desired_trip)
            shifted_starttime = desired_trip_with_shifted_date.starttime
            res, plan, error, all_response = self._query_a_trip_plan(
                desired_trip_with_shifted_date, desired_transport_mode,
                num_of_itineraries, max_walk_distance, show_intermediate_stops)

            if res == 1:
                #store this 'shifted' trip-plan-response for later use ***
                self._store_planning_result(desired_trip_with_shifted_date,
                                            desired_transport_mode,
                                            num_of_itineraries,
                                            max_walk_distance, all_response)
                logi(["plan_a_trip_new() SUCCESS with shifted time"])
            elif res == 0 and self._has_trip_planning_error(
                    all_response
            ):  # only save errors related to trip planning, OTP and so on (NOT the network, exceptions, own custom etc. errors)
                #store this error trip-plan response for later use ***
                self._store_planning_error(desired_trip_with_shifted_date,
                                           desired_transport_mode,
                                           num_of_itineraries,
                                           max_walk_distance, all_response)

        else:
            # if such OTP plan is (requested and) stored before, just use it!
            if not self.config.RETRY_ON_ALL_STORED_PLANS:
                #TODO important, later, possible BUG: if 'itin_starttime' (planned) differs a bit from the stored 'desired_trip.starttime' (desired) ... some plans may get lost ??!
                # one solution: use the requestedParameters['date'] and ['time'] instead of values from itin ???
                restored_plan = self._restore_a_trip_plan_from_cache(
                    desired_trip, desired_transport_mode, num_of_itineraries,
                    max_walk_distance)
                res = restored_plan.res
                plan = restored_plan.plan
                error = restored_plan.error
                planning_response = restored_plan.planning_response
                is_desired_trip_date_shifted = restored_plan.date_was_shifted_forward
                shifted_starttime = restored_plan.shifted_starttime

            if restored_plan.already_restored_the_shifted_date_plan:
                print(
                    "NOTE: restored_plan.already_restored_the_shifted_date_plan"
                )

            # depending on config flags and other conditions:
            # . if flag set: requery regardless of whether we already have the plan in cache
            # . if not loaded from previous plans
            #   . ....
            # send trip-planning query to OTP server:
            if self.config.RETRY_ON_ALL_STORED_PLANS or \
                (not restored_plan.plan_made_before and \
                     ((not restored_plan.is_otp_error) or (self.config.RETRY_ON_ALL_STORED_OTP_ERRORS) or\
                       (self.config.RETRY_ON_STORED_OTP_ERROR_DATE_TOO_FAR and \
                            (not restored_plan.already_restored_the_shifted_date_plan) and\
                            (restored_plan.error['id'] == OTP_ERROR_CODE_DATE_TOO_FAR\
                             # TODO: NOTE: shifting date to current week only is useful for PT trips ***

                             or (restored_plan.error['id'] == OTP_ERROR_CODE_NO_PATH_POSSIBLE and desired_transport_mode=='PUBLIC_TRANSPORT')
                             )
                        )\
                 )\
                ):

                # TODO: important changes made to the above id condition during moprim (both 404 and 406 errors treated thesame)

                res, plan, error, all_response = self._query_a_trip_plan(
                    desired_trip, desired_transport_mode, num_of_itineraries,
                    max_walk_distance, show_intermediate_stops)
                # TODO: WARNING! dummy test only, to help regenerate the error: ValueError('No JSON object could be decoded',) is not JSON serializable
                #   error['id'] = OTP_ERROR_CODE_DATE_TOO_FAR

                if res == 0 \
                    and (error['id'] == OTP_ERROR_CODE_DATE_TOO_FAR \
                         #TODO: OTP_ERROR_CODE_NO_PATH_POSSIBLE added during MOprim data processing. Both 404 and 406 errors are now somehow synonyms fot PT
                         # TODO: NOTE: shifting date to current week only is useful for PT trips ***


                         or (error['id'] == OTP_ERROR_CODE_NO_PATH_POSSIBLE and desired_transport_mode=='PUBLIC_TRANSPORT')
                        ):
                    # second try (adjust the old weekday to current week) ---------------------
                    #store this 'intermediate' error trip-plan response for later use ***
                    self._store_planning_error(desired_trip,
                                               desired_transport_mode,
                                               num_of_itineraries,
                                               max_walk_distance, all_response)

                    # shift the old weekday to current week, and call OTP planner again
                    logi([
                        "plan_a_trip_new() FAILED for trip (" +
                        str(desired_trip.user_id) + " " +
                        str(desired_trip.id) + ") -" + desired_transport_mode +
                        ": OTP ERROR CODE=" + str(error['id']) +
                        "! => Trying second time with current week..."
                    ])
                    is_desired_trip_date_shifted = True  # ***
                    desired_trip_with_shifted_date = self._shift_trip_to_current_week(
                        desired_trip
                    )  # TODO: function algorithm has changed during Moprim ... probably suitable for other TrafficSense data sources too
                    shifted_starttime = desired_trip_with_shifted_date.starttime

                    res, plan, error, all_response = self._query_a_trip_plan(
                        desired_trip_with_shifted_date, desired_transport_mode,
                        num_of_itineraries, max_walk_distance,
                        show_intermediate_stops)
                    if res == 1:
                        #store this 'shifted' trip-plan-response for later use ***
                        self._store_planning_result(
                            desired_trip_with_shifted_date,
                            desired_transport_mode, num_of_itineraries,
                            max_walk_distance, all_response)
                        log(["plan_a_trip_new() SUCCESS with shifted time"])
                    elif res == 0 and self._has_trip_planning_error(
                            all_response
                    ):  # only save errors related to trip planning, OTP and so on (NOT the network, exceptions, own custom etc. errors)
                        #store this error trip-plan response for later use ***
                        self._store_planning_error(
                            desired_trip_with_shifted_date,
                            desired_transport_mode, num_of_itineraries,
                            max_walk_distance, all_response)
                elif res == 0 and self._has_trip_planning_error(all_response):
                    #store this error trip-plan response for later use ***
                    self._store_planning_error(desired_trip,
                                               desired_transport_mode,
                                               num_of_itineraries,
                                               max_walk_distance, all_response)
                elif res == 1:
                    #store this trip-plan-response for later use ***
                    self._store_planning_result(desired_trip,
                                                desired_transport_mode,
                                                num_of_itineraries,
                                                max_walk_distance,
                                                all_response)

        # summarize after trip planning is done: -------------------
        if res == 1 and (plan is None or 'itineraries' not in plan):
            if plan is not None:
                raise Exception("res == 1 but plan is: {}".format(
                    json.dumps(plan)))
            else:
                raise Exception('res == 1 but plan is None')

        trip_planning_res = TripPlanningResult()
        # TODO: Important change: causes that shifted date is saved in trips_alts DB table, later in code
        if is_desired_trip_date_shifted:
            trip_planning_res.is_desired_trip_date_shifted = is_desired_trip_date_shifted
            trip_planning_res.desired_trip_shifted_starttime = shifted_starttime
        if res == 0:
            if error is not None:
                trip_planning_res.error_code = error['id']
                trip_planning_res.error_msg = error['msg']
                trip_planning_res.error_message = error['message']
                return 0, None, trip_planning_res
            else:
                return 0, None, trip_planning_res
        elif res == 1:
            return 1, plan, trip_planning_res
Ejemplo n.º 21
0
    def _restore_a_trip_plan_from_cache(self, desired_trip,
                                        desired_transport_mode,
                                        num_of_itineraries, max_walk_distance):
        is_desired_trip_date_shifted = False
        desired_trip_with_shifted_date = None
        is_otp_error = False
        plan_made_before = False
        already_restored_the_shifted_date_plan = False

        #TODO important, later, possible BUG: if 'itin_starttime' (planned) differs a bit from the stored 'desired_trip.starttime' (desired) ... some plans may get lost ??!
        # one solution: use the requestedParameters['date'] and ['time'] instead of values from itin ???
        res, plan, error, planning_response = self._load_plan_already_stored(
            desired_trip, desired_transport_mode, num_of_itineraries,
            max_walk_distance)
        #print("First try of loading plan from DB; res = ", res)
        # TODO. Changes made during Moprim
        #if res == 0 and error['id'] == OTP_ERROR_CODE_NO_PATH_POSSIBLE:
        #    pass

        # second try (adjust the old weekday to current week) from DB
        if res == 0 and (error['id'] == OTP_ERROR_CODE_DATE_TOO_FAR \
                         #TODO: important Moprim changes!
                         # TODO: NOTE: shifting to current week only is useful for PT trips ***


                         or (error['id'] == OTP_ERROR_CODE_NO_PATH_POSSIBLE and desired_transport_mode=='PUBLIC_TRANSPORT')
                        ):
            log([
                "_restore_a_trip_plan_from_cache(): for trip (" +
                str(desired_trip.user_id) + " " + str(desired_trip.id) +
                "), mode " + desired_transport_mode,
                "load from DB successful.",
                "But trip planning HAD FAILED because loaded record has: OTP error (error['id']={})"
                .format(error['id'])
            ])
            log([
                "Loading second time from DB, with the shifted date (either 'trips.shifted_starttime_for_publictransport_tripplan' or time current week) ..."
            ])

            is_desired_trip_date_shifted = True  # ***
            desired_trip_with_shifted_date = deepcopy(desired_trip)
            if desired_trip.shifted_starttime_for_publictransport_tripplan is not None:  # if already shifted in a previous run, load from DB record values
                #print("TEMP MESSAGE: references-trip shifted-date for PT planning:", desired_trip.shifted_starttime_for_publictransport_tripplan)
                desired_trip_with_shifted_date.starttime = desired_trip.shifted_starttime_for_publictransport_tripplan
            else:  # if not already shifted, do it here, try for same weekday in current week
                print(
                    "Warning! References-trip shifted-date for PT planning NULL; Shifting the date here!!!"
                )
                desired_trip_with_shifted_date.starttime = self.find_same_journey_time_this_week(
                    desired_trip.starttime)
            # update the end-time too, for backwards compatibility
            desired_trip_with_shifted_date.endtime = shift_time_to_specific_date(
                desired_trip.endtime, desired_trip_with_shifted_date.starttime
            )  #TODO ... no separate data field for endtime ?!!!
            #print("TEMP MESSAGE: desired_trip_with_shifted_date:", desired_trip_with_shifted_date.starttime)

            old_error = error
            old_planning_response = planning_response

            res, plan, error, planning_response = self._load_plan_already_stored(
                desired_trip_with_shifted_date, desired_transport_mode,
                num_of_itineraries, max_walk_distance)
            if res:
                log([
                    "SUCCESS: date shifted-forward trip plan found in DB ==> using it ..."
                ])
                # TODO: WARNING! test dummy use only if needed to REMOVE trip-plans for test!!!
                # TODO: WARNING! self.trip_plans_dal.delete_trip_plan(desired_trip_with_shifted_date, desired_transport_mode, num_of_itineraries, max_walk_distance)
            elif self._has_trip_planning_error(planning_response):
                already_restored_the_shifted_date_plan = True
                logi([
                    "ERROR: date shifted-forward trip plan found; But trip planning HAD FAILED again because (error['id']={})"
                    .format(error['id'])
                ])
                # TODO: WARNING! test dummy use only if needed to REMOVE trip-plans for test!!!
                # TODO: WARNING! self.trip_plans_dal.delete_trip_plan(desired_trip_with_shifted_date, desired_transport_mode, num_of_itineraries, max_walk_distance)
            elif error['id'] == 0:
                # restore original error id and message
                error = old_error
                planning_response = old_planning_response
                loge(["ERROR: date shifted-forward trip plan NOT found in DB"])
            #loge([""]) #TODO!!! revert

        # summarize the result:
        if res == 0 and self._has_trip_planning_error(planning_response):
            error['message'] = "_restore_a_trip_plan_from_cache() - " + error[
                'message']
            is_otp_error = True
        elif res == 1:
            plan_made_before = True
            self._increase_no_of_correct_plans_loaded_from_cache()

        restore_res = StoredPlanLoadResult()
        restore_res.set(res, plan, error, planning_response,
                        is_desired_trip_date_shifted,
                        desired_trip_with_shifted_date, is_otp_error,
                        plan_made_before,
                        already_restored_the_shifted_date_plan)
        return restore_res