class MultiExactMatchTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json', 'indicator_test_data_small.json'] def setUp(self): super(MultiExactMatchTestCase, self).setUp() setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) self.autocomp = Autocompleter("mixed") self.autocomp.store_all() def tearDown(self): setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0) self.autocomp.remove_all() def test_exact_suggest(self): """ Exact matching works in multi-provider autocompleters """ matches = self.autocomp.exact_suggest('ma') self.assertEqual(len(matches['stock']), 1) matches = self.autocomp.exact_suggest('US Unemployment Rate') self.assertEqual(len(matches['ind']), 1) def test_move_exact_matches_to_top(self): """ MOVE_EXACT_MATCHES_TO_TOP works in multi-provider autocompleters """ matches = self.autocomp.suggest('Ma') setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches2 = self.autocomp.suggest('Ma') self.assertNotEqual(matches['stock'][0]['search_name'], matches2['stock'][0]['search_name']) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False)
def test_store_and_remove_all_basic_with_caching(self): """ Storing and removing items all at once works with caching turned on """ # Let's turn on caching because that will store things in Redis and we want to make # sure we clean them up. setattr(auto_settings, 'CACHE_TIMEOUT', 3600) autocomp = Autocompleter("stock") autocomp.store_all() keys = self.redis.hkeys('djac.test.stock') self.assertEqual(len(keys), 101) autocomp = Autocompleter("stock") for i in range(0, 3): autocomp.suggest('a') autocomp.suggest('z') autocomp.exact_suggest('aapl') autocomp.exact_suggest('xyz') autocomp.remove_all() keys = self.redis.keys('djac.test.stock*') self.assertEqual(len(keys), 0) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'CACHE_TIMEOUT', 0)
class MultiMatchingPerfTestCase(AutocompleterTestCase): fixtures = ['stock_test_data.json', 'indicator_test_data.json'] num_iterations = 1000 def setUp(self): self.autocomp = Autocompleter("mixed") self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_repeated_matches(self): """ Matching is fast """ setattr(auto_settings, 'MATCH_OUT_OF_ORDER_WORDS', True) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) for i in range(1, self.num_iterations): self.autocomp.suggest('ma') for i in range(1, self.num_iterations): self.autocomp.suggest('price consumer') for i in range(1, self.num_iterations): self.autocomp.suggest('a') for i in range(1, self.num_iterations): self.autocomp.suggest('non revolving') # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MATCH_OUT_OF_ORDER_WORDS', False) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True)
class IndicatorAliasedMatchTestCase(AutocompleterTestCase): fixtures = ['indicator_test_data_small.json'] def setUp(self): self.autocomp = Autocompleter("indicator_aliased") self.autocomp.store_all() super(IndicatorAliasedMatchTestCase, self).setUp() def tearDown(self): self.autocomp.remove_all() def test_aliasing(self): """ Various permutations of aliased matching work """ matches = self.autocomp.suggest('us consumer price index') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('united states consumer price index') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('us cpi') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('united states consumer price index') self.assertNotEqual(len(matches), 0)
def handle(self, *args, **options): # Configure loggingin level = { 0: logging.WARN, 1: logging.INFO, 2: logging.DEBUG }[options.get('verbosity', 0)] logging.basicConfig(level=level, format="%(name)s: %(levelname)s: %(message)s") self.log = logging.getLogger('commands.autocompleter_init') autocomp = Autocompleter(options["name"]) if options['remove']: self.log.info("Removing all objects for autocompleter: %s" % (options['name'])) autocomp.remove_all() if options['store']: delete_old = options['delete_old'] self.log.info("Storing all objects for autocompleter: %s" % (options['name'])) autocomp.store_all(delete_old=delete_old) if options['clear_cache']: self.log.info("Clearing cache for autocompleter: %s" % (options['name'])) autocomp.clear_cache()
def test_dict_store_and_remove_all_basic_with_caching(self): """ Storing and removing items all at once works with caching turned on on dict ac """ # Let's turn on caching because that will store things in Redis and we want to make # sure we clean them up. setattr(auto_settings, 'CACHE_TIMEOUT', 3600) autocomp = Autocompleter("metric") autocomp.store_all() keys = self.redis.hkeys('djac.test.metric') self.assertEqual(len(keys), 8) autocomp = Autocompleter("metric") for i in range(0, 3): autocomp.suggest('m') autocomp.suggest('e') autocomp.exact_suggest('PE Ratio TTM') autocomp.exact_suggest('Market Cap') autocomp.remove_all() keys = self.redis.keys('djac.test.metric*') self.assertEqual(len(keys), 0) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'CACHE_TIMEOUT', 0)
class MultiMatchingPerfTestCase(AutocompleterTestCase): fixtures = ['stock_test_data.json', 'indicator_test_data.json'] num_iterations = 1000 def setUp(self): super(MultiMatchingPerfTestCase, self).setUp() self.autocomp = Autocompleter("mixed") self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_repeated_matches(self): """ Matching is fast """ setattr(auto_settings, 'MATCH_OUT_OF_ORDER_WORDS', True) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) for i in range(1, self.num_iterations): self.autocomp.suggest('ma') for i in range(1, self.num_iterations): self.autocomp.suggest('price consumer') for i in range(1, self.num_iterations): self.autocomp.suggest('a') for i in range(1, self.num_iterations): self.autocomp.suggest('non revolving') # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MATCH_OUT_OF_ORDER_WORDS', False) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True)
def test_store_and_remove_all_basic_with_caching(self): """ Storing and removing items all the once works with caching turned on """ # Let's turn on caching because that will store things in Redis and we want to make # sure we clean them up. setattr(auto_settings, 'CACHE_TIMEOUT', 3600) autocomp = Autocompleter("stock") autocomp.store_all() keys = self.redis.hkeys('djac.stock') self.assertEqual(len(keys), 101) autocomp = Autocompleter("stock") for i in range(0, 3): autocomp.suggest('a') autocomp.suggest('z') autocomp.exact_suggest('aapl') autocomp.exact_suggest('xyz') autocomp.remove_all() keys = self.redis.keys('djac.stock*') self.assertEqual(len(keys), 0) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'CACHE_TIMEOUT', 0)
class MixedFacetProvidersMatchingTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json', 'indicator_test_data_small.json'] def setUp(self): super(MixedFacetProvidersMatchingTestCase, self).setUp() self.autocomp = Autocompleter('facet_stock_no_facet_ind') self.autocomp.store_all() def test_autocompleter_with_facet_and_non_facet_providers(self): """ Autocompleter with facet and non-facet providers works correctly """ registry.set_autocompleter_setting('facet_stock_no_facet_ind', 'MAX_RESULTS', 100) facets = [ { 'type': 'and', 'facets': [{'key': 'sector', 'value': 'Financial Services'}] } ] matches = self.autocomp.suggest('a') facet_matches = self.autocomp.suggest('a', facets=facets) # because we are using the faceted stock provider in the 'facet_stock_no_facet_ind' AC, # we expect using facets will decrease the amount of results when searching. self.assertEqual(len(matches['faceted_stock']), 25) self.assertEqual(len(facet_matches['faceted_stock']), 2) # since the indicator provider does not support facets, # we expect the search results from both a facet and non-facet search to be the same. self.assertEqual(len(matches['ind']), 16) self.assertEqual(len(matches['ind']), len(facet_matches['ind'])) registry.del_autocompleter_setting('facet_stock_no_facet_ind', 'MAX_RESULTS')
def test_facet_match_with_move_exact_matches(self): """ Exact matching still works with facet suggest """ setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) temp_autocomp = Autocompleter('faceted_stock') temp_autocomp.store_all() facets = [ { 'type': 'or', 'facets': [ {'key': 'sector', 'value': 'Technology'}, {'key': 'industry', 'value': 'Software'} ] } ] matches = temp_autocomp.suggest('Ma', facets=facets) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches2 = temp_autocomp.suggest('Ma', facets=facets) self.assertNotEqual(matches[0]['search_name'], matches2[0]['search_name']) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False) temp_autocomp.remove_all()
class IndicatorAliasedMatchTestCase(AutocompleterTestCase): fixtures = ['indicator_test_data_small.json'] def setUp(self): super(IndicatorAliasedMatchTestCase, self).setUp() self.autocomp = Autocompleter("indicator_aliased") self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_basic_aliasing(self): """ Various permutations of aliased matching work """ matches = self.autocomp.suggest('us consumer price index') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('united states consumer price index') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('us cpi') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('united states consumer price index') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('u s a consumer price index') self.assertNotEqual(len(matches), 0) def test_alias_list_creation(self): """ Alias lists have replacement char variations """ provider = registry._providers_by_ac["indicator_aliased"][0] aliases = provider.get_norm_phrase_aliases() usa_aliases = aliases['usa'] self.assertTrue('u sa' in usa_aliases) self.assertTrue('us a' in usa_aliases) self.assertTrue('u s a' in usa_aliases) self.assertFalse('usa' in usa_aliases) def test_multi_term_aliasing(self): matches = self.autocomp.suggest('us consumer price index') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('usa consumer price index') self.assertNotEqual(len(matches), 0) matches = self.autocomp.suggest('america consumer price index') self.assertNotEqual(len(matches), 0) def test_double_aliasing(self): """ Double aliasing does not happen. California -> CA -> Canada """ matches = self.autocomp.suggest('california unemployment') self.assertEqual(len(matches), 1)
class MultiMatchingTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json', 'indicator_test_data_small.json'] def setUp(self): super(MultiMatchingTestCase, self).setUp() self.autocomp = Autocompleter("mixed") self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_basic_match(self): """ A single autocompleter can return results from multiple models. """ matches = self.autocomp.suggest('Aapl') self.assertEqual(len(matches['stock']), 1) matches = self.autocomp.suggest('US Initial Claims') self.assertEqual(len(matches['ind']), 1) matches = self.autocomp.suggest('m') self.assertEqual(len(matches), 3) matches = self.autocomp.suggest('a') self.assertEqual(len(matches['stock']), 6) self.assertEqual(len(matches['ind']), 4) def test_min_letters_setting(self): """ MIN_LETTERS is respected in multi-type search case. """ matches = self.autocomp.suggest('a') self.assertEqual(len(matches['stock']), 6) self.assertEqual(len(matches['ind']), 4) setattr(auto_settings, 'MIN_LETTERS', 2) matches = self.autocomp.suggest('a') self.assertEqual(matches, {}) setattr(auto_settings, 'MIN_LETTERS', 1) def test_ac_provider_specific_min_letters_setting(self): """ Autocompleter/Provider specific MIN_LETTERS is respected in multi-type search case. """ matches = self.autocomp.suggest('a') self.assertEqual(len(matches['stock']), 6) self.assertEqual(len(matches['ind']), 4) registry.set_ac_provider_setting("mixed", IndicatorAutocompleteProvider, 'MIN_LETTERS', 2) registry.set_ac_provider_setting("mixed", CalcAutocompleteProvider, 'MIN_LETTERS', 2) matches = self.autocomp.suggest('a') self.assertEqual(len(matches), 10) self.assertEqual('ind' not in matches, True) registry.del_ac_provider_setting("mixed", IndicatorAutocompleteProvider, 'MIN_LETTERS') registry.del_ac_provider_setting("mixed", CalcAutocompleteProvider, 'MIN_LETTERS')
class MultiMatchingTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json', 'indicator_test_data_small.json'] def setUp(self): super(MultiMatchingTestCase, self).setUp() self.autocomp = Autocompleter("mixed") self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_basic_match(self): """ A single autocompleter can return results from multiple models. """ matches = self.autocomp.suggest('Aapl') self.assertEqual(len(matches['stock']), 1) matches = self.autocomp.suggest('US Initial Claims') self.assertEqual(len(matches['ind']), 1) matches = self.autocomp.suggest('m') self.assertEqual(len(matches), 3) matches = self.autocomp.suggest('a') self.assertEqual(len(matches['stock']), 10) self.assertEqual(len(matches['ind']), 10) def test_min_letters_setting(self): """ MIN_LETTERS is respected in multi-type search case. """ matches = self.autocomp.suggest('a') self.assertEqual(len(matches['stock']), 10) self.assertEqual(len(matches['ind']), 10) setattr(auto_settings, 'MIN_LETTERS', 2) matches = self.autocomp.suggest('a') self.assertEqual(matches, {}) setattr(auto_settings, 'MIN_LETTERS', 1) def test_ac_provider_specific_min_letters_setting(self): """ Autocompleter/Provider specific MIN_LETTERS is respected in multi-type search case. """ matches = self.autocomp.suggest('a') self.assertEqual(len(matches['stock']), 10) self.assertEqual(len(matches['ind']), 10) registry.set_ac_provider_setting("mixed", IndicatorAutocompleteProvider, 'MIN_LETTERS', 2) registry.set_ac_provider_setting("mixed", CalcAutocompleteProvider, 'MIN_LETTERS', 2) matches = self.autocomp.suggest('a') self.assertEqual(len(matches), 10) self.assertEqual('ind' not in matches, True) registry.del_ac_provider_setting("mixed", IndicatorAutocompleteProvider, 'MIN_LETTERS') registry.del_ac_provider_setting("mixed", CalcAutocompleteProvider, 'MIN_LETTERS')
class StockExactMatchTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json'] def setUp(self): super(StockExactMatchTestCase, self).setUp() setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) self.autocomp = Autocompleter("stock") self.autocomp.store_all() def tearDown(self): setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0) self.autocomp.remove_all() def test_exact_suggest(self): """ Exact matching works """ matches_symbol = self.autocomp.exact_suggest('ma') self.assertEqual(len(matches_symbol), 1) def test_move_exact_matches_to_top_setting(self): """ MOVE_EXACT_MATCHES_TO_TOP works """ matches = self.autocomp.suggest('Ma') setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches2 = self.autocomp.suggest('Ma') self.assertNotEqual(matches[0]['search_name'], matches2[0]['search_name']) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False) def test_move_exact_matches_overridable_at_ac_level(self): """ MOVE_EXACT_MATCHES_TO_TOP can be set at the autocompleter level """ matches = self.autocomp.suggest('Ma') registry.set_autocompleter_setting(self.autocomp.name, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches2 = self.autocomp.suggest('Ma') registry.del_autocompleter_setting(self.autocomp.name, 'MOVE_EXACT_MATCHES_TO_TOP') self.assertNotEqual(matches[0]['search_name'], matches2[0]['search_name']) def test_exact_caching(self): """ Exact caching works """ matches = self.autocomp.exact_suggest('aapl') setattr(auto_settings, 'CACHE_TIMEOUT', 3600) for i in range(0, 10): matches2 = self.autocomp.exact_suggest('aapl') self.assertEqual(len(matches), len(matches2)) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'CACHE_TIMEOUT', 0)
def test_remove_intermediate_results_suggest(self): """ After suggest call, all intermediate result sets are removed """ autocomp = Autocompleter('stock') autocomp.store_all() autocomp.suggest('aapl') keys = self.redis.keys('djac.results.*') self.assertEqual(len(keys), 0)
def test_exact_matches_not_stored_by_default(self): """ Exact matches are not stored by default """ autocomp = Autocompleter("stock") autocomp.store_all() keys = self.redis.keys('djac.test.stock.e.*') self.assertEqual(len(keys), 0) self.assertFalse(self.redis.exists('djac.test.stock.es')) autocomp.remove_all()
class DictProviderMatchingTestCase(AutocompleterTestCase): def setUp(self): super(DictProviderMatchingTestCase, self).setUp() self.autocomp = Autocompleter("metric") self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_basic_match(self): matches = self.autocomp.suggest('m') self.assertEqual(len(matches), 1)
def test_store_and_remove_all_basic(self): """ Storing and removing items all at once works for a dictionary obj autocompleter. """ autocomp = Autocompleter("stock") autocomp.store_all() keys = self.redis.hkeys('djac.test.stock') self.assertEqual(len(keys), 101) autocomp.remove_all() keys = self.redis.keys('djac.test.stock*') self.assertEqual(len(keys), 0)
def test_store_and_remove_all_basic(self): """ Storing and removing items all at once works for a dictionary obj autocompleter. """ autocomp = Autocompleter("stock") autocomp.store_all() keys = self.redis.hkeys('djac.test.stock') self.assertEqual(len(keys), 104) autocomp.remove_all() keys = self.redis.keys('djac.test.stock*') self.assertEqual(len(keys), 0)
def test_store_all_facet_data(self): """ Calling store_all stores all facet data """ autocomp = Autocompleter("faceted_stock") autocomp.store_all() facet_set_name = base.FACET_SET_BASE_NAME % ('faceted_stock', 'sector', 'Technology',) set_length = self.redis.zcard(facet_set_name) self.assertEqual(set_length, 12) facet_map_name = base.FACET_MAP_BASE_NAME % ('faceted_stock',) keys = self.redis.hkeys(facet_map_name) self.assertEqual(len(keys), 104)
def test_dict_store_and_remove_all_basic(self): """ Storing and removing items all at once works for a single-model autocompleter. """ autocomp = Autocompleter("metric") autocomp.store_all() keys = self.redis.hkeys('djac.test.metric') self.assertEqual(len(keys), 8) autocomp.remove_all() keys = self.redis.keys('djac.test.metric') self.assertEqual(len(keys), 0)
def test_remove_intermediate_results_exact_suggest(self): """ After exact_suggest call, all intermediate result sets are removed """ setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 2) autocomp = Autocompleter('stock') autocomp.store_all() autocomp.exact_suggest('aapl') keys = self.redis.keys('djac.results.*') self.assertEqual(len(keys), 0) setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0)
def test_store_and_remove_all_basic(self): """ Storing and removing items all the once works for a single-model autocompleter. """ autocomp = Autocompleter("stock") autocomp.store_all() keys = self.redis.hkeys('djac.stock') self.assertEqual(len(keys), 101) autocomp.remove_all() keys = self.redis.keys('djac.stock*') self.assertEqual(len(keys), 0)
class CalcAutocompleteProviderTestCase(AutocompleterTestCase): fixtures = ['indicator_test_data_small.json'] def setUp(self): super(CalcAutocompleteProviderTestCase, self).setUp() self.autocomp = Autocompleter("metric_aliased") self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_one_way_alias_list_creation(self): """ Test that oneway alias lists are created properly """ provider = registry._providers_by_ac["metric_aliased"][0] aliases = provider.get_norm_phrase_aliases() self.assertTrue('revenue' in aliases) self.assertFalse('turnover' in aliases) def test_one_way_aliasing(self): """ Aliases in get_one_way_phrase_aliases are not aliased both ways. """ matches = self.autocomp.suggest('revenue') self.assertEqual(len(matches), 1) matches = self.autocomp.suggest('Turnover') self.assertEqual(len(matches), 2) def test_one_way_with_two_way_alias_list_creation(self): """ Two way and one way aliases are both included/treated properly """ provider = registry._providers_by_ac["metric_aliased"][0] aliases = provider.get_norm_phrase_aliases() self.assertTrue('ev' in aliases) self.assertTrue('enterprise value' in aliases) self.assertTrue('revenue' in aliases) self.assertFalse('turnover' in aliases) def test_one_way_with_two_way_aliasing(self): """ Aliases in get_one_way_phrase_aliases are not aliased both ways. """ rev_matches = self.autocomp.suggest('revenue') turn_matches = self.autocomp.suggest('Turnover') self.assertFalse(rev_matches == turn_matches) ev_matches = self.autocomp.suggest('EV') ent_val_matches = self.autocomp.suggest('Enterprise Value') self.assertEqual(ev_matches, ent_val_matches)
class StockExactMatchTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json'] def setUp(self): super(StockExactMatchTestCase, self).setUp() setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) self.autocomp = Autocompleter("stock") self.autocomp.store_all() def tearDown(self): setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0) self.autocomp.remove_all() def test_exact_suggest(self): """ Exact matching works """ matches_symbol = self.autocomp.exact_suggest('ma') self.assertEqual(len(matches_symbol), 1) def test_move_exact_matches_to_top_setting(self): """ MOVE_EXACT_MATCHES_TO_TOP works """ matches = self.autocomp.suggest('Ma') setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches2 = self.autocomp.suggest('Ma') self.assertNotEqual(matches[0]['search_name'], matches2[0]['search_name']) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False) def test_exact_caching(self): """ Exact caching works """ matches = self.autocomp.exact_suggest('aapl') setattr(auto_settings, 'CACHE_TIMEOUT', 3600) for i in range(0, 10): matches2 = self.autocomp.exact_suggest('aapl') self.assertEqual(len(matches), len(matches2)) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'CACHE_TIMEOUT', 0)
def test_exact_matches_stored_when_turned_on(self): """ We store exact matches when MAX_EXACT_MATCH_WORDS is turned on """ setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) autocomp = Autocompleter("stock") autocomp.store_all() keys = self.redis.keys('djac.test.stock.e.*') self.assertNotEqual(len(keys), 0) self.assertTrue(self.redis.exists('djac.test.stock.es')) autocomp.remove_all() # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0)
def test_selective_add_and_remove(self): """ We can exclude certain objects from the autocompleter selectively. """ autocomp = Autocompleter("indicator") autocomp.store_all() matches = autocomp.suggest('us unemployment rate') self.assertEqual(len(matches), 1) autocomp.remove_all() autocomp = Autocompleter("indicator_selective") autocomp.store_all() matches = autocomp.suggest('us unemployment rate') self.assertEqual(len(matches), 0) autocomp.remove_all()
def test_store_and_remove_all_multi(self): """ Storing and removing items all the once works for a multi-model autocompleter. """ autocomp = Autocompleter("mixed") autocomp.store_all() keys = self.redis.hkeys('djac.stock') self.assertEqual(len(keys), 101) keys = self.redis.hkeys('djac.ind') self.assertEqual(len(keys), 100) autocomp.remove_all() keys = self.redis.keys('djac.stock*') self.assertEqual(len(keys), 0) keys = self.redis.keys('djac.ind*') self.assertEqual(len(keys), 0) keys = self.redis.keys('djac.mixed*') self.assertEqual(len(keys), 0)
def test_orphan_removal(self): """ test orphan removal """ signal_registry.register(Indicator) autocomp = Autocompleter("indicator") autocomp.store_all() unemployment = Indicator.objects.get(internal_name='unemployment_rate') unemployment.name = 'free parking' unemployment.save() self.assertTrue(autocomp.suggest('free parking')[0]['id'] == 1) self.assertTrue(len(autocomp.suggest('US Unemployment Rate')) == 0) autocomp.remove_all() signal_registry.unregister(Indicator)
def test_provider_specific_max_exact_match_words_setting(self): """ We can store exact matches for 1 individual provider, and not others """ setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) registry.set_provider_setting(IndicatorAutocompleteProvider, 'MAX_EXACT_MATCH_WORDS', 0) autocomp = Autocompleter("mixed") autocomp.store_all() keys = self.redis.keys('djac.test.stock.e.*') self.assertNotEqual(len(keys), 0) self.assertTrue(self.redis.exists('djac.test.stock.es')) keys = self.redis.keys('djac.test.ind.e.*') self.assertEqual(len(keys), 0) self.assertFalse(self.redis.exists('djac.test.ind.es')) autocomp.remove_all() registry.del_provider_setting(IndicatorAutocompleteProvider, 'MAX_EXACT_MATCH_WORDS') setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0)
def test_facet_mismatch_with_move_exact_matches(self): """ Exact matching shouldn't move an object that doesn't have a matching facet value """ # This test case depends on very specific data, which is why this test # issues multiple asserts to check our assumptions setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) temp_autocomp = Autocompleter('faceted_stock') temp_autocomp.store_all() facets = [ { 'type': 'and', 'facets': [ {'key': 'sector', 'value': 'Healthcare'}, {'key': 'industry', 'value': 'Healthcare Plans'}, ] } ] # When gathering suggestions for 'Un', based on the stock_data_small.json fixture, # the only match should be UnitedHealth Group Inc. when using the Healthcare sector facet matches = temp_autocomp.suggest('Un', facets=facets) self.assertEqual(len(matches), 1) self.assertEqual(matches[0]['search_name'], "UNH") # When MOVE_EXACT_MATCHES_TO_TOP is set to True and not using facets, # we are expecting Unilever to be moved to the top. setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches = temp_autocomp.suggest('Un') self.assertEqual(matches[0]['search_name'], "UN") # When MOVE_EXACT_MATCHES_TO_TOP is set to True and we are using the # Healthcare sector facet, we are expecting to see UnitedHealth group # since Unilever belongs to the Consumer Defensive sector matches = temp_autocomp.suggest('Un', facets=facets) self.assertEqual(matches[0]['search_name'], "UNH") # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False) temp_autocomp.remove_all()
def handle(self, *args, **options): # Configure loggingin level = { '0': logging.WARN, '1': logging.INFO, '2': logging.DEBUG }[options.get('verbosity', '0')] logging.basicConfig(level=level, format="%(name)s: %(levelname)s: %(message)s") self.log = logging.getLogger('commands.autocompleter_init') autocomp = Autocompleter(options["name"]) if options['remove']: self.log.info("Removing all objects for autocompleter: %s" % (options['name'])) autocomp.remove_all() if options['store']: self.log.info("Storing all objects for autocompleter: %s" % (options['name'])) autocomp.store_all() if options['clear_cache']: self.log.info("Clearing cache for autocompleter: %s" % (options['name'])) autocomp.clear_cache()
def test_exact_matches_respect_max_words(self): """ We don't store exact matches greater than the number of words in MAX_EXACT_MATCH_WORDS """ setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) autocomp = Autocompleter("stock") autocomp.store_all() matches = autocomp.exact_suggest('International Business Machines Corporation') self.assertEqual(len(matches), 1) autocomp.remove_all() setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 2) autocomp = Autocompleter("stock") autocomp.store_all() matches = autocomp.exact_suggest('International Business Machines Corporation') self.assertEqual(len(matches), 0) autocomp.remove_all() # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0)
def test_exact_matches_respect_max_words(self): """ We don't store exact matches greater than the number of words in MAX_EXACT_MATCH_WORDS """ setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) autocomp = Autocompleter("stock") autocomp.store_all() matches = autocomp.exact_suggest( 'International Business Machines Corporation') self.assertEqual(len(matches), 1) autocomp.remove_all() setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 2) autocomp = Autocompleter("stock") autocomp.store_all() matches = autocomp.exact_suggest( 'International Business Machines Corporation') self.assertEqual(len(matches), 0) autocomp.remove_all() # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0)
def test_store_and_remove_all_multi(self): """ Storing and removing items all at once works for a multi-model autocompleter. """ autocomp = Autocompleter("mixed") autocomp.store_all() keys = self.redis.hkeys('djac.test.stock') self.assertEqual(len(keys), 101) keys = self.redis.hkeys('djac.test.ind') self.assertEqual(len(keys), 100) keys = self.redis.hkeys('djac.test.metric') self.assertEqual(len(keys), 8) autocomp.remove_all() keys = self.redis.keys('djac.test.stock*') self.assertEqual(len(keys), 0) keys = self.redis.keys('djac.test.ind*') self.assertEqual(len(keys), 0) keys = self.redis.keys('djac.test.mixed*') self.assertEqual(len(keys), 0) keys = self.redis.keys('djac.test.metric*') self.assertEqual(len(keys), 0)
class TestExactSuggestView(AutocompleterTestCase): fixtures = ['stock_test_data_small.json'] def setUp(self): super(TestExactSuggestView, self).setUp() setattr(settings, 'MAX_EXACT_MATCH_WORDS', 10) self.autocomp = Autocompleter('stock') self.autocomp.store_all() def tearDown(self): setattr(settings, 'MAX_EXACT_MATCH_WORDS', 0) self.autocomp.remove_all() def test_simple_exact_suggest_match(self): """ ExactSuggestView returns 200 status code and correct number of results on match """ exact_suggest_url = reverse('exact_suggest', kwargs={'name': 'stock'}) matches_symbol = self.autocomp.exact_suggest('ma') response = self.client.get(exact_suggest_url, data={settings.SUGGEST_PARAMETER_NAME: 'ma'}) self.assertEqual(response.status_code, 200) json_response = json.loads(response.content.decode('utf-8')) self.assertGreaterEqual(len(json_response), 1) self.assertEqual(len(json_response), len(matches_symbol)) def test_no_exact_suggest_match(self): """ ExactSuggestView returns 200 status code when there is no match """ url = reverse('exact_suggest', kwargs={'name': 'stock'}) matches_symbol = self.autocomp.exact_suggest('gobblygook') response = self.client.get(url, data={settings.SUGGEST_PARAMETER_NAME: 'gobblygook'}) self.assertEqual(response.status_code, 200) json_response = json.loads(response.content.decode('utf-8')) self.assertEqual(len(json_response), len(matches_symbol))
def test_exact_match_low_score_still_at_top(self): """ Exact matching when using facets should push low scoring object to top if exact match """ # The setup for this test case is that we have three stocks that begin with the letter Z # but limit our MAX_RESULTS setting to just 2. # With MOVE_EXACT_MATCHES_TO_TOP initially set to False, we do not expect to see the # stock with symbol 'Z' in the suggest results since it has the lowest market cap of the 3 which is # what we base the score off of. # Once we set MOVE_EXACT_MATCHES_TO_TOP to True we expect Z to be right at the top even though # it didn't even show up in the previous suggest call since it is an exact match. setattr(auto_settings, 'MAX_RESULTS', 2) setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) temp_autocomp = Autocompleter('faceted_stock') temp_autocomp.store_all() facets = [ { 'type': 'and', 'facets': [ {'key': 'sector', 'value': 'Technology'}, {'key': 'industry', 'value': 'Software'}, ] } ] matches = temp_autocomp.suggest('Z', facets=facets) search_names = [match['search_name'] for match in matches] self.assertTrue('Z' not in search_names) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches = temp_autocomp.suggest('Z', facets=facets) self.assertTrue(matches[0]['search_name'] == 'Z') setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False) setattr(auto_settings, 'MAX_RESULTS', 10) setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0) temp_autocomp.remove_all()
class TextFacetSuggestView(AutocompleterTestCase): fixtures = ['stock_test_data_small.json'] def setUp(self): super(TextFacetSuggestView, self).setUp() self.autocomp = Autocompleter('faceted_stock') self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_facet_suggest_match(self): """ Using suggest view works with facets """ suggest_url = reverse('suggest', kwargs={'name': 'faceted_stock'}) facets = [ { 'type': 'or', 'facets': [{'key': 'sector', 'value': 'Technology'}] } ] matches_symbol = self.autocomp.suggest('a', facets=facets) data = { settings.SUGGEST_PARAMETER_NAME: 'a', settings.FACET_PARAMETER_NAME: json.dumps(facets) } response = self.client.get(suggest_url, data=data) self.assertEqual(response.status_code, 200) json_response = json.loads(response.content.decode('utf-8')) self.assertEqual(len(json_response), len(matches_symbol)) def test_empty_facet_suggest(self): """ An empty facet parameter still returns 200 response """ suggest_url = reverse('suggest', kwargs={'name': 'faceted_stock'}) matches_symbol = self.autocomp.suggest('a', facets=[]) data = { settings.SUGGEST_PARAMETER_NAME: 'a', settings.FACET_PARAMETER_NAME: json.dumps([]) } response = self.client.get(suggest_url, data=data) self.assertEqual(response.status_code, 200) json_response = json.loads(response.content.decode('utf-8')) self.assertEqual(len(json_response), len(matches_symbol)) def test_invalid_facet(self): """ An invalid facet should return a 400 response """ suggest_url = reverse('suggest', kwargs={'name': 'faceted_stock'}) no_type_facets = [ { 'facets': [{'key': 'sector', 'value': 'Technology'}] } ] data = { settings.SUGGEST_PARAMETER_NAME: 'a', settings.FACET_PARAMETER_NAME: json.dumps(no_type_facets) } response = self.client.get(suggest_url, data=data) self.assertEqual(response.status_code, 400)
class MaxResultsMatchingTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json', 'indicator_test_data_small.json'] def setUp(self): super(MaxResultsMatchingTestCase, self).setUp() self.autocomp = Autocompleter('ind_stock') self.autocomp.store_all() def test_max_results_respected(self): """ MAX_RESULTS is respected for multi-type search case """ # set MAX_RESULTS to an arbitrarily large number registry.set_autocompleter_setting('ind_stock', 'MAX_RESULTS', 100) matches = self.autocomp.suggest('a') total_matches_with_large_max_results = len(matches['stock']) + len(matches['ind']) self.assertGreaterEqual(100, total_matches_with_large_max_results) self.assertEqual(41, total_matches_with_large_max_results) registry.set_autocompleter_setting('ind_stock', 'MAX_RESULTS', 4) matches = self.autocomp.suggest('a') total_matches_with_small_max_results = len(matches['stock']) + len(matches['ind']) self.assertEqual(4, total_matches_with_small_max_results) self.assertGreater(total_matches_with_large_max_results, total_matches_with_small_max_results) registry.del_autocompleter_setting('ind_stock', 'MAX_RESULTS') def test_max_results_spreads_results_evenly(self): """ MAX_RESULTS spreads the results among providers equally """ registry.set_autocompleter_setting('ind_stock', 'MAX_RESULTS', 4) matches = self.autocomp.suggest('a') self.assertEqual(4, len(matches['stock']) + len(matches['ind'])) self.assertEqual(len(matches['stock']), len(matches['ind'])) registry.del_autocompleter_setting('ind_stock', 'MAX_RESULTS') def test_max_results_handles_surplus(self): """ Suggest respects MAX_RESULTS while still dealing with surplus """ # we know that there are 16 ind matches and 25 stock matches for 'a' registry.set_autocompleter_setting('ind_stock', 'MAX_RESULTS', 36) matches = self.autocomp.suggest('a') self.assertEqual(16, len(matches['ind'])) self.assertEqual(20, len(matches['stock'])) registry.del_autocompleter_setting('ind_stock', 'MAX_RESULTS') def test_max_results_handles_deficit_less_than_surplus(self): """ MAX_RESULTS stops trying to hand out surplus matches when provider's deficits are met """ # Previous code would have failed on this test case because of an infinite while loop that # failed to break when all provider's deficits were met. The setup requires # there to be at least one provider which will have a deficit less than the total surplus. # In this test case, the total surplus will be 3 (since stock has no matches) and the deficit # for indicators will be 2 (since there are 5 total matches for indicators and 3 slots are # reserved initially) registry.set_autocompleter_setting('ind_stock', 'MAX_RESULTS', 6) matches = self.autocomp.suggest('S&P') self.assertEqual(5, len(matches['ind'])) self.assertEqual(0, len(matches['stock'])) registry.del_autocompleter_setting('ind_stock', 'MAX_RESULTS') def test_max_results_has_hard_limit(self): """ Suggest respects MAX_RESULTS over giving every provider at least 1 result """ registry.set_autocompleter_setting('ind_stock', 'MAX_RESULTS', 1) matches = self.autocomp.suggest('a') # Either stock or indicator matches is empty self.assertEqual(1, len(matches['stock']) + len(matches['ind'])) registry.del_autocompleter_setting('ind_stock', 'MAX_RESULTS')
class StockMatchTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json'] def setUp(self): super(StockMatchTestCase, self).setUp() self.autocomp = Autocompleter("stock") self.autocomp.store_all() def tearDown(self): self.autocomp.remove_all() def test_simple_match(self): """ Basic matching works """ matches_symbol = self.autocomp.suggest('a') self.assertEqual(len(matches_symbol), 10) def test_no_match(self): """ Phrases that match nothing work """ matches_symbol = self.autocomp.suggest('gobblygook') self.assertEqual(len(matches_symbol), 0) def test_dual_term_matches(self): """ Items in autocompleter can match against multiple unique terms """ matches_symbol = self.autocomp.suggest('AAPL') self.assertEqual(len(matches_symbol), 1) matches_name = self.autocomp.suggest('Apple') self.assertEqual(len(matches_name), 1) def test_accented_matches(self): """ Accented phrases match against both their orignal accented form, and their non-accented basic form. """ matches = self.autocomp.suggest('estee lauder') self.assertEqual(len(matches), 1) self.assertEqual(matches[0]['search_name'], 'EL') matches = self.autocomp.suggest(u'estée lauder') self.assertEqual(len(matches), 1) self.assertEqual(matches[0]['search_name'], 'EL') def test_max_results_setting(self): """ MAX_RESULTS is respected. """ matches = self.autocomp.suggest('a') self.assertEqual(len(matches), 10) setattr(auto_settings, 'MAX_RESULTS', 2) matches = self.autocomp.suggest('a') self.assertEqual(len(matches), 2) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MAX_RESULTS', 10) def test_ac_provider_specific_max_results_setting(self): """ Autocompleter/Provider specific MAX_RESULTS is respected """ matches = self.autocomp.suggest('a') self.assertEqual(len(matches), 10) registry.set_ac_provider_setting("stock", StockAutocompleteProvider, 'MAX_RESULTS', 5) matches = self.autocomp.suggest('a') self.assertEqual(len(matches), 5) # Must set the setting back to where it was as it will persist registry.del_ac_provider_setting("stock", StockAutocompleteProvider, 'MAX_RESULTS') def test_caching(self): """ Caching works """ matches = self.autocomp.suggest('a') setattr(auto_settings, 'CACHE_TIMEOUT', 3600) for i in range(0, 3): matches2 = self.autocomp.suggest('a') self.assertEqual(len(matches), len(matches2)) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'CACHE_TIMEOUT', 0) def test_dropped_character_matching(self): """ Searching for things that would be normalized to ' ' do not result in redis errors. """ matches = self.autocomp.suggest('+') self.assertEqual(len(matches), 0) matches = self.autocomp.suggest('NBBC vs Regional - Mid-Atlantic Banks vs Financial') self.assertEqual(len(matches), 0)
class FacetMatchingTestCase(AutocompleterTestCase): fixtures = ['stock_test_data_small.json'] def setUp(self): super(FacetMatchingTestCase, self).setUp() self.autocomp = Autocompleter("faceted_stock") self.autocomp.store_all() def test_facet_or_match(self): """ Matching using facets works with the 'or' type """ facets = [ { 'type': 'or', 'facets': [ {'key': 'sector', 'value': 'Technology'}, {'key': 'sector', 'value': 'Consumer Defensive'}, {'key': 'industry', 'value': 'Thisdoesntexist'} ] } ] matches = self.autocomp.suggest('a', facets=facets) self.assertEqual(len(matches), 4) def test_facet_and_match(self): """ Matching using facets works with the 'and' type """ facets = [ { 'type': 'and', 'facets': [ {'key': 'sector', 'value': 'Technology'}, {'key': 'industry', 'value': 'SectorDoesntExist'} ] } ] matches = self.autocomp.suggest('ch', facets=facets) # since a stock can't have two different values for a sector, we expect calculating an 'and' on # two different sectors to have zero matches self.assertEqual(len(matches), 0) facets = [ { 'type': 'and', 'facets': [ {'key': 'sector', 'value': 'Communication Services'}, {'key': 'industry', 'value': 'Telecom Services'} ] } ] matches = self.autocomp.suggest('ch', facets=facets) self.assertEqual(len(matches), 1) facets = [ { 'type': 'and', 'facets': [ {'key': 'sector', 'value': 'Energy'}, {'key': 'industry', 'value': 'Oil & Gas Integrated'} ] } ] matches = self.autocomp.suggest('ch', facets=facets) self.assertEqual(len(matches), 2) def test_provider_keys_is_not_subset_of_facet_keys(self): """ A provider's facet keys has to match at least one of the requested facet keys to kick in """ facets = [ { 'type': 'and', 'facets': [ {'key': 'thisisfake', 'value': 'Technology'}, ] } ] facet_matches = self.autocomp.suggest('a', facets=facets) regular_matches = self.autocomp.suggest('a') # since the 'thisisfake' key does not exist in our provider, the results for a facet # suggest should be the same as a regular suggest self.assertEqual(facet_matches, regular_matches) def test_provider_keys_is_subset_of_facet_keys_no_match(self): """ A provider which declares one of the requested facet keys but has no matches should not return any results """ facets = [ { 'type': 'and', 'facets': [ {'key': 'sector', 'value': 'ZZ9 Plural Z Alpha'}, ] } ] facet_matches = self.autocomp.suggest('a', facets=facets) regular_matches = self.autocomp.suggest('a') # since the 'sector' key does belong to our faceted stock provider facets, we expected facets # logic to kick in, but with a bogus value there should be no results. self.assertEqual(len(facet_matches), 0) self.assertGreaterEqual(len(regular_matches), 1) def test_facet_doesnt_skew_suggest(self): """ Test that using facets takes the suggest term into consideration """ matches = self.autocomp.suggest('nosearchresultsforthisterm') self.assertEqual(len(matches), 0) facets = [ { 'type': 'or', 'facets': [ {'key': 'sector', 'value': 'Technology'}, ] } ] # we expect that adding facets to a suggest call with no results will not # add any results facet_matches = self.autocomp.suggest('nosearchresultsforthisterm', facets=facets) self.assertEqual(len(facet_matches), 0) def test_facet_match_with_move_exact_matches(self): """ Exact matching still works with facet suggest """ setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) temp_autocomp = Autocompleter('faceted_stock') temp_autocomp.store_all() facets = [ { 'type': 'or', 'facets': [ {'key': 'sector', 'value': 'Technology'}, {'key': 'industry', 'value': 'Software'} ] } ] matches = temp_autocomp.suggest('Ma', facets=facets) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches2 = temp_autocomp.suggest('Ma', facets=facets) self.assertNotEqual(matches[0]['search_name'], matches2[0]['search_name']) # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False) temp_autocomp.remove_all() def test_facet_mismatch_with_move_exact_matches(self): """ Exact matching shouldn't move an object that doesn't have a matching facet value """ # This test case depends on very specific data, which is why this test # issues multiple asserts to check our assumptions setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) temp_autocomp = Autocompleter('faceted_stock') temp_autocomp.store_all() facets = [ { 'type': 'and', 'facets': [ {'key': 'sector', 'value': 'Healthcare'}, {'key': 'industry', 'value': 'Healthcare Plans'}, ] } ] # When gathering suggestions for 'Un', based on the stock_data_small.json fixture, # the only match should be UnitedHealth Group Inc. when using the Healthcare sector facet matches = temp_autocomp.suggest('Un', facets=facets) self.assertEqual(len(matches), 1) self.assertEqual(matches[0]['search_name'], "UNH") # When MOVE_EXACT_MATCHES_TO_TOP is set to True and not using facets, # we are expecting Unilever to be moved to the top. setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches = temp_autocomp.suggest('Un') self.assertEqual(matches[0]['search_name'], "UN") # When MOVE_EXACT_MATCHES_TO_TOP is set to True and we are using the # Healthcare sector facet, we are expecting to see UnitedHealth group # since Unilever belongs to the Consumer Defensive sector matches = temp_autocomp.suggest('Un', facets=facets) self.assertEqual(matches[0]['search_name'], "UNH") # Must set the setting back to where it was as it will persist setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False) temp_autocomp.remove_all() def test_exact_match_low_score_still_at_top(self): """ Exact matching when using facets should push low scoring object to top if exact match """ # The setup for this test case is that we have three stocks that begin with the letter Z # but limit our MAX_RESULTS setting to just 2. # With MOVE_EXACT_MATCHES_TO_TOP initially set to False, we do not expect to see the # stock with symbol 'Z' in the suggest results since it has the lowest market cap of the 3 which is # what we base the score off of. # Once we set MOVE_EXACT_MATCHES_TO_TOP to True we expect Z to be right at the top even though # it didn't even show up in the previous suggest call since it is an exact match. setattr(auto_settings, 'MAX_RESULTS', 2) setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 10) temp_autocomp = Autocompleter('faceted_stock') temp_autocomp.store_all() facets = [ { 'type': 'and', 'facets': [ {'key': 'sector', 'value': 'Technology'}, {'key': 'industry', 'value': 'Software'}, ] } ] matches = temp_autocomp.suggest('Z', facets=facets) search_names = [match['search_name'] for match in matches] self.assertTrue('Z' not in search_names) setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', True) matches = temp_autocomp.suggest('Z', facets=facets) self.assertTrue(matches[0]['search_name'] == 'Z') setattr(auto_settings, 'MOVE_EXACT_MATCHES_TO_TOP', False) setattr(auto_settings, 'MAX_RESULTS', 10) setattr(auto_settings, 'MAX_EXACT_MATCH_WORDS', 0) temp_autocomp.remove_all() def test_facet_works_with_cache(self): """ Caching works with facet suggest """ no_cache_no_facet_matches = self.autocomp.suggest('a') facets = [{'type': 'or', 'facets': [{'key': 'sector', 'value': 'Technology'}]}] no_cache_facet_matches = self.autocomp.suggest('a', facets=facets) setattr(auto_settings, 'CACHE_TIMEOUT', 3600) cache_facet_matches = self.autocomp.suggest('a', facets=facets) cache_no_facet_matches = self.autocomp.suggest('a') self.assertEqual(no_cache_no_facet_matches, cache_no_facet_matches) self.assertEqual(cache_facet_matches, no_cache_facet_matches) setattr(auto_settings, 'CACHE_TIMEOUT', 0) def test_multiple_facet_dicts_match(self): """ Matching with multiple passed in facet dicts works """ facets = [ { 'type': 'and', 'facets': [{'key': 'sector', 'value': 'Communication Services'}] }, { 'type': 'and', 'facets': [{'key': 'industry', 'value': 'Telecom Services'}] } ] matches = self.autocomp.suggest('ch', facets=facets) self.assertEqual(len(matches), 1) facets = [ { 'type': 'and', 'facets': [{'key': 'sector', 'value': 'Energy'}] }, { 'type': 'and', 'facets': [{'key': 'industry', 'value': 'Oil & Gas Integrated'}] }, ] matches = self.autocomp.suggest('ch', facets=facets) self.assertEqual(len(matches), 2)