diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d50fe5bee..ac318b255 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: - id: tox-ini-fmt args: ["-p", "fix"] - repo: https://github.com/tox-dev/pyproject-fmt - rev: "0.12.0" + rev: "0.12.1" hooks: - id: pyproject-fmt additional_dependencies: ["tox>=4.6"] @@ -24,7 +24,7 @@ repos: - id: prettier args: ["--print-width=120", "--prose-wrap=always"] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.0.272" + rev: "v0.0.275" hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/docs/changelog/2592.bugfix.rst b/docs/changelog/2592.bugfix.rst new file mode 100644 index 000000000..d861294da --- /dev/null +++ b/docs/changelog/2592.bugfix.rst @@ -0,0 +1 @@ +Fix test suite - by :user:`gaborbernat`. diff --git a/docs/render_cli.py b/docs/render_cli.py index ecf4ec885..557bb80d6 100644 --- a/docs/render_cli.py +++ b/docs/render_cli.py @@ -3,6 +3,7 @@ from argparse import SUPPRESS from collections import namedtuple from contextlib import contextmanager +from typing import Any, ClassVar from docutils import nodes as n from docutils.parsers.rst.directives import unchanged_required @@ -24,8 +25,8 @@ class CliTable(SphinxDirective): - name = "table_cli" - option_spec = {"module": unchanged_required, "func": unchanged_required} + name: ClassVar[str] = "table_cli" + option_spec: ClassVar[str, Any] = {"module": unchanged_required, "func": unchanged_required} def run(self): module_name, attr_name = self.options["module"], self.options["func"] @@ -109,7 +110,7 @@ def _build_table(self, options, title, description): options_group += body return table - plugins = { + plugins: ClassVar[dict[str, str]] = { "creator": "virtualenv.create", "seed": "virtualenv.seed", "activators": "virtualenv.activate", diff --git a/src/virtualenv/activation/via_template.py b/src/virtualenv/activation/via_template.py index 994876c32..239318cde 100644 --- a/src/virtualenv/activation/via_template.py +++ b/src/virtualenv/activation/via_template.py @@ -27,7 +27,7 @@ def generate(self, creator): generated = self._generate(replacements, self.templates(), dest_folder, creator) if self.flag_prompt is not None: creator.pyenv_cfg["prompt"] = self.flag_prompt - return generated # noqa: RET504 + return generated def replacements(self, creator, dest_folder): # noqa: ARG002 return { diff --git a/src/virtualenv/config/convert.py b/src/virtualenv/config/convert.py index a97745608..7f1e9975a 100644 --- a/src/virtualenv/config/convert.py +++ b/src/virtualenv/config/convert.py @@ -2,6 +2,7 @@ import logging import os +from typing import ClassVar class TypeData: @@ -17,7 +18,7 @@ def convert(self, value): class BoolType(TypeData): - BOOLEAN_STATES = { + BOOLEAN_STATES: ClassVar[dict[str, bool]] = { "1": True, "yes": True, "true": True, diff --git a/src/virtualenv/config/ini.py b/src/virtualenv/config/ini.py index e333eefba..cd6ecf504 100644 --- a/src/virtualenv/config/ini.py +++ b/src/virtualenv/config/ini.py @@ -4,6 +4,7 @@ import os from configparser import ConfigParser from pathlib import Path +from typing import ClassVar from platformdirs import user_config_dir @@ -11,8 +12,8 @@ class IniConfig: - VIRTUALENV_CONFIG_FILE_ENV_VAR = "VIRTUALENV_CONFIG_FILE" - STATE = {None: "failed to parse", True: "active", False: "missing"} + VIRTUALENV_CONFIG_FILE_ENV_VAR: ClassVar[str] = "VIRTUALENV_CONFIG_FILE" + STATE: ClassVar[dict[bool | None, str]] = {None: "failed to parse", True: "active", False: "missing"} section = "virtualenv" diff --git a/src/virtualenv/create/via_global_ref/_virtualenv.py b/src/virtualenv/create/via_global_ref/_virtualenv.py index e328be6a3..17f73b1d4 100644 --- a/src/virtualenv/create/via_global_ref/_virtualenv.py +++ b/src/virtualenv/create/via_global_ref/_virtualenv.py @@ -48,7 +48,7 @@ class _Finder: # lock[0] is threading.Lock(), but initialized lazily to avoid importing threading very early at startup, # because there are gevent-based applications that need to be first to import threading by themselves. # See https://github.com/pypa/virtualenv/issues/1895 for details. - lock = [] + lock = [] # noqa: RUF012 def find_spec(self, fullname, path, target=None): # noqa: ARG002 if fullname in _DISTUTILS_PATCH and self.fullname is None: diff --git a/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py b/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py index 598abfaa8..42c191fcb 100644 --- a/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py +++ b/src/virtualenv/create/via_global_ref/builtin/cpython/mac_os.py @@ -74,7 +74,7 @@ def sources(cls, interpreter): @property def reload_code(self): result = super().reload_code - result = dedent( + return dedent( f""" # the bundled site.py always adds the global site package if we're on python framework build, escape this import sys @@ -86,7 +86,6 @@ def reload_code(self): sys._framework = before """, ) - return result def fix_mach_o(exe, current, new, max_size): diff --git a/src/virtualenv/discovery/py_info.py b/src/virtualenv/discovery/py_info.py index 85f563761..0f8258fa1 100644 --- a/src/virtualenv/discovery/py_info.py +++ b/src/virtualenv/discovery/py_info.py @@ -434,7 +434,7 @@ def _resolve_to_system(cls, app_data, target): target.executable = start_executable return target - _cache_exe_discovery = {} + _cache_exe_discovery = {} # noqa: RUF012 def discover_exe(self, app_data, prefix, exact=True, env=None): # noqa: FBT002 key = prefix, exact diff --git a/tests/conftest.py b/tests/conftest.py index 4d21fccc4..a7aca5668 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,6 +7,7 @@ from contextlib import contextmanager from functools import partial from pathlib import Path +from typing import ClassVar import pytest @@ -24,7 +25,7 @@ def pytest_configure(config): """Ensure randomly is called before we re-order""" manager = config.pluginmanager - order = manager.hook.pytest_collection_modifyitems._nonwrappers # noqa: SLF001 + order = manager.hook.pytest_collection_modifyitems._hookimpls # noqa: SLF001 dest = next((i for i, p in enumerate(order) if p.plugin is manager.getplugin("randomly")), None) if dest is not None: from_pos = next(i for i, p in enumerate(order) if p.plugin is manager.getplugin(__file__)) @@ -242,8 +243,10 @@ def _no_coverage(): import coverage class EnableCoverage: - _COV_FILE = Path(coverage.__file__) - _ROOT_COV_FILES_AND_FOLDERS = [i for i in _COV_FILE.parents[1].iterdir() if i.name.startswith("coverage")] + _COV_FILE: ClassVar[Path] = Path(coverage.__file__) + _ROOT_COV_FILES_AND_FOLDERS: ClassVar[list[Path]] = [ + i for i in _COV_FILE.parents[1].iterdir() if i.name.startswith("coverage") + ] def __init__(self, link) -> None: self.link = link diff --git a/tests/unit/config/test_ini.py b/tests/unit/config/test_ini.py index e7fde8274..d3608a6f5 100644 --- a/tests/unit/config/test_ini.py +++ b/tests/unit/config/test_ini.py @@ -1,14 +1,16 @@ from __future__ import annotations +import sys from textwrap import dedent import pytest -from virtualenv.info import fs_supports_symlink +from virtualenv.info import IS_PYPY, IS_WIN, fs_supports_symlink from virtualenv.run import session_via_cli @pytest.mark.skipif(not fs_supports_symlink(), reason="symlink is not supported") +@pytest.mark.xfail(IS_PYPY and IS_WIN and sys.version_info[0:2] == (3, 9), reason="symlink is not supported") def test_ini_can_be_overwritten_by_flag(tmp_path, monkeypatch): custom_ini = tmp_path / "conf.ini" custom_ini.write_text( diff --git a/tests/unit/discovery/py_info/test_py_info.py b/tests/unit/discovery/py_info/test_py_info.py index 260c95ee9..89c98dfc4 100644 --- a/tests/unit/discovery/py_info/test_py_info.py +++ b/tests/unit/discovery/py_info/test_py_info.py @@ -17,7 +17,7 @@ from virtualenv.discovery import cached_py_info from virtualenv.discovery.py_info import PythonInfo, VersionInfo from virtualenv.discovery.py_spec import PythonSpec -from virtualenv.info import IS_PYPY, fs_supports_symlink +from virtualenv.info import IS_PYPY, IS_WIN, fs_supports_symlink CURRENT = PythonInfo.current_system() @@ -144,6 +144,7 @@ def test_py_info_cache_clear(mocker, session_app_data): assert spy.call_count >= 2 * count +@pytest.mark.xfail(IS_PYPY and IS_WIN and sys.version_info[0:2] == (3, 9), reason="symlink is not supported") @pytest.mark.skipif(not fs_supports_symlink(), reason="symlink is not supported") def test_py_info_cached_symlink(mocker, tmp_path, session_app_data): spy = mocker.spy(cached_py_info, "_run_subprocess") diff --git a/tests/unit/seed/wheels/test_periodic_update.py b/tests/unit/seed/wheels/test_periodic_update.py index e4988b5cf..fe563a232 100644 --- a/tests/unit/seed/wheels/test_periodic_update.py +++ b/tests/unit/seed/wheels/test_periodic_update.py @@ -502,8 +502,9 @@ def _download_wheel( # noqa: PLR0913 def test_new_version_eq(): - value = NewVersion("a", datetime.now(tz=timezone.utc), datetime.now(tz=timezone.utc), "periodic") - assert value == value + now = datetime.now(tz=timezone.utc) + value = NewVersion("a", now, now, "periodic") + assert value == NewVersion("a", now, now, "periodic") def test_new_version_ne():