traveltime-dev / traveltime-python-sdk

TravelTime SDK for Python programming language
https://docs.traveltime.com/
MIT License
20 stars 5 forks source link

5p travel cost #82

Closed SergeyAnufriev closed 7 months ago

SergeyAnufriev commented 1 year ago

I have found that quite often API returns single tickets price at 5p. The following code reproduces the error in traveltimepy 3.4.0

from traveltimepy import Location, Coordinates, TravelTimeSdk,PublicTransport,Property,FullRange import asyncio from datetime import datetime

sdk = TravelTimeSdk(' ', ' ')

ids_from = [298555,298331,296932,297784,298405,298121,298202,296933,297600] ids_to = [298285,298229,298571,296052,298574,298179,297684,298669,298400]

'''Input coordinates from and to travel'''

coords_start = [[52.4974 , -2.01641 ], [53.6002 , -2.28587 ], [52.0728 , -0.631566], [52.5806 , -2.11686 ], [53.5737 , -2.42206 ], [51.5271 , -0.238967], [52.6265 , -1.71263 ], [52.0728 , -0.631566], [52.5806 , -2.11686 ]]

coords_end = [[52.8258, -2.00097], [52.6265, -1.71263], [52.8258, -2.00097], [53.1598, -2.66918], [52.8258, -2.00097], [52.6738, -1.75808], [53.6056, -2.39163], [52.8258, -2.00097], [53.3642, -2.29783]]

coords_from = [Coordinates(lat= x, lng= y) for x,y in coords_start] coords_to = [Coordinates(lat= x, lng= y) for x,y in coords_end]

locations_from = [Location(id='s'+str(x),coords = y) for x,y in zip(ids_from,coords_from)] locations_to = [Location(id='e'+str(x),coords = y) for x,y in zip(ids_to,coords_to)]

locations = list(set(locations_from + locations_to)) search_dict = {'s'+str(x):['e'+str(y)] for x,y in zip(ids_from,ids_to)}

async def travel_times(search_dict,locations):

      locations       = locations
      search_ids      = search_dict
      results = await sdk.time_filter_async(

         locations = locations,
         search_ids = search_ids,
         transportation = PublicTransport(),
         properties=[Property.TRAVEL_TIME, Property.FARES],
         departure_time=datetime(2023, 9,27,13,0),
         travel_time=14400)

      return results

asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) res = asyncio.run(travel_times(search_dict,locations))

Define a function to extract single ticket price from a TimeFilterResult object

def extract_single_ticket_price(result): for location in result.locations: for property in location.properties: for fare in property.fares.breakdown: for ticket in fare.tickets: if ticket.type == 'single': return ticket.price return None

Extract and print the single ticket prices for each result

for result in res: single_ticket_price = extract_single_ticket_price(result) if single_ticket_price is not None: print(f"Search ID: {result.search_id}, Single Ticket Price: {single_ticket_price} GBP") else: print(f"Search ID: {result.search_id}, Single Ticket Price not found")

OUTPUT:

Search ID: s296932, Single Ticket Price: 0.05 GBP Search ID: s296933, Single Ticket Price: 0.05 GBP Search ID: s297600, Single Ticket Price: 0.05 GBP Search ID: s297784, Single Ticket Price: 0.05 GBP Search ID: s298121, Single Ticket Price: 0.05 GBP Search ID: s298202, Single Ticket Price: 0.05 GBP Search ID: s298331, Single Ticket Price: 0.05 GBP Search ID: s298405, Single Ticket Price: 0.05 GBP Search ID: s298555, Single Ticket Price: 0.05 GBP

mikism commented 1 year ago

I'm not a Python expert, but I believe this code

#Define a function to extract single ticket price from a TimeFilterResult object
def extract_single_ticket_price(result):
    for location in result.locations:
        for property in location.properties:
            for fare in property.fares.breakdown:
                for ticket in fare.tickets:
                    if ticket.type == 'single':
                        return ticket.price

will take the first single ticket price of the first reachable locations from the breakdown and return it. There is a fares.tickets_total object that has the total sum.

SergeyAnufriev commented 1 year ago

there are still bugs in ticket prices including if fares.tickets_total are used. code below shows tickets_total for 3 h journey returns 3.5 pounds

from traveltimepy import Location, Coordinates, TravelTimeSdk,PublicTransport,Property
import asyncio
from datetime import datetime
import os

sdk = TravelTimeSdk(os.environ.get("TRAVEL_TIME_LOGIN"), os.environ.get("TRAVEL_TIME_PASSWORD"))

ids_from = [298202,296933,297600]
ids_to = [297684,298669,298400]

'''Input coordinates from and to travel'''

coords_start = [
 [52.6265 ,  -1.71263 ],
 [52.0728 ,  -0.631566],
 [52.5806 ,  -2.11686 ]]

coords_end = [
 [53.6056,  -2.39163],
 [52.8258,  -2.00097],
 [53.3642,  -2.29783]]

coords_from = [Coordinates(lat= x, lng= y) for x,y in coords_start]
coords_to = [Coordinates(lat= x, lng= y) for x,y in coords_end]

locations_from = [Location(id='s'+str(x),coords = y) for x,y  in zip(ids_from,coords_from)]
locations_to = [Location(id='e'+str(x),coords = y) for x,y  in zip(ids_to,coords_to)]

