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 <[email protected]>
+
+- 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
[](https://readthedocs.org/projects/curtsies/?badge=latest)

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('some[2Astuff')
@@ -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
[](https://readthedocs.org/projects/curtsies/?badge=latest)

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