TIL in my #python#mypy adventures, the proper way to set up a class that returns itself is to use the Self typing annotation and return values by calling self.__class__ on the new value
from typing import Self
class ImActuallyAString(str):
def one_longer(self) -> Self:
return self.__class__(self + "one")
This feeling when you search for answers, find people with the same questions, who wrote about possible solutions (not once but twice!), but their website is not responding…
@nedbat I couldn't find a cached version (quite probably I didn't look hard enough).
In my case, the offending part was:
class Foo:
bar: Bar = None
Tried:
class Foo:
bar: Optional[Bar] = None
This makes #mypy happy in that spot, but then I would have needed to disambiguate the type (via asserts and the like) all the time, so I went for something simple yet not entirely satisfactory:
class Foo:
bar: Bar = None # type: ignore
And everything else expects bar to be Bar, not None.
I'm always fascinated how amazing the :python: #Python standard library is.
itertools, collections, dataclasses, subprocess, unittest, logging, argparse, pathlib, json, re, shlex [the list goes on] are all so incredibly useful and you can rely on them as they're always there (paying attention to versioning of course).
And with type hints and #mypy I guess I can stay with just Python for a little longer 😉
In addition to using #mypy , can anyone share any guidance, tooling, or blogs that may help steer a #python application towards the "TypeState" pattern? I'm also curious if there are references comparing the "State" pattern to the "TypeState" pattern (Rust).
I suppose I'm looking specifically for Python comparisons with #rust, e.g. if there were a part 2 for the article here:
Comprehensions are currently compiled as nested functions, which provides isolation of the comprehension’s iteration variable, but is inefficient at runtime. This PEP proposes to inline list, dictionary, and set comprehensions into the code where they are defined, and provide the expected isolation by pushing/popping clashing locals on the stack.
Last: F Strings will support some common use cases that broke interpolation in the past, like f'{ myDict['myKey'] }' and f"{'n'.join(a)}"
Asking for specific #examples type checking finds is ... unproductive. You write 2 modules of code, run #mypy, and get a list of the 11 places you need to fix - before you've even written unit tests that may or may not have caught the same problem.
If I tried to keep track of them all, I wouldn't have time to write code.
I just realize: As far as I understand #mypy, my previous #python Elastic Search example wouldn't be caught by #mypy because the parameter was passed to a logging function using formating via an f-string.
hot take: dynamic languages like #python and #javascript would benefit a lot by a little type checking around async/await constructs — simply emitting a compiler error (or even a warning) when you don’t await an async function call would save massive amounts of time
@kellogh In #python, #mypy already reports not awaited functions that you don't assign anywhere. And if you do assign, you'll get a type error when you try to use it as a value instead of as a coroutine.
Turns out using func(**kwargs)becomes very inconvinient, when you're using type-checking.
Pyright 1.1.312 landed a change:
> ... The new behavior matches that of mypy and assumes that the unpacked dict may supply arguments for all otherwise-unmatched keyword parameters even if they have default argument values.
At first, I didn’t like type hints in #Python, but we decided to give it a go since our codebase really exploded in the last couple of years. All I can say now is we should have done it earlier. I still find it unbealivable that we discovered so many small bugs that went unnoticed all these years.
@folkerschamel@_alen I have plenty of examples! I'm integrating #mypy with a 400k LoC #Django monolith (with a help of mypy-baseline), and it uncovers hell of a lot of bugs and bad design choices. The number one bag is, perhaps, a nullable Django model field (detected with django-stubs mypy plugin) that isn't checked for null. Something like this:
send_email(request.user.email, 'hi')
Which will explode if we don't check the user isn't anonymous and that they have an email address.
I really enjoy #mypy updates: transparent, regression-free, and each time it seems #mypy understands more things about my code, so I can remove some type-ignore comments. Kudos to #mypy's maintainers and contributors!