Add __repr__ for QColor?

RoadrunnerWMC roadrunnerwmc at gmail.com
Wed Apr 5 06:17:06 BST 2023


While I disagree with your conclusion, this is a really helpful message
because I hadn't realized that QColor can internally represent colors in
different ways like that.

What you seem to have missed is that the color representation format isn't
*unknowable* to __repr__ -- you can check what it is by using the .spec()
method. Of course, then your __repr__ would need logic to properly handle
all the different specs QColor supports... and both their int- and
float-constructor forms... which would be tricky.

But it's not impossible! And the question interested me enough that I wrote
a proof-of-concept implementation of it.
<https://gist.github.com/RoadrunnerWMC/c7ba91a8f31bb1cd9b99b8926d27552c>

This QColor.__repr__ gives the shortest* possible repr() for every QColor
instance which would eval() back to an identical QColor. More importantly,
it's spec-aware, and (for example) correctly handles the case you gave
above by showing each color in its true form, even though they're all
visually black:

>>> QColor.fromHsv(0, 0, 0)
> PyQt6.QtGui.QColor.fromHsv(0, 0, 0)
> >>> QColor.fromHsv(1, 0, 0)
> PyQt6.QtGui.QColor.fromHsv(1, 0, 0)
> >>> QColor.fromRgb(0, 0, 0)
> PyQt6.QtGui.QColor(0, 0, 0)


**ignoring spaces, of course. Also, for outputs that use float values, I'm
sure you could chop some digits off of the end, but that sounds hard to do
correctly, and I didn't try it*

Unfortunately, since there are no QColor functions to get the raw 16-bit
component values for (say) a HSV color, my __repr__ has to recompute them
from the float values. You could argue that that's hardcoding an
implementation detail of Qt, but technically, "the components are stored
using 16-bit integers" is documented for QColor, so it's not *quite* that
bad. Still, though, if that aspect is problematic, you could fix it by
removing that part and having it always use float representations for
HSV/CMYK/HSL, though the output will be a bit uglier.

On Tue, Apr 4, 2023 at 10:38 PM Maurizio Berti <maurizio.berti at gmail.com>
wrote:

> Il giorno mer 5 apr 2023 alle ore 03:18 RoadrunnerWMC <
> roadrunnerwmc at gmail.com> ha scritto:
>
>> For what it's worth, I'd also like this. The core geometry classes
>> (QPoint, QRect, QLine, etc. and their float versions) have custom reprs,
>> and I've definitely been bitten by wrongly assuming that QColor has one
>> when debugging in the past.
>> [ ... ]
>>
> I think what I'd do, personally, is have it dynamically choose which way
>> to repr itself based on whether all the channels match what Qt would choose
>> for 8-bit input values (aka channel * 0x101):
>>
>
> I've thought about all that in the past.
>
> I made some "shims" on my own as monkey patches for PyQt, as
> helper/utilities for both programming and debugging, but then I hit some
> conceptual issues in cases like these.
> Then I realized that I could only do that whenever I needed it for
> debugging purposes, and *only* based on the debugging purposes of a
> specific context.
>
> While it is true that *some* constructors give slightly different results
> depending on the object value, the most important thing is to keep a *consistent
> reliability* of the given result.
>
> For QPoint, that's valid and consistent: QPoint() is and will always be a
> QPoint with x and y equal to 0.
> For QColor, it is not. It is not an "absolute" (or, at least, a "context
> based absolute", considering the floating point precision issue) value
> representation, and it's not possible to get one due to its very nature.
>
> Consider the basic case of HSV:
>
> c0 = QColor.fromHsv(0, 0, 0)
> c1 = QColor.fromHsv(1, 0, 0)
>
> Both the above colors are *visually* identical: they are black. But then:
>
> c0 == c1
>
> will (not so) obviously return False.
>
> As you correctly mentioned, __repr__() should always "yield an object
> with the same value when passed to eval()".
> That consistency is something that should be important for an API.
> The representation should be an easy, reliable, consistent "visual" aid.
> If we want to show different results, but they may still not be that
> reliable nor consistent (or easily readable), that implementation becomes
> wrong by principle.
> So, while that monkey patch could be theoretically useful, it wouldn't be
> valid: it would be only in certain cases, meaning that it should not nor
> can be part of the API.
>
> Cheers,
> Maurizio
>
> --
> È difficile avere una convinzione precisa quando si parla delle ragioni
> del cuore. - "Sostiene Pereira", Antonio Tabucchi
> http://www.jidesk.net
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20230405/2a238d58/attachment.htm>


More information about the PyQt mailing list