From 039e526d3771976d9e7b0a85caf242f884241c11 Mon Sep 17 00:00:00 2001 From: Caio Ariede Date: Tue, 9 Mar 2021 11:52:44 -0300 Subject: [PATCH] Fixes #63 -- Calling bulk_update w/ incorrect args (#64) --- anon/base.py | 7 +--- anon/compat.py | 6 +-- tests/compat.py | 6 --- tests/models.py | 30 ++++++++++++++ tests/test_base.py | 99 +++++++++++--------------------------------- tests/test_compat.py | 44 ++++---------------- 6 files changed, 67 insertions(+), 125 deletions(-) delete mode 100644 tests/compat.py create mode 100644 tests/models.py diff --git a/anon/base.py b/anon/base.py index 406f24c..5495026 100644 --- a/anon/base.py +++ b/anon/base.py @@ -88,12 +88,9 @@ def run(self, select_chunk_size=None, **bulk_update_kwargs): bulk_update( objs, + update_fields, self.get_manager(), - **dict( - update_fields=update_fields, - batch_size=update_batch_size, - **bulk_update_kwargs - ) + **dict(batch_size=update_batch_size, **bulk_update_kwargs) ) if current_batch == 0: diff --git a/anon/compat.py b/anon/compat.py index fab955a..ebb4838 100644 --- a/anon/compat.py +++ b/anon/compat.py @@ -2,7 +2,7 @@ from django_bulk_update.helper import bulk_update as ext_bulk_update -def bulk_update(objects, manager, **bulk_update_kwargs): +def bulk_update(objects, fields, manager, **bulk_update_kwargs): """Updates the list of objects using django queryset's inbuilt ``.bulk_update()`` method if present, else django_bulk_update's ``bulk_update()`` will be used @@ -16,6 +16,6 @@ def bulk_update(objects, manager, **bulk_update_kwargs): :rtype: None """ try: - manager.bulk_update(objects, **bulk_update_kwargs) + manager.bulk_update(objects, fields, **bulk_update_kwargs) except AttributeError: - ext_bulk_update(objects, **bulk_update_kwargs) + ext_bulk_update(objects, update_fields=fields, **bulk_update_kwargs) diff --git a/tests/compat.py b/tests/compat.py deleted file mode 100644 index f763aba..0000000 --- a/tests/compat.py +++ /dev/null @@ -1,6 +0,0 @@ -try: - # stdlib - from unittest import mock # noqa: F401 -except ImportError: - # deps - import mock # noqa: F401 diff --git a/tests/models.py b/tests/models.py new file mode 100644 index 0000000..fdf3b88 --- /dev/null +++ b/tests/models.py @@ -0,0 +1,30 @@ +# deps +from django.db import models + + +class PersonAnotherQuerySet(models.QuerySet): + pass + + +class Person(models.Model): + first_name = models.CharField(max_length=255) + last_name = models.CharField(max_length=255) + + line1 = models.CharField(max_length=255) + line2 = models.CharField(max_length=255) + line3 = models.CharField(max_length=255) + + raw_data = models.TextField() + + another_manager = models.Manager.from_queryset(PersonAnotherQuerySet) + + +def person_factory(**kwargs): + kwargs.setdefault("first_name", "A") + kwargs.setdefault("last_name", "B") + kwargs.setdefault("line1", "X") + kwargs.setdefault("line2", "Y") + kwargs.setdefault("line3", "Z") + kwargs.setdefault("raw_data", '{"access_token": "XYZ"}') + + return Person.objects.create(**kwargs) diff --git a/tests/test_base.py b/tests/test_base.py index 2183ba4..5a7e20d 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -4,7 +4,7 @@ # local import anon -from .compat import mock +from . import models class BaseAnonymizer(anon.BaseAnonymizer): @@ -30,33 +30,24 @@ class Meta: self.assertIsInstance(anonymizer._meta, Anon.Meta) def test_get_manager(self): - manager = object() - - m = mock.Mock() - m.other_manager = manager - class Anon(BaseAnonymizer): class Meta: - model = m - manager = m.other_manager + model = models.Person + manager = models.PersonAnotherQuerySet anonymizer = Anon() - self.assertEqual(anonymizer.get_manager(), manager) + self.assertEqual(anonymizer.get_manager(), models.PersonAnotherQuerySet) def test_get_queryset(self): - sample_obj = object() - - m = mock.Mock() - m.objects.all.return_value = [sample_obj] + sample_obj = models.person_factory() class Anon(BaseAnonymizer): class Meta: - model = m + model = models.Person anonymizer = Anon() result = anonymizer.get_queryset() - self.assertEqual(result, [sample_obj]) - m.objects.all.assert_called_once() + self.assertSequenceEqual(result, [sample_obj]) def test_patch_object(self): fake_first_name = lambda: "foo" # noqa: E731 @@ -64,99 +55,65 @@ def test_patch_object(self): class Anon(BaseAnonymizer): first_name = fake_first_name last_name = fake_first_name - raw_data = {1: 2} + raw_data = "{1: 2}" - class Obj(object): - def __init__(self): - self.first_name = "zzz" - self.last_name = "" # empty data should be kept empty - self.raw_data = {} - - obj = Obj() + obj = models.person_factory(last_name="") # empty data should be kept empty anonymizer = Anon() anonymizer.patch_object(obj) self.assertEqual(obj.first_name, "foo") self.assertEqual(obj.last_name, "") - self.assertEqual(obj.raw_data, {}) + self.assertEqual(obj.raw_data, "{1: 2}") - @mock.patch("anon.base.bulk_update") - @mock.patch("anon.base.chunkator_page") - def test_run(self, chunkator_page, bulk_update): + def test_run(self): class Anon(BaseAnonymizer): class Meta: - model = mock.Mock(__name__="x") + model = models.Person update_batch_size = 42 - manager = object() first_name = "xyz" - class Obj(object): - def __init__(self): - self.first_name = "zzz" - - obj = Obj() - - chunkator_page.return_value = [[obj]] + obj = models.person_factory() anonymizer = Anon() - anonymizer.get_queryset = mock.Mock(return_value=[obj]) - anonymizer.patch_object = mock.Mock() anonymizer.run() - anonymizer.patch_object.assert_called_once_with(obj) - bulk_update.assert_called_once_with( - [obj], anonymizer.get_manager(), batch_size=42, update_fields=["first_name"] - ) + obj.refresh_from_db() + self.assertEqual(obj.first_name, "xyz") def test_lazy_attribute(self): - lazy_fn = mock.Mock() - fake_first_name = anon.lazy_attribute(lazy_fn) + fake_first_name = anon.lazy_attribute(lambda o: o.last_name) class Anon(BaseAnonymizer): first_name = fake_first_name - class Obj(object): - def __init__(self): - self.first_name = "zzz" - - obj = Obj() + obj = models.person_factory() anonymizer = Anon() anonymizer.patch_object(obj) - lazy_fn.assert_called_once_with(obj) + self.assertEqual(obj.first_name, obj.last_name) def test_lazy_attribute_decorator(self): - lazy_fn = mock.Mock() - class Anon(BaseAnonymizer): @anon.lazy_attribute def first_name(self): - return lazy_fn(self) - - class Obj(object): - def __init__(self): - self.first_name = "zzz" + return "xyz" - obj = Obj() + obj = models.person_factory() anonymizer = Anon() anonymizer.patch_object(obj) - lazy_fn.assert_called_once_with(obj) + self.assertEqual(obj.first_name, "xyz") def test_raw_attributes(self): class Anon(BaseAnonymizer): - raw_data = {} + raw_data = "{}" - class Obj(object): - def __init__(self): - self.raw_data = {"password": "xyz"} - - obj = Obj() + obj = models.person_factory() anonymizer = Anon() anonymizer.patch_object(obj) - self.assertEqual(obj.raw_data, {}) + self.assertEqual(obj.raw_data, "{}") def test_clean(self): class Anon(BaseAnonymizer): @@ -168,13 +125,7 @@ def clean(self, obj): obj.line1 = "foo" obj.line2 = "bar" - class Obj(object): - def __init__(self): - self.line1 = "X" - self.line2 = "Y" - self.line3 = "Z" - - obj = Obj() + obj = models.person_factory() anonymizer = Anon() anonymizer.patch_object(obj) diff --git a/tests/test_compat.py b/tests/test_compat.py index 728f9b3..6a864eb 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -4,44 +4,14 @@ # local from anon.compat import bulk_update -from .compat import mock +from . import models class CompatTestCase(TestCase): - @mock.patch("anon.compat.ext_bulk_update") - def test_call_inbuilt_bulk_update(self, ext_bulk_update): - class Manager: - def bulk_update(self, objects, **kwargs): - pass + def test_call_bulk_update(self): + obj = models.person_factory() + obj.first_name = "xyz" - manager = Manager() - - class Obj(object): - def __init__(self): - self.first_name = "zzz" - - obj = Obj() - - self.assertTrue(hasattr(manager, "bulk_update")) - bulk_update(objects=[obj], manager=manager) - ext_bulk_update.assert_not_called() - - @mock.patch("anon.compat.ext_bulk_update") - def test_call_ext_bulk_update(self, ext_bulk_update): - class Manager: - pass - - manager = Manager() - - class Obj(object): - def __init__(self): - self.first_name = "zzz" - - obj = Obj() - self.assertFalse(hasattr(manager, "bulk_update")) - bulk_update( - objects=[obj], manager=manager, batch_size=42, update_fields=["first_name"] - ) - ext_bulk_update.assert_called_once_with( - [obj], batch_size=42, update_fields=["first_name"] - ) + bulk_update([obj], {"first_name"}, models.Person.objects) + obj.refresh_from_db() + self.assertEqual(obj.first_name, "xyz")