From 770185004ba7efbae758638aa566563e1eb2d430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Mon, 13 Jan 2020 21:55:41 +0200 Subject: [PATCH] Code block improvements (#382) * Use f-strings instead of .format() * Code block language marker fixes * Make example code blocks syntactically valid Python * Run all python code blocks through black https://github.com/scop/misc/blob/master/black_markdown.py * Add some missing code block language markers * Use shell language consistently to mark shell code blocks * Undo folding of some example dicts * Remove outdated OrderedDict comments per Python 3.7, replace with plain dict --- docs/api_lib_auth.md | 28 ++-- docs/api_lib_data_models.md | 23 ++-- docs/api_lib_index.md | 4 +- docs/asyncio_categorizing_functions.md | 4 +- docs/asyncio_working_with_async.md | 24 ++-- docs/auth_api.md | 6 +- docs/auth_auth_provider.md | 10 +- docs/auth_permissions.md | 73 ++++++----- docs/config_entries_config_flow_handler.md | 10 +- docs/config_entries_index.md | 5 +- docs/config_entries_options_flow_handler.md | 2 +- docs/configuration_yaml_index.md | 4 +- docs/creating_component_code_review.md | 4 +- docs/creating_component_index.md | 12 +- docs/creating_integration_manifest.md | 4 +- docs/creating_platform_code_review.md | 22 ++-- docs/data_entry_flow_index.md | 123 ++++++++---------- docs/dev_101_events.md | 14 +- docs/dev_101_index.md | 2 +- docs/dev_101_services.md | 10 +- docs/dev_101_states.md | 24 ++-- docs/development_catching_up.md | 6 +- docs/development_environment.md | 22 ++-- docs/development_guidelines.md | 8 +- docs/development_testing.md | 12 +- docs/development_validation.md | 47 ++++--- docs/device_registry_index.md | 24 ++-- docs/documentation_index.md | 6 +- docs/entity_cover.md | 1 - docs/entity_fan.md | 4 +- docs/entity_index.md | 4 +- docs/entity_light.md | 19 ++- docs/entity_switch.md | 1 - docs/external_api_rest.md | 40 +++--- docs/external_api_server_sent_events.md | 10 +- docs/frontend_add_websocket_api.md | 58 +++++---- docs/frontend_development.md | 12 +- docs/hassio_addon_config.md | 4 +- docs/hassio_addon_publishing.md | 4 +- docs/hassio_addon_tutorial.md | 8 +- docs/hassio_debugging.md | 6 +- docs/hassio_hass.md | 6 +- docs/intent_conversation.md | 8 +- docs/intent_firing.md | 14 +- docs/intent_handling.md | 9 +- ...ternationalization_backend_localization.md | 2 +- docs/maintenance.md | 6 +- docs/reproduce_state_index.md | 1 + 48 files changed, 382 insertions(+), 368 deletions(-) diff --git a/docs/api_lib_auth.md b/docs/api_lib_auth.md index 3c731b0c..6dd19c99 100644 --- a/docs/api_lib_auth.md +++ b/docs/api_lib_auth.md @@ -34,7 +34,7 @@ class Auth: async def request(self, method: str, path: str, **kwargs) -> ClientResponse: """Make a request.""" - headers = kwargs.get('headers') + headers = kwargs.get("headers") if headers is None: headers = {} @@ -44,10 +44,7 @@ class Auth: headers["authorization"] = self.access_token return await self.websession.request( - method, - f"{self.host}/{path}", - **kwargs, - headers=headers, + method, f"{self.host}/{path}", **kwargs, headers=headers, ) ``` @@ -65,10 +62,11 @@ async def main(): auth = Auth(session, "http://example.com/api", "secret_access_token") # This will fetch data from http://example.com/api/lights - resp = await auth.request('get', 'lights') + resp = await auth.request("get", "lights") print("HTTP response status code", resp.status) print("HTTP response JSON content", await resp.json()) + asyncio.run(main()) ``` @@ -88,7 +86,7 @@ class Auth: async def request(self, method: str, path: str, **kwargs) -> requests.Response: """Make a request.""" - headers = kwargs.get('headers') + headers = kwargs.get("headers") if headers is None: headers = {} @@ -98,10 +96,7 @@ class Auth: headers["authorization"] = self.access_token return requests.request( - method, - f"{self.host}/{path}", - **kwargs, - headers=headers, + method, f"{self.host}/{path}", **kwargs, headers=headers, ) ``` @@ -114,7 +109,7 @@ from my_package import Auth auth = Auth("http://example.com/api", "secret_access_token") # This will fetch data from http://example.com/api/lights -resp = auth.request('get', 'lights') +resp = auth.request("get", "lights") print("HTTP response status code", resp.status_code) print("HTTP response JSON content", resp.json()) ``` @@ -147,7 +142,7 @@ class AbstractAuth(ABC): async def request(self, method, url, **kwargs) -> ClientResponse: """Make a request.""" - headers = kwargs.get('headers') + headers = kwargs.get("headers") if headers is None: headers = {} @@ -158,10 +153,7 @@ class AbstractAuth(ABC): headers["authorization"] = f"Bearer {access_token}" return await self.websession.request( - method, - f"{self.host}/{url}", - **kwargs, - headers=headers, + method, f"{self.host}/{url}", **kwargs, headers=headers, ) ``` @@ -172,7 +164,6 @@ from my_package import AbstractAuth class Auth(AbstractAuth): - def __init__(self, websession: ClientSession, host: str, token_manager): """Initialize the auth.""" super().__init__(websession, host) @@ -255,7 +246,6 @@ from my_package import AbstractAuth class Auth(AbstractAuth): - def refresh_tokens(self) -> Dict[str, Union[str, int]]: """Refresh and return new tokens.""" self.token_manager.fetch_access_token() diff --git a/docs/api_lib_data_models.md b/docs/api_lib_data_models.md index 89dd1c5d..ddf6c373 100644 --- a/docs/api_lib_data_models.md +++ b/docs/api_lib_data_models.md @@ -58,29 +58,29 @@ class Light: @property def id(self) -> int: """Return the ID of the light.""" - return self.raw_data['id'] + return self.raw_data["id"] @property def name(self) -> str: """Return the name of the light.""" - return self.raw_data['name'] + return self.raw_data["name"] @property def is_on(self) -> bool: """Return if the light is on.""" - return self.raw_data['id'] + return self.raw_data["id"] async def async_control(self, is_on: bool): """Control the light.""" - resp = await self.auth.request('post', f'light/{self.id}', json={ - 'is_on': is_on - }) + resp = await self.auth.request( + "post", f"light/{self.id}", json={"is_on": is_on} + ) resp.raise_for_status() self.raw_data = await resp.json() async def async_update(self): """Update the light data.""" - resp = await self.auth.request('get', f'light/{self.id}') + resp = await self.auth.request("get", f"light/{self.id}") resp.raise_for_status() self.raw_data = await resp.json() ``` @@ -103,16 +103,13 @@ class ExampleHubAPI: async def async_get_lights(self) -> List[Light]: """Return the lights.""" - resp = await self.auth.request('get', 'lights') + resp = await self.auth.request("get", "lights") resp.raise_for_status() - return [ - Light(light_data, self.auth) - for light_data in await resp.json() - ] + return [Light(light_data, self.auth) for light_data in await resp.json()] async def async_get_light(self, light_id) -> Light: """Return the lights.""" - resp = await self.auth.request('get', f'light/{light_id}') + resp = await self.auth.request("get", f"light/{light_id}") resp.raise_for_status() return Light(await resp.json(), self.auth) ``` diff --git a/docs/api_lib_index.md b/docs/api_lib_index.md index 49aaeaf8..c3051bb5 100644 --- a/docs/api_lib_index.md +++ b/docs/api_lib_index.md @@ -33,12 +33,12 @@ You will need to run an editable version of your library if you want to try your Do so by going to your Home Assistant development environment, activating the virtual environment and typing: -``` +```shell pip3 install -e ../my_lib_folder ``` Now run Home Assistant without installing dependencies from PyPI to avoid overriding your package. -``` +```shell hass --skip-pip ``` diff --git a/docs/asyncio_categorizing_functions.md b/docs/asyncio_categorizing_functions.md index b03650a6..5905cfbd 100644 --- a/docs/asyncio_categorizing_functions.md +++ b/docs/asyncio_categorizing_functions.md @@ -18,7 +18,8 @@ To declare a function a coroutine, add `async` before the `def` of the function async def async_look_my_coroutine(target): result = await entity.async_turn_on() if result: - print("hello {}".format(target)) + print(f"hello {target}") + hass.loop.create_task(async_look_my_coroutine("world")) ``` @@ -36,6 +37,7 @@ A common use case for a callback in Home Assistant is as a listener for an event ```python from homeassistant.core import callback + @callback def async_trigger_service_handler(service_call): """Handle automation trigger service calls.""" diff --git a/docs/asyncio_working_with_async.md b/docs/asyncio_working_with_async.md index 729a01bc..db9bdaed 100644 --- a/docs/asyncio_working_with_async.md +++ b/docs/asyncio_working_with_async.md @@ -16,14 +16,16 @@ To make a component async, implement an async_setup. ```python def setup(hass, config): - # Setup your component outside of the event loop. + """Set up component.""" + # Code for setting up your component outside of the event loop. ``` Will turn into: ```python async def async_setup(hass, config): - # Setup your component inside of the event loop. + """Set up component.""" + # Code for setting up your component inside of the event loop. ``` ## Implementing an async platform @@ -31,16 +33,17 @@ async def async_setup(hass, config): For platforms we support async setup. Instead of setup_platform you need to have a coroutine async_setup_platform. ```python -setup_platform(hass, config, add_entities, discovery_info=None): - # Setup your platform outside of the event loop. +def setup_platform(hass, config, add_entities, discovery_info=None): + """Set up platform.""" + # Code for setting up your platform outside of the event loop. ``` Will turn into: ```python -async def async_setup_platform(hass, config, async_add_entities, - discovery_info=None): - # Setup your platform inside of the event loop +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): + """Set up platform.""" + # Code for setting up your platform inside of the event loop. ``` The only difference with the original parameters is that the `add_entities` function has been replaced by the async friendly callback `async_add_entities`. @@ -76,12 +79,15 @@ In the following example, `say_hello` will schedule `async_say_hello` and block ```python import asyncio + def say_hello(hass, target): return asyncio.run_coroutine_threadsafe( - async_say_hello(hass, target), hass.loop).result() + async_say_hello(hass, target), hass.loop + ).result() + async def async_say_hello(hass, target): - return "Hello {}!".format(target) + return f"Hello {target}!" ``` ## Calling sync functions from async diff --git a/docs/auth_api.md b/docs/auth_api.md index 54d5392f..a84a4b81 100644 --- a/docs/auth_api.md +++ b/docs/auth_api.md @@ -176,7 +176,7 @@ For the websocket connection, pass the access token in the [authentication messa For HTTP requests, pass the token type and access token as the authorization header: -``` +```http Authorization: Bearer ABCDEFGH ``` @@ -195,9 +195,9 @@ import requests url = "https://your.awesome.home/api/error/all" headers = { - 'Authorization': "Bearer ABCDEFGH", + "Authorization": "Bearer ABCDEFGH", } -response = requests.request('GET', url, headers=headers) +response = requests.request("GET", url, headers=headers) print(response.text) ``` diff --git a/docs/auth_auth_provider.md b/docs/auth_auth_provider.md index 0bff728e..8880c3db 100644 --- a/docs/auth_auth_provider.md +++ b/docs/auth_auth_provider.md @@ -36,7 +36,11 @@ Auth providers shall extend the following methods of `LoginFlow` class. ```python async def async_step_init(self, user_input=None): - return self.async_show_form(step_id='init', data_schema='some schema to construct ui form') if user_input is None - return self.async_show_form(step_id='init', errors) if user_input is invalid - return await self.async_finish(username) if user_input is valid + if user_input is None: + return self.async_show_form( + step_id="init", data_schema="some schema to construct ui form" + ) + if is_invalid(user_input): + return self.async_show_form(step_id="init", errors=errors) + return await self.async_finish(user_input) ``` diff --git a/docs/auth_permissions.md b/docs/auth_permissions.md index 00b7a42d..5feddf12 100644 --- a/docs/auth_permissions.md +++ b/docs/auth_permissions.md @@ -14,7 +14,9 @@ Policies are dictionaries that at the root level consist of different categories ```python { - "entities": … + "entities": { + # … + } } ``` @@ -22,10 +24,14 @@ Each category can further split into subcategories that describe parts of that c ```python { - "entities": { - "domains": …, - "entity_ids": … - } + "entities": { + "domains": { + # … + }, + "entity_ids": { + # … + }, + } } ``` @@ -67,19 +73,19 @@ Let's look at an example: ```python { - "entities": { - "entity_ids": { - "light.kitchen": True + "entities": { + "entity_ids": { + "light.kitchen": True + } } - } } ``` ```python { - "entities": { - "entity_ids": True - } + "entities": { + "entity_ids": True + } } ``` @@ -87,9 +93,9 @@ Once merged becomes ```python { - "entities": { - "entity_ids": True - } + "entities": { + "entity_ids": True + } } ``` @@ -105,9 +111,7 @@ To check a permission, you will need to have access to the user object. Once you ```python from homeassistant.exceptions import Unauthorized -from homeasistant.permissions.const import ( - POLICY_READ, POLICY_CONTROL, POLICY_EDIT -) +from homeasistant.permissions.const import POLICY_READ, POLICY_CONTROL, POLICY_EDIT # Raise error if user is not an admin if not user.is_admin: @@ -129,9 +133,9 @@ It's crucial for permission checking that actions taken on behalf of the user ar ```python from homeassistant.core import Context -await hass.services.async_call('homeassistant', 'stop', context=Context( - user_id=user.id -), blocking=True) +await hass.services.async_call( + "homeassistant", "stop", context=Context(user_id=user.id), blocking=True +) ``` ### If a permission check fails @@ -167,9 +171,10 @@ Your service call handler will need to check the permissions for each entity tha from homeassistant.exceptions import Unauthorized, UnknownUser from homeassistant.auth.permissions.const import POLICY_CONTROL + async def handle_entity_service(call): """Handle a service call.""" - entity_ids = call.data['entity_id'] + entity_ids = call.data["entity_id"] for entity_id in entity_ids: if call.context.user_id: @@ -193,7 +198,7 @@ async def handle_entity_service(call): async def async_setup(hass, config): - hass.services.async_register(DOMAIN, 'my_service', handle_entity_service) + hass.services.async_register(DOMAIN, "my_service", handle_entity_service) return True ``` @@ -211,7 +216,7 @@ async def handle_admin_service(call): async def async_setup(hass, config): hass.helpers.service.async_register_admin_service( - DOMAIN, 'my_service', handle_admin_service, vol.Schema({}) + DOMAIN, "my_service", handle_admin_service, vol.Schema({}) ) return True ``` @@ -227,20 +232,20 @@ from homeassistant.exceptions import Unauthorized class MyView(HomeAssistantView): """View to handle Status requests.""" - url = '/api/my-component/my-api' - name = 'api:my-component:my-api' + url = "/api/my-component/my-api" + name = "api:my-component:my-api" async def post(self, request): """Notify that the API is running.""" - hass = request.app['hass'] - user = request['hass_user'] + hass = request.app["hass"] + user = request["hass_user"] if not user.is_admin: raise Unauthorized() - hass.bus.async_fire('my-component-api-running', context=Context( - user_id=user.id - )) + hass.bus.async_fire( + "my-component-api-running", context=Context(user_id=user.id) + ) return self.json_message("Done.") ``` @@ -262,9 +267,9 @@ async def async_setup(hass, config): @websocket_api.require_admin @websocket_api.async_response -@websocket_api.websocket_command({ - vol.Required('type'): 'my-component/my-action', -}) +@websocket_api.websocket_command( + {vol.Required("type"): "my-component/my-action",} +) async def websocket_create(hass, connection, msg): """Create a user.""" # Do action diff --git a/docs/config_entries_config_flow_handler.md b/docs/config_entries_config_flow_handler.md index 7c8ab3d9..b04a91e8 100644 --- a/docs/config_entries_config_flow_handler.md +++ b/docs/config_entries_config_flow_handler.md @@ -21,7 +21,9 @@ Config entries uses the [data flow entry framework](data_entry_flow_index.md) to from homeassistant import config_entries from .const import DOMAIN + class ExampleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): + """Example config flow.""" ``` Once you have updated your manifest and created the `config_flow.py`, you will need to run `python3 -m script.hassfest` (one time only) for Home Assistant to activate the config entry for your integration. @@ -32,16 +34,12 @@ Your config flow will need to define steps of your configuration flow. The docs ```python class ExampleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): - async def async_step_user(self, info): if info is not None: - # process info + pass # TODO: process info return self.async_show_form( - step_id='user', - data_schema=vol.Schema({ - vol.Required('password'): str - }) + step_id="user", data_schema=vol.Schema({vol.Required("password"): str}) ) ``` diff --git a/docs/config_entries_index.md b/docs/config_entries_index.md index 53b7d7b5..a1cb84d2 100644 --- a/docs/config_entries_index.md +++ b/docs/config_entries_index.md @@ -106,13 +106,14 @@ be done by calling the forward function on the config entry manager ([example](h ```python # Use `hass.async_add_job` to avoid a circular dependency between the platform and the component -hass.async_add_job(hass.config_entries.async_forward_entry_setup(config_entry, 'light')) +hass.async_add_job(hass.config_entries.async_forward_entry_setup(config_entry, "light")) ``` For a platform to support config entries, it will need to add a setup entry method ([example](https://github.com/home-assistant/home-assistant/blob/0.68.0/homeassistant/components/light/hue.py#L60)): ```python async def async_setup_entry(hass, config_entry, async_add_devices): + """Set up entry.""" ``` ## Unloading entries @@ -122,7 +123,7 @@ Components can optionally support unloading a config entry. When unloading an en For each platform that you forwarded the config entry to, you will need to forward the unloading too. ```python -await self.hass.config_entries.async_forward_entry_unload(self.config_entry, 'light') +await self.hass.config_entries.async_forward_entry_unload(self.config_entry, "light") ``` If you need to clean up resources used by an entity in a platform, have the entity implement the [`async_will_remove_from_hass`](entity_index.md#async_will_remove_from_hass) method. diff --git a/docs/config_entries_options_flow_handler.md b/docs/config_entries_options_flow_handler.md index 4c66d903..f6f60eab 100644 --- a/docs/config_entries_options_flow_handler.md +++ b/docs/config_entries_options_flow_handler.md @@ -24,7 +24,6 @@ The Flow handler works just like the config flow handler, except that the first ```python class OptionsFlowHandler(config_entries.OptionsFlow): - async def async_step_init(self, user_input=None): """Manage the options.""" if user_input is not None: @@ -55,4 +54,5 @@ The Listener shall be an async function that takes the same input as async_setup ```python async def update_listener(hass, entry): + """Handle options update.""" ``` diff --git a/docs/configuration_yaml_index.md b/docs/configuration_yaml_index.md index 47b98211..59ad72a4 100644 --- a/docs/configuration_yaml_index.md +++ b/docs/configuration_yaml_index.md @@ -47,9 +47,9 @@ will be passed to the component as "platform": "example1" }, { - "platform": "example2, + "platform": "example2", "some_config": True } - ] + ], } ``` diff --git a/docs/creating_component_code_review.md b/docs/creating_component_code_review.md index 6cd718ac..92a7dd73 100644 --- a/docs/creating_component_code_review.md +++ b/docs/creating_component_code_review.md @@ -39,10 +39,10 @@ A checklist of things to do when you're adding a new component. ```python # bad - status = requests.get(url('/status')) - + status = requests.get(url("/status")) # good from phue import Bridge + bridge = Bridge(...) status = bridge.status() ``` diff --git a/docs/creating_component_index.md b/docs/creating_component_index.md index 1fe49adf..254da90b 100644 --- a/docs/creating_component_index.md +++ b/docs/creating_component_index.md @@ -4,7 +4,7 @@ title: "Creating your first integration" Alright, you learned about the [manifest](creating_integration_manifest.md), so it's time to write your first code for your integration. AWESOME. Don't worry, we've tried hard to keep it as easy as possible. From a Home Assistant development environment, type the following and follow the instructions: -```python +```shell python3 -m script.scaffold integration ``` @@ -15,10 +15,11 @@ This will set you up with everything that you need to build an integration that The scaffold integration contains a bit more than just the bare minimum. The minimum is that you define a `DOMAIN` constant that contains the domain of the integration. The second part is that it needs to define a setup method that returns a boolean if the set up was successful. ```python -DOMAIN = 'hello_state' +DOMAIN = "hello_state" + def setup(hass, config): - hass.states.set('hello_state.world', 'Paulus') + hass.states.set("hello_state.world", "Paulus") # Return boolean to indicate that initialization was successful. return True @@ -27,10 +28,11 @@ def setup(hass, config): And if you prefer an async component: ```python -DOMAIN = 'hello_state' +DOMAIN = "hello_state" + async def async_setup(hass, config): - hass.states.async_set('hello_state.world', 'Paulus') + hass.states.async_set("hello_state.world", "Paulus") # Return boolean to indicate that initialization was successful. return True diff --git a/docs/creating_integration_manifest.md b/docs/creating_integration_manifest.md index e7526b29..5351eab9 100644 --- a/docs/creating_integration_manifest.md +++ b/docs/creating_integration_manifest.md @@ -70,7 +70,7 @@ Requirements is an array of strings. Each entry is a `pip` compatible string. Fo During the development of a component, it can be useful to test against different versions of a requirement. This can be done in two steps, using `pychromecast` as an example: -```bash +```shell pip install pychromecast==3.2.0 --target ~/.homeassistant/deps hass --skip-pip ``` @@ -79,7 +79,7 @@ This will use the specified version, and prevent Home Assistant from trying to o If you need to make changes to a requirement to support your component, it's also possible to install a development version of the requirement using `pip install -e`: -```bash +```shell git clone https://github.com/balloob/pychromecast.git pip install -e ./pychromecast hass --skip-pip diff --git a/docs/creating_platform_code_review.md b/docs/creating_platform_code_review.md index 36c5171d..39ec9453 100644 --- a/docs/creating_platform_code_review.md +++ b/docs/creating_platform_code_review.md @@ -35,15 +35,16 @@ from homeassistant.const import CONF_FILENAME, CONF_HOST from homeassistant.components.light import PLATFORM_SCHEMA import homeassistant.helpers.config_validation as cv -CONF_ALLOW_UNREACHABLE = 'allow_unreachable' +CONF_ALLOW_UNREACHABLE = "allow_unreachable" DEFAULT_UNREACHABLE = False -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - vol.Required(CONF_HOST): cv.string, - vol.Optional(CONF_ALLOW_UNREACHABLE, - default=DEFAULT_UNREACHABLE): cv.boolean, - vol.Optional(CONF_FILENAME): cv.string, -}) +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_ALLOW_UNREACHABLE, default=DEFAULT_UNREACHABLE): cv.boolean, + vol.Optional(CONF_FILENAME): cv.string, + } +) ``` ### 3. Setup Platform @@ -59,8 +60,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ ```python from homeassistant.components.light import Light + class HueLight(Light): - ... + """Hue light component.""" ``` 2. Avoid passing in `hass` as a parameter to the entity. When the entity has been added to Home Assistant, `hass` will be set on the entity when the entity is added to Home Assistant. This means you can access `hass` as `self.hass` inside the entity. @@ -75,10 +77,10 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ ```python # bad - status = requests.get(url('/status')) - + status = requests.get(url("/status")) # good from phue import Bridge + bridge = Bridge(...) status = bridge.status() ``` diff --git a/docs/data_entry_flow_index.md b/docs/data_entry_flow_index.md index 7779953f..045f2830 100644 --- a/docs/data_entry_flow_index.md +++ b/docs/data_entry_flow_index.md @@ -12,13 +12,15 @@ Data Entry Flow is used in Home Assistant to create config entries. This is the class that manages the flows that are in progress. When instantiating one, you pass in two async callbacks: ```python -async def async_create_flow(handler, context=context, data=data) +async def async_create_flow(handler, context=context, data=data): + """Create flow.""" ``` The manager delegates instantiating of config flow handlers to this async callback. This allows the parent of the manager to define their own way of finding handlers and preparing a handler for instantiation. For example, in the case of the config entry manager, it will make sure that the dependencies and requirements are setup. ```python -async def async_finish_flow(flow, result) +async def async_finish_flow(flow, result): + """Finish flow.""" ``` This async callback is called when a flow is finished or aborted. i.e. `result['type'] in [RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_ABORT]`. The callback function can modify result and return it back, if the result type changed to `RESULT_TYPE_FORM`, the flow will continue running, display another form. @@ -27,19 +29,19 @@ If the result type is `RESULT_TYPE_FORM`, the result should look like: ```python { # The result type of the flow - 'type': RESULT_TYPE_FORM, + "type": RESULT_TYPE_FORM, # the id of the flow - 'flow_id': 'abcdfgh1234, + "flow_id": "abcdfgh1234", # handler name - 'handler': 'hue', + "handler": "hue", # name of the step, flow.async_step_[step_id] will be called when form submitted - 'step_id': 'init', + "step_id": "init", # a voluptuous schema to build and validate user input - 'data_schema': vol.Schema(), + "data_schema": vol.Schema(), # an errors dict, None if no errors - 'errors': errors, + "errors": errors, # a detail information about the step - 'description_placeholders': description_placeholders, + "description_placeholders": description_placeholders, } ``` @@ -47,17 +49,17 @@ If the result type is `RESULT_TYPE_CREATE_ENTRY`, the result should look like: ```python { # Data schema version of the entry - 'version': 2, + "version": 2, # The result type of the flow - 'type': RESULT_TYPE_CREATE_ENTRY, + "type": RESULT_TYPE_CREATE_ENTRY, # the id of the flow - 'flow_id': 'abcdfgh1234, + "flow_id": "abcdfgh1234", # handler name - 'handler': 'hue', + "handler": "hue", # title and data as created by the handler - 'title': 'Some title', - 'result': { - 'some': 'data' + "title": "Some title", + "result": { + "some": "data" }, } ``` @@ -66,13 +68,13 @@ If the result type is `RESULT_TYPE_ABORT`, the result should look like: ```python { # The result type of the flow - 'type': RESULT_TYPE_ABORT, + "type": RESULT_TYPE_ABORT, # the id of the flow - 'flow_id': 'abcdfgh1234, + "flow_id": "abcdfgh1234", # handler name - 'handler': 'hue', + "handler": "hue", # the abort reason - 'reason': 'already_configured', + "reason": "already_configured", } ``` @@ -88,6 +90,7 @@ The bare minimum config flow: ```python from homeassistant import data_entry_flow + @config_entries.HANDLERS.register(DOMAIN) class ExampleConfigFlow(data_entry_flow.FlowHandler): @@ -97,7 +100,7 @@ class ExampleConfigFlow(data_entry_flow.FlowHandler): VERSION = 1 async def async_step_user(self, user_input=None): - # Do something + """Handle user step.""" ``` ### Show Form @@ -106,17 +109,14 @@ This result type will show a form to the user to fill in. You define the current ```python class ExampleConfigFlow(data_entry_flow.FlowHandler): - async def async_step_user(self, user_input=None): - # Use OrderedDict to guarantee order of the form shown to the user - data_schema = OrderedDict() - data_schema[vol.Required('username')] = str - data_schema[vol.Required('password')] = str + # Specify items in the order they are to be displayed in the UI + data_schema = { + vol.Required("username"): str, + vol.Required("password"): str, + } - return self.async_show_form( - step_id='init', - data_schema=vol.Schema(data_schema) - ) + return self.async_show_form(step_id="init", data_schema=vol.Schema(data_schema)) ``` After the user has filled in the form, the step method will be called again and the user input is passed in. Your step will only be called if the user input passes your data schema. When the user passes in data, you will have to do extra validation of the data. For example, you can verify that the passed in username and password are valid. @@ -125,7 +125,6 @@ If something is wrong, you can return a dictionary with errors. Each key in the ```python class ExampleConfigFlow(data_entry_flow.FlowHandler): - async def async_step_user(self, user_input=None): errors = {} if user_input is not None: @@ -135,17 +134,16 @@ class ExampleConfigFlow(data_entry_flow.FlowHandler): # See next section on create entry usage return self.create_entry(...) - errors['base'] = 'auth_error' + errors["base"] = "auth_error" - # Use OrderedDict to guarantee order of the form shown to the user - data_schema = OrderedDict() - data_schema[vol.Required('username')] = str - data_schema[vol.Required('password')] = str + # Specify items in the order they are to be displayed in the UI + data_schema = { + vol.Required("username"): str, + vol.Required("password"): str, + } return self.async_show_form( - step_id='init', - data_schema=vol.Schema(data_schema), - errors=errors + step_id="init", data_schema=vol.Schema(data_schema), errors=errors ) ``` @@ -155,7 +153,6 @@ If the user input passes validation, you can again return one of the three retur ```python class ExampleConfigFlow(data_entry_flow.FlowHandler): - async def async_step_init(self, user_input=None): errors = {} if user_input is not None: @@ -176,13 +173,12 @@ When the result is "Create Entry", an entry will be created and passed to the pa ```python class ExampleConfigFlow(data_entry_flow.FlowHandler): - async def async_step_user(self, user_input=None): return self.create_entry( - title='Title of the entry', + title="Title of the entry", data={ - 'something_special': user_input['username'] - } + "something_special": user_input["username"] + }, ) ``` @@ -192,11 +188,8 @@ When a flow cannot be finished, you need to abort it. This will finish the flow ```python class ExampleConfigFlow(data_entry_flow.FlowHandler): - async def async_step_user(self, user_input=None): - return self.async_abort( - reason='not_supported' - ) + return self.async_abort(reason="not_supported") ``` ### External Step & External Step Done @@ -222,6 +215,7 @@ Example configuration flow that includes an external step. ```python from homeassistant import config_entries + @config_entries.HANDLERS.register(DOMAIN) class ExampleConfigFlow(data_entry_flow.FlowHandler): VERSION = 1 @@ -230,20 +224,15 @@ class ExampleConfigFlow(data_entry_flow.FlowHandler): async def async_step_user(self, user_input=None): if not user_input: return self.async_external_step( - step_id='user', - url='https://example.com/?config_flow_id={}'.format( - self.flow_id - ), + step_id="user", + url=f"https://example.com/?config_flow_id={self.flow_id}", ) self.data = user_input - return self.async_external_step_done(next_step_id='finish') + return self.async_external_step_done(next_step_id="finish") async def async_step_finish(self, user_input=None): - return self.async_create_entry( - title=self.data['title'], - data=self.data - ) + return self.async_create_entry(title=self.data["title"], data=self.data) ``` Avoid doing work based on the external step data before you return an `async_mark_external_step_done`. Instead, do the work in the step that you refer to as `next_step_id` when marking the external step done. This will give the user a better user experience by showing a spinner in the UI while the work is done. @@ -255,13 +244,14 @@ Example code to mark an external step as done: ```python from homeassistant import data_entry_flow -async def handle_result(hass, flow_id, data): - result = await hass.config_entries.async_configure(flow_id, data) - if result['type'] == data_entry_flow.RESULT_TYPE_EXTERNAL_STEP_DONE: - return "success!" - else: - return "Invalid config flow specified" +async def handle_result(hass, flow_id, data): + result = await hass.config_entries.async_configure(flow_id, data) + + if result["type"] == data_entry_flow.RESULT_TYPE_EXTERNAL_STEP_DONE: + return "success!" + else: + return "Invalid config flow specified" ``` ## Translations @@ -273,14 +263,15 @@ Data entry flows depend on translations for showing the text in the forms. It de You might want to initialize a config flow programmatically. For example, if we discover a device on the network that requires user interaction to finish setup. To do so, pass a source parameter and optional user input when initializing a flow: ```python -await flow_mgr.async_init('hue', context={'source': data_entry_flow.SOURCE_DISCOVERY}, data=discovery_info) +await flow_mgr.async_init( + "hue", context={"source": data_entry_flow.SOURCE_DISCOVERY}, data=discovery_info +) ``` The config flow handler will not start with the `init` step. Instead, it will be instantiated with a step name equal to the source. The step should follow the same return values as a normal step. ```python class ExampleConfigFlow(data_entry_flow.FlowHandler): - async def async_step_discovery(self, info): - # Handle discovery info + """Handle discovery info.""" ``` diff --git a/docs/dev_101_events.md b/docs/dev_101_events.md index aa8ffdef..afffae4a 100644 --- a/docs/dev_101_events.md +++ b/docs/dev_101_events.md @@ -15,15 +15,14 @@ To fire an event, you have to interact with the event bus. The event bus is avai Example component that will fire an event when loaded. Note that custom event names are prefixed with the component name. ```python -DOMAIN = 'example_component' +DOMAIN = "example_component" + def setup(hass, config): """Set up is called when Home Assistant is loading our component.""" # Fire event example_component_my_cool_event with event data answer=42 - hass.bus.fire('example_component_my_cool_event', { - 'answer': 42 - }) + hass.bus.fire("example_component_my_cool_event", {"answer": 42}) # Return successful setup return True @@ -34,7 +33,8 @@ def setup(hass, config): Most of the times you'll not be firing events but instead listen to events. For example, the state change of an entity is broadcasted as an event. ```python -DOMAIN = 'example_component' +DOMAIN = "example_component" + def setup(hass, config): """Set up is called when Home Assistant is loading our component.""" @@ -44,10 +44,10 @@ def setup(hass, config): def handle_event(event): nonlocal count count += 1 - print('Answer {0} is: {1}'.format(count, event.data.get('answer'))) + print(f"Answer {count} is: {event.data.get('answer')}") # Listen for when example_component_my_cool_event is fired - hass.bus.listen('example_component_my_cool_event', handle_event) + hass.bus.listen("example_component_my_cool_event", handle_event) # Return successful setup return True diff --git a/docs/dev_101_index.md b/docs/dev_101_index.md index 8f7cbbb8..cd5e5579 100644 --- a/docs/dev_101_index.md +++ b/docs/dev_101_index.md @@ -21,7 +21,7 @@ DOMAIN = "hello_world" def setup(hass, config): """Setup the hello_world component.""" # States are in the format DOMAIN.OBJECT_ID. - hass.states.set('hello_world.Hello_World', 'Works!') + hass.states.set("hello_world.Hello_World", "Works!") # Return boolean to indicate that initialization was successfully. return True diff --git a/docs/dev_101_services.md b/docs/dev_101_services.md index ba20aa33..17ea7f18 100644 --- a/docs/dev_101_services.md +++ b/docs/dev_101_services.md @@ -10,10 +10,10 @@ This is a simple "hello world" example to show the basics of registering a servi Services can be called from automations and from the service "Developer tools" in the frontend. ```python -DOMAIN = 'hello_service' +DOMAIN = "hello_service" -ATTR_NAME = 'name' -DEFAULT_NAME = 'World' +ATTR_NAME = "name" +DEFAULT_NAME = "World" def setup(hass, config): @@ -23,9 +23,9 @@ def setup(hass, config): """Handle the service call.""" name = call.data.get(ATTR_NAME, DEFAULT_NAME) - hass.states.set('hello_service.hello', name) + hass.states.set("hello_service.hello", name) - hass.services.register(DOMAIN, 'hello', handle_hello) + hass.services.register(DOMAIN, "hello", handle_hello) # Return boolean to indicate that initialization was successfully. return True diff --git a/docs/dev_101_states.md b/docs/dev_101_states.md index 039a827a..74e40e64 100644 --- a/docs/dev_101_states.md +++ b/docs/dev_101_states.md @@ -27,7 +27,8 @@ import logging _LOGGER = logging.getLogger(__name__) -DOMAIN = 'hello_state' +DOMAIN = "hello_state" + def setup(hass, config): """Setup the Hello State component. """ @@ -58,7 +59,7 @@ hello_state: After a start or a restart of Home Assistant the component will create an entry in the log. -```bash +```log 16-03-12 14:16:42 INFO (MainThread) [custom_components.hello_state] The 'hello state' component is ready! ``` @@ -69,10 +70,11 @@ import logging _LOGGER = logging.getLogger(__name__) -DOMAIN = 'hello_state' +DOMAIN = "hello_state" + +CONF_TEXT = "text" +DEFAULT_TEXT = "No text!" -CONF_TEXT = 'text' -DEFAULT_TEXT = 'No text!' def setup(hass, config): """Set up the Hello State component. """ @@ -80,7 +82,7 @@ def setup(hass, config): text = config[DOMAIN].get(CONF_TEXT, DEFAULT_TEXT) # States are in the format DOMAIN.OBJECT_ID - hass.states.set('hello_state.Hello_State', text) + hass.states.set("hello_state.Hello_State", text) return True ``` @@ -99,11 +101,9 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv -CONFIG_SCHEMA = vol.Schema({ - DOMAIN: vol.Schema({ - vol.Required(CONF_TEXT): cv.string, - }) -}, extra=vol.ALLOW_EXTRA) +CONFIG_SCHEMA = vol.Schema( + {DOMAIN: vol.Schema({vol.Required(CONF_TEXT): cv.string,})}, extra=vol.ALLOW_EXTRA +) ``` Now, when `text:` is missing from the config, Home Assistant will alert the user and not setup your component. @@ -116,7 +116,7 @@ After a start or a restart of Home Assistant the component will be visible in th In order to expose attributes for a platform, you will need to define a property called `device_state_attributes` on the entity class, which will return a dictionary of attributes: -``` +```python @property def device_state_attributes(self): """Return device specific state attributes.""" diff --git a/docs/development_catching_up.md b/docs/development_catching_up.md index dde64da8..7c30738d 100644 --- a/docs/development_catching_up.md +++ b/docs/development_catching_up.md @@ -6,7 +6,7 @@ If it's taking a while to develop your feature, and you want to catch up with wh > If you use the workflow below, it is important that you force push the update as described. Git might prompt you to do `git pull` first. Do **NOT** do that! It would mess up your commit history. -```bash +```shell # Run this from your feature branch $ git fetch upstream dev # to pull the latest changes into a local dev branch $ git rebase upstream/dev # to put those changes into your feature branch before your changes @@ -21,14 +21,14 @@ If rebase detects conflicts, repeat this process until all changes have been res After rebasing your branch, you will have rewritten history relative to your GitHub fork's branch. When you go to push you will see an error that your history has diverged from the original branch. In order to get your GitHub fork up-to-date with your local branch, you will need to force push, using the following command: -```bash +```shell # Run this from your feature branch $ git push origin --force ``` Other workflows are covered in detail in the [Github documentation](https://help.github.com/articles/fork-a-repo/). Add an additional `remote` after you clone your fork. -```bash +```shell $ git remote add upstream https://github.com/home-assistant/home-assistant.git ``` diff --git a/docs/development_environment.md b/docs/development_environment.md index 5f84d21f..05b25bbf 100644 --- a/docs/development_environment.md +++ b/docs/development_environment.md @@ -10,13 +10,13 @@ You'll need to set up a development environment if you want to develop a new fea Install the core dependencies. -```bash +```shell $ sudo apt-get install python3-pip python3-dev python3-venv ``` In order to run `script/setup` below you will need some more dependencies. -```bash +```shell $ sudo apt-get install autoconf libssl-dev libxml2-dev libxslt1-dev libjpeg-dev libffi-dev libudev-dev zlib1g-dev pkg-config $ sudo apt-get install -y libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libavresample-dev libavfilter-dev ``` @@ -31,7 +31,7 @@ Since Home Assistant is mainly designed and developed on Linux distributions, on Open Powershell as an Administrator and run -```bash +```shell Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux ``` @@ -39,7 +39,7 @@ From Windows Store install Ubuntu. When the Linux subsystem is set up, perform install as for Linux. -```bash +```shell $ sudo apt-get update $ sudo apt-get install python3-pip python3.7-dev python3.7-venv python-wheel-common $ sudo apt-get install autoconf libssl-dev libxml2-dev libxslt1-dev libjpeg-dev libffi-dev libudev-dev zlib1g-dev @@ -50,7 +50,7 @@ Hint: Git is included in Linux subsytem. When invoking your installation (see below), make sure to specify a folder for configuration which is accessible from Windows. -```bash +```shell $ mkdir -p ../config $ hass -c ../config ``` @@ -59,13 +59,13 @@ $ hass -c ../config Install [Homebrew](https://brew.sh/), then use that to install Python 3: -```bash +```shell $ brew install python3 autoconf ``` Then install ffmpeg: -```bash +```shell $ brew install ffmpeg ``` @@ -105,7 +105,7 @@ Once forked, setup your local copy of the source using the commands: _Windows users should be sure to clone to a path that inside the WSL (ex: ~/)._ -```bash +```shell $ git clone https://github.com/YOUR_GIT_USERNAME/home-assistant.git $ cd home-assistant $ git remote add upstream https://github.com/home-assistant/home-assistant.git @@ -115,20 +115,20 @@ $ git remote add upstream https://github.com/home-assistant/home-assistant.git To isolate your environment from the rest of the system, set up a [`venv`](https://docs.python.org/3/library/venv.html). Within the `home-assistant` directory, create and activate your virtual environment. -```bash +```shell $ python3.7 -m venv venv $ source venv/bin/activate ``` Install the requirements with a provided script named `setup`. -```bash +```shell $ script/setup ``` Invoke your installation, adjusting the [configuration](https://www.home-assistant.io/docs/configuration/) if required. -```bash +```shell $ hass ``` diff --git a/docs/development_guidelines.md b/docs/development_guidelines.md index 7c3d2af4..35175c23 100644 --- a/docs/development_guidelines.md +++ b/docs/development_guidelines.md @@ -34,7 +34,7 @@ There is no need to add the platform or component name to the log messages. This _LOGGER.error("No route to device: %s", self._resource) ``` -```bash +```log 2017-05-01 14:28:07 ERROR [homeassistant.components.sensor.arest] No route to device: 192.168.0.18 ``` @@ -45,7 +45,7 @@ Also note that `_LOGGER.info` is reserved for the core, use `_LOGGER.debug` for Instead of order the imports manually, use [`isort`](https://github.com/timothycrosley/isort). -```bash +```shell $ pip3 install isort $ isort homeassistant/components/sensor/fixer.py ``` @@ -58,8 +58,8 @@ Prefer [f-strings](https://docs.python.org/3/reference/lexical_analysis.html#f-s # New f"{some_value} {some_other_value}" # Old, wrong -"{} {}".format('New', 'style') -"%s %s" % ('Old', 'style') +"{} {}".format("New", "style") +"%s %s" % ("Old", "style") ``` One exception is for logging which uses the percentage formatting. This is to avoid formatting the log message when it is suppressed. diff --git a/docs/development_testing.md b/docs/development_testing.md index 9dfd4cb7..5e64f58e 100644 --- a/docs/development_testing.md +++ b/docs/development_testing.md @@ -9,7 +9,7 @@ As it states in the [Style guidelines section](development_guidelines.md) all co Local testing is done using [Tox](https://tox.readthedocs.io), which has been installed as part of running `script/setup` in the [virtual environment](development_environment.md). To start the tests, activate the virtual environment and simply run the command: -```bash +```shell $ tox ``` @@ -34,7 +34,7 @@ If you are working on tests for an integeration and you need the dependencies av You can pass arguments via `tox` to `py.test` to be able to run single test suites or test files. Replace `py38` with the Python version that you use. -```bash +```shell # Stop after the first test fails $ tox -e py38 -- tests/test_core.py -x # Run test with specified name @@ -49,13 +49,13 @@ $ tox -e py38 -- tests/test_core.py --duration=10 Running `tox` will invoke the full test suite. Even if you specify which tox target to run, you still run all tests inside that target. That's not very convenient to quickly iterate on your code! To be able to run the specific test suites without `tox`, you'll need to install the test dependencies into your Python environment: -```bash +```shell $ pip3 install -r requirements_test_all.txt -c homeassistant/package_constraints.txt ``` Now that you have all test dependencies installed, you can run tests on individual files: -```bash +```shell $ flake8 homeassistant/core.py $ pylint homeassistant/core.py $ pydocstyle homeassistant/core.py @@ -64,7 +64,7 @@ $ py.test tests/test_core.py You can also run linting tests against all changed files, as reported by `git diff upstream/dev... --diff-filter=d --name-only`, using the `lint` script: -```bash +```shell $ script/lint ``` @@ -72,7 +72,7 @@ $ script/lint Save yourself the hassle of extra commits just to fix style errors by enabling the Flake8 git commit hook. Flake8 will check your code when you try to commit to the repository and block the commit if there are any style errors, which gives you a chance to fix them! -```bash +```shell $ pip3 install flake8 flake8-docstrings $ flake8 --install-hook=git ``` diff --git a/docs/development_validation.md b/docs/development_validation.md index eb33577a..d67d7684 100644 --- a/docs/development_validation.md +++ b/docs/development_validation.md @@ -32,11 +32,14 @@ This section contains snippets for the validation we use. It's common to set a default for a sensor if the user doesn't provide a name to use. ```python -DEFAULT_NAME = 'Sensor name' +DEFAULT_NAME = "Sensor name" -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - ... - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + # ... + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + } +) ``` #### Limit the values @@ -44,11 +47,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ You might want to limit the user's input to a couple of options. ```python -DEFAULT_METHOD = 'GET' +DEFAULT_METHOD = "GET" -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - ... - vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(['POST', 'GET']), +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + # ... + vol.Optional(CONF_METHOD, default=DEFAULT_METHOD): vol.In(["POST", "GET"]), + } +) ``` #### Port @@ -58,9 +64,12 @@ All port numbers are from a range of 1 to 65535. ```python DEFAULT_PORT = 993 -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - ... - vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + # ... + vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, + } +) ``` #### Lists @@ -69,12 +78,16 @@ If a sensor has a pre-defined list of available options, test to make sure the c ```python SENSOR_TYPES = { - 'article_cache': ('Article Cache', 'MB'), - 'average_download_rate': ('Average Speed', 'MB/s'), + "article_cache": ("Article Cache", "MB"), + "average_download_rate": ("Average Speed", "MB/s"), } -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ - ... - vol.Optional(CONF_MONITORED_VARIABLES, default=[]): - vol.All(cv.ensure_list, [vol.In(SENSOR_TYPES)]), +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( + { + # ... + vol.Optional(CONF_MONITORED_VARIABLES, default=[]): vol.All( + cv.ensure_list, [vol.In(SENSOR_TYPES)] + ), + } +) ``` diff --git a/docs/device_registry_index.md b/docs/device_registry_index.md index 3ee06835..b3ecdc0d 100644 --- a/docs/device_registry_index.md +++ b/docs/device_registry_index.md @@ -44,21 +44,19 @@ Each entity is able to define a device via the `device_info` property. This prop ```python # Inside a platform class HueLight(LightEntity): - @property def device_info(self): return { - 'identifiers': { + "identifiers": { # Serial numbers are unique identifiers within a specific domain (hue.DOMAIN, self.unique_id) }, - 'name': self.name, - 'manufacturer': self.light.manufacturername, - 'model': self.light.productname, - 'sw_version': self.light.swversion, - 'via_device': (hue.DOMAIN, self.api.bridgeid), + "name": self.name, + "manufacturer": self.light.manufacturername, + "model": self.light.productname, + "sw_version": self.light.swversion, + "via_device": (hue.DOMAIN, self.api.bridgeid), } - ``` Components are also able to register devices in the case that there are no entities representing them. An example is a hub that communicates with the lights. @@ -71,13 +69,9 @@ device_registry = await dr.async_get_registry(hass) device_registry.async_get_or_create( config_entry_id=entry.entry_id, - connections={ - (dr.CONNECTION_NETWORK_MAC, config.mac) - }, - identifiers={ - (DOMAIN, config.bridgeid) - }, - manufacturer='Signify', + connections={(dr.CONNECTION_NETWORK_MAC, config.mac)}, + identifiers={(DOMAIN, config.bridgeid)}, + manufacturer="Signify", name=config.name, model=config.modelid, sw_version=config.swversion, diff --git a/docs/documentation_index.md b/docs/documentation_index.md index 39835fff..08822a1e 100644 --- a/docs/documentation_index.md +++ b/docs/documentation_index.md @@ -33,7 +33,7 @@ Then you can work on the documentation: The site generated by `bundle exec rake` is only available locally. If you are developing on a headless machine, use port forwarding: -```bash +```shell $ ssh -L 4000:localhost:4000 user_on_headless_machine@ip_of_headless_machine ``` @@ -41,12 +41,12 @@ $ ssh -L 4000:localhost:4000 user_on_headless_machine@ip_of_headless_machine Every release we post long changelogs to the website. This slows down generation of the website a bit. We've include some tools to temporarily exclude integrations and blog posts that you're not working on out of the way. -```bash +```shell bundle exec rake isolate[filename-of-blogpost-or-integration] ``` When you're done working on the site, run the following command to move the pages back again: -```bash +```shell bundle exec rake integrate ``` diff --git a/docs/entity_cover.md b/docs/entity_cover.md index 0fea635a..483aa8a8 100644 --- a/docs/entity_cover.md +++ b/docs/entity_cover.md @@ -108,7 +108,6 @@ class MyCover(CoverDevice): async def async_set_cover_position(self, **kwargs): """Move the cover to a specific position.""" - ``` ### Stop cover diff --git a/docs/entity_fan.md b/docs/entity_fan.md index ed4d8354..8eab84ad 100644 --- a/docs/entity_fan.md +++ b/docs/entity_fan.md @@ -54,10 +54,10 @@ Only implement this method if the flag `SUPPORT_SET_SPEED` is set. class FanEntity(ToggleEntity): # Implement one of these methods. - def set_speed(self, speed: str) -> None: + def set_speed(self, speed: str) -> None: """Set the speed of the fan.""" - async def async_set_speed(self, speed: str): + async def async_set_speed(self, speed: str): """Set the speed of the fan.""" ``` diff --git a/docs/entity_index.md b/docs/entity_index.md index c008140a..3916cf7a 100644 --- a/docs/entity_index.md +++ b/docs/entity_index.md @@ -10,15 +10,15 @@ Below is an example switch entity that keeps track of their state in memory. ```python from homeassistant.components.switch import SwitchDevice -class MySwitch(SwitchDevice): +class MySwitch(SwitchDevice): def __init__(self): self._is_on = False @property def name(self): """Name of the device.""" - return 'My Switch' + return "My Switch" @property def is_on(self): diff --git a/docs/entity_light.md b/docs/entity_light.md index ba9c3d11..05ff8119 100644 --- a/docs/entity_light.md +++ b/docs/entity_light.md @@ -39,23 +39,20 @@ A light entity is a device that controls the brightness, RGB value,color tempera ```python class MyLightDevice(LightDevice): - def turn_on(self, **kwargs): - """Turn the device on.""" - - async def async_turn_on(self, **kwargs): - """Turn device on.""" + def turn_on(self, **kwargs): + """Turn the device on.""" + async def async_turn_on(self, **kwargs): + """Turn device on.""" ``` # Turn Off Light Device ```python class MyLightDevice(LightDevice): + def turn_off(self, **kwargs): + """Turn the device off.""" - def turn_off(self, **kwargs): - """Turn the device off.""" - - async def async_turn_off(self, **kwargs): - """Turn device off.""" - + async def async_turn_off(self, **kwargs): + """Turn device off.""" ``` diff --git a/docs/entity_switch.md b/docs/entity_switch.md index 179b005e..66a8c7b9 100644 --- a/docs/entity_switch.md +++ b/docs/entity_switch.md @@ -29,7 +29,6 @@ class MySwitch(SwitchDevice): async def async_turn_on(self, **kwargs): """Turn the entity on.""" - ``` ### Turn Off diff --git a/docs/external_api_rest.md b/docs/external_api_rest.md index 5677d266..7e1640d2 100644 --- a/docs/external_api_rest.md +++ b/docs/external_api_rest.md @@ -15,7 +15,7 @@ All API calls have to be accompanied by the header `Authorization: Bearer ABCDEF There are multiple ways to consume the Home Assistant Rest API. One is with `curl`: -```bash +```shell $ curl -X GET \ -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ @@ -27,10 +27,10 @@ Another option is to use Python and the [Requests](http://docs.python-requests.o ```python from requests import get -url = 'http://localhost:8123/ENDPOINT' +url = "http://localhost:8123/ENDPOINT" headers = { - 'Authorization': 'Bearer ABCDEFGH', - 'content-type': 'application/json', + "Authorization": "Bearer ABCDEFGH", + "content-type": "application/json", } response = get(url, headers=headers) @@ -71,7 +71,7 @@ Returns a message if the API is up and running. Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" http://localhost:8123/api/ ``` @@ -123,7 +123,7 @@ Returns the current configuration as JSON. Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" http://localhost:8123/api/config ``` @@ -143,7 +143,7 @@ Returns basic information about the Home Assistant instance as JSON. Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" http://localhost:8123/api/discovery_info ``` @@ -167,7 +167,7 @@ Returns an array of event objects. Each event object contains event name and lis Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" http://localhost:8123/api/events ``` @@ -196,7 +196,7 @@ Returns an array of service objects. Each object contains the domain and which s Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" http://localhost:8123/api/services ``` @@ -241,19 +241,19 @@ You can pass the following optional GET parameters: Sample `curl` commands: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ http://localhost:8123/api/history/period/2016-12-29T00:00:00+02:00 ``` -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ http://localhost:8123/api/history/period/2016-12-29T00:00:00+02:00?filter_entity_id=sensor.temperature ``` -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ http://localhost:8123/api/history/period/2016-12-29T00:00:00+02:00?end_time=2016-12-31T00%3A00%3A00%2B02%3A00 @@ -282,7 +282,7 @@ Returns an array of state objects. Each state has the following attributes: enti Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" http://localhost:8123/api/states ``` @@ -309,7 +309,7 @@ Returns a state object for specified entity_id. Returns 404 if not found. Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ http://localhost:8123/api/states/sensor.kitchen_temperature @@ -327,7 +327,7 @@ Retrieve all errors logged during the current session of Home Assistant as a pla Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ http://localhost:8123/api/error_log @@ -339,7 +339,7 @@ Returns the data (image) from the specified camera entity_id. Sample `curl` command: -```bash +```shell $ curl -X GET -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ http://localhost:8123/api/camera_proxy/camera.my_sample_camera?time=1462653861261 -o image.jpg @@ -378,7 +378,7 @@ The return code is 200 if the entity existed, 201 if the state of a new entity w Sample `curl` command: -```bash +```shell $ curl -X POST -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ -d '{"state": "25", "attributes": {"unit_of_measurement": "°C"}}' \ @@ -440,7 +440,7 @@ Sample `curl` commands: Turn the light on: -```bash +```shell $ curl -X POST -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ -d '{"entity_id": "switch.christmas_lights"}' \ @@ -449,7 +449,7 @@ $ curl -X POST -H "Authorization: Bearer ABCDEFGH" \ Send a MQTT message: -```bash +```shell $ curl -X POST \ -H "Content-Type: application/json" \ -H "x-ha-access:YOUR_PASSWORD" \ @@ -477,7 +477,7 @@ Paulus is at work! Sample `curl` command: -```bash +```shell $ curl -X POST -H "Authorization: Bearer ABCDEFGH" \ -H "Content-Type: application/json" \ -d '{"template": "It is {{ now() }}!"}' http://localhost:8123/api/template diff --git a/docs/external_api_server_sent_events.md b/docs/external_api_server_sent_events.md index 4e02f86e..b820dc8a 100644 --- a/docs/external_api_server_sent_events.md +++ b/docs/external_api_server_sent_events.md @@ -10,7 +10,7 @@ A requirement on the client-side is existing support for the [EventSource](https There are various ways to access the stream. If you have not set an `api_password` in the [`http`](https://www.home-assistant.io/components/http/) section of your `configuration.yaml` file then you use your modern browser to read the messages. A command-line option is `curl`: -```bash +```shell $ curl -X GET -H 'Authorization: Bearer ABCDEFGH' \ -H "Content-Type: application/json" http://localhost:8123/api/stream ``` @@ -41,7 +41,7 @@ Visit [http://localhost:8123/local/sse.html](http://localhost:8123/local/sse.htm A simple way to consume server-sent events is to use a command-line http client like [httpie](https://httpie.org/). Installation info is on the site (if you use Homebrew, it's `brew install httpie`). Once installed, run this snippet from your terminal: -```bash +```shell $ http --stream http://localhost:8123/api/stream 'Authorization:Bearer ABCDEFGH' content-type:application/json ``` @@ -55,7 +55,7 @@ The [home-assistant-sse](https://github.com/fabaff/home-assistant-sse) repositor If you want to test the server-sent events without creating a website, the Python module [`sseclient` ](https://pypi.python.org/pypi/sseclient/) can help. To install (assuming Python and pip3 are already installed): -```bash +```shell $ pip3 install sseclient ``` @@ -64,8 +64,8 @@ A simple script to consume SSE in Python looks like this: ```python from sseclient import SSEClient -auth = {'Authorization': 'Bearer ABCDEFGH'} -messages = SSEClient('http://localhost:8123/api/stream', headers=auth) +auth = {"Authorization": "Bearer ABCDEFGH"} +messages = SSEClient("http://localhost:8123/api/stream", headers=auth) for msg in messages: print(msg) diff --git a/docs/frontend_add_websocket_api.md b/docs/frontend_add_websocket_api.md index 6cd75567..9c4771ed 100644 --- a/docs/frontend_add_websocket_api.md +++ b/docs/frontend_add_websocket_api.md @@ -14,7 +14,7 @@ Message types are made up the domain and the message type, separated by a forwar ```python # The type of the message -WS_TYPE_MEDIA_PLAYER_THUMBNAIL = 'media_player/thumbnail' +WS_TYPE_MEDIA_PLAYER_THUMBNAIL = "media_player/thumbnail" ``` ### Message Schema @@ -29,12 +29,13 @@ import homeassistant.helpers.config_validation as cv # The schema for the message -SCHEMA_WEBSOCKET_GET_THUMBNAIL = \ - websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({ - 'type': WS_TYPE_MEDIA_PLAYER_THUMBNAIL, +SCHEMA_WEBSOCKET_GET_THUMBNAIL = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend( + { + "type": WS_TYPE_MEDIA_PLAYER_THUMBNAIL, # The entity that we want to retrieve the thumbnail for. - 'entity_id': cv.entity_id - }) + "entity_id": cv.entity_id, + } +) ``` ### Defining a handler @@ -52,9 +53,11 @@ def websocket_handle_thumbnail(hass, connection, msg): # We know the answer without having to fetch any information, # so we send it directly. - connection.to_write.put_nowait(websocket_api.result_message(msg['id'], { - 'thumbnail': 'http://via.placeholder.com/350x150' - })) + connection.to_write.put_nowait( + websocket_api.result_message( + msg["id"], {"thumbnail": "http://via.placeholder.com/350x150"} + ) + ) ``` #### Sending a delayed response @@ -66,12 +69,15 @@ If your command needs to interact with the network, a device or needs to compute def websocket_handle_thumbnail(hass, connection, msg): """Handle get media player cover command.""" # Retrieve media player using passed in entity id. - player = hass.data[DOMAIN].get_entity(msg['entity_id']) + player = hass.data[DOMAIN].get_entity(msg["entity_id"]) # If the player does not exist, send an error message. if player is None: - connection.to_write.put_nowait(websocket_api.error_message( - msg['id'], 'entity_not_found', 'Entity not found')) + connection.to_write.put_nowait( + websocket_api.error_message( + msg["id"], "entity_not_found", "Entity not found" + ) + ) return # Define a function to be enqueued. @@ -81,16 +87,22 @@ def websocket_handle_thumbnail(hass, connection, msg): # No media player thumbnail available if data is None: - connection.send_message_outside(websocket_api.error_message( - msg['id'], 'thumbnail_fetch_failed', - 'Failed to fetch thumbnail')) + connection.send_message_outside( + websocket_api.error_message( + msg["id"], "thumbnail_fetch_failed", "Failed to fetch thumbnail" + ) + ) return - connection.send_message_outside(websocket_api.result_message( - msg['id'], { - 'content_type': content_type, - 'content': base64.b64encode(data).decode('utf-8') - })) + connection.send_message_outside( + websocket_api.result_message( + msg["id"], + { + "content_type": content_type, + "content": base64.b64encode(data).decode("utf-8"), + }, + ) + ) # Player exist. Queue up a job to send the thumbnail. hass.async_add_job(send_image()) @@ -104,8 +116,10 @@ With all pieces defined, it's time to register the command. This is done inside async def async_setup(hass, config): """Setup of your component.""" hass.components.websocket_api.async_register_command( - WS_TYPE_MEDIA_PLAYER_THUMBNAIL, websocket_handle_thumbnail, - SCHEMA_WEBSOCKET_GET_THUMBNAIL) + WS_TYPE_MEDIA_PLAYER_THUMBNAIL, + websocket_handle_thumbnail, + SCHEMA_WEBSOCKET_GET_THUMBNAIL, + ) ``` ## Calling the command from the frontend (JavaScript) diff --git a/docs/frontend_development.md b/docs/frontend_development.md index 944baeb5..fed35449 100644 --- a/docs/frontend_development.md +++ b/docs/frontend_development.md @@ -13,7 +13,7 @@ The Home Assistant frontend is built using web components. For more background a First step is to fork the [home-assistant-polymer repository][hass-polymer] and add the upstream remote. You can place the forked repository anywhere on your system. -```bash +```shell $ git clone git@github.com:YOUR_GIT_USERNAME/home-assistant-polymer.git $ cd home-assistant-polymer $ git remote add upstream https://github.com/home-assistant/home-assistant-polymer.git @@ -35,7 +35,7 @@ frontend: Node.js is required to build the frontend. The preferred method of installing node.js is with [nvm](https://github.com/creationix/nvm). Install nvm using the instructions in the [README](https://github.com/creationix/nvm#install-script), and install the correct node.js by running the following command: -```bash +```shell $ nvm install ``` @@ -43,7 +43,7 @@ $ nvm install Next, development dependencies need to be installed to bootstrap the frontend development environment. First activate the right Node version and then download all the dependencies: -```bash +```shell $ nvm use $ script/bootstrap ``` @@ -52,7 +52,7 @@ $ script/bootstrap During development, you will need to run the development script to maintain a development build of the frontend that auto updates when you change any of the source files. To run this server, run: -```bash +```shell $ nvm use $ script/develop ``` @@ -77,7 +77,7 @@ Make sure you have cache disabled and correct settings to avoid stale content: If you're planning on issuing a PR back to the Home Assistant codebase you need to fork the polymer project and add your fork as a remote to the Home Assistant Polymer repo. -```bash +```shell $ git remote add fork ``` @@ -95,7 +95,7 @@ If you're making changes to the way the frontend is packaged, it might be necess To test it out inside Home Assistant, run the following command from the main Home Assistant repository: -```bash +```shell $ pip3 install -e /path/to/home-assistant-polymer/ $ hass --skip-pip ``` diff --git a/docs/hassio_addon_config.md b/docs/hassio_addon_config.md index 629a0036..994317f3 100644 --- a/docs/hassio_addon_config.md +++ b/docs/hassio_addon_config.md @@ -28,7 +28,7 @@ When developing your script: - `/data` is a volume for persistent storage. - `/data/options.json` contains the user configuration. You can use bashio or `jq` inside your shell script to parse this data. -```bash +```shell CONFIG_PATH=/data/options.json TARGET="$(jq --raw-output '.target' $CONFIG_PATH)" @@ -46,7 +46,7 @@ then there will be a variable `TARGET` containing `beer` in the environment of y All add-ons are based on latest Alpine Linux. Hass.io will automatically substitute the right base image based on the machine architecture. Add `tzdata` if you need run in a different timezone. `tzdata` Is is already added to our base images. -``` +```dockerfile ARG BUILD_FROM FROM $BUILD_FROM diff --git a/docs/hassio_addon_publishing.md b/docs/hassio_addon_publishing.md index 5403a2ca..99fd02c7 100644 --- a/docs/hassio_addon_publishing.md +++ b/docs/hassio_addon_publishing.md @@ -38,7 +38,7 @@ You need a Docker Hub account to make your own add-ons. You can build your Docke For a git repository: -```bash +```shell $ docker run --rm --privileged -v \ ~/.docker:/root/.docker homeassistant/amd64-builder \ --all -t addon-folder -r https://github.com/xy/addons \ @@ -47,7 +47,7 @@ $ docker run --rm --privileged -v \ For a local repository: -```bash +```shell $ docker run --rm --privileged -v \ ~/.docker:/root/.docker -v /my_addon:/data homeassistant/amd64-builder \ --all -t /data diff --git a/docs/hassio_addon_tutorial.md b/docs/hassio_addon_tutorial.md index 8db7a28b..eae4f2f0 100644 --- a/docs/hassio_addon_tutorial.md +++ b/docs/hassio_addon_tutorial.md @@ -26,7 +26,7 @@ Once you have located your add-on directory, it's time to get started! - Inside that directory create three files. `Dockerfile`: -``` +```dockerfile ARG BUILD_FROM FROM $BUILD_FROM @@ -55,7 +55,7 @@ CMD [ "/run.sh" ] ``` `run.sh`: -```bash +```shell echo Hello world! ``` Make sure your editor is using UNIX-like line breaks (LF), not Dos/Windows (CRLF). @@ -102,7 +102,7 @@ To do this, we will need to update our files as follows: Add to your `Dockerfile` before `RUN`: -``` +```dockerfile # Install requirements for add-on RUN apk add --no-cache python3 @@ -132,7 +132,7 @@ Add "ports" to `config.json`. This will make TCP on port 8000 inside the contain Update `run.sh` to start the Python 3 server: -``` +```shell python3 -m http.server 8000 ``` diff --git a/docs/hassio_debugging.md b/docs/hassio_debugging.md index 2ad6aac3..ac77d478 100644 --- a/docs/hassio_debugging.md +++ b/docs/hassio_debugging.md @@ -47,7 +47,7 @@ Use a USB drive formatted with FAT, ext4, or NTFS and name it CONFIG (case sensi You should then be able to SSH into your Hass.io device. On Mac/Linux, use: -``` +```shell ssh root@hassio.local -p 22222 ``` @@ -59,7 +59,7 @@ You will initially be logged in to Hass.io CLI for HassOS where you can perform ## Checking the logs -```bash +```shell # Logs from the supervisor service on the Host OS journalctl -f -u hassos-supervisor.service @@ -72,7 +72,7 @@ docker logs homeassistant ## Accessing the container bash -```bash +```shell docker exec -it homeassistant /bin/bash ``` diff --git a/docs/hassio_hass.md b/docs/hassio_hass.md index 807e8dde..e0f349a2 100644 --- a/docs/hassio_hass.md +++ b/docs/hassio_hass.md @@ -15,7 +15,7 @@ To develop for the frontend, we're going to need API access to the supervisor. - Install the Add-on "Remote API proxy" For some API commands you need explicit the Home Assistant API token, but 99% of the functionality work with `Remote API proxy`. This token change sometimes but you can read the current legal token on host system with: -```sh +```shell $ docker inspect homeassistant | grep HASSIO_TOKEN ``` @@ -25,7 +25,7 @@ $ docker inspect homeassistant | grep HASSIO_TOKEN First, make sure Home Assistant will load the Hass.io component by adding `hassio:` to your `configuration.yaml` file. Next, we will need to tell the local Home Assistant instance how to connect to the remote Hass.io instance. We do this by setting the `HASSIO` and `HASSIO_TOKEN` environment variables when starting Home Assistant. Note that the `HASSIO` value is not the same as the one that we saw above and the `HASSIO_TOKEN` is available inside log output of "Remote API Add-on" (This changes every restart of the add-on!). -```bash +```shell HASSIO=:80 HASSIO_TOKEN= hass ``` @@ -47,7 +47,7 @@ hassio: To build a local version of the Hass.io panel, go to the frontend repository and run: -```bash +```shell cd hassio script/develop ``` diff --git a/docs/intent_conversation.md b/docs/intent_conversation.md index 797c8f1d..14c44222 100644 --- a/docs/intent_conversation.md +++ b/docs/intent_conversation.md @@ -10,10 +10,10 @@ Example code: ```python async def async_setup(hass, config): - hass.components.conversation.async_register('MyCoolIntent', [ - 'I think that {object} is [very] cool', - 'Nothing is cooler than {object}' - ]) + hass.components.conversation.async_register( + "MyCoolIntent", + ["I think that {object} is [very] cool", "Nothing is cooler than {object}"], + ) ``` If a sentence like "I think that beer is cool" comes in, the conversation component will generate an intent of type `MyCoolIntent` and with 1 slot, named `object` and value `beer`. diff --git a/docs/intent_firing.md b/docs/intent_firing.md index f6f644c9..d397b798 100644 --- a/docs/intent_firing.md +++ b/docs/intent_firing.md @@ -9,24 +9,22 @@ Example code to handle an intent in Home Assistant. ```python from homeassistant.helpers import intent -intent_type = 'TurnLightOn' -slots = { - 'entity': { 'value': 'Kitchen' } -} +intent_type = "TurnLightOn" +slots = {"entity": {"value": "Kitchen"}} try: intent_response = yield from intent.async_handle( - hass, 'example_component', intent_type, slots + hass, "example_component", intent_type, slots ) except intent.UnknownIntent as err: - _LOGGER.warning('Received unknown intent %s', intent_type) + _LOGGER.warning("Received unknown intent %s", intent_type) except intent.InvalidSlotInfo as err: - _LOGGER.error('Received invalid slot data: %s', err) + _LOGGER.error("Received invalid slot data: %s", err) except intent.IntentError: - _LOGGER.exception('Error handling request for %s', intent_type) + _LOGGER.exception("Error handling request for %s", intent_type) ``` The intent response is an instance of `homeassistant.helpers.intent.IntentResponse`. diff --git a/docs/intent_handling.md b/docs/intent_handling.md index 0ddefbc6..6c3a9b6a 100644 --- a/docs/intent_handling.md +++ b/docs/intent_handling.md @@ -10,7 +10,8 @@ A component has to register an intent handler for each type that it wants to han import asyncio from homeassistant.helpers import intent -DATA_KEY = 'example_key' +DATA_KEY = "example_key" + @asyncio.coroutine def async_setup(hass, config): @@ -22,7 +23,7 @@ class CountInvocationIntent(intent.IntentHandler): """Handle CountInvocationIntent intents.""" # Type of intent to handle - intent_type = 'CountInvocationIntent' + intent_type = "CountInvocationIntent" # Optional. A validation schema for slots # slot_schema = { @@ -36,7 +37,7 @@ class CountInvocationIntent(intent.IntentHandler): response = intent_obj.create_response() response.async_set_speech( - "This intent has been invoked {} times".format( - intent_obj.hass.data[DATA_KEY])) + f"This intent has been invoked {intent_obj.hass.data[DATA_KEY]} times" + ) return response ``` diff --git a/docs/internationalization_backend_localization.md b/docs/internationalization_backend_localization.md index e7b1e072..0f0d49dd 100644 --- a/docs/internationalization_backend_localization.md +++ b/docs/internationalization_backend_localization.md @@ -7,7 +7,7 @@ Platform translation strings are stored as JSON in the [home-assistant](https:// In order to test changes to translation files, the translation strings must be compiled into Home Assistant’s translation directories by running the following script: -```bash +```shell $ script/translations_develop ``` diff --git a/docs/maintenance.md b/docs/maintenance.md index 0e03e247..14224026 100644 --- a/docs/maintenance.md +++ b/docs/maintenance.md @@ -10,14 +10,14 @@ This page documents a couple of points for maintaining the Home Assistant code. People are using various operating systems to develop components and platforms for Home Assistant. This could lead to different line endings on file. We prefer `LN`. Especially Microsoft Windows tools tend to use `CRLF`. -```bash +```shell $ find homeassistant -name "*.py" -exec file {} \; | grep BOM $ find homeassistant -name "*.py" -exec file {} \; | grep CRLF ``` To fix the line separator, use `dos2unix` or `sed`. -```bash +```shell $ dos2unix homeassistant/components/notify/kodi.py ``` @@ -31,7 +31,7 @@ A lot of components and platforms depends on third-party Python modules. The dep If you update the requirements of a component/platform by updating `manifest.json`, run the provided script to update the `requirements_*.txt` file(s). -```bash +```shell $ script/gen_requirements_all.py ``` diff --git a/docs/reproduce_state_index.md b/docs/reproduce_state_index.md index 0f63efd4..fe49b553 100644 --- a/docs/reproduce_state_index.md +++ b/docs/reproduce_state_index.md @@ -18,6 +18,7 @@ from typing import Iterable, Optional from homeassistant.core import Context, State from homeassistant.helpers.typing import HomeAssistantType + async def async_reproduce_states( hass: HomeAssistantType, states: Iterable[State], context: Optional[Context] = None ) -> None: