fix: fixed templated rendering using class object attributes

This commit is contained in:
Aerex 2019-04-13 01:28:43 -05:00
parent e5e9ddd836
commit 3a85ad936d
6 changed files with 90 additions and 109 deletions

View File

@ -16,11 +16,10 @@ logger = logging.getLogger(__name__)
APP_NAME = 'grocy-cli' APP_NAME = 'grocy-cli'
SAMPLE_CONFIG_FILE = 'sample.config.yml' SAMPLE_CONFIG_FILE = 'sample.config.yml'
TMP_DIR = '/tmp/grocy' TMP_DIR = '/tmp/grocy'
TEMPLATE_DIR = '../templates'
CONFIG_FILE = 'config.yml' CONFIG_FILE = 'config.yml'
CONFIG_DIR = click.get_app_dir(APP_NAME) CONFIG_DIR = click.get_app_dir(APP_NAME)
PROJ_DIR = path.join(path.dirname(path.realpath(__file__))) 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): def __validate_token(cfg):
# Validate token # Validate token
@ -41,21 +40,6 @@ def __create_config_file():
chmod(user_cfg_file, 0o664) chmod(user_cfg_file, 0o664)
return user_cfg_file 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.group()
@click.pass_context @click.pass_context
def main(ctx): def main(ctx):
@ -109,52 +93,51 @@ def shopping(ctx):
shopping_list = shopping.get_list() shopping_list = shopping.get_list()
click.echo(shopping_list) click.echo(shopping_list)
" Recipe Commands "
@main.group() @main.group()
@click.pass_context @click.pass_context
def recipe(ctx): def recipe(ctx):
cfg = ctx.obj['cfg'] if ctx.invoked_subcommand is None:
cfg = ctx.obj['cfg']
receipe = Recipe(**cfg) receipe = Recipe(id=None, **cfg)
recipes = receipe.get_list() recipes = receipe.get_list()
click.echo(recipes) click.echo(recipes)
@recipe.command('edit') @recipe.command('edit')
@click.argument('recipe_id') @click.argument('recipe_id')
@click.pass_context @click.pass_context
def edit(ctx): def edit(ctx, recipe_id):
cfg = ctx.obj['cfg'] cfg = ctx.obj['cfg']
logger = cfg['logger'] logger = cfg['logger']
try: try:
if recipe_id: if recipe_id:
receipe = Recipe(id=receipe_id, **cfg) recipe = Recipe(id=recipe_id, **cfg)
loaded_recipe = recipe.get(include_products=True) recipe.get(include_products=True)
loaded_template = TEMPLATE_LOADER.get_template('recipe.yml') 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: if edited_recipe is not None:
updated_recipe = Recipe(id=receipe_id, **edited_recipe) updated_recipe = Recipe(id=receipe_id, **edited_recipe)
updated_recipe.update() updated_recipe.update()
except Exception as e: except Exception as e:
logger.error(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()
@main.command() #@click.pass_context
@click.pass_context #def chore(ctx):
def chore(ctx): # cfg = ctx.obj['cfg']
cfg = ctx.obj['cfg'] #
# chore = Chore(**cfg)
chore = Chore(**cfg) # chores = chore.get_list()
chores = chore.get_list() # click.echo(chores)
click.echo(chores) #
#@main.command()
@main.command() #@click.pass_context
@click.pass_context #def task(ctx):
def task(ctx): # cfg = ctx.obj['cfg']
cfg = ctx.obj['cfg'] #
# task = Task(**cfg)
task = Task(**cfg) # tasks = task.get_list()
tasks = task.get_list() # click.echo(tasks)
click.echo(tasks)

View File

@ -1,4 +1,5 @@
from grocy.commands.stock import Stock from grocy.commands.stock import Stock
from grocy.commands.product import Product
from grocy.commands.recipe import Recipe from grocy.commands.recipe import Recipe
from grocy.commands.chore import Chore from grocy.commands.chore import Chore
from grocy.commands.task import Task from grocy.commands.task import Task

View File

@ -1,13 +1,14 @@
from grocy import RestService from grocy import RestService
from grocy.commands import products import html2text
from grocy.commands import product
from tabulate import tabulate from tabulate import tabulate
from os import path from os import path
class Recipe(object): class Recipe(object):
GET_RECIPES = '/get-objects/recipes' GET_RECIPES = '/objects/recipes'
GET_RECIPE = '/get-object/recipes/{0}' GET_RECIPE = '/objects/recipes/{0}'
GET_PRODUCT = '/get-object/products/{0}' GET_PRODUCT = '/objects/products/{0}'
GET_RECIPES_POS = '/get-object/recipes_pos' GET_RECIPES_POS = '/objects/recipes_pos'
def __init__(self, id, **entries): def __init__(self, id, **entries):
self.id = id self.id = id
self.__dict__.update(entries) self.__dict__.update(entries)
@ -19,40 +20,6 @@ class Recipe(object):
#if not hasattr('colalign', self): #if not hasattr('colalign', self):
# self.colalign = None # 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): def get_list(self):
try: try:
recipes = self.rest_service.get(Recipe.GET_RECIPES) recipes = self.rest_service.get(Recipe.GET_RECIPES)
@ -67,15 +34,45 @@ class Recipe(object):
# Generate stock overview table # Generate stock overview table
return tabulate(table_entries, headers=table_headers) 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): def get(self, include_products=False):
try: try:
recipe = self.rest_service.get(Recipe.GET_RECIPE.format(self.id)) 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: if include_products:
self.products = self._get_products_by_recipe_id() self._get_products_by_recipe_id()
except Exception as e: except Exception as e:
raise e raise e
return recipe.to_json()

