Skip to content

Commit

Permalink
Fixes #63 -- Calling bulk_update w/ incorrect args (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
caioariede authored Mar 9, 2021
1 parent 4ee821c commit 039e526
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 125 deletions.
7 changes: 2 additions & 5 deletions anon/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 3 additions & 3 deletions anon/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
6 changes: 0 additions & 6 deletions tests/compat.py

This file was deleted.

30 changes: 30 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
@@ -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)
99 changes: 25 additions & 74 deletions tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# local
import anon

from .compat import mock
from . import models


class BaseAnonymizer(anon.BaseAnonymizer):
Expand All @@ -30,133 +30,90 @@ 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

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):
Expand All @@ -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)
Expand Down
44 changes: 7 additions & 37 deletions tests/test_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

0 comments on commit 039e526

Please sign in to comment.