diff --git a/CHANGES/7237.bugfix b/CHANGES/7237.bugfix new file mode 100644 index 00000000000..26f85ea9c95 --- /dev/null +++ b/CHANGES/7237.bugfix @@ -0,0 +1 @@ +Fixed ``PermissionError`` when .netrc is unreadable due to permissions. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 6c2fabbdece..8e31468aee6 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -153,6 +153,7 @@ Jake Davis Jakob Ackermann Jakub Wilk Jan Buchar +Jan Gosmann Jashandeep Sohi Jens Steinhauser Jeonghun Lee diff --git a/aiohttp/helpers.py b/aiohttp/helpers.py index 874ab1ac076..eb0782ff37f 100644 --- a/aiohttp/helpers.py +++ b/aiohttp/helpers.py @@ -3,6 +3,7 @@ import asyncio import base64 import binascii +import contextlib import datetime import functools import inspect @@ -226,8 +227,11 @@ def netrc_from_env() -> Optional[netrc.netrc]: except netrc.NetrcParseError as e: client_logger.warning("Could not parse .netrc file: %s", e) except OSError as e: + netrc_exists = False + with contextlib.suppress(OSError): + netrc_exists = netrc_path.is_file() # we couldn't read the file (doesn't exist, permissions, etc.) - if netrc_env or netrc_path.is_file(): + if netrc_env or netrc_exists: # only warn if the environment wanted us to load it, # or it appears like the default file does actually exist client_logger.warning("Could not read .netrc file: %s", e) @@ -742,7 +746,6 @@ def ceil_timeout(delay: Optional[float]) -> async_timeout.Timeout: class HeadersMixin: - ATTRS = frozenset(["_content_type", "_content_dict", "_stored_content_type"]) _content_type: Optional[str] = None diff --git a/tests/test_helpers.py b/tests/test_helpers.py index d192545de7f..6099afac22a 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -5,6 +5,7 @@ import platform import tempfile from math import isclose, modf +from pathlib import Path from unittest import mock from urllib.request import getproxies_environment @@ -178,7 +179,6 @@ def test_basic_auth_from_not_url() -> None: class ReifyMixin: - reify = NotImplemented def test_reify(self) -> None: @@ -763,3 +763,23 @@ def test_repr(self) -> None: ) def test_parse_http_date(value, expected): assert parse_http_date(value) == expected + + +@pytest.fixture +def protected_dir(tmp_path: Path): + protected_dir = tmp_path / "protected" + protected_dir.mkdir() + try: + protected_dir.chmod(0o600) + yield protected_dir + finally: + protected_dir.rmdir() + + +def test_netrc_from_home_does_not_raise_if_access_denied( + protected_dir: Path, monkeypatch: pytest.MonkeyPatch +): + monkeypatch.setattr(Path, "home", lambda: protected_dir) + monkeypatch.delenv("NETRC", raising=False) + + helpers.netrc_from_env()