Relative Imports#
Relative imports allow modules within a package to reference each other using . (current) and .. (parent) notation.
Prefer Absolute Imports
Relative imports can be ambiguous. We recommend absolute imports in most cases. Use relative imports only for tightly coupled internal package code.
Relative Import Syntax#
| Syntax | Meaning |
|---|---|
.module |
Same directory |
..module |
Parent directory |
...module |
Grandparent directory |
Same-Level Imports (.)#
Import from modules in the same directory.
relative_sibling/
├── main.jac
└── pkg/
├── base.jac # Defines BASE_VALUE, base_func
└── sibling.jac # Uses .base to import
Output
```
Relative import - BASE_VALUE: Base value Relative import - SIBLING_VALUE: Sibling uses Base value Relative import - sibling_func(): Sibling calls: Base function ```
Parent-Level Imports (..)#
Import from the parent directory.
relative_parent/
├── main.jac
└── project/
├── config.jac # Defines CONFIG_VALUE, DEBUG
└── sub/
└── deep.jac # Uses ..config to reach parent
Output
```
Parent relative - CONFIG_VALUE: Project config Parent relative - DEEP_VALUE: Deep module using config: Project config Parent relative - deep_func(): Deep function, DEBUG=True ```
Mixed Absolute and Relative#
You can combine both import styles, but prefer absolute imports for clarity.
Output
```
Mixed - BASE_ID (from import): 1000 Mixed - EXTENDED_ID: 1001 Mixed - get_extended_id(): Base: 1000, Extended: 1001 Mixed - lib_base.BASE_ID (alias): 1000 ```
Relative Import Boundaries
Relative imports only work within packages. You cannot use .. to escape beyond your project's root.
Best Practice
Default to absolute imports. They're explicit and don't break when you reorganize code.