cmd2 2.5.10__py3-none-any.whl → 2.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cmd2/table_creator.py CHANGED
@@ -1,6 +1,5 @@
1
- # coding=utf-8
2
- """
3
- cmd2 table creation API
1
+ """cmd2 table creation API.
2
+
4
3
  This API is built upon two core classes: Column and TableCreator
5
4
  The general use case is to inherit from TableCreator to create a table class with custom formatting options.
6
5
  There are already implemented and ready-to-use examples of this below TableCreator's code.
@@ -11,17 +10,13 @@ import io
11
10
  from collections import (
12
11
  deque,
13
12
  )
13
+ from collections.abc import Sequence
14
14
  from enum import (
15
15
  Enum,
16
16
  )
17
17
  from typing import (
18
18
  Any,
19
- Deque,
20
- List,
21
19
  Optional,
22
- Sequence,
23
- Tuple,
24
- Union,
25
20
  )
26
21
 
27
22
  from wcwidth import ( # type: ignore[import]
@@ -40,7 +35,7 @@ SPACE = ' '
40
35
 
41
36
 
42
37
  class HorizontalAlignment(Enum):
43
- """Horizontal alignment of text in a cell"""
38
+ """Horizontal alignment of text in a cell."""
44
39
 
45
40
  LEFT = 1
46
41
  CENTER = 2
@@ -48,7 +43,7 @@ class HorizontalAlignment(Enum):
48
43
 
49
44
 
50
45
  class VerticalAlignment(Enum):
51
- """Vertical alignment of text in a cell"""
46
+ """Vertical alignment of text in a cell."""
52
47
 
53
48
  TOP = 1
54
49
  MIDDLE = 2
@@ -56,7 +51,7 @@ class VerticalAlignment(Enum):
56
51
 
57
52
 
58
53
  class Column:
59
- """Table column configuration"""
54
+ """Table column configuration."""
60
55
 
61
56
  def __init__(
62
57
  self,
@@ -69,10 +64,9 @@ class Column:
69
64
  data_horiz_align: HorizontalAlignment = HorizontalAlignment.LEFT,
70
65
  data_vert_align: VerticalAlignment = VerticalAlignment.TOP,
71
66
  style_data_text: bool = True,
72
- max_data_lines: Union[int, float] = constants.INFINITY,
67
+ max_data_lines: float = constants.INFINITY,
73
68
  ) -> None:
74
- """
75
- Column initializer
69
+ """Column initializer.
76
70
 
77
71
  :param header: label for column header
78
72
  :param width: display width of column. This does not account for any borders or padding which
@@ -99,8 +93,7 @@ class Column:
99
93
 
100
94
  if width is not None and width < 1:
101
95
  raise ValueError("Column width cannot be less than 1")
102
- else:
103
- self.width: int = width if width is not None else -1
96
+ self.width: int = width if width is not None else -1
104
97
 
105
98
  self.header_horiz_align = header_horiz_align
106
99
  self.header_vert_align = header_vert_align
@@ -117,8 +110,9 @@ class Column:
117
110
 
118
111
 
119
112
  class TableCreator:
120
- """
121
- Base table creation class. This class handles ANSI style sequences and characters with display widths greater than 1
113
+ """Base table creation class.
114
+
115
+ This class handles ANSI style sequences and characters with display widths greater than 1
122
116
  when performing width calculations. It was designed with the ability to build tables one row at a time. This helps
123
117
  when you have large data sets that you don't want to hold in memory or when you receive portions of the data set
124
118
  incrementally.
@@ -132,8 +126,7 @@ class TableCreator:
132
126
  """
133
127
 
134
128
  def __init__(self, cols: Sequence[Column], *, tab_width: int = 4) -> None:
135
- """
136
- TableCreator initializer
129
+ """TableCreator initializer.
137
130
 
138
131
  :param cols: column definitions for this table
139
132
  :param tab_width: all tabs will be replaced with this many spaces. If a row's fill_char is a tab,
@@ -156,9 +149,8 @@ class TableCreator:
156
149
  col.width = max(1, ansi.widest_line(col.header))
157
150
 
158
151
  @staticmethod
159
- def _wrap_long_word(word: str, max_width: int, max_lines: Union[int, float], is_last_word: bool) -> Tuple[str, int, int]:
160
- """
161
- Used by _wrap_text() to wrap a long word over multiple lines
152
+ def _wrap_long_word(word: str, max_width: int, max_lines: float, is_last_word: bool) -> tuple[str, int, int]:
153
+ """Wrap a long word over multiple lines, used by _wrap_text().
162
154
 
163
155
  :param word: word being wrapped
164
156
  :param max_width: maximum display width of a line
@@ -220,25 +212,23 @@ class TableCreator:
220
212
  return wrapped_buf.getvalue(), total_lines, cur_line_width
221
213
 
222
214
  @staticmethod
223
- def _wrap_text(text: str, max_width: int, max_lines: Union[int, float]) -> str:
224
- """
225
- Wrap text into lines with a display width no longer than max_width. This function breaks words on whitespace
226
- boundaries. If a word is longer than the space remaining on a line, then it will start on a new line.
227
- ANSI escape sequences do not count toward the width of a line.
215
+ def _wrap_text(text: str, max_width: int, max_lines: float) -> str:
216
+ """Wrap text into lines with a display width no longer than max_width.
217
+
218
+ This function breaks words on whitespace boundaries. If a word is longer than the space remaining on a line,
219
+ then it will start on a new line. ANSI escape sequences do not count toward the width of a line.
228
220
 
229
221
  :param text: text to be wrapped
230
222
  :param max_width: maximum display width of a line
231
223
  :param max_lines: maximum lines to wrap before ending the last line displayed with an ellipsis
232
224
  :return: wrapped text
233
225
  """
234
-
235
226
  # MyPy Issue #7057 documents regression requiring nonlocals to be defined earlier
236
227
  cur_line_width = 0
237
228
  total_lines = 0
238
229
 
239
230
  def add_word(word_to_add: str, is_last_word: bool) -> None:
240
- """
241
- Called from loop to add a word to the wrapped text
231
+ """Aadd a word to the wrapped text, called from loop.
242
232
 
243
233
  :param word_to_add: the word being added
244
234
  :param is_last_word: True if this is the last word of the total text being wrapped
@@ -382,9 +372,8 @@ class TableCreator:
382
372
 
383
373
  return wrapped_buf.getvalue()
384
374
 
385
- def _generate_cell_lines(self, cell_data: Any, is_header: bool, col: Column, fill_char: str) -> Tuple[Deque[str], int]:
386
- """
387
- Generate the lines of a table cell
375
+ def _generate_cell_lines(self, cell_data: Any, is_header: bool, col: Column, fill_char: str) -> tuple[deque[str], int]:
376
+ """Generate the lines of a table cell.
388
377
 
389
378
  :param cell_data: data to be included in cell
390
379
  :param is_header: True if writing a header cell, otherwise writing a data cell. This determines whether to
@@ -428,8 +417,7 @@ class TableCreator:
428
417
  inter_cell: str = (2 * SPACE),
429
418
  post_line: str = EMPTY,
430
419
  ) -> str:
