Merge "Remove the dependency on prettytable"
This commit is contained in:
commit
9d35f057ba
@ -18,5 +18,3 @@ stevedore>=0.14
|
|||||||
futures>=2.1.6
|
futures>=2.1.6
|
||||||
# Used for structured input validation
|
# Used for structured input validation
|
||||||
jsonschema>=2.0.0,<3.0.0
|
jsonschema>=2.0.0,<3.0.0
|
||||||
# For pretty printing state-machine tables
|
|
||||||
PrettyTable>=0.7,<0.8
|
|
||||||
|
@ -14,5 +14,3 @@ Babel>=1.3
|
|||||||
stevedore>=1.0.0 # Apache-2.0
|
stevedore>=1.0.0 # Apache-2.0
|
||||||
# Used for structured input validation
|
# Used for structured input validation
|
||||||
jsonschema>=2.0.0,<3.0.0
|
jsonschema>=2.0.0,<3.0.0
|
||||||
# For pretty printing state-machine tables
|
|
||||||
PrettyTable>=0.7,<0.8
|
|
||||||
|
@ -47,23 +47,23 @@ class _MachineBuilder(object):
|
|||||||
NOTE(harlowja): the machine states that this build will for are::
|
NOTE(harlowja): the machine states that this build will for are::
|
||||||
|
|
||||||
+--------------+-----------+------------+----------+---------+
|
+--------------+-----------+------------+----------+---------+
|
||||||
| Start | Event | End | On Enter | On Exit |
|
Start | Event | End | On Enter | On Exit
|
||||||
+--------------+-----------+------------+----------+---------+
|
+--------------+-----------+------------+----------+---------+
|
||||||
| ANALYZING | finished | GAME_OVER | on_enter | on_exit |
|
ANALYZING | finished | GAME_OVER | |
|
||||||
| ANALYZING | schedule | SCHEDULING | on_enter | on_exit |
|
ANALYZING | schedule | SCHEDULING | |
|
||||||
| ANALYZING | wait | WAITING | on_enter | on_exit |
|
ANALYZING | wait | WAITING | |
|
||||||
| FAILURE[$] | | | | |
|
FAILURE[$] | | | |
|
||||||
| GAME_OVER | failed | FAILURE | on_enter | on_exit |
|
GAME_OVER | failed | FAILURE | |
|
||||||
| GAME_OVER | reverted | REVERTED | on_enter | on_exit |
|
GAME_OVER | reverted | REVERTED | |
|
||||||
| GAME_OVER | success | SUCCESS | on_enter | on_exit |
|
GAME_OVER | success | SUCCESS | |
|
||||||
| GAME_OVER | suspended | SUSPENDED | on_enter | on_exit |
|
GAME_OVER | suspended | SUSPENDED | |
|
||||||
| RESUMING | schedule | SCHEDULING | on_enter | on_exit |
|
RESUMING | schedule | SCHEDULING | |
|
||||||
| REVERTED[$] | | | | |
|
REVERTED[$] | | | |
|
||||||
| SCHEDULING | wait | WAITING | on_enter | on_exit |
|
SCHEDULING | wait | WAITING | |
|
||||||
| SUCCESS[$] | | | | |
|
SUCCESS[$] | | | |
|
||||||
| SUSPENDED[$] | | | | |
|
SUSPENDED[$] | | | |
|
||||||
| UNDEFINED[^] | start | RESUMING | on_enter | on_exit |
|
UNDEFINED[^] | start | RESUMING | |
|
||||||
| WAITING | analyze | ANALYZING | on_enter | on_exit |
|
WAITING | analyze | ANALYZING | |
|
||||||
+--------------+-----------+------------+----------+---------+
|
+--------------+-----------+------------+----------+---------+
|
||||||
|
|
||||||
Between any of these yielded states (minus ``GAME_OVER`` and ``UNDEFINED``)
|
Between any of these yielded states (minus ``GAME_OVER`` and ``UNDEFINED``)
|
||||||
|
@ -23,6 +23,7 @@ from taskflow import exceptions as excp
|
|||||||
from taskflow import test
|
from taskflow import test
|
||||||
from taskflow.types import fsm
|
from taskflow.types import fsm
|
||||||
from taskflow.types import graph
|
from taskflow.types import graph
|
||||||
|
from taskflow.types import table
|
||||||
from taskflow.types import timing as tt
|
from taskflow.types import timing as tt
|
||||||
from taskflow.types import tree
|
from taskflow.types import tree
|
||||||
|
|
||||||
@ -161,6 +162,26 @@ class StopWatchTest(test.TestCase):
|
|||||||
self.assertGreater(0.01, watch.elapsed())
|
self.assertGreater(0.01, watch.elapsed())
|
||||||
|
|
||||||
|
|
||||||
|
class TableTest(test.TestCase):
|
||||||
|
def test_create_valid_no_rows(self):
|
||||||
|
tbl = table.PleasantTable(['Name', 'City', 'State', 'Country'])
|
||||||
|
self.assertGreater(0, len(tbl.pformat()))
|
||||||
|
|
||||||
|
def test_create_valid_rows(self):
|
||||||
|
tbl = table.PleasantTable(['Name', 'City', 'State', 'Country'])
|
||||||
|
before_rows = tbl.pformat()
|
||||||
|
tbl.add_row(["Josh", "San Jose", "CA", "USA"])
|
||||||
|
after_rows = tbl.pformat()
|
||||||
|
self.assertGreater(len(before_rows), len(after_rows))
|
||||||
|
|
||||||
|
def test_create_invalid_columns(self):
|
||||||
|
self.assertRaises(ValueError, table.PleasantTable, [])
|
||||||
|
|
||||||
|
def test_create_invalid_rows(self):
|
||||||
|
tbl = table.PleasantTable(['Name', 'City', 'State', 'Country'])
|
||||||
|
self.assertRaises(ValueError, tbl.add_row, ['a', 'b'])
|
||||||
|
|
||||||
|
|
||||||
class FSMTest(test.TestCase):
|
class FSMTest(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(FSMTest, self).setUp()
|
super(FSMTest, self).setUp()
|
||||||
|
@ -19,10 +19,10 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
from ordereddict import OrderedDict # noqa
|
from ordereddict import OrderedDict # noqa
|
||||||
|
|
||||||
import prettytable
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from taskflow import exceptions as excp
|
from taskflow import exceptions as excp
|
||||||
|
from taskflow.types import table
|
||||||
|
|
||||||
|
|
||||||
class _Jump(object):
|
class _Jump(object):
|
||||||
@ -252,8 +252,8 @@ class FSM(object):
|
|||||||
if sort:
|
if sort:
|
||||||
return sorted(six.iterkeys(data))
|
return sorted(six.iterkeys(data))
|
||||||
return list(six.iterkeys(data))
|
return list(six.iterkeys(data))
|
||||||
tbl = prettytable.PrettyTable(
|
tbl = table.PleasantTable(["Start", "Event", "End",
|
||||||
["Start", "Event", "End", "On Enter", "On Exit"])
|
"On Enter", "On Exit"])
|
||||||
for state in orderedkeys(self._states):
|
for state in orderedkeys(self._states):
|
||||||
prefix_markings = []
|
prefix_markings = []
|
||||||
if self.current_state == state:
|
if self.current_state == state:
|
||||||
@ -287,4 +287,4 @@ class FSM(object):
|
|||||||
tbl.add_row(row)
|
tbl.add_row(row)
|
||||||
else:
|
else:
|
||||||
tbl.add_row([pretty_state, "", "", "", ""])
|
tbl.add_row([pretty_state, "", "", "", ""])
|
||||||
return tbl.get_string(print_empty=True)
|
return tbl.pformat()
|
||||||
|
128
taskflow/types/table.py
Normal file
128
taskflow/types/table.py
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright (C) 2014 Yahoo! Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
class PleasantTable(object):
|
||||||
|
"""A tiny pretty printing table (like prettytable/tabulate but smaller).
|
||||||
|
|
||||||
|
Creates simply formatted tables (with no special sauce)::
|
||||||
|
|
||||||
|
>>> from taskflow.types import table
|
||||||
|
>>> tbl = table.PleasantTable(['Name', 'City', 'State', 'Country'])
|
||||||
|
>>> tbl.add_row(["Josh", "San Jose", "CA", "USA"])
|
||||||
|
>>> print(tbl.pformat())
|
||||||
|
+------+----------+-------+---------+
|
||||||
|
Name | City | State | Country
|
||||||
|
+------+----------+-------+---------+
|
||||||
|
Josh | San Jose | CA | USA
|
||||||
|
+------+----------+-------+---------+
|
||||||
|
"""
|
||||||
|
COLUMN_STARTING_CHAR = ' '
|
||||||
|
COLUMN_ENDING_CHAR = ''
|
||||||
|
COLUMN_SEPARATOR_CHAR = '|'
|
||||||
|
HEADER_FOOTER_JOINING_CHAR = '+'
|
||||||
|
HEADER_FOOTER_CHAR = '-'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _center_text(text, max_len, fill=' '):
|
||||||
|
return '{0:{fill}{align}{size}}'.format(text, fill=fill,
|
||||||
|
align="^", size=max_len)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _size_selector(cls, possible_sizes):
|
||||||
|
# The number two is used so that the edges of a column have spaces
|
||||||
|
# around them (instead of being right next to a column separator).
|
||||||
|
try:
|
||||||
|
return max(x + 2 for x in possible_sizes)
|
||||||
|
except ValueError:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def __init__(self, columns):
|
||||||
|
if len(columns) == 0:
|
||||||
|
raise ValueError("Column count must be greater than zero")
|
||||||
|
self._columns = [column.strip() for column in columns]
|
||||||
|
self._rows = []
|
||||||
|
|
||||||
|
def add_row(self, row):
|
||||||
|
if len(row) != len(self._columns):
|
||||||
|
raise ValueError("Row must have %s columns instead of"
|
||||||
|
" %s columns" % (len(self._columns), len(row)))
|
||||||
|
self._rows.append([six.text_type(column) for column in row])
|
||||||
|
|
||||||
|
def pformat(self):
|
||||||
|
# Figure out the maximum column sizes...
|
||||||
|
column_count = len(self._columns)
|
||||||
|
column_sizes = [0] * column_count
|
||||||
|
headers = []
|
||||||
|
for i, column in enumerate(self._columns):
|
||||||
|
possible_sizes_iter = itertools.chain(
|
||||||
|
[len(column)], (len(row[i]) for row in self._rows))
|
||||||
|
column_sizes[i] = self._size_selector(possible_sizes_iter)
|
||||||
|
headers.append(self._center_text(column, column_sizes[i]))
|
||||||
|
# Build the header and footer prefix/postfix.
|
||||||
|
header_footer_buf = six.StringIO()
|
||||||
|
header_footer_buf.write(self.HEADER_FOOTER_JOINING_CHAR)
|
||||||
|
for i, header in enumerate(headers):
|
||||||
|
header_footer_buf.write(self.HEADER_FOOTER_CHAR * len(header))
|
||||||
|
if i + 1 != column_count:
|
||||||
|
header_footer_buf.write(self.HEADER_FOOTER_JOINING_CHAR)
|
||||||
|
header_footer_buf.write(self.HEADER_FOOTER_JOINING_CHAR)
|
||||||
|
# Build the main header.
|
||||||
|
content_buf = six.StringIO()
|
||||||
|
content_buf.write(header_footer_buf.getvalue())
|
||||||
|
content_buf.write("\n")
|
||||||
|
content_buf.write(self.COLUMN_STARTING_CHAR)
|
||||||
|
for i, header in enumerate(headers):
|
||||||
|
if i + 1 == column_count:
|
||||||
|
if self.COLUMN_ENDING_CHAR:
|
||||||
|
content_buf.write(headers[i])
|
||||||
|
content_buf.write(self.COLUMN_ENDING_CHAR)
|
||||||
|
else:
|
||||||
|
content_buf.write(headers[i].rstrip())
|
||||||
|
else:
|
||||||
|
content_buf.write(headers[i])
|
||||||
|
content_buf.write(self.COLUMN_SEPARATOR_CHAR)
|
||||||
|
content_buf.write("\n")
|
||||||
|
content_buf.write(header_footer_buf.getvalue())
|
||||||
|
# Build the main content.
|
||||||
|
row_count = len(self._rows)
|
||||||
|
if row_count:
|
||||||
|
content_buf.write("\n")
|
||||||
|
for i, row in enumerate(self._rows):
|
||||||
|
pieces = []
|
||||||
|
for j, column in enumerate(row):
|
||||||
|
pieces.append(self._center_text(column, column_sizes[j]))
|
||||||
|
if j + 1 != column_count:
|
||||||
|
pieces.append(self.COLUMN_SEPARATOR_CHAR)
|
||||||
|
blob = ''.join(pieces)
|
||||||
|
if self.COLUMN_ENDING_CHAR:
|
||||||
|
content_buf.write(self.COLUMN_STARTING_CHAR)
|
||||||
|
content_buf.write(blob)
|
||||||
|
content_buf.write(self.COLUMN_ENDING_CHAR)
|
||||||
|
else:
|
||||||
|
blob = blob.rstrip()
|
||||||
|
if blob:
|
||||||
|
content_buf.write(self.COLUMN_STARTING_CHAR)
|
||||||
|
content_buf.write(blob)
|
||||||
|
if i + 1 != row_count:
|
||||||
|
content_buf.write("\n")
|
||||||
|
content_buf.write("\n")
|
||||||
|
content_buf.write(header_footer_buf.getvalue())
|
||||||
|
return content_buf.getvalue()
|
Loading…
Reference in New Issue
Block a user