Highlights
libterraform 0.15.3 keeps the Terraform 1.15.5 compatibility line and changes the default execution model for TerraformCommand and AsyncTerraformCommand. Commands now run through a subprocess-backed backend by default, so Terraform's internal chdir handling does not change the parent Python process working directory while a command is running.
The previous current-process path is still available for low-overhead, explicitly serialized use with backend="thread" or ThreadTerraformCommand.
What's Changed
- Defaulted
TerraformCommandto a process backend for parent-process cwd isolation. - Defaulted
AsyncTerraformCommandto the same process backend, so asyncio applications no longer observe Terraform's internal cwd changes by default. - Added explicit
ProcessTerraformCommandandThreadTerraformCommandclasses for callers that want to choose a backend by class. - Kept the current-process backend available with
backend="thread"for compatibility-sensitive or low-overhead usage. - Preserved
TerraformPoolworker behavior by keeping pool-internal command execution on the thread backend inside each worker process. - Added regression tests that sample the parent process cwd while Terraform is running.
- Updated English and Chinese docs for the new default backend and thread opt-in path.
Process Backend Usage
TerraformCommand now uses the process backend by default:
from libterraform import TerraformCommand
cli = TerraformCommand("/path/to/module")
cli.init(check=True)
result = cli.apply(auto_approve=True, input=False, check=True)
print(result.retcode)AsyncTerraformCommand also defaults to the process backend:
import asyncio
from libterraform import AsyncTerraformCommand
async def main():
cli = AsyncTerraformCommand("/path/to/module")
result = await cli.validate(check=True)
print(result.value["valid"])
asyncio.run(main())This is the recommended path when application code might read or depend on os.getcwd() while Terraform is running.
Thread Backend Usage
Use the thread backend only when you explicitly want the current-process execution path:
from libterraform import TerraformCommand, ThreadTerraformCommand
cli = TerraformCommand("/path/to/module", backend="thread")
# Equivalent explicit class:
thread_cli = ThreadTerraformCommand("/path/to/module")The thread backend preserves the previous lower-overhead behavior, but Terraform still uses process-wide state internally. libterraform serializes these calls and restores global state after each command, but unrelated Python code can still observe temporary cwd changes during execution.
Parallel Execution Notes
For true parallel Terraform execution across independent module directories, continue to use TerraformPool. Each pool worker has its own Python process and Terraform execution state:
from libterraform import TerraformPool
modules = ["/path/to/module-a", "/path/to/module-b"]
with TerraformPool(max_workers=2) as pool:
for result in pool.map("validate", modules, check=True):
print(result.value["valid"])Compatibility
- Terraform: 1.15.5
- go-plugin: 1.7.0
- Python: 3.9 to 3.14
Install
pip install "libterraform==0.15.3"Links
- PyPI: https://pypi.org/project/libterraform/0.15.3/
- GitHub issue: #11
- Pull request: #12
- Terraform command API: https://prodesire.github.io/py-libterraform/api/terraform-command/
- Async command API: https://prodesire.github.io/py-libterraform/api/async-terraform-command/
- Parallel execution guide: https://prodesire.github.io/py-libterraform/parallel-execution/
- Full changelog: v0.15.2...v0.15.3