Skip to main content

HCP Terraform and Terraform Enterprise Python Client (pyTFE)

PyPI Python Versions Test License Issues

The official Python API client for HCP Terraform and Terraform Enterprise.

This client targets the HCP Terraform V2 API. As Terraform Enterprise is the self-hosted distribution of HCP Terraform, this client supports both HCP Terraform and Terraform Enterprise use cases. In this repository and API, we refer to the platform generically as Terraform Enterprise unless a feature is explicitly called out as only supported in one or the other (rare).

Version Information

We follow Semantic Versioning. During the initial alpha period we use 0.y.z:

  • Minor (0.y.z → 0.(y+1).z): new, backwards-compatible features and enhancements.
  • Patch (0.y.z → 0.y.(z+1)): bug fixes and performance improvements.
  • Occasionally, a function signature change that fixes incorrect behavior may appear in a minor version.

Example Usage

Construct a new pyTFE client, then use the resource services on the client to access different parts of the Terraform Enterprise API. The following example lists all organizations.

(Recommended) Using explicit config

from pytfe import TFEClient, TFEConfig

config = TFEConfig(
    address="https://tfe.local",
    token="insert-your-token-here",
    timeout=30.0,
    user_agent_suffix="example-app/0.1 pytfe/0.1",
)

client = TFEClient(config)

for org in client.organizations.list():
    print(org.name)

Using the default config with environment variables

The default configuration reads the TFE_ADDRESS and TFE_TOKEN environment variables.

  1. TFE_ADDRESS — URL of an HCP Terraform or Terraform Enterprise instance. Example: https://tfe.local
  2. TFE_TOKEN — An API token for the HCP Terraform or Terraform Enterprise instance.

Environment variables are used as a fallback when address or token are not provided explicitly:

Using the default configuration

from pytfe import TFEClient, TFEConfig

# Equivalent to providing no values; falls back to env vars if set.
client = TFEClient(TFEConfig())
for org in client.organizations.list():
    print(org.name)

When host or token is empty

from pytfe import TFEClient, TFEConfig

config = TFEConfig(address="", token="")
client = TFEClient(config)

for org in client.organizations.list():
    print(org.name)

Listing resources

Anything named list or list_* on a resource service returns an iterator, not a Python list. Pagination is handled for you under the hood — the iterator keeps fetching pages from the API until there are no more. This mirrors the underlying HCP Terraform API, where every list endpoint is paginated (page[number] / page[size]), and keeps memory flat even when an organization has thousands of workspaces or runs.

You'll use it one of two ways:

# Stream — handy when you might break early or when results are large
for ws in client.workspaces.list("my-org"):
    if ws.name.startswith("prod-"):
        print(ws.id, ws.name)

# Materialize — when you actually want a list to index, len(), or pass around
workspaces = list(client.workspaces.list("my-org"))
print(f"found {len(workspaces)} workspaces")

A couple of things worth knowing:

  • The iterator is single-use. Once you've walked it, iterating again gives you nothing. Capture it with list(...) first if you need to reuse the result.
  • Filters and page size live on the *ListOptions model for each resource — e.g. WorkspaceListOptions(search="prod", page_size=50). Pagination still happens transparently; page_size only controls how big each underlying API page is.

Logging

pyTFE integrates with Python's standard logging module and is silent by default — nothing is emitted unless you opt in. The library publishes two loggers:

  • pytfe — root namespace; rarely emits directly
  • pytfe.transport — HTTP request/response and retry trace

Turn it on with an environment variable

The quickest way is to set PYTFE_LOG:

PYTFE_LOG=debug python my_script.py

setup_logging() is invoked automatically on package import, so the env var alone is enough — no code change required. Use the programmatic call only when you need to (re)apply env vars set after import (e.g. in a REPL or test):

import pytfe
pytfe.setup_logging()

Levels: debug shows every request/response, info shows retry decisions only.

Sample output

[2026-05-25 14:12:26 pytfe.transport DEBUG]
> GET /api/v2/organizations/acme/workspaces?page[number]=1&page[size]=100
< 200 OK
< {
<   "data": [
<     { "id": "ws-...", "type": "workspaces", ... }
<   ]
< }

Safe by default

Bearer tokens and other credentials are redacted before they reach the logger:

  • Sensitive headers (Authorization, Cookie, anything containing token / secret / password / api-key) are replaced with **REDACTED**. Headers are off by default; even when you turn them on with PYTFE_LOG_HEADERS=true, redaction still applies.
  • JSON bodies have sensitive keys (token, access_token, refresh_token, secret, password, private_key, client_secret) replaced recursively.
  • Large bodies are truncated to PYTFE_LOG_TRUNCATE_BYTES (default 1024). Long arrays are clipped with "... (N additional elements)".
  • Binary responses (state-version downloads, configuration-version tarballs, etc.) render as [raw stream] — the bytes are never decoded into the log.

Compose with your existing logging

Because pyTFE uses stdlib logging, all the standard knobs work:

import logging

# Just the HTTP traffic, at DEBUG
logging.getLogger("pytfe.transport").setLevel(logging.DEBUG)

# Send pyTFE logs to your existing handler instead of stderr
logging.getLogger("pytfe").addHandler(my_json_handler)

For full details — environment variables, redaction guarantees, and how to add log statements to new SDK code — see docs/LOGGING.md.

Documentation

Start with Getting started, then use the API index to find resource-specific guides, examples, and upstream HCP Terraform API docs.

Need Start here
Configure the SDK Authentication, Pagination, Logging
AI coding assistants llms.txt — concise pytfe orientation (quickstart, conventions, error handling) for LLMs writing pytfe code
API guides API index, API coverage, Related resources (include), Workspaces, Runs/plans/applies, State versions, Public Registry
Scenario guides API-driven run, State management, Migrate workspaces and state, Team access onboarding, No-code provisioning, TFE identity bootstrap, TFE admin bootstrap, OIDC dynamic credentials
Operations guides Troubleshooting, Errors, Terraform Enterprise
Contribute to the SDK CONTRIBUTING, ITERATORS, MODELS, RESOURCE

Upstream API reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs

Examples

See the examples/ directory for runnable snippets covering common workflows (workspaces, variables, configuration versions, runs/plans/applies, state, agents).

Running tests

See TESTS.md. Typical flow:

pip install -e .[dev]
make test

Issues and Contributing

See CONTRIBUTING.md. We welcome issues and pull requests.

Releases

See RELEASES.md.

License

This project is licensed under the MPL-2.0. See LICENSE.

Metadata

Release files for pytfe 1.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pytfe 1.5.0
File Size Uploaded
pytfe-1.5.0.tar.gz 428.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pytfe 1.5.0
File Interpreter ABI Platform
pytfe-1.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 749.8 kB

Release files / pytfe-1.5.0.tar.gz

Download URL pytfe-1.5.0.tar.gz
Size 428.3 kB
Tags Source
SHA-256 checksum
How to use checksums
4706219804e06fb41c73563426c66a217000e5ff4759ffd49a869be87aa5a7e5
BLAKE2b-256 checksum
How to use checksums
83f98505cf041b4eedc0685bdcdc1bd2e4f443b14b0256f76af8129c873aa04f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.21

Release files / pytfe-1.5.0-py3-none-any.whl

Download URL pytfe-1.5.0-py3-none-any.whl
Size 321.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c2d287e0903ae25c2c4b80c3e8d016507aabeb4670995ab85fde181912074f08
BLAKE2b-256 checksum
How to use checksums
779cd9918f9c062c581144172a9204b43e81aa1ba3766483392f3af5d7aed4f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.21

Release history Release notifications | RSS feed

This release

1.5.0 This release

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page