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

Alternative constructors with primitive types or NewTypes #415

Closed
davidroeca opened this issue Apr 25, 2017 · 7 comments
Closed

Alternative constructors with primitive types or NewTypes #415

davidroeca opened this issue Apr 25, 2017 · 7 comments
Labels
resolution: out of scope The idea or discussion was out of scope for this repository topic: feature Discussions about new features for Python's type annotations

Comments

@davidroeca
Copy link

davidroeca commented Apr 25, 2017

Hi typing team,

I've noticed that typing.cast and NewType essentially provide the exact same functionality. This makes NewType merely a type alias for convenience.

I'd like NewType to provide the ability to either pass in a callable that serves as the constructor, or for the library to provide an alternative function called ValidatedType (or AlternativelyConstructedType or something like that), implemented in this way (or something similar):

def ValidatedType(
        name,
        parent_type,
        validate_and_initialize  # this will be a Callable[[Any], parent_type]
):
    '''Follows typing NewType and runs the validation function'''
    def validated_type(x):
        return validate_and_initialize(x)
    validated_type.__name__ = name
    validated_type.__supertype__ = parent_type
    return validated_type

This may add some overhead, but it also adds more clarity to codebases and is worth considering.

See python/mypy#3200 -- created this issue here since mypy might not be the right repo to direct this feature request to

@JelleZijlstra
Copy link
Member

I don't think cast is similar to NewType; you can't use a cast in a type annotation.

More broadly, we've generally avoided putting things in typing that affect runtime behavior. I'm not sure what you're asking for is common enough to be added to typing.

@davidroeca
Copy link
Author

davidroeca commented Apr 25, 2017 via email

@davidroeca
Copy link
Author

davidroeca commented Apr 26, 2017

Re: cast vs NewType:

Fair enough, NewType allows for type annotions, which is very valuable, and which is also why I believe that some variant would be useful. The casting of the type is essentially what happens when the inner/hidden new_type function (https://github.com/python/typing/blob/master/src/typing.py#L2178) is called, and that to me is the value in using NewType's constructor (i.e. calling the inner new_type function).

To me, it seems as though this inner new_type function is an optimized special case of something more general. I may be wrong, but customization of this function will not likely add too much overhead to someone who opts out of such a customization and just uses the supported defaults.

@ilevkivskyi
Copy link
Member

More broadly, we've generally avoided putting things in typing that affect runtime behavior. I'm not sure what you're asking for is common enough to be added to typing.

I mostly agree, I think this is more suitable for runtime type enforcement libs like enforce, typecheck-decorator, or typeguard.

There is still something that could be supported statically on literal level, like positive/negative numbers, fixed length/value strings, but we already have an issue for this in mypy python/mypy#3062.

@ilevkivskyi ilevkivskyi added enhancement resolution: out of scope The idea or discussion was out of scope for this repository labels Apr 26, 2017
@JukkaL
Copy link
Contributor

JukkaL commented Apr 26, 2017

I'd probably have a custom constructor for NewType values. For example:

MyType = NewType('MyType', str)

def make_my_type(x: str) -> MyType:
    # do whatever validation and initialization that is needed
    return <whatever>

You can still call MyType directly so this does not enforce anything. It would be easy enough to add a custom lint rule to reject calls to NewType. If you need anything fancier, you are better off writing a custom class. You can perhaps use __new__ to return an instance of another class as the runtime value.

@davidroeca
Copy link
Author

davidroeca commented Apr 26, 2017

I've tried most work-arounds and in my case I've settled with a validator class that maintains internal properties for validation. Unfortunately it looks like the new method doing fancy stuff is of low priority for now python/mypy#1020.

I do like the idea of adding a lint test, though for some cases such as the typed NamedTuple, it's valuable to couple the constructor with the type. and you essentially can't work with the constructor unless NamedTuple itself gets changed -- it will implicitly cast.

EDIT: Realizing that my references to NamedTuple were app-specific modifications

jszopi added a commit to jszopi/repESP that referenced this issue Oct 7, 2018
NewType had many limitations: not supported in sphinx, not possible to
override __repr__, and requirement for standalone helper constructors, like:
python/typing#415 (comment)

My reservations about creating a custom class was performance, but I
hope that was addressed by inheriting from float (or tuple, in the case
of coords) and setting empty __slots__.
@srittau srittau added topic: feature Discussions about new features for Python's type annotations and removed enhancement labels Nov 4, 2021
@srittau
Copy link
Collaborator

srittau commented Nov 4, 2021

Static type checking can't execute Python code, as by now we have type checkers written in Python, C, JavaScript, Java. Therefore I am closing this here.

@srittau srittau closed this as completed Nov 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
resolution: out of scope The idea or discussion was out of scope for this repository topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

5 participants