Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-oslotest for openSUSE:Factory 
checked in at 2026-04-12 17:52:26
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-oslotest (Old)
 and      /work/SRC/openSUSE:Factory/.python-oslotest.new.21863 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-oslotest"

Sun Apr 12 17:52:26 2026 rev:29 rq:1345963 version:6.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-oslotest/python-oslotest.changes  
2026-03-09 16:11:42.757846863 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-oslotest.new.21863/python-oslotest.changes   
    2026-04-12 17:52:28.459562295 +0200
@@ -1,0 +2,20 @@
+Fri Apr 10 19:29:17 UTC 2026 - Dirk Müller <[email protected]>
+
+- add multibuild to avoid build cycle
+
+-------------------------------------------------------------------
+Tue Mar 24 17:13:28 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 6.1.0:
+  * ruff: Configure hacking as external linter
+  * mypy: Disabling warnings for untyped imports
+  * Add typing classifier
+  * Add mypy
+  * typing: Add initial types
+  * Remove unused dependency
+  * Enable logging related ruff checks
+  * Delay string interpolations at logging calls
+  * Remove reference to tag framework
+  * ruff: Use more specific name to enable pyupgrade rule
+
+-------------------------------------------------------------------

Old:
----
  oslotest-6.0.0.tar.gz

New:
----
  _multibuild
  oslotest-6.1.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-oslotest.spec ++++++
--- /var/tmp/diff_new_pack.uqj8th/_old  2026-04-12 17:52:29.151590474 +0200
+++ /var/tmp/diff_new_pack.uqj8th/_new  2026-04-12 17:52:29.151590474 +0200
@@ -16,23 +16,34 @@
 #
 
 
-Name:           python-oslotest
-Version:        6.0.0
+%global flavor @BUILD_FLAVOR@%{nil}
+%if "%{flavor}" == "test"
+%define psuffix -test
+%bcond_without test
+%else
+%define psuffix %{nil}
+%bcond_with test
+%endif
+Name:           python-oslotest%{psuffix}
+Version:        6.1.0
 Release:        0
 Summary:        OpenStack test framework
 License:        Apache-2.0
 Group:          Development/Languages/Python
 URL:            https://docs.openstack.org/oslotest
 Source0:        
https://files.pythonhosted.org/packages/source/o/oslotest/oslotest-%{version}.tar.gz
-BuildRequires:  %{python_module debtcollector}
-BuildRequires:  %{python_module fixtures >= 3.0.0}
+BuildRequires:  %{python_module pbr >= 6.1.1}
 BuildRequires:  %{python_module pip}
+BuildRequires:  %{python_module wheel}
+%if %{with test}
+BuildRequires:  %{python_module fixtures >= 3.0.0}
+BuildRequires:  %{python_module oslo.config >= 5.2.0}
 BuildRequires:  %{python_module python-subunit >= 1.0.0}
-BuildRequires:  %{python_module stestr}
+BuildRequires:  %{python_module stestr >= 2.0.0}
 BuildRequires:  %{python_module testtools >= 2.2.0}
-BuildRequires:  %{python_module wheel}
+%endif
 BuildRequires:  openstack-macros
-Requires:       python-fixtures
+Requires:       python-fixtures >= 3.0.0
 BuildArch:      noarch
 %if "python%{python_nodots_ver}" == "%{primary_python}"
 Obsoletes:      python3-oslotest < %{version}
@@ -60,6 +71,7 @@
 %pyproject_wheel
 
 %install
+%if !%{with test}
 %pyproject_install
 %python_clone -a %{buildroot}%{_bindir}/oslo_debug_helper
 
@@ -73,13 +85,18 @@
 %postun
 %python_uninstall_alternative oslo_debug_helper
 
+%else
+
 %check
 %{openstack_stestr_run}
+%endif
 
+%if !%{with test}
 %files %{python_files}
 %license LICENSE
 %doc ChangeLog README.rst
 %python_alternative %{_bindir}/oslo_debug_helper
 %{python_sitelib}/oslotest
 %{python_sitelib}/oslotest-%{version}.dist-info
+%endif
 

++++++ _multibuild ++++++
<multibuild>
  <package>test</package>
</multibuild>

++++++ oslotest-6.0.0.tar.gz -> oslotest-6.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/.pre-commit-config.yaml 
new/oslotest-6.1.0/.pre-commit-config.yaml
--- old/oslotest-6.0.0/.pre-commit-config.yaml  2025-11-11 14:30:30.000000000 
+0100
+++ new/oslotest-6.1.0/.pre-commit-config.yaml  2026-03-24 11:31:36.000000000 
+0100
@@ -13,13 +13,13 @@
       - id: check-yaml
         files: .*\.(yaml|yml)$
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.12.12
+    rev: v0.14.9
     hooks:
       - id: ruff-check
         args: ['--fix', '--unsafe-fixes']
       - id: ruff-format
   - repo: https://opendev.org/openstack/hacking
