Browse Source

Add filter creation in configuration creation command.

feature/create-config
gabriel becker 2 years ago
parent
commit
79e7714395
  1. 5
      .gitignore
  2. 3
      requirements.txt
  3. 3
      setup.py
  4. 34
      src/ankimaker/config/configuration.py
  5. 7
      src/ankimaker/config/filters.py
  6. 90
      src/ankimaker/tasks/config_tasks/create_config.py

5
.gitignore vendored

@ -157,4 +157,7 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear # and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/ .idea/
# Project Specific
scripts/

3
requirements.txt

@ -1,4 +1,5 @@
click click
genanki genanki
pandas pandas
pyyaml pyyaml
bullet

3
setup.py

@ -8,7 +8,7 @@ def readme():
setup( setup(
name='ankimaker', name='ankimaker',
version='0.0.4', version='0.0.5',
description='Makes anki with files', description='Makes anki with files',
url="https://git.lgoon.xyz/gabriel/ankimaker", url="https://git.lgoon.xyz/gabriel/ankimaker",
license="BSD-3-Clause", license="BSD-3-Clause",
@ -27,6 +27,7 @@ setup(
"genanki", "genanki",
"pandas", "pandas",
"pyyaml", "pyyaml",
"bullet"
], ],
long_description_content_type='text/markdown', long_description_content_type='text/markdown',
) )

34
src/ankimaker/config/configuration.py

@ -14,12 +14,15 @@ class AnkimakerConfig(yaml.YAMLObject):
separators = ',' separators = ','
filters: List[List[FilterConfig]] = list() filters: List[List[FilterConfig]] = list()
def __init__(self, header=None, answer_column=None, question_column=None, filters=tuple()): def __init__(
AnkimakerConfig.answer_column = answer_column self, separators=',', header=None, answer_column=None, question_column=None,
AnkimakerConfig.question_column = question_column filters=tuple(), *args, **karhs
AnkimakerConfig.header = header ):
AnkimakerConfig.AnkimakerConfig = AnkimakerConfig self.answer_column = answer_column
AnkimakerConfig.filters = list(map(lambda x: FilterConfig, filters)) self.question_column = question_column
self.header = header
self.separators = separators
self.filters = _conditionally_create_new_filters(filters)
@staticmethod @staticmethod
def loader(configuration_content): def loader(configuration_content):
@ -31,8 +34,19 @@ class AnkimakerConfig(yaml.YAMLObject):
AnkimakerConfig.question_column = content.question_column AnkimakerConfig.question_column = content.question_column
AnkimakerConfig.answer_column = content.answer_column AnkimakerConfig.answer_column = content.answer_column
AnkimakerConfig.separators = content.separators AnkimakerConfig.separators = content.separators
AnkimakerConfig.filters = [ AnkimakerConfig.filters = _conditionally_create_new_filters(content.filters)
[FilterConfig(**x) for x in or_filter]
for or_filter in content.filters
]
def _conditionally_create_new_filters(filters):
conf_has_filters = len(filters) > 0
if conf_has_filters:
should_cast_filter = not isinstance(filters[0][0], FilterConfig)
if should_cast_filter:
new_filters = [
[FilterConfig(**x) for x in or_filter]
for or_filter in filters
]
else:
new_filters = filters
return new_filters
return list()

7
src/ankimaker/config/filters.py

@ -1,7 +1,10 @@
import yaml
from typing import List, Union from typing import List, Union
class FilterConfig: class FilterConfig(yaml.YAMLObject):
yaml_tag = '!fitlerconfig'
column: Union[str, int] column: Union[str, int]
values: Union[List[Union[int, str]], Union[int, str]] values: Union[List[Union[int, str]], Union[int, str]]
@ -10,7 +13,7 @@ class FilterConfig:
self.values = values self.values = values
def __str__(self): def __str__(self):
return f'<ankimaker.config.filters.FilterConfig {self.column}: {self.values} >' return f'<F({self.column}:{self.values})>'
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()

