Mark integrations as single_config_entry in manifest [k-r] (#128191)

* mark integrations as single_config_entry in manifest

* fix owntracks test
This commit is contained in:
Michael 2024-10-12 09:03:17 +02:00 committed by GitHub
parent c50d0646ab
commit 8236a9529f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 48 additions and 86 deletions

View File

@ -37,9 +37,6 @@ class KitchenSinkConfigFlow(ConfigFlow, domain=DOMAIN):
async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult: async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
"""Set the config entry up from yaml.""" """Set the config entry up from yaml."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
return self.async_create_entry(title="Kitchen Sink", data=import_data) return self.async_create_entry(title="Kitchen Sink", data=import_data)
async def async_step_reauth( async def async_step_reauth(

View File

@ -5,5 +5,6 @@
"codeowners": ["@home-assistant/core"], "codeowners": ["@home-assistant/core"],
"documentation": "https://www.home-assistant.io/integrations/kitchen_sink", "documentation": "https://www.home-assistant.io/integrations/kitchen_sink",
"iot_class": "calculated", "iot_class": "calculated",
"quality_scale": "internal" "quality_scale": "internal",
"single_config_entry": true
} }

View File

@ -18,10 +18,6 @@ class LaunchLibraryFlowHandler(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Handle a flow initialized by the user.""" """Handle a flow initialized by the user."""
# Check if already configured
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
if user_input is not None: if user_input is not None:
return self.async_create_entry(title="Launch Library", data=user_input) return self.async_create_entry(title="Launch Library", data=user_input)

View File

@ -6,5 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/launch_library", "documentation": "https://www.home-assistant.io/integrations/launch_library",
"integration_type": "service", "integration_type": "service",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"requirements": ["pylaunches==2.0.0"] "requirements": ["pylaunches==2.0.0"],
"single_config_entry": true
} }

View File

@ -4,9 +4,6 @@
"user": { "user": {
"description": "Do you want to configure the Launch Library?" "description": "Do you want to configure the Launch Library?"
} }
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
} }
}, },
"entity": { "entity": {

View File

@ -57,9 +57,6 @@ class LiteJetConfigFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Create a LiteJet config entry based upon user input.""" """Create a LiteJet config entry based upon user input."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
errors = {} errors = {}
if user_input is not None: if user_input is not None:
port = user_input[CONF_PORT] port = user_input[CONF_PORT]

View File

@ -8,5 +8,6 @@
"iot_class": "local_push", "iot_class": "local_push",
"loggers": ["pylitejet"], "loggers": ["pylitejet"],
"quality_scale": "platinum", "quality_scale": "platinum",
"requirements": ["pylitejet==0.6.3"] "requirements": ["pylitejet==0.6.3"],
"single_config_entry": true
} }

View File

@ -9,9 +9,6 @@
} }
} }
}, },
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
},
"error": { "error": {
"open_failed": "Cannot open the specified serial port." "open_failed": "Cannot open the specified serial port."
} }

View File

@ -16,9 +16,6 @@ class SimpleConfigFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Handle the initial step.""" """Handle the initial step."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
if user_input is None: if user_input is None:
return self.async_show_form(step_id="user") return self.async_show_form(step_id="user")

View File

@ -5,5 +5,6 @@
"config_flow": true, "config_flow": true,
"dependencies": ["network"], "dependencies": ["network"],
"documentation": "https://www.home-assistant.io/integrations/local_ip", "documentation": "https://www.home-assistant.io/integrations/local_ip",
"iot_class": "local_polling" "iot_class": "local_polling",
"single_config_entry": true
} }

View File

@ -6,9 +6,6 @@
"title": "[%key:component::local_ip::title%]", "title": "[%key:component::local_ip::title%]",
"description": "[%key:common::config_flow::description::confirm_setup%]" "description": "[%key:common::config_flow::description::confirm_setup%]"
} }
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
} }
} }
} }

View File

@ -26,11 +26,6 @@ class LutronConfigFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""First step in the config flow.""" """First step in the config flow."""
# Check if a configuration entry already exists
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
errors = {} errors = {}
if user_input is not None: if user_input is not None:

View File

@ -6,5 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/lutron", "documentation": "https://www.home-assistant.io/integrations/lutron",
"iot_class": "local_polling", "iot_class": "local_polling",
"loggers": ["pylutron"], "loggers": ["pylutron"],
"requirements": ["pylutron==0.2.15"] "requirements": ["pylutron==0.2.15"],
"single_config_entry": true
} }

View File

@ -17,9 +17,6 @@
"description": "Please enter the main repeater login information", "description": "Please enter the main repeater login information",
"title": "Main repeater setup" "title": "Main repeater setup"
} }
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
} }
}, },
"entity": { "entity": {

View File

@ -50,9 +50,6 @@ class NZBGetConfigFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Handle a flow initiated by the user.""" """Handle a flow initiated by the user."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
errors = {} errors = {}
if user_input is not None: if user_input is not None:

View File

@ -6,5 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/nzbget", "documentation": "https://www.home-assistant.io/integrations/nzbget",
"iot_class": "local_polling", "iot_class": "local_polling",
"loggers": ["pynzbgetapi"], "loggers": ["pynzbgetapi"],
"requirements": ["pynzbgetapi==0.2.0"] "requirements": ["pynzbgetapi==0.2.0"],
"single_config_entry": true
} }

View File

@ -19,7 +19,6 @@
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
}, },
"abort": { "abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
"unknown": "[%key:common::config_flow::error::unknown%]" "unknown": "[%key:common::config_flow::error::unknown%]"
} }
}, },

View File

@ -42,12 +42,6 @@ class OmniLogicConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle the initial step.""" """Handle the initial step."""
errors: dict[str, str] = {} errors: dict[str, str] = {}
config_entry = self._async_current_entries()
if config_entry:
return self.async_abort(reason="single_instance_allowed")
errors = {}
if user_input is not None: if user_input is not None:
username = user_input[CONF_USERNAME] username = user_input[CONF_USERNAME]
password = user_input[CONF_PASSWORD] password = user_input[CONF_PASSWORD]

View File

@ -6,5 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/omnilogic", "documentation": "https://www.home-assistant.io/integrations/omnilogic",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["config", "omnilogic"], "loggers": ["config", "omnilogic"],
"requirements": ["omnilogic==0.4.5"] "requirements": ["omnilogic==0.4.5"],
"single_config_entry": true
} }

View File

@ -14,8 +14,7 @@
"unknown": "[%key:common::config_flow::error::unknown%]" "unknown": "[%key:common::config_flow::error::unknown%]"
}, },
"abort": { "abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]", "already_configured": "[%key:common::config_flow::abort::already_configured_account%]"
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
} }
}, },
"options": { "options": {

View File

@ -21,9 +21,6 @@ class OndiloIcoOAuth2FlowHandler(AbstractOAuth2FlowHandler, domain=DOMAIN):
"""Handle a flow initialized by the user.""" """Handle a flow initialized by the user."""
await self.async_set_unique_id(DOMAIN) await self.async_set_unique_id(DOMAIN)
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
self.async_register_implementation( self.async_register_implementation(
self.hass, self.hass,
OndiloOauth2Implementation(self.hass), OndiloOauth2Implementation(self.hass),

View File

@ -8,5 +8,6 @@
"integration_type": "hub", "integration_type": "hub",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["ondilo"], "loggers": ["ondilo"],
"requirements": ["ondilo==0.5.0"] "requirements": ["ondilo==0.5.0"],
"single_config_entry": true
} }

View File

@ -23,9 +23,6 @@ class OwnTracksFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Handle a user initiated set up flow to create OwnTracks webhook.""" """Handle a user initiated set up flow to create OwnTracks webhook."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
if user_input is None: if user_input is None:
return self.async_show_form(step_id="user") return self.async_show_form(step_id="user")

View File

@ -8,5 +8,6 @@
"documentation": "https://www.home-assistant.io/integrations/owntracks", "documentation": "https://www.home-assistant.io/integrations/owntracks",
"iot_class": "local_push", "iot_class": "local_push",
"loggers": ["nacl"], "loggers": ["nacl"],
"requirements": ["PyNaCl==1.5.0"] "requirements": ["PyNaCl==1.5.0"],
"single_config_entry": true
} }