-    rev: 7.0.0
+    rev: 8.0.0
     hooks:
       - id: hacking
         additional_dependencies: []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/ChangeLog new/oslotest-6.1.0/ChangeLog
--- old/oslotest-6.0.0/ChangeLog        2025-11-11 14:31:15.000000000 +0100
+++ new/oslotest-6.1.0/ChangeLog        2026-03-24 11:32:27.000000000 +0100
@@ -1,6 +1,20 @@
 CHANGES
 =======
 
+6.1.0
+-----
+
+* ruff: Configure hacking as external linter
+* mypy: Disabling warnings for untyped imports
+* Add typing classifier
+* Add mypy
+* typing: Add initial types
+* Remove unused dependency
+* Enable logging related ruff checks
+* Delay string interpolations at logging calls
+* Remove reference to tag framework
+* ruff: Use more specific name to enable pyupgrade rule
+
 6.0.0
 -----
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/PKG-INFO new/oslotest-6.1.0/PKG-INFO
--- old/oslotest-6.0.0/PKG-INFO 2025-11-11 14:31:15.673163400 +0100
+++ new/oslotest-6.1.0/PKG-INFO 2026-03-24 11:32:28.078053200 +0100
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: oslotest
-Version: 6.0.0
+Version: 6.1.0
 Summary: Oslo test framework
 Author-email: OpenStack <[email protected]>
 Project-URL: Homepage, https://docs.openstack.org/oslotest
@@ -18,26 +18,23 @@
 Classifier: Programming Language :: Python :: 3.13
 Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Typing :: Typed
 Requires-Python: >=3.10
 Description-Content-Type: text/x-rst
 License-File: LICENSE
 Requires-Dist: fixtures>=3.0.0
-Requires-Dist: python-subunit>=1.0.0
 Requires-Dist: testtools>=2.2.0
+Dynamic: license-file
+Dynamic: requires-dist
 
-========================
-Team and repository tags
-========================
+=====================================================
+oslotest -- OpenStack Testing Framework and Utilities
+=====================================================
 
 .. image:: https://governance.openstack.org/tc/badges/oslotest.svg
-    :target: https://governance.openstack.org/tc/reference/tags/index.html
 
 .. Change things from this point on
 
-=====================================================
-oslotest -- OpenStack Testing Framework and Utilities
-=====================================================
-
 The Oslo Test framework provides common fixtures, support for debugging, and
 better support for mocking results.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/README.rst 
new/oslotest-6.1.0/README.rst
--- old/oslotest-6.0.0/README.rst       2025-11-11 14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/README.rst       2026-03-24 11:31:36.000000000 +0100
@@ -1,16 +1,11 @@
-========================
-Team and repository tags
-========================
+=====================================================
+oslotest -- OpenStack Testing Framework and Utilities
+=====================================================
 
 .. image:: https://governance.openstack.org/tc/badges/oslotest.svg
-    :target: https://governance.openstack.org/tc/reference/tags/index.html
 
 .. Change things from this point on
 
-=====================================================
-oslotest -- OpenStack Testing Framework and Utilities
-=====================================================
-
 The Oslo Test framework provides common fixtures, support for debugging, and
 better support for mocking results.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/base.py 
new/oslotest-6.1.0/oslotest/base.py
--- old/oslotest-6.0.0/oslotest/base.py 2025-11-11 14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/oslotest/base.py 2026-03-24 11:31:36.000000000 +0100
@@ -15,7 +15,9 @@
 
 """Common utilities used in testing"""
 
+from collections.abc import Callable, Sequence
 import logging
+from typing import Any
 from unittest import mock
 
 import fixtures
@@ -29,7 +31,7 @@
 LOG = logging.getLogger(__name__)
 
 _TRUE_VALUES = ('True', 'true', '1', 'yes')
-_LOG_FORMAT = "%(levelname)8s [%(name)s] %(message)s"
+_LOG_FORMAT = '%(levelname)8s [%(name)s] %(message)s'
 
 
 class BaseTestCase(testtools.TestCase):
@@ -88,8 +90,16 @@
     DEFAULT_TIMEOUT = 0
     TIMEOUT_SCALING_FACTOR = 1
 
-    def __init__(self, *args, **kwds):
-        super().__init__(*args, **kwds)
+    # FIXME(stephenfin): This should only accept two kwargs:
+    # - methodName (from stdlib)
+    # - runTest (from testtools)
+    # But we need to type testtools first
+    def __init__(
+        self,
+        methodName: str = 'runTest',
+        runTest: Any = None,
+    ) -> None:
+        super().__init__(methodName=methodName, runTest=runTest)
 
         # This is the number of characters shown when two objects do not
         # match for assertDictEqual, assertMultiLineEqual, and
@@ -97,7 +107,13 @@
         # low for comparing most dicts
         self.maxDiff = 10000
 
-    def addCleanup(self, function, *args, **kwargs):
+    def addCleanup(
+        self,
+        cleanup: Callable[..., object],
+        /,
+        *args: object,
+        **kwargs: object,
+    ) -> None:
         # NOTE(dims): This is a hack for Mitaka. We'll need to undo this as
         # early as possible in Newton and advertise that this hack will not
         # be supported anymore.
@@ -114,9 +130,9 @@
                 'Unable to patch test case. '
                 'mock.patch.stopall cleanup was not registered.'
             )
-        super().addCleanup(function, *args, **kwargs)
+        super().addCleanup(cleanup, *args, **kwargs)
 
-    def setUp(self):
+    def setUp(self) -> None:
         super().setUp()
         self._set_timeout()
         self._fake_output()
@@ -124,7 +140,7 @@
         self.useFixture(fixtures.NestedTempfile())
         self.useFixture(fixtures.TempHomeDir())
 
-    def _set_timeout(self):
+    def _set_timeout(self) -> None:
         self.useFixture(
             timeout.Timeout(
                 default_timeout=self.DEFAULT_TIMEOUT,
@@ -132,24 +148,28 @@
             )
         )
 
-    def _fake_output(self):
+    def _fake_output(self) -> None:
         self.output_fixture = self.useFixture(output.CaptureOutput())
 
-    def _fake_logs(self):
+    def _fake_logs(self) -> None:
         self.log_fixture = self.useFixture(log.ConfigureLogging())
 
-    def create_tempfiles(self, files, ext='.conf', default_encoding='utf-8'):
+    def create_tempfiles(
+        self,
+        files: Sequence[
+            tuple[str, str | bytes, str] | tuple[str, str | bytes]
+        ],
+        ext: str = '.conf',
+        default_encoding: str = 'utf-8',
+    ) -> list[str]:
         """Safely create temporary files.
 
-        :param files: Sequence of tuples containing (filename, file_contents).
-        :type files: list of tuple
+        :param files: Sequence of tuples containing ``(filename,
+            file_contents)`` or ``(filename, file_contents, encoding)``.
         :param ext: File name extension for the temporary file.
-        :type ext: str
         :param default_encoding: Default file content encoding when it is
-                                 not provided, used to decode the tempfile
-                                 contents from a text string into a binary
-                                 string.
-        :type default_encoding: str
+            not provided. Used to decode the tempfile contents from a text
+            string into a binary string.
         :return: A list of str with the names of the files created.
         """
         tempfiles = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/createfile.py 
new/oslotest-6.1.0/oslotest/createfile.py
--- old/oslotest-6.0.0/oslotest/createfile.py   2025-11-11 14:30:30.000000000 
+0100
+++ new/oslotest-6.1.0/oslotest/createfile.py   2026-03-24 11:31:36.000000000 
+0100
@@ -32,10 +32,6 @@
     :class:`fixtures.NestedTempfile` to set the temporary directory
     somewhere safe and to ensure the files are cleaned up.
 
-    .. py:attribute:: path
-
-       The canonical name of the file created.
-
     :param filename: Base file name or full literal path to the file
         to be created.
     :param contents: The data to write to the file. Unicode data will
@@ -43,16 +39,24 @@
     :param ext: An extension to add to filename.
     :param encoding: An encoding to use for unicode data (ignored for
         byte strings).
