From 3a85ad936d85a8a02da274907b568a50a1d49575 Mon Sep 17 00:00:00 2001 From: Aerex Date: Sat, 13 Apr 2019 01:28:43 -0500 Subject: [PATCH] fix: fixed templated rendering using class object attributes --- grocy/cli.py | 79 ++++++++++++++--------------------- grocy/commands/__init__.py | 1 + grocy/commands/recipe.py | 85 ++++++++++++++++++-------------------- grocy/commands/stock.py | 3 -- setup.py | 2 +- templates/recipe.yml | 29 +++++++------ 6 files changed, 90 insertions(+), 109 deletions(-) diff --git a/grocy/cli.py b/grocy/cli.py index 5f4e8a4..8d77c67 100644 --- a/grocy/cli.py +++ b/grocy/cli.py @@ -1,8 +1,8 @@ import click from jinja2 import Environment, FileSystemLoader -from uuid import uuid4 +from uuid import uuid4 from grocy import RestService -from grocy.commands import * +from grocy.commands import * from pkg_resources import iter_entry_points import yaml from sys import exit @@ -16,11 +16,10 @@ logger = logging.getLogger(__name__) APP_NAME = 'grocy-cli' SAMPLE_CONFIG_FILE = 'sample.config.yml' TMP_DIR = '/tmp/grocy' -TEMPLATE_DIR = '../templates' CONFIG_FILE = 'config.yml' CONFIG_DIR = click.get_app_dir(APP_NAME) PROJ_DIR = path.join(path.dirname(path.realpath(__file__))) -TEMPLATE_LOADER = Environment(loader = FileSystemLoader(TEMPLATE_DIR), trim_blocks=True, lstrip_blocks=True) +TEMPLATE_LOADER = Environment(loader = FileSystemLoader('templates'), trim_blocks=True, lstrip_blocks=True) def __validate_token(cfg): # Validate token @@ -41,21 +40,6 @@ def __create_config_file(): chmod(user_cfg_file, 0o664) return user_cfg_file -def open_editor(template, data): - if not path.exists(TMP_DIR): - makedirs(TMP_DIR) - tmp_filename_template = '{}/grocy-{}'.format(TMP_DIR, uuid()) - open_editork k - - - - - - - - - - @click.group() @click.pass_context def main(ctx): @@ -106,55 +90,54 @@ def shopping(ctx): cfg = ctx.obj['cfg'] shopping = Shopping(**cfg) - shopping_list = shopping.get_list() + shopping_list = shopping.get_list() click.echo(shopping_list) -" Recipe Commands " @main.group() @click.pass_context def recipe(ctx): - cfg = ctx.obj['cfg'] + if ctx.invoked_subcommand is None: + cfg = ctx.obj['cfg'] - receipe = Recipe(**cfg) - recipes = receipe.get_list() - click.echo(recipes) + receipe = Recipe(id=None, **cfg) + recipes = receipe.get_list() + click.echo(recipes) @recipe.command('edit') @click.argument('recipe_id') @click.pass_context -def edit(ctx): +def edit(ctx, recipe_id): cfg = ctx.obj['cfg'] logger = cfg['logger'] try: if recipe_id: - receipe = Recipe(id=receipe_id, **cfg) - loaded_recipe = recipe.get(include_products=True) + recipe = Recipe(id=recipe_id, **cfg) + recipe.get(include_products=True) loaded_template = TEMPLATE_LOADER.get_template('recipe.yml') - edited_recipe = click.edit(loaded_template.render(loaded_recipe)) + edited_recipe = click.edit(loaded_template.render(dict(recipe=recipe))) if edited_recipe is not None: updated_recipe = Recipe(id=receipe_id, **edited_recipe) updated_recipe.update() except Exception as e: logger.error(e) - logger.error('Could not edit recipe {}'.format(recipe_id) + logger.error('Could not edit recipe {}'.format(recipe_id)) -" Recipe Commands " -@main.command() -@click.pass_context -def chore(ctx): - cfg = ctx.obj['cfg'] - - chore = Chore(**cfg) - chores = chore.get_list() - click.echo(chores) - -@main.command() -@click.pass_context -def task(ctx): - cfg = ctx.obj['cfg'] - - task = Task(**cfg) - tasks = task.get_list() - click.echo(tasks) +#@main.command() +#@click.pass_context +#def chore(ctx): +# cfg = ctx.obj['cfg'] +# +# chore = Chore(**cfg) +# chores = chore.get_list() +# click.echo(chores) +# +#@main.command() +#@click.pass_context +#def task(ctx): +# cfg = ctx.obj['cfg'] +# +# task = Task(**cfg) +# tasks = task.get_list() +# click.echo(tasks) diff --git a/grocy/commands/__init__.py b/grocy/commands/__init__.py index abd65f1..26556e8 100644 --- a/grocy/commands/__init__.py +++ b/grocy/commands/__init__.py @@ -1,4 +1,5 @@ from grocy.commands.stock import Stock +from grocy.commands.product import Product from grocy.commands.recipe import Recipe from grocy.commands.chore import Chore from grocy.commands.task import Task diff --git a/grocy/commands/recipe.py b/grocy/commands/recipe.py index bdfb0b3..2992a8c 100644 --- a/grocy/commands/recipe.py +++ b/grocy/commands/recipe.py @@ -1,13 +1,14 @@ from grocy import RestService -from grocy.commands import products +import html2text +from grocy.commands import product from tabulate import tabulate from os import path class Recipe(object): - GET_RECIPES = '/get-objects/recipes' - GET_RECIPE = '/get-object/recipes/{0}' - GET_PRODUCT = '/get-object/products/{0}' - GET_RECIPES_POS = '/get-object/recipes_pos' + GET_RECIPES = '/objects/recipes' + GET_RECIPE = '/objects/recipes/{0}' + GET_PRODUCT = '/objects/products/{0}' + GET_RECIPES_POS = '/objects/recipes_pos' def __init__(self, id, **entries): self.id = id self.__dict__.update(entries) @@ -19,40 +20,6 @@ class Recipe(object): #if not hasattr('colalign', self): # self.colalign = None - - - def _get_products_by_recipe_id(self): - recipe_products = self.rest_service.get(Recipe.GET_RECIPES_POS) - products_for_recipe = [] - for recipe_product in recipe_products: - if recipe_product.get('recipe_id') == self.id: - ## TODO: need to find a better way to run a batch call to get only products for recipe - product = self.rest_service.get(Recipe.GET_PRODUCT.format(recipe_product.get('product_id')) - ## combined dict into single dict - product_recipie_info = {k: v for combined_dict in [product, recipe_product] for k, v in combined_dict.items()} - self.products.append(product_recipie_info) - - def _set_default_table_formats(self): - if not hasattr('formats', self): - self.tablefmt = None - self.colalign = None - elif not hasattr('table', self.formats): - self.tableformat = None - elif not hasattr('col', self.formats): - self.colalign = None - - - - def _init_rest_service(self): - if self.api.startswith == '/': - self.api = self.api[1:] - if self.api.endswith == '/': - self.api = self.api[1:-1] - self.rest_service = RestService(self.api, json=True) - self.rest_service.addHeader('Content-Type', 'application/json') - self.rest_service.addToken(self.token) - - def get_list(self): try: recipes = self.rest_service.get(Recipe.GET_RECIPES) @@ -67,15 +34,45 @@ class Recipe(object): # Generate stock overview table return tabulate(table_entries, headers=table_headers) + + def _get_products_by_recipe_id(self): + recipe_products = self.rest_service.get(Recipe.GET_RECIPES_POS) + products_for_recipe = [] + for recipe_product in recipe_products: + if recipe_product.get('recipe_id') == self.id: + ## TODO: need to find a better way to run a batch call to get only products for recipe + product = self.rest_service.get(Recipe.GET_PRODUCT.format(recipe_product.get('product_id'))) + ## combined dict into single dict + product_recipe_info = {k: v for combined_dict in [product, recipe_product] for k, v in combined_dict.items()} + self.products.append(product_recipe_info) + + def _set_default_table_formats(self): + if not hasattr('formats', self): + self.tablefmt = None + self.colalign = None + elif not hasattr('table', self.formats): + self.tableformat = None + elif not hasattr('col', self.formats): + self.colalign = None + + + def _init_rest_service(self): + if self.api.startswith == '/': + self.api = self.api[1:] + if self.api.endswith == '/': + self.api = self.api[1:-1] + self.rest_service = RestService(self.api, json=True) + self.rest_service.addHeader('Content-Type', 'application/json') + self.rest_service.addToken(self.token) + def get(self, include_products=False): try: recipe = self.rest_service.get(Recipe.GET_RECIPE.format(self.id)) + if 'description' in recipe: + recipe['description_txt'] = html2text.html2text(recipe['description'].strip()) + self.__dict__.update(recipe) if include_products: - self.products = self._get_products_by_recipe_id() - + self._get_products_by_recipe_id() except Exception as e: raise e - return recipe.to_json() - - diff --git a/grocy/commands/stock.py b/grocy/commands/stock.py index 161bd12..bf0c12e 100644 --- a/grocy/commands/stock.py +++ b/grocy/commands/stock.py @@ -14,7 +14,6 @@ class Stock(object): #if not hasattr('colalign', self): # self.colalign = None - def _set_default_table_formats(self): if not hasattr('formats', self): @@ -24,7 +23,6 @@ class Stock(object): self.tableformat = None elif not hasattr('col', self.formats): self.colalign = None - def _init_rest_service(self): @@ -59,6 +57,5 @@ class Stock(object): # Generate stock overview table table_headers = ['Product', 'Amount', 'Best Before Date', 'Amount Opened'] return tabulate(table_entries, headers=table_headers) - except Exception as e: raise e diff --git a/setup.py b/setup.py index 75d1549..fd69b8d 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ setup( packages=find_packages(), include_package_data=True, zip_safe=False, - install_requires=['Click', 'pyyaml', 'requests', 'taskw', 'lockfile', 'tox'], + install_requires=['Click', 'pyyaml', 'requests', 'taskw', 'lockfile', 'tox', 'html2text'], long_description=read('README.rst'), tests_require=[ "pytest_mock", diff --git a/templates/recipe.yml b/templates/recipe.yml index e43fe9e..2857007 100644 --- a/templates/recipe.yml +++ b/templates/recipe.yml @@ -1,18 +1,21 @@ -name: {{ name }} -description: {{ description }} -recipe_id: {{ recipe_id } -picture_file_name: {{ picture_file_name | null }} -base_serving: {{ base_serving | "1" }} -desired_serving: {{ desired_serving | "1" }} -not_checking_shopping_list: {{ not_checking_shopping_list | "1" }} -{% for product in products } -products: +name: {{ recipe.name }} +description: >- +{{ recipe.description_txt }} +recipe_id: {{ recipe.id }} +picture_file_name: {% if recipe.picture_file_name is not none %} +{{recipe.picture_file_name}} +{% else %} + +{% endif %} +base_servings: {{ recipe.base_servings | default("1") }} +desired_servings: {{ recipe.desired_servings | default("1") }} +not_checking_shopping_list: {{ recipe.not_checking_shopping_list | default("1") }} +products: {% for product in recipe.products %} - id: {{ product.id }} amount: {{ product.amount }} note: {{ product.note }} - qu_id: + qu_id: '' only_check_single_unit_in_stock: {{ product.only_check_single_unit_in_stock }} - ingredient_group: {{ product.ingredient_group | null }} - not_checking_shopping_list: {{ product.not_checking_shopping_list }} -{% endfor } + ingredient_group: {{ product.ingredient_group | default(null) }} + not_checking_shopping_list: {{ product.not_checking_shopping_list }}{% endfor %}