Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-curtsies for openSUSE:Factory 
checked in at 2025-07-14 10:51:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-curtsies (Old)
 and      /work/SRC/openSUSE:Factory/.python-curtsies.new.7373 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-curtsies"

Mon Jul 14 10:51:43 2025 rev:17 rq:1292442 version:0.4.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-curtsies/python-curtsies.changes  
2025-05-26 18:41:46.335135838 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-curtsies.new.7373/python-curtsies.changes    
    2025-07-14 10:57:02.369906848 +0200
@@ -1,0 +2,7 @@
+Sat Jul 12 17:32:38 UTC 2025 - Dirk Müller <dmuel...@suse.com>
+
+- update to 0.4.3:
+  * Drop support for Python 3.7, 3.8, and 3.9.
+  * Add support for italic.
+
+-------------------------------------------------------------------

Old:
----
  curtsies-0.4.2.tar.gz

New:
----
  curtsies-0.4.3.tar.gz

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

Other differences:
------------------
++++++ python-curtsies.spec ++++++
--- /var/tmp/diff_new_pack.INBVhM/_old  2025-07-14 10:57:03.029934210 +0200
+++ /var/tmp/diff_new_pack.INBVhM/_new  2025-07-14 10:57:03.029934210 +0200
@@ -19,7 +19,7 @@
 %define         skip_python2 1
 %define         skip_python36 1
 Name:           python-curtsies
-Version:        0.4.2
+Version:        0.4.3
 Release:        0
 Summary:        Curses-like terminal wrapper, with colored strings!
 License:        MIT

++++++ curtsies-0.4.2.tar.gz -> curtsies-0.4.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/PKG-INFO new/curtsies-0.4.3/PKG-INFO
--- old/curtsies-0.4.2/PKG-INFO 2023-07-31 22:18:29.564929200 +0200
+++ new/curtsies-0.4.3/PKG-INFO 2025-06-05 08:33:12.418394000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: curtsies
-Version: 0.4.2
+Version: 0.4.3
 Summary: Curses-like terminal wrapper, with colored strings!
 Home-page: https://github.com/bpython/curtsies
 Author: Thomas Ballinger
@@ -13,9 +13,12 @@
 Classifier: Operating System :: POSIX
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Requires-Python: >=3.7
+Requires-Python: >=3.10
 Description-Content-Type: text/markdown
 License-File: LICENSE
