Skip to content

Commit

Permalink
Added '--quiet' option to suppress output.
Browse files Browse the repository at this point in the history
  • Loading branch information
jacebrowning committed Jul 30, 2014
1 parent 06bfbd8 commit 6212dc6
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 53 deletions.
4 changes: 2 additions & 2 deletions Makefile
Expand Up @@ -87,7 +87,7 @@ $(DEPENDS_DEV): Makefile

.PHONY: doorstop
doorstop: env
$(BIN)/doorstop
$(BIN)/doorstop --quiet

.PHONY: gui
gui: env
Expand All @@ -98,7 +98,7 @@ gui: env
.PHONY: doc
doc: readme reqs uml apidocs sphinx

.PHONY: pages
.PHONY: pages
pages: reqs-html sphinx
cp -r docs/gen/ pages/reqs/
cp -r docs/sphinx/_build pages/docs/
Expand Down
68 changes: 33 additions & 35 deletions doorstop/cli/commands.py
Expand Up @@ -5,6 +5,7 @@

from doorstop import common
from doorstop.cli import utilities
from doorstop.cli.utilities import show, ask
from doorstop.core.builder import build
from doorstop.core import editor, importer, exporter, publisher

Expand All @@ -31,17 +32,15 @@ def run(args, cwd, err, catch=True): # pylint: disable=W0613
"""
with utilities.capture(catch=catch) as success:
print("validating tree...", flush=True)
show("validating tree...", flush=True)
tree = build(cwd, root=args.project)
tree.load()
valid = tree.validate()
if not success:
return False

if len(tree) > 1 and valid:
print()
print(tree.draw())
print()
show('\n' + tree.draw() + '\n')

return valid

Expand All @@ -62,8 +61,7 @@ def run_create(args, cwd, _, catch=True):
if not success:
return False

print("created document: {} ({})".format(document.prefix,
document.relpath))
show("created document: {} ({})".format(document.prefix, document.relpath))
return True


Expand All @@ -84,7 +82,7 @@ def run_delete(args, cwd, _, catch=True):
if not success:
return False

print("deleted document: {} ({})".format(prefix, relpath))
show("deleted document: {} ({})".format(prefix, relpath))

return True

Expand All @@ -102,7 +100,7 @@ def run_add(args, cwd, _, catch=True):
tree = build(cwd, root=args.project)
for _ in range(args.count):
item = tree.add_item(args.prefix, level=args.level)
print("added item: {} ({})".format(item.id, item.relpath))
show("added item: {} ({})".format(item.id, item.relpath))

if not success:
return False
Expand All @@ -126,7 +124,7 @@ def run_remove(args, cwd, _, catch=True):
if not success:
return False

print("removed item: {} ({})".format(item.id, item.relpath))
show("removed item: {} ({})".format(item.id, item.relpath))

return True

Expand Down Expand Up @@ -163,7 +161,7 @@ def run_edit(args, cwd, err, catch=True):
return False

if item:
print("opened item: {} ({})".format(item.id, item.relpath))
show("opened item: {} ({})".format(item.id, item.relpath))

return True

Expand All @@ -188,14 +186,14 @@ def run_reorder(args, cwd, err, catch=True, _tree=None):
with utilities.capture(catch=catch) as success:
# automatically order
if args.auto:
print("reordering document {}...".format(document), flush=True)
show("reordering document {}...".format(document), flush=True)
document.reorder(manual=False)
reordered = True
# or, reorder from a previously updated index
elif document.index:
relpath = os.path.relpath(document.index, cwd)
if utilities.ask("reorder from '{}'?".format(relpath)):
print("reordering document {}...".format(document), flush=True)
if ask("reorder from '{}'?".format(relpath)):
show("reordering document {}...".format(document), flush=True)
document.reorder(automatic=not args.manual)
reordered = True
else:
Expand All @@ -207,11 +205,11 @@ def run_reorder(args, cwd, err, catch=True, _tree=None):
editor.edit(relpath, tool=args.tool)
get('reorder')(args, cwd, err, catch=False, _tree=tree)
if not success:
print("after fixing the error: doorstop reorder {}".format(document))
show("after fixing the error: doorstop reorder {}".format(document))
return False

if reordered:
print("reordered document: {}".format(document))
show("reordered document: {}".format(document))

return True

Expand All @@ -232,7 +230,7 @@ def run_link(args, cwd, _, catch=True):
return False

msg = "linked items: {} ({}) -> {} ({})"
print(msg.format(child.id, child.relpath, parent.id, parent.relpath))
show(msg.format(child.id, child.relpath, parent.id, parent.relpath))

return True

Expand All @@ -253,7 +251,7 @@ def run_unlink(args, cwd, _, catch=True):
return False

msg = "unlinked items: {} ({}) -> {} ({})"
print(msg.format(child.id, child.relpath, parent.id, parent.relpath))
show(msg.format(child.id, child.relpath, parent.id, parent.relpath))

return True

Expand All @@ -269,7 +267,7 @@ def run_clear(args, cwd, err, catch=True):
"""
with utilities.capture(catch=catch) as success:
for item in _iter_items(args, cwd, err):
print("clearing item {}'s suspect links...".format(item.id))
show("clearing item {}'s suspect links...".format(item.id))
item.clear()
if not success:
return False
Expand All @@ -288,7 +286,7 @@ def run_review(args, cwd, err, catch=True):
"""
with utilities.capture(catch=catch) as success:
for item in _iter_items(args, cwd, err):
print("marking item {} as reviewed...".format(item.id))
show("marking item {} as reviewed...".format(item.id))
item.review()
if not success:
return False
Expand Down Expand Up @@ -328,7 +326,7 @@ def run_import(args, cwd, err, catch=True, _tree=None):
document = tree.find_document(args.prefix)
msg = "importing '{}' into document {}...".format(args.path,
document)
print(msg, flush=True)
show(msg, flush=True)
importer.import_file(args.path, document, ext, mapping=mapping)
elif args.document:
prefix, path = args.document
Expand All @@ -342,11 +340,11 @@ def run_import(args, cwd, err, catch=True, _tree=None):

# Display result
if document:
print("imported document: {} ({})".format(document.prefix,
document.relpath))
show("imported document: {} ({})".format(document.prefix,
document.relpath))
else:
assert item
print("imported item: {} ({})".format(item.id, item.relpath))
show("imported item: {} ({})".format(item.id, item.relpath))

return True

Expand Down Expand Up @@ -376,22 +374,22 @@ def run_export(args, cwd, err, catch=True):
# Write to output file(s)
if args.path:
if whole_tree:
print("exporting tree to '{}'...".format(args.path), flush=True)
show("exporting tree to '{}'...".format(args.path), flush=True)
path = exporter.export(tree, args.path, ext)
else:
msg = "exporting document {} to '{}'...".format(document,
args.path)
print(msg, flush=True)
show(msg, flush=True)
path = exporter.export(document, args.path, ext)
if path:
print("exported: {}".format(path))
show("exported: {}".format(path))

# Display to standard output
else:
if whole_tree:
err("only single documents can be displayed")
for line in exporter.export_lines(document, ext):
print(line)
show(line)

return True

Expand Down Expand Up @@ -426,22 +424,22 @@ def run_publish(args, cwd, err, catch=True):
# Write to output file(s)
if args.path:
if whole_tree:
print("publishing tree to '{}'...".format(args.path), flush=True)
show("publishing tree to '{}'...".format(args.path), flush=True)
path = publisher.publish(tree, args.path, ext, **kwargs)
else:
msg = "publishing document {} to '{}'...".format(document,
args.path)
print(msg, flush=True)
show(msg, flush=True)
path = publisher.publish(document, args.path, ext, **kwargs)
if path:
print("published: {}".format(path))
show("published: {}".format(path))

# Display to standard output
else:
if whole_tree:
err("only single documents can be displayed")
for line in publisher.publish_lines(document, ext, **kwargs):
print(line)
show(line)

return True

Expand Down Expand Up @@ -520,14 +518,14 @@ def _export_import(args, cwd, err, document, ext):
editor.edit(path, tool=args.tool)

# Import the file to the same document
if utilities.ask("import from '{}'?".format(path)):
if ask("import from '{}'?".format(path)):
args.attrs = {}
args.map = {}
get('import')(args, cwd, err, catch=False, _tree=document.tree)
common.delete(path)
else:
print("import canceled")
if utilities.ask("delete '{}'?".format(path), default='no'):
show("import canceled")
if ask("delete '{}'?".format(path), default='no'):
common.delete(path)
else:
print("to manually import: doorstop import {0}".format(path))
show("to manually import: doorstop import {0}".format(path))
5 changes: 4 additions & 1 deletion doorstop/cli/main.py
Expand Up @@ -22,8 +22,11 @@ def main(args=None): # pylint: disable=R0915
debug.add_argument('-j', '--project', metavar='PATH',
help="path to the root of the project")
debug.add_argument('-V', '--version', action='version', version=VERSION)
debug.add_argument('-v', '--verbose', action='count', default=0,
group = debug.add_mutually_exclusive_group()
group.add_argument('-v', '--verbose', action='count', default=0,
help="enable verbose logging")
group.add_argument('-q', '--quiet', action='store_const', const=-1,
dest='verbose', help="only display errors and prompts")
shared = {'formatter_class': common.HelpFormatter, 'parents': [debug]}

# Build main parser
Expand Down
7 changes: 6 additions & 1 deletion doorstop/cli/test/test_all.py
Expand Up @@ -761,4 +761,9 @@ def test_verbose_4(self):
def test_verbose_5(self):
"""Verify verbose level 5 cannot be set."""
self.assertIs(None, main(['-vvvvv']))
self.assertEqual(4, common.VERBOSITY)
self.assertEqual(4, common.verbosity)

def test_verbose_quiet(self):
"""Verify verbose level -1 can be set."""
self.assertIs(None, main(['-q']))
self.assertEqual(-1, common.verbosity)
19 changes: 19 additions & 0 deletions doorstop/cli/test/test_utilities.py
Expand Up @@ -175,6 +175,25 @@ def test_ask_bad(self):
self.assertTrue(response)


class TestShow(unittest.TestCase): # pylint: disable=R0904

"""Unit tests for the `show` function.""" # pylint: disable=R0201

@patch('builtins.print')
def test_show(self, mock_print):
"""Verify prints are enabled by default."""
msg = "Hello, world!"
utilities.show(msg)
mock_print.assert_called_once_with(msg, flush=False)

@patch('builtins.print')
@patch('doorstop.common.verbosity', common.PRINT_VERBOSITY - 1)
def test_show_hidden(self, mock_print):
"""Verify prints are hidden when verbosity is quiet."""
utilities.show("This won't be printed.")
mock_print.assert_never_called()


class TestPositiveInt(unittest.TestCase): # pylint: disable=R0904

""" Unit tests for the `positive_int` function."""
Expand Down
17 changes: 14 additions & 3 deletions doorstop/cli/utilities.py
Expand Up @@ -35,11 +35,16 @@ def __exit__(self, exc_type, exc_value, traceback):

def configure_logging(verbosity=0):
"""Configure logging using the provided verbosity level (0+)."""
assert common.PRINT_VERBOSITY == 0
assert common.STR_VERBOSITY == 3
assert common.MAX_VERBOSITY == 4

# Configure the logging level and format
if verbosity == 0:
if verbosity == -1:
level = settings.QUIET_LOGGING_LEVEL
default_format = settings.DEFAULT_LOGGING_FORMAT
verbose_format = settings.LEVELED_LOGGING_FORMAT
elif verbosity == 0:
level = settings.DEFAULT_LOGGING_LEVEL
default_format = settings.DEFAULT_LOGGING_FORMAT
verbose_format = settings.LEVELED_LOGGING_FORMAT
Expand Down Expand Up @@ -67,9 +72,9 @@ def configure_logging(verbosity=0):
if verbosity > common.MAX_VERBOSITY:
msg = "maximum verbosity level is {}".format(common.MAX_VERBOSITY)
logging.warn(msg)
common.VERBOSITY = common.MAX_VERBOSITY
common.verbosity = common.MAX_VERBOSITY
else:
common.VERBOSITY = verbosity
common.verbosity = verbosity


def configure_settings(args):
Expand Down Expand Up @@ -169,6 +174,12 @@ def get_ext(args, ext_stdout, ext_file, whole_tree, err):
return ext


def show(message, flush=False):
"""Print (optionally flushed) text to the display."""
if common.verbosity >= common.PRINT_VERBOSITY:
print(message, flush=flush)


def ask(question, default=None):
"""Display a console yes/no prompt.
Expand Down
13 changes: 10 additions & 3 deletions doorstop/common.py
Expand Up @@ -7,9 +7,10 @@

