Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better Result Objects #47

Open
AKuederle opened this issue Sep 21, 2022 · 0 comments
Open

Better Result Objects #47

AKuederle opened this issue Sep 21, 2022 · 0 comments

Comments

@AKuederle
Copy link
Member

AKuederle commented Sep 21, 2022

At the moment all attributes with a trailing underscore are considered results.
This works nice in a general case.

It becomes a little annoying when using dataclasses/attrs, as we need to exclude these fields explicitly, when we provided type information for them.

Further, to don't make the API even more confusing, we only allow the run method to write these attributes. The optimize methods have no way to write results (see #46, #45).

Overcomming both issues, we could allow to define nested typed classes to store results in.
With a little bit of magic (see below), we can enforce that each instance automatically gets a fresh instance of the class to write results in.

We could either enforce naiming of the these objects (e.g. r_, R_) for the actual results or we could use the decorator to mark and find them.

With that we could also allow to define specific additional optimization results. Either using a specific name or a seperate decorator.

from typing import Any, Literal, Optional, Type, Generic, TypeVar, Union, overload

T = TypeVar("T")


class _Generic:
    def __setattr__(self, __name: str, __value: Any) -> None:
        super().__setattr__(__name, __value)

    def __getattr__(self, __name: str) -> None:
        return self.__dict__[__name]


class result(Generic[T]):
    name: str
    klass: Type[T]

    def __init__(self, klass: Type[T] = _Generic):
        self.klass = klass

    def __set_name__(self, owner, name):
        self.name = name

    @overload
    def __get__(self, obj: Literal[None], objtype: Any) -> Type[T]:
        pass

    @overload
    def __get__(self, obj: object, objtype: Any) -> T:
        pass

    def __get__(self, obj: Optional[object], objtype: Any = None) -> Union[T, Type[T]]:
        if obj:
            new_instance = self.klass()
            name: str = getattr(self, "name", self.klass.__name__)
            setattr(obj, name, new_instance)
            return new_instance
        return self.klass


class ParentClassWithTypedResults:
    @result
    class R_:
        test: str


class ParentClassUntypedResults:
    r_ = result()


a = ParentClassUntypedResults()
a.something = "bla"

a = ParentClassWithTypedResults()
a.test = "blas"

Unfortunately, Pycharms autocomplete is not happy with the decorator and we don't get typechecking or autocomplete for the TypedResults case. VsCode works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant