Setup a conversion rate in pint in python

94 views Asked by At

I have this problem I'd like to solve with python pint.

  • 0.29 points / minutes
  • 118 points / (17.35 usd)
  • How much is 5 minutes in usd ?

I have then 2 new abstract units "points" and "usd" and reuse the "time" unit "minute".

I can use simple mathematical operations for that :

import pint
units = pint.UnitRegistry()

units.define("usd = [usd]")
units.define("points = [points]")

a = 0.29 * units.points / units.minutes
b = 118 * units.points / (17.35 * units.usd)

Now I was to have 5 minutes to usd but of course I need to to the computation myself, do I multiply or divide by a ? Same for b ? The answer is one of those line:

5 * units.minutes * a * b
5 * units.minutes * a / b
5 * units.minutes / a * b
5 * units.minutes / a / b

Of course, only one of those line gives unit "usd". So I could compute all the possible ones and keep the one where the unit is usd. Turns out it's the second one.

I wish the library would find a path to convert my "5 minutes" using those relations in this context.

I have read about pint contexts but I didn't find any working solution. I was hoping to be able to write something like this:

(5 * units.minutes).to(units.usd, mycontext_with_the_two_equations)
1

There are 1 answers

1
Jemshit On BEST ANSWER

Manual

From that conversion table, you need to find "usd per minute" which is a/b:

a/b = (0.29 * units.points / units.minutes) / (118 * units.points / (17.35 * units.usd)) 
= (0.29 * (17.35 * units.usd)) / (units.minutes * 118) 
= 0.0426*units.usd / units.minutes

Then you can multiply it with 5, here is the full code:

import pint
units = pint.UnitRegistry()

units.define("usd = [usd]")
units.define("points = [points]")

points_per_minute = 0.29 * units.points / units.minute
points_per_usd = 118 * units.points / (17.35 * units.usd)
usd_per_minute = points_per_minute / points_per_usd

value_in_usd = (5 * units.minute) * usd_per_minute
print(f"5 minutes is worth approximately: {value_in_usd:.2f}")
# 5 minutes is worth approximately: 0.21 usd

Context A

You create context, register you conversion table to that context. Then you add that context into unit registry and now you can use unit registry like units().to()

import pint

units = pint.UnitRegistry()
units.define("usd = [usd]")
units.define("points = [points]")

context = pint.Context("minute-points-usd")
context.add_transformation("minute", "points", lambda ureg, x: x * 0.29 * ureg.points / ureg.minute)
context.add_transformation("points", "usd", lambda ureg, x: x / (118 * ureg.points / (17.35 * ureg.usd)))
units.add_context(context)
a = units("5 min").to("usd", "minute-points-usd")
print(a)

Context B

Same like above example, but this time you enter context using with statement:

import pint

units = pint.UnitRegistry()
units.define("usd = [usd]")
units.define("points = [points]")

c = pint.Context("minute-points-usd")
c.add_transformation("minute", "points", lambda ureg, x: x * 0.29 * ureg.points / ureg.minute)
c.add_transformation("points", "usd", lambda ureg, x: x / (118 * ureg.points / (17.35 * ureg.usd)))
units.add_context(c)

with units.context("minute-points-usd"):
    value_in_usd = (5 * units.minute).to("usd")
    #value_in_usd = units("5 min").to("usd")