View File

@ -15,7 +15,6 @@ class Stock(object):
# self.colalign = None # self.colalign = None
def _set_default_table_formats(self): def _set_default_table_formats(self):
if not hasattr('formats', self): if not hasattr('formats', self):
self.tablefmt = None self.tablefmt = None
@ -26,7 +25,6 @@ class Stock(object):
self.colalign = None self.colalign = None
def _init_rest_service(self): def _init_rest_service(self):
if self.api.startswith == '/': if self.api.startswith == '/':
self.api = self.api[1:] self.api = self.api[1:]
@ -59,6 +57,5 @@ class Stock(object):
# Generate stock overview table # Generate stock overview table
table_headers = ['Product', 'Amount', 'Best Before Date', 'Amount Opened'] table_headers = ['Product', 'Amount', 'Best Before Date', 'Amount Opened']
return tabulate(table_entries, headers=table_headers) return tabulate(table_entries, headers=table_headers)
except Exception as e: except Exception as e:
raise e raise e

View File

@ -22,7 +22,7 @@ setup(
packages=find_packages(), packages=find_packages(),
include_package_data=True, include_package_data=True,
zip_safe=False, 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'), long_description=read('README.rst'),
tests_require=[ tests_require=[
"pytest_mock", "pytest_mock",

View File

@ -1,18 +1,21 @@
name: {{ name }} name: {{ recipe.name }}
description: {{ description }} description: >-
recipe_id: {{ recipe_id } {{ recipe.description_txt }}
picture_file_name: {{ picture_file_name | null }} recipe_id: {{ recipe.id }}
base_serving: {{ base_serving | "1" }} picture_file_name: {% if recipe.picture_file_name is not none %}
desired_serving: {{ desired_serving | "1" }} {{recipe.picture_file_name}}
not_checking_shopping_list: {{ not_checking_shopping_list | "1" }} {% else %}
{% for product in products }
products: {% 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 }} - id: {{ product.id }}
amount: {{ product.amount }} amount: {{ product.amount }}
note: {{ product.note }} note: {{ product.note }}
qu_id: qu_id: ''
only_check_single_unit_in_stock: {{ product.only_check_single_unit_in_stock }} only_check_single_unit_in_stock: {{ product.only_check_single_unit_in_stock }}
ingredient_group: {{ product.ingredient_group | null }} ingredient_group: {{ product.ingredient_group | default(null) }}
not_checking_shopping_list: {{ product.not_checking_shopping_list }} not_checking_shopping_list: {{ product.not_checking_shopping_list }}{% endfor %}
{% endfor }