From fb159ce56ee9c44150685e4a7984be9729c3b59c Mon Sep 17 00:00:00 2001 From: Jordan Hyatt Date: Fri, 8 Dec 2023 16:07:31 -0500 Subject: [PATCH 1/7] Feature Request: Allow args/kwargs to be passed to a callable with an Accessor #939. Additionally added the required unit test --- django_tables2/utils.py | 9 +++++++-- tests/test_utils.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/django_tables2/utils.py b/django_tables2/utils.py index 789834a1..5e1671a0 100644 --- a/django_tables2/utils.py +++ b/django_tables2/utils.py @@ -303,7 +303,12 @@ class Accessor(str): "Failed lookup for key [{key}] in {context}, when resolving the accessor {accessor}" ) - def __new__(cls, value): + def __init__(self, object, *callable_args, **callable_kwargs): + self.callable_args = callable_args + self.callable_kwargs = callable_kwargs + super().__init__() + + def __new__(cls, value, *args, **kwargs): instance = super().__new__(cls, value) if cls.LEGACY_SEPARATOR in value: instance.SEPARATOR = cls.LEGACY_SEPARATOR @@ -394,7 +399,7 @@ def resolve(self, context, safe=True, quiet=False): if safe and getattr(current, "alters_data", False): raise ValueError(self.ALTERS_DATA_ERROR_FMT.format(method=current.__name__)) if not getattr(current, "do_not_call_in_templates", False): - current = current() + current = current(*self.callable_args, **self.callable_kwargs) # Important that we break in None case, or a relationship # spanning across a null-key will raise an exception in the # next iteration, instead of defaulting. diff --git a/tests/test_utils.py b/tests/test_utils.py index 0507c344..ab67b097 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -130,6 +130,17 @@ def test_short_circuit_dict(self): self.assertEqual(Accessor("occupation__name").resolve(context), "Carpenter") + def test_callable_args_kwargs(self): + class MyClass: + def method(self, *args, **kwargs): + return args, kwargs + + callable_args = ('arg1', 'arg2') + callable_kwargs = {'kwarg1': 'val1', 'kwarg2':'val2'} + obj = MyClass() + result = Accessor('method', *callable_args, **callable_kwargs).resolve(obj) + self.assertEqual(result, (callable_args, callable_kwargs)) + class AccessorTestModel(models.Model): foo = models.CharField(max_length=20) From 2865b77dcfba82fcb16837de7aedb7e6af747d49 Mon Sep 17 00:00:00 2001 From: Jordan Hyatt Date: Fri, 8 Dec 2023 16:08:00 -0500 Subject: [PATCH 2/7] after running black --- tests/test_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index ab67b097..390fbb81 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -135,10 +135,10 @@ class MyClass: def method(self, *args, **kwargs): return args, kwargs - callable_args = ('arg1', 'arg2') - callable_kwargs = {'kwarg1': 'val1', 'kwarg2':'val2'} + callable_args = ("arg1", "arg2") + callable_kwargs = {"kwarg1": "val1", "kwarg2": "val2"} obj = MyClass() - result = Accessor('method', *callable_args, **callable_kwargs).resolve(obj) + result = Accessor("method", *callable_args, **callable_kwargs).resolve(obj) self.assertEqual(result, (callable_args, callable_kwargs)) From db938019226d2116c6e835f57a20ead64b83d35c Mon Sep 17 00:00:00 2001 From: Jordan Hyatt Date: Sat, 10 Feb 2024 08:03:03 -0500 Subject: [PATCH 3/7] made updates per PR conversation --- django_tables2/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/django_tables2/utils.py b/django_tables2/utils.py index 5e1671a0..ba4fdb59 100644 --- a/django_tables2/utils.py +++ b/django_tables2/utils.py @@ -303,12 +303,12 @@ class Accessor(str): "Failed lookup for key [{key}] in {context}, when resolving the accessor {accessor}" ) - def __init__(self, object, *callable_args, **callable_kwargs): - self.callable_args = callable_args - self.callable_kwargs = callable_kwargs + def __init__(self, value, callable_args=None, callable_kwargs=None): + self.callable_args = callable_args or [] + self.callable_kwargs = callable_kwargs or {} super().__init__() - def __new__(cls, value, *args, **kwargs): + def __new__(cls, value, callable_args=None, callable_kwargs=None): instance = super().__new__(cls, value) if cls.LEGACY_SEPARATOR in value: instance.SEPARATOR = cls.LEGACY_SEPARATOR From 98f68b76b713f8e714f11db6dc2565d2861b225c Mon Sep 17 00:00:00 2001 From: Jordan Hyatt Date: Sat, 10 Feb 2024 08:05:46 -0500 Subject: [PATCH 4/7] fixed test to accomondate the new design on passing callable args/kwargs --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 390fbb81..977ad548 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -138,7 +138,7 @@ def method(self, *args, **kwargs): callable_args = ("arg1", "arg2") callable_kwargs = {"kwarg1": "val1", "kwarg2": "val2"} obj = MyClass() - result = Accessor("method", *callable_args, **callable_kwargs).resolve(obj) + result = Accessor("method", callable_args, callable_kwargs).resolve(obj) self.assertEqual(result, (callable_args, callable_kwargs)) From ef3af4213e05cf6a1e2e11d073c22463f1732ed5 Mon Sep 17 00:00:00 2001 From: Jordan Hyatt Date: Sat, 10 Feb 2024 08:20:32 -0500 Subject: [PATCH 5/7] fixed init to retain callable_args/kwargs if an Accessor object is passed to the constructor instead of a str object --- django_tables2/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django_tables2/utils.py b/django_tables2/utils.py index ba4fdb59..4d25d3b5 100644 --- a/django_tables2/utils.py +++ b/django_tables2/utils.py @@ -304,8 +304,8 @@ class Accessor(str): ) def __init__(self, value, callable_args=None, callable_kwargs=None): - self.callable_args = callable_args or [] - self.callable_kwargs = callable_kwargs or {} + self.callable_args = callable_args or getattr(value, callable_args, None) or [] + self.callable_kwargs = callable_kwargs or getattr(value, callable_kwargs, None) or {} super().__init__() def __new__(cls, value, callable_args=None, callable_kwargs=None): From e8dd3abbd6847365d5ddea5d2a52911048239cb5 Mon Sep 17 00:00:00 2001 From: Jordan Hyatt Date: Sat, 10 Feb 2024 08:29:16 -0500 Subject: [PATCH 6/7] fixed bug that caused test to fail --- django_tables2/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django_tables2/utils.py b/django_tables2/utils.py index 4d25d3b5..46533f06 100644 --- a/django_tables2/utils.py +++ b/django_tables2/utils.py @@ -304,8 +304,8 @@ class Accessor(str): ) def __init__(self, value, callable_args=None, callable_kwargs=None): - self.callable_args = callable_args or getattr(value, callable_args, None) or [] - self.callable_kwargs = callable_kwargs or getattr(value, callable_kwargs, None) or {} + self.callable_args = callable_args or getattr(value, 'callable_args', None) or [] + self.callable_kwargs = callable_kwargs or getattr(value, 'callable_kwargs', None) or {} super().__init__() def __new__(cls, value, callable_args=None, callable_kwargs=None): From 57a2a80e93bbdd3414f7d37ac75488d48ce63f58 Mon Sep 17 00:00:00 2001 From: Jordan Hyatt Date: Sat, 10 Feb 2024 08:33:42 -0500 Subject: [PATCH 7/7] black formatting update --- django_tables2/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/django_tables2/utils.py b/django_tables2/utils.py index 46533f06..33efabc9 100644 --- a/django_tables2/utils.py +++ b/django_tables2/utils.py @@ -304,8 +304,8 @@ class Accessor(str): ) def __init__(self, value, callable_args=None, callable_kwargs=None): - self.callable_args = callable_args or getattr(value, 'callable_args', None) or [] - self.callable_kwargs = callable_kwargs or getattr(value, 'callable_kwargs', None) or {} + self.callable_args = callable_args or getattr(value, "callable_args", None) or [] + self.callable_kwargs = callable_kwargs or getattr(value, "callable_kwargs", None) or {} super().__init__() def __new__(cls, value, callable_args=None, callable_kwargs=None):