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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nakprok-0.3.0.tar.gz (8.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nakprok-0.3.0-py3-none-any.whl (9.6 kB view details)

Uploaded Python 3

File details

Details for the file nakprok-0.3.0.tar.gz.

File metadata

  • Download URL: nakprok-0.3.0.tar.gz
  • Upload date:
  • Size: 8.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.3 CPython/3.14.3 Linux/6.19.11-200.fc43.x86_64

File hashes

Hashes for nakprok-0.3.0.tar.gz
Algorithm Hash digest
SHA256 2669049b10a57560fe6f66828d42503cca7debd27da9571d177b7cf518155856
MD5 106beb838ca76cb740e47a2252424dd3
BLAKE2b-256 03fdf5e3281f5003950ae6fb2d58f35b1d9d600e782a6935df2d04a9349526f6

See more details on using hashes here.

File details

Details for the file nakprok-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: nakprok-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 9.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.3 CPython/3.14.3 Linux/6.19.11-200.fc43.x86_64

File hashes

Hashes for nakprok-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 03e437de51ab49c907fd871b4ffc3b0831305ab4991d8bbfc5f7748549c7c9eb
MD5 4775ab9f93bea40a71258ca735760c2b
BLAKE2b-256 d55fdb832abed28b0e2cfc4b6f988af3b188164a0abc47b146ce4622d4035519

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page