Skip to content

Alternative constructors with primitive types or NewTypes #415

Closed

Description

@davidroeca

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

Activity

  1. JelleZijlstra commented on Apr 25, 2017

    @JelleZijlstra
    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.

  2. davidroeca commented on Apr 25, 2017

    @davidroeca
    Author
  3. davidroeca commented on Apr 26, 2017

    @davidroeca
    Author

    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.

  4. ilevkivskyi commented on Apr 26, 2017

    @ilevkivskyi
    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.

  5. JukkaL commented on Apr 26, 2017

    @JukkaL
    Contributor

    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.

  6. davidroeca commented on Apr 26, 2017

    @davidroeca
    Author

    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

  7. added a commit that references this issue on Oct 7, 2018
  8. added
    topic: featureDiscussions about new features for Python's type annotations
    and removed on Nov 4, 2021
  9. srittau commented on Nov 4, 2021

    @srittau
    Collaborator

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    resolution: out of scopeThe idea or discussion was out of scope for this repositorytopic: featureDiscussions about new features for Python's type annotations

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions