Skip to content

Commit 316b52a

Browse files
authored
Merge pull request #113 from hashicorp/refactor/Iterator-pattern-conversion
Refactor/iterator pattern conversion
2 parents a001f7d + be6968d commit 316b52a

15 files changed

Lines changed: 727 additions & 182 deletions

examples/policy_check.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ def main():
3535
action="store_true",
3636
help="Get logs for the specified policy check",
3737
)
38-
parser.add_argument("--page", type=int, default=1)
3938
parser.add_argument("--page-size", type=int, default=20)
4039
args = parser.parse_args()
4140

@@ -50,21 +49,19 @@ def main():
5049
_print_header(f"Listing policy checks for run: {args.run_id}")
5150

5251
options = PolicyCheckListOptions(
53-
page_number=args.page,
5452
page_size=args.page_size,
5553
)
5654

5755
try:
58-
pc_list = client.policy_checks.list(args.run_id, options)
56+
pc_list = list(client.policy_checks.list(args.run_id, options))
5957

60-
print(f"Total policy checks: {pc_list.total_count}")
61-
print(f"Page {pc_list.current_page} of {pc_list.total_pages}")
58+
print(f"Total policy checks fetched: {len(pc_list)}")
6259
print()
6360

64-
if not pc_list.items:
61+
if not pc_list:
6562
print("No policy checks found for this run.")
6663
else:
67-
for pc in pc_list.items:
64+
for pc in pc_list:
6865
print(f"- ID: {pc.id}")
6966
print(f"Status: {pc.status}")
7067
print(f"Scope: {pc.scope}")

examples/state_versions.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,23 @@ def main():
3333
parser.add_argument("--workspace-id", required=True, help="Workspace ID")
3434
parser.add_argument("--download", help="Path to save downloaded current state")
3535
parser.add_argument("--upload", help="Path to a .tfstate (or JSON state) to upload")
36-
parser.add_argument("--page", type=int, default=1)
3736
parser.add_argument("--page-size", type=int, default=10)
3837
args = parser.parse_args()
3938

4039
cfg = TFEConfig(address=args.address, token=args.token)
4140
client = TFEClient(cfg)
4241

4342
options = StateVersionListOptions(
44-
page_number=args.page,
4543
page_size=args.page_size,
4644
organization=args.org,
4745
workspace=args.workspace,
4846
)
4947

50-
sv_list = client.state_versions.list(options)
51-
52-
print(f"Total state versions: {sv_list.total_count}")
53-
print(f"Page {sv_list.current_page} of {sv_list.total_pages}")
48+
sv_list = list(client.state_versions.list(options))
49+
print(f"Total state versions: {len(sv_list)}")
5450
print()
5551

56-
for sv in sv_list.items:
52+
for sv in sv_list:
5753
print(f"- {sv.id} | status={sv.status} | created_at={sv.created_at}")
5854

5955
# 1) List all state versions across org and workspace filters
@@ -63,7 +59,7 @@ def main():
6359
organization=args.org, workspace=args.workspace, page_size=args.page_size
6460
)
6561
)
66-
for sv in all_sv.items:
62+
for sv in all_sv:
6763
print(f"- {sv.id} | status={sv.status} | created_at={sv.created_at}")
6864

6965
# 2) Read the current state version (with outputs included if you want)
@@ -84,15 +80,30 @@ def main():
8480