View File

@ -7,8 +7,7 @@
} }
}, },
"abort": { "abort": {
"cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]", "cloud_not_connected": "[%key:common::config_flow::abort::cloud_not_connected%]"
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
}, },
"create_entry": { "create_entry": {
"default": "On Android, open [the OwnTracks app]({android_url}), go to Preferences > Connection. Change the following settings:\n - Mode: HTTP\n - Host: {webhook_url}\n - Identification:\n - Username: `'(Your name)'`\n - Device ID: `'(Your device name)'`\n\nOn iOS, open [the OwnTracks app]({ios_url}), tap (i) icon in top left > Settings. Change the following settings:\n - Mode: HTTP\n - URL: {webhook_url}\n - Turn on authentication\n - UserID: `'(Your name)'`\n\n{secret}\n\nSee [the documentation]({docs_url}) for more information." "default": "On Android, open [the OwnTracks app]({android_url}), go to Preferences > Connection. Change the following settings:\n - Mode: HTTP\n - Host: {webhook_url}\n - Identification:\n - Username: `'(Your name)'`\n - Device ID: `'(Your device name)'`\n\nOn iOS, open [the OwnTracks app]({ios_url}), tap (i) icon in top left > Settings. Change the following settings:\n - Mode: HTTP\n - URL: {webhook_url}\n - Turn on authentication\n - UserID: `'(Your name)'`\n\n{secret}\n\nSee [the documentation]({docs_url}) for more information."

View File

@ -16,9 +16,6 @@ class ProfilerConfigFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Handle the initial step.""" """Handle the initial step."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
if user_input is not None: if user_input is not None:
return self.async_create_entry(title=DEFAULT_NAME, data={}) return self.async_create_entry(title=DEFAULT_NAME, data={})

View File

@ -9,5 +9,6 @@
"pyprof2calltree==1.4.5", "pyprof2calltree==1.4.5",
"guppy3==3.1.4.post1", "guppy3==3.1.4.post1",
"objgraph==3.5.0" "objgraph==3.5.0"
] ],
"single_config_entry": true
} }

View File

@ -4,9 +4,6 @@
"user": { "user": {
"description": "[%key:common::config_flow::description::confirm_setup%]" "description": "[%key:common::config_flow::description::confirm_setup%]"
} }
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
} }
}, },
"services": { "services": {

View File

@ -18,9 +18,6 @@ class RadioBrowserConfigFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Handle the initial step.""" """Handle the initial step."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
if user_input is not None: if user_input is not None:
return self.async_create_entry(title="Radio Browser", data={}) return self.async_create_entry(title="Radio Browser", data={})

View File

@ -6,5 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/radio_browser", "documentation": "https://www.home-assistant.io/integrations/radio_browser",
"integration_type": "service", "integration_type": "service",
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"requirements": ["radios==0.3.1", "pycountry==23.12.11"] "requirements": ["radios==0.3.1", "pycountry==23.12.11"],
"single_config_entry": true
} }

View File

@ -4,9 +4,6 @@
"user": { "user": {
"description": "Do you want to add Radio Browser to Home Assistant?" "description": "Do you want to add Radio Browser to Home Assistant?"
} }
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
} }
} }
} }

View File