431
- """
432
- Generate a header or data table row
420
+ """Generate a header or data table row.
433
421
 
434
422
  :param row_data: data with an entry for each column in the row
435
423
  :param is_header: True if writing a header cell, otherwise writing a data cell. This determines whether to
@@ -450,11 +438,11 @@ class TableCreator:
450
438
  """
451
439
 
452
440
  class Cell:
453
- """Inner class which represents a table cell"""
441
+ """Inner class which represents a table cell."""
454
442
 
455
443
  def __init__(self) -> None:
456
444
  # Data in this cell split into individual lines
457
- self.lines: Deque[str] = deque()
445
+ self.lines: deque[str] = deque()
458
446
 
459
447
  # Display width of this cell
460
448
  self.width = 0
@@ -482,7 +470,7 @@ class TableCreator:
482
470
  total_lines = 0
483
471
 
484
472
  # Generate the cells for this row
485
- cells = list()
473
+ cells = []
486
474
 
487
475
  for col_index, col in enumerate(self.cols):
488
476
  cell = Cell()
@@ -514,9 +502,9 @@ class TableCreator:
514
502
  to_top = line_diff
515
503
  to_bottom = 0
516
504
 
517
- for i in range(to_top):
505
+ for _ in range(to_top):
518
506
  cell.lines.appendleft(padding_line)
519
- for i in range(to_bottom):
507
+ for _ in range(to_bottom):
520
508
  cell.lines.append(padding_line)
521
509
 
522
510
  # Build this row one line at a time
@@ -544,8 +532,8 @@ class TableCreator:
544
532
  # of tables. They can be used as-is or serve as inspiration for other custom table classes.
545
533
  ############################################################################################################
546
534
  class SimpleTable(TableCreator):
547
- """
548
- Implementation of TableCreator which generates a borderless table with an optional divider row after the header.
535
+ """Implementation of TableCreator which generates a borderless table with an optional divider row after the header.
536
+
549
537
  This class can be used to create the whole table at once or one row at a time.
550
538
  """
551
539
 
@@ -559,8 +547,7 @@ class SimpleTable(TableCreator):
559
547
  header_bg: Optional[ansi.BgColor] = None,
560
548
  data_bg: Optional[ansi.BgColor] = None,
561
549
  ) -> None:
562
- """
563
- SimpleTable initializer
550
+ """SimpleTable initializer.
564
551
 
565
552
  :param cols: column definitions for this table
566
553
  :param column_spacing: how many spaces to place between columns. Defaults to 2.
@@ -598,20 +585,20 @@ class SimpleTable(TableCreator):
598
585
  self.data_bg = data_bg
599
586
 
600
587
  def apply_header_bg(self, value: Any) -> str:
601
- """
602
- If defined, apply the header background color to header text
588
+ """If defined, apply the header background color to header text.
589
+
603
590
  :param value: object whose text is to be colored
604
- :return: formatted text
591
+ :return: formatted text.
605
592
  """
606
593
  if self.header_bg is None:
607
594
  return str(value)
608
595
  return ansi.style(value, bg=self.header_bg)
609
596
 
610
597
  def apply_data_bg(self, value: Any) -> str:
611
- """
612
- If defined, apply the data background color to data text
598
+ """If defined, apply the data background color to data text.
599
+
613
600
  :param value: object whose text is to be colored
614
- :return: formatted data string
601
+ :return: formatted data string.
615
602
  """
616
603
  if self.data_bg is None:
617
604
  return str(value)
@@ -619,8 +606,8 @@ class SimpleTable(TableCreator):
619
606
 
620
607
  @classmethod
621
608
  def base_width(cls, num_cols: int, *, column_spacing: int = 2) -> int:
622
- """
623
- Utility method to calculate the display width required for a table before data is added to it.
609
+ """Calculate the display width required for a table before data is added to it.
610
+
624
611
  This is useful when determining how wide to make your columns to have a table be a specific width.
625
612
 
626
613
  :param num_cols: how many columns the table will have
@@ -641,20 +628,20 @@ class SimpleTable(TableCreator):
641
628
  return ansi.style_aware_wcswidth(data_row) - data_width
642
629
 
643
630
  def total_width(self) -> int:
644
- """Calculate the total display width of this table"""
631
+ """Calculate the total display width of this table."""
645
632
  base_width = self.base_width(len(self.cols), column_spacing=self.column_spacing)
646
633
  data_width = sum(col.width for col in self.cols)
647
634
  return base_width + data_width
648
635
 
649
636
  def generate_header(self) -> str:
650
- """Generate table header with an optional divider row"""
637
+ """Generate table header with an optional divider row."""
651
638
  header_buf = io.StringIO()
652
639
 
653
640
  fill_char = self.apply_header_bg(SPACE)
654
641
  inter_cell = self.apply_header_bg(self.column_spacing * SPACE)
655
642
 
656
643
  # Apply background color to header text in Columns which allow it
657
- to_display: List[Any] = []
644
+ to_display: list[Any] = []
658
645
  for col in self.cols:
659
646
  if col.style_header_text:
660
647
  to_display.append(self.apply_header_bg(col.header))
@@ -673,15 +660,14 @@ class SimpleTable(TableCreator):
673
660
  return header_buf.getvalue()