8581
# 4) List outputs for the current state version (paged)
8682
_print_header("Listing outputs (current state version)")
87-
outs = client.state_versions.list_outputs(
88-
current.id, options=StateVersionOutputsListOptions(page_size=50)
83+
outs = list(
84+
client.state_versions.list_outputs(
85+
current.id, options=StateVersionOutputsListOptions(page_size=50)
86+
)
8987
)
90-
if not outs.items:
88+
if not outs:
9189
print("No outputs found.")
92-
for o in outs.items:
90+
for o in outs:
9391
# Sensitive outputs will have value = None
9492
print(f"- {o.name}: sensitive={o.sensitive} type={o.type} value={o.value}")
9593

94+
if args.workspace_id:
95+
# 4b) List outputs for the current state version via workspace endpoint
96+
_print_header("Listing outputs via workspace endpoint")
97+
outs2 = list(
98+
client.state_version_outputs.read_current(
99+
args.workspace_id, options=StateVersionOutputsListOptions(page_size=50)
100+
)
101+
)
102+
if not outs2:
103+
print("No outputs found.")
104+
for o in outs2:
105+
print(f"- {o.name}: sensitive={o.sensitive} type={o.type} value={o.value}")
106+
96107
# 5) (Optional) Upload a new state file
97108
if args.upload:
98109
_print_header(f"Uploading new state from: {args.upload}")

examples/variable_sets.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def variable_set_example():
6464
list_options = VariableSetListOptions(
6565
page_size=10, include=[VariableSetIncludeOpt.WORKSPACES]
6666
)
67-
variable_sets = client.variable_sets.list(org_name, list_options)
67+
variable_sets = list(client.variable_sets.list(org_name, list_options))
6868
print(f"Found {len(variable_sets)} existing variable sets")
6969

7070
for vs in variable_sets[:3]: # Show first 3
@@ -92,6 +92,15 @@ def variable_set_example():
9292
print(f"Priority: {new_variable_set.priority}")
9393
print()
9494

95+
print("Listing existing variable sets...")
96+
list_options = VariableSetListOptions(page_size=10)
97+
variable_sets = list(client.variable_sets.list(org_name, list_options))
98+
print(f"Found {len(variable_sets)} existing variable sets")
99+
100+
for vs in variable_sets: # Show first 3
101+
print(f"- {vs.name} (ID: {vs.id}, Global: {vs.global_})")
102+
print()
103+
95104
# 3. Create variables in the variable set
96105
print("3. Creating variables in the variable set...")
97106

@@ -147,12 +156,16 @@ def variable_set_example():
147156
# 4. List variables in the variable set
148157
print("4. Listing variables in the variable set...")
149158
var_list_options = VariableSetVariableListOptions(page_size=50)
150-
variables = client.variable_set_variables.list(
151-
created_variable_set_id, var_list_options
159+
variables = list(
160+
client.variable_set_variables.list(
161+
created_variable_set_id, var_list_options
162+
)
152163
)
153164
print(f"Found {len(variables)} variables in the set:")
154165

155-
for var in variables:
166+
for var in client.variable_set_variables.list(
167+
created_variable_set_id, var_list_options
168+
):
156169
sensitive_note = " (sensitive)" if var.sensitive else ""
157170
hcl_note = " (HCL)" if var.hcl else ""
158171
print(f"- {var.key}: {var.category.value}{sensitive_note}{hcl_note}")
@@ -212,10 +225,14 @@ def variable_set_example():
212225
print("Successfully applied to workspace")
213226

214227
# List variable sets for this workspace
215-
workspace_varsets = client.variable_sets.list_for_workspace(
228+
print(f"Listing variable sets for workspace: {first_workspace.name}")
229+
workspace_varsets = 0
230+
for ws_varset in client.variable_sets.list_for_workspace(
216231
first_workspace.id
217-
)
218-
print(f"Workspace now has {len(workspace_varsets)} variable sets")
232+
):
233+
print(f"- {ws_varset.name} (ID: {ws_varset.id})")
234+
workspace_varsets += 1
235+
print(f"Workspace now has {workspace_varsets} variable sets")
219236

220237
# Remove from workspace
221238
remove_ws_options = VariableSetRemoveFromWorkspacesOptions(
@@ -250,10 +267,14 @@ def variable_set_example():
250267
print("Successfully applied to project")
251268

252269
# List variable sets for this project
253-
project_varsets = client.variable_sets.list_for_project(
270+
print(f"Listing variable sets for project: {first_project.name}")
271+
project_varsets = 0
272+
for proj_varset in client.variable_sets.list_for_project(
254273
first_project.id
255-
)
256-
print(f"Project now has {len(project_varsets)} variable sets")
274+
):
275+
print(f"- {proj_varset.name} (ID: {proj_varset.id})")
276+
project_varsets += 1
277+
print(f"Project now has {project_varsets} variable sets")
257278

258279
# Remove from project
259280
remove_proj_options = VariableSetRemoveFromProjectsOptions(

src/pytfe/models/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@
106106
PolicyActions,
107107
PolicyCheck,
108108
PolicyCheckIncludeOpt,
109-
PolicyCheckList,
110109
PolicyCheckListOptions,
111110
PolicyPermissions,
112111
PolicyResult,
@@ -605,7 +604,6 @@
605604
"PolicyResult",
606605
"PolicyStatusTimestamps",
607606
"PolicyCheckListOptions",
608-
"PolicyCheckList",
609607
# Policy Evaluation
610608
"PolicyAttachable",
611609
"PolicyEvaluation",
@@ -672,4 +670,3 @@
672670

673671
# Rebuild models with forward references after all models are loaded
674672
PolicyCheck.model_rebuild()
675-
PolicyCheckList.model_rebuild()

src/pytfe/models/policy_check.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ class PolicyCheckListOptions(BaseModel):
106106
model_config = ConfigDict(populate_by_name=True, validate_by_name=True)
107107

108108
include: list[PolicyCheckIncludeOpt] | None = Field(None, alias="include")
109-
page_number: int | None = Field(None, alias="page[number]")
110109
page_size: int | None = Field(None, alias="page[size]")
111110

112111

src/pytfe/models/state_version.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ class StateVersionListOptions(BaseModel):
7878
model_config = ConfigDict(populate_by_name=True, validate_by_name=True)
7979

8080
# Standard pagination + filters
81-
page_number: int | None = Field(None, alias="page[number]")
8281
page_size: int | None = Field(None, alias="page[size]")
8382
organization: str | None = Field(None, alias="filter[organization][name]")
8483
workspace: str | None = Field(None, alias="filter[workspace][name]")

src/pytfe/models/state_version_output.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ class StateVersionOutput(BaseModel):
1919
class StateVersionOutputsListOptions(BaseModel):
2020
model_config = ConfigDict(populate_by_name=True, validate_by_name=True)
2121

22-
page_number: int | None = Field(None, alias="page[number]")
2322
page_size: int | None = Field(None, alias="page[size]")
2423

2524

src/pytfe/models/variable_set.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ class VariableSetListOptions(BaseModel):
6969
"""Options for listing variable sets."""
7070

7171
# Pagination options
72-
page_number: int | None = None
7372
page_size: int | None = None
7473
include: list[VariableSetIncludeOpt] | None = None
7574
query: str | None = None # Filter by name

src/pytfe/resources/policy_check.py

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
from __future__ import annotations
22

33
import time
4+
from collections.abc import Iterator
45

56
from ..errors import (
67
InvalidPolicyCheckIDError,
78
InvalidRunIDError,
89
)
910
from ..models.policy_check import (
1011
PolicyCheck,
11-
PolicyCheckList,
1212
PolicyCheckListOptions,
1313
PolicyStatus,
1414
)
@@ -24,35 +24,19 @@ class PolicyChecks(_Service):
2424

2525
def list(
2626
self, run_id: str, options: PolicyCheckListOptions | None = None
27-
) -> PolicyCheckList:
27+
) -> Iterator[PolicyCheck]:
2828
"""List all policy checks of the given run."""
2929
if not valid_string_id(run_id):
3030
raise InvalidRunIDError()
3131
params = (
3232
options.model_dump(by_alias=True, exclude_none=True) if options else None
3333
)
34-
r = self.t.request(
35-
"GET",
36-
f"/api/v2/runs/{run_id}/policy-checks",
37-
params=params,
38-
)
39-
jd = r.json()
40-
items = []
41-
meta = jd.get("meta", {})
42-
pagination = meta.get("pagination", {})
43-
for d in jd.get("data", []):
44-
attrs = d.get("attributes", {})
45-
attrs["id"] = d.get("id")
46-
attrs["run"] = d.get("relationships", {}).get("run", {})
47-
items.append(PolicyCheck.model_validate(attrs))
48-
return PolicyCheckList(
49-
items=items,
50-
current_page=pagination.get("current-page"),
51-
total_pages=pagination.get("total-pages"),
52-
prev_page=pagination.get("prev-page"),
53-
next_page=pagination.get("next-page"),
54-
total_count=pagination.get("total-count"),
55-
)
34+
path = f"/api/v2/runs/{run_id}/policy-checks"
35+
for item in self._list(path, params=params):
36+
attrs = item.get("attributes", {})
37+
attrs["id"] = item.get("id")
38+
attrs["run"] = item.get("relationships", {}).get("run", {}).get("data")
39+
yield PolicyCheck.model_validate(attrs)
5640

5741
def read(self, policy_check_id: str) -> PolicyCheck:
5842
"""Read a policy check by its ID."""
@@ -66,7 +50,7 @@ def read(self, policy_check_id: str) -> PolicyCheck:
6650
d = jd.get("data", {})
6751
attrs = d.get("attributes", {})
6852
attrs["id"] = d.get("id")
69-
attrs["run"] = d.get("relationships", {}).get("run", {})
53+
attrs["run"] = d.get("relationships", {}).get("run", {}).get("data")
7054
return PolicyCheck.model_validate(attrs)
7155

7256
def override(self, policy_check_id: str) -> PolicyCheck:
@@ -81,7 +65,7 @@ def override(self, policy_check_id: str) -> PolicyCheck:
8165
d = jd.get("data", {})
8266
attrs = d.get("attributes", {})
8367
attrs["id"] = d.get("id")
84-
attrs["run"] = d.get("relationships", {}).get("run", {})
68+
attrs["run"] = d.get("relationships", {}).get("run", {}).get("data")
8569
return PolicyCheck.model_validate(attrs)
8670

8771
def logs(self, policy_check_id: str) -> str:

src/pytfe/resources/state_version_outputs.py

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from __future__ import annotations
22

3+
from collections.abc import Iterator
34
from typing import Any
45

56
from ..models.state_version_output import (
67
StateVersionOutput,
7-
StateVersionOutputsList,
88
StateVersionOutputsListOptions,
99
)
1010
from ..utils import valid_string_id
@@ -42,7 +42,7 @@ def read_current(
4242
self,
4343
workspace_id: str,
4444
options: StateVersionOutputsListOptions | None = None,
45-
) -> StateVersionOutputsList:
45+
) -> Iterator[StateVersionOutput]:
4646
"""
4747
Read outputs for the workspace's current state version.
4848
Note: sensitive outputs are returned with null values by the API.
@@ -52,32 +52,13 @@ def read_current(
5252

5353
params: dict[str, Any] = {}
5454
if options:
55-
if options.page_number is not None:
56-
params["page[number]"] = options.page_number
5755
if options.page_size is not None:
5856
params["page[size]"] = options.page_size
57+
path = f"/api/v2/workspaces/{workspace_id}/current-state-version-outputs"
5958

60-
r = self.t.request(
61-
"GET",
62-
f"/api/v2/workspaces/{workspace_id}/current-state-version-outputs",
63-
params=params,
64-
)
65-
data = r.json()
66-
67-
items: list[StateVersionOutput] = []
68-
for item in data.get("data", []):
69-
attr = item.get("attributes", {}) or {}
70-
items.append(
71-
StateVersionOutput(
72-
id=_safe_str(item.get("id")),
73-
**{k.replace("-", "_"): v for k, v in attr.items()},
74-
)
59+
for d in self._list(path, params=params):
60+
attr = d.get("attributes", {}) or {}
61+
yield StateVersionOutput(
62+
id=_safe_str(d.get("id")),
63+
**{k.replace("-", "_"): v for k, v in attr.items()},
7564
)
76-
77-
meta = data.get("meta", {}).get("pagination", {}) or {}
78-
return StateVersionOutputsList(
79-
items=items,
80-
current_page=meta.get("current-page"),
81-
total_pages=meta.get("total-pages"),
82-
total_count=meta.get("total-count"),
83-
)

0 commit comments

Comments
 (0)