Input file

Convenience functions/classes to construct the input file required by py2gift.

In order to avoid tqdm’s experimental warning

warnings.filterwarnings("ignore", message='Using `tqdm.autonotebook.tqdm` in notebook mode')
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.


source

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: 2
Overwriting _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.


source

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


source

initialize

 initialize (output_file:str, pictures_directory:str)
settings_dict = initialize(output_file='quiz.yaml', pictures_directory='quiz/pics')

source

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}]}

source

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}]}]}

source

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.

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.


source

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, Pathlib

    Input file to be appended to.

  • category_name: str

    Name of the category in which the class will be encompassed.

  • base_category: str, optional

    The parent category for category_name.

  • test_mode: bool

    If True the last two parameters are overriden and the category is simply called test.

Returns

  • category_name: str or list

    The 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


source

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


source

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']