Skip to content

Commit

Permalink
Overrides: NoteModel name, Deck desc (#16)
Browse files Browse the repository at this point in the history
* Notes Override

* Small bugfixes

* Remove ToRead pattern

* Deck Description as HTML

* Media saving maintains subfolder status of existing files when 'recurring' is enabled
  • Loading branch information
ohare93 authored Dec 13, 2020
1 parent da03b71 commit 54a4af1
Show file tree
Hide file tree
Showing 20 changed files with 206 additions and 59 deletions.
7 changes: 2 additions & 5 deletions brain_brew/build_tasks/crowd_anki/headers_to_crowd_anki.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,12 @@ def from_repr(cls, data: Union[Representation, dict, str]):
rep = cls.Representation(part_id=data) # Support single string being passed in

return cls(
headers_to_read=rep.part_id
headers=PartHolder.from_file_manager(rep.part_id).part
)

headers_to_read: str
headers: Headers = field(init=False)
headers: Headers

def execute(self) -> dict:
self.headers = PartHolder.from_file_manager(self.headers_to_read).part

headers = self.headers_to_crowd_anki(self.headers.data_without_name)

return headers
Expand Down
2 changes: 1 addition & 1 deletion brain_brew/build_tasks/crowd_anki/media_to_crowd_anki.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ def from_repr(cls, data: Union[Representation, dict]):
parts: List[MediaGroup]

def execute(self, ca_media_folder: str) -> Set[MediaFile]:
return save_media_groups_to_location(self.parts, ca_media_folder, True)
return save_media_groups_to_location(self.parts, ca_media_folder, True, False)
21 changes: 15 additions & 6 deletions brain_brew/build_tasks/crowd_anki/notes_to_crowd_anki.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import Optional, Union, List

from brain_brew.build_tasks.crowd_anki.shared_base_notes import SharedBaseNotes
from brain_brew.build_tasks.overrides.notes_override import NotesOverride
from brain_brew.configuration.part_holder import PartHolder
from brain_brew.configuration.representation_base import RepresentationBase
from brain_brew.interfaces.yamale_verifyable import YamlRepr
Expand All @@ -23,37 +24,45 @@ def yamale_schema(cls) -> str:
sort_order: list(str(), required=False)
reverse_sort: bool(required=False)
additional_items_to_add: map(str(), key=str(), required=False)
override: include('{NotesOverride.task_name()}', required=False)
'''

@classmethod
def yamale_dependencies(cls) -> set:
return {NotesOverride}

@dataclass
class Representation(RepresentationBase):
part_id: str
additional_items_to_add: Optional[dict] = field(default_factory=lambda: None)
sort_order: Optional[List[str]] = field(default_factory=lambda: None)
reverse_sort: Optional[bool] = field(default_factory=lambda: None)
override: Optional[dict] = field(default_factory=lambda: None)

@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(
notes_to_read=rep.part_id,
notes=PartHolder.from_file_manager(rep.part_id).part,
sort_order=SharedBaseNotes._get_sort_order(rep.sort_order),
reverse_sort=SharedBaseNotes._get_reverse_sort(rep.reverse_sort),
additional_items_to_add=rep.additional_items_to_add or {}
additional_items_to_add=rep.additional_items_to_add or {},
override=NotesOverride.from_repr(rep.override) if rep.override else None
)

notes: Notes = field(init=False)

notes_to_read: str
notes: Notes
additional_items_to_add: dict
sort_order: Optional[List[str]] = field(default_factory=lambda: None)
reverse_sort: Optional[bool] = field(default_factory=lambda: None)
override: Optional[NotesOverride] = field(default_factory=lambda: None)

def execute(self, nm_name_to_id: dict) -> List[dict]:
self.notes = PartHolder.from_file_manager(self.notes_to_read).part

notes = self.notes.get_sorted_notes_copy(sort_by_keys=self.sort_order, reverse_sort=self.reverse_sort)

if self.override:
notes = [self.override.override(note) for note in notes]

note_dicts = [self.note_to_ca_note(note, nm_name_to_id, self.additional_items_to_add) for note in notes]

return note_dicts
Expand Down
11 changes: 4 additions & 7 deletions brain_brew/build_tasks/csvs/csvs_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def task_regex(cls) -> str:
return r'generate_csv[s]?'

@classmethod
def yamale_schema(cls) -> str:
def yamale_schema(cls) -> str: # TODO: Use NotesOverride here, just as in NotesToCrowdAnki
return f'''\
notes: str()
note_model_mappings: list(include('{NoteModelMapping.task_name()}'))
Expand All @@ -32,8 +32,7 @@ def yamale_schema(cls) -> str:
def yamale_dependencies(cls) -> set:
return {NoteModelMapping, FileMapping}

notes_to_read: str # TODO: Accept Multiple Note Parts
notes: PartHolder[Notes] = field(default=None)
notes: PartHolder[Notes] # TODO: Accept Multiple Note Parts

@dataclass
class Representation(SharedBaseCsvs.Representation):
Expand All @@ -43,14 +42,12 @@ class Representation(SharedBaseCsvs.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(
notes_to_read=rep.notes,
notes=PartHolder.from_file_manager(rep.notes),
file_mappings=rep.get_file_mappings(),
note_model_mappings_to_read=rep.note_model_mappings
note_model_mappings=dict(*map(cls.map_nmm, rep.note_model_mappings))
)

def execute(self):
self.setup_note_model_mappings()
self.notes = PartHolder.from_file_manager(self.notes_to_read)
self.verify_contents()

notes: List[Note] = self.notes.part.get_sorted_notes_copy(
Expand Down
3 changes: 1 addition & 2 deletions brain_brew/build_tasks/csvs/notes_from_csvs.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,13 @@ def from_repr(cls, data: Union[Representation, dict]):
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
note_model_mappings=dict(*map(cls.map_nmm, rep.note_model_mappings))
)

part_id: str
save_to_file: Optional[str]

def execute(self):
self.setup_note_model_mappings()
self.verify_contents()

csv_data_by_guid: Dict[str, dict] = {}
Expand Down
13 changes: 5 additions & 8 deletions brain_brew/build_tasks/csvs/shared_base_csvs.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,12 @@ def get_file_mappings(self) -> List[FileMapping]:
return list(map(FileMapping.from_repr, self.file_mappings))

file_mappings: List[FileMapping]
note_model_mappings_to_read: List[NoteModelMapping.Representation]
note_model_mappings: Dict[str, NoteModelMapping] = field(init=False)
note_model_mappings: Dict[str, NoteModelMapping]

def setup_note_model_mappings(self):
def map_nmm(nmm_to_map):
nmm = NoteModelMapping.from_repr(nmm_to_map)
return nmm.get_note_model_mapping_dict()

self.note_model_mappings = dict(*map(map_nmm, self.note_model_mappings_to_read))
@classmethod
def map_nmm(cls, nmm_to_map):
nmm = NoteModelMapping.from_repr(nmm_to_map)
return nmm.get_note_model_mapping_dict()

def verify_contents(self):
errors = []
Expand Down
14 changes: 0 additions & 14 deletions brain_brew/build_tasks/deck_parts/from_yaml_part.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from brain_brew.configuration.build_config.build_task import BuildPartTask
from brain_brew.configuration.part_holder import PartHolder
from brain_brew.configuration.representation_base import RepresentationBase
from brain_brew.representation.yaml.headers import Headers
from brain_brew.representation.yaml.media_group import MediaGroup
from brain_brew.representation.yaml.note_model import NoteModel
from brain_brew.representation.yaml.notes import Notes
Expand Down Expand Up @@ -52,19 +51,6 @@ def task_name(cls) -> str:
part_type = Notes


@dataclass
class HeadersFromYamlPart(FromYamlPartBase, BuildPartTask):
@classmethod
def task_name(cls) -> str:
return r'headers_from_yaml_part'

@classmethod
def task_regex(cls) -> str:
return r'header[s]?_from_yaml_part'

part_type = Headers


@dataclass
class NoteModelsFromYamlPart(FromYamlPartBase, BuildPartTask):
@classmethod
Expand Down
58 changes: 58 additions & 0 deletions brain_brew/build_tasks/deck_parts/headers_from_yaml_part.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from dataclasses import dataclass
from typing import Union

from brain_brew.build_tasks.deck_parts.from_yaml_part import FromYamlPartBase
from brain_brew.build_tasks.overrides.headers_override import HeadersOverride
from brain_brew.configuration.build_config.build_task import BuildPartTask
from brain_brew.configuration.part_holder import PartHolder
from brain_brew.configuration.representation_base import RepresentationBase
from brain_brew.representation.yaml.headers import Headers


@dataclass
class HeadersFromYamlPart(BuildPartTask):
@classmethod
def yamale_schema(cls) -> str:
return f'''\
part_id: str()
file: str()
override: include('{HeadersOverride.task_name()}', required=False)
'''

@classmethod
def yamale_dependencies(cls) -> set:
return {HeadersOverride}

@classmethod
def task_name(cls) -> str:
return r'headers_from_yaml_part'

@classmethod
def task_regex(cls) -> str:
return r'header[s]?_from_yaml_part'

@dataclass
class Representation(RepresentationBase):
part_id: str
file: str
override: dict

@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(
headers=PartHolder.override_or_create(
part_id=rep.part_id,
save_to_file=None,
part=Headers.from_yaml_file(rep.file)
).part,
override=HeadersOverride.from_repr(rep.override)
)

headers: Headers
override: HeadersOverride

def execute(self):
if self.override:
self.headers = self.override.override(self.headers)
12 changes: 8 additions & 4 deletions brain_brew/build_tasks/deck_parts/media_group_to_folder.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dataclasses import dataclass
from dataclasses import dataclass, field
from typing import List, Union, Optional

from brain_brew.configuration.build_config.build_task import BuildPartTask
Expand All @@ -24,26 +24,30 @@ def yamale_schema(cls) -> str:
parts: list(str())
folder: str()
clear_folder: bool(required=False)
recursive: bool(required=False)
'''

@dataclass
class Representation(RepresentationBase):
parts: List[str]
folder: str
clear_folder: Optional[bool]
clear_folder: Optional[bool] = field(default=None)
recursive: Optional[bool] = field(default=None)

@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(
parts=list(holder.part for holder in map(PartHolder.from_file_manager, rep.parts)),
folder=rep.folder,
clear_folder=rep.clear_folder or False
clear_folder=rep.clear_folder or False,
recursive=rep.recursive or False
)

parts: List[MediaGroup]
folder: str
clear_folder: bool
recursive: bool

def execute(self):
save_media_groups_to_location(self.parts, self.folder, self.clear_folder)
save_media_groups_to_location(self.parts, self.folder, self.clear_folder, self.recursive)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from brain_brew.representation.generic.html_file import HTMLFile
from brain_brew.representation.yaml.note_model_template import Template

html_separator = '--'
html_separator = '\n\n--\n\n'


@dataclass
Expand Down Expand Up @@ -74,7 +74,7 @@ def execute(self):

browser_front, browser_back = tuple(browser_data.split(html_separator, maxsplit=1))
else:
browser_front = browser_back = None
browser_front = browser_back = ""

template = Template(
name=self.template_name,
Expand Down
Empty file.
39 changes: 39 additions & 0 deletions brain_brew/build_tasks/overrides/headers_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from dataclasses import dataclass
from typing import Optional, Union

from brain_brew.configuration.representation_base import RepresentationBase
from brain_brew.interfaces.yamale_verifyable import YamlRepr
from brain_brew.representation.generic.html_file import HTMLFile
from brain_brew.representation.yaml.headers import Headers


@dataclass
class HeadersOverride(YamlRepr):
@classmethod
def task_name(cls) -> str:
return r"headers_override"

@classmethod
def yamale_schema(cls) -> str:
return f'''\
deck_description_html_file: str(required=False)
'''

@dataclass
class Representation(RepresentationBase):
deck_description_html_file: Optional[str]

@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(
deck_desc_html_file=HTMLFile.create_or_get(rep.deck_description_html_file)
)

deck_desc_html_file: Optional[HTMLFile]

def override(self, header: Headers):
if self.deck_desc_html_file:
header.description = self.deck_desc_html_file.get_data(deep_copy=True)

return header
38 changes: 38 additions & 0 deletions brain_brew/build_tasks/overrides/notes_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from dataclasses import dataclass
from typing import Optional, Union

from brain_brew.configuration.representation_base import RepresentationBase
from brain_brew.interfaces.yamale_verifyable import YamlRepr
from brain_brew.representation.yaml.notes import Notes, Note


@dataclass
class NotesOverride(YamlRepr):
@classmethod
def task_name(cls) -> str:
return r"notes_override"

@classmethod
def yamale_schema(cls) -> str:
return f'''\
note_model: str(required=False)
'''

@dataclass
class Representation(RepresentationBase):
note_model: Optional[str]

@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(
note_model=rep.note_model
)

note_model: Optional[str]

def override(self, note: Note):
if self.note_model:
note.note_model = self.note_model

return note
5 changes: 3 additions & 2 deletions brain_brew/configuration/build_config/parts_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
from brain_brew.build_tasks.crowd_anki.note_models_from_crowd_anki import NoteModelsFromCrowdAnki
from brain_brew.build_tasks.crowd_anki.notes_from_crowd_anki import NotesFromCrowdAnki
from brain_brew.build_tasks.csvs.notes_from_csvs import NotesFromCsvs
from brain_brew.build_tasks.deck_parts.from_yaml_part import NotesFromYamlPart, HeadersFromYamlPart, \
NoteModelsFromYamlPart, MediaGroupFromYamlPart
from brain_brew.build_tasks.deck_parts.from_yaml_part import NotesFromYamlPart, NoteModelsFromYamlPart, \
MediaGroupFromYamlPart
from brain_brew.build_tasks.deck_parts.headers_from_yaml_part import HeadersFromYamlPart
from brain_brew.build_tasks.deck_parts.media_group_from_folder import MediaGroupFromFolder
from brain_brew.build_tasks.deck_parts.media_group_to_folder import MediaGroupsToFolder
from brain_brew.build_tasks.deck_parts.note_model_from_html_parts import NoteModelFromHTMLParts
Expand Down
3 changes: 2 additions & 1 deletion brain_brew/configuration/build_config/recipe_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,5 @@ def find_matching_task(task_n):

def execute(self):
for task in self.tasks:
task.execute()
if not task.execute_immediately:
task.execute()
Loading

0 comments on commit 54a4af1

Please sign in to comment.