1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 __version__ = "0.7.2"
33
34 import copy
35 import csv
36 import random
37 import re
38 import sys
39 import textwrap
40 import itertools
41 import unicodedata
42
43 py3k = sys.version_info[0] >= 3
44 if py3k:
45 unicode = str
46 basestring = str
47 itermap = map
48 iterzip = zip
49 uni_chr = chr
50 from html.parser import HTMLParser
51 else:
52 itermap = itertools.imap
53 iterzip = itertools.izip
54 uni_chr = unichr
55 from HTMLParser import HTMLParser
56
57 if py3k and sys.version_info[1] >= 2:
58 from html import escape
59 else:
60 from cgi import escape
61
62
63 FRAME = 0
64 ALL = 1
65 NONE = 2
66 HEADER = 3
67
68
69 DEFAULT = 10
70 MSWORD_FRIENDLY = 11
71 PLAIN_COLUMNS = 12
72 RANDOM = 20
73
74 _re = re.compile("\033\[[0-9;]*m")
75
81
83
84 - def __init__(self, field_names=None, **kwargs):
85
86 """Return a new PrettyTable instance
87
88 Arguments:
89
90 encoding - Unicode encoding scheme used to decode any encoded input
91 field_names - list or tuple of field names
92 fields - list or tuple of field names to include in displays
93 start - index of first data row to include in output
94 end - index of last data row to include in output PLUS ONE (list slice style)
95 header - print a header showing field names (True or False)
96 header_style - stylisation to apply to field names in header ("cap", "title", "upper", "lower" or None)
97 border - print a border around the table (True or False)
98 hrules - controls printing of horizontal rules after rows. Allowed values: FRAME, HEADER, ALL, NONE
99 vrules - controls printing of vertical rules between columns. Allowed values: FRAME, ALL, NONE
100 int_format - controls formatting of integer data
101 float_format - controls formatting of floating point data
102 padding_width - number of spaces on either side of column data (only used if left and right paddings are None)
103 left_padding_width - number of spaces on left hand side of column data
104 right_padding_width - number of spaces on right hand side of column data
105 vertical_char - single character string used to draw vertical lines
106 horizontal_char - single character string used to draw horizontal lines
107 junction_char - single character string used to draw line junctions
108 sortby - name of field to sort rows by
109 sort_key - sorting key function, applied to data points before sorting
110 valign - default valign for each row (None, "t", "m" or "b")
111 reversesort - True or False to sort in descending or ascending order"""
112
113 self.encoding = kwargs.get("encoding", "UTF-8")
114
115
116 self._field_names = []
117 self._align = {}
118 self._valign = {}
119 self._max_width = {}
120 self._rows = []
121 if field_names:
122 self.field_names = field_names
123 else:
124 self._widths = []
125
126
127 self._options = "start end fields header border sortby reversesort sort_key attributes format hrules vrules".split()
128 self._options.extend("int_format float_format padding_width left_padding_width right_padding_width".split())
129 self._options.extend("vertical_char horizontal_char junction_char header_style valign xhtml print_empty".split())
130 for option in self._options:
131 if option in kwargs:
132 self._validate_option(option, kwargs[option])
133 else:
134 kwargs[option] = None
135
136 self._start = kwargs["start"] or 0
137 self._end = kwargs["end"] or None
138 self._fields = kwargs["fields"] or None
139
140 if kwargs["header"] in (True, False):
141 self._header = kwargs["header"]
142 else:
143 self._header = True
144 self._header_style = kwargs["header_style"] or None
145 if kwargs["border"] in (True, False):
146 self._border = kwargs["border"]
147 else:
148 self._border = True
149 self._hrules = kwargs["hrules"] or FRAME
150 self._vrules = kwargs["vrules"] or ALL
151
152 self._sortby = kwargs["sortby"] or None
153 if kwargs["reversesort"] in (True, False):
154 self._reversesort = kwargs["reversesort"]
155 else:
156 self._reversesort = False
157 self._sort_key = kwargs["sort_key"] or (lambda x: x)
158
159 self._int_format = kwargs["int_format"] or {}
160 self._float_format = kwargs["float_format"] or {}
161 self._padding_width = kwargs["padding_width"] or 1
162 self._left_padding_width = kwargs["left_padding_width"] or None
163 self._right_padding_width = kwargs["right_padding_width"] or None
164
165 self._vertical_char = kwargs["vertical_char"] or self._unicode("|")
166 self._horizontal_char = kwargs["horizontal_char"] or self._unicode("-")
167 self._junction_char = kwargs["junction_char"] or self._unicode("+")
168
169 if kwargs["print_empty"] in (True, False):
170 self._print_empty = kwargs["print_empty"]
171 else:
172 self._print_empty = True
173 self._format = kwargs["format"] or False
174 self._xhtml = kwargs["xhtml"] or False
175 self._attributes = kwargs["attributes"] or {}
176
178 if not isinstance(value, basestring):
179 value = str(value)
180 if not isinstance(value, unicode):
181 value = unicode(value, self.encoding, "strict")
182 return value
183
184 - def _justify(self, text, width, align):
185 excess = width - _str_block_width(text)
186 if align == "l":
187 return text + excess * " "
188 elif align == "r":
189 return excess * " " + text
190 else:
191 if excess % 2:
192
193
194 if _str_block_width(text) % 2:
195 return (excess//2)*" " + text + (excess//2 + 1)*" "
196
197 else:
198 return (excess//2 + 1)*" " + text + (excess//2)*" "
199
200
201 else:
202
203 return (excess//2)*" " + text + (excess//2)*" "
204
206
207 if name == "rowcount":
208 return len(self._rows)
209 elif name == "colcount":
210 if self._field_names:
211 return len(self._field_names)
212 elif self._rows:
213 return len(self._rows[0])
214 else:
215 return 0
216 else:
217 raise AttributeError(name)
218
220
221 new = PrettyTable()
222 new.field_names = self.field_names
223 for attr in self._options:
224 setattr(new, "_"+attr, getattr(self, "_"+attr))
225 setattr(new, "_align", getattr(self, "_align"))
226 if isinstance(index, slice):
227 for row in self._rows[index]:
228 new.add_row(row)
229 elif isinstance(index, int):
230 new.add_row(self._rows[index])
231 else:
232 raise Exception("Index %s is invalid, must be an integer or slice" % str(index))
233 return new
234
235 if py3k:
238 else:
241
244
245
246
247
248
249
250
251
252
253
254
255
257 if option in ("field_names"):
258 self._validate_field_names(val)
259 elif option in ("start", "end", "max_width", "padding_width", "left_padding_width", "right_padding_width", "format"):
260 self._validate_nonnegative_int(option, val)
261 elif option in ("sortby"):
262 self._validate_field_name(option, val)
263 elif option in ("sort_key"):
264 self._validate_function(option, val)
265 elif option in ("hrules"):
266 self._validate_hrules(option, val)
267 elif option in ("vrules"):
268 self._validate_vrules(option, val)
269 elif option in ("fields"):
270 self._validate_all_field_names(option, val)
271 elif option in ("header", "border", "reversesort", "xhtml", "print_empty"):
272 self._validate_true_or_false(option, val)
273 elif option in ("header_style"):
274 self._validate_header_style(val)
275 elif option in ("int_format"):
276 self._validate_int_format(option, val)
277 elif option in ("float_format"):
278 self._validate_float_format(option, val)
279 elif option in ("vertical_char", "horizontal_char", "junction_char"):
280 self._validate_single_char(option, val)
281 elif option in ("attributes"):
282 self._validate_attributes(option, val)
283 else:
284 raise Exception("Unrecognised option: %s!" % option)
285
287
288 if self._field_names:
289 try:
290 assert len(val) == len(self._field_names)
291 except AssertionError:
292 raise Exception("Field name list has incorrect number of values, (actual) %d!=%d (expected)" % (len(val), len(self._field_names)))
293 if self._rows:
294 try:
295 assert len(val) == len(self._rows[0])
296 except AssertionError:
297 raise Exception("Field name list has incorrect number of values, (actual) %d!=%d (expected)" % (len(val), len(self._rows[0])))
298
299 try:
300 assert len(val) == len(set(val))
301 except AssertionError:
302 raise Exception("Field names must be unique!")
303
305 try:
306 assert val in ("cap", "title", "upper", "lower", None)
307 except AssertionError:
308 raise Exception("Invalid header style, use cap, title, upper, lower or None!")
309
311 try:
312 assert val in ["l","c","r"]
313 except AssertionError:
314 raise Exception("Alignment %s is invalid, use l, c or r!" % val)
315
317 try:
318 assert val in ["t","m","b",None]
319 except AssertionError:
320 raise Exception("Alignment %s is invalid, use t, m, b or None!" % val)
321
323 try:
324 assert int(val) >= 0
325 except AssertionError:
326 raise Exception("Invalid value for %s: %s!" % (name, self._unicode(val)))
327
329 try:
330 assert val in (True, False)
331 except AssertionError:
332 raise Exception("Invalid value for %s! Must be True or False." % name)
333
342
355
357 try:
358 assert hasattr(val, "__call__")
359 except AssertionError:
360 raise Exception("Invalid value for %s! Must be a function." % name)
361
363 try:
364 assert val in (ALL, FRAME, HEADER, NONE)
365 except AssertionError:
366 raise Exception("Invalid value for %s! Must be ALL, FRAME, HEADER or NONE." % name)
367
369 try:
370 assert val in (ALL, FRAME, NONE)
371 except AssertionError:
372 raise Exception("Invalid value for %s! Must be ALL, FRAME, or NONE." % name)
373
375 try:
376 assert (val in self._field_names) or (val is None)
377 except AssertionError:
378 raise Exception("Invalid field name: %s!" % val)
379
381 try:
382 for x in val:
383 self._validate_field_name(name, x)
384 except AssertionError:
385 raise Exception("fields must be a sequence of field names!")
386
388 try:
389 assert _str_block_width(val) == 1
390 except AssertionError:
391 raise Exception("Invalid value for %s! Must be a string of length 1." % name)
392
394 try:
395 assert isinstance(val, dict)
396 except AssertionError:
397 raise Exception("attributes must be a dictionary of name/value pairs!")
398
399
400
401
402
404 return self._field_names
405 """The names of the fields
406
407 Arguments:
408
409 fields - list or tuple of field names"""
411 val = [self._unicode(x) for x in val]
412 self._validate_option("field_names", val)
413 if self._field_names:
414 old_names = self._field_names[:]
415 self._field_names = val
416 if self._align and old_names:
417 for old_name, new_name in zip(old_names, val):
418 self._align[new_name] = self._align[old_name]
419 for old_name in old_names:
420 if old_name not in self._align:
421 self._align.pop(old_name)
422 else:
423 for field in self._field_names:
424 self._align[field] = "c"
425 if self._valign and old_names:
426 for old_name, new_name in zip(old_names, val):
427 self._valign[new_name] = self._valign[old_name]
428 for old_name in old_names:
429 if old_name not in self._valign:
430 self._valign.pop(old_name)
431 else:
432 for field in self._field_names:
433 self._valign[field] = "t"
434 field_names = property(_get_field_names, _set_field_names)
435
439 self._validate_align(val)
440 for field in self._field_names:
441 self._align[field] = val
442 align = property(_get_align, _set_align)
443
447 self._validate_valign(val)
448 for field in self._field_names:
449 self._valign[field] = val
450 valign = property(_get_valign, _set_valign)
451
453 return self._max_width
455 self._validate_option("max_width", val)
456 for field in self._field_names:
457 self._max_width[field] = val
458 max_width = property(_get_max_width, _set_max_width)
459
461 """List or tuple of field names to include in displays
462
463 Arguments:
464
465 fields - list or tuple of field names to include in displays"""
466 return self._fields
470 fields = property(_get_fields, _set_fields)
471
473 """Start index of the range of rows to print
474
475 Arguments:
476
477 start - index of first data row to include in output"""
478 return self._start
479
483 start = property(_get_start, _set_start)
484
486 """End index of the range of rows to print
487
488 Arguments:
489
490 end - index of last data row to include in output PLUS ONE (list slice style)"""
491 return self._end
495 end = property(_get_end, _set_end)
496
498 """Name of field by which to sort rows
499
500 Arguments:
501
502 sortby - field name to sort by"""
503 return self._sortby
507 sortby = property(_get_sortby, _set_sortby)
508
510 """Controls direction of sorting (ascending vs descending)
511
512 Arguments:
513
514 reveresort - set to True to sort by descending order, or False to sort by ascending order"""
515 return self._reversesort
519 reversesort = property(_get_reversesort, _set_reversesort)
520
522 """Sorting key function, applied to data points before sorting
523
524 Arguments:
525
526 sort_key - a function which takes one argument and returns something to be sorted"""
527 return self._sort_key
531 sort_key = property(_get_sort_key, _set_sort_key)
532
534 """Controls printing of table header with field names
535
536 Arguments:
537
538 header - print a header showing field names (True or False)"""
539 return self._header
543 header = property(_get_header, _set_header)
544
546 """Controls stylisation applied to field names in header
547
548 Arguments:
549
550 header_style - stylisation to apply to field names in header ("cap", "title", "upper", "lower" or None)"""
551 return self._header_style
555 header_style = property(_get_header_style, _set_header_style)
556
558 """Controls printing of border around table
559
560 Arguments:
561
562 border - print a border around the table (True or False)"""
563 return self._border
567 border = property(_get_border, _set_border)
568
570 """Controls printing of horizontal rules after rows
571
572 Arguments:
573
574 hrules - horizontal rules style. Allowed values: FRAME, ALL, HEADER, NONE"""
575 return self._hrules
579 hrules = property(_get_hrules, _set_hrules)
580
582 """Controls printing of vertical rules between columns
583
584 Arguments:
585
586 vrules - vertical rules style. Allowed values: FRAME, ALL, NONE"""
587 return self._vrules
591 vrules = property(_get_vrules, _set_vrules)
592
603 int_format = property(_get_int_format, _set_int_format)
604
615 float_format = property(_get_float_format, _set_float_format)
616
618 """The number of empty spaces between a column's edge and its content
619
620 Arguments:
621
622 padding_width - number of spaces, must be a positive integer"""
623 return self._padding_width
627 padding_width = property(_get_padding_width, _set_padding_width)
628
630 """The number of empty spaces between a column's left edge and its content
631
632 Arguments:
633
634 left_padding - number of spaces, must be a positive integer"""
635 return self._left_padding_width
637 self._validate_option("left_padding_width", val)
638 self._left_padding_width = val
639 left_padding_width = property(_get_left_padding_width, _set_left_padding_width)
640
642 """The number of empty spaces between a column's right edge and its content
643
644 Arguments:
645
646 right_padding - number of spaces, must be a positive integer"""
647 return self._right_padding_width
649 self._validate_option("right_padding_width", val)
650 self._right_padding_width = val
651 right_padding_width = property(_get_right_padding_width, _set_right_padding_width)
652
654 """The charcter used when printing table borders to draw vertical lines
655
656 Arguments:
657
658 vertical_char - single character string used to draw vertical lines"""
659 return self._vertical_char
664 vertical_char = property(_get_vertical_char, _set_vertical_char)
665
667 """The charcter used when printing table borders to draw horizontal lines
668
669 Arguments:
670
671 horizontal_char - single character string used to draw horizontal lines"""
672 return self._horizontal_char
677 horizontal_char = property(_get_horizontal_char, _set_horizontal_char)
678
680 """The charcter used when printing table borders to draw line junctions
681
682 Arguments:
683
684 junction_char - single character string used to draw line junctions"""
685 return self._junction_char
690 junction_char = property(_get_junction_char, _set_junction_char)
691
702 format = property(_get_format, _set_format)
703
705 """Controls whether or not empty tables produce a header and frame or just an empty string
706
707 Arguments:
708
709 print_empty - True or False"""
710 return self._print_empty
714 print_empty = property(_get_print_empty, _set_print_empty)
715
717 """A dictionary of HTML attribute name/value pairs to be included in the <table> tag when printing HTML
718
719 Arguments:
720
721 attributes - dictionary of attributes"""
722 return self._attributes
726 attributes = property(_get_attributes, _set_attributes)
727
728
729
730
731
733
734 options = {}
735 for option in self._options:
736 if option in kwargs:
737 self._validate_option(option, kwargs[option])
738 options[option] = kwargs[option]
739 else:
740 options[option] = getattr(self, "_"+option)
741 return options
742
743
744
745
746
759
772
782
790
792
793
794 self.header = random.choice((True, False))
795 self.border = random.choice((True, False))
796 self._hrules = random.choice((ALL, FRAME, HEADER, NONE))
797 self._vrules = random.choice((ALL, FRAME, NONE))
798 self.left_padding_width = random.randint(0,5)
799 self.right_padding_width = random.randint(0,5)
800 self.vertical_char = random.choice("~!@#$%^&*()_+|-=\{}[];':\",./;<>?")
801 self.horizontal_char = random.choice("~!@#$%^&*()_+|-=\{}[];':\",./;<>?")
802 self.junction_char = random.choice("~!@#$%^&*()_+|-=\{}[];':\",./;<>?")
803
804
805
806
807
809
810 """Add a row to the table
811
812 Arguments:
813
814 row - row of data, should be a list with as many elements as the table
815 has fields"""
816
817 if self._field_names and len(row) != len(self._field_names):
818 raise Exception("Row has incorrect number of values, (actual) %d!=%d (expected)" %(len(row),len(self._field_names)))
819 if not self._field_names:
820 self.field_names = [("Field %d" % (n+1)) for n in range(0,len(row))]
821 self._rows.append(list(row))
822
824
825 """Delete a row to the table
826
827 Arguments:
828
829 row_index - The index of the row you want to delete. Indexing starts at 0."""
830
831 if row_index > len(self._rows)-1:
832 raise Exception("Cant delete row at index %d, table only has %d rows!" % (row_index, len(self._rows)))
833 del self._rows[row_index]
834
835 - def add_column(self, fieldname, column, align="c", valign="t"):
836
837 """Add a column to the table.
838
839 Arguments:
840
841 fieldname - name of the field to contain the new column of data
842 column - column of data, should be a list with as many elements as the
843 table has rows
844 align - desired alignment for this column - "l" for left, "c" for centre and "r" for right
845 valign - desired vertical alignment for new columns - "t" for top, "m" for middle and "b" for bottom"""
846
847 if len(self._rows) in (0, len(column)):
848 self._validate_align(align)
849 self._validate_valign(valign)
850 self._field_names.append(fieldname)
851 self._align[fieldname] = align
852 self._valign[fieldname] = valign
853 for i in range(0, len(column)):
854 if len(self._rows) < i+1:
855 self._rows.append([])
856 self._rows[i].append(column[i])
857 else:
858 raise Exception("Column length %d does not match number of rows %d!" % (len(column), len(self._rows)))
859
861
862 """Delete all rows from the table but keep the current field names"""
863
864 self._rows = []
865
867
868 """Delete all rows and field names from the table, maintaining nothing but styling options"""
869
870 self._rows = []
871 self._field_names = []
872 self._widths = []
873
874
875
876
877
879 return copy.deepcopy(self)
880
881
882
883
884
891
893 if options["header"]:
894 widths = [_get_size(field)[0] for field in self._field_names]
895 else:
896 widths = len(self.field_names) * [0]
897 for row in rows:
898 for index, value in enumerate(row):
899 fieldname = self.field_names[index]
900 if fieldname in self.max_width:
901 widths[index] = max(widths[index], min(_get_size(value)[0], self.max_width[fieldname]))
902 else:
903 widths[index] = max(widths[index], _get_size(value)[0])
904 self._widths = widths
905
907
908 if options["left_padding_width"] is not None:
909 lpad = options["left_padding_width"]
910 else:
911 lpad = options["padding_width"]
912 if options["right_padding_width"] is not None:
913 rpad = options["right_padding_width"]
914 else:
915 rpad = options["padding_width"]
916 return lpad, rpad
917
919 """Return only those data rows that should be printed, based on slicing and sorting.
920
921 Arguments:
922
923 options - dictionary of option settings."""
924
925
926 rows = copy.deepcopy(self._rows[options["start"]:options["end"]])
927
928 if options["sortby"]:
929 sortindex = self._field_names.index(options["sortby"])
930
931 rows = [[row[sortindex]]+row for row in rows]
932
933 rows.sort(reverse=options["reversesort"], key=options["sort_key"])
934
935 rows = [row[1:] for row in rows]
936 return rows
937
940
943
944
945
946
947
949
950 """Return string representation of table in current state.
951
952 Arguments:
953
954 start - index of first data row to include in output
955 end - index of last data row to include in output PLUS ONE (list slice style)
956 fields - names of fields (columns) to include
957 header - print a header showing field names (True or False)
958 border - print a border around the table (True or False)
959 hrules - controls printing of horizontal rules after rows. Allowed values: ALL, FRAME, HEADER, NONE
960 vrules - controls printing of vertical rules between columns. Allowed values: FRAME, ALL, NONE
961 int_format - controls formatting of integer data
962 float_format - controls formatting of floating point data
963 padding_width - number of spaces on either side of column data (only used if left and right paddings are None)
964 left_padding_width - number of spaces on left hand side of column data
965 right_padding_width - number of spaces on right hand side of column data
966 vertical_char - single character string used to draw vertical lines
967 horizontal_char - single character string used to draw horizontal lines
968 junction_char - single character string used to draw line junctions
969 sortby - name of field to sort rows by
970 sort_key - sorting key function, applied to data points before sorting
971 reversesort - True or False to sort in descending or ascending order
972 print empty - if True, stringify just the header for an empty table, if False return an empty string """
973
974 options = self._get_options(kwargs)
975
976 lines = []
977
978
979
980 if self.rowcount == 0 and (not options["print_empty"] or not options["border"]):
981 return ""
982
983
984 rows = self._get_rows(options)
985
986
987 formatted_rows = self._format_rows(rows, options)
988
989
990 self._compute_widths(formatted_rows, options)
991
992
993 self._hrule = self._stringify_hrule(options)
994 if options["header"]:
995 lines.append(self._stringify_header(options))
996 elif options["border"] and options["hrules"] in (ALL, FRAME):
997 lines.append(self._hrule)
998
999
1000 for row in formatted_rows:
1001 lines.append(self._stringify_row(row, options))
1002
1003
1004 if options["border"] and options["hrules"] == FRAME:
1005 lines.append(self._hrule)
1006
1007 return self._unicode("\n").join(lines)
1008
1010
1011 if not options["border"]:
1012 return ""
1013 lpad, rpad = self._get_padding_widths(options)
1014 if options['vrules'] in (ALL, FRAME):
1015 bits = [options["junction_char"]]
1016 else:
1017 bits = [options["horizontal_char"]]
1018
1019 if not self._field_names:
1020 bits.append(options["junction_char"])
1021 return "".join(bits)
1022 for field, width in zip(self._field_names, self._widths):
1023 if options["fields"] and field not in options["fields"]:
1024 continue
1025 bits.append((width+lpad+rpad)*options["horizontal_char"])
1026 if options['vrules'] == ALL:
1027 bits.append(options["junction_char"])
1028 else:
1029 bits.append(options["horizontal_char"])
1030 if options["vrules"] == FRAME:
1031 bits.pop()
1032 bits.append(options["junction_char"])
1033 return "".join(bits)
1034
1036
1037 bits = []
1038 lpad, rpad = self._get_padding_widths(options)
1039 if options["border"]:
1040 if options["hrules"] in (ALL, FRAME):
1041 bits.append(self._hrule)
1042 bits.append("\n")
1043 if options["vrules"] in (ALL, FRAME):
1044 bits.append(options["vertical_char"])
1045 else:
1046 bits.append(" ")
1047
1048 if not self._field_names:
1049 if options["vrules"] in (ALL, FRAME):
1050 bits.append(options["vertical_char"])
1051 else:
1052 bits.append(" ")
1053 for field, width, in zip(self._field_names, self._widths):
1054 if options["fields"] and field not in options["fields"]:
1055 continue
1056 if self._header_style == "cap":
1057 fieldname = field.capitalize()
1058 elif self._header_style == "title":
1059 fieldname = field.title()
1060 elif self._header_style == "upper":
1061 fieldname = field.upper()
1062 elif self._header_style == "lower":
1063 fieldname = field.lower()
1064 else:
1065 fieldname = field
1066 bits.append(" " * lpad + self._justify(fieldname, width, self._align[field]) + " " * rpad)
1067 if options["border"]:
1068 if options["vrules"] == ALL:
1069 bits.append(options["vertical_char"])
1070 else:
1071 bits.append(" ")
1072
1073
1074 if options["border"] and options["vrules"] == FRAME:
1075 bits.pop()
1076 bits.append(options["vertical_char"])
1077 if options["border"] and options["hrules"] != NONE:
1078 bits.append("\n")
1079 bits.append(self._hrule)
1080 return "".join(bits)
1081
1083
1084 for index, field, value, width, in zip(range(0,len(row)), self._field_names, row, self._widths):
1085
1086 lines = value.split("\n")
1087 new_lines = []
1088 for line in lines:
1089 if _str_block_width(line) > width:
1090 line = textwrap.fill(line, width)
1091 new_lines.append(line)
1092 lines = new_lines
1093 value = "\n".join(lines)
1094 row[index] = value
1095
1096 row_height = 0
1097 for c in row:
1098 h = _get_size(c)[1]
1099 if h > row_height:
1100 row_height = h
1101
1102 bits = []
1103 lpad, rpad = self._get_padding_widths(options)
1104 for y in range(0, row_height):
1105 bits.append([])
1106 if options["border"]:
1107 if options["vrules"] in (ALL, FRAME):
1108 bits[y].append(self.vertical_char)
1109 else:
1110 bits[y].append(" ")
1111
1112 for field, value, width, in zip(self._field_names, row, self._widths):
1113
1114 valign = self._valign[field]
1115 lines = value.split("\n")
1116 dHeight = row_height - len(lines)
1117 if dHeight:
1118 if valign == "m":
1119 lines = [""] * int(dHeight / 2) + lines + [""] * (dHeight - int(dHeight / 2))
1120 elif valign == "b":
1121 lines = [""] * dHeight + lines
1122 else:
1123 lines = lines + [""] * dHeight
1124
1125 y = 0
1126 for l in lines:
1127 if options["fields"] and field not in options["fields"]:
1128 continue
1129
1130 bits[y].append(" " * lpad + self._justify(l, width, self._align[field]) + " " * rpad)
1131 if options["border"]:
1132 if options["vrules"] == ALL:
1133 bits[y].append(self.vertical_char)
1134 else:
1135 bits[y].append(" ")
1136 y += 1
1137
1138
1139
1140 for y in range(0, row_height):
1141 if options["border"] and options["vrules"] == FRAME:
1142 bits[y].pop()
1143 bits[y].append(options["vertical_char"])
1144
1145 if options["border"] and options["hrules"]== ALL:
1146 bits[row_height-1].append("\n")
1147 bits[row_height-1].append(self._hrule)
1148
1149 for y in range(0, row_height):
1150 bits[y] = "".join(bits[y])
1151
1152 return "\n".join(bits)
1153
1154
1155
1156
1157
1159
1160 """Return string representation of HTML formatted version of table in current state.
1161
1162 Arguments:
1163
1164 start - index of first data row to include in output
1165 end - index of last data row to include in output PLUS ONE (list slice style)
1166 fields - names of fields (columns) to include
1167 header - print a header showing field names (True or False)
1168 border - print a border around the table (True or False)
1169 hrules - controls printing of horizontal rules after rows. Allowed values: ALL, FRAME, HEADER, NONE
1170 vrules - controls printing of vertical rules between columns. Allowed values: FRAME, ALL, NONE
1171 int_format - controls formatting of integer data
1172 float_format - controls formatting of floating point data
1173 padding_width - number of spaces on either side of column data (only used if left and right paddings are None)
1174 left_padding_width - number of spaces on left hand side of column data
1175 right_padding_width - number of spaces on right hand side of column data
1176 sortby - name of field to sort rows by
1177 sort_key - sorting key function, applied to data points before sorting
1178 attributes - dictionary of name/value pairs to include as HTML attributes in the <table> tag
1179 xhtml - print <br/> tags if True, <br> tags if false"""
1180
1181 options = self._get_options(kwargs)
1182
1183 if options["format"]:
1184 string = self._get_formatted_html_string(options)
1185 else:
1186 string = self._get_simple_html_string(options)
1187
1188 return string
1189
1191
1192 lines = []
1193 if options["xhtml"]:
1194 linebreak = "<br/>"
1195 else:
1196 linebreak = "<br>"
1197
1198 open_tag = []
1199 open_tag.append("<table")
1200 if options["attributes"]:
1201 for attr_name in options["attributes"]:
1202 open_tag.append(" %s=\"%s\"" % (attr_name, options["attributes"][attr_name]))
1203 open_tag.append(">")
1204 lines.append("".join(open_tag))
1205
1206
1207 if options["header"]:
1208 lines.append(" <tr>")
1209 for field in self._field_names:
1210 if options["fields"] and field not in options["fields"]:
1211 continue
1212 lines.append(" <th>%s</th>" % escape(field).replace("\n", linebreak))
1213 lines.append(" </tr>")
1214
1215
1216 rows = self._get_rows(options)
1217 formatted_rows = self._format_rows(rows, options)
1218 for row in formatted_rows:
1219 lines.append(" <tr>")
1220 for field, datum in zip(self._field_names, row):
1221 if options["fields"] and field not in options["fields"]:
1222 continue
1223 lines.append(" <td>%s</td>" % escape(datum).replace("\n", linebreak))
1224 lines.append(" </tr>")
1225
1226 lines.append("</table>")
1227
1228 return self._unicode("\n").join(lines)
1229
1289
1290
1291
1292
1293
1295
1296
1297
1298 if 0x0021 <= char <= 0x007e:
1299 return 1
1300
1301 if 0x4e00 <= char <= 0x9fff:
1302 return 2
1303
1304 if 0xac00 <= char <= 0xd7af:
1305 return 2
1306
1307 if unicodedata.combining(uni_chr(char)):
1308 return 0
1309
1310 if 0x3040 <= char <= 0x309f or 0x30a0 <= char <= 0x30ff:
1311 return 2
1312
1313 if 0xff01 <= char <= 0xff60:
1314 return 2
1315
1316 if 0x3000 <= char <= 0x303e:
1317 return 2
1318
1319 if char in (0x0008, 0x007f):
1320 return -1
1321
1322 elif char in (0x0000, 0x001f):
1323 return 0
1324
1325 return 1
1326
1330
1331
1332
1333
1334
1335 -def from_csv(fp, field_names = None, **kwargs):
1336
1337 dialect = csv.Sniffer().sniff(fp.read(1024))
1338 fp.seek(0)
1339 reader = csv.reader(fp, dialect)
1340
1341 table = PrettyTable(**kwargs)
1342 if field_names:
1343 table.field_names = field_names
1344 else:
1345 if py3k:
1346 table.field_names = [x.strip() for x in next(reader)]
1347 else:
1348 table.field_names = [x.strip() for x in reader.next()]
1349
1350 for row in reader:
1351 table.add_row([x.strip() for x in row])
1352
1353 return table
1354
1356
1357 if cursor.description:
1358 table = PrettyTable(**kwargs)
1359 table.field_names = [col[0] for col in cursor.description]
1360 for row in cursor.fetchall():
1361 table.add_row(row)
1362 return table
1363
1365
1367 HTMLParser.__init__(self)
1368 self.kwargs = kwargs
1369 self.tables = []
1370 self.last_row = []
1371 self.rows = []
1372 self.max_row_width = 0
1373 self.active = None
1374 self.last_content = ""
1375 self.is_last_row_header = False
1376
1378 self.active = tag
1379 if tag == "th":
1380 self.is_last_row_header = True
1381
1383 if tag in ["th", "td"]:
1384 stripped_content = self.last_content.strip()
1385 self.last_row.append(stripped_content)
1386 if tag == "tr":
1387 self.rows.append(
1388 (self.last_row, self.is_last_row_header))
1389 self.max_row_width = max(self.max_row_width, len(self.last_row))
1390 self.last_row = []
1391 self.is_last_row_header = False
1392 if tag == "table":
1393 table = self.generate_table(self.rows)
1394 self.tables.append(table)
1395 self.rows = []
1396 self.last_content = " "
1397 self.active = None
1398
1399
1401 self.last_content += data
1402
1404 """
1405 Generates from a list of rows a PrettyTable object.
1406 """
1407 table = PrettyTable(**self.kwargs)
1408 for row in self.rows:
1409 if len(row[0]) < self.max_row_width:
1410 appends = self.max_row_width - len(row[0])
1411 for i in range(1,appends):
1412 row[0].append("-")
1413
1414 if row[1] == True:
1415 self.make_fields_unique(row[0])
1416 table.field_names = row[0]
1417 else:
1418 table.add_row(row[0])
1419 return table
1420
1422 """
1423 iterates over the row and make each field unique
1424 """
1425 for i in range(0, len(fields)):
1426 for j in range(i+1, len(fields)):
1427 if fields[i] == fields[j]:
1428 fields[j] += "'"
1429
1431 """
1432 Generates a list of PrettyTables from a string of HTML code. Each <table> in
1433 the HTML becomes one PrettyTable object.
1434 """
1435
1436 parser = TableHandler(**kwargs)
1437 parser.feed(html_code)
1438 return parser.tables
1439
1441 """
1442 Generates a PrettyTables from a string of HTML code which contains only a
1443 single <table>
1444 """
1445
1446 tables = from_html(html_code, **kwargs)
1447 try:
1448 assert len(tables) == 1
1449 except AssertionError:
1450 raise Exception("More than one <table> in provided HTML code! Use from_html instead.")
1451 return tables[0]
1452
1453
1454
1455
1456
1458
1459 x = PrettyTable(["City name", "Area", "Population", "Annual Rainfall"])
1460 x.sortby = "Population"
1461 x.reversesort = True
1462 x.int_format["Area"] = "04d"
1463 x.float_format = "6.1f"
1464 x.align["City name"] = "l"
1465 x.add_row(["Adelaide", 1295, 1158259, 600.5])
1466 x.add_row(["Brisbane", 5905, 1857594, 1146.4])
1467 x.add_row(["Darwin", 112, 120900, 1714.7])
1468 x.add_row(["Hobart", 1357, 205556, 619.5])
1469 x.add_row(["Sydney", 2058, 4336374, 1214.8])
1470 x.add_row(["Melbourne", 1566, 3806092, 646.9])
1471 x.add_row(["Perth", 5386, 1554769, 869.4])
1472 print(x)
1473
1474 if __name__ == "__main__":
1475 main()
1476