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
caioariede authored Mar 9, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 4ee821c commit 039e526
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
@@ -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:
6 changes: 3 additions & 3 deletions anon/compat.py
Original file line number Diff line number Diff line change
@@ -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)
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
@@ -4,7 +4,7 @@
# local
import anon

from .compat import mock
from . import models


class BaseAnonymizer(anon.BaseAnonymizer):
@@ -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):
@@ -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)
44 changes: 7 additions & 37 deletions tests/test_compat.py
Original file line number Diff line number Diff line change
@@ -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.