Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ dist

.coverage
.cover/*
/.venv/
2 changes: 1 addition & 1 deletion prettytable/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@

from .prettytable import PrettyTable
from .prettytable import ALL, HEADER, MSWORD_FRIENDLY, NONE, PLAIN_COLUMNS
from .factory import from_csv, from_db_cursor, from_html, from_html_one
from .factory import from_csv, from_json, from_db_cursor, from_html, from_html_one
23 changes: 23 additions & 0 deletions prettytable/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Table factories
"""
import csv
import json
from .prettytable import PrettyTable
from ._compact import py3k, HTMLParser

Expand Down Expand Up @@ -34,6 +35,28 @@ def from_csv(fp, field_names=None, **kwargs):
return table


def from_json(fp, field_names=None, **kwargs):
reader = json.load(fp)

table = PrettyTable(**kwargs)
table_field_names = []
if field_names:
table_field_names.extend(field_names)
else:
for row in reader:
table_field_names.extend([x for x in row.keys() if x not in table_field_names])

table.field_names = table_field_names

for row in reader:
d = {k: "" for k in table_field_names}
d.update(row)
add_row = [x for x in d.values()]
table.add_row(add_row)

return table


def from_db_cursor(cursor, **kwargs):
if cursor.description:
table = PrettyTable(**kwargs)
Expand Down
18 changes: 9 additions & 9 deletions prettytable/prettytable.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ def align(self):
def align(self, val):
if not self._field_names:
self._align = {}
elif val is None or (isinstance(val, dict) and len(val) is 0):
elif val is None or (isinstance(val, dict) and len(val) == 0):
for field in self._field_names:
self._align[field] = "c"
else:
Expand All @@ -441,7 +441,7 @@ def valign(self):
def valign(self, val):
if not self._field_names:
self._valign = {}
elif val is None or (isinstance(val, dict) and len(val) is 0):
elif val is None or (isinstance(val, dict) and len(val) == 0):
for field in self._field_names:
self._valign[field] = "t"
else:
Expand All @@ -459,7 +459,7 @@ def max_width(self):

@max_width.setter
def max_width(self, val):
if val is None or (isinstance(val, dict) and len(val) is 0):
if val is None or (isinstance(val, dict) and len(val) == 0):
self._max_width = {}
else:
self._validate_option("max_width", val)
Expand Down Expand Up @@ -489,7 +489,7 @@ def min_width(self):

@min_width.setter
def min_width(self, val):
if val is None or (isinstance(val, dict) and len(val) is 0):
if val is None or (isinstance(val, dict) and len(val) == 0):
self._min_width = {}
else:
self._validate_option("min_width", val)
Expand Down Expand Up @@ -687,7 +687,7 @@ def int_format(self):

@int_format.setter
def int_format(self, val):
if val is None or (isinstance(val, dict) and len(val) is 0):
if val is None or (isinstance(val, dict) and len(val) == 0):
self._int_format = {}
else:
self._validate_option("int_format", val)
Expand All @@ -704,7 +704,7 @@ def float_format(self):

@float_format.setter
def float_format(self, val):
if val is None or (isinstance(val, dict) and len(val) is 0):
if val is None or (isinstance(val, dict) and len(val) == 0):
self._float_format = {}
else:
self._validate_option("float_format", val)
Expand Down Expand Up @@ -1295,7 +1295,7 @@ def _stringify_header(self, options):
fieldname = field.lower()
else:
fieldname = field
bits.append(" " * lpad + self._justify(fieldname, width, self._align[field]) + " " * rpad)
bits.append(" " * lpad + self._justify(fieldname, width, self._align.get(field, 'c')) + " " * rpad)
if options["border"]:
if options["vrules"] == ALL:
bits.append(options["vertical_char"])
Expand Down Expand Up @@ -1343,7 +1343,7 @@ def _stringify_row(self, row, options):

for field, value, width, in zip(self._field_names, row, self._widths):

valign = self._valign[field]
valign = self._valign.get(field, 'm')
lines = value.split("\n")
dHeight = row_height - len(lines)
if dHeight:
Expand All @@ -1359,7 +1359,7 @@ def _stringify_row(self, row, options):
if options["fields"] and field not in options["fields"]:
continue

bits[y].append(" " * lpad + self._justify(l, width, self._align[field]) + " " * rpad)
bits[y].append(" " * lpad + self._justify(l, width, self._align.get(field, 'c')) + " " * rpad)
if options["border"]:
if options["vrules"] == ALL:
bits[y].append(self.vertical_char)
Expand Down
100 changes: 76 additions & 24 deletions tests/test_prettytable.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from prettytable import PrettyTable
from prettytable import ALL, HEADER, MSWORD_FRIENDLY, NONE
from prettytable import from_csv, from_db_cursor, from_html, from_html_one
from prettytable import from_csv, from_json, from_db_cursor, from_html, from_html_one

from prettytable._compact import StringIO
try:
Expand Down Expand Up @@ -64,29 +64,28 @@ def testRowMixEquivalenceHTML(self):
self.assertEqual(self.row.get_html_string(), self.mix.get_html_string())


# class FieldnamelessTableTest(unittest.TestCase):
#
# """Make sure that building and stringing a table with no fieldnames works fine"""
#
# def setUp(self):
# self.x = PrettyTable()
# self.x.add_row(["Adelaide",1295, 1158259, 600.5])
# self.x.add_row(["Brisbane",5905, 1857594, 1146.4])
# self.x.add_row(["Darwin", 112, 120900, 1714.7])
# self.x.add_row(["Hobart", 1357, 205556, 619.5])
# self.x.add_row(["Sydney", 2058, 4336374, 1214.8])
# self.x.add_row(["Melbourne", 1566, 3806092, 646.9])
# self.x.add_row(["Perth", 5386, 1554769, 869.4])
#
# def testCanStringASCII(self):
# self.x.get_string()
#
# def testCanStringHTML(self):
# self.x.get_html_string()
#
# def testAddFieldnamesLater(self):
# self.x.field_names = ["City name", "Area", "Population", "Annual Rainfall"]
# self.x.get_string()
class FieldnamelessTableTest(unittest.TestCase):
"""Make sure that building and stringing a table with no fieldnames works fine"""

def setUp(self):
self.x = PrettyTable()
self.x.add_row(["Adelaide", 1295, 1158259, 600.5])
self.x.add_row(["Brisbane", 5905, 1857594, 1146.4])
self.x.add_row(["Darwin", 112, 120900, 1714.7])
self.x.add_row(["Hobart", 1357, 205556, 619.5])
self.x.add_row(["Sydney", 2058, 4336374, 1214.8])
self.x.add_row(["Melbourne", 1566, 3806092, 646.9])
self.x.add_row(["Perth", 5386, 1554769, 869.4])

def testCanStringASCII(self):
self.x.get_string()

def testCanStringHTML(self):
self.x.get_html_string()

def testAddFieldnamesLater(self):
self.x.field_names = ["City name", "Area", "Population", "Annual Rainfall"]
self.x.get_string()


class CityDataTest(unittest.TestCase):
Expand Down Expand Up @@ -595,6 +594,59 @@ def setUp(self):
self.x = from_csv(csv_fp)


class JsonConstructorTest(BasicTests):
def setUp(self):
json_string = """[
{
"City name": "Sydney",
"Area": "2058",
"Population": "4336374",
"Annual Rainfall": "1214.8"
},
{
"City name": "Melbourne",
"Area": "1566",
"Population": "3806092",
"Annual Rainfall": "646.9"
},
{
"City name": "Brisbane",
"Area": "5905",
"Population": "1857594",
"Annual Rainfall": "1146.4"
},
{
"City name": "Perth",
"Area": "5386",
"Population": "1554769",
"Coordinates": "31.9523° S, 115.8613° E",
"Annual Rainfall": "869.4"
},
{
"City name": "Adelaide",
"Area": "1295",
"Population": "1158259",
"Annual Rainfall": "600.5"
},
{
"City name": "Hobart",
"Area": "1357",
"Population": "205556",
"Annual Rainfall": "619.5"
},
{
"City name": "Darwin",
"Area": "0112",
"Population": "120900",
"Annual Rainfall": "1714.7"
}
]"""
json_fp = StringIO.StringIO(json_string)
self.x = from_json(json_fp)
print("Generated using json:")
print(self.x)


if _have_sqlite:
class DatabaseConstructorTest(BasicTests):
def setUp(self):
Expand Down