Skip to main content

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

  1. Explicit is Better than Implicit: If a value's type can't be seen in the code, it shouldn't be there.
  2. Zero Runtime Overhead: Validation happens at the AST level before execution. Once validated, it runs as standard CPython.
  3. Ecosystem Compatibility: Works with all existing Python libraries and tools.
  4. 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, int where float is 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: -> None or -> int must be specified.
  • Exceptions: self and cls parameters in methods are exempt.
  • Variadic arguments: *args: str and **kwargs: Any must also have annotations.

2. Variable Declarations

  • Strict Local Typing: Every local variable must be declared with a type.

    • x: int = 10 (Annotated assignment)
    • x: int followed by x = 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 as in match patterns 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 unless x and y were previously declared.

🔮 Future Roadmap

The project aims to become a complete "strict mode" for Python. Future plans include:

  1. Module-Level Enforcement: Extend strict typing to all module-level variables (not just UPPERCASE constants).
  2. Type-Safe Imports: Validate that imported names are used consistently with their types (integration with mypy or pyright stubs).
  3. Strict Class Attributes: Enforce that all class attributes are declared in the class body with types.
  4. Decorator Validation: Ensure decorators preserve type information and are themselves strictly typed.
  5. Linter Integration: A dedicated VS Code / PyCharm extension to show nakprok errors 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)

Source distribution for nakprok 0.3.0
File Size Uploaded
nakprok-0.3.0.tar.gz 8.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nakprok 0.3.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page