Skip to content

More Features

KotlinIsland edited this page Jul 26, 2022 · 19 revisions

Strict Defaults

Basedmypy has all strictness options enabled by default. This can often be a little overwhelming, and the baseline functionality can help alleviate this. For a good compromise of safety and ease of use, we can recommend setting allow_any_expr.

Legacy Mode (--legacy)

By default basedmypy is as strict as possible with all inspection options enabled. If you desire mypy's selection of strictness you can use the config option --legacy. While this sets the configuration options to match mypys, functionality is not identical, see the changelog for a comprehensive list. Baseline functionality is still active in legacy mode.
To disable the baseline, invoke basedmypy specifying the baseline file as an empty string: mypy --baseline-file= src

Default Return Type of None (default_return)

Causes an unannotated return type to be inferred as None.

def foo(i: int):
  print(i)

reveal_type(foo)  # revealed type is "def(int)"

It is recommended to only apply this option in the specific modules that will use it, as partially typed third party code can cause problems.

[[tool.mypy-overrides]]
module = ["mypackage.*"]
default_return = true

This plays conservatively with allow_untyped_defs and allow_incomplete_defs

# mypy: default-return, allow-incomplete-defs, allow-untyped-defs
def foo(): ... # def() -> Any
def bar(a, b): ... # def(Any, Any) -> Any
def foo(a: int, b): ... # def(int, Any) -> None

Ignore Unused Ignores (type: ignore[X, unused-ignore])

Often when dealing with multi-platform code, type ignores produce false positives:

import sys

if sys.platform != "linux":
  foo()  # type: ignore[misc]
> mypy .
main.py:4: error: Unused "type: ignore" comment
Found 1 error in 1 file (checked 1 source file)

In basedmypy you can add the ignore code unused-ignore to ignore the unused ignore error:

import sys

if sys.platform != "linux":
  foo()  # type: ignore[misc, unused-ignore]
> mypy .
Success: no issues found in 1 source file

Nonlocal Partial Types (--nonlocal-partial-types)

The --local-partial-types flag in mypy is confusing, so in basedmypy it's removed in favor of the inverse --nonlocal-partial-types

ignore_any_from_error

Often times, a small error can cause hundreds of errors, this feature helps to surface only Any expressions that aren't from errors.

new in 1.4

Infer function types

Basedmypy can infer function parameter types from default values (restricted to literal expressions for now):

def foo(a=1): ...
reveal_type(foo)  # def (a: int = 1)

And property types from the getter:

class A:
    @property
    def foo(self) -> int: ...
    @foo.setter
    def foo(self, value): ...  # no need for annotations

Overload implementations from the parts:

@overload
def foo(a: int) -> int: ...
@overload
def foo(a: str) -> str: ...
def foo(a): ... # inferred type is (a: int | str) -> int | str

new in 1.4

basedtyping.Untyped and no-untyped-usage

Untyped is a specialized form of Any that can he helpful when gradually adopting type annotations:

a: Untyped

a = 1  # error: usage of untyped name
b = a  # error: usage of untyped name 

Basedmypy can now detect usage of partially typed functions:

def foo(a, b=1): ...  # inferred as def (a: Untyped, b: int = ...)
def bar(a: int, b): ...  # inferred as def (a: int, b: Untyped)

foo(1, 2)  # error: call to incomplete function
foo(1, 2)  # error: call to incomplete function

new in 1.4

incomplete-is-typed

A flag that assists with no-untyped-call to partial functions, it indicates that a partially typed function should be regarded as fully typed. This flag is different to most other options in that it applies to where the function is defined, not where it is called from.

new in 1.4

Bare Literals (bare-literals)

With this feature it is legal to use a literal int, bool or Enum in a type position when it is safe to do so. This safety is determined by whether __future__.annotations is active, if the file is a stub, if the literal is used in a type operation, and if the literal is used in an expression position(TypeVar etc)

a: 1  # valid
b: 1 | 2  # invalid

from __future__ import annotations
c: 1 | 2  # valid
D = TypeVar("D", 1, 2)  # invalid
# test.pyi
D = TypeVar("C", 1, 2)  # valid

new in 1.5