Opened 11 years ago
Closed 11 years ago
#21765 closed New feature (fixed)
Contexts cannot be compared for equality.
Reported by: | Owned by: | onjin | |
---|---|---|---|
Component: | Template system | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Currently, comparing two contexts for equality requires knowing the internals of how Context
is implemented -- ie: that there is a .dicts
attribute available on an instance. For the purposes of writing unit tests, I needed to compare a context and a mutated one, and was surprised to find there's no concept of context equality:
>>> from django.template import Context >>> Context() == Context() False >>> Context().dicts == Context().dicts True >>> Context({'x': 'y'}).dicts == Context({'x': 'y'}).dicts True >>> Context({'x': 'y'}).dicts == Context({'x': 'z'}).dicts False >>>
It possibly doesn't make sense for Context
to have the gt/ge/lt/le magic methods defined on it (though one could argue they check the length of the .dicts
), but from an API standpoint it might be nice to see eq/ne implemented for clean comparisons.
Tagging with master as the context doesn't seem to have changed since 1.6.1, which is what I'm testing against.
Change History (7)
comment:1 by , 11 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 11 years ago
As an implementation detail, should any context subclass be considered equal if it's underlying dataset is the same, such that Context({'x': 1}) == RenderContext({'x': 1})
and vice versa, or should type(x) == type(y)
in addition to x.dicts == y.dicts
? It's unclear what the best course of action would be, given there's no expectation of equality except my own.
comment:3 by , 11 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:4 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
comment:5 by , 11 years ago
Resolution: | fixed |
---|---|
Status: | closed → new |
Re-opening with permission:
The fix as committed is not entirely correct, I don't think, as it only compares the last state change of a given context, so comparisons can incorrectly return as equal if context states drift and then re-align, for example:
>>> import django >>> from django.template import Context >>> a = Context() >>> b = Context() >>> a == b True
the above is correct; from here on out, the contexts are continuations of the above example:
>>> a.update({'a': 1}) >>> a == b False
that's also correct.
>>> a.update({'c': 3}) >>> b.update({'c': 3}) >>> a == b True
This is where the incorrectness appears. They are not equal, but their last push to the stack was, so they're being treated as equal. Based on the commit in question (d97bf2e9c8971764690caaf81a0914bc368d6b02
), the change would be going from:
return self.dicts[-1] == other.dicts[-1]
to
return self.dicts == other.dicts
which would at least ensure the rest of the context is taken into account, though that fix in itself may not be as correct as it should be -- it is strict in the sense that the entire history of the contexts being compared must be aligned, where it should perhaps instead squash the stack into one dictionary for both sides and compare them for equality.
(Whether or not strictness is a benefit or problem is probably a DDN, and like testing equality for context subclasses which differ (or have different attrs, for things like RenderContext
) could probably be tracked in separate tickets, though.)
comment:7 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
It seems like the reported issue is finally fixed after the update by 8274fa60f88607eb0e81908f049c391455956dd8.
Seems a reasonable request to me.