import yaml

VERBOSITY = 0 # global verbosity setting for controlling string formatting
STR_VERBOSITY = 3
MAX_VERBOSITY = 4
verbosity = None # global verbosity setting for controlling string formatting
PRINT_VERBOSITY = 0 # minimum verbosity to using `print`
STR_VERBOSITY = 3 # minimum verbosity to use verbose `__str__`
MAX_VERBOSITY = 4 # maximum verbosity level implemented


def _trace(self, message, *args, **kws): # pragma: no cover (manual test)
Expand All @@ -25,6 +26,9 @@ def _trace(self, message, *args, **kws): # pragma: no cover (manual test)
log = logger(__name__)


# exception classes ##########################################################


class DoorstopError(Exception):

"""Generic Doorstop error."""
Expand Down Expand Up @@ -66,6 +70,9 @@ def format(self, record): # pragma: no cover (manual test)
return super().format(record)


# disk helper functions ######################################################


def create_dirname(path):
"""Ensure a parent directory exists for a path."""
dirpath = os.path.dirname(path)
Expand Down
2 changes: 1 addition & 1 deletion doorstop/core/document.py
Expand Up @@ -57,7 +57,7 @@ def __repr__(self):
return "Document('{}')".format(self.path)

def __str__(self):
if common.VERBOSITY < common.STR_VERBOSITY:
if common.verbosity < common.STR_VERBOSITY:
return self.prefix
else:
return "{} ({})".format(self.prefix, self.relpath)
Expand Down

0 comments on commit 6212dc6

Please sign in to comment.