Modules & Imports¶
Desi uses a file-based module system similar to Python.
Import Syntax¶
# Import entire module
import math
# Import specific items
from math import add, sub
# Import with alias
from math import add as plus
import some_module as m
# Import all (wildcard)
from math import *
# Relative import (current directory)
from .utils import helper
# Stdlib import (always uses stdlib, never local)
from std.math import add
Export Visibility¶
By default, items are private. Use pub to export:
# Private - only visible in this file
def helper():
pass
# Public - can be imported by other modules
pub def add(x: int, y: int) -> int:
return x + y
# Classes at top-level are public by default
class Point:
x: int
y: int
Public Re-exports¶
Use pub from to re-export items as part of your module's public API:
# mylib.desi - re-export print for users of mylib
pub from io import print
pub from math import add, sub
# Consumers can now do: from mylib import print, add
Module Structure¶
myproject/
├── main.desi # Entry point
├── math.desi # from math import add
└── utils/
├── __mod.desi # Package marker
└── helpers.desi # from utils.helpers import foo
Import Errors¶
Circular Imports (DME0008)¶
Reserved Namespace (DME0009)¶
Shadowing Stdlib (DME0010)¶
# If you have local math.desi AND stdlib has math:
from math import add # ❌ Local shadows stdlib
from std.math import add # ✓ Use this instead
Ambiguous Module (DME0011)¶
Lazy Initialization¶
Imports are lazy by default — modules initialize only when first used:
import log
import math
def main() -> int:
print("Starting...")
log.info("Using log now") # log module initializes here
# math is never used, so it never initializes
0
Benefits¶
- Performance — unused imports have zero runtime cost
- Circular imports — modules can import each other safely
- No boilerplate — lazy behavior is automatic
How It Works¶
Each module has an init guard:
- First call to
log.info()triggers__ensure_log_init() - The init thunk checks a flag and calls the module's
__top__()if needed - Subsequent calls skip initialization
This happens transparently — you don't need to think about it!