Agree with Alex. We're considering moving more towards decorating
views rather than class attributes. I'm not sure of the performance
implications of many classes vs decorating functions on a large class
instead, but it just seems to make more sense in some cases.
Here's a working (we're now using it) version of the previous decorator:
def with_settings(**overrides):
"""Allows you to define settings that are required for this
function to work"""
NotDefined = object()
def wrapped(func):
@wraps(func)
def _with_settings(*args, **kwargs):
_orig = {}
for k, v in overrides.iteritems():
_orig[k] = getattr(settings, k, NotDefined)
setattr(settings, k, v)
try:
func(*args, **kwargs)
finally:
for k, v in _orig.iteritems():
if v is NotDefined:
delattr(settings, k)
else:
setattr(settings, k, v)
return _with_settings
return wrapped
--
David Cramer
http://www.davidcramer.net
On Thu, Nov 4, 2010 at 2:26 PM, Alex Gaynor <[email protected]> wrote:
> 2010/11/4 Łukasz Rekucki <[email protected]>:
>> Funny, I had exactly the same problem today at work while refactoring
>> my application's tests suite :).
>>
>> Currently, I'm using a pair of save/restore functions: save() monkey
>> patches the settings module and returns a dictionary of old values,
>> restore() puts back the old values based on the dictionary. I usually
>> put this in setUp/tearDown so I don't have to repeat in every test. I
>> was about to propose that
>> Django's TestCase should do something similar by default.
>>
>> Both the decorator and context processor are very useful, but having
>> something to set values for the whole test case instead of a single
>> test or a block of code would be great too. I was thinking about
>> something in line of:
>>
>> class EmailTestCase(TestCase):
>> settings = dict(DEFAULT_FROM_EMAIL="[email protected]")
>>
>> On 4 November 2010 21:11, David Cramer <[email protected]> wrote:
>>> With a decorator approach here's what I whipped up:
>>>
>>> (This is dry code)
>>>
>>> def with_settings(**overrides):
>>> """Allows you to define settings that are required for this
>>> function to work"""
>>> NotDefined = object()
>>> def wrapped(func):
>>> �...@wraps(func)
>>> def _with_settings(*args, **kwargs):
>>> _orig = {}
>>> for k, v in overrides.iteritems():
>>> _orig[k] = getattr(settings, k, NotDefined)
>>>
>>> try:
>>> func(*args, **kwargs)
>>> finally:
>>> for k, v in _orig.iteritems():
>>> if v is NotDefined:
>>> delattr(settings, k)
>>> else:
>>> setattr(settings, k, v)
>>> return _with_settings
>>> return wrapped
>>>
>>> I'm not familiar with the context managers, but I imagine those would
>>> solve things like adjusting CONTEXT_PROCESSORS.
>>>
>>> On Thu, Nov 4, 2010 at 1:06 PM, Dan Fairs <[email protected]> wrote:
>>>>
>>>>> Let me start with an example test:
>>>>>
>>>>> def test_with_awesome_setting(self):
>>>>> _orig = getattr(settings, 'AWESOME', None)
>>>>> settings.AWESOME = True
>>>>>
>>>>> # do my test
>>>>> ...
>>>>>
>>>>> settings.AWESOME = _orig
>>>>>
>>>>
>>>> Pedant: there's a small bug above which has bitten me before doing a
>>>> similar thing - settings.AWESOME ends up set to None after the test has
>>>> run if it didn't exist before.
>>>>
>>>>> Anyways, I'd love to hear how others have dealt with this and any
>>>>> other possible solutions.
>>>>
>>>> I've used Michael Foord's Mock library to patch a setting for the duration
>>>> of a test case. Chris Withers' testfixtures library also has some sugar to
>>>> provide a context manager approach, though I haven't used that in a little
>>>> while.
>>>>
>>>> Cheers,
>>>> Dan
>>>>
>>>> --
>>>> Dan Fairs | [email protected] | www.fezconsulting.com
>>>>
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google Groups
>>>> "Django developers" group.
>>>> To post to this group, send email to [email protected].
>>>> To unsubscribe from this group, send email to
>>>> [email protected].
>>>> For more options, visit this group at
>>>> http://groups.google.com/group/django-developers?hl=en.
>>>>
>>>>
>>>
>>> --
>>> You received this message because you are subscribed to the Google Groups
>>> "Django developers" group.
>>> To post to this group, send email to [email protected].
>>> To unsubscribe from this group, send email to
>>> [email protected].
>>> For more options, visit this group at
>>> http://groups.google.com/group/django-developers?hl=en.
>>>
>>>
>>
>>
>>
>> --
>> Łukasz Rekucki
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Django developers" group.
>> To post to this group, send email to [email protected].
>> To unsubscribe from this group, send email to
>> [email protected].
>> For more options, visit this group at
>> http://groups.google.com/group/django-developers?hl=en.
>>
>>
>
> Well, there's no reason the decorator couldn't be used as a class
> decorator (on 2.6 and above). I'll admit that the settings attribute
> on TestCase is more consistant with how we've handled other things
> (urls, fixtures), however, for whatever reason I'm not a fan, as it
> forces you to split up tests that should logically be grouped on a
> single class.
>
> Alex
>
> --
> "I disapprove of what you say, but I will defend to the death your
> right to say it." -- Voltaire
> "The people's good is the highest law." -- Cicero
> "Code can always be simpler than you think, but never as simple as you
> want" -- Me
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/django-developers?hl=en.
>
>
--
You received this message because you are subscribed to the Google Groups
"Django developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-developers?hl=en.