diff --git a/.coveragerc b/.coveragerc index a7ee641e0..ad3153683 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,3 +1,3 @@ [run] -include = - arrow/*.py +branch = True +source = arrow diff --git a/.travis.yml b/.travis.yml index 090e242d4..61ea1f3eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,3 +12,4 @@ install: - if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then make build34; fi - if [[ $TRAVIS_PYTHON_VERSION == '3.5' ]]; then make build35; fi script: make test +after_success: codecov diff --git a/Makefile b/Makefile index 966744a52..bd5622a40 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ build35: test: rm -f .coverage - . local/bin/activate && nosetests --all-modules --with-coverage arrow tests + . local/bin/activate && nosetests docs: touch docs/index.rst diff --git a/README.rst b/README.rst index 5a1bd0094..3f1ea7b4f 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,17 @@ Arrow - Better dates & times for Python ======================================= -.. image:: https://travis-ci.org/crsmithdev/arrow.png +.. image:: https://travis-ci.org/crsmithdev/arrow.svg :alt: build status :target: https://travis-ci.org/crsmithdev/arrow -.. image:: https://pypip.in/d/arrow/badge.png - :alt: downloads +.. image:: https://codecov.io/github/crsmithdev/arrow.svg?branch=master + :target: https://codecov.io/github/crsmithdev/arrow + :alt: Codecov + +.. image:: https://img.shields.io/pypi/v/arrow.svg :target: https://crate.io/packages/arrow + :alt: downloads Documentation: `arrow.readthedocs.org `_ --------------------------------------------------------------------------------- diff --git a/arrow/locales.py b/arrow/locales.py index 4041aebb8..cfe6d72e9 100644 --- a/arrow/locales.py +++ b/arrow/locales.py @@ -760,9 +760,7 @@ class UkrainianLocale(SlavicBaseLocale): day_abbreviations = ['', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'нд'] -class GermanLocale(Locale): - - names = ['de', 'de_de'] +class _DeutschLocaleCommonMixin(object): past = 'vor {0}' future = 'in {0}' @@ -786,65 +784,39 @@ class GermanLocale(Locale): '', 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ] + month_abbreviations = [ '', 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez' ] day_names = [ - '', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', - 'Samstag', 'Sonntag' + '', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', + 'Samstag', 'Sonntag' ] - day_abbreviations = ['', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'] + day_abbreviations = [ + '', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So' + ] def _ordinal_number(self, n): return '{0}.'.format(n) -class AustriaLocale(Locale): - - names = ['de', 'de_at'] - - past = 'vor {0}' - future = 'in {0}' +class GermanLocale(_DeutschLocaleCommonMixin, Locale): - timeframes = { - 'now': 'gerade eben', - 'seconds': 'Sekunden', - 'minute': 'einer Minute', - 'minutes': '{0} Minuten', - 'hour': 'einer Stunde', - 'hours': '{0} Stunden', - 'day': 'einem Tag', - 'days': '{0} Tage', - 'month': 'einem Monat', - 'months': '{0} Monaten', - 'year': 'einem Jahr', - 'years': '{0} Jahren', - } + names = ['de', 'de_de'] - month_names = [ - '', 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', - 'August', 'September', 'Oktober', 'November', 'Dezember' - ] + timeframes = _DeutschLocaleCommonMixin.timeframes.copy() + timeframes['days'] = '{0} Tagen' - month_abbreviations = [ - '', 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', - 'Okt', 'Nov', 'Dez' - ] - day_names = [ - '', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', - 'Samstag', 'Sonntag' - ] +class AustriaLocale(_DeutschLocaleCommonMixin, Locale): - day_abbreviations = [ - '', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So' - ] + names = ['de', 'de_at'] - def _ordinal_number(self, n): - return '{0}.'.format(n) + timeframes = _DeutschLocaleCommonMixin.timeframes.copy() + timeframes['days'] = '{0} Tage' class NorwegianLocale(Locale): diff --git a/requirements.txt b/requirements.txt index 9d4e50993..52c4ccaf3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +codecov==1.6.3 python-dateutil==2.1 nose==1.3.0 nose-cov==1.6 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..dbf2184b1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,11 @@ +[nosetests] +where = tests +verbosity = 2 + +all-modules = true +with-coverage = true +cover-min-percentage = 100 +cover-package = arrow +cover-erase = true +cover-inclusive = true +cover-branches = true diff --git a/tests/arrow_tests.py b/tests/arrow_tests.py index 508fe3ec4..d0d717d3e 100644 --- a/tests/arrow_tests.py +++ b/tests/arrow_tests.py @@ -413,11 +413,10 @@ def test_to(self): dt_from = datetime.now() arrow_from = arrow.Arrow.fromdatetime(dt_from, tz.gettz('US/Pacific')) - result = arrow_from.to('UTC') - expected = dt_from.replace(tzinfo=tz.gettz('US/Pacific')).astimezone(tz.tzutc()) - assertEqual(result.datetime, expected) + assertEqual(arrow_from.to('UTC').datetime, expected) + assertEqual(arrow_from.to(tz.tzutc()).datetime, expected) class ArrowPicklingTests(Chai): diff --git a/tests/factory_tests.py b/tests/factory_tests.py index 35d60edbc..a669e6cfd 100644 --- a/tests/factory_tests.py +++ b/tests/factory_tests.py @@ -84,6 +84,12 @@ def test_one_arg_tzinfo(self): assertDtEqual(self.factory.get(tz.gettz('US/Pacific')), expected) + def test_kwarg_tzinfo(self): + + expected = datetime.utcnow().replace(tzinfo=tz.tzutc()).astimezone(tz.gettz('US/Pacific')) + + assertDtEqual(self.factory.get(tzinfo=tz.gettz('US/Pacific')), expected) + def test_one_arg_iso_str(self): dt = datetime.utcnow() diff --git a/tests/formatter_tests.py b/tests/formatter_tests.py index 5b64afad0..23a977c6e 100644 --- a/tests/formatter_tests.py +++ b/tests/formatter_tests.py @@ -127,3 +127,8 @@ def test_am_pm(self): dt = datetime(2012, 1, 1, 13) assertEqual(self.formatter._format_token(dt, 'a'), 'pm') assertEqual(self.formatter._format_token(dt, 'A'), 'PM') + + def test_nonsense(self): + dt = datetime(2012, 1, 1, 11) + assertEqual(self.formatter._format_token(dt, None), None) + assertEqual(self.formatter._format_token(dt, 'NONSENSE'), None) diff --git a/tests/locales_tests.py b/tests/locales_tests.py index 42a5a6fab..95a7337d4 100644 --- a/tests/locales_tests.py +++ b/tests/locales_tests.py @@ -90,6 +90,11 @@ def test_ordinal_number(self): assertEqual(self.locale.ordinal_number(123), '123rd') assertEqual(self.locale.ordinal_number(124), '124th') + def test_meridian_invalid_token(self): + assertEqual(self.locale.meridian(7, None), None) + assertEqual(self.locale.meridian(7, 'B'), None) + assertEqual(self.locale.meridian(7, 'NONSENSE'), None) + class ItalianLocalesTests(Chai): @@ -172,6 +177,7 @@ def test_format_timeframe(self): assertEqual(self.locale._format_timeframe('hours', -2), '2 tímum') assertEqual(self.locale._format_timeframe('hours', 2), '2 tíma') + assertEqual(self.locale._format_timeframe('now', 0), 'rétt í þessu') class MalayalamLocaleTests(Chai): @@ -242,13 +248,17 @@ def setUp(self): def test_format_timeframe(self): assertEqual(self.locale._format_timeframe('hours', 2), '2 hodiny') + assertEqual(self.locale._format_timeframe('hours', 5), '5 hodin') assertEqual(self.locale._format_timeframe('hour', 0), '0 hodin') + assertEqual(self.locale._format_timeframe('hours', -2), '2 hodinami') + assertEqual(self.locale._format_timeframe('hours', -5), '5 hodinami') + assertEqual(self.locale._format_timeframe('now', 0), 'Teď') def test_format_relative_now(self): result = self.locale._format_relative('Teď', 'now', 0) - assertEqual(result, 'Teď') + def test_format_relative_future(self): result = self.locale._format_relative('hodinu', 'hour', 1) @@ -309,3 +319,88 @@ def test_format_relative_future(self): # Not currently implemented def test_ordinal_number(self): assertEqual(self.locale.ordinal_number(1), '1') + + +class FinnishLocaleTests(Chai): + + def setUp(self): + super(FinnishLocaleTests, self).setUp() + + self.locale = locales.FinnishLocale() + + def test_format_timeframe(self): + assertEqual(self.locale._format_timeframe('hours', 2), + ('2 tuntia', '2 tunnin')) + assertEqual(self.locale._format_timeframe('hour', 0), + ('tunti', 'tunnin')) + + def test_format_relative_now(self): + result = self.locale._format_relative(['juuri nyt', 'juuri nyt'], 'now', 0) + assertEqual(result, 'juuri nyt') + + def test_format_relative_past(self): + result = self.locale._format_relative(['tunti', 'tunnin'], 'hour', 1) + assertEqual(result, 'tunnin kuluttua') + + def test_format_relative_future(self): + result = self.locale._format_relative(['tunti', 'tunnin'], 'hour', -1) + assertEqual(result, 'tunti sitten') + + def test_ordinal_number(self): + assertEqual(self.locale.ordinal_number(1), '1.') + + +class GermanLocaleTests(Chai): + + def setUp(self): + super(GermanLocaleTests, self).setUp() + + self.locale = locales.GermanLocale() + + def test_ordinal_number(self): + assertEqual(self.locale.ordinal_number(1), '1.') + + +class HungarianLocaleTests(Chai): + + def setUp(self): + super(HungarianLocaleTests, self).setUp() + + self.locale = locales.HungarianLocale() + + def test_format_timeframe(self): + assertEqual(self.locale._format_timeframe('hours', 2), '2 óra') + assertEqual(self.locale._format_timeframe('hour', 0), 'egy órával') + assertEqual(self.locale._format_timeframe('hours', -2), '2 órával') + assertEqual(self.locale._format_timeframe('now', 0), 'éppen most') + + +class ThaiLocaleTests(Chai): + + def setUp(self): + super(ThaiLocaleTests, self).setUp() + + self.locale = locales.ThaiLocale() + + def test_year_full(self): + assertEqual(self.locale.year_full(2015), '2558') + + def test_year_abbreviation(self): + assertEqual(self.locale.year_abbreviation(2015), '58') + + def test_format_relative_now(self): + result = self.locale._format_relative('ขณะนี้', 'now', 0) + assertEqual(result, 'ขณะนี้') + + def test_format_relative_past(self): + result = self.locale._format_relative('1 ชั่วโมง', 'hour', 1) + assertEqual(result, 'ในอีก 1 ชั่วโมง') + result = self.locale._format_relative('{0} ชั่วโมง', 'hours', 2) + assertEqual(result, 'ในอีก {0} ชั่วโมง') + result = self.locale._format_relative('ไม่กี่วินาที', 'seconds', 42) + assertEqual(result, 'ในอีกไม่กี่วินาที') + + def test_format_relative_future(self): + result = self.locale._format_relative('1 ชั่วโมง', 'hour', -1) + assertEqual(result, '1 ชั่วโมง ที่ผ่านมา') + diff --git a/tests/parser_tests.py b/tests/parser_tests.py index dfd7f8cb6..ed34863e2 100644 --- a/tests/parser_tests.py +++ b/tests/parser_tests.py @@ -37,6 +37,19 @@ def test_parse_multiformat_all_fail(self): with assertRaises(Exception): self.parser._parse_multiformat('str', ['fmt_a', 'fmt_b']) + def test_parse_token_nonsense(self): + parts = {} + self.parser._parse_token('NONSENSE', '1900', parts) + assertEqual(parts, {}) + + def test_parse_token_invalid_meridians(self): + parts = {} + self.parser._parse_token('A', 'a..m', parts) + assertEqual(parts, {}) + self.parser._parse_token('a', 'p..m', parts) + assertEqual(parts, {}) + + class DateTimeParserParseTests(Chai):