warnings.filterwarnings("ignore", message='Using `tqdm.autonotebook.tqdm` in notebook mode')Input file
In order to avoid tqdm’s experimental warning
test_file = '_input_.yaml'Finding the appropriate settings in the file
A convenience function to extract the settings of a given class within a certain category. If there are duplicated categories and/or classes, the one that is found first is returned.
extract_class_settings
extract_class_settings (category_name:Union[str,list], class_name:str, settings:dict)
output file: third_midterm.yaml
pictures base directory: tc/midterm3
path to gift-wrapper: '~/gift-wrapper/wrap.py'
categories:
- name: Entropy of the input given the output
classes:
- name: EntropyOfInputGivenOutput
question base name: Entropy of input given the output
init parameters:
picture_file: DMCs/entropy_at_input_given_output.tex
statement: |
Consider...
feedback: |
One way of tackling the problem is...
number of instances: 2Writing _input_.yaml
with open(test_file) as yaml_data:
settings = yaml.load(yaml_data, Loader=yaml.FullLoader)
extract_class_settings('Entropy of the input given the output', 'EntropyOfInputGivenOutput', settings){'name': 'EntropyOfInputGivenOutput',
'question base name': 'Entropy of input given the output',
'init parameters': {'picture_file': 'DMCs/entropy_at_input_given_output.tex'},
'statement': 'Consider...\n',
'feedback': 'One way of tackling the problem is...\n',
'number of instances': 2}
Managing the settings with an ad-hoc object
A class to manage (in memory) all the settings required to build the questions.
Settings
Settings (output_file:str='quiz.yaml', pictures_directory:str='quiz/pics', test_mode:bool=False)
Initialize self. See help(type(self)) for accurate signature.
The object right after initialization:
settings = Settings()
settings{'categories': None,
'output file': 'quiz.yaml',
'pictures base directory': 'quiz/pics'}
A scalar category is added (it doesn’t have any class yet)
settings.add_category('My category')
settings{'categories': [{'classes': None, 'name': 'My category'}],
'output file': 'quiz.yaml',
'pictures base directory': 'quiz/pics'}
If test_mode is set to True when instantiating the class,
settings = Settings(test_mode=True)then the passed category name is ignored and test is used
category_name = settings.add_category('My category')
settings{'categories': [{'classes': None, 'name': 'test'}],
'output file': 'quiz.yaml',
'pictures base directory': 'quiz/pics'}
In such case, it is important to retrieve the value returned by add_category, since that is the actual category name added.
settings.add_or_update_class(
category_name=category_name, class_name='MeanLinearCombinationCosineAndUniform', question_base_name='Mean of a random process',
init_parameters=dict(
uniform_low_range=[2, 8], uniform_high_range=[12, 30], mean_range=[-5, 5],
variance_range=[1, 10], cosine_frequency_over_pi=[1, 2, 3], t_range=[0, 30]
),
n_instances=2, time=4
)
settings{'categories': [{'classes': [{'init parameters': {'cosine_frequency_over_pi': [1,
2,
3],
'mean_range': [-5, 5],
't_range': [0, 30],
'uniform_high_range': [12,
30],
'uniform_low_range': [2, 8],
'variance_range': [1, 10]},
'name': 'MeanLinearCombinationCosineAndUniform',
'number of instances': 2,
'question base name': 'Mean of a random process',
'time': 4}],
'name': 'test'}],
'output file': 'quiz.yaml',
'pictures base directory': 'quiz/pics'}
settings = Settings()
settings.add_category('My category')
settings.add_or_update_class(category_name='My category',class_name='A', question_base_name='question for class #1', n_instances=2, time=4)
settings.add_or_update_class(category_name='My category',class_name='B', question_base_name='question for class #2', n_instances=2, time=10)
settings.add_category(category_name='My category #1',base_category='Parent')
settings.add_or_update_class(
category_name=['Parent', 'Parent/My category #1'],class_name='C', question_base_name='question for class #2', n_instances=2, time=10)settings{'categories': [{'classes': [{'name': 'A',
'number of instances': 2,
'question base name': 'question for class #1',
'time': 4},
{'name': 'B',
'number of instances': 2,
'question base name': 'question for class #2',
'time': 10}],
'name': 'My category'},
{'classes': [{'name': 'C',
'number of instances': 2,
'question base name': 'question for class #2',
'time': 10}],
'name': ['Parent', 'Parent/My category #1']}],
'output file': 'quiz.yaml',
'pictures base directory': 'quiz/pics'}
settings.locate('My category', 'B'){'name': 'B',
'question base name': 'question for class #2',
'number of instances': 2,
'time': 10}
settings.locate(category_name=['Parent', 'Parent/My category #1']){'name': ['Parent', 'Parent/My category #1'],
'classes': [{'name': 'C',
'question base name': 'question for class #2',
'number of instances': 2,
'time': 10}]}
If the classes do exist
class A:
name = 'A'
class B:
name = 'B'
class C:
name = 'C'classes_container = settings.fake_module
print(classes_container.A.name)
print(classes_container.B.name)A
B
Composing a dictionary with the YAML settings
initialize
initialize (output_file:str, pictures_directory:str)
settings_dict = initialize(output_file='quiz.yaml', pictures_directory='quiz/pics')set_class_preamble
set_class_preamble (settings:dict, category_name:str, base_category:Optional[str]=None, test_mode:bool=False)
set_class_preamble(settings_dict, 'Test category')
settings_dict{'output file': 'quiz.yaml',
'pictures base directory': 'quiz/pics',
'categories': [{'name': 'Test category', 'classes': None}]}
set_class_closing
set_class_closing (settings:dict, n_instances:int, time:Optional[int]=None)
set_class_closing(settings_dict, 2, 15)
settings_dict{'output file': 'quiz.yaml',
'pictures base directory': 'quiz/pics',
'categories': [{'name': 'Test category',
'classes': [{'number of instances': 2, 'time': 15}]}]}
set_class
set_class (settings:dict, class_name:str, question_base_name:str, init_parameters:Optional[dict]=None, parameters:Optional[List[dict]]=None, n_instances:Optional[int]=None, time:Optional[int]=None)
set_class(
settings_dict, class_name='MeanLinearCombinationCosineAndUniform', question_base_name='Mean of a random process',
init_parameters=dict(
uniform_low_range=[2, 8], uniform_high_range=[12, 30], mean_range=[-5, 5],
variance_range=[1, 10], cosine_frequency_over_pi=[1, 2, 3], t_range=[0, 30]
), n_instances=2, time=4)settings_dict{'output file': 'quiz.yaml',
'pictures base directory': 'quiz/pics',
'categories': [{'name': 'Test category',
'classes': [{'name': 'MeanLinearCombinationCosineAndUniform',
'question base name': 'Mean of a random process',
'init parameters': {'uniform_low_range': [2, 8],
'uniform_high_range': [12, 30],
'mean_range': [-5, 5],
'variance_range': [1, 10],
'cosine_frequency_over_pi': [1, 2, 3],
't_range': [0, 30]},
'number of instances': 2,
'time': 4}]}]}
Writing
Code to write input files.
Header
A function to write the header of the file. * file: name of the input file to be created
write_header
write_header (file:Union[str,pathlib.Path], output_file:str, pictures_directory:str)
write_header(test_file, output_file='quiz.yaml', pictures_directory='quiz/pics')output file: quiz.yaml
pictures base directory: quiz/pics
categories:
Class
Writing the preamble
A function to write the preamble for a class which includes the name of the category. Strictly speaking, it’s not necessary to create a new category every time a class is added, but this is more general and a category can show up many times in the input file. * file: name of the input file to be appended to * category_name: name of the category in which the class will be encompassed * base_category: a parent category for category_name (optional) * test_mode: if True, the last two parameters are overriden and the category is simply called test
For convenience, the final category_name (notice that it might get tweaked because of the other parameters) is returned.
write_class_preamble
write_class_preamble (file:Union[str,pathlib.Path], category_name:str, base_category:Optional[str]=None, test_mode:bool=False)
*Writes the preamble for a class which includes the name of the category. Strictly speaking, it’s not necessary to create a new category every time a class is added, but this is more general and a category can show up many times in the input file.
Parameters
file: str, PathlibInput file to be appended to.
category_name: strName of the category in which the class will be encompassed.
base_category: str, optionalThe parent category for
category_name.test_mode: boolIf
Truethe last two parameters are overriden and the category is simply calledtest.
Returns
category_name: str or listThe final name for the category (notice that it might get tweaked due to
test_mode).*
write_class_preamble(test_file, 'Test category')'Test category'
output file: quiz.yaml
pictures base directory: quiz/pics
categories:
- name: Test category
classes:
Parameter base_category allows to create hierarchical categories
write_header(test_file, output_file='quiz.yaml', pictures_directory='quiz/pics')
write_class_preamble(test_file, 'Test category', base_category='base')['base', 'base/Test category']
output file: quiz.yaml
pictures base directory: quiz/pics
categories:
- name:
- base
- base/Test category
classes:
In test_mode
write_header(test_file, output_file='quiz.yaml', pictures_directory='quiz/pics')
write_class_preamble(test_file, 'Test category', base_category='base', test_mode=True)'test'
output file: quiz.yaml
pictures base directory: quiz/pics
categories:
- name: test
classes:
Writing the closing
A function to write the closing settings of a class. * file: name of the input file to be appended to * n_instances: number of questions of this class that will be created (the setup method of the class should be non-deterministic) * time: time in minutes (an integer) estimated necessary to solve the question
write_class_closing
write_class_closing (file:Union[str,pathlib.Path], n_instances:int, time:Optional[int]=None)
write_class_closing(test_file, 2, 15)output file: quiz.yaml
pictures base directory: quiz/pics
categories:
- name: test
classes:
- number of instances: 2
time: 15
!rm {test_file}Categories
function_to_make_hierarchical_category_name
function_to_make_hierarchical_category_name (base_category:str)
f = function_to_make_hierarchical_category_name('2020 exam')
f('Random')['2020 exam', '2020 exam/Random']