di / id

A tool for generating OIDC identities
Apache License 2.0
9 stars 3 forks source link

gcp-related tests broken on PyPy3.10 7.3.17 #287

Open mgorny opened 2 weeks ago

mgorny commented 2 weeks ago

The few gcp-related tests seem to be failing. I think they're trying to mock CPython implementation details:

$ EPYTHON=pypy3 make test
# Create our Python 3 virtual environment
python3 -m venv env
env/bin/python -m pip install --upgrade pip
Requirement already satisfied: pip in ./env/lib/pypy3.10/site-packages (24.2)
env/bin/python -m pip install -e .[dev]
Obtaining file:///tmp/id
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Preparing editable metadata (pyproject.toml) ... done
Collecting pydantic (from id==1.4.0)
  Using cached pydantic-2.9.2-py3-none-any.whl.metadata (149 kB)
Collecting requests (from id==1.4.0)
  Using cached requests-2.32.3-py3-none-any.whl.metadata (4.6 kB)
Collecting build (from id==1.4.0)
  Using cached build-1.2.2-py3-none-any.whl.metadata (6.2 kB)
Collecting bump>=1.3.2 (from id==1.4.0)
  Using cached bump-1.3.2-py3-none-any.whl.metadata (2.7 kB)
Collecting click<9,>=6 (from bump>=1.3.2->id==1.4.0)
  Using cached click-8.1.7-py3-none-any.whl.metadata (3.0 kB)
Collecting first (from bump>=1.3.2->id==1.4.0)
  Using cached first-2.0.2-py2.py3-none-any.whl.metadata (7.0 kB)
Collecting packaging>=17.1 (from bump>=1.3.2->id==1.4.0)
  Using cached packaging-24.1-py3-none-any.whl.metadata (3.2 kB)
Collecting toml (from bump>=1.3.2->id==1.4.0)
  Using cached toml-0.10.2-py2.py3-none-any.whl.metadata (7.1 kB)
Collecting pyproject_hooks (from build->id==1.4.0)
  Using cached pyproject_hooks-1.1.0-py3-none-any.whl.metadata (1.3 kB)
Collecting tomli>=1.1.0 (from build->id==1.4.0)
  Using cached tomli-2.0.1-py3-none-any.whl.metadata (8.9 kB)
Collecting bandit (from id==1.4.0)
  Using cached bandit-1.7.10-py3-none-any.whl.metadata (6.7 kB)
Collecting interrogate (from id==1.4.0)
  Using cached interrogate-1.7.0-py3-none-any.whl.metadata (37 kB)
Collecting mypy (from id==1.4.0)
  Using cached mypy-1.11.2-py3-none-any.whl.metadata (1.9 kB)
Collecting ruff<0.6.8 (from id==1.4.0)
  Using cached ruff-0.6.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (25 kB)
Collecting types-requests (from id==1.4.0)
  Using cached types_requests-2.32.0.20240914-py3-none-any.whl.metadata (1.9 kB)
Collecting pytest (from id==1.4.0)
  Using cached pytest-8.3.3-py3-none-any.whl.metadata (7.5 kB)
Collecting pytest-cov (from id==1.4.0)
  Using cached pytest_cov-5.0.0-py3-none-any.whl.metadata (27 kB)
Collecting pretend (from id==1.4.0)
  Using cached pretend-1.0.9-py2.py3-none-any.whl.metadata (4.4 kB)
Collecting coverage[toml] (from id==1.4.0)
  Using cached coverage-7.6.1-pp38.pp39.pp310-none-any.whl.metadata (8.3 kB)
Collecting annotated-types>=0.6.0 (from pydantic->id==1.4.0)
  Using cached annotated_types-0.7.0-py3-none-any.whl.metadata (15 kB)
Collecting pydantic-core==2.23.4 (from pydantic->id==1.4.0)
  Downloading pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB)
Collecting typing-extensions>=4.6.1 (from pydantic->id==1.4.0)
  Using cached typing_extensions-4.12.2-py3-none-any.whl.metadata (3.0 kB)
