Python Type Challenges is a Flask site of typing exercises
Master Python typing (type hints) with interactive online exercises!
At a glance
- What is it?
- Python Type Challenges is a small web application where you solve type hint exercises, each one a folder holding a question and a solution, checked with Pyright. The project runs on Flask with HTMX, requires Python 3.14, and ships its own packaging tooling so the requirements file is generated rather than edited.
- Who is it for?
- Python Type Challenges suits a developer who wants to get faster at reading and writing Python type hints, especially someone coming from a statically typed language where the gradual typing rules feel arbitrary, since the exercises are graded by a real type checker rather than a set of answers.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 65 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A small Flask application with a directory of exercises
Python Type Challenges is a set of interactive online exercises for learning Python type hints, and the deployed site is at python-type-challenges.laike9m.com. The repository is a Flask application rather than a static site, which is the interesting structural choice, because an exercise that checks your answer needs a server to run a type checker and compare results. The tree shows the shape of it, with an application module at the root, a views directory holding the request handling, a templates directory and a static directory for the front end, a challenges directory holding the exercises themselves, a tests directory, a documentation directory, and the packaging files. The dependency list includes flask-htmx, which is how the page updates without full reloads, and flask-sitemapper, which generates the site map for the exercise index, along with the markdown library for rendering the question text. The idea the project is built on is that typing is best learned by writing an annotation and seeing immediately whether the checker agrees with you.
One folder, one question, one solution
The contribution guide states the rule for adding a challenge in one sentence: you only need to create a new folder, add a question file and a solution file, and that is it. A detailed guidance document in the docs directory expands on it, and a separate document covers the development workflow for new features and bug fixes. This is the design decision that keeps the project growing. There is no database, no admin interface and no authoring format to learn, so a contributor can add an exercise in the time it takes to write the problem, and the review burden is a type checking pass rather than a content pipeline. The structure also means the exercises are plain Python files in a repository, so they can be read, forked and reused as a course, and the type checker sees the same files a reader would. Questions that need general discussion go to the discussions area, while bugs and feature requests go to the issue tracker, and the readme keeps those two routes distinct.
Pyright does the grading, so the feedback is the feedback you will get
The checker is Pyright, and that single choice explains what the exercises feel like. The dependency list pins pyright at 1.1.338 or newer, and the type checker configuration in the packaging file points at a local virtual environment and sets the Python version to 3.14, so the checks run against the same interpreter version the project targets. The consequence for a learner is that the exercise feedback is not a simplified model of typing, it is the real output of a tool used in production, which means the errors you are shown are the errors you would see in your editor. That is the difference between a tutorial and a practice environment. It also means the exercises are tied to a specific checker version, and a change in how Pyright reports a diagnostic can change what an answer looks like. The tool is not run by the reader, the server runs it against the submitted answer, and the readme's greeting, happy typing, is the joke that this is a checker-driven drill rather than a quiz.
Python 3.14 only, which is the sharpest constraint
The packaging file is where the hard requirements live, and there is one that will stop a reader immediately. The project requires Python 3.14 and above and below 3.15, a narrow range, and the type checker configuration agrees, setting the Python version to 3.14. For a project that teaches typing, using the newest interpreter is defensible, since new syntax and new standard library annotations are part of what is being taught, and the pinned range means the exercise solutions cannot accidentally rely on behaviour that changes in the next release. It is still a real barrier for anyone on an older distribution, and it applies to the local setup as much as to the hosted site. The second constraint is that the toolchain is specific rather than generic. The requirements file is generated by the packaging tool and marked as such, and it pins every transitive dependency to an exact version, including the checker, the test framework and the linting tools.
PDM generates the requirements file and the scripts do the work
The project uses PDM, which the readme recommends, and the alternative is a plain pip install from the requirements file followed by a Flask run. The two local setup paths are short.
pdm install
pdm dev # This will run a local Flask serverpip install -r requirements.txt
flask runThe PDM scripts are defined in the packaging file, and they are where the project reveals its habits. The development script runs Flask with the debug flag, the production script runs gunicorn with the threading worker class, two workers and four threads, a 15 second timeout and a bind address of all interfaces on port 5000.
dev = "flask --app app run --debug"
prod = "gunicorn -k gthread -w 2 --threads 4 --timeout 15 -b 0.0.0.0:{args:5000} app:app"
test = "pytest -n auto"The test script runs pytest with parallel workers across the available cores, which is the right choice for a suite of many small checks, and the formatting setup is a composite of ruff for Python and djhtml for the templates with a tab width of two, driven by pre-commit. The requirements file is not maintained by hand at all, since a PDM autoexport entry generates it from the default dependency group with hashes omitted, so the two installation paths cannot drift apart.
The ideas came from Rust and TypeScript
The credits section names the two projects the design comes from, a Rust type exercise by skyzh and the type challenges collection by antfu, which is the usual lineage for this kind of interactive typing drill. The Rust project in particular is the one that set the shape, since it asks you to make a function compile with a given signature rather than to guess an answer, and that is the same mechanic the Python version uses with a type checker. The graphics in the interface come from a named photographer, credited in the readme with a link to the source. On the project status, the repository is MIT licensed with the terms in the license file, publishes no GitHub releases, and the last push was on 2026-08-20, so the site is deployed from the default branch rather than from tagged artifacts. The question to ask before depending on it is therefore not about the code, which is small and readable, but about the site, since a hosted learning resource can change its shape without a version number changing.
Editorial conclusion
Python Type Challenges suits a developer who wants to get faster at reading and writing Python type hints, especially someone coming from a statically typed language where the gradual typing rules feel arbitrary, since the exercises are graded by a real type checker rather than a set of answers. It is a poor choice if you need a curriculum with a defined path, because the site is a collection of independent challenges, and it is a poor choice on an older Python, because the project requires Python 3.14 and pins the pyright configuration to that version. Verify three things before you fork it: that you can run a Python 3.14 interpreter, since the requirement is a narrow range, that the checker is the one you use in your own work, because the feedback you get is Pyright's, and whether you want the local server or the hosted one, since the local setup is a PDM install plus a Flask development server. The licence is MIT, the last push was on 2026-08-20, and the repository publishes no GitHub releases.
Frequently asked questions
How do I run Python Type Challenges locally?
Clone the project and install the dependencies with PDM, which the readme recommends, then run the dev script to start a local Flask server. Alternatively install from the requirements file with pip and run flask run. The requirements file is generated by PDM and should not be edited by hand.
What Python version does Python Type Challenges need?
The packaging file requires Python 3.14 and above and below 3.15, and the pyright configuration sets the Python version to 3.14, so the exercises and the checker both target that release.
How do I add a new challenge?
Create a new folder and add a question file and a solution file, according to the readme, with detailed guidance in the contribution document in the docs directory. New features and bug fixes follow a separate development guide.
What checks the answers in Python Type Challenges?
Pyright, the type checker, which is a runtime dependency of the project and is configured to run against the local virtual environment with Python 3.14. The test suite runs separately with pytest in parallel across cores.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/laike9m-python-type-challenges)Was this useful?