A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/pradeep90/annotation_collector below:

pradeep90/annotation_collector: Collect typed annotations from Python source code.

Overall Stats in Typeshed

See here for the raw types.

Annotation name Frequency in Typeshed Optional 10237 Tuple 2296 Union 2162 List 1937 Callable 1314 Dict 1286 Iterable 1261 Set 159

As of October 2021, Callable is the most frequently used special form that still requires an import. Others like List have a builtin equivalent like list. Optional[int] is very frequently used but is technically expressible as int | None. That may still be cumbersome, though.

Typed Projects - Callable type

Uses of the Callable special form:

Type Frequency Percentage Example Callables with 0 parameters 286 11% Callable[[], None] Callables with 1 parameters 796 31% Callable[[int], None] Callables with 2 parameters 235 9% Callable[[int, str], None] Callables with 3 parameters 59 2% Callable[[int, str, bool], None] Callables with 4 parameters 18 ~0% Callable[[A, B, C, D], None] Callables with 5 parameters 9 ~0% Callable[[A, B, C, D, E], None] Callables with arbitrary parameters 1082 42% Callable[..., None], Callable Callback Protocols 41 1% class MyCallback(Protocol): def __call__(x: int) -> str: ... Typed Projects - Callback Usage

How callbacks are used, regardless of whether they are given a Callable type (in mypy, spark, sphinx, and jax):

How the callback is used Frequency Percentage Example Callback is called with positional arguments 442 69% callback(1, "hello") Callback is called with *args, **kwargs 57 9% callback(*args, **kwargs) Callback is called with *args 67 10% callback(*args) Callback is called with **kwargs 13 2% callback(**kwargs) Callback is called with a named argument or default value 18 2% callback(1, greeting="hello") Class type 35 5% cls_type(height=2.0, width=3.0)

How callbacks are used (in django, sentry, and tensorflow):

How the callback is used Frequency Percentage Example Callback is called with positional arguments 526 43% callback(1, "hello") Callback is called with *args, **kwargs 319 26% callback(*args, **kwargs) Callback is called with *args 56 4% callback(*args) Callback is called with **kwargs 99 8% callback(**kwargs) Callback is called with a named argument or default value 28 2% callback(1, greeting="hello") Class type 181 15% cls_type(height=2.0, width=3.0)

Here are stats for common OSS projects. Click the project name to see the raw methods. There are two columns:

Project Method signatures with self or cls annotation Method bodies returning self or cls(...) Notes typeshed 523 0 mypy 2 8 tornado 1 4 Filtered out methods with self: Any. spark 57 127 Filtered out methods that needed the exact generic parameters self: RDD[Tuple[K, V]]. sphinx 0 11 jax 0 28 ignite 0 9 vision 0 2 pandas 228 126 scipy 0 33 black 3 2 tensorflow 2 200 Total 816 550

To get stats on Callable annotations, run:

./callable_annotations.py <directory>

To see the actual Callable annotations, run:

./callable_annotations.py <directory> --show-callables

For example:

$ ./callable_annotations.py ~/Programs/typeshed/stdlib/xmlrpc/
Callables with 0 parameters: 2
Callables with 1 parameters: 15
Callables with 2 parameters: 5
Callables with 3 parameters: 1
Callables with 4 parameters: 0
Callables with 5 parameters: 0
Callables with arbitrary parameters: 2
Callback Protocols: 6

$ ./callable_annotations.py ~/Programs/typeshed/stdlib/concurrent/ --show-callables
Callables with 0 parameters: 2
    Callable[[], None]
    Callable[[], None]
Callables with 1 parameters: 15
    Callable[[Any], None]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], Any]
    Callable[[str], str]
    Callable[[str], str]
Callables with 2 parameters: 5
    Callable[[Optional[str], Tuple[_Marshallable, ...]], Union[Fault, Tuple[_Marshallable, ...]]]
    Callable[[Optional[str], Tuple[_Marshallable, ...]], Union[Fault, Tuple[_Marshallable, ...]]]
    Callable[[Unmarshaller, str], None]
    Callable[[str, Tuple[_Marshallable, ...]], _Marshallable]
    Callable[[str, Tuple[_Marshallable, ...]], _Marshallable]
