Skip to main content

Python with enforced static typing

Project description

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

Project details


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.

Supported by

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