-
     """
 
-    def __init__(self, filename, contents, ext='.conf', encoding='utf-8'):
+    #: The canonical name of the file created.
+    path: str
+
+    def __init__(
+        self,
+        filename: str,
+        contents: str | bytes,
+        ext: str = '.conf',
+        encoding: str = 'utf-8',
+    ) -> None:
         self._filename = filename
         self._contents = contents
         self._ext = ext
         self._encoding = encoding
 
-    def setUp(self):
+    def setUp(self) -> None:
         super().setUp()
         contents = self._contents
         if isinstance(contents, str):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/log.py 
new/oslotest-6.1.0/oslotest/log.py
--- old/oslotest-6.0.0/oslotest/log.py  2025-11-11 14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/oslotest/log.py  2026-03-24 11:31:36.000000000 +0100
@@ -12,6 +12,7 @@
 
 import logging
 import os
+from typing import Any
 
 import fixtures
 
@@ -26,7 +27,7 @@
 )
 
 
-def _try_int(value):
+def _try_int(value: Any) -> int | None:
     """Try to make some value into an int."""
     try:
         return int(value)
@@ -62,10 +63,10 @@
     DEFAULT_FORMAT = "%(levelname)8s [%(name)s] %(message)s"
     """Default log format"""
 
-    def __init__(self, format=DEFAULT_FORMAT):
+    def __init__(self, format: str = DEFAULT_FORMAT) -> None:
         super().__init__()
         self._format = format
-        self.level = None
+        self.level = 0
         _os_debug = os.environ.get('OS_DEBUG')
         _os_level = _try_int(_os_debug)
         if _os_debug in _TRUE_VALUES:
@@ -77,9 +78,9 @@
         elif _os_debug and _os_debug not in _FALSE_VALUES:
             raise ValueError(f'OS_DEBUG={_os_debug} is invalid.')
         self.capture_logs = os.environ.get('OS_LOG_CAPTURE') in _TRUE_VALUES
-        self.logger = None
+        self.logger: fixtures.FakeLogger | None = None
 
-    def setUp(self):
+    def setUp(self) -> None:
         super().setUp()
         if self.capture_logs:
             self.logger = self.useFixture(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/mock_fixture.py 
new/oslotest-6.1.0/oslotest/mock_fixture.py
--- old/oslotest-6.0.0/oslotest/mock_fixture.py 2025-11-11 14:30:30.000000000 
+0100
+++ new/oslotest-6.1.0/oslotest/mock_fixture.py 2026-03-24 11:31:36.000000000 
+0100
@@ -13,22 +13,32 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from __future__ import annotations
+
+from collections.abc import Callable
 import functools
+from typing import Any, ParamSpec, TypeVar, TYPE_CHECKING
 from unittest import mock
 
 import fixtures
 
+_T = TypeVar('_T')
+
 
-def _lazy_autospec_method(mocked_method, original_method, eat_self):
+def _lazy_autospec_method(
+    mocked_method: Any,
+    original_method: Any,
+    eat_self: bool,
+) -> None:
     if mocked_method._mock_check_sig.__dict__.get('autospeced'):
         return
 
-    _lazy_autospec = mock.create_autospec(original_method)
+    _lazy_autospec: Any = mock.create_autospec(original_method)
     if eat_self:
         # consume self argument.
         _lazy_autospec = functools.partial(_lazy_autospec, None)
 
-    def _autospeced(*args, **kwargs):
+    def _autospeced(*args: Any, **kwargs: Any) -> None:
         _lazy_autospec(*args, **kwargs)
 
     # _mock_check_sig is called by the mock's __call__ method.
@@ -41,7 +51,10 @@
 class _AutospecMockMixin:
     """Mock object that lazily autospecs the given spec's methods."""
 
-    def __init__(self, *args, **kwargs):
+    # These are defined by mock.Mock but we need to declare them for typing
+    return_value: Any
+
+    def __init__(self, *args: Any, **kwargs: Any) -> None:
         super().__init__(*args, **kwargs)
         autospec = kwargs.get('autospec')
         self.__dict__['_autospec'] = autospec
@@ -56,8 +69,8 @@
         if autospec:
             self.return_value.__dict__['_autospec'] = autospec
 
-    def __getattr__(self, name):
-        attr = super().__getattr__(name)
+    def __getattr__(self, name: str) -> Any:
+        attr = super().__getattr__(name)  # type: ignore[misc]
 
         original_spec = self.__dict__['_autospec']
         if not original_spec:
@@ -71,7 +84,8 @@
         original_attr = getattr(original_spec, name)
         if callable(original_attr):
             # lazily autospec callable attribute.
-            eat_self = mock._must_skip(
+            # NOTE: _must_skip is a private function in the mock module
+            eat_self = mock._must_skip(  # type: ignore[attr-defined]
                 original_spec, name, isinstance(original_spec, type)
             )
 
@@ -106,7 +120,7 @@
           mocked method's signature is also checked.
     """
 
-    def setUp(self):
+    def setUp(self) -> None:
         super().setUp()
 
         # patch both external and internal usage of Mock / MagicMock.
@@ -118,7 +132,16 @@
         )
 
 
-class _patch(mock._patch):
+if TYPE_CHECKING:
+    Base = mock._patch
+else:
+    # as of Python 3.13 this is not subscriptable at runtime
+    class Base(mock._patch):
+        def __class_getitem__(cls, _):
+            return cls
+
+
+class _patch(Base[_T]):
     """Patch class with working autospec functionality.
 
     Currently, mock.patch functionality doesn't handle the autospec parameter
@@ -128,7 +151,7 @@
     https://github.com/testing-cabal/mock/issues/396
     """
 
-    def __enter__(self):
+    def __enter__(self) -> _T:
         # NOTE(claudiub): we're doing the autospec checks here so unit tests
         # have a chance to set up mocks in advance (e.g.: mocking platform
         # specific libraries, which would cause the patch to fail otherwise).
@@ -160,7 +183,8 @@
         if autospec:
             target = self.getter()
             original_attr = getattr(target, self.attribute)
-            eat_self = mock._must_skip(
+            # NOTE: _must_skip is a private function in the mock module
+            eat_self = mock._must_skip(  # type: ignore[attr-defined]
                 target, self.attribute, isinstance(target, type)
             )
 
@@ -177,24 +201,32 @@
             return super().__enter__()
 
 
-def _safe_attribute_error_wrapper(func):
-    def wrapper(*args, **kwargs):
+P = ParamSpec('P')
+R = TypeVar('R')
+
+
+def _safe_attribute_error_wrapper(
+    func: Callable[P, R],
+) -> Callable[P, R | None]:
+    def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None:
         try:
             return func(*args, **kwargs)
         except AttributeError:
-            pass
+            return None
 
     return wrapper
 
 
-def patch_mock_module():
+def patch_mock_module() -> None:
     """Replaces the mock.patch class."""
-    mock._patch = _patch
+    # NOTE: _patch is a private class in the mock module
+    mock._patch = _patch  # type: ignore[misc]
 
     # NOTE(claudiub): mock cannot autospec partial functions properly,
     # especially those created by LazyLoader objects (scheduler client),
     # as it will try to copy the partial function's __name__ (which they do
     # not have).
-    mock._copy_func_details = _safe_attribute_error_wrapper(
-        mock._copy_func_details
+    # NOTE: _copy_func_details is a private function in the mock module
+    mock._copy_func_details = _safe_attribute_error_wrapper(  # type: 
ignore[attr-defined]
+        mock._copy_func_details  # type: ignore[attr-defined]
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/modules.py 
new/oslotest-6.1.0/oslotest/modules.py
--- old/oslotest-6.0.0/oslotest/modules.py      2025-11-11 14:30:30.000000000 
+0100
+++ new/oslotest-6.1.0/oslotest/modules.py      2026-03-24 11:31:36.000000000 
+0100
@@ -10,7 +10,10 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+from collections.abc import Sequence
+from importlib.machinery import ModuleSpec
 import sys
+from types import ModuleType
 
 import fixtures
 
@@ -18,11 +21,11 @@
 class DisableModuleFixture(fixtures.Fixture):
     """A fixture to provide support for unloading/disabling modules."""
 
-    def __init__(self, module, *args, **kwargs):
-        super().__init__(*args, **kwargs)
+    def __init__(self, module: str):
+        super().__init__()
         self.module = module
 
-    def setUp(self):
+    def setUp(self) -> None:
         """Ensure ImportError for the specified module."""
         super().setUp()
 
@@ -42,9 +45,16 @@
 class _NoModuleFinder:
     """Disallow further imports of 'module'."""
 
-    def __init__(self, module):
+    def __init__(self, module: str) -> None:
         self.module = module
 
-    def find_spec(self, fullname, path, target):
+    def find_spec(
+        self,
+        fullname: str,
+        path: Sequence[str] | None,
+        target: ModuleType | None = None,
+        /,
+    ) -> ModuleSpec | None:
         if fullname == self.module or fullname.startswith(self.module + '.'):
             raise ImportError
+        return None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/output.py 
new/oslotest-6.1.0/oslotest/output.py
--- old/oslotest-6.0.0/oslotest/output.py       2025-11-11 14:30:30.000000000 
+0100
+++ new/oslotest-6.1.0/oslotest/output.py       2026-03-24 11:31:36.000000000 
+0100
@@ -11,6 +11,7 @@
 # under the License.
 
 import os
+from typing import IO
 
 import fixtures
 
@@ -44,7 +45,9 @@
 
     """
 
-    def __init__(self, do_stdout=None, do_stderr=None):
+    def __init__(
+        self, do_stdout: bool | None = None, do_stderr: bool | None = None
+    ):
         super().__init__()
         if do_stdout is None:
             self.do_stdout = (
@@ -58,10 +61,10 @@
             )
         else:
             self.do_stderr = do_stderr
-        self.stdout = None
-        self.stderr = None
+        self.stdout: IO[str] | None = None
+        self.stderr: IO[str] | None = None
 
-    def setUp(self):
+    def setUp(self) -> None:
         super().setUp()
         if self.do_stdout:
             self._stdout_fixture = fixtures.StringStream('stdout')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/tests/unit/test_base.py 
new/oslotest-6.1.0/oslotest/tests/unit/test_base.py
--- old/oslotest-6.0.0/oslotest/tests/unit/test_base.py 2025-11-11 
14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/oslotest/tests/unit/test_base.py 2026-03-24 
11:31:36.000000000 +0100
@@ -14,6 +14,7 @@
 
 import logging
 import os
+from typing import Any
 import unittest
 from unittest import mock
 
@@ -84,7 +85,8 @@
     def test_mock_patch_cleanup_on_teardown(self):
         # create an object and save its reference
         class Sub:
-            pass
+            value: Any
+            backup: Any
 
         obj = Sub()
         obj.value = obj.backup = object()
@@ -138,7 +140,7 @@
 
 class TestTempFiles(base.BaseTestCase):
     def test_create_unicode_files(self):
-        files = [["no_approve", 'ಠ_ಠ']]
+        files = [('no_approve', 'ಠ_ಠ')]
         temps = self.create_tempfiles(files)
         self.assertEqual(1, len(temps))
         with open(temps[0], 'rb') as f:
@@ -146,7 +148,7 @@
         self.assertEqual('ಠ_ಠ', str(contents, encoding='utf-8'))
 
     def test_create_unicode_files_encoding(self):
-        files = [["embarrassed", '⊙﹏⊙', 'utf-8']]
+        files = [('embarrassed', '⊙﹏⊙', 'utf-8')]
         temps = self.create_tempfiles(files)
         self.assertEqual(1, len(temps))
         with open(temps[0], 'rb') as f:
@@ -155,8 +157,8 @@
 
     def test_create_unicode_files_multi_encoding(self):
         files = [
-            ["embarrassed", '⊙﹏⊙', 'utf-8'],
-            ['abc', 'abc', 'ascii'],
+            ('embarrassed', '⊙﹏⊙', 'utf-8'),
+            ('abc', 'abc', 'ascii'),
         ]
         temps = self.create_tempfiles(files)
         self.assertEqual(2, len(temps))
@@ -170,16 +172,16 @@
             )
 
     def test_create_bad_encoding(self):