+Requires-Dist: blessed>=1.5
+Requires-Dist: cwcwidth
+Dynamic: license-file
 
 [![Documentation 
Status](https://readthedocs.org/projects/curtsies/badge/?version=latest)](https://readthedocs.org/projects/curtsies/?badge=latest)
 ![Curtsies Logo](http://ballingt.com/assets/curtsiestitle.png)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/__init__.py 
new/curtsies-0.4.3/curtsies/__init__.py
--- old/curtsies-0.4.2/curtsies/__init__.py     2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/__init__.py     2025-06-05 08:33:08.000000000 
+0200
@@ -1,5 +1,6 @@
 """Terminal-formatted strings"""
-__version__ = "0.4.2"
+
+__version__ = "0.4.3"
 
 from .window import FullscreenWindow, CursorAwareWindow
 from .input import Input
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/configfile_keynames.py 
new/curtsies-0.4.3/curtsies/configfile_keynames.py
--- old/curtsies-0.4.2/curtsies/configfile_keynames.py  2023-07-31 
22:18:21.000000000 +0200
+++ new/curtsies-0.4.3/curtsies/configfile_keynames.py  2025-06-05 
08:33:08.000000000 +0200
@@ -15,7 +15,7 @@
 class KeyMap:
     """Maps config file key syntax to Curtsies names"""
 
-    def __getitem__(self, key: str) -> Tuple[str, ...]:
+    def __getitem__(self, key: str) -> tuple[str, ...]:
         if not key:  # Unbound key
             return ()
         elif key in SPECIALS:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/curtsieskeys.py 
new/curtsies-0.4.3/curtsies/curtsieskeys.py
--- old/curtsies-0.4.2/curtsies/curtsieskeys.py 2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/curtsieskeys.py 2025-06-05 08:33:08.000000000 
+0200
@@ -1,4 +1,5 @@
 """All the key sequences"""
+
 # If you add a binding, add something about your setup
 # if you can figure out why it's different
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/escseqparse.py 
new/curtsies-0.4.3/curtsies/escseqparse.py
--- old/curtsies-0.4.2/curtsies/escseqparse.py  2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/escseqparse.py  2025-06-05 08:33:08.000000000 
+0200
@@ -11,15 +11,15 @@
 
 from typing import (
     List,
-    Mapping,
     Union,
     Tuple,
-    Match,
     cast,
     Dict,
     Any,
     Optional,
 )
+from collections.abc import Mapping
+from re import Match
 
 import re
 
@@ -34,14 +34,14 @@
 )
 
 
-Token = Dict[str, Union[str, List[int]]]
+Token = dict[str, Union[str, list[int]]]
 
 
 def remove_ansi(s: str) -> str:
     return re.sub(r"(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]", "", s)
 
 
-def parse(s: str) -> List[Union[str, Dict[str, Union[str, bool, None]]]]:
+def parse(s: str) -> list[str | dict[str, str | bool | None]]:
     r"""
     Returns a list of strings or format dictionaries to describe the strings.
 
@@ -52,7 +52,7 @@
     >>> 
parse("\x1b[33m[\x1b[39m\x1b[33m]\x1b[39m\x1b[33m[\x1b[39m\x1b[33m]\x1b[39m\x1b[33m[\x1b[39m\x1b[33m]\x1b[39m\x1b[33m[\x1b[39m")
     [{'fg': 'yellow'}, '[', {'fg': None}, {'fg': 'yellow'}, ']', {'fg': None}, 
{'fg': 'yellow'}, '[', {'fg': None}, {'fg': 'yellow'}, ']', {'fg': None}, 
{'fg': 'yellow'}, '[', {'fg': None}, {'fg': 'yellow'}, ']', {'fg': None}, 
{'fg': 'yellow'}, '[', {'fg': None}]
     """
-    stuff: List[Union[str, Dict[str, Union[str, bool, None]]]] = []
+    stuff: list[str | dict[str, str | bool | None]] = []
     rest = s
     while True:
         front, token, rest = peel_off_esc_code(rest)
@@ -73,7 +73,7 @@
     return stuff
 
 
-def peel_off_esc_code(s: str) -> Tuple[str, Optional[Token], str]:
+def peel_off_esc_code(s: str) -> tuple[str, Token | None, str]:
     r"""Returns processed text, the next token, and unprocessed text
 
     >>> front, d, rest = peel_off_esc_code('somestuff')
@@ -114,7 +114,7 @@
         m = None
 
     if m:
-        d: Dict[str, Any] = m.groupdict()
+        d: dict[str, Any] = m.groupdict()
         del d["front"]
         del d["rest"]
         if "numbers" in d and all(d["numbers"].split(";")):
@@ -125,12 +125,12 @@
         return s, None, ""
 
 
-def token_type(info: Token) -> Optional[List[Dict[str, Union[str, bool, 
None]]]]:
+def token_type(info: Token) -> list[dict[str, str | bool | None]] | None:
     if info["command"] == "m":
         # The default action for ESC[m is to act like ESC[0m
         # Ref: https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes
-        values = cast(List[int], info["numbers"]) if len(info["numbers"]) else 
[0]
-        tokens: List[Dict[str, Union[str, bool, None]]] = []
+        values = cast(list[int], info["numbers"]) if len(info["numbers"]) else 
[0]
+        tokens: list[dict[str, str | bool | None]] = []
         for value in values:
             if value in FG_NUMBER_TO_COLOR:
                 tokens.append({"fg": FG_NUMBER_TO_COLOR[value]})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/events.py 
new/curtsies-0.4.3/curtsies/events.py
--- old/curtsies-0.4.2/curtsies/events.py       2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/events.py       2025-06-05 08:33:08.000000000 
+0200
@@ -1,9 +1,11 @@
 """Events for keystrokes and other input events"""
+
 import codecs
 import itertools
 import sys
 from enum import Enum, auto
-from typing import Optional, List, Sequence, Union
+from typing import Optional, List, Union
+from collections.abc import Sequence
 
 from .termhelpers import Termmode
 from .curtsieskeys import CURTSIES_NAMES as special_curtsies_names
@@ -103,9 +105,7 @@
 
 
 class WindowChangeEvent(Event):
-    def __init__(
-        self, rows: int, columns: int, cursor_dy: Optional[int] = None
-    ) -> None:
+    def __init__(self, rows: int, columns: int, cursor_dy: int | None = None) 
-> None:
         self.rows = rows
         self.columns = columns
         self.cursor_dy = cursor_dy
@@ -143,7 +143,7 @@
     """
 
     def __init__(self) -> None:
-        self.events: List[str] = []
+        self.events: list[str] = []
 
     def __repr__(self) -> str:
         return "<Paste Event with data: %r>" % self.events
@@ -200,7 +200,7 @@
     encoding: str,
     keynames: Keynames = Keynames.CURTSIES,
     full: bool = False,
-) -> Optional[str]:
+) -> str | None:
     """Return key pressed from bytes_ or None
 
     Return a key name or None meaning it's an incomplete sequence of bytes
@@ -279,7 +279,7 @@
     )
 
 
-def pp_event(seq: Union[Event, str]) -> Union[str, bytes]:
+def pp_event(seq: Event | str) -> str | bytes:
     """Returns pretty representation of an Event or keypress"""
 
     if isinstance(seq, Event):
@@ -288,7 +288,7 @@
     # Get the original sequence back if seq is a pretty name already
     rev_curses = {v: k for k, v in CURSES_NAMES.items()}
     rev_curtsies = {v: k for k, v in CURTSIES_NAMES.items()}
-    bytes_seq: Optional[bytes] = None
+    bytes_seq: bytes | None = None
     if seq in rev_curses:
         bytes_seq = rev_curses[seq]
     elif seq in rev_curtsies:
@@ -301,7 +301,7 @@
     return repr(seq).lstrip("u")[1:-1]
 
 
-def curtsies_name(seq: bytes) -> Union[str, bytes]:
+def curtsies_name(seq: bytes) -> str | bytes:
     return CURTSIES_NAMES.get(seq, seq)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/fmtfuncs.py 
new/curtsies-0.4.3/curtsies/fmtfuncs.py
--- old/curtsies-0.4.2/curtsies/fmtfuncs.py     2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/fmtfuncs.py     2025-06-05 08:33:08.000000000 
+0200
@@ -22,6 +22,7 @@
 
 bold = _partial(fmtstr, style="bold")
 dark = _partial(fmtstr, style="dark")
+italic = _partial(fmtstr, style="italic")
 underline = _partial(fmtstr, style="underline")
 blink = _partial(fmtstr, style="blink")
 invert = _partial(fmtstr, style="invert")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/formatstring.py 
new/curtsies-0.4.3/curtsies/formatstring.py
--- old/curtsies-0.4.2/curtsies/formatstring.py 2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/formatstring.py 2025-06-05 08:33:08.000000000 
+0200
@@ -21,27 +21,19 @@
 
 import re
 from cwcwidth import wcswidth, wcwidth
+from functools import cached_property
 from itertools import chain
 from typing import (
     Any,
-    Callable,
     Dict,
-    Iterable,
-    Iterator,
     List,
-    Mapping,
-    MutableMapping,
     Optional,
     Tuple,
     Union,
     cast,
     no_type_check,
 )
-
-try:
-    from functools import cached_property
-except ImportError:
-    from backports.cached_property import cached_property  # type: ignore
+from collections.abc import Callable, Iterable, Iterator, Mapping, 
MutableMapping
 
 from .escseqparse import parse, remove_ansi
 from .termformatconstants import (
@@ -59,27 +51,28 @@
 one_arg_xforms: Mapping[str, Callable[[str], str]] = {
     "bold": lambda s: seq(STYLES["bold"]) + s + seq(RESET_ALL),
     "dark": lambda s: seq(STYLES["dark"]) + s + seq(RESET_ALL),
+    "italic": lambda s: seq(STYLES["italic"]) + s + seq(RESET_ALL),
     "underline": lambda s: seq(STYLES["underline"]) + s + seq(RESET_ALL),
     "blink": lambda s: seq(STYLES["blink"]) + s + seq(RESET_ALL),
     "invert": lambda s: seq(STYLES["invert"]) + s + seq(RESET_ALL),
 }
 
 two_arg_xforms: Mapping[str, Callable[[str, int], str]] = {
-    "fg": lambda s, v: "{}{}{}".format(seq(v), s, seq(RESET_FG)),
+    "fg": lambda s, v: f"{seq(v)}{s}{seq(RESET_FG)}",
     "bg": lambda s, v: seq(v) + s + seq(RESET_BG),
 }
 
 
-class FrozenAttributes(Dict[str, Union[int, bool]]):
+class FrozenAttributes(dict[str, Union[int, bool]]):
     """Immutable dictionary class for format string attributes"""
 
-    def __setitem__(self, key: str, value: Union[int, bool]) -> None:
+    def __setitem__(self, key: str, value: int | bool) -> None:
         raise Exception("Cannot change value.")
 
     def update(self, *args: Any, **kwds: Any) -> None:
         raise Exception("Cannot change value.")
 
-    def extend(self, dictlike: Mapping[str, Union[int, bool]]) -> 
"FrozenAttributes":
+    def extend(self, dictlike: Mapping[str, int | bool]) -> "FrozenAttributes":
         return FrozenAttributes(chain(self.items(), dictlike.items()))
 
     def remove(self, *keys: str) -> "FrozenAttributes":
@@ -92,9 +85,11 @@
     Does not work for dicts with unicode strings as values."""
     inner = ", ".join(
         "{}: {}".format(
-            repr(k)[1:]
-            if repr(k).startswith("u'") or repr(k).startswith('u"')
-            else repr(k),
+            (
+                repr(k)[1:]
+                if repr(k).startswith("u'") or repr(k).startswith('u"')
+                else repr(k)
+            ),
             v,
         )
         for k, v in sorted(d.items())
@@ -107,9 +102,7 @@
 
     Subject to change, not part of the API"""
 
-    def __init__(
-        self, string: str, atts: Optional[Mapping[str, Union[int, bool]]] = 
None
-    ):
+    def __init__(self, string: str, atts: Mapping[str, int | bool] | None = 
None):
         if not isinstance(string, str):
             raise ValueError("unicode string required, got %r" % string)
         self._s = string
@@ -216,7 +209,7 @@
             divides.append(divides[-1] + wcwidth(c))
         self.divides = divides
 
-    def request(self, max_width: int) -> Optional[Tuple[int, Chunk]]:
+    def request(self, max_width: int) -> tuple[int, Chunk] | None:
         """Requests a sub-chunk of max_width or shorter. Returns None if no 
chunks left."""
         if max_width < 1:
             raise ValueError("requires positive integer max_width")
@@ -283,10 +276,10 @@
         self.chunks = list(components)
 
         # caching these leads to a significant speedup
-        self._unicode: Optional[str] = None
-        self._len: Optional[int] = None
-        self._s: Optional[str] = None
-        self._width: Optional[int] = None
+        self._unicode: str | None = None
+        self._len: int | None = None
+        self._s: str | None = None
+        self._width: int | None = None
 
     @staticmethod
     def from_str(s: str) -> "FmtStr":
@@ -353,7 +346,7 @@
         return result
 
     def splice(
-        self, new_str: Union[str, "FmtStr"], start: int, end: Optional[int] = 
None
+        self, new_str: Union[str, "FmtStr"], start: int, end: int | None = None
     ) -> "FmtStr":
         """Returns a new FmtStr with the input string spliced into the
         the original FmtStr at start and end.
@@ -405,7 +398,7 @@
     def append(self, string: Union[str, "FmtStr"]) -> "FmtStr":
         return self.splice(string, len(self.s))
 
-    def copy_with_new_atts(self, **attributes: Union[bool, int]) -> "FmtStr":
+    def copy_with_new_atts(self, **attributes: bool | int) -> "FmtStr":
         """Returns a new FmtStr with the same content but new formatting"""
 
         return FmtStr(
@@ -414,8 +407,8 @@
 
     def join(self, iterable: Iterable[Union[str, "FmtStr"]]) -> "FmtStr":
         """Joins an iterable yielding strings or FmtStrs with self as 
separator"""
-        before: List[Chunk] = []
-        chunks: List[Chunk] = []
+        before: list[Chunk] = []
+        chunks: list[Chunk] = []
         for s in iterable:
             chunks.extend(before)
             before = self.chunks
@@ -430,10 +423,10 @@
     # TODO make this split work like str.split
     def split(
         self,
-        sep: Optional[str] = None,
-        maxsplit: Optional[int] = None,
+        sep: str | None = None,
+        maxsplit: int | None = None,
         regex: bool = False,
-    ) -> List["FmtStr"]:
+    ) -> list["FmtStr"]:
         """Split based on separator, optionally using a regex.
 
         Capture groups are ignored in regex, the whole pattern is matched
@@ -454,7 +447,7 @@
             )
         ]
 
-    def splitlines(self, keepends: bool = False) -> List["FmtStr"]:
+    def splitlines(self, keepends: bool = False) -> list["FmtStr"]:
         """Return a list of lines, split on newline characters,
         include line boundaries, if keepends is true."""
         lines = self.split("\n")
@@ -466,7 +459,7 @@
 
     # proxying to the string via __getattr__ is insufficient
     # because we shouldn't drop foreground or formatting info
-    def ljust(self, width: int, fillchar: Optional[str] = None) -> "FmtStr":
+    def ljust(self, width: int, fillchar: str | None = None) -> "FmtStr":
         """S.ljust(width[, fillchar]) -> string
 
         If a fillchar is provided, less formatting information will be 
preserved
@@ -481,7 +474,7 @@
             uniform = self.new_with_atts_removed("bg")
             return uniform + fmtstr(to_add, **self.shared_atts) if to_add else 
uniform
 
-    def rjust(self, width: int, fillchar: Optional[str] = None) -> "FmtStr":
+    def rjust(self, width: int, fillchar: str | None = None) -> "FmtStr":
         """S.rjust(width[, fillchar]) -> string
 
         If a fillchar is provided, less formatting information will be 
preserved
@@ -561,7 +554,7 @@
     # TODO ensure empty FmtStr isn't a problem
 
     @property
-    def shared_atts(self) -> Dict[str, Union[int, bool]]:
+    def shared_atts(self) -> dict[str, int | bool]:
         """Gets atts shared among all nonzero length component Chunks"""
         # TODO cache this, could get ugly for large FmtStrs
         atts = {}
@@ -583,7 +576,7 @@
         return result
 
     @no_type_check
-    def __getattr__(self, att):
+    def __getattr__(self, att: str):
         # thanks to @aerenchyma/@jczett
         if not hasattr(self.s, att):
             raise AttributeError(f"No attribute {att!r}")
@@ -601,7 +594,7 @@
         return func_help
 
     @property
-    def divides(self) -> List[int]:
+    def divides(self) -> list[int]:
         """List of indices of divisions between the constituent chunks."""
         acc = [0]
         for s in self.chunks:
@@ -615,7 +608,7 @@
         self._s = "".join(fs.s for fs in self.chunks)
         return self._s
 
-    def __getitem__(self, index: Union[int, slice]) -> "FmtStr":
+    def __getitem__(self, index: int | slice) -> "FmtStr":
         index = normalize_slice(len(self), index)
         counter = 0
         parts = []
@@ -635,7 +628,7 @@
                 break
         return FmtStr(*parts) if parts else fmtstr("")
 
-    def width_aware_slice(self, index: Union[int, slice]) -> "FmtStr":
+    def width_aware_slice(self, index: int | slice) -> "FmtStr":
         """Slice based on the number of columns it would take to display the 
substring."""
         if wcswidth(self.s, None) == -1:
             raise ValueError("bad values for width aware slicing")
@@ -691,7 +684,7 @@
         if chunks_of_line:
             yield FmtStr(*chunks_of_line)
 
-    def _getitem_normalized(self, index: Union[int, slice]) -> "FmtStr":
+    def _getitem_normalized(self, index: int | slice) -> "FmtStr":
         """Builds the more compact fmtstrs by using fromstr( of the control 
sequences)"""
         index = normalize_slice(len(self), index)
         counter = 0
@@ -753,7 +746,7 @@
     return "".join(new_chunk_chars)
 
 
-def linesplit(string: Union[str, FmtStr], columns: int) -> List[FmtStr]:
+def linesplit(string: str | FmtStr, columns: int) -> list[FmtStr]:
     """Returns a list of lines, split on the last possible space of each line.
 
     Split spaces will be removed. Whitespaces will be normalized to one space.
@@ -798,7 +791,7 @@
     return lines
 
 
-def normalize_slice(length: int, index: Union[int, slice]) -> slice:
+def normalize_slice(length: int, index: int | slice) -> slice:
     "Fill in the Nones in a slice."
     is_int = False
     if isinstance(index, int):
@@ -821,9 +814,9 @@
 
 
 def parse_args(
-    args: Tuple[str, ...],
-    kwargs: MutableMapping[str, Union[int, bool, str]],
-) -> Mapping[str, Union[int, bool]]:
+    args: tuple[str, ...],
+    kwargs: MutableMapping[str, int | bool | str],
+) -> MutableMapping[str, int | bool]:
     """Returns a kwargs dictionary by turning args into kwargs"""
     if "style" in kwargs:
         args += (cast(str, kwargs["style"]),)