@ -3107,7 +3107,8 @@
"name": "Everything but the Kitchen Sink", "name": "Everything but the Kitchen Sink",
"integration_type": "hub", "integration_type": "hub",
"config_flow": false, "config_flow": false,
"iot_class": "calculated" "iot_class": "calculated",
"single_config_entry": true
}, },
"kiwi": { "kiwi": {
"name": "KIWI", "name": "KIWI",
@ -3221,7 +3222,8 @@
"name": "Launch Library", "name": "Launch Library",
"integration_type": "service", "integration_type": "service",
"config_flow": true, "config_flow": true,
"iot_class": "cloud_polling" "iot_class": "cloud_polling",
"single_config_entry": true
}, },
"laundrify": { "laundrify": {
"name": "laundrify", "name": "laundrify",
@ -3363,7 +3365,8 @@
"name": "LiteJet", "name": "LiteJet",
"integration_type": "hub", "integration_type": "hub",
"config_flow": true, "config_flow": true,
"iot_class": "local_push" "iot_class": "local_push",
"single_config_entry": true
}, },
"litterrobot": { "litterrobot": {
"name": "Litter-Robot", "name": "Litter-Robot",
@ -3397,7 +3400,8 @@
"local_ip": { "local_ip": {
"integration_type": "hub", "integration_type": "hub",
"config_flow": true, "config_flow": true,
"iot_class": "local_polling" "iot_class": "local_polling",
"single_config_entry": true
}, },
"local_todo": { "local_todo": {
"integration_type": "hub", "integration_type": "hub",
@ -4248,7 +4252,8 @@
"name": "NZBGet", "name": "NZBGet",
"integration_type": "hub", "integration_type": "hub",
"config_flow": true, "config_flow": true,
"iot_class": "local_polling" "iot_class": "local_polling",
"single_config_entry": true
}, },
"oasa_telematics": { "oasa_telematics": {
"name": "OASA Telematics", "name": "OASA Telematics",
@ -4296,7 +4301,8 @@
"name": "Hayward Omnilogic", "name": "Hayward Omnilogic",
"integration_type": "hub", "integration_type": "hub",
"config_flow": true, "config_flow": true,
"iot_class": "cloud_polling" "iot_class": "cloud_polling",
"single_config_entry": true
}, },
"oncue": { "oncue": {
"name": "Oncue by Kohler", "name": "Oncue by Kohler",
@ -4308,7 +4314,8 @@
"name": "Ondilo ICO", "name": "Ondilo ICO",
"integration_type": "hub", "integration_type": "hub",
"config_flow": true, "config_flow": true,
"iot_class": "cloud_polling" "iot_class": "cloud_polling",
"single_config_entry": true
}, },
"onewire": { "onewire": {
"name": "1-Wire", "name": "1-Wire",
@ -4516,7 +4523,8 @@
"name": "OwnTracks", "name": "OwnTracks",
"integration_type": "hub", "integration_type": "hub",
"config_flow": true, "config_flow": true,
"iot_class": "local_push" "iot_class": "local_push",
"single_config_entry": true
}, },
"p1_monitor": { "p1_monitor": {
"name": "P1 Monitor", "name": "P1 Monitor",
@ -4731,7 +4739,8 @@
"profiler": { "profiler": {
"name": "Profiler", "name": "Profiler",
"integration_type": "hub", "integration_type": "hub",
"config_flow": true "config_flow": true,
"single_config_entry": true
}, },
"progettihwsw": { "progettihwsw": {
"name": "ProgettiHWSW Automation", "name": "ProgettiHWSW Automation",
@ -4946,7 +4955,8 @@
"name": "Radio Browser", "name": "Radio Browser",
"integration_type": "service", "integration_type": "service",
"config_flow": true, "config_flow": true,
"iot_class": "cloud_polling" "iot_class": "cloud_polling",
"single_config_entry": true
}, },
"radiotherm": { "radiotherm": {
"name": "Radio Thermostat", "name": "Radio Thermostat",

View File

@ -94,13 +94,14 @@ async def test_import_setup(hass: HomeAssistant) -> None:
async def test_abort_if_already_setup(hass: HomeAssistant) -> None: async def test_abort_if_already_setup(hass: HomeAssistant) -> None:
"""Test that we can't add more than one instance.""" """Test that we can't add more than one instance."""
flow = await init_config_flow(hass)
MockConfigEntry(domain=DOMAIN, data={}).add_to_hass(hass) MockConfigEntry(domain=DOMAIN, data={}).add_to_hass(hass)
assert hass.config_entries.async_entries(DOMAIN) assert hass.config_entries.async_entries(DOMAIN)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
# Should fail, already setup (flow) # Should fail, already setup (flow)
result = await flow.async_step_user({})
assert result["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "single_instance_allowed" assert result["reason"] == "single_instance_allowed"