-        files = [["hrm", 'ಠ~ಠ', 'ascii']]
+        files = [['hrm', 'ಠ~ಠ', 'ascii']]
         self.assertRaises(UnicodeError, self.create_tempfiles, files)
 
     def test_prefix(self):
-        files = [["testing", '']]
+        files = [('testing', '')]
         temps = self.create_tempfiles(files)
         self.assertEqual(1, len(temps))
         basename = os.path.basename(temps[0])
         self.assertTrue(basename.startswith('testing'))
 
     def test_wrong_length(self):
-        files = [["testing"]]
+        files = [('testing',)]
         self.assertRaises(ValueError, self.create_tempfiles, files)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslotest-6.0.0/oslotest/tests/unit/test_createfile.py 
new/oslotest-6.1.0/oslotest/tests/unit/test_createfile.py
--- old/oslotest-6.0.0/oslotest/tests/unit/test_createfile.py   2025-11-11 
14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/oslotest/tests/unit/test_createfile.py   2026-03-24 
11:31:36.000000000 +0100
@@ -25,8 +25,8 @@
             'ಠ_ಠ',
         )
         f.setUp()
-        with open(f.path, 'rb') as f:
-            contents = f.read()
+        with open(f.path, 'rb') as fh:
+            contents = fh.read()
         self.assertEqual('ಠ_ಠ', str(contents, encoding='utf-8'))
 
     def test_create_unicode_files_encoding(self):
@@ -36,8 +36,8 @@
             encoding='utf-8',
         )
         f.setUp()
-        with open(f.path, 'rb') as f:
-            contents = f.read()
+        with open(f.path, 'rb') as fh:
+            contents = fh.read()
         self.assertEqual('⊙﹏⊙', str(contents, encoding='utf-8'))
 
     def test_create_bad_encoding(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/oslotest-6.0.0/oslotest/tests/unit/test_mock_fixture.py 
new/oslotest-6.1.0/oslotest/tests/unit/test_mock_fixture.py
--- old/oslotest-6.0.0/oslotest/tests/unit/test_mock_fixture.py 2025-11-11 
14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/oslotest/tests/unit/test_mock_fixture.py 2026-03-24 
11:31:36.000000000 +0100
@@ -124,16 +124,16 @@
     ):
         foo = Foo()
         # we're checking that method signature is not enforced.
-        foo.bar()
+        foo.bar()  # type: ignore[call-arg]
         mock_meth.assert_called_once_with()
-        foo.classic_bar()
+        foo.classic_bar()  # type: ignore[call-arg]
         mock_cmeth.assert_called_once_with()
-        foo.static_bar()
+        foo.static_bar()  # type: ignore[call-arg]
         mock_smeth.assert_called_once_with()
 
     @mock.patch.object(Foo, 'lish', create=True)
     def test_patch_create(self, mock_lish):
         foo = Foo()
 
-        foo.lish()
+        foo.lish()  # type: ignore[attr-defined]
         mock_lish.assert_called_once_with()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/tests/unit/test_timeout.py 
new/oslotest-6.1.0/oslotest/tests/unit/test_timeout.py
--- old/oslotest-6.0.0/oslotest/tests/unit/test_timeout.py      2025-11-11 
14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/oslotest/tests/unit/test_timeout.py      2026-03-24 
11:31:36.000000000 +0100
@@ -63,7 +63,7 @@
         self, fixture_timeout_mock, fixture_mock, env_get_mock
     ):
         env_get_mock.return_value = 'invalid'
