diff --git a/features/column-formatters.feature b/features/column-formatters.feature index 4567ed48..7b8b8659 100644 --- a/features/column-formatters.feature +++ b/features/column-formatters.feature @@ -16,3 +16,22 @@ Feature: Column formatters | input | | floats | | integers | + + Scenario Outline: Unit formatter + Given an instance of toyplot.format.UnitFormatter + Then formatting with the toyplot.format.UnitFormatter should produce valid output + + Examples: + | input | + | inch units | + | point units | + + Scenario Outline: Currency formatter + Given an instance of toyplot.format.CurrencyFormatter + Then formatting with the toyplot.format.CurrencyFormatter should produce valid output + + Examples: + | input | + | Canadian currency | + | European currency | + | British currency | diff --git a/features/steps/format.py b/features/steps/format.py index 61f0b62a..1cd9fbb7 100644 --- a/features/steps/format.py +++ b/features/steps/format.py @@ -54,3 +54,68 @@ def step_impl(context): nose.tools.assert_equal(prefix, "1") nose.tools.assert_equal(separator, "") nose.tools.assert_equal(suffix, "") + + +@given(u'an instance of toyplot.format.UnitFormatter') +def step_impl(context): + context.formatter = toyplot.format.UnitFormatter() + + +@then( + u'formatting inch units with the toyplot.format.UnitFormatter should produce valid output') +def step_impl(context): + val = context.formatter.format(12.2, "inches") + prefix, separator, suffix, units = val + nose.tools.assert_equal(prefix, "12") + nose.tools.assert_equal(separator, ".") + nose.tools.assert_equal(suffix, "2") + nose.tools.assert_equal(units, "in") + + +@then( + u'formatting point units with the toyplot.format.UnitFormatter should produce valid output') +def step_impl(context): + val = context.formatter.format(5.1, "points") + prefix, separator, suffix, units = val + nose.tools.assert_equal(prefix, "5") + nose.tools.assert_equal(separator, ".") + nose.tools.assert_equal(suffix, "1") + nose.tools.assert_equal(units, "pt") + + +@given(u'an instance of toyplot.format.CurrencyFormatter') +def step_impl(context): + context.formatter = toyplot.format.CurrencyFormatter(curr="cad") + + +@then( + u'formatting Canadian currency with the toyplot.format.CurrencyFormatter should produce valid output') +def step_impl(context): + codes, prefix, dp, suffix = context.formatter.format(100.00) + nose.tools.assert_equal(codes, "$") + nose.tools.assert_equal(prefix, "100") + nose.tools.assert_equal(dp, ".") + nose.tools.assert_equal(suffix, "00") + + +@then( + u'formatting European currency with the toyplot.format.CurrencyFormatter should produce valid output') +def step_impl(context): + context.formatter = toyplot.format.CurrencyFormatter(curr="eur") + val = context.formatter.format(9000.56) + codes, prefix, dp, suffix = val + nose.tools.assert_equal(codes, "€") + nose.tools.assert_equal(prefix, "9,000") + nose.tools.assert_equal(dp, ".") + nose.tools.assert_equal(suffix, "56") + +@then( + u'formatting British currency with the toyplot.format.CurrencyFormatter should produce valid output') +def step_impl(context): + context.formatter = toyplot.format.CurrencyFormatter(curr="gbp") + val = context.formatter.format(23423410.5) + codes, prefix, dp, suffix = val + nose.tools.assert_equal(codes, "£") + nose.tools.assert_equal(prefix, "23,423,410") + nose.tools.assert_equal(dp, ".") + nose.tools.assert_equal(suffix, "50") diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/format_tests.py b/tests/format_tests.py new file mode 100644 index 00000000..97623c99 --- /dev/null +++ b/tests/format_tests.py @@ -0,0 +1,12 @@ +import toyplot +import nose.tools + +def test_float_formatter(): + formatter = toyplot.format.UnitFormatter() + val = formatter.format(12.2, "inches") + nose.tools.assert_equal(1, val) + +def test_currency_formatter(): + formatter = toyplot.format.CurrencyFormatter(curr="gbp") + val = formatter.format(23423410.5) + nose.tools.assert_equal(1, val) diff --git a/toyplot/format.py b/toyplot/format.py index ad08e918..83f9f031 100644 --- a/toyplot/format.py +++ b/toyplot/format.py @@ -71,3 +71,92 @@ def format(self, value): if len(formatted) == 1: return formatted[0], "", "" return formatted[0], ".", formatted[1] + + +class UnitFormatter(Formatter): + """Formats values with corresponding units + """ + + def __init__(self, format="{:.6}", nanshow=True): + self._format = format + self._nanshow = nanshow + + def format(self, value, units): + + if units not in UnitFormatter._units: + raise Exception("Incorrect type of units provided") + + if isinstance(value, six.string_types): + return value, "", "" + + if numpy.isnan(value) and not self._nanshow: + return "", "", "" + + formatted = self._format.format(value).split(".") + if len(formatted) == 1: + return formatted[0], "", "" + return formatted[0], ".", formatted[1], UnitFormatter._units[units] + + +UnitFormatter._units = { + "centimeter": "cm", + "centimeters": "cm", + "cm": "cm", + "decimeter": "dm", + "decimeters": "dm", + "dm": "dm", + "in": "in", + "inch": "in", + "inches": "in", + "m": "m", + "meter": "m", + "meters": "m", + "millimeter": "mm", + "millimeters": "mm", + "mm": "mm", + "pc": "pc", + "pica": "pc", + "picas": "pc", + "pixel": "px", + "pixels": "px", + "point": "pt", + "points": "pt", + "pt": "pt", + "px": "px", +} + + + +class CurrencyFormatter(Formatter): + """Formats currency value with corresponding codes + places: required number of places after the decimal point + curr: optional currency symbol before the sign (may be blank) + sep: optional grouping separator (comma, period, space, or blank) + dp: decimal point indicator (comma or period) + only specify as blank when places is zero + """ + def __init__(self, format="{:,.2f}", nanshow=True, curr='$', + sep=',', dp='.',): + self._format = format + self._nanshow = nanshow + self._curr = curr + self._sep = sep + self._dp = dp + + if self._curr not in CurrencyFormatter._codes: + raise Exception("Incorrect currency provided") + + def format(self, value): + formatted = self._format.format(value).split(".") + + return CurrencyFormatter._codes[self._curr], formatted[0], self._dp, formatted[1] + + +CurrencyFormatter._codes = { + "aud": "$", + "cad": "$", + "eur": "€", + "gbp": "£", + "hkd": "HK$", + "usd": "$", +}