Callables with 3 parameters: 1
    Callable[[Marshaller, Any, Callable[[str], Any]], None]
Callables with 4 parameters: 0
Callables with 5 parameters: 0
Callables with arbitrary parameters: 2
    Callable[..., Any]
    Callable[..., Any]
Callback Protocols: 6
    _DispatchArity0 - def __call__(self) -> _Marshallable: pass
    _DispatchArity1 - def __call__(self, __arg1: _Marshallable) -> _Marshallable: pass
    _DispatchArity2 - def __call__(self, __arg1: _Marshallable, __arg2: _Marshallable) -> _Marshallable: pass
    _DispatchArity3 - def __call__(self, __arg1: _Marshallable, __arg2: _Marshallable, __arg3: _Marshallable) -> _Marshallable: pass
    _DispatchArity4 - def __call__(
        self, __arg1: _Marshallable, __arg2: _Marshallable, __arg3: _Marshallable, __arg4: _Marshallable
    ) -> _Marshallable: pass
    _DispatchArityN - def __call__(self, *args: _Marshallable) -> _Marshallable: pass
Calls to Callback Parameters

To see functions that call one of their parameters, use --show-callback-parameters:

$ ./callable_annotations.py --show-callback-parameters /Users/pradeepkumars/Programs/github-clones/django/django/views/decorators/http.py
Callables with 0 parameters: 0
Callables with 1 parameters: 0
Callables with 2 parameters: 0
Callables with 3 parameters: 0
Callables with 4 parameters: 0
Callables with 5 parameters: 0
Callables with arbitrary parameters: 0
Callback Protocols: 0
Functions with callback parameters: 3
    def condition(etag_func=None, last_modified_func=None): ...
    	etag_func(request, *args, **kwargs)
    	last_modified_func(request, *args, **kwargs)

    def decorator(func): ...
    	func(request, *args, **kwargs)

    def decorator(func): ...
    	func(request, *args, **kwargs)

Computed for the following repositories. Click to see the raw stats and callables.

Projects with well-typed callables

Combined stats:

Callables with 0 parameters: 258 (14.86%)
Callables with 1 parameters: 712 (41.01%)
Callables with 2 parameters: 210 (12.10%)
Callables with 3 parameters: 49 (2.82%)
Callables with 4 parameters: 15 (0.86%)
Callables with 5 parameters: 8 (0.46%)
Callables with arbitrary parameters: 443 (25.52%)
Callback Protocols: 41 (2.36%)
Projects with loosely-typed callables (mostly f: Callable)

Combined stats:

Callables with 0 parameters: 13 (1.76%)
Callables with 1 parameters: 62 (8.39%)
Callables with 2 parameters: 19 (2.57%)
Callables with 3 parameters: 9 (1.22%)
Callables with 4 parameters: 3 (0.41%)
Callables with 5 parameters: 0 (0.00%)
Callables with arbitrary parameters: 633 (85.66%)
Callback Protocols: 0 (0.00%)

Skipped:

Let's look at how callbacks are called in untyped Python code. (Click to see the individual functions.)

Weighted by function counts (biased towards tensorflow, which is very large):

Average of percentages:

Callback parameters in Typed Projects Calls to PyTorch register_buffer

To see the initial argument passed to the Pytorch method self.register_buffer:

