Home Assistant Unofficial Reference 2024.12.1
data_entry_flow.py
Go to the documentation of this file.
1 """Helpers for the data entry flow."""
2 
3 from __future__ import annotations
4 
5 from http import HTTPStatus
6 from typing import Any, Generic
7 
8 from aiohttp import web
9 from typing_extensions import TypeVar
10 import voluptuous as vol
11 import voluptuous_serialize
12 
13 from homeassistant import data_entry_flow
14 from homeassistant.components.http import HomeAssistantView
15 from homeassistant.components.http.data_validator import RequestDataValidator
16 
17 from . import config_validation as cv
18 
19 _FlowManagerT = TypeVar(
20  "_FlowManagerT",
21  bound=data_entry_flow.FlowManager[Any, Any],
23 )
24 
25 
26 class _BaseFlowManagerView(HomeAssistantView, Generic[_FlowManagerT]):
27  """Foundation for flow manager views."""
28 
29  def __init__(self, flow_mgr: _FlowManagerT) -> None:
30  """Initialize the flow manager index view."""
31  self._flow_mgr_flow_mgr = flow_mgr
32 
34  self, result: data_entry_flow.FlowResult
36  """Convert result to JSON."""
37  if result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY:
38  data = result.copy()
39  data.pop("result")
40  data.pop("data")
41  data.pop("context")
42  return data
43 
44  if "data_schema" not in result:
45  return result
46 
47  data = result.copy()
48 
49  if (schema := data["data_schema"]) is None:
50  data["data_schema"] = [] # type: ignore[typeddict-item] # json result type
51  else:
52  data["data_schema"] = voluptuous_serialize.convert(
53  schema, custom_serializer=cv.custom_serializer
54  )
55 
56  return data
57 
58 
60  """View to create config flows."""
61 
62  @RequestDataValidator( vol.Schema( { vol.Required("handler"): str,
63  vol.Optional("show_advanced_options", default=False): cv.boolean,
64  },
65  extra=vol.ALLOW_EXTRA,
66  )
67  )
68  async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
69  """Initialize a POST request.
70 
71  Override `_post_impl` in subclasses which need
72  to implement their own `RequestDataValidator`
73  """
74  return await self._post_impl_post_impl(request, data)
75 
76  async def _post_impl(
77  self, request: web.Request, data: dict[str, Any]
78  ) -> web.Response:
79  """Handle a POST request."""
80  try:
81  result = await self._flow_mgr_flow_mgr.async_init(
82  data["handler"],
83  context=self.get_contextget_context(data),
84  )
86  return self.json_message("Invalid handler specified", HTTPStatus.NOT_FOUND)
87  except data_entry_flow.UnknownStep as err:
88  return self.json_message(str(err), HTTPStatus.BAD_REQUEST)
89 
90  result = self._prepare_result_json_prepare_result_json(result)
91 
92  return self.json(result)
93 
94  def get_context(self, data: dict[str, Any]) -> dict[str, Any]:
95  """Return context."""
96  return {"show_advanced_options": data["show_advanced_options"]}
97 
98 
99 class FlowManagerResourceView(_BaseFlowManagerView[_FlowManagerT]):
100  """View to interact with the flow manager."""
101 
102  async def get(self, request: web.Request, /, flow_id: str) -> web.Response:
103  """Get the current state of a data_entry_flow."""
104  try:
105  result = await self._flow_mgr_flow_mgr.async_configure(flow_id)
107  return self.json_message("Invalid flow specified", HTTPStatus.NOT_FOUND)
108 
109  result = self._prepare_result_json_prepare_result_json(result)
110 
111  return self.json(result)
112 
113  @RequestDataValidator(vol.Schema(dict), allow_empty=True)
114  async def post(
115  self, request: web.Request, data: dict[str, Any], flow_id: str
116  ) -> web.Response:
117  """Handle a POST request."""
118  try:
119  result = await self._flow_mgr_flow_mgr.async_configure(flow_id, data)
121  return self.json_message("Invalid flow specified", HTTPStatus.NOT_FOUND)
122  except data_entry_flow.InvalidData as ex:
123  return self.json({"errors": ex.schema_errors}, HTTPStatus.BAD_REQUEST)
124 
125  result = self._prepare_result_json_prepare_result_json(result)
126 
127  return self.json(result)
128 
129  async def delete(self, request: web.Request, flow_id: str) -> web.Response:
130  """Cancel a flow in progress."""
131  try:
132  self._flow_mgr_flow_mgr.async_abort(flow_id)
134  return self.json_message("Invalid flow specified", HTTPStatus.NOT_FOUND)
135 
136  return self.json_message("Flow aborted")
137 
web.Response post(self, web.Request request, dict[str, Any] data)
web.Response _post_impl(self, web.Request request, dict[str, Any] data)
dict[str, Any] get_context(self, dict[str, Any] data)
web.Response get(self, web.Request request, str flow_id)
web.Response post(self, web.Request request, dict[str, Any] data, str flow_id)
None __init__(self, _FlowManagerT flow_mgr)
data_entry_flow.FlowResult _prepare_result_json(self, data_entry_flow.FlowResult result)
_flow_mgr
web.Response delete(self, web.Request request, str config_key)
Definition: view.py:144