diff --git a/pubs/commands/tag_cmd.py b/pubs/commands/tag_cmd.py index 34485b8..cb259d3 100644 --- a/pubs/commands/tag_cmd.py +++ b/pubs/commands/tag_cmd.py @@ -19,23 +19,25 @@ The different use cases are : import re -from ..repo import Repository, InvalidReference +from ..repo import Repository from ..configs import config from ..uis import get_ui from .. import pretty from .. import color + def parser(subparsers): parser = subparsers.add_parser('tag', help="add, remove and show tags") - parser.add_argument('citekeyOrTag', nargs='?', default = None, + parser.add_argument('citekeyOrTag', nargs='?', default=None, help='citekey or tag.') - parser.add_argument('tags', nargs='*', default = None, + parser.add_argument('tags', nargs='*', default=None, help='If the previous argument was a citekey, then ' - 'then a list of tags separated by a +.') + 'a list of tags separated by a +.') # TODO find a way to display clear help for multiple command semantics, # indistinguisable for argparse. (fabien, 201306) return parser + def _parse_tags(list_tags): """Transform 'math-ai network -search' in ['+math', '-ai', '+network', '-search']""" tags = [] @@ -43,9 +45,12 @@ def _parse_tags(list_tags): tags += _parse_tag_seq(s) return tags + def _parse_tag_seq(s): """Transform 'math-ai' in ['+math', '-ai']""" tags = [] + if s[0] == ':': + s = '-' + s[1:] if s[0] not in ['+', '-']: s = '+' + s last = 0 @@ -62,6 +67,7 @@ def _parse_tag_seq(s): tags.append(s[last:]) return tags + def _tag_groups(tags): plus_tags, minus_tags = [], [] for tag in tags: @@ -72,6 +78,7 @@ def _tag_groups(tags): minus_tags.append(tag[1:]) return set(plus_tags), set(minus_tags) + def command(args): """Add, remove and show tags""" @@ -79,7 +86,6 @@ def command(args): citekeyOrTag = args.citekeyOrTag tags = args.tags - rp = Repository(config()) if citekeyOrTag is None: @@ -88,8 +94,7 @@ def command(args): if rp.databroker.exists(citekeyOrTag): p = rp.pull_paper(citekeyOrTag) if tags == []: - ui.message(color.dye_out(' '.join(sorted(p.tags)), - color.tag)) + ui.message(color.dye_out(' '.join(sorted(p.tags)), color.tag)) else: add_tags, remove_tags = _tag_groups(_parse_tags(tags)) for tag in add_tags: @@ -109,4 +114,4 @@ def command(args): papers_list.append(p) ui.message('\n'.join(pretty.paper_oneliner(p) - for p in papers_list)) + for p in papers_list)) diff --git a/tests/test_tag.py b/tests/test_tag.py index 7e08d43..409ebc5 100644 --- a/tests/test_tag.py +++ b/tests/test_tag.py @@ -6,16 +6,21 @@ from pubs.commands.tag_cmd import _parse_tags, _tag_groups class TestTag(unittest.TestCase): - def test_tag_parsing(self): - + def test_parse_tags(self): self.assertEqual(['+abc', '+def9'], _parse_tags([ 'abc+def9'])) self.assertEqual(['+abc', '-def9'], _parse_tags([ 'abc-def9'])) self.assertEqual(['-abc', '-def9'], _parse_tags(['-abc-def9'])) self.assertEqual(['+abc', '-def9'], _parse_tags(['+abc-def9'])) - self.assertEqual(({'math', 'romance'}, {'war'}), _tag_groups(_parse_tags(['-war+math+romance']))) - self.assertEqual(({'math', 'romance'}, {'war'}), _tag_groups(_parse_tags(['+math+romance-war']))) - self.assertEqual(({'math', 'romance'}, {'war'}), _tag_groups(_parse_tags(['math+romance-war']))) + def test_tag_groups(self): + self.assertEqual(({'math', 'romance'}, {'war'}), + _tag_groups(_parse_tags(['-war+math+romance']))) + self.assertEqual(({'math', 'romance'}, {'war'}), + _tag_groups(_parse_tags([':war+math+romance']))) + self.assertEqual(({'math', 'romance'}, {'war'}), + _tag_groups(_parse_tags(['+math+romance-war']))) + self.assertEqual(({'math', 'romance'}, {'war'}), + _tag_groups(_parse_tags(['math+romance-war']))) if __name__ == '__main__': diff --git a/tests/test_usecase.py b/tests/test_usecase.py index 5464d21..7345918 100644 --- a/tests/test_usecase.py +++ b/tests/test_usecase.py @@ -116,7 +116,7 @@ class DataCommandTestCase(CommandTestCase): """ def setUp(self): - CommandTestCase.setUp(self) + super(DataCommandTestCase, self).setUp() fake_env.copy_dir(self.fs, os.path.join(os.path.dirname(__file__), 'data'), 'data') @@ -249,6 +249,76 @@ class TestList(DataCommandTestCase): self.assertEqual(0 + 1, len(outs[-1].split('\n'))) +class TestTag(DataCommandTestCase): + + def setUp(self): + super(TestTag, self).setUp() + init = ['pubs init', + 'pubs add data/pagerank.bib', + 'pubs add -k Turing1950 data/turing1950.bib', + ] + self.execute_cmds(init) + + def test_add_tag(self): + cmds = ['pubs tag Page99 search', + 'pubs tag Turing1950 ai', + 'pubs list', + ] + correct = ['', + '', + '[Page99] Page, Lawrence et al. "The PageRank Citation Ranking: Bringing Order to the Web." (1999) | search\n' + + '[Turing1950] Turing, Alan M "Computing machinery and intelligence" Mind (1950) | ai\n', + ] + out = self.execute_cmds(cmds) + self.assertEqual(out, correct) + + def test_add_tags(self): + """Adds several tags at once. + Also checks that tags printed in alphabetic order. + """ + cmds = ['pubs tag Page99 search+network', + 'pubs list', + ] + correct = ['', + '[Page99] Page, Lawrence et al. "The PageRank Citation Ranking: Bringing Order to the Web." (1999) | network,search\n' + + '[Turing1950] Turing, Alan M "Computing machinery and intelligence" Mind (1950) \n', + ] + out = self.execute_cmds(cmds) + self.assertEqual(out, correct) + + def test_remove_tag(self): + cmds = ['pubs tag Page99 search+network', + 'pubs tag Page99 :network', + 'pubs list', + ] + correct = ['', + '', + '[Page99] Page, Lawrence et al. "The PageRank Citation Ranking: Bringing Order to the Web." (1999) | search\n' + + '[Turing1950] Turing, Alan M "Computing machinery and intelligence" Mind (1950) \n', + ] + out = self.execute_cmds(cmds) + self.assertEqual(out, correct) + + def test_add_remove_tag(self): + cmds = ['pubs tag Page99 a', + 'pubs tag Page99 b-a', + 'pubs list', + ] + correct = ['', + '', + '[Page99] Page, Lawrence et al. "The PageRank Citation Ranking: Bringing Order to the Web." (1999) | b\n' + + '[Turing1950] Turing, Alan M "Computing machinery and intelligence" Mind (1950) \n', + ] + out = self.execute_cmds(cmds) + self.assertEqual(out, correct) + + def test_wrong_citekey(self): + cmds = ['pubs tag Page999 a', + ] + with self.assertRaises(SystemExit): + self.execute_cmds(cmds) + + class TestUsecase(DataCommandTestCase): def test_first(self): @@ -438,7 +508,7 @@ class TestUsecase(DataCommandTestCase): ] self.execute_cmds(cmds) self.assertFalse(self.fs['os'].path.exists('/data/pagerank.pdf')) - + if __name__ == '__main__': unittest.main()