Please ignore type hinting on function return values on the browser

Type hinting is usually ignored on the browser, which is good, because it allows to add type hinting to the module and take advantage of it when working on it offline, with PyCharm for example.

Unfortunately it is not ignored when it defines the return type of a function:

# this imports typing only when working offline or on the server (good)
if anvil.server.context.type != 'browser':
    from typing import Dict

# this works on the server and is ignored on the browser (good)
cookies_1: Dict[str, Cookie] = {}

# this works on the server and FAILS on the browser (bad)
@property
def cookies_2(self) -> Dict[str, Cookie]:

EDIT
The workaround is easy: enclose the type hinting expression in quotes:

# this works
@property
def cookies_2(self) -> 'Dict[str, Cookie]':

Since skulpt attempts to mirror Cpython in its implementation this is unlikely to change.

Whilst it feels like type hints are ignored by python and require an external type checker like mypy or an IDE to work, it’s only part of the story.

def inc(x: int) -> int:
    return x + 1

print(inc.__annotations__)
# {'x': <class 'int'>, 'return': <class 'int'>}

In this example you see that python actually uses the type annotations and they are a property of the function.

This is the same with module annotations and class annotations.

# Module1

foo: str

class A:
  x: int

print(__annotations__) # modules have __annotations__ if they define them
# {'foo': <class 'str'>}

print(A.__annotations__) # classes have a __annotations__ if they define them
# {'x': <class 'int'>}

The only place type annotations are ignored in python (so far as I’m aware) is inside the body of a function.

def foo():
    x: foobarbaz # I am ignored by the compiler

So I assume that in the first example - cookies_1 is defined inside the body of a function somewhere.

If it was a top level module variable or a class annotation it would get compiled and throw a NameError for Dict.


When is this useful?
At some point skulpt will support the dataclasses module. It explicitly uses the class __annotations__ to infer the __init__ method.

from dataclasses import dataclass

@dataclass
@anvil.server.portable_class
class Person:
    first_name: str
    last_name: str


In the snippet provided, the client doesn’t import the typing module but the variables are used as if they’re in the namespace, which might lead to future problems (it already leads to problems):

Another way might be to create a mocktyping module

class GeneircType:
    def __getitem__(self, item):
        return self
    def __call__(self, *args, **kws):
        return self

def __getattr__(self, name):
    return GenericType()

try:
    from typing import Dict
except ImportError:
    from .mocktyping import Dict


related discussion:

Typing module gone missing

4 Likes