nakprok - Python with Enforced Static Typing
Same Python syntax. Zero dynamic typing.
nakprok (นาคปรก) is a subset of Python that enforces static type annotations
everywhere. It's not a new language, but a stricter runtime for the Python you
already know.
Why the name? Nakprok is a depiction of the Buddha sheltered by the multi-headed serpent Nāga in Thai Buddhist art. Just as the Naga protected the Buddha, this project protects your code from untyped or mistyped logic.
🚀 Key Concepts
- Explicit is Better than Implicit: If a value's type can't be seen in the code, it shouldn't be there.
- Zero Runtime Overhead: Validation happens at the AST level before execution. Once validated, it runs as standard CPython.
- Ecosystem Compatibility: Works with all existing Python libraries and tools.
- No New Syntax: Uses standard Python 3.10+ type hinting syntax.
🆚 How is this different from mypy?
nakprok is not a replacement for mypy. They tackle type safety from
different angles and work well together:
| mypy | nakprok | |
|---|---|---|
| When | Static analysis (separate step) | AST validation before execution |
| What | Deep type inference & checking | Enforces explicit type declarations |
| Scope | All valid Python | Strict subset (blocks lambda, untyped unpacking, etc.) |
| Result | Advisory report (can be ignored) | Hard block — code won't run |
Think of it this way:
- nakprok ensures every value is explicitly typed at the source level.
- mypy then verifies those types are semantically correct (e.g., protocol
compliance, generic constraints,
intwherefloatis expected).
You can (and should) run both:
nakprok check . # Enforces explicit typing
mypy . # Validates type correctness
🛠️ Implemented Rules
nakprok currently enforces the following rules inside functions (and classes):
1. Function Signatures
- All parameters must be typed:
def add(a: int, b: int)is required. - Return types are mandatory:
-> Noneor-> intmust be specified. - Exceptions:
selfandclsparameters in methods are exempt. - Variadic arguments:
*args: strand**kwargs: Anymust also have annotations.
2. Variable Declarations
-
Strict Local Typing: Every local variable must be declared with a type.
x: int = 10(Annotated assignment)x: intfollowed byx = 10(Declaration then assignment)
-
Re-assignment: Once a variable is typed in the current scope, it can be re-assigned without repeating the annotation.
x: int = 10 x = 20 # Valid
3. Control Flow
-
For Loops: Loop variables must be previously declared.
i: int for i in range(10): ...
-
With Statements: Context manager variables must be previously declared.
f: TextIO with open("file.txt") as f: ...
-
Match Case: Variable captures via
asinmatchpatterns must be pre-declared with a type annotation:val: int match data: case int() as val: print(val)
Star patterns (
[*rest]) follow the same rule:rest: list[int] match items: case [*rest]: print(rest)
Type-only matches without binding (
case int():) are always valid.
4. Global Constants
- Immutability: UPPERCASE variables are treated as constants and are immutable everywhere. Once assigned a value, any attempt to re-assign or shadow them will result in an error.
- Exemptions: UPPERCASE constants at the module level are exempt from strict
typing by convention (e.g.,
MAX_SIZE = 100).
5. Prohibited Features
- Lambdas: Blocked because Python provides no syntax for annotating their parameters or return types.
- Untyped Unpacking:
x, y = (1, 2)is blocked unlessxandywere previously declared.
🔮 Future Roadmap
The project aims to become a complete "strict mode" for Python. Future plans include:
- Module-Level Enforcement: Extend strict typing to all module-level variables (not just UPPERCASE constants).
- Type-Safe Imports: Validate that imported names are used consistently
with their types (integration with
mypyorpyrightstubs). - Strict Class Attributes: Enforce that all class attributes are declared in the class body with types.
- Decorator Validation: Ensure decorators preserve type information and are themselves strictly typed.
- Linter Integration: A dedicated VS Code / PyCharm extension to show
nakprokerrors in real-time.
📦 Installation & Usage
Installation
pip install -e .
Usage
# Check and run (default)
nakprok file.py
# Check types only (file or directory)
nakprok check file.py
nakprok check src/
# Explicit run
nakprok run file.py
Example: factorial.py
def factorial(n: int) -> int:
if n <= 1:
return 1
return n * factorial(n - 1)
def main() -> None:
result: int = factorial(5)
print(f"5! = {result}")
if __name__ == "__main__":
main()
$ nakprok factorial.py
5! = 120
🧪 Testing
We maintain a comprehensive test suite to ensure all rules are correctly enforced.
pytest tests/ -v
Metadata
Release files for nakprok 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nakprok-0.3.0.tar.gz | 8.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nakprok-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.7 kB
Release files / nakprok-0.3.0.tar.gz
| Download URL | nakprok-0.3.0.tar.gz |
|---|---|
| Size | 8.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2669049b10a57560fe6f66828d42503cca7debd27da9571d177b7cf518155856
|
|
BLAKE2b-256 checksum How to use checksums |
03fdf5e3281f5003950ae6fb2d58f35b1d9d600e782a6935df2d04a9349526f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.3.3 CPython/3.14.3 Linux/6.19.11-200.fc43.x86_64
|
Release files / nakprok-0.3.0-py3-none-any.whl
| Download URL | nakprok-0.3.0-py3-none-any.whl |
|---|---|
| Size | 9.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
03e437de51ab49c907fd871b4ffc3b0831305ab4991d8bbfc5f7748549c7c9eb
|
|
BLAKE2b-256 checksum How to use checksums |
d55fdb832abed28b0e2cfc4b6f988af3b188164a0abc47b146ce4622d4035519
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.3.3 CPython/3.14.3 Linux/6.19.11-200.fc43.x86_64
|