SF.net SVN: docutils:[10047 ] trunk/docutils/docutils/ utils
aa-turner--- via Docutils-checkins <[email protected]> Sun, 09 Mar 2025 02:07:24 +0000
| Newsgroups | gmane.text.docutils.cvs |
|---|---|
| Message-ID | <[email protected]> |
Revision: 10047
http://sourceforge.net/p/docutils/code/10047
Author: aa-turner
Date: 2025-03-09 02:07:23 +0000 (Sun, 09 Mar 2025)
Log Message:
-----------
Update ``_roman_numerals``
* Remove runtime ``typing`` import
* Add type annotations
* Rephrase docstrings to the imperative mood and add missing docstrings
* Use ``cls`` in classmethods
Modified Paths:
--------------
trunk/docutils/docutils/utils/_roman_numerals.py
trunk/docutils/docutils/utils/_typing.py
Modified: trunk/docutils/docutils/utils/_roman_numerals.py
===================================================================
--- trunk/docutils/docutils/utils/_roman_numerals.py 2025-03-09 01:45:28 UTC (rev 10046)
+++ trunk/docutils/docutils/utils/_roman_numerals.py 2025-03-09 02:07:23 UTC (rev 10047)
@@ -11,17 +11,22 @@
from __future__ import annotations
import sys
-from typing import TYPE_CHECKING, final
+TYPE_CHECKING = False
if TYPE_CHECKING:
- from typing import Final, Self
+ from typing import Final, final
-__all__ = (
+ from docutils.utils._typing import Self
+else:
+ from docutils.utils._typing import final
+
+
+__all__: Final = (
+ 'MAX',
'MIN',
- 'MAX',
+ 'InvalidRomanNumeralError',
+ 'OutOfRangeError',
'RomanNumeral',
- 'OutOfRangeError',
- 'InvalidRomanNumeralError',
)
MIN: Final = 1
@@ -35,14 +40,16 @@
"""The value of the largest well-formed roman numeral."""
+@final
class OutOfRangeError(TypeError):
"""Number out of range (must be between 1 and 4,999)."""
+@final
class InvalidRomanNumeralError(ValueError):
"""Not a valid Roman numeral."""
- def __init__(self, value, *args):
+ def __init__(self, value: str, *args: object) -> None:
msg = f'Invalid Roman numeral: {value}'
super().__init__(msg, *args)
@@ -58,53 +65,63 @@
>>> print(answer.to_uppercase())
XLII
"""
+
__slots__ = ('_value',)
_value: int
def __init__(self, value: int, /) -> None:
if not isinstance(value, int):
- msg = 'RomanNumeral: an integer is required, not %r'
- raise TypeError(msg % type(value).__qualname__)
+ value_qualname = type(value).__qualname__
+ msg = f'RomanNumeral: an integer is required, not {value_qualname!r}' # NoQA: E501
+ raise TypeError(msg)
if value < MIN or value > MAX:
- msg = 'Number out of range (must be between 1 and 4,999). Got %s.'
- raise OutOfRangeError(msg % value)
+ msg = f'Number out of range (must be between 1 and 4,999). Got {value}.' # NoQA: E501
+ raise OutOfRangeError(msg)
super().__setattr__('_value', value)
def __int__(self) -> int:
+ """Return the integer value of this numeral."""
return self._value
def __str__(self) -> str:
+ """Return the well-formed (uppercase) string for this numeral."""
return self.to_uppercase()
- def __repr__(self):
+ def __repr__(self) -> str:
+ """Return the string representation of this numeral."""
return f'{self.__class__.__name__}({self._value!r})'
- def __eq__(self, other):
+ def __eq__(self, other: object) -> bool:
+ """Return self == other."""
if isinstance(other, RomanNumeral):
return self._value == other._value
return NotImplemented
- def __lt__(self, other):
+ def __lt__(self, other: object) -> bool:
+ """Return self < other."""
if isinstance(other, RomanNumeral):
return self._value < other._value
return NotImplemented
- def __hash__(self):
+ def __hash__(self) -> int:
+ """Return the hashed value of this numeral."""
return hash(self._value)
- def __setattr__(self, key, value):
+ def __setattr__(self, key: str, value: object) -> None:
+ """Implement setattr(self, name, value)."""
if key == '_value':
- raise AttributeError('Cannot set the value attribute.')
+ msg = f'Cannot set the {key!r} attribute.'
+ raise AttributeError(msg)
super().__setattr__(key, value)
def to_uppercase(self) -> str:
- """Converts a ``RomanNumeral`` to an uppercase string.
+ """Convert a ``RomanNumeral`` to an uppercase string.
>>> answer = RomanNumeral(42)
>>> assert answer.to_uppercase() == 'XLII'
"""
- out = []
- n = int(self)
+ out: list[str] = []
+ n = self._value
for value, name, _ in _ROMAN_NUMERAL_PREFIXES:
while n >= value:
n -= value
@@ -112,13 +129,13 @@
return ''.join(out)
def to_lowercase(self) -> str:
- """Converts a ``RomanNumeral`` to a lowercase string.
+ """Convert a ``RomanNumeral`` to a lowercase string.
>>> answer = RomanNumeral(42)
>>> assert answer.to_lowercase() == 'xlii'
"""
- out = []
- n = int(self)
+ out: list[str] = []
+ n = self._value
for value, _, name in _ROMAN_NUMERAL_PREFIXES:
while n >= value:
n -= value
@@ -126,8 +143,8 @@
return ''.join(out)
@classmethod
- def from_string(self, string: str, /) -> Self:
- """Creates a ``RomanNumeral`` from a well-formed string representation.
+ def from_string(cls, string: str, /) -> Self:
+ """Create a ``RomanNumeral`` from a well-formed string representation.
Returns ``RomanNumeral`` or raises ``InvalidRomanNumeralError``.
@@ -162,7 +179,7 @@
else:
break
if len(chars) == idx:
- return RomanNumeral(result)
+ return cls(result)
# Hundreds: 900 ("CM"), 400 ("CD"), 0-300 (0 to 3 "C" chars),
# or 500-800 ("D", followed by 0 to 3 "C" chars)
@@ -183,7 +200,7 @@
else:
break
if len(chars) == idx:
- return RomanNumeral(result)
+ return cls(result)
# Tens: 90 ("XC"), 40 ("XL"), 0-30 (0 to 3 "X" chars),
# or 50-80 ("L", followed by 0 to 3 "X" chars)
@@ -204,7 +221,7 @@
else:
break
if len(chars) == idx:
- return RomanNumeral(result)
+ return cls(result)
# Ones: 9 ("IX"), 4 ("IV"), 0-3 (0 to 3 "I" chars),
# or 5-8 ("V", followed by 0 to 3 "I" chars)
@@ -225,7 +242,7 @@
else:
break
if len(chars) == idx:
- return RomanNumeral(result)
+ return cls(result)
raise InvalidRomanNumeralError(string)
Modified: trunk/docutils/docutils/utils/_typing.py
===================================================================
--- trunk/docutils/docutils/utils/_typing.py 2025-03-09 01:45:28 UTC (rev 10046)
+++ trunk/docutils/docutils/utils/_typing.py 2025-03-09 02:07:23 UTC (rev 10047)
@@ -9,8 +9,13 @@
if TYPE_CHECKING:
import sys
from collections.abc import Callable
- from typing import Any, Final, TypeVar, overload
+ from typing import Any, Final, TypeVar, final, overload
+ if sys.version_info[:2] >= (3, 11):
+ from typing import Self
+ else:
+ from typing_extensions import Self # NoQA: F401
+
if sys.version_info[:2] >= (3, 12):
from typing import TypeAlias
else:
@@ -17,8 +22,12 @@
from typing_extensions import TypeAlias # NoQA: F401
_F = TypeVar("_F", bound=Callable[..., Any])
+ _T = TypeVar('_T')
else:
+ def final(f: _T) -> _T:
+ return f
+
def _overload_inner(*args, **kwds):
raise NotImplementedError
@@ -26,4 +35,4 @@
def overload(func: _F) -> _F:
return _overload_inner
-__all__: Final = ('overload',)
+__all__: Final = ('final', 'overload')
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.