kotlinisland / basedmypy Goto Github PK
View Code? Open in Web Editor NEWThis project forked from python/mypy
Based Python static type checker with baseline, sane default settings and based typing features
License: Other
This project forked from python/mypy
Based Python static type checker with baseline, sane default settings and based typing features
License: Other
class A:
def foo(): ...
class B(A):
def bar(): ...
def foo(b: B):
b.foo()
I would expect that the type annotation for b
would give a warning: "type could be wider ('A')".
def foo(f: Callable[[B], None]): ...
foo(
cast(
Callable[[A], None], # should be: type could be narrower ('Callable[[B], None]')
lambda a: a.foo()
)
)
This example is pretty bad because it's using a cast, it's supposed to be:
fun foo(f: (B) -> Unit) {}
foo { a: A -> a.foo() } # should be: type of 'a' could be narrower ('B')
see this
def foo(a: int) -> int | None:
return a + 1
I would expect that the return type annotation would give a warning: "type could be narrower ('int')".
a: int = 1
b: typeof[a] = 2
typeof
or TypeOf
?
Feature
Usages of cast
should narrow a variable
def foo(a: A):
b = cast(B, a)
reveal_type(a) # expect: A & B, actual: A
reveal_type(b) # expect: B, actual: B
Allegedly, cast is only used for sus dynamic nonsense. I've heard basedtyping is planning on implementing a based cast that performs a lot more cool stuff and shouldn't require any implicit functionality.
Currently they are all under misc
, dynamic
sounds a lot better.
@overload
? YUCK, the impl doesn't even do anything
@overload
def foo(x: int): ...
@overload
def foo(x: str): ...
def foo(x): print(x)
def foo(x: int): ...
def foo(x: str): ...
def foo(x): print(x)
Would be much more based.
int
ducktypes to float
, whacky alert!, add a Float
type that doesn't ducktype.
def foo(f: Float): ...
foo(1) # invalid
Add support for Intersection types.
Intersection[A, B]
== <subclass of "A" and "B">
.
class A:
def foo(self) -> A: ...
class B:
def foo(self) -> B: ...
class C(A, B):
def foo(self) -> A & B: ...
Due to the sussy-ness of future annotations, this should be opt in.
Due to it getting canceled maybe this isn't a good one then.
To specify that this is based
# from __future__ import annotations
from typing import ForwardRef
def foo(a: "asdf") -> True: # literal string `"asdf"`
...
MyType: TypeAlias = int | ForwardRef("asdf") # a forward reference to the type `asdf`
ForwardRef
or some alternative in type aliasesAn easy route would be to not use ForwardRef
at all and just force usage of Literal
in type aliases.
Change all defaults to be strict but reasonable
The --strict
switch sounds reasonable, but doesn't activate "disallow_any_explicit" which I think should be enabled.
Overriding existing types and monkey patching sounds based.
@extension[str]
class StrExtension:
foo: int
"asdf".foo + 1
While often frowned upon(just fix it at the source), it could be also be useful for fixing up third-party packages that have incomplete / incorrect stubs:
Official stub:
class SomeThirdPartyClass:
def foo(self, a, b, c): ...
vendored stub:
@extension[SomeThirdPartyClass]
class _SomeThirdPartyClass:
def foo(self, a: int, b: str, c: bool) -> Foo: ...
There would need to be some thought as to how this could be applied to module level declarations, perhaps steal module
from typescript?
An option to specify overriding vs augmenting would be needed.
Also, should it be a decorator, or part of the class bases?
@extension[str]
class StrExtension: ...
class StrExtension(Extension[str]): ...
An alternative to this approach could be a magic module path like __extensions__
/__overrides__
. Everything in this folder would mirror the module space(eg: __extensions__/SomeThirdPartyPackage/SomeThirdPartyModule.py
). Anything in this directory would be applied on top of the base types.
sitecustomize.py
could be a useful place to do things
Bivariance is certified cringe, but it has it's moments.
Mypy currently categorizes misuse of a typevar into misc
but I think that there should be a unstable-variance
Would also need an explainer message along the lines of:
"This usage of T
is incorrect for it's variance type, if this is intentional and you know what you are doing, you can ignore this line with 'unstable-variance'"
from typing import Generic, TypeVar
T_co = TypeVar("T_co", covariant=True)
class Foo(Generic[T_co]):
def foo(self, a: T_co) -> None: # type: ignore[misc]
...
Foo[int]().foo("") # error: Argument 1 to "foo" of "Foo" has incompatible type "str"; expected "int" [arg-type]
Maybe if upstream has a release a pr could be generated for a bmypy based release.
But not master branch, that would suck I think.
We have a based 100 seat client that is requesting the ability to perform operations on type annotations while also retaining the typing of the values, eg something along the lines of:
T = TypeVar("T", bound=tuple[object, ...])
def literal_to_tuple(l: LiteralTypeAnontaion[T]) -> T:
return get_args(l)
literal_to_tuple(Literla[1]) # prints (1,) and has the type `tuple[1]`
It's not currently possible to use _LiteralSpecialForm
(the type of a Literal
annotation) it isn't exported/typed or generic.
What if there was a LiteralType
and it was generic to the parameters.
Would this require variadic generics? or a way to spread a tuple type or something?
Cringe:
a: int = "asdf" # type: ignore
Based:
a: int = "asdf" # type: ignore[assignment]
As there are breaking features in basedmypy, I would want a way to gradually adopt them.
maybe on a file level, such that the whole file will use normal mypy rules until it is updated to be compatible with basedmypy, then the file will become basedmypy only
if thing:
def foo(x: A) -> A: ...
else:
def foo(x: B) -> B: ...
# expected
reveal_type(foo) # (x: A & B) -> A | B
currently error: All conditional function variants must have identical signatures
Important to keep separate from python/mypy
def f(x: object) -> TypeAssertion[int]: # demarcation is tentative, maybe `Asserts[x is int]`
assert isinstance(x, int)
a: object
f(a)
reveal_type(a) # int is
def f(x: object) -> Asserts[x is int] & str: ...
def asserts(x: object) -> Asserts[x] ...
a: object
asserts(isinstance(a, bool))
reveal_type(a) # bool
Reified Generics in basedtyping need special casing in basedmypy.
isinstance
and issubclass
:
class Foo(ReifiedGeneric[T]): ...
isinstance(Foo[int](), Foo[int])
Ban TypeVar
s:
def foo(t: T):
a: ReifiedList[T] # should be an error
a: int = 1 # type: ignore[assignment]
error: unused "type: ignore" comment
This error should be suppressible with:
a: bool = "" # type: ignore[assignment, unused-ignore]
lib authors won't be able to use this at all if it has breaking changes, so add a lib
mode that is compatible with mypy.
Honestly this sounds very unbased.
a = 1
a = 2 # should be an error imo
a: var = 1
a = 2 # yeah, that's ok
Feature
We could use ...
, but that might cause trouble with tuple
and Callable
so idk.
def foo(l: list[...]):
print(l)
https://kotlinlang.org/docs/generics.html#star-projections
T = TypeVar(bound=TUpper)
T_co = TypeVar(bound=TUpper, covariant=True)
T_cont = TypeVar(contravariant=True)
NoReturn_cont = TypeVar(bound=NoReturn, contravariant=True)
class Foo(Generic[T_co]): ...
Foo[...] = Foo[T_co]
class Foo(Generic[T_cont]): ...
Foo[...] = Foo[NoReturn_cont]
class Foo(Generic[T]): ...
Foo[...] = Foo[T_co]
Adopting new strictness flags is based, but it's sucks that you have to go and fix a million usages of things.
Would be super based if mypy supported incremental adoption of flags where old usages are still valid but new usages are invalid.
I think that it could work by storing a file containing all the invalid usages at a point in time, which is committed to the repo. Any error in that file is then ignored when mypy is run.
Probs would want the ability to add things to that list, like if an error gets updated incidentally.
would need new cli options for baselining the ignore list.
This would be a pretty big feature.
Same thing with unsafe variance in protocol inheritance:
from typing import Protocol, _T_co as T_co
class A(Protocol[T_co]): # type: ignore
def foo(self, t: T_co) -> None: ... # type: ignore
class B(A[T_co], Protocol): # ERROR! using covariant type variable where invariant one expected!!!
def bar(self) -> T_co: ...
A type that is distinct from None
that serves the purpose of being useless.
All usages of it should be reported as warnings.
I wonder if Void
should be the root type?
So in typing land None
actually means Void
when it's the sole return type.
But there are other use cases:
fn1: Callable[[int], None] = lambda arg: arg
fn2: Callable[[int], Optional[str]] = fn1 # Note this assignment
value: Optional[str] = fn2(123) # value would be int actually
a: Callable[[], None] = lambda: 1
b: Callable[[], None | str] = a # INVALID!
v: str | None = b()
assert v
reveal_type(v) # str, but it's actually int
a: Callable[[], int] = ...
b: Callable[[], Void] = a # valid, the return type is covariant and Void is the root type
v: str | Void = b() # probs an error?
assert not isinstance(b, Void)
reveal_type(v) # <nothing>, unreachable
And remove the fake stub in typeshed folder
it's cringe, and differs from daemon
Would be based to help transition people to pyproject.
TypeGuard
is a certified cringe moment, it should not be bivariant.
def f(x: list[object]) -> TypeGuard[list[int]]: ... # expected error
I think this should be possible:
a: () -> int = lambda: 1
a: () -> int = 1
^^
SyntaxError: invalid syntax
nah
def foo() -> Never: ... # allowed
b = Union[int, str] # not allowed
basedtyping
as well.
Maybe types
as well.
We could modify sitecustomize.py
to actually load these for real. (mypy install-site-types
maybe)
b = Union[int, str] # allowed
Using Sequence
when you want an covariant or immutable list
is not always optimal.
We propose:
ListLike
/DictLike
etc protocolsmutable
use site modifier that will make mutation methods accessible (append, clear, etc)
such that
Sequence
↑
ListLike
↑
list
↑
mutable[list]
A collection coming from third party code (inc std) would always be a mutable[list]
.
I assume the breaking changes introduced broken tests.
But should it be None
, Void
or inferred?
None
Void
is implemented, return that instead.A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.