From 79efd00cdca72bb391fa438b488377b3e75bdafe Mon Sep 17 00:00:00 2001 From: NicolasNewman Date: Sun, 18 Aug 2024 00:39:15 +0000 Subject: [PATCH] updated reddit sensor to support users --- homeassistant/components/reddit/sensor.py | 91 +++++++++++++++-------- tests/components/reddit/test_sensor.py | 23 ++++++ 2 files changed, 81 insertions(+), 33 deletions(-) diff --git a/homeassistant/components/reddit/sensor.py b/homeassistant/components/reddit/sensor.py index 35962ac091b1cf..8eeeec74e449a1 100644 --- a/homeassistant/components/reddit/sensor.py +++ b/homeassistant/components/reddit/sensor.py @@ -4,6 +4,7 @@ from datetime import timedelta import logging +from typing import Any, Final import praw import voluptuous as vol @@ -29,15 +30,17 @@ CONF_SORT_BY = "sort_by" CONF_SUBREDDITS = "subreddits" - -ATTR_BODY = "body" -ATTR_COMMENTS_NUMBER = "comms_num" -ATTR_CREATED = "created" -ATTR_POSTS = "posts" -ATTR_SUBREDDIT = "subreddit" -ATTR_SCORE = "score" -ATTR_TITLE = "title" -ATTR_URL = "url" +CONF_REDDITORS = "redditors" + +ATTR_BODY: Final = "body" +ATTR_COMMENTS_NUMBER: Final = "comms_num" +ATTR_CREATED: Final = "created" +ATTR_POSTS: Final = "posts" +ATTR_SUBREDDIT: Final = "subreddit" +ATTR_SCORE: Final = "score" +ATTR_TITLE: Final = "title" +ATTR_URL: Final = "url" +ATTR_REDDITOR: Final = "redditor" DEFAULT_NAME = "Reddit" @@ -54,6 +57,7 @@ vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_SUBREDDITS): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(CONF_REDDITORS): vol.All(cv.ensure_list, [cv.string]), vol.Optional(CONF_SORT_BY, default="hot"): vol.All( cv.string, vol.In(LIST_TYPES) ), @@ -70,10 +74,10 @@ def setup_platform( ) -> None: """Set up the Reddit sensor platform.""" subreddits = config[CONF_SUBREDDITS] + redditors = config.get(CONF_REDDITORS, []) user_agent = f"{config[CONF_USERNAME]}_home_assistant_sensor" limit = config[CONF_MAXIMUM] sort_by = config[CONF_SORT_BY] - try: reddit = praw.Reddit( client_id=config[CONF_CLIENT_ID], @@ -90,35 +94,53 @@ def setup_platform( return sensors = [ - RedditSensor(reddit, subreddit, limit, sort_by) for subreddit in subreddits + RedditSensor(reddit, subreddit, limit, sort_by, ATTR_SUBREDDIT) + for subreddit in subreddits ] + sensors.extend( + RedditSensor(reddit, redditor, limit, sort_by, ATTR_REDDITOR) + for redditor in redditors + ) + add_entities(sensors, True) class RedditSensor(SensorEntity): """Representation of a Reddit sensor.""" - def __init__(self, reddit, subreddit: str, limit: int, sort_by: str) -> None: + def __init__( + self, + reddit, + subreddit: str, + limit: int, + sort_by: str, + mode: str, + ) -> None: """Initialize the Reddit sensor.""" self._reddit = reddit self._subreddit = subreddit self._limit = limit self._sort_by = sort_by + self._mode = mode self._subreddit_data: list = [] @property - def name(self): + def name(self) -> str: """Return the name of the sensor.""" - return f"reddit_{self._subreddit}" + return ( + self._mode == ATTR_SUBREDDIT + and f"reddit_{self._subreddit}" + or f"reddit_user_{self._subreddit}" + ) @property - def native_value(self): + def native_value(self) -> int: """Return the state of the sensor.""" return len(self._subreddit_data) @property - def extra_state_attributes(self): + def extra_state_attributes(self) -> dict[str, Any]: """Return the state attributes.""" return { ATTR_SUBREDDIT: self._subreddit, @@ -127,7 +149,7 @@ def extra_state_attributes(self): } @property - def icon(self): + def icon(self) -> str: """Return the icon to use in the frontend.""" return "mdi:reddit" @@ -136,22 +158,25 @@ def update(self) -> None: self._subreddit_data = [] try: - subreddit = self._reddit.subreddit(self._subreddit) - if hasattr(subreddit, self._sort_by): - method_to_call = getattr(subreddit, self._sort_by) - - for submission in method_to_call(limit=self._limit): - self._subreddit_data.append( - { - ATTR_ID: submission.id, - ATTR_URL: submission.url, - ATTR_TITLE: submission.title, - ATTR_SCORE: submission.score, - ATTR_COMMENTS_NUMBER: submission.num_comments, - ATTR_CREATED: submission.created, - ATTR_BODY: submission.selftext, - } - ) + if hasattr(self._reddit, self._mode): + data_source = getattr(self._reddit, self._mode)(self._subreddit) + if hasattr(data_source, self._sort_by): + method_to_call = getattr(data_source, self._sort_by) + + for submission in method_to_call(limit=self._limit): + self._subreddit_data.append( + { + ATTR_ID: getattr(submission, "id", ""), + ATTR_URL: getattr(submission, "url", ""), + ATTR_TITLE: getattr(submission, "title", ""), + ATTR_SCORE: getattr(submission, "score", ""), + ATTR_COMMENTS_NUMBER: getattr( + submission, "num_comments", "" + ), + ATTR_CREATED: getattr(submission, "created", ""), + ATTR_BODY: getattr(submission, "selftext", ""), + } + ) except praw.exceptions.PRAWException as err: _LOGGER.error("Reddit error %s", err) diff --git a/tests/components/reddit/test_sensor.py b/tests/components/reddit/test_sensor.py index 98cf2b79db32da..06da37049553d4 100644 --- a/tests/components/reddit/test_sensor.py +++ b/tests/components/reddit/test_sensor.py @@ -37,6 +37,18 @@ } } +VALID_CONFIG_REDDITOR = { + "sensor": { + "platform": DOMAIN, + CONF_CLIENT_ID: "test_client_id", + CONF_CLIENT_SECRET: "test_client_secret", + CONF_USERNAME: "test_username", + CONF_PASSWORD: "test_password", + "subreddits": [], + "redditors": ["test_user"], + } +} + VALID_LIMITED_CONFIG = { "sensor": { "platform": DOMAIN, @@ -58,6 +70,7 @@ CONF_USERNAME: "test_username", CONF_PASSWORD: "test_password", "subreddits": ["worldnews", "news"], + "redditors": [], "sort_by": "invalid_sort_by", } } @@ -177,6 +190,16 @@ async def test_setup_with_valid_config(hass: HomeAssistant) -> None: assert state.attributes[CONF_SORT_BY] == "hot" +@patch("praw.Reddit", new=MockPraw) +async def test_setup_with_valid_config_redditor(hass: HomeAssistant) -> None: + """Test the platform setup with Reddit configuration.""" + assert await async_setup_component(hass, "sensor", VALID_CONFIG_REDDITOR) + await hass.async_block_till_done() + + state = hass.states.get("sensor.reddit_user_test_user") + assert int(state.state) == 0 + + @patch("praw.Reddit", new=MockPraw) async def test_setup_with_invalid_config(hass: HomeAssistant) -> None: """Test the platform setup with invalid Reddit configuration."""