示例#1
0
def convert(expression):
    try:
        unitsIndex = units.getIndex()
        expressionUnits = parseExpression(expression, unitsIndex)
        toValueUnit = convertUnit(expressionUnits['fromValueUnit'],
                                  expressionUnits['toUnit'])
        responseMessage = formatValueUnit(toValueUnit)
        responseType = 'success'
    except (IncompatibleCategoriesException,
            InvalidExpressionException) as error:
        responseMessage = str(error)
        responseType = error.__class__.__name__
    except Exception:
        responseMessage = InvalidExpressionException.defaultErrorMessage
        responseType = InvalidExpressionException.__name__
        if os.environ.get('DEBUG'):
            traceback.print_exc()

    log = {
        'command': 'convert',
        'type': responseType,
        'expression': expression,
        'response': responseMessage
    }

    if responseType == 'success':
        log['fullResponse'] = '{} = {}'.format(
            formatValueUnit(expressionUnits['fromValueUnit']),
            formatValueUnit(toValueUnit))

    return log
示例#2
0
def test_normalizeExpression():
    cases = [
        ('Convert 100,000M to cubic foot', '100000 m to ft³'),
        ('100.1fl oz = m²', '100.1 fl.oz = m²'),
        ('1/4€ in ₽', '1/4 € in ₽')
    ]

    unitsIndex = units.getIndex()
    for expression, expectedNormalizedExpression in cases:
        assert normalizeExpression(expression, unitsIndex) == expectedNormalizedExpression
示例#3
0
def test_formatValueUnit():
    cases = [(5.23, 'EUR', '5.23 €'), (123456789, 'FOOT', '123,456,789 ft'),
             (3.140, 'METER', '3.14 m'), (1.5, 'FOOT_SQUARE', '1.5 ft²'),
             (1.0 / 3, 'KILOGRAM', '0.333 kg'), (0, 'HOUR', '0 h'),
             (-100, 'DAY', '-100 d'),
             (1200, 'IMPERIAL_FLUID_OUNCE', '1,200 fl.oz'),
             (1.2, 'KILOMETER_PER_HOUR', '1.2 km/h')]

    unitsIndex = units.getIndex()
    for value, unitName, formattedValueUnit in cases:
        assert formatValueUnit({
            'value': value,
            'unit': unitsIndex[unitName]
        }) == formattedValueUnit