locations = list(set(locations_from + locations_to))
search_dict = {'s'+str(x):['e'+str(y)] for x,y in zip(ids_from,ids_to)}

async def travel_times(search_dict,locations):

          locations       = locations
          search_ids      = search_dict
          results = await sdk.time_filter_async(

             locations = locations,
             search_ids = search_ids,
             transportation = PublicTransport(),
             properties=[Property.TRAVEL_TIME, Property.FARES],
             departure_time=datetime(2023, 9,27,13,0),
             travel_time=14400)

          return results

asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
res = asyncio.run(travel_times(search_dict,locations))

#Define a function to extract single ticket price from a TimeFilterResult object
def extract_single_ticket_price(result):
    for location in result.locations:
        for property in location.properties:
            travel_time = 0  # Initialize total travel time
            for prop in location.properties:
                if prop.travel_time:
                    travel_time += prop.travel_time
            return property.fares.tickets_total,  property.fares.breakdown, travel_time

    return None

for result in res:
    tickets_total, breakdown , travel_time = extract_single_ticket_price(result)
    print('tickets_total',tickets_total)
    print('breakdown',breakdown)
    print('travel_time',travel_time/3600)

OUTPUT: tickets_total [Ticket(type='single', price=9.15, currency='GBP'), Ticket(type='week', price=187.8, currency='GBP'), Ticket(type='month', price=721.1519999999999, currency='GBP'), Ticket(type='year', price=7512.0, currency='GBP')] breakdown [FareBreakdown(modes=['rail_national'], route_part_ids=[10], tickets=[Ticket(type='single', price=0.05, currency='GBP'), Ticket(type='week', price=141.6, currency='GBP'), Ticket(type='month', price=543.7439999999999, currency='GBP'), Ticket(type='year', price=5664.0, currency='GBP')]), FareBreakdown(modes=['rail_national'], route_part_ids=[11], tickets=[Ticket(type='single', price=9.1, currency='GBP'), Ticket(type='week', price=46.2, currency='GBP'), Ticket(type='month', price=177.40800000000002, currency='GBP'), Ticket(type='year', price=1848.0, currency='GBP')])] travel_time 3.825 tickets_total [Ticket(type='single', price=3.4499999999999997, currency='GBP'), Ticket(type='week', price=148.3, currency='GBP'), Ticket(type='month', price=569.472, currency='GBP'), Ticket(type='year', price=5932.0, currency='GBP')] breakdown [FareBreakdown(modes=['rail_national'], route_part_ids=[13, 14], tickets=[Ticket(type='single', price=0.05, currency='GBP'), Ticket(type='week', price=148.3, currency='GBP'), Ticket(type='month', price=569.472, currency='GBP'), Ticket(type='year', price=5932.0, currency='GBP')]), FareBreakdown(modes=['bus'], route_part_ids=[7], tickets=[Ticket(type='single', price=3.4, currency='GBP')])] travel_time 2.561111111111111 tickets_total [Ticket(type='week', price=194.7, currency='GBP'), Ticket(type='month', price=687.36, currency='GBP'), Ticket(type='year', price=7160.0, currency='GBP'), Ticket(type='single', price=4.25, currency='GBP')] breakdown [FareBreakdown(modes=['rail_national'], route_part_ids=[20, 19, 18], tickets=[Ticket(type='single', price=0.05, currency='GBP')]), FareBreakdown(modes=['bus'], route_part_ids=[9, 13], tickets=[Ticket(type='single', price=4.2, currency='GBP'), Ticket(type='week', price=15.7, currency='GBP')]), FareBreakdown(modes=['rail_national'], route_part_ids=[19, 18], tickets=[Ticket(type='week', price=148.8, currency='GBP'), Ticket(type='month', price=571.392, currency='GBP'), Ticket(type='year', price=5952.0, currency='GBP')]), FareBreakdown(modes=['rail_national'], route_part_ids=[20], tickets=[Ticket(type='week', price=30.2, currency='GBP'), Ticket(type='month', price=115.96799999999999, currency='GBP'), Ticket(type='year', price=1208.0, currency='GBP')])] travel_time 3.4516666666666667

Process finished with exit code 0

SergeyAnufriev commented 1 year ago

in addition rail segments often cost 5pence

MicrosoftTeams-image

williamnorledge commented 1 year ago

just take a glance at the data

we get 15% of all trains cost 5p

image

chris-traveltime commented 1 year ago

Hi Sergey, William

Thanks for flagging this, we will need to take a deeper look into the data to work out what is going on. I'll let you know once we know more.

Thanks, Chris

chris-traveltime commented 1 year ago

Hey Sergey, William

Thanks for you patience on this. We found a couple of ticket types that were returning the 5p fare, but it took some investigation to establish whether they were valid or not.

It turns out they were not (they were related to things like a staff only discounted fare) so we have removed them from the dataset.

Chris

SergeyAnufriev commented 1 year ago

Does that mean we can use current versions of APIs, since the bug in dataset or do we have to update TravelAPI package?

chris-traveltime commented 1 year ago

Apologies I got slightly ahead of myself and I didn't realise that we are still waiting to merge the fix and will then need to redeploy the maps.

I will let you know once this is done. You won't need to change anything at your end, the API will then use the updated data.