import logging import os from typing import Generator from flask import current_app from .exceptions import NotFoundException from .instructions import BrickInstructions logger = logging.getLogger(__name__) # Lego sets instruction list class BrickInstructionsList(object): all: dict[str, BrickInstructions] rejected_total: int sets: dict[str, list[BrickInstructions]] sets_total: int unknown_total: int def __init__(self, /, force=False): # Load instructions only if there is none already loaded all = getattr(self, 'all', None) if all is None or force: logger.info('Loading instructions file list') BrickInstructionsList.all = {} BrickInstructionsList.rejected_total = 0 BrickInstructionsList.sets = {} BrickInstructionsList.sets_total = 0 BrickInstructionsList.unknown_total = 0 # Try to list the files in the instruction folder try: # Make a folder relative to static folder: str = os.path.join( current_app.static_folder, # type: ignore current_app.config['INSTRUCTIONS_FOLDER'].value, ) for file in os.scandir(folder): instruction = BrickInstructions(file) # Unconditionnally add to the list BrickInstructionsList.all[instruction.filename] = instruction # noqa: E501 if instruction.allowed: if instruction.number: # Instantiate the list if not existing yet if instruction.number not in BrickInstructionsList.sets: # noqa: E501 BrickInstructionsList.sets[instruction.number] = [] # noqa: E501 BrickInstructionsList.sets[instruction.number].append(instruction) # noqa: E501 BrickInstructionsList.sets_total += 1 else: BrickInstructionsList.unknown_total += 1 else: BrickInstructionsList.rejected_total += 1 # Associate bricksets # Not ideal, to avoid a circular import from .set import BrickSet from .set_list import BrickSetList # Grab the generic list of sets bricksets: dict[str, BrickSet] = {} for brickset in BrickSetList().generic().records: bricksets[brickset.fields.set_num] = brickset # Return the files for instruction in self.all.values(): # Inject the brickset if it exists if ( instruction.allowed and instruction.number is not None and instruction.brickset is None and instruction.number in bricksets ): instruction.brickset = bricksets[instruction.number] # Ignore errors except Exception: pass # Grab instructions for a set def get(self, number: str) -> list[BrickInstructions]: if number in self.sets: return self.sets[number] else: return [] # Grab instructions for a file def get_file(self, name: str) -> BrickInstructions: if name not in self.all: raise NotFoundException('Instruction file {name} does not exist'.format( # noqa: E501 name=name )) return self.all[name] # List of all instruction files def list(self, /) -> Generator[BrickInstructions, None, None]: # Get the filenames and sort them filenames = list(self.all.keys()) filenames.sort() # Return the files for filename in filenames: yield self.all[filename]