示例#4
0
def test_convertUnit():
    cases = [
        # Length
        ((1, 'FOOT'), (0.3048, 'METER')),
        ((13, 'NAUTICAL_MILE'), (24.076, 'KILOMETER')),
        ((10, 'ANGSTROM'), (1, 'NANOMETER')),
        ((1000, 'ASTRONOMICAL_UNIT'), (0.0048, 'PARSEC')),
        ((1, 'LIGHT_YEAR'), (63241.0771, 'ASTRONOMICAL_UNIT')),

        # Area
        ((50.5, 'FOOT_SQUARE'), (4.6916, 'METER_SQUARE')),
        ((100, 'KILOMETER_SQUARE'), (38.6102, 'MILE_SQUARE')),

        # Volume
        ((1.2, 'METER_CUBIC'), (1200, 'LITER')),
        ((1234, 'MILLILITER'), (1.234, 'LITER')),
        ((12, 'IMPERIAL_GALLON'), (54.5531, 'LITER')),
        ((1, 'CUP'), (250, 'MILLILITER')),
        ((1, 'TEASPOON'), (5, 'MILLILITER')),
        ((1, 'TABLESPOON'), (15, 'MILLILITER')),
        ((1, 'US_FLUID_OUNCE'), (29.5735, 'MILLILITER')),
        ((1, 'US_GILL'), (118.2941, 'MILLILITER')),
        ((1, 'US_PINT'), (473.1765, 'MILLILITER')),
        ((1, 'US_QUART'), (946.3529, 'MILLILITER')),
        ((1, 'US_GALLON'), (3.7854, 'LITER')),

        # Currencies
        ((2, 'USD'), (2, 'USD')),
        ((10.2, 'USD'), (8.5778, 'EUR')),
        ((10.3, 'GBP'), (13.2894, 'USD')),

        # Mass
        ((1.2, 'POUND'), (544.3108, 'GRAM')),
        ((500, 'OUNCE'), (31.25, 'POUND')),

        # Speed
        ((1, 'METER_PER_SECOND'), (3.6, 'KILOMETER_PER_HOUR')),
        ((100, 'MILE_PER_HOUR'), (86.8976, 'KNOT')),
        ((1, 'KILOMETER_PER_SECOND'), (2236.9363, 'MILE_PER_HOUR')),

        # Time
        ((1, 'YEAR'), (365.2425, 'DAY')),
        ((1, 'MILLISECOND'), (1000000, 'NANOSECOND')),

        # Temperature
        ((12, 'CELSIUS'), (12, 'CELSIUS')),
        ((294.5, 'KELVIN'), (21.35, 'CELSIUS')),
        ((0, 'CELSIUS'), (273.15, 'KELVIN')),
        ((3284.9, 'FAHRENHEIT'), (1807.1667, 'CELSIUS')),
        ((394.5, 'CELSIUS'), (742.1, 'FAHRENHEIT')),

        # Density
        ((19.5, 'GRAM_PER_CENTIMETER_CUBIC'), (19500,
                                               'KILOGRAM_PER_METER_CUBIC')),

        # Information
        ((1, 'GIGABYTE'), (1024, 'MEGABYTE')),
        ((1, 'BYTE'), (8, 'BIT')),
        ((1, 'TERABYTE'), (1073741824, 'KILOBYTE')),

        # Pressure
        ((1, 'BAR'), (100000, 'PASCAL')),
        ((1, 'TECHNICAL_ATMOSPHERE'), (98.0665, 'KILOPASCAL')),
        ((1, 'STANDARD_ATMOSPHERE'), (1013.25, 'HECTOPASCAL')),
        ((1, 'TORR'), (133.3224, 'PASCAL')),
        ((1, 'POUND_PER_SQUARE_INCH'), (6894.7238, 'PASCAL')),
        ((1, 'KILOBAR'), (14503.8443, 'POUND_PER_SQUARE_INCH')),
        ((1, 'MEGABAR'), (986923.2667, 'STANDARD_ATMOSPHERE')),

        # Fuel consumption
        ((1, 'MILE_PER_US_GALLON'), (0.4251, 'KILOMETER_PER_LITER')),
        ((1, 'MILE_PER_US_GALLON'), (0.2642, 'MILE_PER_LITER')),
        ((1, 'MILE_PER_US_GALLON'), (1.6093, 'KILOMETER_PER_US_GALON')),

        # Power
        ((1, 'KILOWATT'), (1000, 'WATT')),
        ((1, 'METRIC_HORSEPOWER'), (735.4987, 'WATT')),
        ((1, 'MECHANICAL_HORSEPOWER'), (745.6999, 'WATT')),

        # Torque
        ((1, 'NEWTON_METER'), (0.7376, 'POUND_FOOT')),
        ((1, 'POUND_FOOT'), (1.3558, 'NEWTON_METER')),
    ]

    unitsIndex = units.getIndex()

    # Invalid case
    with pytest.raises(Exception) as cm:
        convertUnit({
            'value': 1.0,
            'unit': unitsIndex['FOOT']
        }, unitsIndex['GRAM'])
        assert str(
            cm.exception
        ) == "Sorry, I can't convert foot to gram (at least in this universe)."

    # Valid cases
    for fromUnit, toUnit in cases:
        fromValueUnit = {
            'value': float(fromUnit[0]),
            'unit': unitsIndex[fromUnit[1]]
        }

        toValueUnit = {
            'value': float(toUnit[0]),
            'unit': unitsIndex[toUnit[1]]
        }

        result = convertUnit(fromValueUnit, toValueUnit['unit'])
        result['value'] = round(result['value'], 4)

        assert result == toValueUnit
