- hauntsaninja parentYes, uv skipping this step is a one time significant hit to start up time. E.g. if you're building a Dockerfile I'd recommend setting `--compile-bytecode` / `UV_COMPILE_BYTECODE`
- Unknown has the exact same type system semantics as Any.
Unknown is a pyright specific term for inferred Any that is used as the basis for enabling additional diagnostics prohibiting gradual typing.
Notably, this is quite different from TypeScript’s unknown, which is type safe.
- I’ve added ecosystem regression checks to every Python type checker and typeshed via https://github.com/hauntsaninja/mypy_primer. This helped a tonne with preventing unintended or overly burdensome regressions in mypy, so glad to hear upgrades are less of an Event for you
- The conformance test suite is currently mostly focused on “what does an explicit type annotation mean”
A shared spec for this is important because if you write a Python library, you don’t want to have to write a different set of types for each Python type checker
Here are some things the spec has nothing to say about:
Inference
You don’t want to annotate every expression in your program. Type checkers have a lot of leeway here and this makes a huge difference to what it feels like to use a type checker.
For instance, mypy will complain about the following, but pyright will not (because it infers the types of unannotated collections as having Any):
The spec has nothing to say about this.x = [] x.append(1) x[0] + "oops"Diagnostics
The spec has very little to say about what a type checker should do with all the information it has. Should it complain about unreachable code? Should it complain if you did `if foo` instead of `if foo()` because it’s always true? The line between type checker and linter is murky. Decisions here have nothing to do with “what does this annotation mean”, so are mostly out of scope from the spec.
Configuration
This makes a huge difference when adapting huge codebases to different levels of type checking. Also the defaults really matter, which can be tricky when Python type checkers serve so many different audiences.
Other things the spec doesn’t say anything about: error messages quality, editor integration, speed, long tail of UX issues, implementation of new type system features, plugins, type system extensions or special casing
And then of course there are things we would like to spec but haven’t yet!
- Mentioned this in another comment, but the spec conformance suite is not representative of the things users care about (nor is it meant to be).
The spec mostly concerns itself with the semantics of annotations, not diagnostics or inference. I don't really recommend using it as the basis for choosing a type checker.
(I was on the Python Typing Council and helped put together the spec, the conformance test suite, etc)
- Note: while spec conformance is important, I don't recommend using it as the basis for choosing a type checker. It is not representative of the things that most users actually care about (and is not meant to be).
(I was on the Python Typing Council and helped put together the spec, the conformance test suite, etc)
- pyright will accept this. mypy should accept this when using --allow-redefinition-new as well
- text-davinci-001 is just not GPT-3 in any real sense
(I work at OpenAI, I helped build this page and helped train text-davinci-001)
- Note that `uvx mypy` may give you inaccurate timings on macOS. The antivirus in macOS goes a little crazy the first time it executes a mypyc compiled program.
- We had so many of these issues that we ended up LD_PRELOAD-ing patch getenv / setenv / putenv
- Yeah, that's not exactly the problematic situation... but the good news is I improved the Python's error message for this in 3.13. See https://docs.python.org/3/whatsnew/3.13.html#improved-error-...
- You don't need to use pytz, you can use the following on all Python 3: tz_UTC = datetime.timezone.utc
- Lean heavier on a mypy config file. Make heavy use of per-module configuration, in particular, setting per-module ignore_errors = true for modules you’re not yet ready to type check.
See https://mypy.readthedocs.io/en/stable/existing_code.html for some more advice.
- 3 points
- In Python 3.11, you can use the "-P" flag or the "PYTHONSAFEPATH" environment variable to avoid adding cwd to sys.path
https://docs.python.org/3.11/whatsnew/3.11.html#summary-rele...
- You can use numpy just fine. Unlike Cython, mypyc doesn’t give you a way of accessing numpy’s C API (because you’re basically just writing Python code).
- mypy compiles itself with mypyc, for about a 3.5-4x speed up. black very recently started shipping mypyc compiled binaries, for about a 2x speed up (iirc).
- mypyc has escape hatches, e.g. casting to Any is a common trick.
- I wrote a similar tool a while back. My solution for this was to statically analyse the input to discover unused names. The cool part of doing transformations statically is that you're able to see the exact Python code you'd run without running it, e.g. `pyp --explain x[:5]`. https://github.com/hauntsaninja/pyp
- I wrote a similar tool a while back that lets you create your own "magic" variables. I use `f` all the time! https://github.com/hauntsaninja/pyp#pyp-lets-you-configure-y...
- Python's static type system can express what you describe using TypeVars or overloads. The issue is that `int pow(int, int)` is fundamentally incorrect. If the exponent is a negative integer, the return type would need to be float.
As evidenced by your comment, most people forget about negative exponents. The vast majority of usage is positive exponents; people expect an int back when they do `pow(2, 2)` and returning a Union or float would result in annoying false positives.
- Thanks to everyone who checked pyp out!
Not sure if this comment will ever get seen, but I just added the ability to configure pyp with statically analysed Python, so it's easy to define your own functions, import aliases, or use libraries like pipetools to make your life easier! More details at https://github.com/hauntsaninja/pyp#pyp-is-configurable
- There are a number of possible options! And remember you can always pipe pyp to pyp. Here are some ideas, in order of what came to mind, where the operation is incrementing.
pyp 'lines[lines.index("start") + 1:]' | pyp 'lines[:lines.index("end")]' | pyp 'int(x) + 1' pyp 'start = lines.index("start"); end = lines.index("end", start); map(lambda x: int(x) + 1, lines[start + 1:end])' pyp 'dropwhile(lambda x: x != "start", lines)' | pyp 'lines[1:]' | pyp 'takewhile(lambda x: x != "end", lines)' | pyp 'int(x) + 1' pyp 'map(lambda x: int(x) + 1, takewhile(lambda x: x != "end", islice(dropwhile(lambda x: x != "start", lines), 1, None)))' pyp -b 'cond = False' 'if cond and x == "end": break' 'if cond: print(int(x) + 1)' 'if x == "start": cond = True' - Given that the original project has been unmaintained for several years and is Python 2 only, I think it's not unreasonable. There's very little reason to have both installed, so I don't think it's a problem for users either.
It's also just the perfect name! It's punny, it's short and it acknowledges prior art. And of course, if the original author took issue with it, I would change the name.
- Thanks for sharing! I hadn't seen Mario before. The async support is super nifty! From a quick look, it looks like pyp might be a little quicker for some use cases since it doesn't need subcommands, but I'll definitely be updating https://github.com/hauntsaninja/pyp#related-projects
- xonsh is great! I'm a fan of your cousin's work :-) I mentioned it in https://github.com/hauntsaninja/pyp#related-projects for if you want even more Python in your shell.
- Yup, that was the inspiration for this project and its name. See https://github.com/hauntsaninja/pyp#related-projects for more discussion. By no means is this a new idea, but I think this iteration has some convenient twists :-)
- Thanks for checking pyp out!
Startup time hasn't been particularly perceptible in my use of it. Just ran a quick benchmark on my (old, not powerful) laptop:
Since there isn't any input, this should just measure startup and AST transformation time.~ λ hyperfine 'pyp x' Benchmark #1: pyp x Time (mean ± σ): 75.9 ms ± 1.2 ms [User: 55.9 ms, System: 15.1 ms] Range (min … max): 74.5 ms … 79.0 ms 36 runs - 285 points