Skip to content

Commit

Permalink
Merge pull request #88 from ogajduse/feat/more-typing-n-enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
ogajduse authored Aug 8, 2023
2 parents e5af5b9 + a450fbb commit 3c73434
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 57 deletions.
37 changes: 30 additions & 7 deletions custom_components/feedparser/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@


async def async_setup_platform(
hass: HomeAssistant,
hass: HomeAssistant, # noqa: ARG001
config: ConfigType,
async_add_devices: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
discovery_info: DiscoveryInfoType | None = None, # noqa: ARG001
) -> None:
"""Set up the Feedparser sensor."""
async_add_devices(
Expand Down Expand Up @@ -92,6 +92,7 @@ def __init__(
scan_interval: timedelta,
local_time: bool,
) -> None:
"""Initialize the Feedparser sensor."""
self._feed = feed
self._attr_name = name
self._attr_icon = "mdi:rss"
Expand All @@ -112,6 +113,7 @@ def update(self: FeedParserSensor) -> None:
self._attr_native_value = None
return

# set the sensor value to the amount of entries
self._attr_native_value = (
self._show_topn
if len(parsed_feed.entries) > self._show_topn
Expand All @@ -120,7 +122,8 @@ def update(self: FeedParserSensor) -> None:
self._entries.extend(self._generate_entries(parsed_feed))

def _generate_entries(
self: FeedParserSensor, parsed_feed: FeedParserDict
self: FeedParserSensor,
parsed_feed: FeedParserDict,
) -> list[dict[str, str]]:
return [
self._generate_sensor_entry(feed_entry)
Expand All @@ -130,7 +133,8 @@ def _generate_entries(
]

def _generate_sensor_entry(
self: FeedParserSensor, feed_entry: FeedParserDict
self: FeedParserSensor,
feed_entry: FeedParserDict,
) -> dict[str, str]:
sensor_entry = {}
for key, value in feed_entry.items():
Expand Down Expand Up @@ -166,14 +170,16 @@ def _parse_date(self: FeedParserSensor, date: str) -> datetime:
if not parsed_time.tzname():
# replace tzinfo with UTC offset if tzinfo does not contain a TZ name
parsed_time = parsed_time.replace(
tzinfo=timezone(parsed_time.utcoffset()) # type: ignore[arg-type]
tzinfo=timezone(parsed_time.utcoffset()), # type: ignore[arg-type]
)
if self._local_time:
parsed_time = dt.as_local(parsed_time)
return parsed_time

def _process_image(
self: FeedParserSensor, feed_entry: FeedParserDict, sensor_entry: dict[str, str]
self: FeedParserSensor,
feed_entry: FeedParserDict,
sensor_entry: dict[str, str],
) -> None:
if "image" in self._inclusions and "image" not in sensor_entry.keys():
if "enclosures" in feed_entry:
Expand All @@ -191,7 +197,24 @@ def _process_image(
"image"
] = DEFAULT_THUMBNAIL # use default image if no image found

@property
def feed_entries(self: FeedParserSensor) -> list[dict[str, str]]:
"""Return feed entries."""
if hasattr(self, "_entries"):
return self._entries
return []

@property
def local_time(self: FeedParserSensor) -> bool:
"""Return local_time."""
return self._local_time

@local_time.setter
def local_time(self: FeedParserSensor, value: bool) -> None:
"""Set local_time."""
self._local_time = value

@property
def extra_state_attributes(self: FeedParserSensor) -> dict[str, list]:
"""Return entity specific state attributes."""
return {"entries": self._entries}
return {"entries": self.feed_entries}
42 changes: 31 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dev = [
"types-python-dateutil",
"types-PyYAML",
"voluptuous-stubs",
"pyyaml"
"pyyaml",

]
[project.urls]
Expand Down Expand Up @@ -67,26 +67,41 @@ exclude = '''
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = [
"E",
"F",
"ANN",
"ARG",
"ARG",
"B",
"RET",
"PL",
"C",
"COM",
"D",
"ANN",
"D",
"DTZ",
"E",
"EM",
"F",
"FBT",
"FBT",
"ARG",
"I",
"UP",
"PGH",
"PL",
"PLR",
"PT",
"RET",
"RUF",
"SIM",
"SLF",
"TCH",
"TRY",
"UP",
]

# Q000,ANN,PT009,D,E501,
ignore = [
"D107", # Missing docstring in __init__
"FBT001", # Boolean positional arg in function definition
"PLR0913", # Too many arguments to function call
"ARG001", # Unused function argument
"D203", # 1 blank line required before class docstring
"D213", # Multi-line docstring summary should start at the first line
"FBT001" # Boolean positional argument in function definition
]

# Allow autofix for all enabled rules (when `--fix`) is provided.
Expand All @@ -113,7 +128,6 @@ exclude = [
"dist",
"venv",
]
per-file-ignores = {}

# Same as Black.
line-length = 88
Expand All @@ -124,6 +138,12 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
# Assume Python 3.11.
target-version = "py311"

[tool.ruff.per-file-ignores]
"tests/**" = ["S101"]

[tool.ruff.pylint]
max-args = 9

[[tool.mypy.overrides]]
module = "feedparser.*"
# Workaround till https://github.com/kurtmckee/feedparser/pull/282 gets merged to the main branch
Expand Down
7 changes: 3 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import pytest
from constants import TEST_FEEDS
from feedsource import FeedSource
from pytest import FixtureRequest

from custom_components.feedparser.sensor import FeedParserSensor

Expand All @@ -20,13 +19,13 @@ def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
metafunc.parametrize("feed", feeds, ids=[f.name for f in feeds], indirect=True)


@pytest.fixture
def feed(request: FixtureRequest) -> FeedSource:
@pytest.fixture()
def feed(request: pytest.FixtureRequest) -> FeedSource:
"""Return feed file source."""
return request.param


@pytest.fixture
@pytest.fixture()
def feed_sensor(feed: FeedSource) -> FeedParserSensor:
"""Return feed sensor initialized with the local RSS feed."""
return FeedParserSensor(**feed.sensor_config_local_feed)
9 changes: 4 additions & 5 deletions tests/download.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
"""Download RSS feeds for testing."""
import asyncio
import datetime
import json
from datetime import datetime

import aiohttp
from constants import TEST_FEEDS
from feedsource import FeedSource

base_date = datetime.now()
base_date = datetime.datetime.now(datetime.UTC)


async def run_feed(feed: FeedSource) -> None:
"""Download feed and store its metadata and content."""
async with aiohttp.ClientSession() as session:
async with session.get(feed.url) as response:
text = await response.text()
async with aiohttp.ClientSession() as session, session.get(feed.url) as response:
text = await response.text()
metadata = feed.raw
metadata["download_date"] = base_date.isoformat()
feed.metadata_path.write_text(json.dumps(metadata, indent=4) + "\n")
Expand Down
11 changes: 8 additions & 3 deletions tests/feedsource.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,12 @@ def download_date(self: "FeedSource") -> datetime:
try:
return datetime.fromisoformat(self.metadata["download_date"])
except KeyError as ke:
raise KeyError(
msg = (
f"download_date not found in {self.metadata_path}. "
"Is feed metadata downloaded?"
)
raise KeyError(
msg,
) from ke

@property
Expand Down Expand Up @@ -121,14 +124,16 @@ def ha_config_entry(self: "FeedSource") -> dict[str, Any]:

@classmethod
def gen_ha_sensors_yml_config(
cls: type["FeedSource"], sensors: list["FeedSource"]
cls: type["FeedSource"],
sensors: list["FeedSource"],
) -> str:
"""Generate HA "sensors" config."""
return yaml.dump([s.ha_config_entry for s in sensors])

@classmethod
def create_ha_sensors_config_file(
cls: type["FeedSource"], sensors: list["FeedSource"]
cls: type["FeedSource"],
sensors: list["FeedSource"],
) -> None:
"""Create HA "sensors" config file."""
sensors_yml = TEST_HASS_PATH / "sensors.yaml"
Expand Down
2 changes: 1 addition & 1 deletion tests/generate_ha_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
from feedsource import FeedSource

fsources = [FeedSource(fs) for fs in TEST_FEEDS]
FeedSource.create_ha_sensors_config_file([fs for fs in fsources])
FeedSource.create_ha_sensors_config_file(fsources)
Loading

0 comments on commit 3c73434

Please sign in to comment.