674
661
 
675
662
  def generate_divider(self) -> str:
676
- """Generate divider row"""
663
+ """Generate divider row."""
677
664
  if self.divider_char is None:
678
665
  return ''
679
666
 
680
667
  return utils.align_left('', fill_char=self.divider_char, width=self.total_width())
681
668
 
682
669
  def generate_data_row(self, row_data: Sequence[Any]) -> str:
683
- """
684
- Generate a data row
670
+ """Generate a data row.
685
671
 
686
672
  :param row_data: data with an entry for each column in the row
687
673
  :return: data row string
@@ -694,7 +680,7 @@ class SimpleTable(TableCreator):
694
680
  inter_cell = self.apply_data_bg(self.column_spacing * SPACE)
695
681
 
696
682
  # Apply background color to data text in Columns which allow it
697
- to_display: List[Any] = []
683
+ to_display: list[Any] = []
698
684
  for index, col in enumerate(self.cols):
699
685
  if col.style_data_text:
700
686
  to_display.append(self.apply_data_bg(row_data[index]))
@@ -704,8 +690,7 @@ class SimpleTable(TableCreator):
704
690
  return self.generate_row(to_display, is_header=False, fill_char=fill_char, inter_cell=inter_cell)
705
691
 
706
692
  def generate_table(self, table_data: Sequence[Sequence[Any]], *, include_header: bool = True, row_spacing: int = 1) -> str:
707
- """
708
- Generate a table from a data set
693
+ """Generate a table from a data set.
709
694
 
710
695
  :param table_data: Data with an entry for each data row of the table. Each entry should have data for
711
696
  each column in the row.
@@ -740,9 +725,9 @@ class SimpleTable(TableCreator):
740
725
 
741
726
 
742
727
  class BorderedTable(TableCreator):
743
- """
744
- Implementation of TableCreator which generates a table with borders around the table and between rows. Borders
745
- between columns can also be toggled. This class can be used to create the whole table at once or one row at a time.
728
+ """Implementation of TableCreator which generates a table with borders around the table and between rows.
729
+
730
+ Borders between columns can also be toggled. This class can be used to create the whole table at once or one row at a time.
746
731
  """
747
732
 
748
733
  def __init__(
@@ -757,8 +742,7 @@ class BorderedTable(TableCreator):
757
742
  header_bg: Optional[ansi.BgColor] = None,
758
743
  data_bg: Optional[ansi.BgColor] = None,
759
744
  ) -> None:
760
- """
761
- BorderedTable initializer
745
+ """BorderedTable initializer.
762
746
 
763
747
  :param cols: column definitions for this table
764
748
  :param tab_width: all tabs will be replaced with this many spaces. If a row's fill_char is a tab,
@@ -788,30 +772,30 @@ class BorderedTable(TableCreator):
788
772
  self.data_bg = data_bg
789
773
 
790
774
  def apply_border_color(self, value: Any) -> str:
791
- """
792
- If defined, apply the border foreground and background colors
775
+ """If defined, apply the border foreground and background colors.
776
+
793
777
  :param value: object whose text is to be colored
794
- :return: formatted text
778
+ :return: formatted text.
795
779
  """
796
780
  if self.border_fg is None and self.border_bg is None:
797
781
  return str(value)
798
782
  return ansi.style(value, fg=self.border_fg, bg=self.border_bg)
799
783
 
800
784
  def apply_header_bg(self, value: Any) -> str:
801
- """
802
- If defined, apply the header background color to header text
785
+ """If defined, apply the header background color to header text.
786
+
803
787
  :param value: object whose text is to be colored
804
- :return: formatted text
788
+ :return: formatted text.
805
789
  """
806
790
  if self.header_bg is None:
807
791
  return str(value)
808
792
  return ansi.style(value, bg=self.header_bg)
809
793
 
810
794
  def apply_data_bg(self, value: Any) -> str:
811
- """
812
- If defined, apply the data background color to data text
795
+ """If defined, apply the data background color to data text.
796
+
813
797
  :param value: object whose text is to be colored
814
- :return: formatted data string
798
+ :return: formatted data string.
815
799
  """
