ludeeus / pyhaversion Goto Github PK
View Code? Open in Web Editor NEWGet the latest Home Assistant version from various sources.
Home Page: https://pypi.org/project/pyhaversion/
License: MIT License
Get the latest Home Assistant version from various sources.
Home Page: https://pypi.org/project/pyhaversion/
License: MIT License
Describe the bug
When using the "beta" branch for PyPi, if the beta has more than 10 releases, for example 0.115 which is currently at 0.115.0b11, the wrong version is returned (in this case 0.115.0b9). It would appear that the beta part of the version number is being sorted alphanumerically resulting in 0.115.0b11 (and 0.115.0b10) coming before 0.115.0b9
log
Add your logs here.
Prior to 2021.7 and the introduction of series version tags container versions would appear with full patch number, eg 2021.6.6
. Now the container version sensor shows only 2021.7
, with no indication that there is a new patch release.
For me this has broken some automation around when a new release comes out. I am interested to hear others thoughts on the new behavior.
2021-07-12 15:35:11 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: entity_id=sensor.ha_docker_version_stable, old_state=None, new_state=<state sensor.ha_docker_version_stable=2021.7; source=HaVersionSource.CONTAINER, channel=HaVersionChannel.STABLE, friendly_name=Latest Docker, icon=mdi:docker @ 2021-07-12T15:35:11.983537-05:00>>
2021-07-12 15:35:12 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: entity_id=sensor.ha_github_version, old_state=None, new_state=<state sensor.ha_github_version=2021.7.1; friendly_name=Latest Github, icon=mdi:github @ 2021-07-12T15:35:12.325471-05:00>>
Currently there is support for querying the Docker Hub version, but according to the hass website, the preferred way to get the docker images is from ghcr.io (see the first entry under "Breaking Changes" in the 2023.7 release notes). It would be ideal if I can track that version, rather than the one on Docker Hub.
I haven't read the code, but I imagine it would be a clone of the existing Docker Hub code but with a different url.
The Docker Hub version is an ok proxy for now, but I'd rather not mix-and-match sources if I can help it.
If you look at the documentation off Home Assistant(https://www.home-assistant.io/integrations/version/#supported-images-for-hassio-and-docker) it looks like raspberrypi4 and raspberrypi4-64 images are included but this script doesn't include them.
Would it be possible to include these?
Dependabot couldn't authenticate with https://pypi.python.org/simple/.
You can provide authentication details in your Dependabot dashboard by clicking into the account menu (in the top right) and selecting 'Config variables'.
Describe the bug
I tried to use the version sensor in home assistant with source set to haio
and I received this message in my logs:
log
2020-06-08 12:50:48 CRITICAL (MainThread) [pyhaversion] Something really wrong happened! - Expecting value: line 1 column 1 (char 0)
I looked in the source here and it seems when trying to use pyhaversion with source of haio
it tries to use the URL https://www.home-assistant.io/version.json to get the version info. This URL does not return JSON though, it returns HTML with JSON inside it.
I'm not sure what broke, seems like either the website needs to be fixed so it serves up JSON again, the library needs to change the URL it uses or the haio
option needs to be removed.
Is your feature request related to a problem? Please describe.
PyPiVersion is returning the wrong version number (99.3) for the "beta" branch.
I'd reported this over at the Home Assistant repo (home-assistant/core#32268) but the issue appears to be with this package.
Describe the solution you'd like
Should return the latest beta version (which was 0.106.b5 at the time I tested this).
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
Additional context
Add any other context or screenshots about the feature request here.
Appears to be due to using the built-in sorted function to sort the releases by version in descending order and, with a simple alphanumeric sort, 0.99.3 is treated as the latest version.
It looks like this can be fixed by using the natsorted function from the natsort package instead which applied a "natural" sorting and seems to pick up the correct version.
Hi,
first I hope you don't mind that I use your integration in Home Assistant Gentoo Overlay, find your Ebuilds are in: https://github.com/onkelbeh/HomeAssistantRepository/tree/master/dev-python/pyhaversion
Describe the bug
During some compile tests I saw that pyhaversion tries to install 'test' package at top level, this is fobidden in Gentoo (and most other Distri's). This could easily be fixed with a small change to setup.py:
For now, I added a small generic sed
script to my ebuilds:
src_prepare() {
sed "s/packages=find_packages()/packages=find_packages(exclude=['tests','tests.*'])/g" -i setup.py || die
eapply_user
}
I fixed this in my repo a few days ago, but I have a reminder for cleanup which just popped up again.
I'll send a pull request in a few seconds.
Thanks a lot.
Please drop me a not when it's fixed, so I can remove the patch.
\B.
log
please see https://git.edevau.net/onkelbeh/HomeAssistantRepository/issues/179 for the build log.
Describe the bug
It seems that with a recent change (maybe home-assistant/core#26085), the Docker versioning schema has changed a little bit and pyhaversion
is always returning the details for dev
.
Docker beta
Version: 0.98.0.dev20190827
Attributes: {'beta': True, 'source': 'Docker', 'image': 'qemux86-64-homeassistant'}
Docker stable
Version: 0.98.0.dev20190827
Attributes: {'beta': False, 'source': 'Docker', 'image': 'qemux86-64-homeassistant'}
See also: home-assistant/core#26213
The test suite fails two tests on python 3.11:
FAILED tests/test_supervisor.py::test_stable_version - pyhaversion.exceptions.HaVersionFetchException: Error fetching version information from HaVersionSource.SUPERVISOR Server disconnected
FAILED tests/test_supervisor.py::test_etag - pyhaversion.exceptions.HaVersionFetchException: Error fetching version information from HaVersionSource.SUPERVISOR Server disconnected
Running pytest
against python 3.11 should surface the issue.
============================================ test session starts =============================================
platform linux -- Python 3.11.3, pytest-7.3.1, pluggy-1.0.0
rootdir: /tmp/pyhaversion
plugins: asyncio-0.21.0, aresponses-2.1.6
asyncio: mode=Mode.STRICT
collected 27 items
tests/test_container.py .......... [ 37%]
tests/test_haio.py ... [ 48%]
tests/test_local.py . [ 51%]
tests/test_pypi.py ..... [ 70%]
tests/test_supervisor.py F..F [ 85%]
tests/test_version.py .... [100%]
================================================== FAILURES ==================================================
____________________________________________ test_stable_version _____________________________________________
self = <pyhaversion.version.HaVersion object at 0x7f07f315e2d0>
async def get_version(
self,
*,
etag: str | None = None,
) -> tuple[AwesomeVersion, dict[str, Any]]:
"""
Get version update.
Returns a tupe with version, version_data.
"""
try:
> await self._handler.fetch(etag=etag)
pyhaversion/version.py:89:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = HaVersionSupervisor(source=<HaVersionSource.SUPERVISOR: 'supervisor'>, channel=<HaVersionChannel.STABLE: 'stable'>, board='ova', image='default', _etag=None)
kwargs = {'etag': None}
headers = {'Content-Type': 'application/json', 'If-None-Match': 'W/"test"', 'User-Agent': 'python/pyhaversion'}
etag = None
async def fetch(self, **kwargs):
"""Logic to fetch new version data."""
headers = DEFAULT_HEADERS
if (etag := kwargs.get("etag")) is not None:
headers[IF_NONE_MATCH] = etag
> request = await self.session.get(
url=URL.format(channel=self.channel),
headers=headers,
timeout=ClientTimeout(total=self.timeout),
)
pyhaversion/supervisor.py:47:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <aiohttp.client.ClientSession object at 0x7f07f315ed50>, method = 'GET'
str_or_url = 'https://version.home-assistant.io/HaVersionChannel.STABLE.json'
async def _request(
self,
method: str,
str_or_url: StrOrURL,
*,
params: Optional[Mapping[str, str]] = None,
data: Any = None,
json: Any = None,
cookies: Optional[LooseCookies] = None,
headers: Optional[LooseHeaders] = None,
skip_auto_headers: Optional[Iterable[str]] = None,
auth: Optional[BasicAuth] = None,
allow_redirects: bool = True,
max_redirects: int = 10,
compress: Optional[str] = None,
chunked: Optional[bool] = None,
expect100: bool = False,
raise_for_status: Optional[bool] = None,
read_until_eof: bool = True,
proxy: Optional[StrOrURL] = None,
proxy_auth: Optional[BasicAuth] = None,
timeout: Union[ClientTimeout, object] = sentinel,
verify_ssl: Optional[bool] = None,
fingerprint: Optional[bytes] = None,
ssl_context: Optional[SSLContext] = None,
ssl: Optional[Union[SSLContext, bool, Fingerprint]] = None,
proxy_headers: Optional[LooseHeaders] = None,
trace_request_ctx: Optional[SimpleNamespace] = None,
read_bufsize: Optional[int] = None,
) -> ClientResponse:
# NOTE: timeout clamps existing connect and read timeouts. We cannot
# set the default to None because we need to detect if the user wants
# to use the existing timeouts by setting timeout to None.
if self.closed:
raise RuntimeError("Session is closed")
ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)
if data is not None and json is not None:
raise ValueError(
"data and json parameters can not be used at the same time"
)
elif json is not None:
data = payload.JsonPayload(json, dumps=self._json_serialize)
if not isinstance(chunked, bool) and chunked is not None:
warnings.warn("Chunk size is deprecated #1615", DeprecationWarning)
redirects = 0
history = []
version = self._version
# Merge with default headers and transform to CIMultiDict
headers = self._prepare_headers(headers)
proxy_headers = self._prepare_headers(proxy_headers)
try:
url = self._build_url(str_or_url)
except ValueError as e:
raise InvalidURL(str_or_url) from e
skip_headers = set(self._skip_auto_headers)
if skip_auto_headers is not None:
for i in skip_auto_headers:
skip_headers.add(istr(i))
if proxy is not None:
try:
proxy = URL(proxy)
except ValueError as e:
raise InvalidURL(proxy) from e
if timeout is sentinel:
real_timeout: ClientTimeout = self._timeout
else:
if not isinstance(timeout, ClientTimeout):
real_timeout = ClientTimeout(total=timeout) # type: ignore[arg-type]
else:
real_timeout = timeout
# timeout is cumulative for all request operations
# (request, redirects, responses, data consuming)
tm = TimeoutHandle(self._loop, real_timeout.total)
handle = tm.start()
if read_bufsize is None:
read_bufsize = self._read_bufsize
traces = [
Trace(
self,
trace_config,
trace_config.trace_config_ctx(trace_request_ctx=trace_request_ctx),
)
for trace_config in self._trace_configs
]
for trace in traces:
await trace.send_request_start(method, url.update_query(params), headers)
timer = tm.timer()
try:
with timer:
while True:
url, auth_from_url = strip_auth_from_url(url)
if auth and auth_from_url:
raise ValueError(
"Cannot combine AUTH argument with "
"credentials encoded in URL"
)
if auth is None:
auth = auth_from_url
if auth is None:
auth = self._default_auth
# It would be confusing if we support explicit
# Authorization header with auth argument
if (
headers is not None
and auth is not None
and hdrs.AUTHORIZATION in headers
):
raise ValueError(
"Cannot combine AUTHORIZATION header "
"with AUTH argument or credentials "
"encoded in URL"
)
all_cookies = self._cookie_jar.filter_cookies(url)
if cookies is not None:
tmp_cookie_jar = CookieJar()
tmp_cookie_jar.update_cookies(cookies)
req_cookies = tmp_cookie_jar.filter_cookies(url)
if req_cookies:
all_cookies.load(req_cookies)
if proxy is not None:
proxy = URL(proxy)
elif self._trust_env:
with suppress(LookupError):
proxy, proxy_auth = get_env_proxy_for_url(url)
req = self._request_class(
method,
url,
params=params,
headers=headers,
skip_auto_headers=skip_headers,
data=data,
cookies=all_cookies,
auth=auth,
version=version,
compress=compress,
chunked=chunked,
expect100=expect100,
loop=self._loop,
response_class=self._response_class,
proxy=proxy,
proxy_auth=proxy_auth,
timer=timer,
session=self,
ssl=ssl,
proxy_headers=proxy_headers,
traces=traces,
)
# connection timeout
try:
async with ceil_timeout(real_timeout.connect):
assert self._connector is not None
conn = await self._connector.connect(
req, traces=traces, timeout=real_timeout
)
except asyncio.TimeoutError as exc:
raise ServerTimeoutError(
"Connection timeout " "to host {}".format(url)
) from exc
assert conn.transport is not None
assert conn.protocol is not None
conn.protocol.set_response_params(
timer=timer,
skip_payload=method.upper() == "HEAD",
read_until_eof=read_until_eof,
auto_decompress=self._auto_decompress,
read_timeout=real_timeout.sock_read,
read_bufsize=read_bufsize,
)
try:
try:
resp = await req.send(conn)
try:
> await resp.start(conn)
.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/client.py:560:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <ClientResponse(https://version.home-assistant.io/HaVersionChannel.STABLE.json) [None None]>
None
connection = Connection<ConnectionKey(host='version.home-assistant.io', port=443, is_ssl=False, ssl=None, proxy=None, proxy_auth=None, proxy_headers_hash=None)>
async def start(self, connection: "Connection") -> "ClientResponse":
"""Start response processing."""
self._closed = False
self._protocol = connection.protocol
self._connection = connection
with self._timer:
while True:
# read response
try:
protocol = self._protocol
> message, payload = await protocol.read() # type: ignore[union-attr]
.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/client_reqrep.py:899:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <aiohttp.client_proto.ResponseHandler object at 0x7f07f311fc40>
async def read(self) -> _T:
if not self._buffer and not self._eof:
assert not self._waiter
self._waiter = self._loop.create_future()
try:
> await self._waiter
E aiohttp.client_exceptions.ServerDisconnectedError: Server disconnected
.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/streams.py:616: ServerDisconnectedError
The above exception was the direct cause of the following exception:
aresponses = <aresponses.main.ResponsesMockServer object at 0x7f07f315d590>
@pytest.mark.asyncio
async def test_stable_version(aresponses):
"""Test hassio stable."""
aresponses.add(
"version.home-assistant.io",
"/stable.json",
"get",
aresponses.Response(
text=fixture("supervisor/default", False), status=200, headers=HEADERS
),
)
async with aiohttp.ClientSession() as session:
haversion = HaVersion(session=session, source=HaVersionSource.SUPERVISOR)
> await haversion.get_version()
tests/test_supervisor.py:32:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <pyhaversion.version.HaVersion object at 0x7f07f315e2d0>
async def get_version(
self,
*,
etag: str | None = None,
) -> tuple[AwesomeVersion, dict[str, Any]]:
"""
Get version update.
Returns a tupe with version, version_data.
"""
try:
await self._handler.fetch(etag=etag)
except asyncio.TimeoutError as exception:
raise HaVersionFetchException(
f"Timeout of {self._handler.timeout} seconds was "
f"reached while fetching version for {self.source}"
) from exception
except (ClientError, gaierror) as exception:
> raise HaVersionFetchException(
f"Error fetching version information from {self.source} {exception}"
) from exception
E pyhaversion.exceptions.HaVersionFetchException: Error fetching version information from HaVersionSource.SUPERVISOR Server disconnected
pyhaversion/version.py:98: HaVersionFetchException
------------------------------------------- Captured stderr setup --------------------------------------------
DEBUG:asyncio:Using selector: EpollSelector
--------------------------------------------- Captured log setup ---------------------------------------------
DEBUG asyncio:selector_events.py:54 Using selector: EpollSelector
-------------------------------------------- Captured stderr call --------------------------------------------
ERROR:aiohttp.server:Unhandled runtime exception
Traceback (most recent call last):
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 600, in finish_response
prepare_meth = resp.prepare
^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'prepare'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 512, in start
resp, reset = await task
^^^^^^^^^^
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 458, in _handle_request
reset = await self.finish_response(request, resp, start_time)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 603, in finish_response
raise RuntimeError("Missing return " "statement on request handler")
RuntimeError: Missing return statement on request handler
--------------------------------------------- Captured log call ----------------------------------------------
ERROR aiohttp.server:web_protocol.py:403 Unhandled runtime exception
Traceback (most recent call last):
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 600, in finish_response
prepare_meth = resp.prepare
^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'prepare'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 512, in start
resp, reset = await task
^^^^^^^^^^
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 458, in _handle_request
reset = await self.finish_response(request, resp, start_time)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 603, in finish_response
raise RuntimeError("Missing return " "statement on request handler")
RuntimeError: Missing return statement on request handler
------------------------------------------ Captured stderr teardown ------------------------------------------
DEBUG:asyncio:Using selector: EpollSelector
------------------------------------------- Captured log teardown --------------------------------------------
DEBUG asyncio:selector_events.py:54 Using selector: EpollSelector
_________________________________________________ test_etag __________________________________________________
self = <pyhaversion.version.HaVersion object at 0x7f07f3115250>
async def get_version(
self,
*,
etag: str | None = None,
) -> tuple[AwesomeVersion, dict[str, Any]]:
"""
Get version update.
Returns a tupe with version, version_data.
"""
try:
> await self._handler.fetch(etag=etag)
pyhaversion/version.py:89:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = HaVersionSupervisor(source=<HaVersionSource.SUPERVISOR: 'supervisor'>, channel=<HaVersionChannel.STABLE: 'stable'>, board='ova', image='default', _etag=None)
kwargs = {'etag': None}
headers = {'Content-Type': 'application/json', 'If-None-Match': 'W/"test"', 'User-Agent': 'python/pyhaversion'}
etag = None
async def fetch(self, **kwargs):
"""Logic to fetch new version data."""
headers = DEFAULT_HEADERS
if (etag := kwargs.get("etag")) is not None:
headers[IF_NONE_MATCH] = etag
> request = await self.session.get(
url=URL.format(channel=self.channel),
headers=headers,
timeout=ClientTimeout(total=self.timeout),
)
pyhaversion/supervisor.py:47:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <aiohttp.client.ClientSession object at 0x7f07f3114fd0>, method = 'GET'
str_or_url = 'https://version.home-assistant.io/HaVersionChannel.STABLE.json'
async def _request(
self,
method: str,
str_or_url: StrOrURL,
*,
params: Optional[Mapping[str, str]] = None,
data: Any = None,
json: Any = None,
cookies: Optional[LooseCookies] = None,
headers: Optional[LooseHeaders] = None,
skip_auto_headers: Optional[Iterable[str]] = None,
auth: Optional[BasicAuth] = None,
allow_redirects: bool = True,
max_redirects: int = 10,
compress: Optional[str] = None,
chunked: Optional[bool] = None,
expect100: bool = False,
raise_for_status: Optional[bool] = None,
read_until_eof: bool = True,
proxy: Optional[StrOrURL] = None,
proxy_auth: Optional[BasicAuth] = None,
timeout: Union[ClientTimeout, object] = sentinel,
verify_ssl: Optional[bool] = None,
fingerprint: Optional[bytes] = None,
ssl_context: Optional[SSLContext] = None,
ssl: Optional[Union[SSLContext, bool, Fingerprint]] = None,
proxy_headers: Optional[LooseHeaders] = None,
trace_request_ctx: Optional[SimpleNamespace] = None,
read_bufsize: Optional[int] = None,
) -> ClientResponse:
# NOTE: timeout clamps existing connect and read timeouts. We cannot
# set the default to None because we need to detect if the user wants
# to use the existing timeouts by setting timeout to None.
if self.closed:
raise RuntimeError("Session is closed")
ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint)
if data is not None and json is not None:
raise ValueError(
"data and json parameters can not be used at the same time"
)
elif json is not None:
data = payload.JsonPayload(json, dumps=self._json_serialize)
if not isinstance(chunked, bool) and chunked is not None:
warnings.warn("Chunk size is deprecated #1615", DeprecationWarning)
redirects = 0
history = []
version = self._version
# Merge with default headers and transform to CIMultiDict
headers = self._prepare_headers(headers)
proxy_headers = self._prepare_headers(proxy_headers)
try:
url = self._build_url(str_or_url)
except ValueError as e:
raise InvalidURL(str_or_url) from e
skip_headers = set(self._skip_auto_headers)
if skip_auto_headers is not None:
for i in skip_auto_headers:
skip_headers.add(istr(i))
if proxy is not None:
try:
proxy = URL(proxy)
except ValueError as e:
raise InvalidURL(proxy) from e
if timeout is sentinel:
real_timeout: ClientTimeout = self._timeout
else:
if not isinstance(timeout, ClientTimeout):
real_timeout = ClientTimeout(total=timeout) # type: ignore[arg-type]
else:
real_timeout = timeout
# timeout is cumulative for all request operations
# (request, redirects, responses, data consuming)
tm = TimeoutHandle(self._loop, real_timeout.total)
handle = tm.start()
if read_bufsize is None:
read_bufsize = self._read_bufsize
traces = [
Trace(
self,
trace_config,
trace_config.trace_config_ctx(trace_request_ctx=trace_request_ctx),
)
for trace_config in self._trace_configs
]
for trace in traces:
await trace.send_request_start(method, url.update_query(params), headers)
timer = tm.timer()
try:
with timer:
while True:
url, auth_from_url = strip_auth_from_url(url)
if auth and auth_from_url:
raise ValueError(
"Cannot combine AUTH argument with "
"credentials encoded in URL"
)
if auth is None:
auth = auth_from_url
if auth is None:
auth = self._default_auth
# It would be confusing if we support explicit
# Authorization header with auth argument
if (
headers is not None
and auth is not None
and hdrs.AUTHORIZATION in headers
):
raise ValueError(
"Cannot combine AUTHORIZATION header "
"with AUTH argument or credentials "
"encoded in URL"
)
all_cookies = self._cookie_jar.filter_cookies(url)
if cookies is not None:
tmp_cookie_jar = CookieJar()
tmp_cookie_jar.update_cookies(cookies)
req_cookies = tmp_cookie_jar.filter_cookies(url)
if req_cookies:
all_cookies.load(req_cookies)
if proxy is not None:
proxy = URL(proxy)
elif self._trust_env:
with suppress(LookupError):
proxy, proxy_auth = get_env_proxy_for_url(url)
req = self._request_class(
method,
url,
params=params,
headers=headers,
skip_auto_headers=skip_headers,
data=data,
cookies=all_cookies,
auth=auth,
version=version,
compress=compress,
chunked=chunked,
expect100=expect100,
loop=self._loop,
response_class=self._response_class,
proxy=proxy,
proxy_auth=proxy_auth,
timer=timer,
session=self,
ssl=ssl,
proxy_headers=proxy_headers,
traces=traces,
)
# connection timeout
try:
async with ceil_timeout(real_timeout.connect):
assert self._connector is not None
conn = await self._connector.connect(
req, traces=traces, timeout=real_timeout
)
except asyncio.TimeoutError as exc:
raise ServerTimeoutError(
"Connection timeout " "to host {}".format(url)
) from exc
assert conn.transport is not None
assert conn.protocol is not None
conn.protocol.set_response_params(
timer=timer,
skip_payload=method.upper() == "HEAD",
read_until_eof=read_until_eof,
auto_decompress=self._auto_decompress,
read_timeout=real_timeout.sock_read,
read_bufsize=read_bufsize,
)
try:
try:
resp = await req.send(conn)
try:
> await resp.start(conn)
.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/client.py:560:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <ClientResponse(https://version.home-assistant.io/HaVersionChannel.STABLE.json) [None None]>
None
connection = Connection<ConnectionKey(host='version.home-assistant.io', port=443, is_ssl=False, ssl=None, proxy=None, proxy_auth=None, proxy_headers_hash=None)>
async def start(self, connection: "Connection") -> "ClientResponse":
"""Start response processing."""
self._closed = False
self._protocol = connection.protocol
self._connection = connection
with self._timer:
while True:
# read response
try:
protocol = self._protocol
> message, payload = await protocol.read() # type: ignore[union-attr]
.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/client_reqrep.py:899:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <aiohttp.client_proto.ResponseHandler object at 0x7f07f2ed1be0>
async def read(self) -> _T:
if not self._buffer and not self._eof:
assert not self._waiter
self._waiter = self._loop.create_future()
try:
> await self._waiter
E aiohttp.client_exceptions.ServerDisconnectedError: Server disconnected
.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/streams.py:616: ServerDisconnectedError
The above exception was the direct cause of the following exception:
aresponses = <aresponses.main.ResponsesMockServer object at 0x7f07f30c1350>
@pytest.mark.asyncio
async def test_etag(aresponses):
"""Test hassio etag."""
aresponses.add(
"version.home-assistant.io",
"/stable.json",
"get",
aresponses.Response(
text=fixture("supervisor/default", False),
status=200,
headers={**HEADERS, "Etag": "test"},
),
)
aresponses.add(
"version.home-assistant.io",
"/stable.json",
"get",
aresponses.Response(status=304, headers=HEADERS),
)
async with aiohttp.ClientSession() as session:
haversion = HaVersion(session=session, source=HaVersionSource.SUPERVISOR)
> await haversion.get_version(etag=haversion.etag)
tests/test_supervisor.py:83:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <pyhaversion.version.HaVersion object at 0x7f07f3115250>
async def get_version(
self,
*,
etag: str | None = None,
) -> tuple[AwesomeVersion, dict[str, Any]]:
"""
Get version update.
Returns a tupe with version, version_data.
"""
try:
await self._handler.fetch(etag=etag)
except asyncio.TimeoutError as exception:
raise HaVersionFetchException(
f"Timeout of {self._handler.timeout} seconds was "
f"reached while fetching version for {self.source}"
) from exception
except (ClientError, gaierror) as exception:
> raise HaVersionFetchException(
f"Error fetching version information from {self.source} {exception}"
) from exception
E pyhaversion.exceptions.HaVersionFetchException: Error fetching version information from HaVersionSource.SUPERVISOR Server disconnected
pyhaversion/version.py:98: HaVersionFetchException
------------------------------------------- Captured stderr setup --------------------------------------------
DEBUG:asyncio:Using selector: EpollSelector
--------------------------------------------- Captured log setup ---------------------------------------------
DEBUG asyncio:selector_events.py:54 Using selector: EpollSelector
-------------------------------------------- Captured stderr call --------------------------------------------
ERROR:aiohttp.server:Unhandled runtime exception
Traceback (most recent call last):
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 600, in finish_response
prepare_meth = resp.prepare
^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'prepare'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 512, in start
resp, reset = await task
^^^^^^^^^^
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 458, in _handle_request
reset = await self.finish_response(request, resp, start_time)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 603, in finish_response
raise RuntimeError("Missing return " "statement on request handler")
RuntimeError: Missing return statement on request handler
--------------------------------------------- Captured log call ----------------------------------------------
ERROR aiohttp.server:web_protocol.py:403 Unhandled runtime exception
Traceback (most recent call last):
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 600, in finish_response
prepare_meth = resp.prepare
^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'prepare'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 512, in start
resp, reset = await task
^^^^^^^^^^
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 458, in _handle_request
reset = await self.finish_response(request, resp, start_time)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/pyhaversion/.venv/lib/python3.11/site-packages/aiohttp-3.8.4-py3.11-linux-x86_64.egg/aiohttp/web_protocol.py", line 603, in finish_response
raise RuntimeError("Missing return " "statement on request handler")
RuntimeError: Missing return statement on request handler
------------------------------------------ Captured stderr teardown ------------------------------------------
DEBUG:asyncio:Using selector: EpollSelector
------------------------------------------- Captured log teardown --------------------------------------------
DEBUG asyncio:selector_events.py:54 Using selector: EpollSelector
========================================== short test summary info ===========================================
FAILED tests/test_supervisor.py::test_stable_version - pyhaversion.exceptions.HaVersionFetchException: Error fetching version information from HaVersionSource.S...
FAILED tests/test_supervisor.py::test_etag - pyhaversion.exceptions.HaVersionFetchException: Error fetching version information from HaVersionSource.S...
======================================== 2 failed, 25 passed in 0.16s ========================================
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.