def _get_linked_recipe(ingredient: Ingredient, *, base_url: URL, parser: RecipeParser, flatten: bool = True) -> Recipe: url = base_url.join(URL(ingredient.link)) try: with urllib.request.urlopen(str(url)) as req: encoding = req.info().get_content_charset() or 'UTF-8' src = req.read().decode(encoding) except Exception as e: raise RuntimeError( f'''Couldn't find linked recipe for ingredient "{ingredient.name}"''' ) from e try: link_recipe = parser.parse(src) except Exception as e: raise RuntimeError( f'''Couldn't parse linked recipe for ingredient "{ingredient.name}"''' ) from e if flatten: link_recipe = _get_flattened_recipe(link_recipe, base_url=url, parser=parser) if ingredient.amount: try: link_recipe = get_recipe_with_yield(link_recipe, ingredient.amount) except StopIteration: print(_make_missing_yield_warning(link_recipe, ingredient.amount), file=sys.stderr) return link_recipe
def main(): # completions argcomplete.autocomplete(parser) # parse args args = parser.parse_args() # initialize rp = RecipeParser() rs = RecipeSerializer() # read and parse recipe src = args.file.read() r = rp.parse(src) # scale recipe r = _process_scaling(r, args) # base url for late use base_url = URL(f'file://{os.path.abspath(args.file.name)}') # export linked recipes if args.export_links: _export_links(r, args, base_url, rp, rs) return # flatten recipe if args.flatten: r = _get_flattened_recipe(r, base_url=base_url, parser=rp) # create output depending on arguments print(_create_recipe_output(r, rs, args))
def main(): parser = argparse.ArgumentParser(description='Read and process recipemd recipes') parser.add_argument( 'file', type=argparse.FileType('r', encoding='UTF-8'), help='A recipemd file' ).completer = FilesCompleter(allowednames='*.md') display_parser = parser.add_mutually_exclusive_group() display_parser.add_argument('-t', '--title', action='store_true', help='Display recipe title') display_parser.add_argument('-i', '--ingredients', action='store_true', help='Display recipe ingredients') parser.add_argument( '-f', '--flatten', action='store_true', help='Flatten ingredients and instructions of linked recipes into main recipe' ) parser.add_argument( '-r', '--round', type=lambda s: None if s.lower() == 'no' else int(s), metavar='n', default=2, help='Round amount to n digits after decimal point. Default is "2", use "no" to disable rounding.' ).completer = ChoicesCompleter(('no', *range(0, decimal.getcontext().prec + 1))) scale_parser = parser.add_mutually_exclusive_group() scale_parser.add_argument('-m', '--multiply', type=str, help='Multiply recipe by N', metavar='N') scale_parser.add_argument( '-y', '--yield', type=str, help='Scale the recipe for yield Y, e.g. "5 servings"', metavar='Y', dest='required_yield' ).completer = _yield_completer # completions argcomplete.autocomplete(parser) # parse args args = parser.parse_args() # read and parse recipe src = args.file.read() rp = RecipeParser() r = rp.parse(src) # scale recipe r = _process_scaling(r, args) # flatten recipe if args.flatten: base_url = URL(f'file://{os.path.abspath(args.file.name)}') r = _get_flattened_ingredients_recipe(r, base_url=base_url, parser=rp) # create output depending on arguments if args.title: print(r.title) elif args.ingredients: for ingr in r.leaf_ingredients: print(_ingredient_to_string(ingr, rounding=args.round)) else: rs = RecipeSerializer() print(rs.serialize(r, rounding=args.round))
def get_filtered_recipes(args): rp = RecipeParser() result = [] for path in glob.glob(os.path.join(args.folder, '**/*.md'), recursive=True): try: with open(path, 'r', encoding='UTF-8') as file: recipe = rp.parse(file.read()) tags = recipe.tags if evaluate(args.filter, tags): result.append((recipe, os.path.relpath(path, args.folder))) except Exception as e: if not args.no_messages: print(f"An error occurred, skipping {os.path.relpath(path, args.folder)}: {e.args[0]}", file=sys.stderr) return result
def _get_linked_recipe(ingredient: Ingredient, *, base_url: URL, parser: RecipeParser, flatten: bool=True) -> Recipe: url = base_url.join(URL(ingredient.link)) try: with urllib.request.urlopen(str(url)) as req: encoding = req.info().get_content_charset() or 'UTF-8' src = req.read().decode(encoding) except Exception as e: raise RuntimeError(f'''Couldn't find linked recipe for ingredient "{ingredient.name}"''') from e try: link_recipe = parser.parse(src) except Exception as e: raise RuntimeError(f'''Couldn't parse linked recipe for ingredient "{ingredient.name}"''') from e if flatten: link_recipe = _get_flattened_ingredients_recipe(link_recipe, base_url=url, parser=parser) return link_recipe
def main(): parser = argparse.ArgumentParser( description='Read and process recipemd recipes') parser.add_argument('file', type=open, help='A recipemd file') display_parser = parser.add_mutually_exclusive_group() display_parser.add_argument('-t', '--title', action='store_true', help='Display recipe title') display_parser.add_argument('-i', '--ingredients', action='store_true', help='Display recipe ingredients') scale_parser = parser.add_mutually_exclusive_group() scale_parser.add_argument('-m', '--multiply', type=str, help='Multiply recipe by N', metavar='N') scale_parser.add_argument('-y', '--yield', type=str, help='Scale the recipe for yield Y', metavar='Y', dest='required_yield') args = parser.parse_args() src = args.file.read() rp = RecipeParser() r = rp.parse(src) if args.required_yield is not None: required_yield = RecipeParser.parse_amount(args.required_yield) if required_yield is None or required_yield.factor is None: print(f'Given yield is not valid', file=sys.stderr) exit(1) matching_recipe_yield = next( (y for y in r.yields if y.unit == required_yield.unit), None) if matching_recipe_yield is None: if required_yield.unit is None: matching_recipe_yield = Amount(Decimal(1)) else: print( f'Recipe "{r.title}" does not specify a yield in the unit "{required_yield.unit}". The ' f'following units can be used: ' + ", ".join(f'"{y.unit}"' for y in r.yields), file=sys.stderr) exit(1) r = multiply_recipe( r, required_yield.factor / matching_recipe_yield.factor) elif args.multiply is not None: multiply = RecipeParser.parse_amount(args.multiply) if multiply is None or multiply.factor is None: print(f'Given multiplier is not valid', file=sys.stderr) exit(1) if multiply.unit is not None: print(f'A recipe can only be multiplied with a unitless amount', file=sys.stderr) exit(1) r = multiply_recipe(r, multiply.factor) if args.title: print(r.title) elif args.ingredients: for ingr in r.leaf_ingredients: print(_ingredient_to_string(ingr)) else: rs = RecipeSerializer() print(rs.serialize(r))
from recipemd.data import RecipeParser from unidecode import unidecode root_path = '.' rp = RecipeParser() tt = str.maketrans({ "ä": "ae", "ö": "oe", "ü": "ue", "Ä": "Ae", "Ö": "Oe", "Ü": "Ue", "ß": "ss", }) for path in glob.glob(os.path.join(root_path, '**/*.md'), recursive=True): try: with open(path, 'r', encoding='UTF-8') as file: recipe = rp.parse(file.read()) filename = recipe.title filename = filename.translate(tt) filename = unidecode(filename) filename = re.sub(r'[^a-zA-Z0-9]+', '_', filename) filename = re.sub(r'^_+|_+$', '', filename) new_path = os.path.join(os.path.dirname(path), f'{filename}.md') os.rename(path, new_path) except Exception as e: print(f'[Filenames] Ignoring {path}', file=sys.stderr) pprint(e, stream=sys.stderr)