#37088: path based MediaAsset equality
----------------------------------+------------------------------------
     Reporter:  Johannes Maron    |                    Owner:  (none)
         Type:  Bug               |                   Status:  new
    Component:  Forms             |                  Version:  6.0
     Severity:  Normal            |               Resolution:
     Keywords:  Media MediaAsset  |             Triage Stage:  Accepted
    Has patch:  0                 |      Needs documentation:  0
  Needs tests:  0                 |  Patch needs improvement:  0
Easy pickings:  1                 |                    UI/UX:  0
----------------------------------+------------------------------------
Changes (by Natalia Bidart):

 * keywords:   => Media MediaAsset
 * stage:  Unreviewed => Accepted


Old description:

> This is a spin-off from here:
> https://github.com/django/django/pull/21239#issuecomment-4396168812
>
> Currently MediaAsset.__eq__ compares only the path.
>
> This approach was deliberately chosen to benefit performance.
>
> However, in the case of `link`-elements and even `script` this approach
> can break.
> For a link, `rel=stylesheet` and `rel=refretch` can share the same path.
> Prefetching is also not too crazy a use case; someone will probably try
> to do it.
>
> A compromise could be to define an explicit list of attributes to
> compare, instead of doing a full dictionary comparison via `attributres`.
> Something like:
>

> {{{
> diff --git a/django/forms/widgets.py b/django/forms/widgets.py
> index 6972155402..70561d2c8c 100644
> --- a/django/forms/widgets.py
> +++ b/django/forms/widgets.py
> @@ -66,14 +66,20 @@ class MediaOrderConflictWarning(RuntimeWarning):
>  class MediaAsset:
>      element_template = "{path}"
>
> +    # Only compare selected attributes to ensure performant comparison
> in Media.merge.
> +    equality_attributes = ("path",)
> +
>      def __init__(self, path, **attributes):
>          self._path = path
>          self.attributes = attributes
>
>      def __eq__(self, other):
> -        # Compare the path only, to ensure performant comparison in
> -        # Media.merge.
> -        return (self.__class__ is other.__class__ and self.path ==
> other.path) or (
> +        return (
> +            self.__class__ is other.__class__ and self.path ==
> other.path and all(
> +                self.attributes.get(attr, None) ==
> other.attributes.get(attr, None)
> +                for attr in self.equality_attributes
> +            )
> +        ) or (
>              isinstance(other, str) and self._path == other
>          )
>

> }}}

New description:

 This is a spin-off from here:
 https://github.com/django/django/pull/21239#issuecomment-4396168812

 Currently `MediaAsset.__eq__` compares only the path.

 This approach was deliberately chosen to benefit performance.

 However, in the case of `link`-elements and even `script` this approach
 can break.
 For a link, `rel=stylesheet` and `rel=prefetch` can share the same path.
 Prefetching is also not too crazy a use case; someone will probably try to
 do it.

 A compromise could be to define an explicit list of attributes to compare,
 instead of doing a full dictionary comparison via `attributres`.
 Something like:


 {{{
 diff --git a/django/forms/widgets.py b/django/forms/widgets.py
 index 6972155402..70561d2c8c 100644
 --- a/django/forms/widgets.py
 +++ b/django/forms/widgets.py
 @@ -66,14 +66,20 @@ class MediaOrderConflictWarning(RuntimeWarning):
  class MediaAsset:
      element_template = "{path}"

 +    # Only compare selected attributes to ensure performant comparison in
 Media.merge.
 +    equality_attributes = ("path",)
 +
      def __init__(self, path, **attributes):
          self._path = path
          self.attributes = attributes

      def __eq__(self, other):
 -        # Compare the path only, to ensure performant comparison in
 -        # Media.merge.
 -        return (self.__class__ is other.__class__ and self.path ==
 other.path) or (
 +        return (
 +            self.__class__ is other.__class__ and self.path == other.path
 and all(
 +                self.attributes.get(attr, None) ==
 other.attributes.get(attr, None)
 +                for attr in self.equality_attributes
 +            )
 +        ) or (
              isinstance(other, str) and self._path == other
          )


 }}}

--
Comment:

 Thank you Johannes, this makes sense. Though implementation wise, I would
 rather each class defines their own `__eq__` isolating the specific
 semantic instead of defining a class attribute.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/37088#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019e026f7e44-0614351a-4f0c-424c-8c3b-084d790df1e1-000000%40eu-central-1.amazonses.com.

Reply via email to