Imperial to Metric Conversion (and vice-versa) Script

 Imperial to Metric Conversion (and vice-versa) Script



An idea for a project that I had was one to have a python script that would use functions to convert Imperial values to Metric and also Metric values to Imperial. This is useful here in Canada, where we will often measure temperature in Celcius and distance in kilometers, but then also measure height in feet and weight in pounds! It can all get a bit much to keep track of sometimes.

I wanted to get more familiar with classes in python, so I started with a master 'Conversion' class that would handle the math, and then several local classes for each kind of unit being converted. This is the main class and the units being utilized:

class Converter:

    """

    A class to convert values between different units of measurement.

    Supports temperature, length, volume, and weight conversions.

    """

    def __init__(self):

        """

        Initializes the Converter class with dictionaries mapping units

        within categories to their target unit and conversion function.

        """

        self.conversions = {

            'temperature': {

                'celsius': ('fahrenheit', self.celsius_to_fahrenheit),

                'fahrenheit': ('celsius', self.fahrenheit_to_celsius),

            },

            'length': {

                'kilometers': ('miles', self.kilometers_to_miles),

                'miles': ('kilometers', self.miles_to_kilometers),

                'yards': ('meters', self.yards_to_meters),

                'meters': ('yards', self.meters_to_yards),

                'feet': ('meters', self.feet_to_meters),

                'inches': ('centimeters', self.inches_to_centimeters),

                'centimeters': ('inches', self.centimeters_to_inches),

            },

            'volume': {

                'gallon': ('liter', self.gallon_to_liter),

                'liter': ('gallon', self.liter_to_gallon),

                'quart': ('liter', self.quart_to_liter),

                'pint': ('liter', self.pint_to_liter),

            },

            'weight': {

                'ton': ('tonne', self.ton_to_tonne),

                'tonne': ('ton', self.tonne_to_ton),

                'pound': ('kilogram', self.pound_to_kilogram),

                'kilogram': ('pound', self.kilogram_to_pound),

                'ounce': ('gram', self.ounce_to_gram),

                'gram': ('ounce', self.gram_to_ounce),

            }

        }


It was important to get the units right and try to avoid things like typos and inconsistencies with the Flask script. Once this was done, I moved on to a catch-all script that would take the formulas from all of the local classes and use them to provide a final result:

    def convert(self, value, from_unit, category):

        """

        Converts a given value from one unit to another within a specified category.


        Parameters:

        - value: The numerical value to convert.

        - from_unit: The unit of the value to convert from.

        - category: The category of the conversion (e.g., 'temperature').


        Returns:

        A tuple of the converted value and its unit.

        """

        if category in self.conversions and from_unit in self.conversions[category]:

            to_unit, conversion_function = self.conversions[category][from_unit]

            result = conversion_function(value)

            return result, to_unit

        else:

            raise ValueError("Unsupported unit or category for conversion")


Some docstrings were added to provide additional detail, always a good practice. In addition, type hints could have been added, so I will look to that for a future update. An 'else' statement is provided in case of any unexpected values being input. Finally some local classes, as mentioned, were added to provide the actual, discrete formulas for each unit of measurement - for example:

    """

    Temperature Conversion

    """


    @staticmethod

    def celsius_to_fahrenheit(value):

        return round((value * 9 / 5) + 32, 2)


    @staticmethod

    def fahrenheit_to_celsius(value):

        return round((value - 32) * 5 / 9, 2)


Something similar was done for the distance, weight, and volume conversions as well. This provided the backbone of the interface. Now Flask isn't really my area of expertise, but briefly a script was made that would call on our conversion code and display them as results on the webpage:

@app.route("/", methods=["GET", "POST"])

def imperial_to_metric():

    result = None

    if request.method == "POST":

        try:

            value = int(request.form["value"])

            unit = request.form["unit"]

            converter = Converter()

            result, _ = converter.convert(value, unit, "temperature" if unit in ["fahrenheit", "celsius"] else "length" if unit in ["miles", "yards", "feet", "inches", "kilometers", "meters", "centimeters"] else "volume" if unit in ["gallon", "quart", "pint", "liter"] else "weight")

            result = f"{value} {unit} is {result} {converter.conversions['temperature'][unit][0] if unit in ['fahrenheit', 'celsius'] else converter.conversions['length'][unit][0] if unit in ['miles', 'yards', 'feet', 'inches', 'kilometers', 'meters', 'centimeters'] else converter.conversions['volume'][unit][0] if unit in ['gallon', 'quart', 'pint', 'liter'] else converter.conversions['weight'][unit][0]}"

        except ValueError as e:

            result = "Error: " + str(e)

        except Exception as e:

            result = "An error occurred"

    return render_template_string(html_template, result=result)

And of course, something similar was done for the Metric to Imperial conversions. That is the gist of it, I do like the results but down the road I would like to add more fine-grained input values - for example, the ability to add feet and inches and convert them to metric. For now, you can view the results at:

https://vshideler.pythonanywhere.com/

Comments

Popular posts from this blog

The Basics of IICS

Real Estate Data Pipeline, Part 2

Real Estate Data Pipeline, Part 1