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

Extending NewType to support "spreading" #3489

Closed
ddworken opened this issue Jun 1, 2017 · 2 comments
Closed

Extending NewType to support "spreading" #3489

ddworken opened this issue Jun 1, 2017 · 2 comments

Comments

@ddworken
Copy link

ddworken commented Jun 1, 2017

Currently NewType doesn't have any way of "spreading" whereby UserID(1) + UserID(2) would be a UserID (instead it is an int). I'm working on implementing a form of taint analysis using mypy for compile time detection of tainted data hitting sensitive sinks and adding this would be unbelievably helpful for my project and I imagine many others. Additionally, this was actually one of the suggested uses of NewType in #1284 but as far as I can tell it isn't possible given the current implementation of NewType.

The ultimate goal would be to make it so that something like this would pass type checking:

from typing import NewType, TypeVar, Callable

Type = NewType('Type', str, spread=True)

def src() -> Type:
	return Type("Type!")

def dst(data: Type) -> None:
	print(data)

dst(src())  # Currently passes
dst(src()+"OtherData")  # Currently fails type checking
dst("OtherData"+src())  # Currently fails type checking

What do people think of this as an extension to NewType?

@ddfisher
Copy link
Collaborator

ddfisher commented Jun 1, 2017

I'm not convinced this is generally useful enough to be worth adding to mypy. Instead, you could implement something like this yourself:

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    class TaintedString:
        def __init__(self, x: str) -> None: ...
        def __add__(self, x: str) -> TaintedString: ...
        def __radd__(self, x: str) -> TaintedString: ...
else:
    TaintedString = lambda x: x


def src() -> TaintedString:
	return TaintedString("Type!")

def dst(data: TaintedString) -> None:
	print(data)

dst(src())  # Currently passes
dst(src()+"OtherData")  # Passes
dst("OtherData"+src())  # Passes

One caveat is that TaintedString will need to re-specify all the string methods you want to use with appropriate type signatures, but in the worst case (if you want all of them) you can copy them from typeshed with minor modifications.

@ddworken ddworken closed this as completed Jun 1, 2017
@ddworken
Copy link
Author

ddworken commented Jun 1, 2017

Thanks for the feedback!

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

2 participants