From 6708ef1bdfea27c9ad3ce933ceec2fc73a8da9ac Mon Sep 17 00:00:00 2001 From: Joe Jevnik Date: Wed, 27 Jul 2016 23:28:02 -0400 Subject: [PATCH] ENH: update assets-db-error-msg --- tests/test_assets.py | 16 ++++++++++----- zipline/assets/asset_writer.py | 36 ++++++++++++++++++++++++++-------- zipline/utils/range.py | 10 ++++++++++ 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/tests/test_assets.py b/tests/test_assets.py index ac725649..b81fac57 100644 --- a/tests/test_assets.py +++ b/tests/test_assets.py @@ -642,10 +642,16 @@ class AssetFinderTestCase(WithTradingCalendar, ZiplineTestCase): self.assertEqual( str(e.exception), - "Ambiguous ownership of 'MULTIPLE', multiple companies held this" - " ticker over the following ranges:\n" - "[('2010-01-01 00:00:00', '2012-01-01 00:00:00')," - " ('2011-01-01 00:00:00', '2012-01-01 00:00:00')]", + "Ambiguous ownership for 1 symbol, multiple assets held the" + " following symbols:\n" + "MULTIPLE:\n" + " intersections: (('2010-01-01 00:00:00', '2012-01-01 00:00:00')," + " ('2011-01-01 00:00:00', '2012-01-01 00:00:00'))\n" + " start_date end_date\n" + " sid \n" + " 1 2010-01-01 2012-01-01\n" + " 2 2010-01-01 2013-01-01\n" + " 3 2011-01-01 2012-01-01" ) def test_lookup_generic(self): @@ -1381,7 +1387,7 @@ class TestAssetDBVersioning(ZiplineTestCase): downgrade(self.engine, 3) metadata = sa.MetaData(conn) metadata.reflect(bind=self.engine) - check_version_info(metadata.tables['version_info'], 3) + check_version_info(conn, metadata.tables['version_info'], 3) self.assertFalse('exchange_full' in metadata.tables) # now go all the way to v0 diff --git a/zipline/assets/asset_writer.py b/zipline/assets/asset_writer.py index ecf4d7b3..35084e6c 100644 --- a/zipline/assets/asset_writer.py +++ b/zipline/assets/asset_writer.py @@ -226,19 +226,39 @@ def _split_symbol_mappings(df): end_date. """ mappings = df[list(mapping_columns)] + ambigious = {} for symbol in mappings.symbol.unique(): persymbol = mappings[mappings.symbol == symbol] - intersections = list(intersecting_ranges( - map(from_tuple, zip(persymbol.start_date, persymbol.end_date)), - )) + intersections = list(intersecting_ranges(map( + from_tuple, + zip(persymbol.start_date, persymbol.end_date), + ))) if intersections: - raise ValueError( - 'Ambiguous ownership of %r, multiple companies held this' - ' ticker over the following ranges:\n%s' % ( - symbol, - list(map(_format_range, intersections)), + ambigious[symbol] = ( + intersections, + persymbol[['start_date', 'end_date']].astype('datetime64[ns]'), + ) + + if ambigious: + raise ValueError( + 'Ambiguous ownership for %d symbol%s, multiple assets held the' + ' following symbols:\n%s' % ( + len(ambigious), + '' if len(ambigious) == 1 else 's', + '\n'.join( + '%s:\n intersections: %s\n %s' % ( + symbol, + tuple(map(_format_range, intersections)), + # indent the dataframe string + '\n '.join(str(df).splitlines()), + ) + for symbol, (intersections, df) in sorted( + ambigious.items(), + key=first, + ), ), ) + ) return ( df.groupby(level=0).apply(_check_asset_group), df[list(mapping_columns)], diff --git a/zipline/utils/range.py b/zipline/utils/range.py index 45d44b37..0e2f46e1 100644 --- a/zipline/utils/range.py +++ b/zipline/utils/range.py @@ -1,3 +1,4 @@ +from functools import reduce import operator as op from six import PY2 @@ -64,6 +65,15 @@ if PY2: self.stop, (', ' + str(self.step)) if self.step != 1 else '', ) + + def __hash__(self): + return hash((type(self), self.start, self.stop, self.step)) + + def __eq__(self, other): + return reduce( + getattr(self, attr) == getattr(other, attr) + for attr in self.__slots__ + ) else: range = range