Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

consider descriptor pattern for GraphicFeature. #389

Copy link
Copy link
Closed
@tlambert03

Description

@tlambert03
Issue body actions

While playing around with some examples, I saw this type error reported by mypy:

Screenshot 2023-12-04 at 12 01 06 PM

I dug into a bit and learned about the Graphic/GraphicFeature relationship. Apologies if you already know this and specifically decided against it... but the general pattern of an abstract _set method on GraphicFeature objects that retain a pointer to some parent object looks very much like it could be replaced/improved with python descriptors.

For example, the current pattern (highly simplified) is:

class GraphicFeature:
    def __init__(self, parent):
        self._parent = weakref.proxy(parent)

    def _set(self, value):
        raise NotImplementedError


class SomeFeature(GraphicFeature):
    def _set(self, value):
        print(f"setting {self.name!r} on {self._parent} to {value!r}")


class Graphic:
    def __setattr__(self, key, value):
        if hasattr(self, key):
            attr = getattr(self, key)
            if isinstance(attr, GraphicFeature):
                attr._set(value)
                return

        super().__setattr__(key, value)


class SomeGraphic(Graphic):
    def __init__(self) -> None:
        self.feature = SomeFeature()

with the descriptor pattern, that all reduces to

class SomeFeature:
    def __get__(self, instance, owner):
        ...

    def __set__(self, obj, value):
        print(f"setting feature on {obj} to {value!r}")


class SomeGraphic:
    feature = SomeFeature()

and when you set the feature attribute on an instance of SomeGraphic, then SomeFeature.__set__ will be called with the instance and value:

In [18]: g = SomeGraphic()

In [19]: g.feature = 1
setting feature on <__main__.SomeGraphic object at 0x106c33750> to 1

this also works very nicely for typing:

Screenshot 2023-12-04 at 12 11 15 PM

note that it neither complains when setting .feature = [1,2,3], and it also recognizes that accessing .feature will return a str (i.e. it's been coerced from list to some internal value), based on the type hints of __set__ and __get__

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.