Code Monkey home page Code Monkey logo

basedmypy's People

Contributors

97littleleaf11 avatar alexwaygood avatar cdce8p avatar ddfisher avatar ecprice avatar elazarg avatar ethanhs avatar gnprice avatar gvanrossum avatar hauntsaninja avatar hughhan1 avatar ikonst avatar ilevkivskyi avatar ilinum avatar ivuk avatar jellezijlstra avatar jhance avatar jukkal avatar kotlinisland avatar matthiaskramm avatar michael0x2a avatar msullivan avatar o11c avatar pkch avatar pranavrajpal avatar rwbarton avatar sobolevn avatar spkersten avatar srittau avatar th3charlie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

basedmypy's Issues

warn when type could be wider/narrower

Wider

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')".

Narrower

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')".

Narrow variables when `cast`

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.

overloads without `@overload`

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

Intersection types

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: ...

Bare literal types (without `Literal`) and support `ForwardRef` in types tracking issue

# 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`
  • support non string literal types (#137)
    • int
    • bool
    • Enum
  • tuple
  • support strings as literal types in type annotations (#361)
  • support ForwardRef or some alternative in type aliases

An easy route would be to not use ForwardRef at all and just force usage of Literal in type aliases.

make strict default

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.

  • disallow_any_unimported
  • disallow_any_decorated
  • disallow_any_explicit
  • disallow_any_generics
  • disallow_subclassing_any
  • disallow_untyped_calls
  • disallow_untyped_defs
  • disallow_incomplete_defs
  • check_untyped_defs
  • disallow_untyped_decorators
  • no_implicit_optional
  • warn_redundant_casts
  • warn_unused_ignores
  • warn_return_any
  • warn_unreachable
  • allow_redefinition
  • implicit_reexport = false
  • strict_equality
  • show_error_codes

Support extension stubs / type augmentation

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]): ...

Alternative

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.

Additional points

sitecustomize.py could be a useful place to do things

Add an error code for unstable-variance

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]

Type some of the type machinery, namely `Literal`, `Union` etc

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?

add support to incrementally adopt features from basedmypy

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

Support multidefs

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

assert style type guards

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

Notes:

  • Would want to be able to provide an assertion and a return type
    def f(x: object) -> Asserts[x is int] & str: ...
  • Would want to be able to do 'truthy' assertions / invariants
    def asserts(x: object) -> Asserts[x] ...
    a: object
    asserts(isinstance(a, bool))
    reveal_type(a)  # bool

Support for `ReifiedGeneric`s

Reified Generics in basedtyping need special casing in basedmypy.

isinstance and issubclass:

class Foo(ReifiedGeneric[T]): ...

isinstance(Foo[int](), Foo[int])

Ban TypeVars:

def foo(t: T):
    a: ReifiedList[T]  # should be an error

Add a `lib` mode that is 484 compatable

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.

Support unbound generics

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]

Baseline (Basedline) / Support incremental adoption of strictness flags

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.

unsafe variance errors shouldn't propagate down

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: ...

playground

Add `Void` type

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

Allow usage of all `typing` members in annotations

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

immutable collections by default (`mutable`/covariant/protocol/nominal)

Using Sequence when you want an covariant or immutable list is not always optimal.

We propose:

  • ListLike/DictLike etc protocols
  • A mutable use site modifier that will make mutation methods accessible (append, clear, etc)
    • update the definition of the collections with markers on the mutable methods
  • Make the default type of the collections immutable and covariant

such that

Sequence
↑
ListLike
↑
list
↑
mutable[list]

A collection coming from third party code (inc std) would always be a mutable[list].

Default return type

But should it be None, Void or inferred?

  • Default to None
  • Once Void is implemented, return that instead.
  • Add return type inference later.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.