816
800
  if self.data_bg is None:
817
801
  return str(value)
@@ -819,8 +803,8 @@ class BorderedTable(TableCreator):
819
803
 
820
804
  @classmethod
821
805
  def base_width(cls, num_cols: int, *, column_borders: bool = True, padding: int = 1) -> int:
822
- """
823
- Utility method to calculate the display width required for a table before data is added to it.
806
+ """Calculate the display width required for a table before data is added to it.
807
+
824
808
  This is useful when determining how wide to make your columns to have a table be a specific width.
825
809
 
826
810
  :param num_cols: how many columns the table will have
@@ -841,13 +825,13 @@ class BorderedTable(TableCreator):
841
825
  return ansi.style_aware_wcswidth(data_row) - data_width
842
826
 
843
827
  def total_width(self) -> int:
844
- """Calculate the total display width of this table"""
828
+ """Calculate the total display width of this table."""
845
829
  base_width = self.base_width(len(self.cols), column_borders=self.column_borders, padding=self.padding)
846
830
  data_width = sum(col.width for col in self.cols)
847
831
  return base_width + data_width
848
832
 
849
833
  def generate_table_top_border(self) -> str:
850
- """Generate a border which appears at the top of the header and data section"""
834
+ """Generate a border which appears at the top of the header and data section."""
851
835
  fill_char = '═'
852
836
 
853
837
  pre_line = '╔' + self.padding * '═'
@@ -869,7 +853,7 @@ class BorderedTable(TableCreator):
869
853
  )
870
854
 
871
855
  def generate_header_bottom_border(self) -> str:
872
- """Generate a border which appears at the bottom of the header"""
856
+ """Generate a border which appears at the bottom of the header."""
873
857
  fill_char = '═'
874
858
 
875
859
  pre_line = '╠' + self.padding * '═'
@@ -891,7 +875,7 @@ class BorderedTable(TableCreator):
891
875
  )
892
876
 
893
877
  def generate_row_bottom_border(self) -> str:
894
- """Generate a border which appears at the bottom of rows"""
878
+ """Generate a border which appears at the bottom of rows."""
895
879
  fill_char = '─'
896
880
 
897
881
  pre_line = '╟' + self.padding * '─'
@@ -900,7 +884,6 @@ class BorderedTable(TableCreator):
900
884
  if self.column_borders:
901
885
  inter_cell += '┼'
902
886
  inter_cell += self.padding * '─'
903
- inter_cell = inter_cell
904
887
 
905
888
  post_line = self.padding * '─' + '╢'
906
889
 
@@ -914,7 +897,7 @@ class BorderedTable(TableCreator):
914
897
  )
915
898
 
916
899
  def generate_table_bottom_border(self) -> str:
917
- """Generate a border which appears at the bottom of the table"""
900
+ """Generate a border which appears at the bottom of the table."""
918
901
  fill_char = '═'
919
902
 
920
903
  pre_line = '╚' + self.padding * '═'
@@ -936,7 +919,7 @@ class BorderedTable(TableCreator):
936
919
  )
937
920
 
938
921
  def generate_header(self) -> str:
939
- """Generate table header"""
922
+ """Generate table header."""
940
923
  fill_char = self.apply_header_bg(SPACE)
941
924
 
942
925
  pre_line = self.apply_border_color('║') + self.apply_header_bg(self.padding * SPACE)
@@ -949,7 +932,7 @@ class BorderedTable(TableCreator):
949
932
  post_line = self.apply_header_bg(self.padding * SPACE) + self.apply_border_color('║')
950
933
 
951
934
  # Apply background color to header text in Columns which allow it
952
- to_display: List[Any] = []
935
+ to_display: list[Any] = []
953
936
  for col in self.cols:
954
937
  if col.style_header_text:
955
938
  to_display.append(self.apply_header_bg(col.header))
@@ -971,8 +954,7 @@ class BorderedTable(TableCreator):
971
954
  return header_buf.getvalue()
972
955
 
973
956
  def generate_data_row(self, row_data: Sequence[Any]) -> str:
974
- """
975
- Generate a data row
957
+ """Generate a data row.
976
958
 
977
959
  :param row_data: data with an entry for each column in the row
