Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-pytest-mypy-plugins for
openSUSE:Factory checked in at 2026-07-17 18:47:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pytest-mypy-plugins (Old)
and /work/SRC/openSUSE:Factory/.python-pytest-mypy-plugins.new.24530 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pytest-mypy-plugins"
Fri Jul 17 18:47:52 2026 rev:2 rq:1366401 version:4.0.3
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-pytest-mypy-plugins/python-pytest-mypy-plugins.changes
2025-05-20 09:36:14.264559809 +0200
+++
/work/SRC/openSUSE:Factory/.python-pytest-mypy-plugins.new.24530/python-pytest-mypy-plugins.changes
2026-07-17 18:48:43.227715447 +0200
@@ -1,0 +2,18 @@
+Thu Jul 16 08:25:41 UTC 2026 - Markéta Machová <[email protected]>
+
+- Update to version 4.0.3
+ * Adds official python3.14 support
+ * Allow --mypy-testing-base to be relative by resolving
+ execution_path before cd
+ * Breaking: Errors are now ignored in site-packages by default.
+ The --mypy-only-local-stub flag has been removed and replaced
+ with --mypy-no-silence-site-packages which can be used to
+ restore the previous behavior if needed.
+ * Breaking: When running in a subprocess (the default),
+ PYTHONPATH is no longer set. With the above change, violations
+ would still be raised in the main module for a test case, but
+ those that were flagged in imported modules would no longer be
+ raised.
+- Skip broken tests
+
+-------------------------------------------------------------------
Old:
----
pytest_mypy_plugins-3.2.0.tar.gz
New:
----
_scmsync.obsinfo
build.specials.obscpio
pytest_mypy_plugins-4.0.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pytest-mypy-plugins.spec ++++++
--- /var/tmp/diff_new_pack.zMLyYe/_old 2026-07-17 18:48:44.707765435 +0200
+++ /var/tmp/diff_new_pack.zMLyYe/_new 2026-07-17 18:48:44.707765435 +0200
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-pytest-mypy-plugins
-Version: 3.2.0
+Version: 4.0.3
Release: 0
Summary: pytest plugin for mypy plugins
License: MIT
@@ -67,7 +67,10 @@
%check
export PYTHONPATH=%{buildroot}:$PYTHONPATH
-%pytest
+# mypy cache does not work in OBS environment
+rm pytest_mypy_plugins/tests/test_mypy_cache.py
+# test_no_silence_site_packages_only and
test_no_silence_site_packages_and_modify_pythonpath fail with mypy 2.3.0 (no
idea why it surfaces with our mypy):
https://github.com/typeddjango/pytest-mypy-plugins/pull/201
+%pytest -k "not test_no_silence_site_packages"
%files %{python_files}
%{python_sitelib}/pytest_mypy_plugins
++++++ _scmsync.obsinfo ++++++
mtime: 1784290867
commit: cf28e2a15f17807c4f0348b1d48178fe8f2809c54129239f499cc5590a1af842
url: https://src.opensuse.org/python-pytest/python-pytest-mypy-plugins
revision: cf28e2a15f17807c4f0348b1d48178fe8f2809c54129239f499cc5590a1af842
projectscmsync: https://src.opensuse.org/python-pytest/_ObsPrj.git
++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore 1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore 2026-07-17 14:21:07.000000000 +0200
@@ -0,0 +1 @@
+.osc
++++++ pytest_mypy_plugins-3.2.0.tar.gz -> pytest_mypy_plugins-4.0.3.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_mypy_plugins-3.2.0/PKG-INFO
new/pytest_mypy_plugins-4.0.3/PKG-INFO
--- old/pytest_mypy_plugins-3.2.0/PKG-INFO 2024-12-21 21:11:15.534639800
+0100
+++ new/pytest_mypy_plugins-4.0.3/PKG-INFO 2026-05-14 09:43:07.924585000
+0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
Name: pytest-mypy-plugins
-Version: 3.2.0
+Version: 4.0.3
Summary: pytest plugin for writing tests for mypy plugins
Home-page: https://github.com/TypedDjango/pytest-mypy-plugins
Author: Maksim Kurnikov
@@ -8,16 +8,16 @@
Maintainer: Nikita Sobolev
Maintainer-email: [email protected]
License: MIT
-Classifier: Development Status :: 4 - Beta
+Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
-Requires-Python: >=3.9
+Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Jinja2
@@ -29,6 +29,19 @@
Requires-Dist: pyyaml
Requires-Dist: regex
Requires-Dist: tomlkit>=0.11
+Dynamic: author
+Dynamic: author-email
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: maintainer
+Dynamic: maintainer-email
+Dynamic: requires-dist
+Dynamic: requires-python
+Dynamic: summary
<img src="http://mypy-lang.org/static/mypy_light.svg" alt="mypy logo"
width="300px"/>
@@ -241,8 +254,12 @@
--mypy-extension-hook=MYPY_EXTENSION_HOOK
Fully qualified path to the extension hook function,
in case you need custom yaml keys. Has to be top-level
- --mypy-only-local-stub
- mypy will ignore errors from site-packages
+ --mypy-no-silence-site-packages
+ mypy will not silence errors from site-packages
+ --mypy-modify-pythonpath
+ When running mypy in a subprocess, modify `PYTHONPATH`
+ to force packages to be treated as site-packages.
+ Incompatible with `--mypy-same-process`
--mypy-closed-schema
Use closed schema to validate YAML test cases,
which won't allow any extra keys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_mypy_plugins-3.2.0/README.md
new/pytest_mypy_plugins-4.0.3/README.md
--- old/pytest_mypy_plugins-3.2.0/README.md 2024-12-21 20:37:31.000000000
+0100
+++ new/pytest_mypy_plugins-4.0.3/README.md 2026-05-14 09:40:55.000000000
+0200
@@ -209,8 +209,12 @@
--mypy-extension-hook=MYPY_EXTENSION_HOOK
Fully qualified path to the extension hook function,
in case you need custom yaml keys. Has to be top-level
- --mypy-only-local-stub
- mypy will ignore errors from site-packages
+ --mypy-no-silence-site-packages
+ mypy will not silence errors from site-packages
+ --mypy-modify-pythonpath
+ When running mypy in a subprocess, modify `PYTHONPATH`
+ to force packages to be treated as site-packages.
+ Incompatible with `--mypy-same-process`
--mypy-closed-schema
Use closed schema to validate YAML test cases,
which won't allow any extra keys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_mypy_plugins-3.2.0/pyproject.toml
new/pytest_mypy_plugins-4.0.3/pyproject.toml
--- old/pytest_mypy_plugins-3.2.0/pyproject.toml 2024-12-21
21:10:55.000000000 +0100
+++ new/pytest_mypy_plugins-4.0.3/pyproject.toml 2026-05-14
09:40:55.000000000 +0200
@@ -9,7 +9,7 @@
[tool.black]
line-length = 120
-target-version = ["py39"]
+target-version = ["py310"]
[tool.isort]
include_trailing_comma = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/collect.py
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/collect.py
--- old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/collect.py
2024-12-21 21:10:55.000000000 +0100
+++ new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/collect.py
2026-05-14 09:40:55.000000000 +0200
@@ -99,7 +99,8 @@
for title_node, _contents_node in node.value:
if title_node.value == "main":
starting_line = title_node.start_mark.line + 1
- mapping["__line__"] = starting_line
+ if "case" in mapping:
+ mapping["__line__"] = starting_line
return mapping
@@ -204,9 +205,14 @@
"Has to be top-level.",
)
group.addoption(
- "--mypy-only-local-stub",
+ "--mypy-no-silence-site-packages",
action="store_true",
- help="mypy will ignore errors from site-packages",
+ help="mypy will not silence errors from site-packages",
+ )
+ group.addoption(
+ "--mypy-modify-pythonpath",
+ action="store_true",
+ help="When running mypy in a subprocess, modify `PYTHONPATH` to force
packages to be treated as site-packages. Incompatible with
`--mypy-same-process`",
)
group.addoption(
"--mypy-closed-schema",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/configs.py
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/configs.py
--- old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/configs.py
2024-12-21 20:37:31.000000000 +0100
+++ new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/configs.py
2026-05-14 09:40:55.000000000 +0200
@@ -32,11 +32,11 @@
with open(base_pyproject_toml_fpath) as f:
toml_config = tomlkit.parse(f.read())
else:
- # Emtpy document with `[tool.mypy` empty table,
+ # Empty document with `[tool.mypy]` empty table,
# useful for overrides further.
toml_config = tomlkit.document()
- if "tool" not in toml_config or "mypy" not in toml_config["tool"]: #
type: ignore[operator]
+ if "tool" not in toml_config or "mypy" not in toml_config["tool"]:
tool = tomlkit.table(is_super_table=True)
tool.append("mypy", tomlkit.table())
toml_config.append("tool", tool)
@@ -46,15 +46,15 @@
additional_mypy_config =
f"{_TOML_TABLE_NAME}\n{dedent(additional_mypy_config)}"
additional_data = tomlkit.parse(additional_mypy_config)
- toml_config["tool"]["mypy"].update( # type: ignore[index, union-attr]
- additional_data["tool"]["mypy"].value.items(), # type:
ignore[index]
+ toml_config["tool"]["mypy"].update(
+ additional_data["tool"]["mypy"].value.items(),
)
mypy_config_file_path = execution_path / "pyproject.toml"
with mypy_config_file_path.open("w") as f:
# We don't want the whole config file, because it can contain
# other sections like `[tool.isort]`, we only need `[tool.mypy]` part.
- tool_mypy = toml_config["tool"]["mypy"] # type: ignore[index]
+ tool_mypy = toml_config["tool"]["mypy"]
# construct toml output
min_toml = tomlkit.document()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/item.py
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/item.py
--- old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/item.py 2024-12-21
20:55:06.000000000 +0100
+++ new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/item.py 2026-05-14
09:40:55.000000000 +0200
@@ -1,3 +1,4 @@
+import glob
import importlib
import io
import os
@@ -27,6 +28,7 @@
from mypy import build
from mypy.fscache import FileSystemCache
from mypy.main import process_options
+from mypy.metastore import FilesystemMetadataStore, MetadataStore,
SqliteMetadataStore
from pytest_mypy_plugins import configs, utils
from pytest_mypy_plugins.collect import File, YamlTestFile
@@ -137,17 +139,20 @@
class MypyExecutor:
def __init__(
self,
+ *,
same_process: bool,
rootdir: Union[Path, None],
execution_path: Path,
environment_variables: Dict[str, Any],
mypy_executable: str,
+ modify_pythonpath: bool,
) -> None:
self.rootdir = rootdir
self.same_process = same_process
self.execution_path = execution_path
self.mypy_executable = mypy_executable
self.environment_variables = environment_variables
+ self.modify_pythonpath = modify_pythonpath
def execute(self, mypy_cmd_options: List[str]) -> Tuple[int, Tuple[str,
str]]:
# Returns (returncode, (stdout, stderr))
@@ -157,8 +162,10 @@
return self._typecheck_in_new_subprocess(mypy_cmd_options)
def _typecheck_in_new_subprocess(self, mypy_cmd_options: List[Any]) ->
Tuple[int, Tuple[str, str]]:
- # add current directory to path
- self._collect_python_path(self.rootdir)
+ if self.modify_pythonpath:
+ # add current directory to path
+ self._collect_python_path(self.rootdir)
+
# adding proper MYPYPATH variable
self._collect_mypy_path(self.rootdir)
@@ -263,7 +270,7 @@
disable_cache: bool,
mypy_executor: MypyExecutor,
output_checker: OutputChecker,
- test_only_local_stub: bool,
+ no_silence_site_packages: bool,
incremental_cache_dir: str,
) -> None:
self.files = files
@@ -273,7 +280,7 @@
self.mypy_executor = mypy_executor
self.disable_cache = disable_cache
self.output_checker = output_checker
- self.test_only_local_stub = test_only_local_stub
+ self.no_silence_site_packages = no_silence_site_packages
self.incremental_cache_dir = incremental_cache_dir
def run(self) -> None:
@@ -301,7 +308,7 @@
"--no-pretty",
"--hide-error-context",
]
- if not self.test_only_local_stub:
+ if self.no_silence_site_packages:
mypy_cmd_options.append("--no-silence-site-packages")
if not self.disable_cache:
mypy_cmd_options.extend(["--cache-dir",
self.incremental_cache_dir])
@@ -338,7 +345,8 @@
self.additional_mypy_config = mypy_config
self.parsed_test_data = parsed_test_data
self.same_process = self.config.option.mypy_same_process
- self.test_only_local_stub = self.config.option.mypy_only_local_stub
+ self.modify_pythonpath = self.config.option.mypy_modify_pythonpath
+ self.no_silence_site_packages =
self.config.option.mypy_no_silence_site_packages
# config parameters
self.root_directory = self.config.option.mypy_testing_base
@@ -358,25 +366,68 @@
self.incremental_cache_dir = os.path.join(self.root_directory,
".mypy_cache")
def remove_cache_files(self, fpath_no_suffix: Path) -> None:
- cache_file = Path(self.incremental_cache_dir)
- cache_file /= ".".join([str(part) for part in sys.version_info[:2]])
- for part in fpath_no_suffix.parts:
- cache_file /= part
-
- data_json_file = cache_file.with_suffix(".data.json")
- if data_json_file.exists():
- data_json_file.unlink()
- meta_json_file = cache_file.with_suffix(".meta.json")
- if meta_json_file.exists():
- meta_json_file.unlink()
+ cache_dir = os.path.join(
+ self.incremental_cache_dir,
+ ".".join([str(part) for part in sys.version_info[:2]]),
+ )
+ if not os.path.isdir(cache_dir):
+ return
- for parent_dir in cache_file.parents:
+ # Build entry names to remove for each path component so
namespace-package
+ # cache entries are also cleaned (e.g. "pkg.*", "pkg/sub.*",
"pkg/sub/mod.*").
+ suffixes = (
+ ".meta.json",
+ ".data.json",
+ ".err.json",
+ ".meta.ff",
+ ".data.ff",
+ ".err.ff",
+ # mypy >= 2.0 also writes a `.meta_ex` companion file
+ ".meta_ex.json",
+ ".meta_ex.ff",
+ )
+ entries: list[str] = []
+ accumulated = ""
+ for i, part in enumerate(fpath_no_suffix.parts):
if (
- parent_dir.exists()
- and len(list(parent_dir.iterdir())) == 0
- and str(self.incremental_cache_dir) in str(parent_dir)
+ i == 0
+ and part.endswith("-stubs")
+ and os.path.isdir(os.path.join(cache_dir,
part.removesuffix("-stubs")))
):
- parent_dir.rmdir()
+ part = part.removesuffix("-stubs")
+ accumulated = f"{accumulated}/{part}" if accumulated else part
+ entries.extend(accumulated + s for s in suffixes)
+
+ stores: list[MetadataStore] = []
+
+ # mypy >= 2.0 shards the sqlite cache across `cache.{i}.db` files
instead of one `cache.db` file
+ # https://github.com/python/mypy/pull/21292
+ shard_dbs = glob.glob(os.path.join(cache_dir, "cache.*.db"))
+ if shard_dbs:
+ try:
+ # `num_shards` was added in mypy 2.0; pinned lint mypy is
older.
+ stores.append(SqliteMetadataStore(cache_dir,
num_shards=len(shard_dbs))) # type: ignore[call-arg]
+ except TypeError:
+ # For backward compatibility with `SqliteMetadataStore` with
no `num_shards` arg.
+ stores.append(SqliteMetadataStore(cache_dir))
+ elif os.path.isfile(os.path.join(cache_dir, "cache.db")):
+ stores.append(SqliteMetadataStore(cache_dir))
+ stores.append(FilesystemMetadataStore(cache_dir))
+
+ for store in stores:
+ try:
+ for entry in entries:
+ try:
+ store.remove(entry)
+ except FileNotFoundError:
+ pass
+ store.commit()
+ finally:
+ # ``MetadataStore.close`` was added in mypy 1.20; guard for
older
+ # mypy versions that are still within our supported range
(>=1.3).
+ close = getattr(store, "close", None)
+ if close is not None:
+ close()
def execute_extension_hook(self) -> None:
extension_hook_fqname = self.config.option.mypy_extension_hook
@@ -406,7 +457,7 @@
):
self.execute_extension_hook()
- execution_path = Path(temp_dir.name)
+ execution_path = Path(temp_dir.name).absolute()
with utils.cd(execution_path):
mypy_executor = MypyExecutor(
same_process=self.same_process,
@@ -414,6 +465,7 @@
rootdir=rootdir,
environment_variables=self.environment_variables,
mypy_executable=mypy_executable,
+ modify_pythonpath=self.modify_pythonpath,
)
output_checker = OutputChecker(
@@ -428,12 +480,12 @@
disable_cache=self.disable_cache,
mypy_executor=mypy_executor,
output_checker=output_checker,
- test_only_local_stub=self.test_only_local_stub,
+ no_silence_site_packages=self.no_silence_site_packages,
incremental_cache_dir=self.incremental_cache_dir,
).run()
finally:
temp_dir.cleanup()
- # remove created modules
+ # remove created modules from the shared cache
if not self.disable_cache:
for file in self.files:
path = Path(file.path)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test-parametrized.yml
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test-parametrized.yml
---
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test-parametrized.yml
2024-12-21 20:37:31.000000000 +0100
+++
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test-parametrized.yml
2026-05-14 09:40:55.000000000 +0200
@@ -1,9 +1,11 @@
- case: only_main
parametrized:
- a: 1
- revealed_type: builtins.int
+ revealed_type: int
- a: 1.0
- revealed_type: builtins.float
+ revealed_type: float
+ - a: {a: "test"}
+ revealed_type: dict[str, str]
main: |
a = {{ a }}
reveal_type(a) # N: Revealed type is "{{ revealed_type }}"
@@ -32,9 +34,9 @@
- case: with_out
parametrized:
- what: cat
- rt: builtins.str
+ rt: str
- what: dog
- rt: builtins.str
+ rt: str
main: |
animal = '{{ what }}'
reveal_type(animal)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test-regex-assertions.yml
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test-regex-assertions.yml
---
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test-regex-assertions.yml
2024-12-21 20:37:31.000000000 +0100
+++
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test-regex-assertions.yml
2026-05-14 09:40:55.000000000 +0200
@@ -4,7 +4,7 @@
a = 1
b = 'hello'
- reveal_type(a) # N: Revealed type is "builtins.int"
+ reveal_type(a) # N: Revealed type is "int"
reveal_type(b) # N: .*str.*
- case: expected_message_regex_with_out
@@ -61,7 +61,7 @@
def foo(bar: str, ham: int = 42) -> Set[Union[str, int]]:
return {bar, ham}
- reveal_type(foo) # NR: Revealed type is "def \(bar: builtins\.str, ham:
builtins\.int =\) -> .*"
+ reveal_type(foo) # NR: Revealed type is "def \(bar: str, ham: int =\) ->
.*"
- case: regex_against_callable_out
regex: yes
@@ -72,4 +72,4 @@
return {bar, ham}
reveal_type(foo)
out: |
- main:5: note: Revealed type is "def \(bar: builtins\.str, ham:
builtins\.int =\) -> .*"
+ main:5: note: Revealed type is "def \(bar: str, ham: int =\) -> .*"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test-simple-cases.yml
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test-simple-cases.yml
---
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test-simple-cases.yml
2024-12-21 20:37:31.000000000 +0100
+++
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test-simple-cases.yml
2026-05-14 09:40:55.000000000 +0200
@@ -6,8 +6,8 @@
class MyClass:
pass
- reveal_type(a) # N: Revealed type is "builtins.int"
- reveal_type(b) # N: Revealed type is "builtins.str"
+ reveal_type(a) # N: Revealed type is "int"
+ reveal_type(b) # N: Revealed type is "str"
- case: revealed_type_with_environment
@@ -19,8 +19,8 @@
b = 'hello'
- reveal_type(a) # N: Revealed type is "builtins.int"
- reveal_type(b) # N: Revealed type is "builtins.str"
+ reveal_type(a) # N: Revealed type is "int"
+ reveal_type(b) # N: Revealed type is "str"
env:
- DJANGO_SETTINGS_MODULE=mysettings
@@ -28,7 +28,7 @@
- case: revealed_type_with_disabled_cache
main: |
a = 1
- reveal_type(a) # N: Revealed type is "builtins.int"
+ reveal_type(a) # N: Revealed type is "int"
disable_cache: true
@@ -37,13 +37,13 @@
a = 1
reveal_type(a)
out: |
- main:2: note: Revealed type is "builtins.int"
+ main:2: note: Revealed type is "int"
- case: create_files
main: |
a = 1
- reveal_type(a) # N: Revealed type is "builtins.int"
+ reveal_type(a) # N: Revealed type is "int"
files:
- path: myapp/__init__.py
- path: myapp/models.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test_mypy_cache.py
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test_mypy_cache.py
--- old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test_mypy_cache.py
1970-01-01 01:00:00.000000000 +0100
+++ new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test_mypy_cache.py
2026-05-14 09:40:55.000000000 +0200
@@ -0,0 +1,242 @@
+import glob
+import os
+import subprocess
+from collections.abc import Generator
+from pathlib import Path
+from sys import version_info
+from tempfile import TemporaryDirectory
+
+import pytest
+from mypy.metastore import FilesystemMetadataStore, MetadataStore,
SqliteMetadataStore
+
+
+def test_non_test_case_files_remain(temp_dir: Path) -> None:
+ """
+ Tests that cache files not associated with ``files`` in a test case do not
get removed.
+
+ Assumes that cache files will be generated for typeshed's ``builtins.pyi``
when running any test case.
+ """
+
+ cache_dir = temp_dir / ".mypy_cache" /
f"{version_info[0]}.{version_info[1]}"
+ # pytest and mypy hasn't been run yet, so no cache should exist
+ assert not cache_dir.is_dir()
+
+ make_yaml_test_file(
+ temp_dir,
+ """
+- case: test_non_test_case_files_cache_files_remain
+ main: |
+ """,
+ )
+ res = subprocess.run(
+ ["pytest", f"--mypy-testing-base={temp_dir}"], cwd=temp_dir,
stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
+ )
+
+ # pytest was invoked correctly and there are no failures unrelated to tests
+ assert res.returncode in (pytest.ExitCode.OK, pytest.ExitCode.TESTS_FAILED)
+ # Cache files should not be deleted
+ assert get_created_cache_files(cache_dir, ("builtins",))
+
+
+CACHE_FILES_REMOVED_TEST_DATA = {
+ "single_module_distribution": (
+ """
+- case: single_module_distribution
+ main: |
+ import my_mod
+ files:
+ - path: my_mod.py
+ """,
+ ("my_mod",),
+ ),
+ "standard_package": (
+ """
+- case: standard_package
+ main: |
+ import my_pkg.my_mod
+ import my_pkg.my_subpkg.my_mod
+ files:
+ - path: my_pkg/__init__.py
+ - path: my_pkg/my_mod.py
+ - path: my_pkg/my_subpkg/__init__.py
+ - path: my_pkg/my_subpkg/my_mod.py
+ """,
+ ("my_pkg/__init__", "my_pkg/my_mod", "my_pkg/my_subpkg/__init__",
"my_pkg/my_subpkg/my_mod"),
+ ),
+ "namespace_package": (
+ """
+- case: namespace_package
+ main: |
+ import my_nspkg.my_mod
+ import my_nspkg.my_nssubpkg.my_mod
+ files:
+ - path: my_nspkg/my_mod.py
+ - path: my_nspkg/my_nssubpkg/my_mod.py
+ """,
+ ("my_nspkg", "my_nspkg/my_mod", "my_nspkg/my_nssubpkg",
"my_nspkg/my_nssubpkg/my_mod"),
+ ),
+ "standard_stub_package": (
+ """
+- case: standard_stub_package
+ main: |
+ import my_pkg.my_mod
+ import my_pkg.my_subpkg.my_mod
+ files:
+ - path: my_pkg-stubs/__init__.pyi
+ - path: my_pkg-stubs/my_mod.pyi
+ - path: my_pkg-stubs/my_subpkg/__init__.pyi
+ - path: my_pkg-stubs/my_subpkg/my_mod.pyi
+ """,
+ ("my_pkg/__init__", "my_pkg/my_mod", "my_pkg/my_subpkg/__init__",
"my_pkg/my_subpkg/my_mod"),
+ ),
+ "namespace_stub_package": (
+ """
+- case: namespace_stub_package
+ main: |
+ import my_nspkg.my_mod
+ import my_nspkg.my_nssubpkg.my_mod
+ files:
+ - path: my_nspkg-stubs/my_mod.pyi
+ - path: my_nspkg-stubs/my_nssubpkg/my_mod.pyi
+ """,
+ ("my_nspkg", "my_nspkg/my_mod", "my_nspkg/my_nssubpkg",
"my_nspkg/my_nssubpkg/my_mod"),
+ ),
+ "mixed_modules_and_packages": (
+ """
+- case: mixed_modules_and_packages
+ main: |
+ import my_mod
+ import my_pkg.my_submod
+ import my_pkg.my_nssubpkg.my_submod
+ import my_nspkg.my_submod
+ import my_nspkg.my_subpkg
+ import my_stubpkg.my_submod
+ import my_stubpkg.my_subpkg.my_submod
+ import my_nsstubpkg.my_subpkg
+ files:
+ - path: my_mod.py
+ - path: my_pkg/__init__.py
+ - path: my_pkg/my_submod.pyi
+ - path: my_pkg/my_nssubpkg/my_submod.pyi
+ - path: my_nspkg/my_submod.pyi
+ - path: my_nspkg/my_subpkg/__init__.py
+ - path: my_stubpkg-stubs/__init__.pyi
+ - path: my_stubpkg-stubs/my_submod.pyi
+ - path: my_stubpkg-stubs/my_subpkg/my_submod.pyi
+ - path: my_nsstubpkg-stubs/my_subpkg/__init__.pyi
+ """,
+ (
+ "my_mod",
+ "my_pkg/__init__",
+ "my_pkg/my_submod",
+ "my_pkg/my_nssubpkg",
+ "my_pkg/my_nssubpkg/my_submod",
+ "my_nspkg",
+ "my_nspkg/my_submod",
+ "my_nspkg/my_subpkg",
+ "my_nspkg/my_subpkg/__init__",
+ "my_stubpkg/__init__",
+ "my_stubpkg/my_submod",
+ "my_stubpkg/my_subpkg",
+ "my_stubpkg/my_subpkg/my_submod",
+ "my_nsstubpkg",
+ "my_nsstubpkg/my_subpkg/__init__",
+ ),
+ ),
+}
+
+
[email protected](
+ "mypy_cache_config",
+ [
+ pytest.param("", id="default"),
+ pytest.param("sqlite_cache = False\n", id="no-sqlite"),
+ pytest.param("fixed_format_cache = False\n", id="no-fixed-format"),
+ pytest.param("sqlite_cache = False\nfixed_format_cache = False\n",
id="legacy"),
+ ],
+)
[email protected](
+ ("contents", "module_fpaths_no_suffix"),
+ CACHE_FILES_REMOVED_TEST_DATA.values(),
+ ids=CACHE_FILES_REMOVED_TEST_DATA.keys(),
+)
+def test_cache_files_removed(
+ temp_dir: Path, contents: str, module_fpaths_no_suffix: tuple[str, ...],
mypy_cache_config: str
+) -> None:
+ """Tests that cache files associated with ``files`` in a test case get
removed"""
+
+ cache_dir = temp_dir / ".mypy_cache" /
f"{version_info[0]}.{version_info[1]}"
+ # pytest and mypy hasn't been run yet, so no cache should exist
+ assert not cache_dir.is_dir()
+
+ if mypy_cache_config:
+ config_lines = mypy_cache_config.strip().splitlines()
+ indented = "\n".join(f" {line}" for line in config_lines)
+ contents = contents.replace(" main: |", f" mypy_config:
|\n{indented}\n main: |")
+
+ make_yaml_test_file(temp_dir, contents)
+ res = subprocess.run(
+ ["pytest", f"--mypy-testing-base={temp_dir}"], cwd=temp_dir,
stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
+ )
+
+ # pytest was invoked correctly and there are no failures unrelated to tests
+ assert res.returncode in (pytest.ExitCode.OK, pytest.ExitCode.TESTS_FAILED)
+ # Cache files exist but test case cache files are removed
+ assert get_created_cache_files(cache_dir, ("builtins",))
+ assert not get_created_cache_files(cache_dir, module_fpaths_no_suffix)
+
+
[email protected]
+def temp_dir() -> Generator[Path]:
+ """
+ Create a temporary directory to run each test case in an isolated process.
+
+ Test files and the mypy cache is expected to be created in this temporary
directory, and is deleted upon test case
+ completion.
+ """
+
+ with TemporaryDirectory() as d:
+ yield Path(d)
+
+
+def make_yaml_test_file(
+ root_dir: Path,
+ contents: str,
+ /,
+ *,
+ file_base_name: str = "test-case",
+) -> str:
+ path = root_dir / f"{file_base_name}.yml"
+ path.write_text(contents)
+ return str(path)
+
+
+def get_created_cache_files(cache_dir: Path, module_rel_paths_no_suffix:
tuple[str, ...]) -> list[str]:
+ stores: list[MetadataStore] = []
+ cache_dir_str = str(cache_dir)
+ # mypy >= 2.0 shards the sqlite cache across `cache.{i}.db` files instead
of one `cache.db` file
+ shard_dbs = glob.glob(os.path.join(cache_dir_str, "cache.*.db"))
+ if shard_dbs:
+ try:
+ # `num_shards` was added in mypy 2.0; pinned lint mypy is older.
+ stores.append(SqliteMetadataStore(cache_dir_str,
num_shards=len(shard_dbs))) # type: ignore[call-arg]
+ except TypeError:
+ stores.append(SqliteMetadataStore(cache_dir_str))
+ elif (cache_dir / "cache.db").is_file():
+ stores.append(SqliteMetadataStore(cache_dir_str))
+ if cache_dir.is_dir():
+ stores.append(FilesystemMetadataStore(cache_dir_str))
+
+ created = []
+ for store in stores:
+ try:
+ for entry in store.list_all():
+ if any(os.path.normpath(entry).startswith(rel_path + ".") for
rel_path in module_rel_paths_no_suffix):
+ created.append(entry)
+ finally:
+ # See PR #188: mypy < 1.20 does not have MetadataStore.close
+ close = getattr(store, "close", None)
+ if close is not None:
+ close()
+
+ return created
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test_site_packages.py
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test_site_packages.py
---
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins/tests/test_site_packages.py
1970-01-01 01:00:00.000000000 +0100
+++
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins/tests/test_site_packages.py
2026-05-14 09:40:55.000000000 +0200
@@ -0,0 +1,161 @@
+import os.path
+import site
+import subprocess
+from pathlib import Path
+
+import pytest
+
+
+def test_default(tmp_path: Path) -> None:
+ make_yaml_test_file(
+ tmp_path,
+ """
+- case: test_non_test_case_files_cache_files_remain
+ mypy_config: |
+ strict=true
+ main: |
+ import subpkg
+
+ a: str
+ a / 2
+ files:
+ - path: subpkg.py
+ content: |
+ a: str
+ a / 2
+ out: |
+ main:4: error: Unsupported operand types for / ("str" and "int")
[operator]
+ subpkg:2: error: Unsupported operand types for / ("str" and "int")
[operator]
+ """,
+ )
+ res = subprocess.run(
+ [
+ "pytest",
+ f"--mypy-testing-base={tmp_path}",
+ ],
+ cwd=tmp_path,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.STDOUT,
+ )
+ assert res.returncode == pytest.ExitCode.OK
+
+
+def test_modify_pythonpath_only(tmp_path: Path) -> None:
+ make_yaml_test_file(
+ tmp_path,
+ """
+- case: test_non_test_case_files_cache_files_remain
+ mypy_config: |
+ strict=true
+ main: |
+ import subpkg
+
+ a: str
+ a / 2
+ files:
+ - path: subpkg.py
+ content: |
+ a: str
+ a / 2 # Modifying `PYTHONPATH` causes this to not raise an error as
expected.
+ out: |
+ main:4: error: Unsupported operand types for / ("str" and "int")
[operator]
+ """,
+ )
+ res = subprocess.run(
+ [
+ "pytest",
+ f"--mypy-testing-base={tmp_path}",
+ "--mypy-modify-pythonpath",
+ ],
+ cwd=tmp_path,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.STDOUT,
+ )
+ assert res.returncode == pytest.ExitCode.OK
+
+
+def test_no_silence_site_packages_only(tmp_path: Path) -> None:
+ make_yaml_test_file(
+ tmp_path,
+ """
+- case: test_non_test_case_files_cache_files_remain
+ mypy_config: |
+ strict=true
+ main: |
+ import subpkg
+
+ a: str
+ a / 2
+ files:
+ - path: subpkg.py
+ content: |
+ a: str
+ a / 2
+ out: |
+ {site_packages_path}/mypy/typeshed/stdlib/types.pyi:716: error: Class
cannot subclass "Any" (has type "Any") [misc]
+ main:4: error: Unsupported operand types for / ("str" and "int")
[operator]
+ subpkg:2: error: Unsupported operand types for / ("str" and "int")
[operator]
+ """,
+ )
+ res = subprocess.run(
+ [
+ "pytest",
+ f"--mypy-testing-base={tmp_path}",
+ "--mypy-no-silence-site-packages",
+ ],
+ cwd=tmp_path,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.STDOUT,
+ )
+ assert res.returncode == pytest.ExitCode.OK
+
+
+def test_no_silence_site_packages_and_modify_pythonpath(tmp_path: Path) ->
None:
+ make_yaml_test_file(
+ tmp_path,
+ """
+- case: test_non_test_case_files_cache_files_remain
+ mypy_config: |
+ strict=true
+ main: |
+ import subpkg
+
+ a: str
+ a / 2
+ files:
+ - path: subpkg.py
+ content: |
+ a: str
+ a / 2
+ out: |
+ {site_packages_path}/mypy/typeshed/stdlib/types.pyi:716: error: Class
cannot subclass "Any" (has type "Any") [misc]
+ main:4: error: Unsupported operand types for / ("str" and "int")
[operator]
+ subpkg:2: error: Unsupported operand types for / ("str" and "int")
[operator]
+ """,
+ )
+ res = subprocess.run(
+ [
+ "pytest",
+ f"--mypy-testing-base={tmp_path}",
+ "--mypy-no-silence-site-packages",
+ "--mypy-modify-pythonpath",
+ ],
+ cwd=tmp_path,
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.STDOUT,
+ )
+ assert res.returncode == pytest.ExitCode.OK
+
+
+def make_yaml_test_file(
+ root_dir: Path,
+ contents: str,
+ /,
+ *,
+ file_base_name: str = "test-case",
+) -> None:
+ output_path = root_dir.joinpath(file_base_name).with_suffix(".yml")
+ site_packages_path: Path | str = Path(site.getsitepackages()[0])
+ site_packages_path = os.path.relpath(site_packages_path, start=output_path)
+ contents = contents.format(site_packages_path=site_packages_path)
+ output_path.write_text(contents)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins.egg-info/PKG-INFO
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins.egg-info/PKG-INFO
--- old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins.egg-info/PKG-INFO
2024-12-21 21:11:15.000000000 +0100
+++ new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins.egg-info/PKG-INFO
2026-05-14 09:43:07.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
Name: pytest-mypy-plugins
-Version: 3.2.0
+Version: 4.0.3
Summary: pytest plugin for writing tests for mypy plugins
Home-page: https://github.com/TypedDjango/pytest-mypy-plugins
Author: Maksim Kurnikov
@@ -8,16 +8,16 @@
Maintainer: Nikita Sobolev
Maintainer-email: [email protected]
License: MIT
-Classifier: Development Status :: 4 - Beta
+Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
-Requires-Python: >=3.9
+Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Jinja2
@@ -29,6 +29,19 @@
Requires-Dist: pyyaml
Requires-Dist: regex
Requires-Dist: tomlkit>=0.11
+Dynamic: author
+Dynamic: author-email
+Dynamic: classifier
+Dynamic: description
+Dynamic: description-content-type
+Dynamic: home-page
+Dynamic: license
+Dynamic: license-file
+Dynamic: maintainer
+Dynamic: maintainer-email
+Dynamic: requires-dist
+Dynamic: requires-python
+Dynamic: summary
<img src="http://mypy-lang.org/static/mypy_light.svg" alt="mypy logo"
width="300px"/>
@@ -241,8 +254,12 @@
--mypy-extension-hook=MYPY_EXTENSION_HOOK
Fully qualified path to the extension hook function,
in case you need custom yaml keys. Has to be top-level
- --mypy-only-local-stub
- mypy will ignore errors from site-packages
+ --mypy-no-silence-site-packages
+ mypy will not silence errors from site-packages
+ --mypy-modify-pythonpath
+ When running mypy in a subprocess, modify `PYTHONPATH`
+ to force packages to be treated as site-packages.
+ Incompatible with `--mypy-same-process`
--mypy-closed-schema
Use closed schema to validate YAML test cases,
which won't allow any extra keys
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins.egg-info/SOURCES.txt
new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins.egg-info/SOURCES.txt
--- old/pytest_mypy_plugins-3.2.0/pytest_mypy_plugins.egg-info/SOURCES.txt
2024-12-21 21:11:15.000000000 +0100
+++ new/pytest_mypy_plugins-4.0.3/pytest_mypy_plugins.egg-info/SOURCES.txt
2026-05-14 09:43:07.000000000 +0200
@@ -28,6 +28,8 @@
pytest_mypy_plugins/tests/test-simple-cases.yml
pytest_mypy_plugins/tests/test_explicit_configs.py
pytest_mypy_plugins/tests/test_input_schema.py
+pytest_mypy_plugins/tests/test_mypy_cache.py
+pytest_mypy_plugins/tests/test_site_packages.py
pytest_mypy_plugins/tests/test_utils.py
pytest_mypy_plugins/tests/test_configs/mypy1.ini
pytest_mypy_plugins/tests/test_configs/mypy2.ini
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_mypy_plugins-3.2.0/requirements.txt
new/pytest_mypy_plugins-4.0.3/requirements.txt
--- old/pytest_mypy_plugins-3.2.0/requirements.txt 2024-12-21
21:10:55.000000000 +0100
+++ new/pytest_mypy_plugins-4.0.3/requirements.txt 2026-05-14
09:40:55.000000000 +0200
@@ -4,5 +4,5 @@
types-PyYAML
types-setuptools
types-regex
-mypy==1.13
+mypy==1.20.2
-e .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pytest_mypy_plugins-3.2.0/setup.py
new/pytest_mypy_plugins-4.0.3/setup.py
--- old/pytest_mypy_plugins-3.2.0/setup.py 2024-12-21 21:10:55.000000000
+0100
+++ new/pytest_mypy_plugins-4.0.3/setup.py 2026-05-14 09:41:41.000000000
+0200
@@ -17,7 +17,7 @@
setup(
name="pytest-mypy-plugins",
- version="3.2.0",
+ version="4.0.3",
description="pytest plugin for writing tests for mypy plugins",
long_description=readme,
long_description_content_type="text/markdown",
@@ -31,19 +31,19 @@
# the following makes a plugin available to pytest
entry_points={"pytest11": ["pytest-mypy-plugins =
pytest_mypy_plugins.collect"]},
install_requires=dependencies,
- python_requires=">=3.9",
+ python_requires=">=3.10",
package_data={
"pytest_mypy_plugins": ["py.typed", "schema.json"],
},
classifiers=[
- "Development Status :: 4 - Beta",
+ "Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
"Typing :: Typed",
],
)