Support direct EvColumn adds to EvTable. Resolves #2762

This commit is contained in:
Griatch 2022-11-06 10:23:20 +01:00
parent 7d8c6f2a26
commit 9438e5856a
4 changed files with 102 additions and 20 deletions

View file

@ -217,6 +217,7 @@ Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10
(mainly for custom align/valign). `EvCells` now makes use of `utils.justify`.
- `utils.justify` now supports `align="a"` (absolute alignments. This keeps
the given left indent but crops/fills to the width. Used in EvCells.
- `EvTable` now supports passing `EvColumn`s as a list directly, (`EvTable(table=[colA,colB])`)
## Evennia 0.9.5

View file

@ -471,9 +471,6 @@ class EvCell:
else:
self.height = self.raw_height
# prepare data
# self.formatted = self._reformat()
def _crop(self, text, width):
"""
Apply cropping of text.
@ -853,16 +850,19 @@ class EvCell:
Get data, padded and aligned in the form of a list of lines.
"""
self.formatted = self._reformat()
if not self.formatted:
self.formatted = self._reformat()
return self.formatted
def __repr__(self):
self.formatted = self._reformat()
if not self.formatted:
self.formatted = self._reformat()
return str(ANSIString("<EvCel %s>" % self.formatted))
def __str__(self):
"returns cell contents on string form"
self.formatted = self._reformat()
if not self.formatted:
self.formatted = self._reformat()
return str(ANSIString("\n").join(self.formatted))
@ -1146,7 +1146,19 @@ class EvTable:
self.options = kwargs
# use the temporary table to generate the table on the fly, as a list of EvColumns
self.table = [EvColumn(*col, **kwargs) for col in table]
self.table = []
for col in table:
if isinstance(col, EvColumn):
self.add_column(col, **kwargs)
elif isinstance(col, (list, tuple)):
self.table.append(EvColumn(*col, **kwargs))
else:
raise RuntimeError(
"EvTable 'table' kwarg must be a list of EvColumns or a list-of-lists of"
f" strings. Found {type(col)}."
)
# self.table = [EvColumn(*col, **kwargs) for col in table]
# this is the actual working table
self.worktable = None
@ -1508,7 +1520,12 @@ class EvTable:
options = dict(list(self.options.items()) + list(kwargs.items()))
xpos = kwargs.get("xpos", None)
column = EvColumn(*args, **options)
if args and isinstance(args[0], EvColumn):
column = args[0]
column.reformat(**kwargs)
else:
column = EvColumn(*args, **options)
wtable = self.ncols
htable = self.nrows
@ -1546,7 +1563,6 @@ class EvTable:
xpos = min(wtable - 1, max(0, int(xpos)))
self.table.insert(xpos, column)
self.ncols += 1
# self._balance()
def add_row(self, *args, **kwargs):
"""

View file

@ -196,7 +196,8 @@ class TestEvTable(EvenniaTestCase):
def test_multiple_rows(self):
"""
adding a lot of rows with `.add_row`.
Adding a lot of rows with `.add_row`.
"""
table = evtable.EvTable("|yHeading1|n", "|B|[GHeading2|n", "Heading3")
nlines = 12
@ -222,3 +223,56 @@ class TestEvTable(EvenniaTestCase):
expected = "\n".join(expected)
self._validate(expected, str(table))
def test_2762(self):
"""
Testing https://github.com/evennia/evennia/issues/2762
Extra spaces getting added to cell content
Also testing out adding EvColumns directly to the table kwarg.
"""
# direct table add
table = evtable.EvTable(table=[["another"]], fill_char=".", pad_char="#", width=8)
expected = """
+------+
|#anot#|
|#her.#|
+------+
"""
self._validate(expected, str(table))
# add with .add_column
table = evtable.EvTable(fill_char=".", pad_char="#")
table.add_column("another", width=8)
self._validate(expected, str(table))
# add by passing a column to constructor directly
colB = evtable.EvColumn("another", width=8)
table = evtable.EvTable(table=[colB], fill_char=".", pad_char="#")
self._validate(expected, str(table))
# more complex table
colA = evtable.EvColumn("this", "is", "a", "column") # no width
colB = evtable.EvColumn("and", "another", "one", "here", width=8)
table = evtable.EvTable(table=[colA, colB], fill_char=".", pad_char="#")
expected = """
+--------+-------+
|#this..#|#and..#|
|#is....#|#anoth#|
|#......#|#er...#|
|#a.....#|#one..#|
|#column#|#here.#|
+--------+-------+
"""
self._validate(expected, str(table))

View file

@ -2193,23 +2193,34 @@ def calledby(callerdepth=1):
another function; it will print which function called it.
Args:
callerdepth (int): Must be larger than 0. When > 1, it will
print the caller of the caller etc.
callerdepth (int or None): If None, show entire stack. If int, must be larger than 0.
When > 1, it will print the sequence to that depth.
Returns:
calledby (str): A debug string detailing which routine called
us.
calledby (str): A debug string detailing the code that called us.
"""
import inspect
def _stack_display(frame):
path = os.path.sep.join(frame[1].rsplit(os.path.sep, 2)[-2:])
return (
f"> called by '{frame[3]}': {path}:{frame[2]} >>>"
f" {frame[4][0].strip() if frame[4] else ''}"
)
stack = inspect.stack()
# we must step one extra level back in stack since we don't want
# to include the call of this function itself.
callerdepth = min(max(2, callerdepth + 1), len(stack) - 1)
frame = inspect.stack()[callerdepth]
path = os.path.sep.join(frame[1].rsplit(os.path.sep, 2)[-2:])
return "[called by '%s': %s:%s %s]" % (frame[3], path, frame[2], frame[4])
out = []
if callerdepth is None:
callerdepth = len(stack) - 1
# show range
for idepth in range(1, max(1, callerdepth + 1)):
# we must step one extra level back in stack since we don't want
# to include the call of this function itself.
out.append(_stack_display(stack[min(idepth + 1, len(stack) - 1)]))
return "\n".join(out[::-1])
def m_len(target):