[HN Gopher] Comparing Python Type Checkers: Typing Spec Conformance
___________________________________________________________________
Comparing Python Type Checkers: Typing Spec Conformance
Author : ocamoss
Score : 84 points
Date : 2026-03-16 12:25 UTC (10 hours ago)
(HTM) web link (pyrefly.org)
(TXT) w3m dump (pyrefly.org)
| persedes wrote:
| Article is a nice write up of
| https://htmlpreview.github.io/?https://github.com/python/typ...
|
| (glad they include ty now)
| Pay08 wrote:
| I still can't get over the utter idiocy in Python's type hints
| being decorative. In what world does x: int = "thing" not give
| someone in the standardisation process pause?
| dcreager wrote:
| Can you elaborate what you mean by decorative?
|
| If you run a type checker like ty or pyright they're not
| decorative -- you'll get clear diagnostics for that particular
| example [1], and any other type errors you might have. You can
| set up CI so that e.g. blocks PRs from being merged, just like
| any other test failure.
|
| If you mean types not being checked at runtime, the consensus
| is that most users don't want to pay the cost of the checks
| every time the program is run. It's more cost-effective to do
| those checks at development/test/CI time using a type checker,
| as described above. But if you _do_ want that, you can opt in
| to that using something like beartype [2].
|
| [1] https://play.ty.dev/905db656-e271-4a3a-b27d-18a4dd45f5da
|
| [2] https://github.com/beartype/beartype/
| Pay08 wrote:
| Exactly my point. If I need to run 300 external tools for a
| language feature to be worth a damn, why is it a language
| feature?
| wiseowise wrote:
| 'uvx ty check' or 'uvx pyrefly check'. That's hardly 300
| external tools.
| badlibrarian wrote:
| It's a community that delayed progress for a decade while they
| waited for everyone to put parenthesis on the print statement.
| Give 'em enough time and they'll figure out best practices.
| Spivak wrote:
| In C-ish languages the statement int x =
| "thing"
|
| is perfectly valid. It means reserve a spot for a 32 bit int
| and then shove the pointer to the string "thing" at the address
| of x. It will do the wrong thing and also overflow memory but
| you could generate code for it. The type checker is what stops
| you. It's the same in Python, if you make type checking a build
| breaker then the annotations mean something. Types aren't
| checked at runtime but C doesn't check them either.
| lefra wrote:
| In C, int may be as small as 16 bits You may get 32 bits (or
| more) but it's not guaranteed. I don't see how you get a
| memory overflow though?
|
| I'd be surprised if a compiler with -Wall -Werror accepts to
| compile this.
|
| Trying to cast back the int to a char* might work if the
| pointers are the same size as int on the target platform, but
| it's actually Undefined Behaviour IIRC.
| Pay08 wrote:
| I guess an overflow would be possible if the size of a
| point and int differs.
| Pay08 wrote:
| It's valid in C, due to semantics around pointers. Try that
| in Java and you'll quickly find that it's not valid in "C-ish
| languages". C absolutely checks types, it's just weakly
| typed. Python doesn't check types at all, which I wouldn't
| have a problem with, if the language didn't have type
| annotations that sure look like they'll do something.
| tialaramex wrote:
| It won't "overflow memory".
|
| This says there will be an immutable array of six bytes, with
| the ASCII letters for "thing" in the first five and then the
| sixth is zero, this array can be coerced to the pointer type
| char* (a pointer to bytes) and then (though a modern C
| compiler will tell you this is a terrible idea) coerced to
| the signed integer type int.
|
| The six byte array will end up in the "read only data"
| section of the executable, it doesn't "overflow memory" and
| isn't stored in the x. Even if you gave x a more sensible
| type "char*" that word "thing" isn't somehow stored in your
| variable, it's a pointer.
|
| So, this isn't the same at all _and_ you don 't understand C
| as well as you thought you did.
|
| Edited: fix escaping bold markers
| Daishiman wrote:
| It's the complete opposite. The objective of type hints is that
| they're optional precisely because type hints narrow the
| functionality of the language. And evidenced by the fact that
| different type checks have different heuristics for determining
| what is a valid typed program and what isn't, it seems that the
| decision is correct.
|
| No type system will allow for the dynamism that Python
| supports. It's not a question of how you annotate types, it's
| about how you resolve types.
| hrmtst93837 wrote:
| Optional on paper, sure. Once you publish shared libs or keep
| a nontrivial repo usable across teams, type hints stop
| feeling optional fast, because the minute mypy, pyright, and
| Pyre disagree on metaprogramming or runtime patching you get
| three incompatible stories about the same program and a pile
| of contraditions instead of signal. Python can stay dynamic,
| yet this setup mostly buys busywork for CI and false
| confidence for humans.
| Pay08 wrote:
| Nobody is saying they are mandatory, and I'm actually a big
| fan of gradual typing. My point is that they do nothing.
|
| However, type hints reducing the functionality of the
| language isn't true either.
| martinky24 wrote:
| I've been using ty on some previously untyped codebases at work.
| It does a good job of being fast and easy to use while catching
| many issues without being overly draconian.
|
| My teammates who were writing untyped Python previously don't
| seem to mind it. It's a good addition to the ecosystem!
| tfrancisl wrote:
| And it makes it infinitely easier for them to get with the
| times and start typing their code!
| ddxv wrote:
| I've used mypy forever and never even tried these others. Looking
| at them though it looks like it's worth trying out Zuban or
| Pyright? Is there a noticeable benefit when switching between
| different checkers?
| x187463 wrote:
| Speed, especially in larger codebases.
| rirze wrote:
| If you care about correctness, unless you pick pyright, don't
| bother at the moment. If you're creating a new project and
| looking for a promise for better faster typing, then pick one
| of Zuban, Pyrefly, or ty.
| winrid wrote:
| Mypy still best for Django
| lastofus wrote:
| As a long time Django user that wants to start using typing,
| can you elaborate on why mypy is still the way to go?
| vesselapi wrote:
| Django's ORM generates a lot of dynamic attributes --
| querysets, related managers, model fields -- that don't
| exist as static class members. The django-stubs plugin for
| mypy has years of work encoding those patterns as special-
| case type narrowing rules. Pyright handles some of it
| through its own django plugin, but mypy+django-stubs is
| still the most battle-tested combo for catching things like
| filter() field name typos or wrong annotation on a
| ForeignKey. It's less about mypy being better in general
| and more about the plugin ecosystem being further along.
| Scene_Cast2 wrote:
| Are there any good static (i.e. not runtime) type checkers for
| arrays and tensors? E.g. "16x64x256 fp16" in numpy, pytorch, jax,
| cupy, or whatever framework. Would be pretty useful for ML work.
| ocamoss wrote:
| We're working on statically checking Jaxtyping annotations in
| Pyrefly, but it's incomplete and not ready to use yet :)
| jmalicki wrote:
| Have you looked at jaxtyping? I've found it to be pretty useful
| - it works for PyTorch not just Jax.
|
| https://github.com/patrick-kidger/jaxtyping
| westurner wrote:
| - /?hnlog pycontract icontract
| https://westurner.github.io/hnlog/ :
|
| From https://news.ycombinator.com/item?id=14246095 (2017) :
|
| > _PyContracts supports runtime type-checking and value
| constraints /assertions (as @contract decorators, annotations,
| and docstrings)._
|
| > _Unfortunately, there 's yet no unifying syntax between
| PyContracts and the newer python type annotations which MyPy
| checks at compile-type._
|
| Or beartype.
|
| Pycontracts has: https://andreacensi.github.io/contracts/ :
| @contract def my_function(a : 'int,>0', b :
| 'list[N],N>0') -> 'list[N]':
| @contract(image='array[HxWx3](uint8),H>10,W>10') def
| recolor(image):
|
| For icontract, there's icontract-hyothesis.
|
| parquery/icontract: https://github.com/Parquery/icontract :
|
| > _There exist a couple of contract libraries. However, at the
| time of this writing (September 2018), they all required the
| programmer either to learn a new syntax (PyContracts) or to
| write redundant condition descriptions ( e.g., contracts,
| covenant, deal, dpcontracts, pyadbc and pcd)._
| @icontract.require(lambda x: x > 3, "x must not be small")
| def some_func(x: int, y: int = 5) -> None:
|
| icontract with numpy array types:
| @icontract.require(lambda arr: isinstance(arr, np.ndarray))
| @icontract.require(lambda arr: arr.shape == (3, 3))
| @icontract.require(lambda arr: np.all(arr >= 0), "All elements
| must be non-negative") def process_matrix(arr:
| np.ndarray): return np.sum(arr)
| invalid_matrix = np.array([[1, -2, 3], [4, 5, 6], [7, 8, 9]])
| process_matrix(invalid_matrix) # Raises
| icontract.ViolationError
| extr wrote:
| Wow, quite surprising results. I have been working on a personal
| project with the astral stack (uv, ruff, ty) that's using
| extremely strict lint/type checking settings, you could call it
| an experiment in setting up a python codebase to work well with
| AI. I was not aware that ty's gaps were significant. I just tried
| with zuban + pyright. Both catch a half dozen issues that ty is
| ignoring. Zuban has one FP and one FN, pyright is 100% correct.
|
| Looks like I will be converting to pyright. No disrespect to the
| astral team, I think they have been pretty careful to note that
| ty is still in early days. I'm sure I will return to it at some
| point - uv and ruff are excellent.
| roflcopter69 wrote:
| This is the way. For now, pyright it's also 100% pyright for
| me. I can recommend turning on reportMatchNotExhaustive if
| you're into Python's match statements but would love the
| exhaustiveness check you get in Rust. Eric Traut has done a
| marvellous job working on pyright, what a legend!
|
| But don't get me wrong, I made an entry in my calendar to
| remind me of checking out ty in half a year. I'm quite
| optimistic they will get there.
| pgwalsh wrote:
| Using VSCodium I was having issues with python type checkers for
| quite a while. I did the basedpyright thing for a while but that
| was painful. It's a bit too based for me, and I'm not sure i'd
| call it based. Right now I have uv, ruff, and ty and I'm happy
| with it. It's super easy to update and super fast. I didn't
| realize the coverage wasn't as good as some others but I still
| like it. I may have to try pyrefly. Never heard of it until this
| post, so thank you.
| IshKebab wrote:
| Interesting. This is the first I've heard of Zuban.
|
| The fact that Mypy fails so badly matches my experience. It would
| be interesting to see exactly where Pyright "fails". It's been so
| reliable to me I wouldn't be 100% surprised if these are
| deliberate deviations from the spec, where it is dumb.
___________________________________________________________________
(page generated 2026-03-16 23:01 UTC)