978
960
  :return: data row string
@@ -993,7 +975,7 @@ class BorderedTable(TableCreator):
993
975
  post_line = self.apply_data_bg(self.padding * SPACE) + self.apply_border_color('║')
994
976
 
995
977
  # Apply background color to data text in Columns which allow it
996
- to_display: List[Any] = []
978
+ to_display: list[Any] = []
997
979
  for index, col in enumerate(self.cols):
998
980
  if col.style_data_text:
999
981
  to_display.append(self.apply_data_bg(row_data[index]))
@@ -1005,8 +987,7 @@ class BorderedTable(TableCreator):
1005
987
  )
1006
988
 
1007
989
  def generate_table(self, table_data: Sequence[Sequence[Any]], *, include_header: bool = True) -> str:
1008
- """
1009
- Generate a table from a data set
990
+ """Generate a table from a data set.
1010
991
 
1011
992
  :param table_data: Data with an entry for each data row of the table. Each entry should have data for
1012
993
  each column in the row.
@@ -1038,9 +1019,9 @@ class BorderedTable(TableCreator):
1038
1019
 
1039
1020
 
1040
1021
  class AlternatingTable(BorderedTable):
1041
- """
1042
- Implementation of BorderedTable which uses background colors to distinguish between rows instead of row border
1043
- lines. This class can be used to create the whole table at once or one row at a time.
1022
+ """Implementation of BorderedTable which uses background colors to distinguish between rows instead of row border lines.
1023
+
1024
+ This class can be used to create the whole table at once or one row at a time.
1044
1025
 
1045
1026
  To nest an AlternatingTable within another AlternatingTable, set style_data_text to False on the Column
1046
1027
  which contains the nested table. That will prevent the current row's background color from affecting the colors
@@ -1060,8 +1041,7 @@ class AlternatingTable(BorderedTable):
1060
1041
  odd_bg: Optional[ansi.BgColor] = None,
1061
1042
  even_bg: Optional[ansi.BgColor] = ansi.Bg.DARK_GRAY,
1062
1043
  ) -> None:
1063
- """
1064
- AlternatingTable initializer
1044
+ """AlternatingTable initializer.
1065
1045
 
1066
1046
  Note: Specify background colors using subclasses of BgColor (e.g. Bg, EightBitBg, RgbBg)
1067
1047
 
@@ -1094,21 +1074,19 @@ class AlternatingTable(BorderedTable):
1094
1074
  self.even_bg = even_bg
1095
1075
 
1096
1076
  def apply_data_bg(self, value: Any) -> str:
1097
- """
1098
- Apply background color to data text based on what row is being generated and whether a color has been defined
1077
+ """Apply background color to data text based on what row is being generated and whether a color has been defined.
1078
+
1099
1079
  :param value: object whose text is to be colored
1100
- :return: formatted data string
1080
+ :return: formatted data string.
1101
1081
  """
1102
1082
  if self.row_num % 2 == 0 and self.even_bg is not None:
1103
1083
  return ansi.style(value, bg=self.even_bg)
1104
- elif self.row_num % 2 != 0 and self.odd_bg is not None:
1084
+ if self.row_num % 2 != 0 and self.odd_bg is not None:
1105
1085
  return ansi.style(value, bg=self.odd_bg)
1106
- else:
1107
- return str(value)
1086
+ return str(value)
1108
1087
 
1109
1088
  def generate_data_row(self, row_data: Sequence[Any]) -> str:
1110
- """
1111
- Generate a data row
1089
+ """Generate a data row.
1112
1090
 
1113
1091
  :param row_data: data with an entry for each column in the row
1114
1092
  :return: data row string
@@ -1118,8 +1096,7 @@ class AlternatingTable(BorderedTable):
1118
1096
  return row
1119
1097
 
1120
1098
  def generate_table(self, table_data: Sequence[Sequence[Any]], *, include_header: bool = True) -> str:
1121
- """
1122
- Generate a table from a data set
1099
+ """Generate a table from a data set.
1123
1100
 
1124
1101
  :param table_data: Data with an entry for each data row of the table. Each entry should have data for
1125
1102
  each column in the row.