@@ -859,7 +852,7 @@
     return cast(MutableMapping[str, Union[int, bool]], kwargs)
 
 
-def fmtstr(string: Union[str, FmtStr], *args: Any, **kwargs: Any) -> FmtStr:
+def fmtstr(string: str | FmtStr, *args: Any, **kwargs: Any) -> FmtStr:
     """
     Convenience function for creating a FmtStr
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/formatstringarray.py 
new/curtsies-0.4.3/curtsies/formatstringarray.py
--- old/curtsies-0.4.2/curtsies/formatstringarray.py    2023-07-31 
22:18:21.000000000 +0200
+++ new/curtsies-0.4.3/curtsies/formatstringarray.py    2025-06-05 
08:33:08.000000000 +0200
@@ -34,12 +34,12 @@
     Optional,
     Union,
     List,
-    Sequence,
     overload,
     Tuple,
     cast,
     no_type_check,
 )
+from collections.abc import Sequence
 
 logger = logging.getLogger(__name__)
 
@@ -60,7 +60,7 @@
         self, num_rows: int, num_columns: int, *args: Any, **kwargs: Any
     ) -> None:
         self.saved_args, self.saved_kwargs = args, kwargs
-        self.rows: List[FmtStr] = [fmtstr("", *args, **kwargs) for _ in 
range(num_rows)]
+        self.rows: list[FmtStr] = [fmtstr("", *args, **kwargs) for _ in 
range(num_rows)]
         self.num_columns = num_columns
 
     @overload
@@ -68,18 +68,16 @@
         pass
 
     @overload
-    def __getitem__(self, slicetuple: slice) -> List[FmtStr]:
+    def __getitem__(self, slicetuple: slice) -> list[FmtStr]:
         pass
 
     @overload
-    def __getitem__(
-        self, slicetuple: Tuple[Union[slice, int], Union[slice, int]]
-    ) -> List[FmtStr]:
+    def __getitem__(self, slicetuple: tuple[slice | int, slice | int]) -> 
list[FmtStr]:
         pass
 
     def __getitem__(
-        self, slicetuple: Union[int, slice, Tuple[Union[int, slice], 
Union[int, slice]]]
-    ) -> Union[FmtStr, List[FmtStr]]:
+        self, slicetuple: int | slice | tuple[int | slice, int | slice]
+    ) -> FmtStr | list[FmtStr]:
         if isinstance(slicetuple, int):
             if slicetuple < 0:
                 slicetuple = len(self.rows) - slicetuple
@@ -99,7 +97,7 @@
         return len(self.rows)
 
     @property
-    def shape(self) -> Tuple[int, int]:
+    def shape(self) -> tuple[int, int]:
         """Tuple of (len(rows, len(num_columns)) numpy-style shape"""
         return len(self.rows), self.num_columns
 
@@ -250,8 +248,8 @@
 
 
 def fsarray(
-    strings: Sequence[Union[FmtStr, str]],
-    width: Optional[int] = None,
+    strings: Sequence[FmtStr | str],
+    width: int | None = None,
     *args: Any,
     **kwargs: Any,
 ) -> FSArray:
@@ -283,7 +281,7 @@
     return arr
 
 
-def simple_format(x: Union[FSArray, Sequence[FmtStr]]) -> str:
+def simple_format(x: FSArray | Sequence[FmtStr]) -> str:
     return "\n".join(str(l) for l in x)
 
 
@@ -301,7 +299,7 @@
 
 def assertFSArraysEqualIgnoringFormatting(a: FSArray, b: FSArray) -> None:
     """Also accepts arrays of strings"""
-    assert len(a) == len(b), "fsarray heights do not match: %s %s \n%s \n%s" % 
(
+    assert len(a) == len(b), "fsarray heights do not match: {} {} \n{} 
\n{}".format(
         len(a),
         len(b),
         simple_format(a),
@@ -310,7 +308,7 @@
     for i, (a_row, b_row) in enumerate(zip(a, b)):
         a_row = a_row.s if isinstance(a_row, FmtStr) else a_row
         b_row = b_row.s if isinstance(b_row, FmtStr) else b_row
-        assert a_row == b_row, "FSArrays differ first on line %s:\n%s" % (
+        assert a_row == b_row, "FSArrays differ first on line {}:\n{}".format(
             i,
             FSArray.diff(a, b, ignore_formatting=True),
         )
@@ -319,7 +317,7 @@
 if __name__ == "__main__":
     a = FSArray(3, 14, bg="blue")
     a[0:2, 5:11] = cast(
-        Tuple[FmtStr, ...],
+        tuple[FmtStr, ...],
         (fmtstr("hey", "on_blue") + " " + fmtstr("yo", "on_red"), fmtstr("qwe 
qw")),
     )
     a.dumb_display()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/input.py 
new/curtsies-0.4.3/curtsies/input.py
--- old/curtsies-0.4.2/curtsies/input.py        2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/input.py        2025-06-05 08:33:08.000000000 
+0200
@@ -13,7 +13,6 @@
 from . import events
 
 from typing import (
-    Callable,
     ContextManager,
     Type,
     TextIO,
@@ -24,6 +23,7 @@
     Tuple,
     Any,
 )
+from collections.abc import Callable
 from types import TracebackType, FrameType
 
 
@@ -47,9 +47,9 @@
 
     def __exit__(
         self,
-        type: Optional[Type[BaseException]] = None,
-        value: Optional[BaseException] = None,
-        traceback: Optional[TracebackType] = None,
+        type: type[BaseException] | None = None,
+        value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         signal.signal(signal.SIGINT, self.orig_sigint_handler)
 
@@ -57,11 +57,13 @@
 class Input(ContextManager["Input"]):
     """Keypress and control event generator"""
 
+    in_stream: TextIO
+
     def __init__(
         self,
-        in_stream: Optional[TextIO] = None,
-        keynames: Union[events.Keynames, str] = events.Keynames.CURTSIES,
-        paste_threshold: Optional[int] = events.MAX_KEYPRESS_SIZE + 1,
+        in_stream: TextIO | None = None,
+        keynames: events.Keynames | str = events.Keynames.CURTSIES,
+        paste_threshold: int | None = events.MAX_KEYPRESS_SIZE + 1,
         sigint_event: bool = False,
         disable_terminal_start_stop: bool = False,
     ) -> None:
@@ -82,8 +84,9 @@
         """
         if in_stream is None:
             in_stream = sys.__stdin__
+            assert in_stream is not None
         self.in_stream = in_stream
-        self.unprocessed_bytes: List[bytes] = []  # leftover from stdin, 
unprocessed yet
+        self.unprocessed_bytes: list[bytes] = []  # leftover from stdin, 
unprocessed yet
         if isinstance(keynames, str):
             # TODO: Remove this block with the next API breaking release.
             if keynames == "curtsies":
@@ -99,14 +102,14 @@
         self.paste_threshold = paste_threshold
         self.sigint_event = sigint_event
         self.disable_terminal_start_stop = disable_terminal_start_stop
-        self.sigints: List[events.SigIntEvent] = []
-        self.wakeup_read_fd: Optional[int] = None
-        self.wakeup_write_fd: Optional[int] = None
-
-        self.readers: List[int] = []
-        self.queued_interrupting_events: List[Union[events.Event, str]] = []
-        self.queued_events: List[Union[events.Event, None]] = []
-        self.queued_scheduled_events: List[Tuple[float, 
events.ScheduledEvent]] = []
+        self.sigints: list[events.SigIntEvent] = []
+        self.wakeup_read_fd: int | None = None
+        self.wakeup_write_fd: int | None = None
+
+        self.readers: list[int] = []
+        self.queued_interrupting_events: list[events.Event | str] = []
+        self.queued_events: list[events.Event | None] = []
+        self.queued_scheduled_events: list[tuple[float, 
events.ScheduledEvent]] = []
 
     # prospective: this could be useful for an external select loop
     def fileno(self) -> int:
@@ -118,7 +121,7 @@
 
         if self.disable_terminal_start_stop:
             attrs = termios.tcgetattr(self.in_stream)
-            tty_cc = cast(List[Union[bytes, int]], attrs[-1])
+            tty_cc = cast(list[Union[bytes, int]], attrs[-1])
             tty_cc[termios.VSTOP] = 0  # Ctrl-s
             tty_cc[termios.VSTART] = 0  # Ctrl-q
             termios.tcsetattr(self.in_stream, termios.TCSANOW, attrs)
@@ -126,7 +129,7 @@
         if sys.platform == "darwin":
             attrs = termios.tcgetattr(self.in_stream)
             VDSUSP = termios.VSUSP + 1
-            tty_cc = cast(List[Union[bytes, int]], attrs[-1])
+            tty_cc = cast(list[Union[bytes, int]], attrs[-1])
             tty_cc[VDSUSP] = 0
             termios.tcsetattr(self.in_stream, termios.TCSANOW, attrs)
 
@@ -145,9 +148,9 @@
 
     def __exit__(
         self,
-        type: Optional[Type[BaseException]] = None,
-        value: Optional[BaseException] = None,
-        traceback: Optional[TracebackType] = None,
+        type: type[BaseException] | None = None,
+        value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         if (
             self.sigint_event
@@ -164,14 +167,14 @@
         termios.tcsetattr(self.in_stream, termios.TCSANOW, self.original_stty)
 
     def sigint_handler(
-        self, signum: Union[signal.Signals, int], frame: Optional[FrameType]
+        self, signum: signal.Signals | int, frame: FrameType | None
     ) -> None:
         self.sigints.append(events.SigIntEvent())
 
     def __iter__(self) -> "Input":
         return self
 
-    def __next__(self) -> Union[None, str, events.Event]:
+    def __next__(self) -> None | str | events.Event:
         return self.send(None)
 
     def unget_bytes(self, string: bytes) -> None:
@@ -183,8 +186,8 @@
         self.unprocessed_bytes.extend(string[i : i + 1] for i in 
range(len(string)))
 
     def _wait_for_read_ready_or_timeout(
-        self, timeout: Union[float, int, None]
-    ) -> Tuple[bool, Optional[Union[events.Event, str]]]:
+        self, timeout: float | int | None
+    ) -> tuple[bool, events.Event | str | None]:
         """Returns tuple of whether stdin is ready to read and an event.
 
         If an event is returned, that event is more pressing than reading
@@ -229,9 +232,7 @@
                 if remaining_timeout is not None:
                     remaining_timeout = max(remaining_timeout - (time.time() - 
t0), 0)
 
-    def send(
-        self, timeout: Optional[Union[float, None]] = None
-    ) -> Union[None, str, events.Event]:
+    def send(self, timeout: float | None | None = None) -> None | str | 
events.Event:
         """Returns an event or None if no events occur before timeout."""
         if self.sigint_event and is_main_thread():
             with ReplacedSigIntHandler(self.sigint_handler):
@@ -239,8 +240,8 @@
         else:
             return self._send(timeout)
 
-    def _send(self, timeout: Union[float, int, None]) -> Union[None, str, 
events.Event]:
-        def find_key() -> Optional[str]:
+    def _send(self, timeout: float | int | None) -> None | str | events.Event:
+        def find_key() -> str | None:
             """Returns keypress identified by adding unprocessed bytes or 
None"""
             current_bytes = []
             while self.unprocessed_bytes:
@@ -340,7 +341,7 @@
                 return 0
 
     def event_trigger(
-        self, event_type: Union[Type[events.Event], Callable[..., None]]
+        self, event_type: type[events.Event] | Callable[..., None]
     ) -> Callable[..., None]:
         """Returns a callback that creates events.
 
@@ -353,7 +354,7 @@
         return callback
 
     def scheduled_event_trigger(
-        self, event_type: Type[events.ScheduledEvent]
+        self, event_type: type[events.ScheduledEvent]
     ) -> Callable[[float], None]:
         """Returns a callback that schedules events for the future.
 
@@ -366,7 +367,7 @@
         return callback
 
     def threadsafe_event_trigger(
-        self, event_type: Union[Type[events.Event], Callable[..., None]]
+        self, event_type: type[events.Event] | Callable[..., None]
     ) -> Callable[..., None]:
         """Returns a callback to creates events, interrupting current event 
requests.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/termformatconstants.py 
new/curtsies-0.4.3/curtsies/termformatconstants.py
--- old/curtsies-0.4.2/curtsies/termformatconstants.py  2023-07-31 
22:18:21.000000000 +0200
+++ new/curtsies-0.4.3/curtsies/termformatconstants.py  2025-06-05 
08:33:08.000000000 +0200
@@ -1,12 +1,12 @@
 """Constants for terminal formatting"""
 
-from typing import Mapping
+from collections.abc import Mapping
 
 colors = "black", "red", "green", "yellow", "blue", "magenta", "cyan", "gray"
 FG_COLORS: Mapping[str, int] = dict(zip(colors, range(30, 38)))
 BG_COLORS: Mapping[str, int] = dict(zip(colors, range(40, 48)))
 STYLES: Mapping[str, int] = dict(
-    zip(("bold", "dark", "underline", "blink", "invert"), (1, 2, 4, 5, 7))
+    zip(("bold", "dark", "italic", "underline", "blink", "invert"), (1, 2, 3, 
4, 5, 7))
 )
 FG_NUMBER_TO_COLOR: Mapping[int, str] = dict(zip(FG_COLORS.values(), 
FG_COLORS.keys()))
 BG_NUMBER_TO_COLOR: Mapping[int, str] = dict(zip(BG_COLORS.values(), 
BG_COLORS.keys()))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/termhelpers.py 
new/curtsies-0.4.3/curtsies/termhelpers.py
--- old/curtsies-0.4.2/curtsies/termhelpers.py  2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/termhelpers.py  2025-06-05 08:33:08.000000000 
+0200
@@ -6,7 +6,7 @@
 from typing import IO, ContextManager, Type, List, Union, Optional
 from types import TracebackType
 
-_Attr = List[Union[int, List[Union[bytes, int]]]]
+_Attr = list[Union[int, list[Union[bytes, int]]]]
 
 
 class Nonblocking(ContextManager):
@@ -24,9 +24,9 @@
 
     def __exit__(
         self,
-        type: Optional[Type[BaseException]] = None,
-        value: Optional[BaseException] = None,
-        traceback: Optional[TracebackType] = None,
+        type: type[BaseException] | None = None,
+        value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         fcntl.fcntl(self.fd, fcntl.F_SETFL, self.orig_fl)
 
@@ -42,9 +42,9 @@
 
     def __exit__(
         self,
-        type: Optional[Type[BaseException]] = None,
-        value: Optional[BaseException] = None,
-        traceback: Optional[TracebackType] = None,
+        type: type[BaseException] | None = None,
+        value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         termios.tcsetattr(self.stream, termios.TCSANOW, self.original_stty)
 
@@ -60,8 +60,8 @@
 
     def __exit__(
         self,
-        type: Optional[Type[BaseException]] = None,
-        value: Optional[BaseException] = None,
-        traceback: Optional[TracebackType] = None,
+        type: type[BaseException] | None = None,
+        value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         termios.tcsetattr(self.stream, termios.TCSANOW, self.original_stty)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies/window.py 
new/curtsies-0.4.3/curtsies/window.py
--- old/curtsies-0.4.2/curtsies/window.py       2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/curtsies/window.py       2025-06-05 08:33:08.000000000 
+0200
@@ -7,16 +7,15 @@
     Optional,
     IO,
     Dict,
-    Sequence,
     TypeVar,
     Type,
     Tuple,
-    Callable,
     cast,
     TextIO,
     Union,
     List,
 )
+from collections.abc import Callable, Sequence
 from types import TracebackType
 
 import logging
@@ -36,18 +35,17 @@
 
 
 class BaseWindow(ContextManager):
-    def __init__(
-        self, out_stream: Optional[IO] = None, hide_cursor: bool = True
-    ) -> None:
+    def __init__(self, out_stream: IO | None = None, hide_cursor: bool = True) 
-> None:
         logger.debug("-------initializing Window object %r------" % self)
         if out_stream is None:
             out_stream = sys.__stdout__
+            assert out_stream is not None
         self.t = blessed.Terminal(stream=out_stream, force_styling=True)
         self.out_stream = out_stream
         self.hide_cursor = hide_cursor
-        self._last_lines_by_row: Dict[int, Optional[FmtStr]] = {}
-        self._last_rendered_width: Optional[int] = None
-        self._last_rendered_height: Optional[int] = None
+        self._last_lines_by_row: dict[int, FmtStr | None] = {}
+        self._last_rendered_width: int | None = None
+        self._last_rendered_height: int | None = None
 
     def scroll_down(self) -> None:
         logger.debug("sending scroll down message w/ cursor on bottom line")
@@ -68,9 +66,9 @@
 
     def __exit__(
         self,
-        type: Optional[Type[BaseException]] = None,
-        value: Optional[BaseException] = None,
-        traceback: Optional[TracebackType] = None,
+        type: type[BaseException] | None = None,
+        value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         logger.debug("running BaseWindow.__exit__")
         if self.hide_cursor:
@@ -84,11 +82,11 @@
         self._last_rendered_height = height
 
     def render_to_terminal(
-        self, array: Union[FSArray, List[FmtStr]], cursor_pos: Tuple[int, int] 
= (0, 0)
-    ) -> Optional[int]:
+        self, array: FSArray | list[FmtStr], cursor_pos: tuple[int, int] = (0, 
0)
+    ) -> int | None:
         raise NotImplementedError
 
-    def get_term_hw(self) -> Tuple[int, int]:
+    def get_term_hw(self) -> tuple[int, int]:
         """Returns current terminal height and width"""
         return self.t.height, self.t.width
 
@@ -144,9 +142,7 @@
         its out_stream; cached writes will be inaccurate.
     """
 
-    def __init__(
-        self, out_stream: Optional[IO] = None, hide_cursor: bool = True
-    ) -> None:
+    def __init__(self, out_stream: IO | None = None, hide_cursor: bool = True) 
-> None:
         """Constructs a FullscreenWindow
 
         Args:
@@ -162,15 +158,15 @@
 
     def __exit__(
         self,
-        type: Optional[Type[BaseException]] = None,
-        value: Optional[BaseException] = None,
-        traceback: Optional[TracebackType] = None,
+        type: type[BaseException] | None = None,
+        value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         self.fullscreen_ctx.__exit__(type, value, traceback)
         super().__exit__(type, value, traceback)
 
     def render_to_terminal(
-        self, array: Union[FSArray, List[FmtStr]], cursor_pos: Tuple[int, int] 
= (0, 0)
+        self, array: FSArray | list[FmtStr], cursor_pos: tuple[int, int] = (0, 
0)
     ) -> None:
         """Renders array to terminal and places (0-indexed) cursor
 
@@ -197,7 +193,7 @@
         if height != self._last_rendered_height or width != 
self._last_rendered_width:
             self.on_terminal_size_change(height, width)
 
-        current_lines_by_row: Dict[int, Optional[FmtStr]] = {}
+        current_lines_by_row: dict[int, FmtStr | None] = {}
 
         # rows which we have content for and don't require scrolling
         for row, line in enumerate(array):
@@ -241,13 +237,15 @@
         Only use the render_to_terminal interface for moving the cursor.
     """
 
+    in_stream: TextIO
+
     def __init__(
         self,
-        out_stream: Optional[IO] = None,
-        in_stream: Optional[IO] = None,
+        out_stream: TextIO | None = None,
+        in_stream: TextIO | None = None,
         keep_last_line: bool = False,
         hide_cursor: bool = True,
-        extra_bytes_callback: Optional[Callable[[bytes], None]] = None,
+        extra_bytes_callback: Callable[[bytes], None] | None = None,
     ):
         """Constructs a CursorAwareWindow
 
@@ -264,13 +262,14 @@
         super().__init__(out_stream=out_stream, hide_cursor=hide_cursor)
         if in_stream is None:
             in_stream = sys.__stdin__
+            assert in_stream is not None
         self.in_stream = in_stream
         # whether we can use blessed to handle some operations
         self._use_blessed = (
             self.out_stream == sys.__stdout__ and self.in_stream == 
sys.__stdin__
         )
-        self._last_cursor_column: Optional[int] = None
-        self._last_cursor_row: Optional[int] = None
+        self._last_cursor_column: int | None = None
+        self._last_cursor_row: int | None = None
         self.keep_last_line = keep_last_line
         self.extra_bytes_callback = extra_bytes_callback
 
@@ -292,9 +291,9 @@
 
     def __exit__(
         self,
-        type: Optional[Type[BaseException]] = None,
-        value: Optional[BaseException] = None,
-        traceback: Optional[TracebackType] = None,
+        type: type[BaseException] | None = None,
+        value: BaseException | None = None,
+        traceback: TracebackType | None = None,
     ) -> None:
         if self.keep_last_line:
             # just moves cursor down if not on last line
@@ -306,7 +305,7 @@
         self.cbreak.__exit__(type, value, traceback)
         super().__exit__(type, value, traceback)
 
-    def get_cursor_position(self) -> Tuple[int, int]:
+    def get_cursor_position(self) -> tuple[int, int]:
         """Returns the terminal (row, column) of the cursor
 
         0-indexed, like blessed cursor positions"""
@@ -426,8 +425,8 @@
 
     def render_to_terminal(
         self,
-        array: Union[FSArray, Sequence[FmtStr]],
-        cursor_pos: Tuple[int, int] = (0, 0),
+        array: FSArray | Sequence[FmtStr],
+        cursor_pos: tuple[int, int] = (0, 0),
     ) -> int:
         """Renders array to terminal, returns the number of lines scrolled 
offscreen
 
@@ -458,7 +457,7 @@
         if height != self._last_rendered_height or width != 
self._last_rendered_width:
             self.on_terminal_size_change(height, width)
 
-        current_lines_by_row: Dict[int, Optional[FmtStr]] = {}
+        current_lines_by_row: dict[int, FmtStr | None] = {}
         rows_for_use = list(range(self.top_usable_row, height))
 
         # rows which we have content for and don't require scrolling
@@ -527,9 +526,7 @@
                 if c == "":
                     sys.exit()  # same as raise SystemExit()
                 elif c == "h":
-                    a: Union[List[FmtStr], FSArray] = w.array_from_text(
-                        "a for small array"
-                    )
+                    a: list[FmtStr] | FSArray = w.array_from_text("a for small 
array")
                 elif c == "a":
                     a = [fmtstr(c * columns) for _ in range(rows)]
                 elif c == "s":
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies.egg-info/PKG-INFO 
new/curtsies-0.4.3/curtsies.egg-info/PKG-INFO
--- old/curtsies-0.4.2/curtsies.egg-info/PKG-INFO       2023-07-31 
22:18:29.000000000 +0200
+++ new/curtsies-0.4.3/curtsies.egg-info/PKG-INFO       2025-06-05 
08:33:12.000000000 +0200
@@ -1,6 +1,6 @@
-Metadata-Version: 2.1
+Metadata-Version: 2.4
 Name: curtsies
-Version: 0.4.2
+Version: 0.4.3
 Summary: Curses-like terminal wrapper, with colored strings!
 Home-page: https://github.com/bpython/curtsies
 Author: Thomas Ballinger
@@ -13,9 +13,12 @@
 Classifier: Operating System :: POSIX
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
-Requires-Python: >=3.7
+Requires-Python: >=3.10
 Description-Content-Type: text/markdown
 License-File: LICENSE
+Requires-Dist: blessed>=1.5
+Requires-Dist: cwcwidth
+Dynamic: license-file
 
 [![Documentation 
Status](https://readthedocs.org/projects/curtsies/badge/?version=latest)](https://readthedocs.org/projects/curtsies/?badge=latest)
 ![Curtsies Logo](http://ballingt.com/assets/curtsiestitle.png)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies.egg-info/SOURCES.txt 
new/curtsies-0.4.3/curtsies.egg-info/SOURCES.txt
--- old/curtsies-0.4.2/curtsies.egg-info/SOURCES.txt    2023-07-31 
22:18:29.000000000 +0200
+++ new/curtsies-0.4.3/curtsies.egg-info/SOURCES.txt    2025-06-05 
08:33:12.000000000 +0200
@@ -3,7 +3,6 @@
 README.md
 pyproject.toml
 setup.cfg
-setup.py
 curtsies/__init__.py
 curtsies/configfile_keynames.py
 curtsies/curtsieskeys.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/curtsies.egg-info/requires.txt 
new/curtsies-0.4.3/curtsies.egg-info/requires.txt
--- old/curtsies-0.4.2/curtsies.egg-info/requires.txt   2023-07-31 
22:18:29.000000000 +0200
+++ new/curtsies-0.4.3/curtsies.egg-info/requires.txt   2025-06-05 
08:33:12.000000000 +0200
@@ -1,5 +1,2 @@
 blessed>=1.5
 cwcwidth
-
-[:python_version < "3.8"]
-backports.cached-property
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/curtsies-0.4.2/examples/demo_fullscreen_with_input.py 
new/curtsies-0.4.3/examples/demo_fullscreen_with_input.py
--- old/curtsies-0.4.2/examples/demo_fullscreen_with_input.py   2023-07-31 
22:18:21.000000000 +0200
+++ new/curtsies-0.4.3/examples/demo_fullscreen_with_input.py   2025-06-05 
08:33:08.000000000 +0200
@@ -10,7 +10,7 @@
     print('this should be just off-screen')
     w = FullscreenWindow(sys.stdout)
     def sigwinch_handler(signum, frame):
-        print('sigwinch! Changed from {!r} to {!r}'.format((rows, columns), 
(w.height, w.width)))
+        print(f'sigwinch! Changed from {(rows, columns)!r} to {(w.height, 
w.width)!r}')
     signal.signal(signal.SIGWINCH, sigwinch_handler)
     with w:
         with Cbreak(sys.stdin):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/examples/demo_scrolling.py 
new/curtsies-0.4.3/examples/demo_scrolling.py
--- old/curtsies-0.4.2/examples/demo_scrolling.py       2023-07-31 
22:18:21.000000000 +0200
+++ new/curtsies-0.4.3/examples/demo_scrolling.py       2025-06-05 
08:33:08.000000000 +0200
@@ -17,7 +17,7 @@
         dy = w.get_cursor_vertical_diff()
         old_rows, old_columns = rows, columns
         rows, columns = w.height, w.width
-        print('sigwinch! Changed from {!r} to {!r}'.format((old_rows, 
old_columns), (rows, columns)))
+        print(f'sigwinch! Changed from {(old_rows, old_columns)!r} to {(rows, 
columns)!r}')
         print('cursor moved %d lines down' % dy)
         w.write(w.t.move_up)
         w.write(w.t.move_up)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/pyproject.toml 
new/curtsies-0.4.3/pyproject.toml
--- old/curtsies-0.4.2/pyproject.toml   2023-07-31 22:18:21.000000000 +0200
+++ new/curtsies-0.4.3/pyproject.toml   2025-06-05 08:33:08.000000000 +0200
@@ -1,12 +1,12 @@
 [build-system]
 requires = [
-  "setuptools >= 43",
+  "setuptools >= 46.4.0",
 ]
 build-backend = "setuptools.build_meta"
 
 [tool.black]
 line-length = 88
-target_version = ["py36"]
+target_version = ["py310"]
 exclude = '''
 (
     /(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/setup.cfg new/curtsies-0.4.3/setup.cfg
--- old/curtsies-0.4.2/setup.cfg        2023-07-31 22:18:29.568929400 +0200
+++ new/curtsies-0.4.3/setup.cfg        2025-06-05 08:33:12.419394300 +0200
@@ -1,5 +1,6 @@
 [metadata]
 name = curtsies
+version = attr: curtsies.__version__
 description = Curses-like terminal wrapper, with colored strings!
 long_description = file: README.md,
 long_description_content_type = text/markdown
@@ -18,13 +19,12 @@
        Programming Language :: Python :: 3
 
 [options]
-python_requires = >=3.7
+python_requires = >=3.10
 zip_safe = False
 packages = curtsies
 install_requires = 
        blessed>=1.5
        cwcwidth
-       backports.cached-property; python_version < "3.8"
 tests_require = 
        pyte
        pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/setup.py new/curtsies-0.4.3/setup.py
--- old/curtsies-0.4.2/setup.py 2023-07-31 22:18:21.000000000 +0200
+++ new/curtsies-0.4.3/setup.py 1970-01-01 01:00:00.000000000 +0100
@@ -1,16 +0,0 @@
-from setuptools import setup
-import ast
-import os
-
-
-def version():
-    """Return version string."""
-    with open(os.path.join("curtsies", "__init__.py")) as input_file:
-        for line in input_file:
-            if line.startswith("__version__"):
-                return ast.parse(line).body[0].value.s
-
-
-setup(
-    version=version(),
-)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/curtsies-0.4.2/tests/test_terminal.py 
new/curtsies-0.4.3/tests/test_terminal.py
--- old/curtsies-0.4.2/tests/test_terminal.py   2023-07-31 22:18:21.000000000 
+0200
+++ new/curtsies-0.4.3/tests/test_terminal.py   2025-06-05 08:33:08.000000000 
+0200
@@ -63,11 +63,7 @@
             to.write(event.upper() + " ")
             to.write("; ".join(map(repr, args)))
             to.write(" ")
-            to.write(
-                ", ".join(
-                    "{}: {}".format(name, repr(arg)) for name, arg in 
flags.items()
-                )
-            )
+            to.write(", ".join(f"{name}: {repr(arg)}" for name, arg in 
flags.items()))
             to.write(os.linesep)
 
         return inner

Reply via email to