$ python3 function_call.py /Users/pradeepkumars/Programs/github-clones/pytorch/torch/utils/ --verbose
PROGRESS: Parsed 20/103 files...
PROGRESS: Parsed 40/103 files...
PROGRESS: Parsed 60/103 files...
PROGRESS: Parsed 80/103 files...
PROGRESS: Parsed 100/103 files...
Register buffer calls: 12
dense_module.weight.to_mkldnn(dtype)
dense_module.bias.to_mkldnn()
torch.zeros([dense_module.weight.size(0)], dtype=torch.float).to_mkldnn()
dense_module.bias.to_mkldnn()
torch.zeros([dense_module.weight.size(0)], dtype=torch.float).to_mkldnn()
dense_module.weight.to_mkldnn(dtype)
torch._C._nn.mkldnn_reorder_conv2d_weight(
    dense_module.weight.to_mkldnn(dtype),
    self.padding,
    self.stride,
    self.dilation,
    self.groups)
torch._C._nn.mkldnn_reorder_conv3d_weight(
    dense_module.weight.to_mkldnn(dtype),
    self.padding,
    self.stride,
    self.dilation,
    self.groups)
dense_module.weight.to_mkldnn()
dense_module.bias.to_mkldnn()
dense_module.running_mean.to_mkldnn()
dense_module.running_var.to_mkldnn()
Calls that have a Literal Argument
./function_call.py /Users/pradeepkumars/Programs/github-clones/pytorch/torch/utils/mkldnn.py --verbose
...

Calls with literals: 12
self.register_buffer('weight', dense_module.weight.to_mkldnn(dtype))
self.register_buffer('bias', dense_module.bias.to_mkldnn())
self.register_buffer(
    'bias',
    torch.zeros([dense_module.weight.size(0)], dtype=torch.float).to_mkldnn())
self.register_buffer('bias', dense_module.bias.to_mkldnn())
self.register_buffer(
    'bias',
    torch.zeros([dense_module.weight.size(0)], dtype=torch.float).to_mkldnn())
self.register_buffer('weight', dense_module.weight.to_mkldnn(dtype))
self.register_buffer('weight', torch._C._nn.mkldnn_reorder_conv2d_weight(
    dense_module.weight.to_mkldnn(dtype),
    self.padding,
    self.stride,
    self.dilation,
    self.groups))
self.register_buffer('weight', torch._C._nn.mkldnn_reorder_conv3d_weight(
    dense_module.weight.to_mkldnn(dtype),
    self.padding,
    self.stride,
    self.dilation,
    self.groups))
self.register_buffer('weight', dense_module.weight.to_mkldnn())
self.register_buffer('bias', dense_module.bias.to_mkldnn())
self.register_buffer('running_mean', dense_module.running_mean.to_mkldnn())
self.register_buffer('running_var', dense_module.running_var.to_mkldnn())
Methods returning self or cls

If you have a method that returns an object of the same type, the way to write type annotations is as below:

T = TypeVar("T", bound="Base")

class Base:
    @classmethod
    def from_config(cls: Type[T], config: Dict[str, str]) -> T:
        return cls(**config)

class Child(Base):
    def child_method(self) -> None:
	    print("Child!")

Note that we have to use Type[T] as the type of cls and have a return type T. Otherwise, someone constructing a Child object using from_config will get an object of type Base, not Child.

# If we used `Base` as the return type of `from_config`.

class Base:
    @classmethod
    def from_config(cls: Type[T], config: Dict[str, str]) -> Base:
        return cls(**config)

class Child(Base):
    def child_method(self) -> None:
	    print("Child!")

def main() -> None:
	child = Child.from_config(config) # => actually of type Base
	child.child_method() # error: No method `child_method` in class Base.

For more details, see my presentation from the Typing Summit at PyCon 2021 (slides).

Methods where the self or cls parameter is annotated

Run the script as below:

python self_annotation.py /Users/pradeepkumars/Programs/typeshed/stdlib/distutils/version.pyi /Users/pradeepkumars/Programs/typeshed/stdlib/ctypes/__init__.pyi --verbose

