ADR-0002: Runtime Namespace Design
ADR-0002: Runtime Namespace Design (py.*)
Status
Superseded by ADR-0009
Context
Python has many operations and built-in functions that don’t have direct JavaScript equivalents:
- Floor division
//(Python rounds toward negative infinity) - Modulo
%(Python result has sign of divisor) - Slicing with negative indices and step
range(),enumerate(),zip()as iterables- Type conversion functions (
int(),str(), etc.) - String methods with Python-specific behavior
We need to decide how to handle these in the generated TypeScript code.
Options considered:
-
Inline code generation: Generate equivalent JS code inline
- Pro: No runtime dependency
- Con: Verbose output, complex for features like slicing
-
Individual function imports:
import { floordiv, slice } from 'python2ts'- Pro: Tree-shakeable
- Con: Many imports, cluttered generated code
-
Single namespace object:
import { py } from 'python2ts/runtime'- Pro: Clean, discoverable API, single import
- Con: Slightly larger bundle if not all functions used
Decision
We will use a single namespace object called py that contains all Python-compatible helper
functions.
import { py } from "python2ts/runtime"
py.floordiv(10, 3) // 3py.slice(arr, 1, 4) // Slicingpy.range(10) // IterableDesign principles:
- Namespace prefix: All Python-specific operations use
py.* - Semantic naming: Function names match Python’s (
floordiv, notfloorDivide) - Grouped by category: Arithmetic, collections, iterables, etc.
- Nested namespaces:
py.string.*for string-specific methods
Consequences
Positive
- Discoverability: IDE autocomplete shows all available functions
- Clean imports: Single import statement regardless of features used
- Readable output:
py.floordiv(a, b)is self-documenting - Runtime tracking: Generator knows which runtime functions are used
Negative
- Bundle includes unused functions (mitigated by bundler tree-shaking)
- Extra indirection for function calls (negligible performance impact)
Generated Code Example
# Pythonx = 10 // 3items = [1, 2, 3]for i, v in enumerate(items): print(i, v)// Generated TypeScriptimport { py } from "python2ts/runtime"
let x = py.floordiv(10, 3)let items = [1, 2, 3]for (const [i, v] of py.enumerate(items)) { console.log(i, v)}