def test_set_existing(): """Setting a similarity for an existing pair just updates the score.""" obj_a = make_quote('Hello') obj_b = make_quote('World') sim_obj = models.ObjectSimilarity.set(obj_a, obj_b, 10) sim_obj_2 = models.ObjectSimilarity.set(obj_a, obj_b, 20) assert sim_obj.pk == sim_obj_2.pk assert sim_obj_2.score == 20
def test_instance_list(): """Querysets/model managers have an instance_list method.""" set_score = models.ObjectSimilarity.set # Just a readability alias obj_a = make_quote('Hello') obj_b = make_quote('World') obj_c = make_quote('Foobar') set_score(obj_a, obj_b, 1) set_score(obj_a, obj_c, 2) instances = models.ObjectSimilarity.objects.all().order_by( 'score').get_instances_for(obj_a) assert [obj_b, obj_c] == list(instances)
def test_set_0_doesnt_create(): """Giving a pair of new objects a score of 0 does nothing.""" obj_a = make_quote('Hello', pk=12) obj_b = make_quote('World', pk=22) ctype = ct_models.ContentType.objects.get_for_model(obj_a) sim_obj = models.ObjectSimilarity.set(obj_a, obj_b, 0) assert sim_obj is None assert not models.ObjectSimilarity.objects.filter( object_1_content_type=ctype, object_2_content_type=ctype, object_1_id=obj_a.id, object_2_id=obj_b.pk).exists()
def test_similar_to(): """similar_to is like similar_objects but returns a queryset.""" quote_a = make_quote("foo") quote_b = make_quote("bar") quote_c = make_quote("baz") sim_ab = django_recommend.models.ObjectSimilarity.set(quote_a, quote_b, 10) sim_ac = django_recommend.models.ObjectSimilarity.set(quote_a, quote_c, 5) sim_quotes = django_recommend.similar_to(quote_a) assert list(sim_quotes) == [sim_ab, sim_ac] sim_quotes = sim_quotes.exclude_objects(quotes.models.Quote.objects.filter(pk=quote_b.pk)) assert list(sim_quotes) == [sim_ac]
def test_get_instances_nopurge(settings): """get_instances_for propagates ObjectDoesNotExist without a handler.""" settings.RECOMMEND_PURGE_MISSING_DATA = False set_score = models.ObjectSimilarity.set # Just a readability alias obj_a = make_quote('Hello') obj_b = make_quote('World') obj_c = make_quote('Foobar') set_score(obj_a, obj_b, 1) set_score(obj_a, obj_c, 2) obj_b.delete() with pytest.raises(quotes.models.Quote.DoesNotExist): models.ObjectSimilarity.objects.all().order_by( 'score').get_instances_for(obj_a)
def test_similar_to(): """similar_to is like similar_objects but returns a queryset.""" quote_a = make_quote('foo') quote_b = make_quote('bar') quote_c = make_quote('baz') sim_ab = django_recommend.models.ObjectSimilarity.set(quote_a, quote_b, 10) sim_ac = django_recommend.models.ObjectSimilarity.set(quote_a, quote_c, 5) sim_quotes = django_recommend.similar_to(quote_a) assert list(sim_quotes) == [sim_ab, sim_ac] sim_quotes = sim_quotes.exclude_objects( quotes.models.Quote.objects.filter(pk=quote_b.pk)) assert list(sim_quotes) == [sim_ac]
def test_set_existing_to_0(): """A score of 0 causes deletion of an existing ObjectSimilarity.""" obj_a = make_quote('Hello', pk=12) obj_b = make_quote('World', pk=22) sim_obj = models.ObjectSimilarity.set(obj_a, obj_b, 10) ctype = ct_models.ContentType.objects.get_for_model(obj_a) models.ObjectSimilarity.set(obj_a, obj_b, 0) with pytest.raises(models.ObjectSimilarity.DoesNotExist): models.ObjectSimilarity.objects.get(pk=sim_obj.pk) assert not models.ObjectSimilarity.objects.filter( object_1_content_type=ctype, object_2_content_type=ctype, object_1_id=obj_a.id, object_2_id=obj_b.pk).exists()
def test_get_score_when_unset(): """If a score is not in the DB, 0 is returned.""" user = User.objects.create() quote = make_quote(content="foobar") assert django_recommend.models.UserScore.objects.count() == 0 assert django_recommend.get_score(user, quote) == 0
def test_get_score_with_user(): """The get_score function can get the user's score for an object.""" user = User.objects.create(username='******') quote = make_quote(content='fizzbuzz') django_recommend.models.UserScore.set(user, quote, 55) assert django_recommend.get_score(user, quote) == 55
def test_exclude_objects_qset(): """ObjectSimilarity qset.exclude_objects can take a queryset.""" set_score = models.ObjectSimilarity.set # Just a readability alias obj_a = make_quote('Hello') obj_b = make_quote('World') obj_c = make_quote('Foo') obj_d = make_quote('Bar') sim_b = set_score(obj_a, obj_b, 1) set_score(obj_a, obj_c, 2) sim_d = set_score(obj_a, obj_d, 3) sims = models.ObjectSimilarity.objects.all().order_by('score') sims = sims.exclude_objects( quotes.models.Quote.objects.filter(pk=obj_c.pk)) assert [sim_b, sim_d] == list(sims)
def test_set_bad_order(): """ObjectSimilarity.set() always stores in the same order.""" quote_a = make_quote(content='Hello', pk=30) quote_b = make_quote(content='World', pk=40) sim_obj = models.ObjectSimilarity.set(quote_a, quote_b, 10) assert sim_obj.object_1 == quote_a assert sim_obj.object_2 == quote_b # Give quotes in other order and make sure the same result happens. sim_obj.delete() sim_obj = models.ObjectSimilarity.set(quote_b, quote_a, 20) assert sim_obj.object_1 == quote_a assert sim_obj.object_2 == quote_b
def test_get_score_when_unset(): """If a score is not in the DB, 0 is returned.""" user = User.objects.create() quote = make_quote(content='foobar') assert django_recommend.models.UserScore.objects.count() == 0 assert django_recommend.get_score(user, quote) == 0
def test_get_score_with_user(): """The get_score function can get the user's score for an object.""" user = User.objects.create(username="******") quote = make_quote(content="fizzbuzz") django_recommend.models.UserScore.set(user, quote, 55) assert django_recommend.get_score(user, quote) == 55
def test_set_score_direct_user(): """set_score() can take a user instead of a request.""" user = User.objects.create(pk=3) quote = make_quote(content="fizzbuzz") django_recommend.set_score(user, quote, 5) assert django_recommend.scores_for(quote) == {"user:3": 5}
def test_get_instances_purge(settings): """get_instances_for deletes missing data when purge is set.""" settings.RECOMMEND_PURGE_MISSING_DATA = True obj_a = make_quote('Hello') obj_b = make_quote('World') django_recommend.set_score('foo', obj_a, 1) django_recommend.set_score('foo', obj_b, 2) django_recommend.tasks.update_similarity(obj_a) obj_b.delete() assert 2 == django_recommend.models.UserScore.objects.count() assert 1 == django_recommend.models.ObjectSimilarity.objects.count() models.ObjectSimilarity.objects.all().order_by('score').get_instances_for( obj_a) assert 1 == django_recommend.models.UserScore.objects.count() assert 0 == django_recommend.models.ObjectSimilarity.objects.count()
def test_set_score_direct_user(): """set_score() can take a user instead of a request.""" user = User.objects.create(pk=3) quote = make_quote(content='fizzbuzz') django_recommend.set_score(user, quote, 5) assert django_recommend.scores_for(quote) == {'user:3': 5}
def test_get_instances_purge(settings): """get_instances_for deletes missing data when purge is set.""" settings.RECOMMEND_PURGE_MISSING_DATA = True obj_a = make_quote('Hello') obj_b = make_quote('World') django_recommend.set_score('foo', obj_a, 1) django_recommend.set_score('foo', obj_b, 2) django_recommend.tasks.update_similarity(obj_a) obj_b.delete() assert 2 == django_recommend.models.UserScore.objects.count() assert 1 == django_recommend.models.ObjectSimilarity.objects.count() models.ObjectSimilarity.objects.all().order_by( 'score').get_instances_for(obj_a) assert 1 == django_recommend.models.UserScore.objects.count() assert 0 == django_recommend.models.ObjectSimilarity.objects.count()
def sample_data(): """Create a set of sample data.""" quote = { 1: make_quote('quote 1'), 2: make_quote('quote 2'), 3: make_quote('quote 3'), 4: make_quote('quote 4'), } django_recommend.set_score('foo', quote[1], 3) django_recommend.set_score('foo', quote[2], 2) django_recommend.set_score('bar', quote[2], 3) django_recommend.set_score('bar', quote[3], 4) django_recommend.set_score('baz', quote[4], 5) # Note: quote 4/baz are not related to other users/quotes. return quote
def test_filter_objects(): """ObjectSimilarity qset.filter_objects takes a queryset.""" set_score = models.ObjectSimilarity.set # Just a readability alias obj_a = make_quote('Hello') obj_b = make_quote('World') obj_c = make_quote('Foo') obj_d = make_quote('Bar') sim_ab = set_score(obj_a, obj_b, 1) sim_ac = set_score(obj_a, obj_c, 2) sim_ad = set_score(obj_a, obj_d, 3) set_score(obj_b, obj_c, 5) # This data that shouldn't be included set_score(obj_b, obj_d, 6) quote_a = quotes.models.Quote.objects.filter(pk=obj_a.pk) sims = models.ObjectSimilarity.objects.filter_objects(quote_a) sims = sims.order_by('score') assert [sim_ab, sim_ac, sim_ad] == list(sims)
def test_get_instances_fallback(): """get_instances_for uses a callback when an instance is missing.""" set_score = models.ObjectSimilarity.set # Just a readability alias obj_a = make_quote('Hello') obj_b = make_quote('World') obj_c = make_quote('Foobar') ctype = ct_models.ContentType.objects.get_for_model(obj_a) set_score(obj_a, obj_b, 1) set_score(obj_a, obj_c, 2) obj_b_pk = obj_b.pk # .pk gets set to None after delete() obj_b.delete() handle_missing = mock.MagicMock() objs = models.ObjectSimilarity.objects.all().order_by( 'score').get_instances_for(obj_a, handle_missing) assert 1 == handle_missing.call_count assert mock.call(ctype.pk, obj_b_pk) == handle_missing.call_args assert [obj_c] == list(objs)
def test_set_score_request_user(client): """The set_score method associates a score with a user.""" make_user(username='******', password='******', pk=30) assert client.login(username='******', password='******') req = client.get('/foo').wsgi_request quote = make_quote(content='hello world') django_recommend.set_score(req, quote, 1) assert django_recommend.scores_for(quote) == {'user:30': 1} make_user(username='******', password='******', pk=55) assert client.login(username='******', password='******') req = client.get('/bar/').wsgi_request quote = make_quote(content='Fizzbuzz') django_recommend.set_score(req, quote, 5) assert django_recommend.scores_for(quote) == {'user:55': 5}
def test_setdefault_score(): """setdefault_score only sets a score if it doesn't exist.""" user = User.objects.create() quote = make_quote(content="foobar") assert django_recommend.get_score(user, quote) == 0 django_recommend.setdefault_score(user, quote, 3) assert django_recommend.get_score(user, quote) == 3 django_recommend.setdefault_score(user, quote, 5) assert django_recommend.get_score(user, quote) == 3
def test_setdefault_score(): """setdefault_score only sets a score if it doesn't exist.""" user = User.objects.create() quote = make_quote(content='foobar') assert django_recommend.get_score(user, quote) == 0 django_recommend.setdefault_score(user, quote, 3) assert django_recommend.get_score(user, quote) == 3 django_recommend.setdefault_score(user, quote, 5) assert django_recommend.get_score(user, quote) == 3
def test_set_score_request_user(client): """The set_score method associates a score with a user.""" make_user(username="******", password="******", pk=30) assert client.login(username="******", password="******") req = client.get("/foo").wsgi_request quote = make_quote(content="hello world") django_recommend.set_score(req, quote, 1) assert django_recommend.scores_for(quote) == {"user:30": 1} make_user(username="******", password="******", pk=55) assert client.login(username="******", password="******") req = client.get("/bar/").wsgi_request quote = make_quote(content="Fizzbuzz") django_recommend.set_score(req, quote, 5) assert django_recommend.scores_for(quote) == {"user:55": 5}
def test_get_similar_objects(): """get_similar_objects gets instances most similar to the given object.""" quote_a = make_quote('foo') quote_b = make_quote('bar') quote_c = make_quote('baz') django_recommend.models.ObjectSimilarity.set(quote_a, quote_b, 10) django_recommend.models.ObjectSimilarity.set(quote_a, quote_c, 5) sim_quotes = django_recommend.similar_objects(quote_a) assert list(sim_quotes) == [quote_b, quote_c] # Change scores to ensure sorted order is given. django_recommend.models.ObjectSimilarity.set(quote_a, quote_b, 4) django_recommend.models.ObjectSimilarity.set(quote_a, quote_c, 12) sim_quotes = django_recommend.similar_objects(quote_a) assert list(sim_quotes) == [quote_c, quote_b] # Change which object is requested to make sure SUT isn't only filtering # against object_1 sim_quotes = django_recommend.similar_objects(quote_b) assert list(sim_quotes) == [quote_a]
def test_forget_object(): """forget_object() will delete all similarity data for objects.""" make_quote = quotes.models.Quote.objects.create obj_a = make_quote(content='Hello') obj_b = make_quote(content='World') obj_c = make_quote(content='Foobar') django_recommend.set_score('foo', obj_a, 1) django_recommend.set_score('foo', obj_b, 1) django_recommend.set_score('foo', obj_c, 1) ctype = ct_models.ContentType.objects.get_for_model(obj_a) django_recommend.tasks.update_similarity((obj_a.pk, ctype.pk)) ctype = ct_models.ContentType.objects.get_for_model(obj_b) obj_b_pk = obj_b.pk # .pk gets set to None after delete() obj_b.delete() obj_b.pk = obj_b_pk django_recommend.forget_object(ctype.pk, obj_b_pk) assert 1 == django_recommend.models.ObjectSimilarity.objects.count() assert 2 == django_recommend.models.UserScore.objects.count() assert 0 == django_recommend.get_score('foo', obj_b) assert [obj_c] == django_recommend.similar_objects(obj_a)
def test_get_similar_objects(): """get_similar_objects gets instances most similar to the given object.""" quote_a = make_quote("foo") quote_b = make_quote("bar") quote_c = make_quote("baz") django_recommend.models.ObjectSimilarity.set(quote_a, quote_b, 10) django_recommend.models.ObjectSimilarity.set(quote_a, quote_c, 5) sim_quotes = django_recommend.similar_objects(quote_a) assert list(sim_quotes) == [quote_b, quote_c] # Change scores to ensure sorted order is given. django_recommend.models.ObjectSimilarity.set(quote_a, quote_b, 4) django_recommend.models.ObjectSimilarity.set(quote_a, quote_c, 12) sim_quotes = django_recommend.similar_objects(quote_a) assert list(sim_quotes) == [quote_c, quote_b] # Change which object is requested to make sure SUT isn't only filtering # against object_1 sim_quotes = django_recommend.similar_objects(quote_b) assert list(sim_quotes) == [quote_a]
def test_forget_object(): """forget_object() will delete all similarity data for objects.""" make_quote = quotes.models.Quote.objects.create obj_a = make_quote(content="Hello") obj_b = make_quote(content="World") obj_c = make_quote(content="Foobar") django_recommend.set_score("foo", obj_a, 1) django_recommend.set_score("foo", obj_b, 1) django_recommend.set_score("foo", obj_c, 1) ctype = ct_models.ContentType.objects.get_for_model(obj_a) django_recommend.tasks.update_similarity((obj_a.pk, ctype.pk)) ctype = ct_models.ContentType.objects.get_for_model(obj_b) obj_b_pk = obj_b.pk # .pk gets set to None after delete() obj_b.delete() obj_b.pk = obj_b_pk django_recommend.forget_object(ctype.pk, obj_b_pk) assert 1 == django_recommend.models.ObjectSimilarity.objects.count() assert 2 == django_recommend.models.UserScore.objects.count() assert 0 == django_recommend.get_score("foo", obj_b) assert [obj_c] == django_recommend.similar_objects(obj_a)