Collecting charset-normalizer<4,>=2 (from requests->id==1.4.0)
  Using cached charset_normalizer-3.3.2-py3-none-any.whl.metadata (33 kB)
Collecting idna<4,>=2.5 (from requests->id==1.4.0)
  Using cached idna-3.10-py3-none-any.whl.metadata (10 kB)
Collecting urllib3<3,>=1.21.1 (from requests->id==1.4.0)
  Using cached urllib3-2.2.3-py3-none-any.whl.metadata (6.5 kB)
Collecting certifi>=2017.4.17 (from requests->id==1.4.0)
  Using cached certifi-2024.8.30-py3-none-any.whl.metadata (2.2 kB)
Collecting PyYAML>=5.3.1 (from bandit->id==1.4.0)
  Using cached pyyaml-6.0.2.tar.gz (130 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Collecting stevedore>=1.20.0 (from bandit->id==1.4.0)
  Using cached stevedore-5.3.0-py3-none-any.whl.metadata (2.3 kB)
Collecting rich (from bandit->id==1.4.0)
  Using cached rich-13.8.1-py3-none-any.whl.metadata (18 kB)
Collecting attrs (from interrogate->id==1.4.0)
  Using cached attrs-24.2.0-py3-none-any.whl.metadata (11 kB)
Collecting colorama (from interrogate->id==1.4.0)
  Using cached colorama-0.4.6-py2.py3-none-any.whl.metadata (17 kB)
Collecting py (from interrogate->id==1.4.0)
  Using cached py-1.11.0-py2.py3-none-any.whl.metadata (2.8 kB)
Collecting tabulate (from interrogate->id==1.4.0)
  Using cached tabulate-0.9.0-py3-none-any.whl.metadata (34 kB)
Collecting mypy-extensions>=1.0.0 (from mypy->id==1.4.0)
  Using cached mypy_extensions-1.0.0-py3-none-any.whl.metadata (1.1 kB)
Collecting iniconfig (from pytest->id==1.4.0)
  Using cached iniconfig-2.0.0-py3-none-any.whl.metadata (2.6 kB)
Collecting pluggy<2,>=1.5 (from pytest->id==1.4.0)
  Using cached pluggy-1.5.0-py3-none-any.whl.metadata (4.8 kB)
Collecting exceptiongroup>=1.0.0rc8 (from pytest->id==1.4.0)
  Using cached exceptiongroup-1.2.2-py3-none-any.whl.metadata (6.6 kB)
Collecting pbr>=2.0.0 (from stevedore>=1.20.0->bandit->id==1.4.0)
  Using cached pbr-6.1.0-py2.py3-none-any.whl.metadata (3.4 kB)
Collecting markdown-it-py>=2.2.0 (from rich->bandit->id==1.4.0)
  Using cached markdown_it_py-3.0.0-py3-none-any.whl.metadata (6.9 kB)
Collecting pygments<3.0.0,>=2.13.0 (from rich->bandit->id==1.4.0)
  Using cached pygments-2.18.0-py3-none-any.whl.metadata (2.5 kB)
Collecting mdurl~=0.1 (from markdown-it-py>=2.2.0->rich->bandit->id==1.4.0)
  Using cached mdurl-0.1.2-py3-none-any.whl.metadata (1.6 kB)
Using cached bump-1.3.2-py3-none-any.whl (4.1 kB)
Using cached build-1.2.2-py3-none-any.whl (22 kB)
Using cached pydantic-2.9.2-py3-none-any.whl (434 kB)
Downloading pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.9/1.9 MB 9.9 MB/s eta 0:00:00
Using cached requests-2.32.3-py3-none-any.whl (64 kB)
Using cached annotated_types-0.7.0-py3-none-any.whl (13 kB)
Using cached certifi-2024.8.30-py3-none-any.whl (167 kB)
Using cached charset_normalizer-3.3.2-py3-none-any.whl (48 kB)
Using cached click-8.1.7-py3-none-any.whl (97 kB)
Using cached idna-3.10-py3-none-any.whl (70 kB)
Using cached packaging-24.1-py3-none-any.whl (53 kB)
Using cached ruff-0.6.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (10.8 MB)
Using cached tomli-2.0.1-py3-none-any.whl (12 kB)
Using cached typing_extensions-4.12.2-py3-none-any.whl (37 kB)
Using cached urllib3-2.2.3-py3-none-any.whl (126 kB)
Using cached bandit-1.7.10-py3-none-any.whl (130 kB)
Using cached first-2.0.2-py2.py3-none-any.whl (5.4 kB)
Using cached interrogate-1.7.0-py3-none-any.whl (46 kB)
Using cached mypy-1.11.2-py3-none-any.whl (2.6 MB)
Using cached pretend-1.0.9-py2.py3-none-any.whl (3.8 kB)
Using cached pyproject_hooks-1.1.0-py3-none-any.whl (9.2 kB)
Using cached pytest-8.3.3-py3-none-any.whl (342 kB)
Using cached pytest_cov-5.0.0-py3-none-any.whl (21 kB)
Using cached toml-0.10.2-py2.py3-none-any.whl (16 kB)
Using cached types_requests-2.32.0.20240914-py3-none-any.whl (15 kB)
Using cached coverage-7.6.1-pp38.pp39.pp310-none-any.whl (198 kB)
Using cached exceptiongroup-1.2.2-py3-none-any.whl (16 kB)
Using cached mypy_extensions-1.0.0-py3-none-any.whl (4.7 kB)
Using cached pluggy-1.5.0-py3-none-any.whl (20 kB)
Using cached stevedore-5.3.0-py3-none-any.whl (49 kB)
Using cached attrs-24.2.0-py3-none-any.whl (63 kB)
Using cached colorama-0.4.6-py2.py3-none-any.whl (25 kB)
Using cached iniconfig-2.0.0-py3-none-any.whl (5.9 kB)
Using cached py-1.11.0-py2.py3-none-any.whl (98 kB)
Using cached rich-13.8.1-py3-none-any.whl (241 kB)
Using cached tabulate-0.9.0-py3-none-any.whl (35 kB)
Using cached markdown_it_py-3.0.0-py3-none-any.whl (87 kB)
Using cached pbr-6.1.0-py2.py3-none-any.whl (108 kB)
Using cached pygments-2.18.0-py3-none-any.whl (1.2 MB)
Using cached mdurl-0.1.2-py3-none-any.whl (10.0 kB)
Building wheels for collected packages: id, PyYAML
  Building editable for id (pyproject.toml) ... done
  Created wheel for id: filename=id-1.4.0-py3-none-any.whl size=7210 sha256=7fd8043ceeedd120626a7dddc4bef4d9c2e21bdce18d0e963b89647c43b95f3a
  Stored in directory: /tmp/pip-ephem-wheel-cache-j9tic0_1/wheels/d1/50/4e/419c2e32aa2099f90fa357c1f33c08b51a76e014c9febf8458
  Building wheel for PyYAML (pyproject.toml) ... done
  Created wheel for PyYAML: filename=PyYAML-6.0.2-pp310-pypy310_pp73-linux_x86_64.whl size=139776 sha256=0c2e73d4614991a4ddfae8572347cea4444b9e8b4b042829bc4418113d11fc5a
  Stored in directory: /home/mgorny/.cache/pip/wheels/f1/fa/b9/e50f710a7faf331dec84bc8853e39b0f81d75a70a889641975
Successfully built id PyYAML
Installing collected packages: pretend, first, urllib3, typing-extensions, tomli, toml, tabulate, ruff, PyYAML, pyproject_hooks, pygments, py, pluggy, pbr, packaging, mypy-extensions, mdurl, iniconfig, idna, exceptiongroup, coverage, colorama, click, charset-normalizer, certifi, attrs, annotated-types, types-requests, stevedore, requests, pytest, pydantic-core, mypy, markdown-it-py, interrogate, bump, build, rich, pytest-cov, pydantic, id, bandit
Successfully installed PyYAML-6.0.2 annotated-types-0.7.0 attrs-24.2.0 bandit-1.7.10 build-1.2.2 bump-1.3.2 certifi-2024.8.30 charset-normalizer-3.3.2 click-8.1.7 colorama-0.4.6 coverage-7.6.1 exceptiongroup-1.2.2 first-2.0.2 id-1.4.0 idna-3.10 iniconfig-2.0.0 interrogate-1.7.0 markdown-it-py-3.0.0 mdurl-0.1.2 mypy-1.11.2 mypy-extensions-1.0.0 packaging-24.1 pbr-6.1.0 pluggy-1.5.0 pretend-1.0.9 py-1.11.0 pydantic-2.9.2 pydantic-core-2.23.4 pygments-2.18.0 pyproject_hooks-1.1.0 pytest-8.3.3 pytest-cov-5.0.0 requests-2.32.3 rich-13.8.1 ruff-0.6.7 stevedore-5.3.0 tabulate-0.9.0 toml-0.10.2 tomli-2.0.1 types-requests-2.32.0.20240914 typing-extensions-4.12.2 urllib3-2.2.3
. env/bin/activate && \
    pytest --cov=id test/unit  && \
    python -m coverage report -m 
========================================================= test session starts =========================================================
platform linux -- Python 3.10.14[pypy-7.3.17-final], pytest-8.3.3, pluggy-1.5.0
rootdir: /tmp/id
configfile: pyproject.toml
plugins: cov-5.0.0
collected 33 items                                                                                                                    

test/unit/internal/oidc/test_ambient.py ................FFFFFF...........                                                       [100%]

============================================================== FAILURES ===============================================================
__________________________________________________________ test_gcp_bad_env ___________________________________________________________

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x00007f1fef02fad0>

    def test_gcp_bad_env(monkeypatch):
        oserror = pretend.raiser(OSError)
>       monkeypatch.setitem(ambient.__builtins__, "open", oserror)  # type: ignore

test/unit/internal/oidc/test_ambient.py:405: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.monkeypatch.MonkeyPatch object at 0x00007f1fef02fad0>, dic = <module 'builtins'>, name = 'open'
value = <function raiser.<locals>.inner at 0x00007f1fef18c2a0>

    def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None:
        """Set dictionary entry ``name`` to value."""
>       self._setitem.append((dic, name, dic.get(name, notset)))
E       AttributeError: module 'builtins' has no attribute 'get'

env/lib/pypy3.10/site-packages/_pytest/monkeypatch.py:293: AttributeError
_______________________________________________________ test_gcp_wrong_product ________________________________________________________

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x00005582ad1a13d0>

    def test_gcp_wrong_product(monkeypatch):
        stub_file = pretend.stub(
            __enter__=lambda *a: pretend.stub(read=lambda: "Unsupported Product"),
            __exit__=lambda *a: None,
        )
>       monkeypatch.setitem(ambient.__builtins__, "open", lambda fn: stub_file)  # type: ignore

test/unit/internal/oidc/test_ambient.py:423: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.monkeypatch.MonkeyPatch object at 0x00005582ad1a13d0>, dic = <module 'builtins'>, name = 'open'
value = <function test_gcp_wrong_product.<locals>.<lambda> at 0x00005582acf514c0>

    def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None:
        """Set dictionary entry ``name`` to value."""
>       self._setitem.append((dic, name, dic.get(name, notset)))
E       AttributeError: module 'builtins' has no attribute 'get'

env/lib/pypy3.10/site-packages/_pytest/monkeypatch.py:293: AttributeError
____________________________________________________ test_detect_gcp_request_fails ____________________________________________________

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x00005582ad78bef8>

    def test_detect_gcp_request_fails(monkeypatch):
        stub_file = pretend.stub(
            __enter__=lambda *a: pretend.stub(read=lambda: "Google"),
            __exit__=lambda *a: None,
        )
>       monkeypatch.setitem(ambient.__builtins__, "open", lambda fn: stub_file)  # type: ignore

test/unit/internal/oidc/test_ambient.py:444: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.monkeypatch.MonkeyPatch object at 0x00005582ad78bef8>, dic = <module 'builtins'>, name = 'open'
value = <function test_detect_gcp_request_fails.<locals>.<lambda> at 0x00005582ad62ad40>

    def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None:
        """Set dictionary entry ``name`` to value."""
>       self._setitem.append((dic, name, dic.get(name, notset)))
E       AttributeError: module 'builtins' has no attribute 'get'

env/lib/pypy3.10/site-packages/_pytest/monkeypatch.py:293: AttributeError
___________________________________________________ test_detect_gcp_request_timeout ___________________________________________________

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x00007f1ff2c17cc8>

    def test_detect_gcp_request_timeout(monkeypatch):
        stub_file = pretend.stub(
            __enter__=lambda *a: pretend.stub(read=lambda: "Google"),
            __exit__=lambda *a: None,
        )
>       monkeypatch.setitem(ambient.__builtins__, "open", lambda fn: stub_file)  # type: ignore

test/unit/internal/oidc/test_ambient.py:474: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.monkeypatch.MonkeyPatch object at 0x00007f1ff2c17cc8>, dic = <module 'builtins'>, name = 'open'
value = <function test_detect_gcp_request_timeout.<locals>.<lambda> at 0x00005582ad62b7e0>

    def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None:
        """Set dictionary entry ``name`` to value."""
>       self._setitem.append((dic, name, dic.get(name, notset)))
E       AttributeError: module 'builtins' has no attribute 'get'

env/lib/pypy3.10/site-packages/_pytest/monkeypatch.py:293: AttributeError
_______________________________________________________ test_detect_gcp[Google] _______________________________________________________

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x00007f1feee7e678>, product_name = 'Google'

    @pytest.mark.parametrize("product_name", ("Google", "Google Compute Engine"))
    def test_detect_gcp(monkeypatch, product_name):
        stub_file = pretend.stub(
            __enter__=lambda *a: pretend.stub(read=lambda: product_name),
            __exit__=lambda *a: None,
        )
>       monkeypatch.setitem(ambient.__builtins__, "open", lambda fn: stub_file)  # type: ignore

test/unit/internal/oidc/test_ambient.py:505: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.monkeypatch.MonkeyPatch object at 0x00007f1feee7e678>, dic = <module 'builtins'>, name = 'open'
value = <function test_detect_gcp.<locals>.<lambda> at 0x00007f1fef2088e0>

    def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None:
        """Set dictionary entry ``name`` to value."""
>       self._setitem.append((dic, name, dic.get(name, notset)))
E       AttributeError: module 'builtins' has no attribute 'get'

env/lib/pypy3.10/site-packages/_pytest/monkeypatch.py:293: AttributeError
_______________________________________________ test_detect_gcp[Google Compute Engine] ________________________________________________

monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x00007f1fee57e4b8>, product_name = 'Google Compute Engine'

    @pytest.mark.parametrize("product_name", ("Google", "Google Compute Engine"))
    def test_detect_gcp(monkeypatch, product_name):
        stub_file = pretend.stub(
            __enter__=lambda *a: pretend.stub(read=lambda: product_name),
            __exit__=lambda *a: None,
        )
>       monkeypatch.setitem(ambient.__builtins__, "open", lambda fn: stub_file)  # type: ignore

test/unit/internal/oidc/test_ambient.py:505: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <_pytest.monkeypatch.MonkeyPatch object at 0x00007f1fee57e4b8>, dic = <module 'builtins'>, name = 'open'
value = <function test_detect_gcp.<locals>.<lambda> at 0x00007f1ff3936700>

    def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None:
        """Set dictionary entry ``name`` to value."""
>       self._setitem.append((dic, name, dic.get(name, notset)))
E       AttributeError: module 'builtins' has no attribute 'get'

env/lib/pypy3.10/site-packages/_pytest/monkeypatch.py:293: AttributeError

---------- coverage: platform linux, python 3.10.14-final-0 ----------
Name                            Stmts   Miss  Cover
---------------------------------------------------
id/__init__.py                     23      4    83%
id/__main__.py                     30     30     0%
id/_internal/oidc/__init__.py       0      0   100%
id/_internal/oidc/ambient.py      128     20    84%
---------------------------------------------------
TOTAL                             181     54    70%

======================================================= short test summary info =======================================================
FAILED test/unit/internal/oidc/test_ambient.py::test_gcp_bad_env - AttributeError: module 'builtins' has no attribute 'get'
FAILED test/unit/internal/oidc/test_ambient.py::test_gcp_wrong_product - AttributeError: module 'builtins' has no attribute 'get'
FAILED test/unit/internal/oidc/test_ambient.py::test_detect_gcp_request_fails - AttributeError: module 'builtins' has no attribute 'get'
FAILED test/unit/internal/oidc/test_ambient.py::test_detect_gcp_request_timeout - AttributeError: module 'builtins' has no attribute 'get'
FAILED test/unit/internal/oidc/test_ambient.py::test_detect_gcp[Google] - AttributeError: module 'builtins' has no attribute 'get'
FAILED test/unit/internal/oidc/test_ambient.py::test_detect_gcp[Google Compute Engine] - AttributeError: module 'builtins' has no attribute 'get'
==================================================== 6 failed, 27 passed in 2.67s =====================================================
make: *** [Makefile:80: test] Error 1

Reproduced on top of 8dfaa83e8d21ebb97138a2d43e1b95260817f2b3.

woodruffw commented 2 weeks ago

Yep, looks like we monkeypatch open to induce some failures, so that we get 100% coverage. I suppose we could switch detect_gcp to use either a wrapper around open or a higher level API (like Path), which presumably wouldn't be as much of a patching issue for PyPy?

mgorny commented 2 weeks ago

My gut feeling is that there must be a portable way to mock it. I'll experiment with it today.

mgorny commented 2 weeks ago

FWICS, you can patch it using unittest.mock directly, but for some reason pytest doesn't seem to wrap the plain patch call, e.g.:

diff --git a/test/unit/internal/oidc/test_ambient.py b/test/unit/internal/oidc/test_ambient.py
index 0d5d589..0c532c6 100644
--- a/test/unit/internal/oidc/test_ambient.py
+++ b/test/unit/internal/oidc/test_ambient.py
@@ -16,6 +16,7 @@ import json

 import pretend
 import pytest
+from unittest.mock import patch
 from requests import HTTPError, Timeout

 from id import detect_credential
@@ -402,17 +403,18 @@ def test_gcp_impersonation_succeeds(monkeypatch):

 def test_gcp_bad_env(monkeypatch):
     oserror = pretend.raiser(OSError)
-    monkeypatch.setitem(ambient.__builtins__, "open", oserror)  # type: ignore
+    #monkeypatch.setitem(ambient.__builtins__, "open", oserror)  # type: ignore

     logger = pretend.stub(debug=pretend.call_recorder(lambda s: None))
     monkeypatch.setattr(ambient, "logger", logger)

-    assert ambient.detect_gcp("some-audience") is None
-    assert logger.debug.calls == [
-        pretend.call("GCP: looking for OIDC credentials"),
-        pretend.call("GCP: GOOGLE_SERVICE_ACCOUNT_NAME not set; skipping impersonation"),
-        pretend.call("GCP: environment doesn't have GCP product name file; giving up"),
-    ]
+    with patch("id._internal.oidc.ambient.open", oserror):
+        assert ambient.detect_gcp("some-audience") is None
+        assert logger.debug.calls == [
+            pretend.call("GCP: looking for OIDC credentials"),
+            pretend.call("GCP: GOOGLE_SERVICE_ACCOUNT_NAME not set; skipping impersonation"),

I can make a (cleaner) pull request if you wish. That said, pytest docs advise against patching open() as it can apparently conflict with pytest internals.

woodruffw commented 2 weeks ago

Thanks for looking into it. Yeah, I think we should probably revisit our use of open(...) rather than risk future issues with pytest. I'll look at a separate PR for that today.