-        tc = timeout.Timeout(default_timeout='invalid')
+        tc = timeout.Timeout(default_timeout='invalid')  # type: ignore
         tc.setUp()
         env_get_mock.assert_called_once_with('OS_TEST_TIMEOUT', 0)
         self.assertEqual(0, fixture_timeout_mock.call_count)
@@ -89,7 +89,7 @@
         self, fixture_timeout_mock, fixture_mock, env_get_mock
     ):
         env_get_mock.return_value = 2
-        tc = timeout.Timeout(scaling_factor='invalid')
+        tc = timeout.Timeout(scaling_factor='invalid')  # type: ignore
         tc.setUp()
         env_get_mock.assert_called_once_with('OS_TEST_TIMEOUT', 0)
         fixture_timeout_mock.assert_called_once_with(2, gentle=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/timeout.py 
new/oslotest-6.1.0/oslotest/timeout.py
--- old/oslotest-6.0.0/oslotest/timeout.py      2025-11-11 14:30:30.000000000 
+0100
+++ new/oslotest-6.1.0/oslotest/timeout.py      2026-03-24 11:31:36.000000000 
+0100
@@ -22,7 +22,11 @@
 
     """
 
-    def __init__(self, default_timeout=0, scaling_factor=1):
+    def __init__(
+        self,
+        default_timeout: int | float = 0,
+        scaling_factor: int | float = 1,
+    ) -> None:
         super().__init__()
         try:
             self._default_timeout = int(default_timeout)
@@ -31,7 +35,7 @@
             self._default_timeout = 0
         self._scaling_factor = scaling_factor
 
-    def setUp(self):
+    def setUp(self) -> None:
         super().setUp()
         test_timeout = os.environ.get('OS_TEST_TIMEOUT', self._default_timeout)
         try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest/tools/config.py 
new/oslotest-6.1.0/oslotest/tools/config.py
--- old/oslotest-6.0.0/oslotest/tools/config.py 2025-11-11 14:30:30.000000000 
+0100
+++ new/oslotest-6.1.0/oslotest/tools/config.py 2026-03-24 11:31:36.000000000 
+0100
@@ -13,6 +13,7 @@
 """Utilities functions for working with oslo.config from the tool scripts."""
 
 import os
+from typing import TypeVar
 
 from oslo_config import cfg
 
@@ -22,7 +23,7 @@
 ]
 
 
-def get_config_parser():
+def get_config_parser() -> cfg.ConfigOpts:
     conf = cfg.ConfigOpts()
     conf.register_cli_opt(
         cfg.StrOpt(
@@ -34,12 +35,14 @@
     return conf
 
 
-def parse_arguments(conf):
+_ConfigOptT = TypeVar('_ConfigOptT', bound=cfg.ConfigOpts)
+
+
+def parse_arguments(conf: type[_ConfigOptT]) -> _ConfigOptT:
     # Look for a few configuration files, and load the ones we find.
     default_config_files = [
         f for f in DEFAULT_CONFIG_FILES if os.path.exists(f)
     ]
-    return conf(
-        project='oslo',
-        default_config_files=default_config_files,
+    return conf(  # type: ignore
+        project='oslo', default_config_files=default_config_files
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest.egg-info/PKG-INFO 
new/oslotest-6.1.0/oslotest.egg-info/PKG-INFO
--- old/oslotest-6.0.0/oslotest.egg-info/PKG-INFO       2025-11-11 
14:31:15.000000000 +0100
+++ new/oslotest-6.1.0/oslotest.egg-info/PKG-INFO       2026-03-24 
11:32:28.000000000 +0100
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: oslotest
-Version: 6.0.0
+Version: 6.1.0
 Summary: Oslo test framework
 Author-email: OpenStack <[email protected]>
 Project-URL: Homepage, https://docs.openstack.org/oslotest
@@ -18,26 +18,23 @@
 Classifier: Programming Language :: Python :: 3.13
 Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Typing :: Typed
 Requires-Python: >=3.10
 Description-Content-Type: text/x-rst
 License-File: LICENSE
 Requires-Dist: fixtures>=3.0.0
-Requires-Dist: python-subunit>=1.0.0
 Requires-Dist: testtools>=2.2.0
+Dynamic: license-file
+Dynamic: requires-dist
 
-========================
-Team and repository tags
-========================
+=====================================================
+oslotest -- OpenStack Testing Framework and Utilities
+=====================================================
 
 .. image:: https://governance.openstack.org/tc/badges/oslotest.svg
-    :target: https://governance.openstack.org/tc/reference/tags/index.html
 
 .. Change things from this point on
 
-=====================================================
-oslotest -- OpenStack Testing Framework and Utilities
-=====================================================
-
 The Oslo Test framework provides common fixtures, support for debugging, and
 better support for mocking results.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest.egg-info/SOURCES.txt 
new/oslotest-6.1.0/oslotest.egg-info/SOURCES.txt
--- old/oslotest-6.0.0/oslotest.egg-info/SOURCES.txt    2025-11-11 
14:31:15.000000000 +0100
+++ new/oslotest-6.1.0/oslotest.egg-info/SOURCES.txt    2026-03-24 
11:32:28.000000000 +0100
@@ -35,6 +35,7 @@
 oslotest/mock_fixture.py
 oslotest/modules.py
 oslotest/output.py
+oslotest/py.typed
 oslotest/timeout.py
 oslotest.egg-info/PKG-INFO
 oslotest.egg-info/SOURCES.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest.egg-info/pbr.json 
new/oslotest-6.1.0/oslotest.egg-info/pbr.json
--- old/oslotest-6.0.0/oslotest.egg-info/pbr.json       2025-11-11 
14:31:15.000000000 +0100
+++ new/oslotest-6.1.0/oslotest.egg-info/pbr.json       2026-03-24 
11:32:28.000000000 +0100
@@ -1 +1 @@
-{"git_version": "b5e4a4c", "is_release": true}
\ No newline at end of file
+{"git_version": "3722be4", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/oslotest.egg-info/requires.txt 
new/oslotest-6.1.0/oslotest.egg-info/requires.txt
--- old/oslotest-6.0.0/oslotest.egg-info/requires.txt   2025-11-11 
14:31:15.000000000 +0100
+++ new/oslotest-6.1.0/oslotest.egg-info/requires.txt   2026-03-24 
11:32:28.000000000 +0100
@@ -1,3 +1,2 @@
 fixtures>=3.0.0
-python-subunit>=1.0.0
 testtools>=2.2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/pyproject.toml 
new/oslotest-6.1.0/pyproject.toml
--- old/oslotest-6.0.0/pyproject.toml   2025-11-11 14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/pyproject.toml   2026-03-24 11:31:36.000000000 +0100
@@ -25,6 +25,7 @@
     "Programming Language :: Python :: 3.13",
     "Programming Language :: Python :: 3 :: Only",
     "Programming Language :: Python :: Implementation :: CPython",
+    "Typing :: Typed",
 ]
 
 [project.urls]
@@ -39,6 +40,20 @@
     "tools/oslo_debug_helper",
 ]
 
+[tool.mypy]
+python_version = "3.10"
+show_column_numbers = true
+show_error_context = true
+strict = true
+disable_error_code = ["import-untyped"]
+exclude = "(?x)(doc | releasenotes)"
+
+[[tool.mypy.overrides]]
+module = ["oslotest.tests.*"]
+disallow_untyped_calls = false
+disallow_untyped_defs = false
+disallow_subclassing_any = false
+
 [tool.ruff]
 line-length = 79
 
@@ -47,7 +62,8 @@
 docstring-code-format = true
 
 [tool.ruff.lint]
-select = ["E4", "E5", "E7", "E9", "F", "S", "U"]
+select = ["E4", "E5", "E7", "E9", "F", "G", "LOG", "S", "UP"]
+external = ["H"]
 ignore = [
     # we only use asserts for type narrowing
     "S101",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/requirements.txt 
new/oslotest-6.1.0/requirements.txt
--- old/oslotest-6.0.0/requirements.txt 2025-11-11 14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/requirements.txt 2026-03-24 11:31:36.000000000 +0100
@@ -1,3 +1,2 @@
 fixtures>=3.0.0 # Apache-2.0/BSD
-python-subunit>=1.0.0 # Apache-2.0/BSD
 testtools>=2.2.0 # MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/oslotest-6.0.0/tox.ini new/oslotest-6.1.0/tox.ini
--- old/oslotest-6.0.0/tox.ini  2025-11-11 14:30:30.000000000 +0100
+++ new/oslotest-6.1.0/tox.ini  2026-03-24 11:31:36.000000000 +0100
@@ -10,10 +10,23 @@
 commands = stestr run --slowest {posargs}
 
 [testenv:pep8]
+description =
+  Run style checks.
 deps =
   pre-commit
+  {[testenv:mypy]deps}
 commands =
   pre-commit run -a
+  {[testenv:mypy]commands}
+
+[testenv:mypy]
+description =
+  Run type checks.
+deps =
+  {[testenv]deps}
+  mypy
+commands =
+  mypy --cache-dir="{envdir}/mypy_cache" {posargs:oslotest}
 
 [testenv:cover]
 setenv =
@@ -42,7 +55,7 @@
 
 [flake8]
 # We only enable the hacking (H) checks
-select = H,O
+select = H
 # H301 Black will put commas after imports that can't fit on one line
 ignore = H301
 show-source = true

Reply via email to