diff options
| -rw-r--r-- | lesana/collection.py | 20 | ||||
| -rw-r--r-- | lesana/command.py | 21 | ||||
| -rw-r--r-- | tests/data/simple/templates/new_entry_from_data.yaml | 12 | ||||
| -rw-r--r-- | tests/data/simple/templates/new_entry_from_data_broken.yaml | 14 | ||||
| -rw-r--r-- | tests/data/simple/templates/new_entry_from_data_invalid_yaml.yaml | 13 | ||||
| -rw-r--r-- | tests/data/simple/templates/new_entry_from_multiple_data.yaml | 12 | ||||
| -rw-r--r-- | tests/test_collection.py | 71 | 
7 files changed, 150 insertions, 13 deletions
diff --git a/lesana/collection.py b/lesana/collection.py index 41dd23f..20f8a0c 100644 --- a/lesana/collection.py +++ b/lesana/collection.py @@ -523,6 +523,26 @@ class Collection(object):              raise TemplatingError('Could not find template ' + str(e))          return template +    def entry_from_rendered_template(self, template, data): +        try: +            template = self.get_template(template) +            rendered = template.render(**data) +        except jinja2.exceptions.TemplateSyntaxError as e: +            raise TemplatingError(e) +        try: +            data = ruamel.yaml.load(rendered, ruamel.yaml.RoundTripLoader) +        except ruamel.yaml.YAMLError as e: +            logger.warning( +                "The following data failed to load as YAML: \n{}".format( +                    rendered +                ) + +            ) +            raise TemplatingError(e) +        entry = self.entry_class(self, data=data) +        self.save_entries([entry]) +        return entry +      @classmethod      def init(          cls, directory=None, git_enabled=True, edit_file=None, settings={} diff --git a/lesana/command.py b/lesana/command.py index 0521234..4c723af 100644 --- a/lesana/command.py +++ b/lesana/command.py @@ -4,8 +4,6 @@ import os  import subprocess  import sys -import ruamel.yaml -  from . import Collection, Entry, TemplatingError  logger = logging.getLogger(__name__) @@ -420,22 +418,19 @@ class Export(Command):              collection.start_search(' '.join(self.args.query))              results = collection.get_all_search_results()          for entry in results: +            data = { +                "entry": entry +            } +            data.update(entry.data)              try: -                template = collection.get_template(self.args.template) -                rendered = template.render(entry=entry, **entry.data) +                destination.entry_from_rendered_template( +                    self.args.template, +                    data +                )              except TemplatingError as e:                  logger.error("Error converting entry: {}".format(entry))                  logger.error("{}".format(e))                  sys.exit(1) -            try: -                data = ruamel.yaml.load(rendered, ruamel.yaml.RoundTripLoader) -            except ruamel.yaml.YAMLError as e: -                logger.error("Error loading exported entry: {}".format(entry)) -                logger.error("exported data was\n{}".format(rendered)) -                logger.error("{}".format(e)) -                sys.exit(1) -            e = self.entry_class(destination, data=data) -            destination.save_entries([e])  class Init(Command): diff --git a/tests/data/simple/templates/new_entry_from_data.yaml b/tests/data/simple/templates/new_entry_from_data.yaml new file mode 100644 index 0000000..1f9e9a5 --- /dev/null +++ b/tests/data/simple/templates/new_entry_from_data.yaml @@ -0,0 +1,12 @@ +name: '{{ name }}' +description: | +  {{ description if description else "." | indent(width=2, first=False) }} +position: '{{ position }}' +# # quantity (integer): how many items are there +quantity: {{ quantity if quantity else "0" }} +# # value (float): how much each item is +value: 0.0 +# # cost (decimal): how much this costs +cost: '0' +# # other (yaml):  +other: diff --git a/tests/data/simple/templates/new_entry_from_data_broken.yaml b/tests/data/simple/templates/new_entry_from_data_broken.yaml new file mode 100644 index 0000000..73798ce --- /dev/null +++ b/tests/data/simple/templates/new_entry_from_data_broken.yaml @@ -0,0 +1,14 @@ +name: '{{ name }}' +description: | +  {{ description if description else "." indent(width=2, first=False) }} +  # Note that the lack of | between "." and indent is wanted, to get a proper +  # TemplatingError. +position: '{{ position }}' +# quantity (integer): how many items are there +quantity: {{ quantity if quantity else "0" }} +# value (float): how much each item is +value: 0.0 +# cost (decimal): how much this costs +cost: '0' +# other (yaml):  +other: diff --git a/tests/data/simple/templates/new_entry_from_data_invalid_yaml.yaml b/tests/data/simple/templates/new_entry_from_data_invalid_yaml.yaml new file mode 100644 index 0000000..7493947 --- /dev/null +++ b/tests/data/simple/templates/new_entry_from_data_invalid_yaml.yaml @@ -0,0 +1,13 @@ +# A : in that position should result in invalid yaml +name: '{{ name }}': some text +description: | +  {{ description if description else "." | indent(width=2, first=False) }} +position: '{{ position }}' +# # quantity (integer): how many items are there +quantity: {{ quantity if quantity else "0" }} +# # value (float): how much each item is +value: 0.0 +# # cost (decimal): how much this costs +cost: '0' +# # other (yaml):  +other: diff --git a/tests/data/simple/templates/new_entry_from_multiple_data.yaml b/tests/data/simple/templates/new_entry_from_multiple_data.yaml new file mode 100644 index 0000000..cfa4296 --- /dev/null +++ b/tests/data/simple/templates/new_entry_from_multiple_data.yaml @@ -0,0 +1,12 @@ +name: '{{ data.name }}' +description: | +  {{ description if description else "." | indent(width=2, first=False) }} +position: '{{ data.position }}' +# # quantity (integer): how many items are there +quantity: {{ values.quantity if values.quantity else "0" }} +# # value (float): how much each item is +value: 0.0 +# # cost (decimal): how much this costs +cost: '{{ values.cost if values.cost else "0.0" }}' +# # other (yaml):  +other: diff --git a/tests/test_collection.py b/tests/test_collection.py index d05415f..2308633 100644 --- a/tests/test_collection.py +++ b/tests/test_collection.py @@ -1,4 +1,5 @@  import datetime +import decimal  import logging  import os.path  import shutil @@ -294,6 +295,76 @@ class testSimpleCollection(unittest.TestCase):              {'value': None, 'frequency': 1},          ]) +    def test_entry_from_template(self): +        # TODO: make finding the templates less prone to breaking and +        # then remove the cwd change from here +        old_cwd = os.getcwd() +        os.chdir(self.tmpdir) +        data = { +            "name": "This is a name", +        } +        entry = self.collection.entry_from_rendered_template( +            "templates/new_entry_from_data.yaml", +            data +        ) +        os.chdir(old_cwd) +        self.assertIsInstance(entry, lesana.Entry) +        self.assertEqual(entry.data["name"], "This is a name") + +    def test_entry_from_template_multiple_data_sources(self): +        # TODO: make finding the templates less prone to breaking and +        # then remove the cwd change from here +        old_cwd = os.getcwd() +        os.chdir(self.tmpdir) +        data = { +            "name": "This is a name", +        } +        values = { +            "quantity": 5, +            "cost": decimal.Decimal("3.5"), +        } +        entry = self.collection.entry_from_rendered_template( +            "templates/new_entry_from_multiple_data.yaml", +            { +                "data": data, +                "values": values +            } +        ) +        os.chdir(old_cwd) +        self.assertIsInstance(entry, lesana.Entry) +        self.assertEqual(entry.data["name"], "This is a name") +        self.assertEqual(entry.data["quantity"], 5) + +    def test_entry_from_bad_template(self): +        # TODO: make finding the templates less prone to breaking and +        # then remove the cwd change from here +        old_cwd = os.getcwd() +        os.chdir(self.tmpdir) +        data = { +            "name": "This is a name", +        } +        with self.assertRaises(lesana.collection.TemplatingError): +            self.collection.entry_from_rendered_template( +                "templates/new_entry_from_data_broken.yaml", +                data +            ) +        os.chdir(old_cwd) + +    def test_entry_from_bad_yaml(self): +        # TODO: make finding the templates less prone to breaking and +        # then remove the cwd change from here +        old_cwd = os.getcwd() +        os.chdir(self.tmpdir) +        data = { +            "name": "This is a name", +        } +        with self.assertRaises(lesana.collection.TemplatingError): +            self.collection.entry_from_rendered_template( +                "templates/new_entry_from_data_invalid_yaml.yaml", +                data +            ) +        os.chdir(old_cwd) +  class testComplexCollection(unittest.TestCase):      def setUp(self):  | 