示例#5
0
def test_parseExpression():
    cases = [
        # Length
        ('1 ft to m', 1, 'FOOT', 'METER'),
        ('10 meters to kilometer', 10, 'METER', 'KILOMETER'),
        ('1.5 km in hour', 1.5, 'KILOMETER', 'HOUR'),
        ('100,000m to ft', 100000, 'METER', 'FOOT'),
        ('93ft', 93, 'FOOT', 'METER'),
        ('38 meters to', 38, 'METER', 'FOOT'),

        # Area
        ('10 ft² to m²', 10, 'FOOT_SQUARE', 'METER_SQUARE'),
        ('100 km2 to m^2', 100, 'KILOMETER_SQUARE', 'METER_SQUARE'),
        ('1 sq cm to square m', 1, 'CENTIMETER_SQUARE', 'METER_SQUARE'),
        ('1sq centimeters', 1, 'CENTIMETER_SQUARE', 'METER_SQUARE'),

        # Volume
        ('10 fl. oz. to dm³', 10, 'IMPERIAL_FLUID_OUNCE', 'DECIMETER_CUBIC'),
        ('10 fl oz to dm³', 10, 'IMPERIAL_FLUID_OUNCE', 'DECIMETER_CUBIC'),
        ('10 fl.oz to dm³', 10, 'IMPERIAL_FLUID_OUNCE', 'DECIMETER_CUBIC'),
        ('12 in^3=m3', 12, 'INCH_CUBIC', 'METER_CUBIC'),
        ('10 cubic m to cu dm', 10, 'METER_CUBIC', 'DECIMETER_CUBIC'),
        ('1 meter^3', 1, 'METER_CUBIC', 'CENTIMETER_CUBIC'),
        ('1 cup', 1, 'CUP', 'MILLILITER'),

        # Currencies
        ('100 $ to ₽', 100, 'USD', 'RUB'),
        ('100 fr to yen', 100, 'CHF', 'JPY'),
        ('100.50 Nicaraguan Córdoba to rubles', 100.5, 'NIO', 'RUB'),
        ('12 nuevo sol to won', 12, 'PEN', 'KRW'),
        ('1 eur', 1, 'EUR', 'USD'),
        ('1 CZK', 1, 'CZK', 'EUR'),
        ('$1 to CZK', 1, 'USD', 'CZK'),
        ('£ 100', 100, 'GBP', 'USD'),

        # Mass
        ('0.45 KG to G', 0.45, 'KILOGRAM', 'GRAM'),
        ('1 pound', 1, 'POUND', 'GRAM'),

        # Speed
        ('12 km/hr to ft/s', 12, 'KILOMETER_PER_HOUR', 'FOOT_PER_SECOND'),
        ('1 m/s to km/h to mph', 1, 'METER_PER_SECOND', 'MILE_PER_HOUR'),
        ('12 m/s', 12, 'METER_PER_SECOND', 'KILOMETER_PER_HOUR'),

        # Time
        ('100 d to yr', 100, 'DAY', 'YEAR'),
        ('1230s go', 1230, 'SECOND', 'MILLISECOND'),
        ('100 yr =', 100, 'YEAR', 'DAY'),

        # Temperature
        ('100.5 °C to F', 100.5, 'CELSIUS', 'FAHRENHEIT'),
        ('34 K = C', 34, 'KELVIN', 'CELSIUS'),
        ('100 C', 100, 'CELSIUS', 'FAHRENHEIT'),
        ('23 K', 23, 'KELVIN', 'CELSIUS'),

        # Density
        ('100 g/cm³ to kg/m³', 100, 'GRAM_PER_CENTIMETER_CUBIC', 'KILOGRAM_PER_METER_CUBIC'),
        ('19 gram per cubic cm to kilograms per cu metre', 19, 'GRAM_PER_CENTIMETER_CUBIC', 'KILOGRAM_PER_METER_CUBIC'),
        ('10 kg per m to grams per centimeters', 10, 'KILOGRAM_PER_METER_CUBIC', 'GRAM_PER_CENTIMETER_CUBIC'),
        ('1 g/cm to kg/m3', 1, 'GRAM_PER_CENTIMETER_CUBIC', 'KILOGRAM_PER_METER_CUBIC'),
        ('1 kg/m to g/ml', 1, 'KILOGRAM_PER_METER_CUBIC', 'GRAM_PER_MILLILITER'),
        ('1 g/cm', 1, 'GRAM_PER_CENTIMETER_CUBIC', 'KILOGRAM_PER_METER_CUBIC'),

        # Information
        ('1 Mb to kb', 1, 'MEGABYTE', 'KILOBYTE'),
        ('1 gigabyte to kibibyte', 1, 'GIGABYTE', 'KILOBYTE'),
        ('1 mbytes to kbyte', 1, 'MEGABYTE', 'KILOBYTE'),
        ('1 mbit to kibibits', 1, 'MEGABIT', 'KILOBIT'),
        ('1 kilobit to yibit', 1, 'KILOBIT', 'YOTTABIT'),
        ('1 byte', 1, 'BYTE', 'BIT'),
        ('1 bit', 1, 'BIT', 'BYTE'),

        # Pressure
        ('1 hPa to pound-force per square inch', 1, 'HECTOPASCAL', 'POUND_PER_SQUARE_INCH'),
        ('1 lbf/in2 = torr', 1, 'POUND_PER_SQUARE_INCH', 'TORR'),
        ('1 Pa', 1, 'PASCAL', 'HECTOPASCAL'),

        # Torque
        ('1 n m to lbf ft', 1, 'NEWTON_METER', 'POUND_FOOT'),
    ]

    # invalidExpressionError = "Sorry, I don't understand your question. I'm just a bot :-( Please ask something simple like '100 ft to m'."
    invalidValueErrorTemplate = "Sorry, I don't understand the number '{}'. Please type it in a more ordinary way, like 100 or 12.5"
    invalidUnitErrorTemplate = "Sorry, I'm just a stupid bot :-( I don't know what does '{}' mean. " \
        + "But my master probably does. I'd ask him to teach me."

    invalidTestCases = [
        ('1 фут в метры', invalidUnitErrorTemplate.format('фут')),
        ('1/4 inch to cm', invalidValueErrorTemplate.format('1/4'))
    ]

    unitsIndex = units.getIndex()
    for expression, value, fromUnitName, toUnitName in cases:
        assert parseExpression(expression, unitsIndex) == {
            'fromValueUnit': {
                'value': value,
                'unit': unitsIndex[fromUnitName]
            },
            'toUnit': unitsIndex[toUnitName]
        }

    for expression, errorMessage in invalidTestCases:
        with pytest.raises(InvalidExpressionException) as cm:
            parseExpression(expression, unitsIndex)
            assert cm.exception == errorMessage
示例#6
0
import sys
sys.path.append('.')
from chalicelib.modules.parser import parseExpression, parseMessageText  # noqa: E402
from chalicelib.modules.converter import convertUnit  # noqa: E402
from chalicelib.modules.formatter import formatValueUnit  # noqa: E402
from chalicelib import units  # noqa: E402

if len(sys.argv) < 2:
    expressions = [line.strip() for line in sys.stdin]
else:
    expressions = [' '.join(sys.argv[1:]).strip()]

unitsIndex = units.getIndex()
for expression in expressions:
    try:
        units = parseExpression(
            parseMessageText(expression)['expression'], unitsIndex)
        toValueUnit = convertUnit(units['fromValueUnit'], units['toUnit'])
        print(f'{expression}: {formatValueUnit(toValueUnit)}')
    except Exception as error:
        print('{:32s} {}'.format(error.__class__.__name__, expression))