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

Monkey patching support #718

Open
srittau opened this issue Apr 25, 2020 · 3 comments
Open

Monkey patching support #718

srittau opened this issue Apr 25, 2020 · 3 comments
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@srittau
Copy link
Collaborator

srittau commented Apr 25, 2020

These are just some not terribly well though out ideas about possible monkey support in typing. This would need a proper PEP if it was ever implemented, but I just want to record my ideas here:

# foo accepts a date object, but allows to add and access
# unknown attributes at runtime. It basically treats date
# as having __getattr__()/__setattr__() methods.
def foo(date: Dynamic[datetime.date]) -> None:
    date.my_attr = 123
    print(date.added_by_called)


# typing.dynamic() is a no-op at runtime and basically an alias
# for cast(Generic[X], y) at type-check time, where X is the
# type of y.
# In this example, dt has type Dynamic[datetime.date].
dt = dynamic(datetime.date.today())
foo(dt)

# The following would also work:
foo(datetime.date.today())
other_dt: datetime.date = dt

A possible extensions would be to define the allowed monkey-patched attributes. Something like:

class Monkey(Protocol):
    donkey: int

def foo(dt: Dynamic[datetime.date, Monkey]) -> None:
    # ok:
    print(dt.year)
    dt.donkey += 3
    # errors:
    print(dt.kong)
    dt.donkey += ""

dt = dynamic(datetime.date.today(), Monkey)
@srittau
Copy link
Collaborator Author

srittau commented Apr 25, 2020

One open question is: What does foo: Dynamic[X, Y] mean? Does is mean that foo is guaranteed to already have the attributes defined by Y or only that it allows those attributes to be set? The former would make x = dynamic(datetime.date.today(), Y) not work, the latter would compromise type safety.

@JukkaL
Copy link
Contributor

JukkaL commented Apr 27, 2020

Dynamic[X, Y] sounds similar to "unsafe unions" that have been discussed previously. X would be compatible with Dynamic[X, Y], and vice versa. Dynamic[X] could potentially be represented as an unsafe union of X and a type with suitable __getattr__ and __setattr__ methods.

@bluetech
Copy link

# The following would also work:
foo(datetime.date.today())
other_dt: datetime.date = dt

The two lines combine to mean that X is both a subtype and a supertype of Dynamic[X], isn't it a bit strange? I would have expected the first line not to work without a dynamic(...).


Dynamic[X, Y] sounds similar to "unsafe unions" that have been discussed previously.

Is a Union is the right concept for this? A monkeypatching can happen on top of another monkeypatching and override with a different type, which makes it non-commutative.

Maybe Augmented[X, Y], Augmented[X, Y, Z] == Augmented[Augmented[X, Y], Z]?


BTW, we've had a somewhat related use case in pytest, where un-type-safe monkey-patching was used extensively, and came up with this solution: https://github.com/pytest-dev/pytest/blob/5.4.2/src/_pytest/store.py. However it requires the cooperation of the source type to expose a "Store", so doesn't handle arbitrary augmentations of 3rd-party types.

@srittau srittau added the topic: feature Discussions about new features for Python's type annotations label Nov 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

3 participants