From 5ec6b3f125585715e6f651fee1fe53eddbc30b88 Mon Sep 17 00:00:00 2001 From: Jordan Munch O'Hare Date: Sun, 4 Oct 2020 11:55:03 +0200 Subject: [PATCH] Ug feeback changes (#13) * Task Matching * Builder files -> Recipe; Deck Part Name -> Part Id * Release V0.2.4 --- MANIFEST.in | 1 + Pipfile | 2 +- Pipfile.lock | 23 ++++++++++--------- brain_brew/argument_reader.py | 12 +++++----- .../crowd_anki/crowd_anki_generate.py | 3 +-- .../crowd_anki/crowd_anki_to_deck_parts.py | 3 +-- .../crowd_anki/headers_from_crowdanki.py | 4 ++-- .../crowd_anki/note_models_from_crowd_anki.py | 6 ++--- .../crowd_anki/notes_from_crowd_anki.py | 4 ++-- brain_brew/build_tasks/csvs/csvs_generate.py | 6 ++--- .../build_tasks/csvs/csvs_to_deck_parts.py | 3 +-- .../build_tasks/csvs/notes_from_csvs.py | 8 +++---- .../build_tasks/csvs/shared_base_csvs.py | 2 +- .../build_tasks/deck_parts/from_deck_part.py | 11 ++++----- brain_brew/file_manager.py | 6 ++--- brain_brew/main.py | 8 +++---- .../build_config/generate_deck_parts.py | 13 +++++------ .../{task_builder.py => recipe_builder.py} | 2 +- ...builder.py => top_level_recipe_builder.py} | 19 ++++++++------- .../configuration/note_model_mapping.py | 6 ++--- .../transformers/base_deck_part_from.py | 8 +++---- .../representation/yaml/deck_part_holder.py | 14 +++++------ .../schemas/{builder.yaml => recipe.yaml} | 22 +++++++++--------- brain_brew/utils.py | 6 ----- brain_brew/yaml_verifier.py | 10 ++++---- build.bash | 3 ++- setup.py | 2 +- tests/test_argument_reader.py | 20 ++++++++-------- tests/test_builder.py | 2 +- 29 files changed, 110 insertions(+), 119 deletions(-) create mode 100644 MANIFEST.in rename brain_brew/representation/build_config/{task_builder.py => recipe_builder.py} (98%) rename brain_brew/representation/build_config/{top_level_task_builder.py => top_level_recipe_builder.py} (54%) rename brain_brew/schemas/{builder.yaml => recipe.yaml} (77%) diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..4d17a07 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include brain_brew/schemas/recipe.yaml diff --git a/Pipfile b/Pipfile index a0b7c10..5cf6d86 100644 --- a/Pipfile +++ b/Pipfile @@ -10,7 +10,7 @@ pytest = "==5.4.1" args = "==0.1.0" clint = "==0.5.1" coverage = "==4.5.4" -ruamel-yaml = "==0.16.10" +"ruamel.yaml" = "==0.16.10" yamale = "==3.0.4" PyYaml = "*" diff --git a/Pipfile.lock b/Pipfile.lock index cf77f63..94b781b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9c9d18c53efca3d811a364f0b5207179a9cf9eb8fb47db85c9b8a53fa5b26bda" + "sha256": "db655f3c486cd1cca9fa3933db29f726157cea5c53e046b11bda830178fb4325" }, "pipfile-spec": 6, "requires": { @@ -82,9 +82,10 @@ "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c", "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a" ], + "index": "Brain Brew", "version": "==5.3.1" }, - "ruamel-yaml": { + "ruamel.yaml": { "hashes": [ "sha256:0962fd7999e064c4865f96fb1e23079075f4a2a14849bcdc5cdba53a24f9759b", "sha256:099c644a778bf72ffa00524f78dd0b6476bca94a1da344130f4bf3381ce5b954" @@ -131,19 +132,19 @@ "develop": { "attrs": { "hashes": [ - "sha256:0ef97238856430dcf9228e07f316aefc17e8939fc8507e18c6501b761ef1a42a", - "sha256:2867b7b9f8326499ab5b0e2d12801fa5c98842d2cbd22b35112ae04bf85b4dff" + "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594", + "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==20.1.0" + "version": "==20.2.0" }, "importlib-metadata": { "hashes": [ - "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83", - "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070" + "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da", + "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3" ], "markers": "python_version < '3.8'", - "version": "==1.7.0" + "version": "==2.0.0" }, "more-itertools": { "hashes": [ @@ -210,11 +211,11 @@ }, "zipp": { "hashes": [ - "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b", - "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96" + "sha256:64ad89efee774d1897a58607895d80789c59778ea02185dd846ac38394a8642b", + "sha256:eed8ec0b8d1416b2ca33516a37a08892442f3954dee131e92cfd92d8fe3e7066" ], "markers": "python_version >= '3.6'", - "version": "==3.1.0" + "version": "==3.3.0" } } } diff --git a/brain_brew/argument_reader.py b/brain_brew/argument_reader.py index 041dcb6..d30841b 100644 --- a/brain_brew/argument_reader.py +++ b/brain_brew/argument_reader.py @@ -12,10 +12,10 @@ def __init__(self): def _set_parser_arguments(self): self.add_argument( - "builder_file", - metavar="builder file", + "recipe", + metavar="recipe", type=str, - help="Run a builder file" + help="Yaml file to use as the recipe" ) self.add_argument( "--config", "--global-config", "-c", @@ -30,20 +30,20 @@ def _set_parser_arguments(self): action="store_true", dest="verify_only", default=False, - help="Only verify the builder contents, without running it." + help="Only verify the recipe contents, without running it." ) def get_parsed(self, override_args=None): parsed_args = self.parse_args(args=override_args) # Required - builder = self.error_if_blank(parsed_args.builder_file) + recipe = self.error_if_blank(parsed_args.recipe) # Optional config_file = parsed_args.config_file verify_only = parsed_args.verify_only - return builder, config_file, verify_only + return recipe, config_file, verify_only def error_if_blank(self, arg): if arg == "" or arg is None: diff --git a/brain_brew/build_tasks/crowd_anki/crowd_anki_generate.py b/brain_brew/build_tasks/crowd_anki/crowd_anki_generate.py index a576d88..c305291 100644 --- a/brain_brew/build_tasks/crowd_anki/crowd_anki_generate.py +++ b/brain_brew/build_tasks/crowd_anki/crowd_anki_generate.py @@ -15,12 +15,11 @@ from brain_brew.representation.build_config.build_task import TopLevelBuildTask from brain_brew.representation.build_config.representation_base import RepresentationBase -from brain_brew.utils import all_combos_prepend_append @dataclass class CrowdAnkiGenerate(TopLevelBuildTask): - task_regex = r'.*crowd[\s_-]*?anki.*' + task_regex = r'generate_crowd_anki' @dataclass class Representation(RepresentationBase): diff --git a/brain_brew/build_tasks/crowd_anki/crowd_anki_to_deck_parts.py b/brain_brew/build_tasks/crowd_anki/crowd_anki_to_deck_parts.py index e57cb0c..b4f0aa6 100644 --- a/brain_brew/build_tasks/crowd_anki/crowd_anki_to_deck_parts.py +++ b/brain_brew/build_tasks/crowd_anki/crowd_anki_to_deck_parts.py @@ -10,12 +10,11 @@ from brain_brew.representation.build_config.representation_base import RepresentationBase from brain_brew.representation.json.crowd_anki_export import CrowdAnkiExport from brain_brew.representation.yaml.note_model_repr import NoteModel -from brain_brew.utils import all_combos_prepend_append @dataclass class CrowdAnkiToDeckParts(DeckPartBuildTask): - task_regex = r'.*crowd[\s_-]*?anki.*' + task_regex = r'from_crowd_anki' @dataclass class Representation(RepresentationBase): diff --git a/brain_brew/build_tasks/crowd_anki/headers_from_crowdanki.py b/brain_brew/build_tasks/crowd_anki/headers_from_crowdanki.py index ffc2a47..841768d 100644 --- a/brain_brew/build_tasks/crowd_anki/headers_from_crowdanki.py +++ b/brain_brew/build_tasks/crowd_anki/headers_from_crowdanki.py @@ -26,14 +26,14 @@ class Representation(BaseDeckPartsFrom.Representation): def from_repr(cls, data: Union[Representation, dict]): rep: cls.Representation = data if isinstance(data, cls.Representation) else cls.Representation.from_dict(data) return cls( - name=rep.name, + part_id=rep.part_id, save_to_file=rep.save_to_file ) def execute(self, ca_wrapper: CrowdAnkiJsonWrapper): headers = Headers(self.crowd_anki_to_headers(ca_wrapper.data)) - DeckPartHolder.override_or_create(self.name, self.save_to_file, headers) + DeckPartHolder.override_or_create(self.part_id, self.save_to_file, headers) return headers diff --git a/brain_brew/build_tasks/crowd_anki/note_models_from_crowd_anki.py b/brain_brew/build_tasks/crowd_anki/note_models_from_crowd_anki.py index e6dbdbd..527d57f 100644 --- a/brain_brew/build_tasks/crowd_anki/note_models_from_crowd_anki.py +++ b/brain_brew/build_tasks/crowd_anki/note_models_from_crowd_anki.py @@ -22,8 +22,8 @@ class Representation(BaseDeckPartsFrom.Representation): def from_repr(cls, data: Union[Representation, dict]): rep: cls.Representation = data if isinstance(data, cls.Representation) else cls.Representation.from_dict(data) return cls( - name=rep.name, - model_name=rep.model_name or rep.name, + part_id=rep.part_id, + model_name=rep.model_name or rep.part_id, save_to_file=rep.save_to_file ) @@ -51,7 +51,7 @@ def execute(self, ca_wrapper: CrowdAnkiJsonWrapper) -> List[NoteModel]: extra_models.remove(nm_item.model_name) deck_part = NoteModel.from_crowdanki(model) - DeckPartHolder.override_or_create(nm_item.name, nm_item.save_to_file, deck_part) + DeckPartHolder.override_or_create(nm_item.part_id, nm_item.save_to_file, deck_part) dp_note_models.append(deck_part) diff --git a/brain_brew/build_tasks/crowd_anki/notes_from_crowd_anki.py b/brain_brew/build_tasks/crowd_anki/notes_from_crowd_anki.py index 922fecf..f2c7009 100644 --- a/brain_brew/build_tasks/crowd_anki/notes_from_crowd_anki.py +++ b/brain_brew/build_tasks/crowd_anki/notes_from_crowd_anki.py @@ -19,7 +19,7 @@ class Representation(BaseDeckPartsFrom.Representation): def from_repr(cls, data: Union[Representation, dict]): rep: cls.Representation = data if isinstance(data, cls.Representation) else cls.Representation.from_dict(data) return cls( - name=rep.name, + part_id=rep.part_id, sort_order=SharedBaseNotes._get_sort_order(rep.sort_order), reverse_sort=SharedBaseNotes._get_reverse_sort(rep.reverse_sort), save_to_file=rep.save_to_file @@ -33,7 +33,7 @@ def execute(self, ca_wrapper: CrowdAnkiJsonWrapper, nm_id_to_name: dict) -> Note notes = Notes.from_list_of_notes(note_list) # TODO: pass in sort method - DeckPartHolder.override_or_create(self.name, self.save_to_file, notes) + DeckPartHolder.override_or_create(self.part_id, self.save_to_file, notes) return notes diff --git a/brain_brew/build_tasks/csvs/csvs_generate.py b/brain_brew/build_tasks/csvs/csvs_generate.py index 5a2990c..6309aad 100644 --- a/brain_brew/build_tasks/csvs/csvs_generate.py +++ b/brain_brew/build_tasks/csvs/csvs_generate.py @@ -6,12 +6,12 @@ from brain_brew.representation.configuration.note_model_mapping import NoteModelMapping from brain_brew.representation.yaml.deck_part_holder import DeckPartHolder from brain_brew.representation.yaml.note_repr import Notes, Note -from brain_brew.utils import all_combos_prepend_append, join_tags +from brain_brew.utils import join_tags @dataclass class CsvsGenerate(SharedBaseCsvs, TopLevelBuildTask): - task_regex = r'.*csv.*' + task_regex = r'generate_csvs' notes_to_read: str notes: DeckPartHolder[Notes] = field(default=None) @@ -52,7 +52,7 @@ def execute(self): def verify_notes_match_note_model_mappings(self, notes: List[Note]): note_models_used = {note.note_model for note in notes} - errors = [TypeError(f"Unknown note model type '{model}' in deck part '{self.notes.name}'. " + errors = [TypeError(f"Unknown note model type '{model}' in deck part '{self.notes.part_id}'. " f"Add mapping for that model.") for model in note_models_used if model not in self.note_model_mappings.keys()] diff --git a/brain_brew/build_tasks/csvs/csvs_to_deck_parts.py b/brain_brew/build_tasks/csvs/csvs_to_deck_parts.py index f174b83..2658dbb 100644 --- a/brain_brew/build_tasks/csvs/csvs_to_deck_parts.py +++ b/brain_brew/build_tasks/csvs/csvs_to_deck_parts.py @@ -4,12 +4,11 @@ from brain_brew.build_tasks.csvs.notes_from_csvs import NotesFromCsvs from brain_brew.representation.build_config.build_task import DeckPartBuildTask from brain_brew.representation.build_config.representation_base import RepresentationBase -from brain_brew.utils import all_combos_prepend_append @dataclass class CsvsToDeckParts(DeckPartBuildTask): - task_regex = r'.*csv.*' + task_regex = r'from_csvs' @dataclass class Representation(RepresentationBase): diff --git a/brain_brew/build_tasks/csvs/notes_from_csvs.py b/brain_brew/build_tasks/csvs/notes_from_csvs.py index 3049049..04bd08a 100644 --- a/brain_brew/build_tasks/csvs/notes_from_csvs.py +++ b/brain_brew/build_tasks/csvs/notes_from_csvs.py @@ -13,15 +13,15 @@ class NotesFromCsvs(SharedBaseCsvs, BaseDeckPartsFrom): @dataclass(init=False) class Representation(SharedBaseCsvs.Representation, BaseDeckPartsFrom.Representation): - def __init__(self, name, file_mappings, note_model_mappings, save_to_file=None): + def __init__(self, part_id, file_mappings, note_model_mappings, save_to_file=None): SharedBaseCsvs.Representation.__init__(self, file_mappings, note_model_mappings) - BaseDeckPartsFrom.Representation.__init__(self, name, save_to_file) + BaseDeckPartsFrom.Representation.__init__(self, part_id, save_to_file) @classmethod def from_repr(cls, data: Union[Representation, dict]): rep: cls.Representation = data if isinstance(data, cls.Representation) else cls.Representation.from_dict(data) return cls( - name=rep.name, + part_id=rep.part_id, save_to_file=rep.save_to_file, file_mappings=rep.get_file_mappings(), note_model_mappings_to_read=rep.note_model_mappings @@ -40,7 +40,7 @@ def execute(self): deck_part_notes: List[Note] = [self.csv_row_to_note(row, self.note_model_mappings) for row in csv_rows] notes = Notes.from_list_of_notes(deck_part_notes) - DeckPartHolder.override_or_create(self.name, self.save_to_file, notes) + DeckPartHolder.override_or_create(self.part_id, self.save_to_file, notes) @staticmethod def csv_row_to_note(row: dict, note_model_mappings: Dict[str, NoteModelMapping]) -> Note: diff --git a/brain_brew/build_tasks/csvs/shared_base_csvs.py b/brain_brew/build_tasks/csvs/shared_base_csvs.py index 574e928..a81fb83 100644 --- a/brain_brew/build_tasks/csvs/shared_base_csvs.py +++ b/brain_brew/build_tasks/csvs/shared_base_csvs.py @@ -66,7 +66,7 @@ def verify_contents(self): missing_columns = [col for col in holder.deck_part.field_names_lowercase if col not in nm_map.csv_headers_map_to_note_fields(available_columns)] if missing_columns: - logging.warning(f"Csvs are missing columns from {holder.name} {missing_columns}") + logging.warning(f"Csvs are missing columns from {holder.part_id} {missing_columns}") if errors: raise Exception(errors) diff --git a/brain_brew/build_tasks/deck_parts/from_deck_part.py b/brain_brew/build_tasks/deck_parts/from_deck_part.py index 35bccc6..75be591 100644 --- a/brain_brew/build_tasks/deck_parts/from_deck_part.py +++ b/brain_brew/build_tasks/deck_parts/from_deck_part.py @@ -7,16 +7,15 @@ from brain_brew.representation.yaml.headers_repr import Headers from brain_brew.representation.yaml.note_model_repr import NoteModel from brain_brew.representation.yaml.note_repr import Notes -from brain_brew.utils import all_combos_prepend_append @dataclass class FromDeckParts(DeckPartBuildTask): - task_regex = r'.*deck[\s_-]*?part.*' + task_regex = r'from_deck_parts' @dataclass class DeckPartToRead(RepresentationBase): - name: str + part_id: str file: str @dataclass @@ -39,11 +38,11 @@ def from_repr(cls, data: Union[Representation, dict]): return cls( notes=[DeckPartHolder.override_or_create( - name=note.name, save_to_file=None, deck_part=Notes.from_file(note.file)) for note in notes], + part_id=note.part_id, save_to_file=None, deck_part=Notes.from_file(note.file)) for note in notes], note_models=[DeckPartHolder.override_or_create( - name=model.name, save_to_file=None, deck_part=NoteModel.from_file(model.file)) for model in note_models], + part_id=model.part_id, save_to_file=None, deck_part=NoteModel.from_file(model.file)) for model in note_models], headers=[DeckPartHolder.override_or_create( - name=header.name, save_to_file=None, deck_part=Headers.from_file(header.file)) for header in headers] + part_id=header.part_id, save_to_file=None, deck_part=Headers.from_file(header.file)) for header in headers] ) def execute(self): diff --git a/brain_brew/file_manager.py b/brain_brew/file_manager.py index ceee543..b56cf56 100644 --- a/brain_brew/file_manager.py +++ b/brain_brew/file_manager.py @@ -75,9 +75,9 @@ def _register_media_file(self, file: MediaFile): f" and '{self.known_media_files_dict[file.filename].source_loc}'") def new_deck_part(self, dp: DeckPartHolder) -> DeckPartHolder: - if dp.name in self.deck_part_pool: - raise KeyError(f"Cannot use same name '{dp.name}' for multiple Deck Parts") - self.deck_part_pool.setdefault(dp.name, dp) + if dp.part_id in self.deck_part_pool: + raise KeyError(f"Cannot use same name '{dp.part_id}' for multiple Deck Parts") + self.deck_part_pool.setdefault(dp.part_id, dp) return dp # Gets diff --git a/brain_brew/main.py b/brain_brew/main.py index 1bd7eab..e2d51db 100644 --- a/brain_brew/main.py +++ b/brain_brew/main.py @@ -1,7 +1,7 @@ import logging from brain_brew.argument_reader import BBArgumentReader -from brain_brew.representation.build_config.top_level_task_builder import TopLevelTaskBuilder +from brain_brew.representation.build_config.top_level_recipe_builder import TopLevelRecipeBuilder from brain_brew.file_manager import FileManager from brain_brew.representation.configuration.global_config import GlobalConfig @@ -15,7 +15,7 @@ def main(): # Read in Arguments argument_reader = BBArgumentReader() - builder_file_name, global_config_file, verify_only = argument_reader.get_parsed() + recipe_file_name, global_config_file, verify_only = argument_reader.get_parsed() # Read in Global Config File global_config = GlobalConfig.from_file(global_config_file) if global_config_file else GlobalConfig.from_file() @@ -23,11 +23,11 @@ def main(): # Parse Build Config File YamlVerifier() - builder = TopLevelTaskBuilder.parse_and_read(builder_file_name) + recipe = TopLevelRecipeBuilder.parse_and_read(recipe_file_name) # If all good, execute it if not verify_only: - builder.execute() + recipe.execute() if __name__ == "__main__": diff --git a/brain_brew/representation/build_config/generate_deck_parts.py b/brain_brew/representation/build_config/generate_deck_parts.py index 52d2320..d10d728 100644 --- a/brain_brew/representation/build_config/generate_deck_parts.py +++ b/brain_brew/representation/build_config/generate_deck_parts.py @@ -2,18 +2,17 @@ from typing import Dict, Type, List from brain_brew.representation.build_config.build_task import BuildTask, TopLevelBuildTask, DeckPartBuildTask -from brain_brew.representation.build_config.task_builder import TaskBuilder +from brain_brew.representation.build_config.recipe_builder import RecipeBuilder # Build Tasks -from brain_brew.build_tasks.deck_parts.from_deck_part import FromDeckParts -from brain_brew.build_tasks.csvs.csvs_to_deck_parts import CsvsToDeckParts -from brain_brew.build_tasks.crowd_anki.crowd_anki_to_deck_parts import CrowdAnkiToDeckParts -from brain_brew.utils import str_to_lowercase_no_separators +from brain_brew.build_tasks.deck_parts.from_deck_part import FromDeckParts # noqa +from brain_brew.build_tasks.csvs.csvs_to_deck_parts import CsvsToDeckParts # noqa +from brain_brew.build_tasks.crowd_anki.crowd_anki_to_deck_parts import CrowdAnkiToDeckParts # noqa @dataclass -class GenerateDeckParts(TaskBuilder, TopLevelBuildTask): - task_regex = r'.*deck[\s_-]*?part.*' +class BuildDeckParts(RecipeBuilder, TopLevelBuildTask): + task_regex = r'build_deck_parts' @classmethod def known_task_dict(cls) -> Dict[str, Type[BuildTask]]: diff --git a/brain_brew/representation/build_config/task_builder.py b/brain_brew/representation/build_config/recipe_builder.py similarity index 98% rename from brain_brew/representation/build_config/task_builder.py rename to brain_brew/representation/build_config/recipe_builder.py index 553796b..bbe712c 100644 --- a/brain_brew/representation/build_config/task_builder.py +++ b/brain_brew/representation/build_config/recipe_builder.py @@ -9,7 +9,7 @@ @dataclass -class TaskBuilder(YamlRepr): +class RecipeBuilder(YamlRepr): tasks: List[BuildTask] @classmethod diff --git a/brain_brew/representation/build_config/top_level_task_builder.py b/brain_brew/representation/build_config/top_level_recipe_builder.py similarity index 54% rename from brain_brew/representation/build_config/top_level_task_builder.py rename to brain_brew/representation/build_config/top_level_recipe_builder.py index b4aaa1d..7a55f15 100644 --- a/brain_brew/representation/build_config/top_level_task_builder.py +++ b/brain_brew/representation/build_config/top_level_recipe_builder.py @@ -2,26 +2,25 @@ from typing import Dict, Type from brain_brew.representation.build_config.build_task import BuildTask, TopLevelBuildTask -from brain_brew.representation.build_config.task_builder import TaskBuilder +from brain_brew.representation.build_config.recipe_builder import RecipeBuilder # Build Tasks -from brain_brew.build_tasks.csvs.csvs_generate import CsvsGenerate -from brain_brew.build_tasks.crowd_anki.crowd_anki_generate import CrowdAnkiGenerate -from brain_brew.representation.build_config.generate_deck_parts import GenerateDeckParts -from brain_brew.utils import str_to_lowercase_no_separators +from brain_brew.build_tasks.csvs.csvs_generate import CsvsGenerate # noqa +from brain_brew.build_tasks.crowd_anki.crowd_anki_generate import CrowdAnkiGenerate # noqa +from brain_brew.representation.build_config.generate_deck_parts import BuildDeckParts # noqa -class TopLevelTaskBuilder(TaskBuilder): +class TopLevelRecipeBuilder(RecipeBuilder): @classmethod def known_task_dict(cls) -> Dict[str, Type[BuildTask]]: values = TopLevelBuildTask.get_all_task_regex() return values @classmethod - def parse_and_read(cls, filename) -> 'TopLevelTaskBuilder': - builder_data = TopLevelTaskBuilder.read_to_dict(filename) + def parse_and_read(cls, filename) -> 'TopLevelRecipeBuilder': + recipe_data = TopLevelRecipeBuilder.read_to_dict(filename) from brain_brew.yaml_verifier import YamlVerifier - YamlVerifier.get_instance().verify_builder(filename) + YamlVerifier.get_instance().verify_recipe(filename) - return TopLevelTaskBuilder.from_list(builder_data) + return TopLevelRecipeBuilder.from_list(recipe_data) diff --git a/brain_brew/representation/configuration/note_model_mapping.py b/brain_brew/representation/configuration/note_model_mapping.py index 8cf94d2..2bdaeb2 100644 --- a/brain_brew/representation/configuration/note_model_mapping.py +++ b/brain_brew/representation/configuration/note_model_mapping.py @@ -61,7 +61,7 @@ def from_repr(cls, data: Representation): field_type=FieldMapping.FieldMappingType.PERSONAL_FIELD, field_name=field, value="") for field in data.personal_fields], - note_models=dict(map(lambda nm: (nm.name, nm), note_models)) + note_models=dict(map(lambda nm: (nm.part_id, nm), note_models)) ) def get_note_model_mapping_dict(self): @@ -83,7 +83,7 @@ def verify_contents(self): missing.append(req) if missing: - errors.append(KeyError(f"""Note model(s) "{holder.name}" to Csv config error: \ + errors.append(KeyError(f"""Note model(s) "{holder.part_id}" to Csv config error: \ Definitions for fields {missing} are required.""")) # Check Fields Align with Note Type @@ -95,7 +95,7 @@ def verify_contents(self): if missing: errors.append( - KeyError(f"Note model '{holder.name}' to Csv config error. " + KeyError(f"Note model '{holder.part_id}' to Csv config error. " f"It expected {[field.name for field in model.fields]} but was missing: {missing}") ) diff --git a/brain_brew/representation/transformers/base_deck_part_from.py b/brain_brew/representation/transformers/base_deck_part_from.py index 281ee9a..f25be2b 100644 --- a/brain_brew/representation/transformers/base_deck_part_from.py +++ b/brain_brew/representation/transformers/base_deck_part_from.py @@ -8,12 +8,12 @@ class BaseDeckPartsFrom: @dataclass class Representation(RepresentationBase): - name: str + part_id: str save_to_file: Optional[str] - def __init__(self, name, save_to_file=None): - self.name = name + def __init__(self, part_id, save_to_file=None): + self.part_id = part_id self.save_to_file = save_to_file - name: str + part_id: str save_to_file: Optional[str] diff --git a/brain_brew/representation/yaml/deck_part_holder.py b/brain_brew/representation/yaml/deck_part_holder.py index 9e9d05d..e30fe82 100644 --- a/brain_brew/representation/yaml/deck_part_holder.py +++ b/brain_brew/representation/yaml/deck_part_holder.py @@ -6,7 +6,7 @@ @dataclass class DeckPartHolder(Generic[T]): - name: str + part_id: str save_to_file: Optional[str] deck_part: T @@ -20,19 +20,19 @@ def get_file_manager(cls): return cls.file_manager @classmethod - def from_deck_part_pool(cls, name: str) -> T: - return cls.get_file_manager().deck_part_from_pool(name) + def from_deck_part_pool(cls, part_id: str) -> T: + return cls.get_file_manager().deck_part_from_pool(part_id) @classmethod - def override_or_create(cls, name: str, save_to_file: Optional[str], deck_part: T): + def override_or_create(cls, part_id: str, save_to_file: Optional[str], deck_part: T): fm = cls.get_file_manager() - dp = fm.deck_part_if_exists(name) + dp = fm.deck_part_if_exists(part_id) if dp is None: - dp = fm.new_deck_part(DeckPartHolder(name, save_to_file, deck_part)) + dp = fm.new_deck_part(DeckPartHolder(part_id, save_to_file, deck_part)) else: dp.deck_part = deck_part - dp.save_to_file = save_to_file # ? + dp.save_to_file = save_to_file dp.write_to_file() diff --git a/brain_brew/schemas/builder.yaml b/brain_brew/schemas/recipe.yaml similarity index 77% rename from brain_brew/schemas/builder.yaml rename to brain_brew/schemas/recipe.yaml index 04395fe..b99789f 100644 --- a/brain_brew/schemas/builder.yaml +++ b/brain_brew/schemas/recipe.yaml @@ -1,16 +1,16 @@ list( - map(include('generate_deck_parts'), key=regex('.*deck[\s_-]*?part.*', ignore_case=True)), - map(include('generate_csv'), key=regex('.*csv.*', ignore_case=True)), - map(include('generate_crowd_anki'), key=regex('.*crowd[\s_-]*?anki.*', ignore_case=True)) + map(include('generate_deck_parts'), key=regex('build_deck_parts', ignore_case=True)), + map(include('generate_csv'), key=regex('generate_csvs', ignore_case=True)), + map(include('generate_crowd_anki'), key=regex('generate_crowd_anki', ignore_case=True)) ) --- generate_deck_parts: list( - map(include('from_deck_parts'), key=regex('.*deck[\s_-]*?part.*', ignore_case=True)), - map(include('from_csv'), key=regex('.*csv.*', ignore_case=True)), - map(include('from_crowd_anki'), key=regex('.*crowd[\s_-]*?anki.*', ignore_case=True)) + map(include('from_deck_parts'), key=regex('from_deck_parts', ignore_case=True)), + map(include('from_csv'), key=regex('from_csvs', ignore_case=True)), + map(include('from_crowd_anki'), key=regex('from_crowd_anki', ignore_case=True)) ) @@ -33,17 +33,17 @@ generate_crowd_anki: from_ca_notes: - name: str() + part_id: str() sort_order: list(str(), required=False) save_to_file: str(required=False) from_ca_note_models: - name: str() + part_id: str() model_name: str(required=False) save_to_file: str(required=False) from_ca_headers: - name: str() + part_id: str() save_to_file: str(required=False) ca_media: @@ -71,14 +71,14 @@ from_deck_parts: headers: list(include('deck_part_to_read'), required=False) deck_part_to_read: - name: str() + part_id: str() file: str() from_csv: notes: - name: str() + part_id: str() save_to_file: str(required=False) note_model_mappings: list(include('note_model_mapping')) file_mappings: list(include('file_mapping')) diff --git a/brain_brew/utils.py b/brain_brew/utils.py index 5ef1660..687149c 100644 --- a/brain_brew/utils.py +++ b/brain_brew/utils.py @@ -23,12 +23,6 @@ def single_item_to_list(item): return [item] -def all_combos_prepend_append(original_list: list, prepend_with: str, append_with: str): - return list({append_or_not for normal in original_list - for prepend_or_not in (normal, prepend_with + normal) - for append_or_not in (prepend_or_not, prepend_or_not + append_with)}) - - def str_to_lowercase_no_separators(str_to_tidy: str): return re.sub(r'[\s+_-]+', '', str_to_tidy.lower()) diff --git a/brain_brew/yaml_verifier.py b/brain_brew/yaml_verifier.py index 6c9603d..d64e3f5 100644 --- a/brain_brew/yaml_verifier.py +++ b/brain_brew/yaml_verifier.py @@ -12,7 +12,7 @@ class YamlVerifier: __instance = None - builder_schema: Schema + recipe_schema: Schema def __init__(self): if YamlVerifier.__instance is None: @@ -20,17 +20,17 @@ def __init__(self): else: raise Exception("Multiple YamlVerifiers created") - path = os.path.join(os.path.dirname(__file__), "schemas/builder.yaml") - self.builder_schema = yamale.make_schema(path, parser='ruamel', validators=validators) + path = os.path.join(os.path.dirname(__file__), "schemas/recipe.yaml") + self.recipe_schema = yamale.make_schema(path, parser='ruamel', validators=validators) @staticmethod def get_instance() -> 'YamlVerifier': return YamlVerifier.__instance - def verify_builder(self, filename): + def verify_recipe(self, filename): data = yamale.make_data(filename) try: - yamale.validate(self.builder_schema, data) + yamale.validate(self.recipe_schema, data) except YamaleError as e: print('Validation failed!\n') for result in e.results: diff --git a/build.bash b/build.bash index 2928a7b..1213b46 100644 --- a/build.bash +++ b/build.bash @@ -1,3 +1,4 @@ # Build -rm -v dist/* +rm -r dist +rm -r build python3 setup.py sdist bdist_wheel \ No newline at end of file diff --git a/setup.py b/setup.py index 3c51b33..17738d7 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="Brain-Brew", - version="0.2.2", + version="0.2.4", author="Jordan Munch O'Hare", author_email="brainbrew@jordan.munchohare.com", description="Automated Anki flashcard creation and extraction to/from Csv ", diff --git a/tests/test_argument_reader.py b/tests/test_argument_reader.py index 86e6d63..94c12a9 100644 --- a/tests/test_argument_reader.py +++ b/tests/test_argument_reader.py @@ -18,8 +18,8 @@ def test_constructor(arg_reader_test1): class TestArguments: @pytest.mark.parametrize("arguments", [ - (["test_builder.yaml", "--config"]), - (["test_builder.yaml", "config_file.yaml", "--config"]), + (["test_recipe.yaml", "--config"]), + (["test_recipe.yaml", "config_file.yaml", "--config"]), (["--config", "config_file.yaml"]), ([""]), ([]) @@ -32,16 +32,16 @@ def raise_exit(message): with patch.object(BBArgumentReader, "error", side_effect=raise_exit): parsed_args = arg_reader_test1.get_parsed(arguments) - @pytest.mark.parametrize("arguments, builder_file, config_file, verify_only", [ - (["test_builder.yaml"], "test_builder.yaml", None, False), - (["test_builder.yaml", "--verify"], "test_builder.yaml", None, True), - (["test_builder.yaml", "-v"], "test_builder.yaml", None, True), - (["test_builder.yaml", "--config", "other_config.yaml"], "test_builder.yaml", "other_config.yaml", False), - (["test_builder.yaml", "--config", "other_config.yaml", "-v"], "test_builder.yaml", "other_config.yaml", True), + @pytest.mark.parametrize("arguments, recipe, config_file, verify_only", [ + (["test_recipe.yaml"], "test_recipe.yaml", None, False), + (["test_recipe.yaml", "--verify"], "test_recipe.yaml", None, True), + (["test_recipe.yaml", "-v"], "test_recipe.yaml", None, True), + (["test_recipe.yaml", "--config", "other_config.yaml"], "test_recipe.yaml", "other_config.yaml", False), + (["test_recipe.yaml", "--config", "other_config.yaml", "-v"], "test_recipe.yaml", "other_config.yaml", True), ]) - def test_correct_arguments(self, arg_reader_test1, arguments, builder_file, config_file, verify_only): + def test_correct_arguments(self, arg_reader_test1, arguments, recipe, config_file, verify_only): parsed_args = arg_reader_test1.parse_args(arguments) - assert parsed_args.builder_file == builder_file + assert parsed_args.recipe == recipe assert parsed_args.config_file == config_file assert parsed_args.verify_only == verify_only diff --git a/tests/test_builder.py b/tests/test_builder.py index 9b7dce8..263e888 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -5,7 +5,7 @@ # patch.object(CsvFile, "create_or_get", return_value=Mock()): # # data = YamlRepr.read_to_dict(TestFiles.BuildConfig.ONE_OF_EACH_TYPE) -# builder = TopLevelTaskBuilder.from_list(data) +# builder = TopLevelRecipeBuilder.from_list(data) # builder.execute() # # assert len(builder.tasks) == 1