Extending flitsr advanced types

flitsr provides a number of techniques implemented as advanced types, which you can employ when using flitsr. However flitsr also provides the functionality for you to easily create your own advanced type, if you would like to extend flitsr to support another technique.

To create a new technique for an advanced type, you will need to define a class which extends a current advanced type base class. The available advanced types are given in flitsr advanced types. You would create your advanced type either within the advanced package of flitsr, or (more likely) create a separate plugin. Creating this concrete implementation of an advanced type using either of these two ways will allow flitsr to automatically discover and make available your advanced type.

To create an advanced type plugin, use the flitsr.advanced entry point, for example:

pyproject.toml
[project.entry-points.'flitsr.advanced']
adv_mthd = "my-package.custom_adv_type:CustomTechnique"

Where CustomTechnique is a custom advanced type that inherits one of the advanced types.

Since custom techniques will have various different algorithms and potentially other input, flitsr makes it easy to customize advanced types by providing some helpful structure and functions for advanced types.

Passing input parameters – the __init__ method

flitsr allows any advanced type to take additional inputs which they can use within their implementation. To do this, flitsr analyzes the signature of the __init__ method of any advanced type, and processes the parameters of this method, making them automatically available as command line parameters, which flitsr will provide when calling the advanced type.

As an example, let’s use the parallel advanced type. The __init__ method of the parallel advanced type is as follows:

advanced/parallel.py
 def __init__(self, parType: str = 'msp'):
     self.parType = parType

This advanced type takes one additional parameter, parType which has a type hint indicating it is a str. It also has a default value set, which is 'msp'.

flitsr automatically processes this advanced types __init__ method, and extracts this information, automatically producing the command line option –parallel-parType. The command line option is automatically created to have a parameter with type str, which has the default value of 'msp'.

flitsr uses argparse for its command line processing, which will automatically support conversion to any primitive type. For conversion to a non-primitive type, you must implement a method named _<param> in your advanced type class, where <param> is the name of the __init__ parameter to convert, which takes a string and converts it to your custom type. For example, if your technique takes a parameter my_date, which is a date in the format 'Jun 1 2005  1:33PM', you could specify the function:

@staticmethod
def _my_date(date_str : str):
    from datetime import datetime
    return datetime.strptime(date_str, '%b %d %Y %I:%M%p').date()

This would be automatically discovered by flitsr, and will be passed to argparse to be used to convert the parameter to a date object.

Advanced type attributes – existing

In some cases, you would like to define a parameter to your function that takes the value of an argument already passed to flitsr, instead of defining a new command line argument. For example, you might want your technique to use the --tiebrk argument to flitsr, with which the user specifies how to break ties throughout flitsr. To include already defined arguments in the parameters of your advanced type, flitsr provides the existing decorator function which can be applied to the __init__ method. The decorator has the following usage:

flitsr.advanced.attributes.existing(*params: str)

A python decorator to mark the given parameter(s) as one(s) already defined in FLITSR’s arguments. These parameters for the decorated advanced type are therefore not added as FLITSR command line arguments, but are instead taken from the existing command line arguments.

Parameters:

*params – str: The parameters of the __init__ function to mark as already existing flitsr parameters.

Using the example of the --tiebrk option, you would do the following:

@existing('tiebrk')
def __init__(self, tiebrk: Tiebrk):
    self.tiebrk = tiebrk

flitsr would then automatically fill that parameter with the value of the --tiebrk command line argument when instantiating your advanced type.

Advanced type attributes – choices

For some parameters, you may also want to specify a number of pre-defined choices for a particular parameter. flitsr allows you to do this using the choices decorator, which can be applied to the __init__ method, similar to the existing decorator. The choices decorator has the following usage:

flitsr.advanced.attributes.choices(param: str, choices: Collection[Any])

An advanced types decorator to specfiy the choices available for a given parameter. The given choices will be added as available choices for the command line argument for FLITSR.

Parameters:
  • param – str: The parameter to set choices for.

  • choices – Collection[Any]: The collection of choices for the parameter.

As an example, the parType parameter of our --parallel example has four pre-defined strings that it accepts: bdm, msp, hwk, and vwk. To define this set of choices for the parallel advanced type, we would do the following:

@choices('parType', ['bdm', 'msp', 'hwk', 'vwk'])
def __init__(self, parType: str = 'msp'):
    self.parType = parType

This is the implementation used for the __init__ method of the parallel technique, from which flitsr automatically creates the –parallel-parType command line option.

Advanced type attributes – print_name

The last type of helper method that flitsr provides is the print_name decorator. This is a class level decorator, that can be used on an advanced type class to define a different name to be used when flitsr prints results to output files. This name will then appear in file names and merged result files. The usage of this decorator is as follows:

flitsr.advanced.attributes.print_name(print_name: str)

An advanced types decorator to specfiy an alternative name for the decorated class to use when printing results to a file. By default the lower-case name of the advanced type is used.

Parameters:

print_name – str: The name to use when printing this advanced type.

An example of the usage is for the sbfl advanced type in flitsr. For this advanced type, we would like a different name to be used when printing out results, namely 'base' instead of 'sbfl'. The sbfl class is thus defined as:

@print_name('base')
class SBFL(Ranker):
    ...