90
src/ankimaker/tasks/config_tasks/create_config.py

@ -1,10 +1,12 @@
import os import os
import yaml import yaml
import click import click
import pandas as pd import pandas as pd
from typing import Type from typing import Type, List
from bullet import Bullet, Input, YesNo
from ankimaker.config import Config from ankimaker.config import Config, FilterConfig
__CONFIRMATION_QUESTION = """ __CONFIRMATION_QUESTION = """
@ -25,25 +27,93 @@ __COMMAND_SAMPLE = """ankimaker csv \
""" """
__ADD_FILTER_QUESTION = """Do you want do add a filter to the configuration?"""
def create_config(input_file, output_path): def create_config(input_file, output_path):
new_config = Config()
new_config.separators = handle_read_option( separators = handle_read_option(
input_file, read_option='sep', sep=new_config.separators input_file, read_option='sep', sep=','
) )
new_config.header = handle_read_option( header = handle_read_option(
input_file, read_option='header', header=new_config.header, input_file, read_option='header', header=None,
sep=new_config.separators, option_type=int sep=separators, option_type=int
) )
new_config.question_column = get_column('question') question_column = get_column('question')
new_config.answer_column = get_column('answer') answer_column = get_column('answer')
filters = process_filters(input_file, header, separators)
new_config = Config(
separators=separators,
header=header,
question_column=question_column,
answer_column=answer_column,
filters=filters
)
save_file(new_config, output_path) save_file(new_config, output_path)
finish_message = __SUCCESS_MESSAGE.format(command=make_sample_command(input_file, output_path)) finish_message = __SUCCESS_MESSAGE.format(command=make_sample_command(input_file, output_path))
click.clear()
click.echo(finish_message) click.echo(finish_message)
def process_filters(input_file, header, separators):
df = pd.read_csv(input_file, header=header, sep=separators)
filters = add_filters_to_config(df)
return filters
def __inline_yes_or_no_question(question):
answer = YesNo(prompt=question, default='n').launch()
return answer
def add_filters_to_config(df: pd.DataFrame) -> List[List[FilterConfig]]:
config = Config()
should_add_filter = __inline_yes_or_no_question(__ADD_FILTER_QUESTION)
while should_add_filter:
config = add_filter_to_or_create_filter_group(df, config)
should_add_filter = __inline_yes_or_no_question(__ADD_FILTER_QUESTION)
return config.filters
def add_filter_to_or_create_filter_group(df: pd.DataFrame, config: Config) -> Config:
config_has_filters = len(config.filters) > 0
chosen_group = -1
if config_has_filters:
filter_options = [f'({"|".join(map(str, group)):.45s})' for group in config.filters]
filter_options = [f'Group{i+1}{s}' for i, s in enumerate(filter_options)]
cli = Bullet(
prompt="Select group: ",
choices=["Create new", *filter_options],
return_index=True,
)
chosen_group = cli.launch()[1] - 1
new_filter = create_filter_config(df)
if chosen_group < 0:
config.filters.append([new_filter])
else:
config.filters[chosen_group].append(new_filter)
return config
def create_filter_config(df: pd.DataFrame) -> FilterConfig:
options = list(df.columns)
cli = Bullet(
prompt="Select a columns to filter: ",
choices=list(map(str, options)),
return_index=True
)
chosen = cli.launch()[1]
filter_column = options[chosen]
columns_values = df[filter_column].unique()
values = Input(f'Which values fo filter out? values[{columns_values}]: ').launch()
new_filter = FilterConfig(column=filter_column, values=values)
return new_filter
def get_column(name: str) -> str: def get_column(name: str) -> str:
answer = click.prompt(f'Which is your {name} column?', type=str, confirmation_prompt=True) answer = click.prompt(f'Which is your {name} column?', type=str, confirmation_prompt=True)
return answer return answer

Loading…
Cancel
Save