A fast, opinionated floor under every Python codebase you are about to read. It assumes total fluency in programming and near-zero recall of Python's surface, so nothing here explains what a for loop is, and everything here tells you how to spell one. Four modules: the syntax refresher pitched at someone who forgot the keywords rather than the concepts; the 2026 toolchain, which is uv and almost nothing else, plus the virtualenv story that explains why uv had to exist; typing, honestly, including how much weaker the guarantees are than TypeScript's and why Pydantic is the part that actually runs; and the four idioms you will meet on your first day in a LangChain or LangGraph repo. Every example is biased toward code you will actually hit, so the decorator lesson looks like a tool definition and the typing lessons look like state schemas.
You have the spelling, the toolchain, the type system and the four protocols. The last thing worth doing is the thing that actually converts recognition into recall: writing some.
Pick something you already own in TypeScript. Small. A CLI you wrote, a scraper, a webhook handler, a bit of glue that talks to one API and writes one file. Not a framework, not a rewrite of anything with a UI. Something you could finish in an evening and whose correct behaviour you can already check, because knowing what the right answer looks like is what makes the port a language exercise instead of a debugging exercise.
Port it.
uv init and never type activate. Every command goes through uv run. If you find yourself sourcing an activate script, you have reached for a 2015 habit and you should stop and ask what you were trying to do.uv add. No pip install. Commit the uv.lock.pyright or mypy runs clean over the project. Add it as a dependency group and run it through uv run.TypedDict, and you can say in one sentence why it is not a Pydantic model.asyncio.TaskGroup or asyncio.gather, not by awaiting in a loop.Three short answers in a scratch file. Not an essay.
dict you assumed was ordered by key, an await in a loop, a type hint that was quietly a lie at runtime.The port runs. The typechecker is clean. The lockfile is committed. And every Pydantic model in it is there because data crosses a boundary at that point, rather than because Pydantic was the shape you happened to remember.
If you can hand this to someone and they cannot tell from the code that you learned Python last week, you are done. The tell is never the algorithm. It is activate in the README, a dict used where a dataclass belonged, and a bare except: swallowing something that should have crashed.