Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/pytfe/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@
)
from .run_task_request import (
RunTaskRequest,
RunTaskRequestCapabilitites,
RunTaskRequestCapabilities,
)
from .run_trigger import (
RunTrigger,
Expand Down Expand Up @@ -750,7 +750,7 @@
"RunTaskReadOptions",
# Run Task Request
"RunTaskRequest",
"RunTaskRequestCapabilitites",
"RunTaskRequestCapabilities",
# Task Result
"TaskResult",
"TaskResultEnforcementLevel",
Expand Down
8 changes: 4 additions & 4 deletions src/pytfe/models/run_task_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pydantic import BaseModel, ConfigDict, Field


class RunTaskRequestCapabilitites(BaseModel):
class RunTaskRequestCapabilities(BaseModel):
"""Defines the capabilities that the caller supports."""

model_config = ConfigDict(populate_by_name=True)
Expand All @@ -27,9 +27,9 @@ class RunTaskRequest(BaseModel):
access_token: str = Field(
..., alias="access_token", description="The access token for the run task"
)
capabilitites: RunTaskRequestCapabilitites = Field(
default_factory=lambda: RunTaskRequestCapabilitites(outcomes=False),
alias="capabilitites",
capabilities: RunTaskRequestCapabilities = Field(
default_factory=lambda: RunTaskRequestCapabilities(outcomes=False),
alias="capabilities",
description="The capabilities that the caller supports",
Comment on lines +30 to 33

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep backward alias for misspelled capabilities key

Changing the field/alias to capabilities removes support for the old capabilitites spelling with no fallback (validation_alias/alias choice), so persisted payloads or caller code built against earlier SDK versions will fail deserialization or attribute access after upgrade. For a typo fix in a stable SDK, this should remain backward-compatible (for at least one deprecation cycle) to avoid runtime breakage.

Useful? React with 👍 / 👎.

)
configuration_version_download_url: str | None = Field(
Expand Down
8 changes: 1 addition & 7 deletions src/pytfe/models/task_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,10 @@

from pytfe.models.policy_evaluation import PolicyEvaluation
from pytfe.models.run import Run
from pytfe.models.run_task import Stage

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve legacy task-stage enum members

Importing Stage from run_task replaces the previously exported task_stage.Stage members (pre_plan, post_plan, etc.) with uppercase members (PRE_PLAN, ...). Any existing client code that does from pytfe.models.task_stage import Stage and references Stage.pre_plan will now raise AttributeError at runtime, which is a breaking API change for a 1.x SDK unless a compatibility alias/shim is kept.

Useful? React with 👍 / 👎.

from pytfe.models.task_result import TaskResult


class Stage(str, Enum):
pre_plan = "pre_plan"
post_plan = "post_plan"
pre_apply = "pre_apply"
post_apply = "post_apply"


class TaskStageStatus(str, Enum):
pending = "pending"
running = "running"
Expand Down
1 change: 0 additions & 1 deletion src/pytfe/resources/task_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ def read(self, task_result_id: str) -> TaskResult:
return self._parse_task_result(data)

def _parse_task_result(self, data: dict[str, Any]) -> TaskResult:

attributes = data.get("attributes", {})
attributes["id"] = data.get("id")

Expand Down
40 changes: 40 additions & 0 deletions tests/units/test_run_task_request.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Unit tests for run task webhook request models."""

from pytfe.models import RunTaskRequest, RunTaskRequestCapabilities


def _run_task_request_payload() -> dict:
return {
"access_token": "token",
"configuration_version_download_url": "https://example.com/cv",
"configuration_version_id": "cv-123",
"is_speculative": False,
"organization_name": "example-org",
"payload_version": 1,
"plan_json_api_url": "https://example.com/plan-json",
"run_app_url": "https://example.com/run",
"run_created_at": "2024-01-01T00:00:00Z",
"run_created_by": "user-123",
"run_id": "run-123",
"run_message": "Queued manually",
"stage": "post_plan",
"task_result_callback_url": "https://example.com/callback",
"task_result_enforcement_level": "mandatory",
"task_result_id": "taskrs-123",
"workspace_app_url": "https://example.com/workspace",
"workspace_id": "ws-123",
"workspace_name": "example-workspace",
}


def test_run_task_request_parses_capabilities_from_live_payload():
payload = _run_task_request_payload()
payload["capabilities"] = {"outcomes": True}

request = RunTaskRequest.model_validate(payload)

assert isinstance(request.capabilities, RunTaskRequestCapabilities)
assert request.capabilities.outcomes is True
dumped = request.model_dump(by_alias=True)
assert dumped["capabilities"] == {"outcomes": True}
assert "capabilitites" not in dumped
11 changes: 9 additions & 2 deletions tests/units/test_task_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from pytfe.client import TFEClient
from pytfe.errors import InvalidTaskStageIDError
from pytfe.models import Stage as ExportedStage
from pytfe.models.run_task import Stage as RunTaskStage
from pytfe.models.task_stage import (
Stage,
TaskStage,
Expand All @@ -25,6 +27,11 @@ def test_task_stage_methods_exist():
assert hasattr(client.task_stages, "override")


def test_task_stage_uses_canonical_stage_enum():
assert Stage is RunTaskStage
assert Stage is ExportedStage


# InvalidTaskStageIDError tests


Expand Down Expand Up @@ -69,7 +76,7 @@ def test_task_stage_partial_payload():
{"id": "ts-456", "stage": "pre_plan", "status": "pending"}
)
assert ts.id == "ts-456"
assert ts.stage == Stage.pre_plan
assert ts.stage == Stage.PRE_PLAN
assert ts.status == TaskStageStatus.pending
assert ts.status_timestamps is None
assert ts.created_at is None
Expand All @@ -90,7 +97,7 @@ def test_task_stage_full_payload():
"actions": {"is-overridable": False},
}
)
assert ts.stage == Stage.post_plan
assert ts.stage == Stage.POST_PLAN
assert ts.status == TaskStageStatus.passed
assert ts.permissions is not None
assert ts.permissions.can_override is True
Expand Down
Loading