Methods with `self` or `cls` annotations: 17
    def __lt__(self: _T, other: Union[_T, str]) -> bool: ...

    def __le__(self: _T, other: Union[_T, str]) -> bool: ...

    def __gt__(self: _T, other: Union[_T, str]) -> bool: ...

    def __ge__(self: _T, other: Union[_T, str]) -> bool: ...

    @abstractmethod
    def parse(self: _T, vstring: str) -> _T: ...

    @abstractmethod
    def _cmp(self: _T, other: Union[_T, str]) -> bool: ...

    def parse(self: _T, vstring: str) -> _T: ...

    def _cmp(self: _T, other: Union[_T, str]) -> bool: ...

    def parse(self: _T, vstring: str) -> _T: ...

    def _cmp(self: _T, other: Union[_T, str]) -> bool: ...

    # By default mypy complains about the following two methods, because strictly speaking cls
    # might not be a Type[_CT]. However this can never actually happen, because the only class that
    # uses _CDataMeta as its metaclass is _CData. So it's safe to ignore the errors here.
    def __mul__(cls: Type[_CT], other: int) -> Type[Array[_CT]]: ...  # type: ignore

    def __rmul__(cls: Type[_CT], other: int) -> Type[Array[_CT]]: ...  # type: ignore

    @classmethod
    def from_buffer(cls: Type[_CT], source: _WritableBuffer, offset: int = ...) -> _CT: ...

    @classmethod
    def from_buffer_copy(cls: Type[_CT], source: _ReadOnlyBuffer, offset: int = ...) -> _CT: ...

    @classmethod
    def from_address(cls: Type[_CT], address: int) -> _CT: ...

    @classmethod
    def from_param(cls: Type[_CT], obj: Any) -> _UnionT[_CT, _CArgObject]: ...

    @classmethod
    def in_dll(cls: Type[_CT], library: CDLL, name: str) -> _CT: ...
Methods that return self or cls(...) in their body

Run the script as below:

python self_annotation.py /Users/pradeepkumars/Programs/github-clones/tensorflow/tensorflow/python/autograph/operators/variables.py /Users/pradeepkumars/Programs/github-clones/tensorflow/tensorflow/python/keras/layers/recurrent.py --verbose

Methods returning `self` or `cls(...)`: 5
    def __getitem__(self, i):
        return self

    @classmethod
    def from_config(cls, config, custom_objects=None):
        from tensorflow.python.keras.layers import deserialize as deserialize_layer  # pylint: disable=g-import-not-at-top
        cells = []
        for cell_config in config.pop('cells'):
            cells.append(
                deserialize_layer(cell_config, custom_objects=custom_objects))
        return cls(cells, **config)

    @classmethod
    def from_config(cls, config):
        if 'implementation' in config:
            config.pop('implementation')
        return cls(**config)

    @classmethod
    def from_config(cls, config):
        if 'implementation' in config and config['implementation'] == 0:
            config['implementation'] = 1
        return cls(**config)

    @classmethod
    def from_config(cls, config):
        if 'implementation' in config and config['implementation'] == 0:
            config['implementation'] = 1
        return cls(**config)
# Ignore Mypy's copy of typeshed.
time python self_annotation.py /Users/pradeepkumars/Programs/mypy/misc /Users/pradeepkumars/Programs/mypy/mypyc /Users/pradeepkumars/Programs/mypy/scripts /Users/pradeepkumars/Programs/mypy/mypy/dmypy /Users/pradeepkumars/Programs/mypy/mypy/plugins /Users/pradeepkumars/Programs/mypy/mypy/server /Users/pradeepkumars/Programs/mypy/mypy/test /Users/pradeepkumars/Programs/mypy/mypy/xml /Users/pradeepkumars/Programs/mypy/mypy/*.py --verbose > data/mypy-non-typeshed-methods-returning-self.txt

time python self_annotation.py /Users/pradeepkumars/Programs/tornado/ --verbose > data/tornado-methods-returning-self.txt

for project in spark sphinx jax ignite vision pandas scipy black; do echo $project; time python self_annotation.py /Users/pradeepkumars/Programs/$project --verbose > data/$project-methods-returning-self.txt; echo ''; done

This includes annotations from parameter types, return types, attribute types, etc.

It extracts Callable[[int], str] from within List[Callable[[int], str]].

It doesn't:


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4