Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-roman-numerals for
openSUSE:Factory checked in at 2026-03-11 20:49:45
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-roman-numerals (Old)
and /work/SRC/openSUSE:Factory/.python-roman-numerals.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-roman-numerals"
Wed Mar 11 20:49:45 2026 rev:3 rq:1337903 version:4.1.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-roman-numerals/python-roman-numerals.changes
2025-04-15 16:48:01.740437838 +0200
+++
/work/SRC/openSUSE:Factory/.python-roman-numerals.new.8177/python-roman-numerals.changes
2026-03-11 20:49:52.452524690 +0100
@@ -1,0 +2,9 @@
+Wed Mar 4 08:27:57 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 4.1.0:
+ * Rename Python package to roman-numerals on PyPI.
+ * Drop support for Python 3.9.
+ * Declare support for Python 3.15.
+ * Increase the minimum supported Rust version (MSRV) to 1.81.0.
+
+-------------------------------------------------------------------
Old:
----
roman_numerals-3.1.0.tar.gz
New:
----
roman_numerals-4.1.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-roman-numerals.spec ++++++
--- /var/tmp/diff_new_pack.QbE314/_old 2026-03-11 20:49:54.172594426 +0100
+++ /var/tmp/diff_new_pack.QbE314/_new 2026-03-11 20:49:54.188595075 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-roman-numerals
#
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,19 +18,16 @@
%{?sle15_python_module_pythons}
Name: python-roman-numerals
-Version: 3.1.0
+Version: 4.1.0
Release: 0
Summary: Manipulate well-formed Roman numerals
License: 0BSD
URL: https://github.com/AA-Turner/roman-numerals/
Source:
https://files.pythonhosted.org/packages/source/r/roman-numerals/roman_numerals-%{version}.tar.gz
-BuildRequires: %{python_module flit-core >= 3.7}
+BuildRequires: %{python_module flit-core >= 3.12}
BuildRequires: %{python_module pip}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
-Suggests: python-mypy = 1.15.0
-Suggests: python-pyright = 1.1.394
-Suggests: python-ruff = 0.9.7
BuildArch: noarch
# SECTION test requirements
BuildRequires: %{python_module pytest >= 8}
++++++ roman_numerals-3.1.0.tar.gz -> roman_numerals-4.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/roman_numerals-3.1.0/PKG-INFO
new/roman_numerals-4.1.0/PKG-INFO
--- old/roman_numerals-3.1.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/roman_numerals-4.1.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
@@ -1,35 +1,28 @@
Metadata-Version: 2.4
Name: roman-numerals
-Version: 3.1.0
+Version: 4.1.0
Summary: Manipulate well-formed Roman numerals
Author: Adam Turner
-Requires-Python: >=3.9
+Requires-Python: >=3.10
Description-Content-Type: text/x-rst
+License-Expression: 0BSD OR CC0-1.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: Zero-Clause BSD (0BSD)
-Classifier: License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
-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: Programming Language :: Python :: 3.15
License-File: LICENCE.rst
-Requires-Dist: mypy==1.15.0 ; extra == "lint"
-Requires-Dist: ruff==0.9.7 ; extra == "lint"
-Requires-Dist: pyright==1.1.394 ; extra == "lint"
-Requires-Dist: pytest>=8 ; extra == "test"
Project-URL: Changelog,
https://github.com/AA-Turner/roman-numerals/blob/master/CHANGES.rst
Project-URL: Code, https://github.com/AA-Turner/roman-numerals/
Project-URL: Download, https://pypi.org/project/roman-numerals/
Project-URL: Issue tracker, https://github.com/AA-Turner/roman-numerals/issues
-Provides-Extra: lint
-Provides-Extra: test
===============
roman-numerals
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/roman_numerals-3.1.0/pyproject.toml
new/roman_numerals-4.1.0/pyproject.toml
--- old/roman_numerals-3.1.0/pyproject.toml 2025-03-12 01:38:03.517545700
+0100
+++ new/roman_numerals-4.1.0/pyproject.toml 2025-12-17 19:25:19.569588200
+0100
@@ -3,7 +3,7 @@
# Use flit as a build backend (https://flit.pypa.io/)
# Build with (https://build.pypa.io/)
[build-system]
-requires = ["flit_core>=3.7,<4"]
+requires = ["flit_core>=3.12,<4"]
build-backend = "flit_core.buildapi"
# Project metadata
@@ -16,25 +16,23 @@
urls.Code = "https://github.com/AA-Turner/roman-numerals/"
urls.Download = "https://pypi.org/project/roman-numerals/"
urls."Issue tracker" = "https://github.com/AA-Turner/roman-numerals/issues"
-license.file = "LICENCE.rst"
-requires-python = ">=3.9"
+license = "0BSD OR CC0-1.0"
+requires-python = ">=3.10"
# Classifiers list: https://pypi.org/classifiers/
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: Developers",
- "License :: OSI Approved :: Zero-Clause BSD (0BSD)",
- "License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
- "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",
+ "Programming Language :: Python :: 3.15",
]
dependencies = []
dynamic = ["version"]
@@ -42,14 +40,23 @@
[[project.authors]]
name = "Adam Turner"
-[project.optional-dependencies]
+[dependency-groups]
+lint = [
+ "ruff==0.14.9",
+]
+package = [
+ "build",
+ "pypi-attestations==0.0.29",
+ "twine>=6.1",
+]
test = [
- "pytest>=8",
+ "pytest>=9",
]
-lint = [
- "mypy==1.15.0",
- "ruff==0.9.7",
- "pyright==1.1.394",
+types = [
+ "mypy==1.19.1",
+ "pyrefly",
+ "pyright==1.1.407",
+ "ty",
]
[tool.flit.module]
@@ -65,7 +72,7 @@
"roman_numerals",
"tests",
]
-python_version = "3.9"
+python_version = "3.10"
strict = true
show_column_numbers = true
show_error_context = true
@@ -91,20 +98,3 @@
"roman_numerals",
"tests",
]
-
-[tool.pytest.ini_options]
-minversion = "6.0"
-addopts = [
- "-ra",
- "--import-mode=prepend",
- "--pythonwarnings=error",
- "--strict-config",
- "--strict-markers",
-]
-empty_parameter_set_mark = "xfail"
-filterwarnings = [
- "all",
-]
-log_cli_level = "INFO"
-testpaths = ["tests"]
-xfail_strict = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/roman_numerals-3.1.0/roman_numerals/__init__.py
new/roman_numerals-4.1.0/roman_numerals/__init__.py
--- old/roman_numerals-3.1.0/roman_numerals/__init__.py 2025-03-12
01:37:57.164751300 +0100
+++ new/roman_numerals-4.1.0/roman_numerals/__init__.py 2025-12-17
19:25:19.569588200 +0100
@@ -12,19 +12,17 @@
TYPE_CHECKING = False
if TYPE_CHECKING:
- from typing import Final, TypeVar, final
+ from typing import Final, final
from typing_extensions import Self
-
- _T = TypeVar('_T')
else:
- def final(f: _T) -> _T:
+ def final(f): # NoQA: ANN001, ANN202
return f
-__version__: Final = '3.1.0'
-version_info: Final = (3, 1, 0)
+__version__: Final = '4.1.0'
+version_info: Final = (4, 1, 0)
__all__: Final = (
'MAX',
@@ -70,15 +68,18 @@
__slots__ = ('_value',)
_value: int
- def __init__(self, value: int, /) -> None:
- if not isinstance(value, int): # pyright:
ignore[reportUnnecessaryIsInstance]
- value_qualname = type(value).__qualname__
- msg = f'RomanNumeral: an integer is required, not
{value_qualname!r}'
+ def __new__(cls, value: int, /) -> Self:
+ """Construct a RomanNumeral from an integer."""
+ if type(value) is not int:
+ type_name = type(value).__qualname__
+ msg = f'RomanNumeral() argument must be an integer, not
{type_name!r}'
raise TypeError(msg)
if value < MIN or value > MAX:
- msg = f'Number out of range (must be between 1 and 3,999). Got
{value}.'
+ msg = f'{value} is out of range (must be between 1 and 3,999).'
raise OutOfRangeError(msg)
- super().__setattr__('_value', value)
+ obj: Self = object.__new__(cls) # pyrefly: ignore[bad-assignment]
+ object.__setattr__(obj, '_value', value)
+ return obj
def __int__(self) -> int:
"""Return the integer value of this numeral."""
@@ -115,6 +116,13 @@
raise AttributeError(msg)
super().__setattr__(key, value)
+ def __delattr__(self, key: str) -> None:
+ """Implement delattr(self, name)."""
+ if key == '_value':
+ msg = f'Cannot delete the {key!r} attribute.'
+ raise AttributeError(msg)
+ super().__delattr__(key)
+
def to_uppercase(self) -> str:
"""Convert a ``RomanNumeral`` to an uppercase string.
@@ -247,7 +255,7 @@
raise InvalidRomanNumeralError(string)
-_ROMAN_NUMERAL_PREFIXES: Final = [
+_ROMAN_NUMERAL_PREFIXES: Final = (
(1000, sys.intern('M'), sys.intern('m')),
(900, sys.intern('CM'), sys.intern('cm')),
(500, sys.intern('D'), sys.intern('d')),
@@ -261,5 +269,5 @@
(5, sys.intern('V'), sys.intern('v')),
(4, sys.intern('IV'), sys.intern('iv')),
(1, sys.intern('I'), sys.intern('i')),
-]
+)
"""Numeral value, uppercase character, and lowercase character."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/roman_numerals-3.1.0/tests/test_from_string.py
new/roman_numerals-4.1.0/tests/test_from_string.py
--- old/roman_numerals-3.1.0/tests/test_from_string.py 2025-03-12
01:37:57.164751300 +0100
+++ new/roman_numerals-4.1.0/tests/test_from_string.py 2025-12-17
19:25:19.570588000 +0100
@@ -1,5 +1,3 @@
-from __future__ import annotations
-
import pytest
from roman_numerals import (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/roman_numerals-3.1.0/tests/test_new_roman_numeral.py
new/roman_numerals-4.1.0/tests/test_new_roman_numeral.py
--- old/roman_numerals-3.1.0/tests/test_new_roman_numeral.py 2025-03-12
01:37:57.164751300 +0100
+++ new/roman_numerals-4.1.0/tests/test_new_roman_numeral.py 2025-12-17
19:25:19.570588000 +0100
@@ -1,5 +1,3 @@
-from __future__ import annotations
-
import pytest
from roman_numerals import (
@@ -14,7 +12,7 @@
with pytest.raises(OutOfRangeError) as ctx:
RomanNumeral(0)
msg = str(ctx.value)
- assert msg == 'Number out of range (must be between 1 and 3,999). Got 0.'
+ assert msg == '0 is out of range (must be between 1 and 3,999).'
def test_one() -> None:
@@ -41,18 +39,45 @@
with pytest.raises(OutOfRangeError) as ctx:
RomanNumeral(4_000)
msg = str(ctx.value)
- assert msg == 'Number out of range (must be between 1 and 3,999). Got
4000.'
+ assert msg == '4000 is out of range (must be between 1 and 3,999).'
def test_minus_one() -> None:
with pytest.raises(OutOfRangeError) as ctx:
RomanNumeral(-1)
msg = str(ctx.value)
- assert msg == 'Number out of range (must be between 1 and 3,999). Got -1.'
+ assert msg == '-1 is out of range (must be between 1 and 3,999).'
def test_float() -> None:
with pytest.raises(TypeError) as ctx:
RomanNumeral(4.2) # type: ignore[arg-type]
msg = str(ctx.value)
- assert msg == "RomanNumeral: an integer is required, not 'float'"
+ assert msg == "RomanNumeral() argument must be an integer, not 'float'"
+
+
+def test_mutation() -> None:
+ obj = RomanNumeral(MIN)
+ with pytest.raises(AttributeError, match=r"Cannot set the '_value'
attribute."):
+ obj._value = 0 # NoQA: SLF001 # pyright: ignore[reportPrivateUsage]
+ with pytest.raises(AttributeError, match=r"Cannot delete the '_value'
attribute."):
+ del obj._value # NoQA: SLF001 # pyright: ignore[reportPrivateUsage]
+
+
+def test_non_existing_attribute() -> None:
+ obj = RomanNumeral(MIN)
+ with pytest.raises(
+ AttributeError,
+ match=r"'RomanNumeral' object has no attribute 'spam'",
+ ):
+ _ = obj.spam # type: ignore[attr-defined]
+ with pytest.raises(
+ AttributeError,
+ match=r"'RomanNumeral' object has no attribute 'spam'",
+ ):
+ obj.spam = 0
+ with pytest.raises(
+ AttributeError,
+ match=r"'RomanNumeral' object has no attribute 'spam'",
+ ):
+ del obj.spam # type: ignore[attr-defined]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/roman_numerals-3.1.0/tests/test_round_trip.py
new/roman_numerals-4.1.0/tests/test_round_trip.py
--- old/roman_numerals-3.1.0/tests/test_round_trip.py 2025-03-12
01:34:00.457255800 +0100
+++ new/roman_numerals-4.1.0/tests/test_round_trip.py 2025-12-17
19:25:19.570588000 +0100
@@ -1,5 +1,3 @@
-from __future__ import annotations
-
from roman_numerals import (
MAX,
MIN,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/roman_numerals-3.1.0/tests/test_to_string.py
new/roman_numerals-4.1.0/tests/test_to_string.py
--- old/roman_numerals-3.1.0/tests/test_to_string.py 2025-03-12
01:37:57.164751300 +0100
+++ new/roman_numerals-4.1.0/tests/test_to_string.py 2025-12-17
19:25:19.570588000 +0100
@@ -1,5 +1,3 @@
-from __future__ import annotations
-
import pytest
from roman_numerals import (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/roman_numerals-3.1.0/tests/utils.py
new/roman_numerals-4.1.0/tests/utils.py
--- old/roman_numerals-3.1.0/tests/utils.py 2025-03-12 01:37:57.164751300
+0100
+++ new/roman_numerals-4.1.0/tests/utils.py 2025-12-17 19:25:19.570588000
+0100
@@ -1,5 +1,3 @@
-from __future__ import annotations
-
TEST_NUMERALS_UPPER = [
'I',
'II',