Opened 8 years ago

Closed 2 years ago

#26287 closed New feature (fixed)

SimpleLazyObject doesn't implement __radd__

Reported by: Keryn Knight Owned by: Theofilos Alexiou
Component: Utilities Version: dev
Severity: Normal Keywords:
Cc: django@…, debanshuk2007@… Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Technically, there's a whole bunch of magic methods it doesn't implement, compared to a complete proxy implementation, like that of wrapt.ObjectProxy, but __radd__ being missing is the one that's biting me at the moment.

As far as I can tell, the implementation can't just be

__radd__ = new_method_proxy(operator.radd)

because that doesn't exist, which is rubbish.

__radd__ = new_method_proxy(operator.attrgetter("__radd__"))

also won't work because types may not have that attr, and attrgetter doesn't supress the exception (correctly)

The minimal implementation I've found that works for me is:

    def __radd__(self, other):
        if self._wrapped is empty:
            self._setup()
        return other + self._wrapped

Change History (11)

comment:1 by Tim Graham, 8 years ago

Could you please give some sample code with your use case?

comment:2 by Keryn Knight, 8 years ago

In a boiled-down nutshell:

def lazy_consumer():
    # something more complex, obviously.
    return [1, 3, 5]
consumer = SimpleLazyObject(lazy_consumer)

# inside third party code ...
def some_func(param):
    third_party_code = [...]
    # then, through parameter passing, my value is provided to be used.
    # param is at  this point, `consumer`
    third_party_code_plus_mine = third_party_code + param

which ultimately yields:

TypeError: unsupported operand type(s) for +: 'list' and 'SimpleLazyObject'

comment:3 by Tim Graham, 8 years ago

Triage Stage: UnreviewedAccepted

Seems okay, although I'm not an expert on the SimpleLazyObject class.

in reply to:  2 comment:4 by Attila Tovt, 8 years ago

Replying to kezabelle:

def lazy_consumer():
    # something more complex, obviously.
    return [1, 3, 5]
consumer = SimpleLazyObject(lazy_consumer)

If you know what is the resulting type or possible resulting types of your expression, I think you better use django.utils.functional.lazy which will provide all the necessary methods.

in reply to:  description comment:5 by Debanshu Kundu, 8 years ago

Replying to kezabelle:

As far as I can tell, the implementation can't just be

__radd__ = new_method_proxy(operator.radd)

because that doesn't exist, which is rubbish.

__radd__ = new_method_proxy(operator.attrgetter("__radd__"))

also won't work because types may not have that attr, and attrgetter doesn't supress the exception (correctly)

Wouldn't the following code work?

    __add__ = new_method_proxy(operator.add)
    __radd__ = new_method_proxy(lambda a, b: operator.add(b, a))

I have tested this and it seems to work as excepted.

comment:6 by Debanshu Kundu, 8 years ago

Cc: debanshuk2007@… added

comment:7 by Theofilos Alexiou, 2 years ago

Owner: changed from nobody to Theofilos Alexiou
Status: newassigned

comment:8 by Theofilos Alexiou, 2 years ago

Has patch: set
Triage Stage: AcceptedReady for checkin

PR here: https://github.com/django/django/pull/15400. Tried the suggestion by @Debanshu Kundu and it seems to work.

comment:9 by Mariusz Felisiak, 2 years ago

Triage Stage: Ready for checkinAccepted

RFC should be set by reviewer, see docs.

comment:10 by Mariusz Felisiak, 2 years ago

Triage Stage: AcceptedReady for checkin

comment:11 by Mariusz Felisiak <felisiak.mariusz@…>, 2 years ago

Resolution: fixed
Status: assignedclosed

In f9ec777a:

Fixed #26287 -- Added support for addition operations to SimpleLazyObject.

Note: See TracTickets for help on using tickets.
Back to Top