Skip to content

Commit c184f03

Browse files
authored
Merge pull request #115 from ogajduse/feat/add-http-headers-to-request
2 parents e617dbe + 6bddfc9 commit c184f03

File tree

5 files changed

+58
-10
lines changed

5 files changed

+58
-10
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ repos:
2828
voluptuous-stubs,
2929
types-python-dateutil,
3030
types-PyYAML,
31+
types-requests,
3132
]
3233
- repo: https://github.com/astral-sh/ruff-pre-commit
3334
# Ruff version.

custom_components/feedparser/sensor.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99

1010
import feedparser # type: ignore[import]
1111
import homeassistant.helpers.config_validation as cv
12+
import requests
1213
import voluptuous as vol
1314
from dateutil import parser
1415
from feedparser import FeedParserDict
1516
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
1617
from homeassistant.const import CONF_NAME, CONF_SCAN_INTERVAL
1718
from homeassistant.util import dt
19+
from requests_file import FileAdapter
1820

1921
if TYPE_CHECKING:
2022
from homeassistant.core import HomeAssistant
@@ -38,6 +40,7 @@
3840
DEFAULT_SCAN_INTERVAL = timedelta(hours=1)
3941
DEFAULT_THUMBNAIL = "https://www.home-assistant.io/images/favicon-192x192-full.png"
4042
DEFAULT_TOPN = 9999
43+
USER_AGENT = f"Home Assistant Feed-parser Integration {__version__}"
4144

4245
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
4346
{
@@ -124,9 +127,14 @@ def __repr__(self: FeedParserSensor) -> str:
124127
def update(self: FeedParserSensor) -> None:
125128
"""Parse the feed and update the state of the sensor."""
126129
_LOGGER.debug("Feed %s: Polling feed data from %s", self.name, self._feed)
127-
parsed_feed: FeedParserDict = feedparser.parse(self._feed)
128-
129-
if not parsed_feed:
130+
s: requests.Session = requests.Session()
131+
s.mount("file://", FileAdapter())
132+
s.headers.update({"User-Agent": USER_AGENT})
133+
res: requests.Response = s.get(self._feed)
134+
res.raise_for_status()
135+
parsed_feed: FeedParserDict = feedparser.parse(res.text)
136+
137+
if not parsed_feed.entries:
130138
self._attr_native_value = None
131139
_LOGGER.warning("Feed %s: No data received.", self.name)
132140
return

pyproject.toml

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ classifiers = [
2323
"Programming Language :: Python :: 3.11",
2424
]
2525
requires-python = ">=3.11.0"
26-
dependencies = ["python-dateutil", "feedparser==6.0.10", "homeassistant"]
26+
dependencies = [
27+
"feedparser==6.0.10",
28+
"homeassistant",
29+
"python-dateutil",
30+
"requests-file",
31+
"requests",
32+
]
2733

2834
[project.optional-dependencies]
2935
dev = [
@@ -34,6 +40,7 @@ dev = [
3440
"ruff",
3541
"types-python-dateutil",
3642
"types-PyYAML",
43+
"types-requests",
3744
"voluptuous-stubs",
3845
"pyyaml",
3946

@@ -97,11 +104,11 @@ select = [
97104

98105
# Q000,ANN,PT009,D,E501,
99106
ignore = [
100-
"D107", # Missing docstring in __init__
101-
"FBT001", # Boolean positional arg in function definition
102-
"D203", # 1 blank line required before class docstring
103-
"D213", # Multi-line docstring summary should start at the first line
104-
"FBT001" # Boolean positional argument in function definition
107+
"D107", # Missing docstring in __init__
108+
"FBT001", # Boolean positional arg in function definition
109+
"D203", # 1 blank line required before class docstring
110+
"D213", # Multi-line docstring summary should start at the first line
111+
"FBT001", # Boolean positional argument in function definition
105112
]
106113

107114
# Allow autofix for all enabled rules (when `--fix`) is provided.

tests/constants.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,14 @@
9393
DEFAULT_EXCLUSIONS: list[str] = []
9494
DEFAULT_INCLUSIONS = ["image", "title", "link", "published"]
9595
DATE_FORMAT = "%a, %d %b %Y %H:%M:%S UTC%z"
96+
97+
URLS_HEADERS_REQUIRED = [
98+
{
99+
"name": "elcomercio_gijon",
100+
"url": "https://www.elcomercio.es/rss/2.0/?section=gijon",
101+
},
102+
{
103+
"name": "nasdaq_options",
104+
"url": "https://www.nasdaq.com/feed/rssoutbound?category=Options",
105+
},
106+
]

tests/test_sensors.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import feedparser
88
import pytest
9-
from constants import DATE_FORMAT
9+
from constants import DATE_FORMAT, URLS_HEADERS_REQUIRED
1010
from feedsource import FeedSource
1111

1212
from custom_components.feedparser.sensor import (
@@ -157,3 +157,24 @@ def test_check_duplicates(feed_sensor: FeedParserSensor) -> None:
157157
feed_sensor.update()
158158
after_second_update = len(feed_sensor.feed_entries)
159159
assert after_first_update == after_second_update
160+
161+
162+
@pytest.mark.parametrize(
163+
"online_feed",
164+
URLS_HEADERS_REQUIRED,
165+
ids=lambda feed_url: feed_url["name"],
166+
)
167+
def test_fetch_data_headers_required(online_feed: dict) -> None:
168+
"""Test fetching feed from remote server that requires request with headers."""
169+
feed_sensor = FeedParserSensor(
170+
feed=online_feed["url"],
171+
name=online_feed["name"],
172+
date_format=DATE_FORMAT,
173+
local_time=False,
174+
show_topn=9999,
175+
inclusions=["image", "title", "link", "published"],
176+
exclusions=[],
177+
scan_interval=DEFAULT_SCAN_INTERVAL,
178+
)
179+
feed_sensor.update()
180+
assert feed_sensor.feed_entries

0 commit comments

Comments
 (0)