Command-Line Fuel Cost Analyzer – Seeking Advice!

Hello Python Discourse community! I’m new here, working through Python basics and excited to join this awesome forum. I’m building a command-line tool to analyze fuel costs for my car trips, and I’d love your feedback to improve it and learn some Python best practices.

My project is a simple script that calculates fuel costs based on trip distance, fuel efficiency, and price per liter, with an option to save results to a CSV file for tracking. I got inspired by a straightforward fuel calculator I found at kalkulatorpaliwa.com.pl, which has a clean interface and quick calculations. I want my tool to be similarly user-friendly but run from the terminal for quick use.

Here’s my current script using argparse for command-line inputs:

import argparse
import csv
import os

def calculate_fuel_cost(distance, efficiency, price):
    if distance <= 0 or efficiency <= 0 or price <= 0:
        return None, "Error: Inputs must be positive numbers!"
    fuel_needed = distance / efficiency
    cost = fuel_needed * price
    return cost, None

def save_to_csv(trip_data, filename="fuel_log.csv"):
    file_exists = os.path.isfile(filename)
    with open(filename, 'a', newline='') as f:
        writer = csv.writer(f)
        if not file_exists:
            writer.writerow(["Distance (km)", "Efficiency (km/l)", "Price ($/l)", "Cost ($)"])
        writer.writerow(trip_data)

def main():
    parser = argparse.ArgumentParser(description="Calculate fuel cost for a trip")
    parser.add_argument("--distance", type=float, required=True, help="Trip distance in km")
    parser.add_argument("--efficiency", type=float, required=True, help="Fuel efficiency in km/liter")
    parser.add_argument("--price", type=float, required=True, help="Fuel price per liter in $")
    parser.add_argument("--save", action="store_true", help="Save results to CSV")
    args = parser.parse_args()

    cost, error = calculate_fuel_cost(args.distance, args.efficiency, args.price)
    if error:
        print(error)
        return
    print(f"Total fuel cost: ${cost:.2f}")
    if args.save:
        save_to_csv([args.distance, args.efficiency, args.price, round(cost, 2)])
        print(f"Saved to fuel_log.csv")

if __name__ == "__main__":
    main()

Example usage:

python fuel_cost.py --distance 300 --efficiency 14 --price 1.7 --save

This outputs the cost and saves the data to a CSV if --save is used. I’m aiming to make it as intuitive as the calculator at kalkulatorpaliwa.com.pl, but I’m hitting some roadblocks as a beginner. Questions for the community:

  • Is argparse the best choice for a command-line interface, or should I look into something like click?
  • How can I improve error handling for edge cases (e.g., non-numeric inputs or file write issues)?
  • Any suggestions for adding stats, like average cost per km across multiple trips in the CSV?

I’d love to hear your thoughts on improving the code or cool features to add (maybe integrating an API for fuel prices?). Thanks for any advice, and thrilled to be part of this community!

1 Like

IMO for a simple, unitask, command line application argparse is a great choice. You might also consider dykes which is a wrapper around argparse that gives you a typed response. While I love click and use it I find for something like this it is somewhat overkill and you might end up spending more time dealing with it rather than writing the actual business logic.

One of the benefits of argparse is that, when you give it the type, you get the type back - it handles that for you. I would check the validity of the arguments (i.e. >= 0) before calling calculate_fuel_cost and give the user an indication of which one is invalid. If you are worried about file write issues, you can wrap the file processes in a try/except and handle any exceptions that might come up.

I think statistical analysis of the data is a good thing you might want to add - if you do you’ll probably find that you either want a separate tool to handle that or that you do want to use something more robust, like click to allow for multiple commands.

The only other thing I would suggest is that you switch from float to decimal.Decimal for your values to get a higher level of precision than float allows for.

Overall it looks like a nice little app.

Thanks for the awesome feedback! I really appreciate you taking the time to dive into my project. Your point about sticking with argparse for a simple CLI tool makes a lot of sense—glad to know it’s a solid choice for a beginner like me. I hadn’t heard of dykes before, so I’ll definitely check it out for typed responses. click does sound like it could be overkill for this, but I’m curious—would you recommend it if I add more complex features later, like subcommands for different types of analysis?

I love the idea of validating inputs before calling calculate_fuel_cost. I’ll add checks for negative values and give specific error messages (e.g., “Distance must be positive!”). Wrapping file operations in a try/except block is a great tip too—I’ll implement that to handle CSV write errors gracefully.

Switching to decimal.Decimal for better precision is a fantastic suggestion! I hadn’t considered floating-point issues. Would you recommend using Decimal for all calculations, or just for the final output to avoid rounding errors?

For statistical analysis, I’m thinking of adding basic stats like average MPG or cost per km across trips in the CSV. Do you have a favorite library for this? I was leaning toward pandas for its data handling, but is there a lighter alternative for a small script? Also, if I stick with argparse, how would you handle multiple commands (e.g., one for calculating, another for stats) without making the code too messy?

Thanks again for the insights! Excited to keep tweaking this and learning from the community.

1 Like

I would using decimal.Decimal from the start to avoid weirdness.
If you are planning on adding sub-commands then click is definitely the way to go.
I can’t offer any real insights into statistical analysis libraries - it’s not something I’ve worked with.

Hello,

you can improve the user experience by adding a GUI interface. The library package to use is tkinter since it already comes bundled with your Python download. This way, you don’t have to deal with the command prompt directly.

You can do this with the openpyxl library package. I would recommend first creating an Excel file and saving it to a folder. The 'openpyxl library allows you to both read and write directly to Excel files (worksheets within files and particular cells within worksheets) which makes it an ideal choice for this application. It is actually pretty easy to use.

Hope this helps!

Update:

Ok, I clicked the link that you provided. And read this:

In that case, disregard my GUI suggestion. :slightly_smiling_face:

I don’t think there is any reason to use Decimal – there’s no way you need more precision that float provides (a Python float carries about 15 decimal digits of precision – I’m sure you don’t know how much fuel you’ve burned to that precision!

This is a common mis-conception – decimal numbers are not more precise or accurate that binary floats [*] – they can exactly represent decimal fractions – e.g. 1/10 (0.1), but they can’t represent any rational number, e.g (1/3 or 0.3333333333333…0).

So decimal numbers are really only better for human consumption. And for that, you will want to pay a bit of attention to how you output your numbers, which you can do by using formatting to specify precision.

As for statistics and pandas – the stdlib statistics module would be more than up to the task for this. But if you do want to go the pandas route, I’d use it to read and write CSV files for you.

I would not use openpyxl – unless you really want Excel files and more features than raw CSV will provide. CSV files are very easy to write, and not hard to read with the csv lib or pandas.

[*] OK, to be clear – the Python Decimal type does provide control over precision, so you can use it to get higher precision, but that’s not because it’s using a decimal representation, only because it has more features. There are variable precision binary float types around, too. And that much precision is irrelevant to this use case.

If you’re dealing with money you should use decimal.Decimal and not float.