Skip to content

factories

Factory class for registering and creating strategy instances.

Factory wrapper methods for creating the individual strategies.

StrategiesNotLoaded

Bases: Exception

Entry point strategies have not been loaded, run load_strategies().

Source code in oteapi/plugins/factories.py
17
18
19
class StrategiesNotLoaded(Exception):
    """Entry point strategies have not been loaded, run
    [`load_strategies()`][oteapi.plugins.factories.load_strategies]."""

StrategyFactory

Decorator-based Factory class.

Attributes:

Name Type Description
strategy_create_func Dict[StrategyType, EntryPointStrategyCollection]

An in-memory cache of all registered strategies.

Source code in oteapi/plugins/factories.py
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
class StrategyFactory:
    """Decorator-based Factory class.

    Attributes:
        strategy_create_func (Dict[StrategyType, EntryPointStrategyCollection]): An
            in-memory cache of all registered strategies.

    """

    strategy_create_func: "Dict[StrategyType, EntryPointStrategyCollection]"

    @classmethod
    def make_strategy(
        cls, config: "StrategyConfig", strategy_type: "Union[StrategyType, str]"
    ) -> "IStrategy":
        """Instantiate a strategy in a context class.

        Parameters:
            config: A strategy configuration.
            strategy_type: The strategy type, e.g., `"scheme"`, `"mediaType"`, ... or
                `"download"`, `"parse"`, ...
                See the [`StrategyType`][oteapi.plugins.entry_points.StrategyType]
                enumeration for a definition of valid strategy types.

        Raises:
            NotImplementedError: If the strategy cannot be found.
            ValueError: If the `strategy_type` is not a valid strategy type.
                See the [`StrategyType`][oteapi.plugins.entry_points.StrategyType]
                enumeration for a definition of valid strategy types.
            StrategiesNotLoaded: If the entry point strategies have not been loaded.

        Returns:
            An instantiated strategy. The strategy is instantiated with the provided
            configuration, through the `config` parameter.

        """
        if not hasattr(cls, "strategy_create_func"):
            raise StrategiesNotLoaded(
                "Strategies have not been loaded, run `load_strategies()` or "
                "`StrategyFactory.load_strategies()`."
            )

        if isinstance(strategy_type, str):
            try:
                strategy_type = StrategyType.init(strategy_type)
            except ValueError as exc:
                raise ValueError(
                    f"Strategy type {strategy_type!r} is not supported."
                ) from exc
        elif not isinstance(strategy_type, StrategyType):
            raise TypeError(
                "strategy_type should be either of type StrategyType or a string."
            )

        strategy_name: str = cls._get_strategy_name(config, strategy_type)

        if (strategy_type, strategy_name) in cls.strategy_create_func[strategy_type]:
            return cls.strategy_create_func[strategy_type][
                (strategy_type, strategy_name)
            ].implementation(
                config  # type: ignore[arg-type]
            )
        raise NotImplementedError(
            f"The {strategy_type.value} strategy {strategy_name!r} does not exist."
        )

    @classmethod
    def _get_strategy_name(
        cls,
        config: "StrategyConfig",
        strategy_type: StrategyType,
    ) -> str:
        """Return the strategy name through the config.

        This is a method to accommodate strategy type-specific quirks to retrieve the
        strategy name.

        Parameters:
            config: A strategy configuration.
            strategy_type: The strategy type as initialized in `make_strategy()`.

        Returns:
            The strategy name provided in the configuration.

        """
        if strategy_type == StrategyType.DOWNLOAD:
            return config.downloadUrl.scheme if config.downloadUrl is not None else ""  # type: ignore[union-attr]  # pylint: disable=line-too-long
        return getattr(config, strategy_type.map_to_field(), "")

    @classmethod
    def load_strategies(cls, test_for_uniqueness: bool = True) -> None:
        """Load strategies from entry points and store in class attribute.

        Important:
            This is not a cached method.
            The importlib.metadata API will be re-requested to load the entry points
            and strategies.

        Note:
            This does *not* import the actual strategy implementations (classes).
            It only loads the strategies from the registerred OTE-API entry points.

        Raises:
            KeyError: If `test_for_uniqueness` is `True` and an entry point strategy is
                duplicated.

        Parameters:
            test_for_uniqueness: If `True`, this will raise `KeyError` should an entry
                point strategy be duplicated. Otherwise, the first loaded entry point
                strategy will silently become the implementation of choice for the
                duplicated strategy and the duplicates will be ignored.

        """
        cls.strategy_create_func = {
            strategy_type: get_strategy_entry_points(
                strategy_type, enforce_uniqueness=test_for_uniqueness
            )
            for strategy_type in StrategyType
        }

_get_strategy_name(cls, config, strategy_type)

Return the strategy name through the config.

This is a method to accommodate strategy type-specific quirks to retrieve the strategy name.

Parameters:

Name Type Description Default
config 'StrategyConfig'

A strategy configuration.

required
strategy_type StrategyType

The strategy type as initialized in make_strategy().

required

Returns:

Type Description
str

The strategy name provided in the configuration.

Source code in oteapi/plugins/factories.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@classmethod
def _get_strategy_name(
    cls,
    config: "StrategyConfig",
    strategy_type: StrategyType,
) -> str:
    """Return the strategy name through the config.

    This is a method to accommodate strategy type-specific quirks to retrieve the
    strategy name.

    Parameters:
        config: A strategy configuration.
        strategy_type: The strategy type as initialized in `make_strategy()`.

    Returns:
        The strategy name provided in the configuration.

    """
    if strategy_type == StrategyType.DOWNLOAD:
        return config.downloadUrl.scheme if config.downloadUrl is not None else ""  # type: ignore[union-attr]  # pylint: disable=line-too-long
    return getattr(config, strategy_type.map_to_field(), "")

load_strategies(cls, test_for_uniqueness=True)

Important

This is not a cached method. The importlib.metadata API will be re-requested to load the entry points and strategies.

Note

This does not import the actual strategy implementations (classes). It only loads the strategies from the registerred OTE-API entry points.

Load strategies from entry points and store in class attribute.

Raises:

Type Description
KeyError

If test_for_uniqueness is True and an entry point strategy is duplicated.

Parameters:

Name Type Description Default
test_for_uniqueness bool

If True, this will raise KeyError should an entry point strategy be duplicated. Otherwise, the first loaded entry point strategy will silently become the implementation of choice for the duplicated strategy and the duplicates will be ignored.

True
Source code in oteapi/plugins/factories.py
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
@classmethod
def load_strategies(cls, test_for_uniqueness: bool = True) -> None:
    """Load strategies from entry points and store in class attribute.

    Important:
        This is not a cached method.
        The importlib.metadata API will be re-requested to load the entry points
        and strategies.

    Note:
        This does *not* import the actual strategy implementations (classes).
        It only loads the strategies from the registerred OTE-API entry points.

    Raises:
        KeyError: If `test_for_uniqueness` is `True` and an entry point strategy is
            duplicated.

    Parameters:
        test_for_uniqueness: If `True`, this will raise `KeyError` should an entry
            point strategy be duplicated. Otherwise, the first loaded entry point
            strategy will silently become the implementation of choice for the
            duplicated strategy and the duplicates will be ignored.

    """
    cls.strategy_create_func = {
        strategy_type: get_strategy_entry_points(
            strategy_type, enforce_uniqueness=test_for_uniqueness
        )
        for strategy_type in StrategyType
    }

make_strategy(cls, config, strategy_type)

Instantiate a strategy in a context class.

Parameters:

Name Type Description Default
config 'StrategyConfig'

A strategy configuration.

required
strategy_type 'Union[StrategyType, str]'

The strategy type, e.g., "scheme", "mediaType", ... or "download", "parse", ... See the StrategyType enumeration for a definition of valid strategy types.

required

Raises:

Type Description
NotImplementedError

If the strategy cannot be found.

ValueError

If the strategy_type is not a valid strategy type. See the StrategyType enumeration for a definition of valid strategy types.

StrategiesNotLoaded

If the entry point strategies have not been loaded.

Returns:

Type Description
'IStrategy'

An instantiated strategy. The strategy is instantiated with the provided

'IStrategy'

configuration, through the config parameter.

Source code in oteapi/plugins/factories.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
@classmethod
def make_strategy(
    cls, config: "StrategyConfig", strategy_type: "Union[StrategyType, str]"
) -> "IStrategy":
    """Instantiate a strategy in a context class.

    Parameters:
        config: A strategy configuration.
        strategy_type: The strategy type, e.g., `"scheme"`, `"mediaType"`, ... or
            `"download"`, `"parse"`, ...
            See the [`StrategyType`][oteapi.plugins.entry_points.StrategyType]
            enumeration for a definition of valid strategy types.

    Raises:
        NotImplementedError: If the strategy cannot be found.
        ValueError: If the `strategy_type` is not a valid strategy type.
            See the [`StrategyType`][oteapi.plugins.entry_points.StrategyType]
            enumeration for a definition of valid strategy types.
        StrategiesNotLoaded: If the entry point strategies have not been loaded.

    Returns:
        An instantiated strategy. The strategy is instantiated with the provided
        configuration, through the `config` parameter.

    """
    if not hasattr(cls, "strategy_create_func"):
        raise StrategiesNotLoaded(
            "Strategies have not been loaded, run `load_strategies()` or "
            "`StrategyFactory.load_strategies()`."
        )

    if isinstance(strategy_type, str):
        try:
            strategy_type = StrategyType.init(strategy_type)
        except ValueError as exc:
            raise ValueError(
                f"Strategy type {strategy_type!r} is not supported."
            ) from exc
    elif not isinstance(strategy_type, StrategyType):
        raise TypeError(
            "strategy_type should be either of type StrategyType or a string."
        )

    strategy_name: str = cls._get_strategy_name(config, strategy_type)

    if (strategy_type, strategy_name) in cls.strategy_create_func[strategy_type]:
        return cls.strategy_create_func[strategy_type][
            (strategy_type, strategy_name)
        ].implementation(
            config  # type: ignore[arg-type]
        )
    raise NotImplementedError(
        f"The {strategy_type.value} strategy {strategy_name!r} does not exist."
    )

create_strategy(strategy_type, config)

Proxy function for StrategyFactory.make_strategy().

Parameters:

Name Type Description Default
strategy_type 'Union[StrategyType, str]'

A valid strategy type. See the StrategyType enumeration for a definition of valid strategy types.

required
config 'StrategyConfig'

A strategy configuration.

required

Returns:

Type Description
'IStrategy'

The created strategy.

Source code in oteapi/plugins/factories.py
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
def create_strategy(
    strategy_type: "Union[StrategyType, str]", config: "StrategyConfig"
) -> "IStrategy":
    """Proxy function for
    [`StrategyFactory.make_strategy()`][oteapi.plugins.factories.StrategyFactory.make_strategy].

    Parameters:
        strategy_type: A valid strategy type.
            See the [`StrategyType`][oteapi.plugins.entry_points.StrategyType] enumeration
            for a definition of valid strategy types.
        config: A strategy configuration.

    Returns:
        The created strategy.

    """
    return StrategyFactory.make_strategy(config, strategy_type)

load_strategies(test_for_uniqueness=True)

Proxy function for StrategyFactory.load_strategies().

Parameters:

Name Type Description Default
test_for_uniqueness bool

If True, this will raise KeyError should an entry point strategy be duplicated. Otherwise, the first loaded entry point strategy will silently become the implementation of choice for the duplicated strategy and the duplicates will be ignored.

True
Source code in oteapi/plugins/factories.py
143
144
145
146
147
148
149
150
151
152
153
154
155
def load_strategies(test_for_uniqueness: bool = True) -> None:
    # pylint: disable=line-too-long
    """Proxy function for
    [`StrategyFactory.load_strategies()`][oteapi.plugins.factories.StrategyFactory.load_strategies].

    Parameters:
        test_for_uniqueness: If `True`, this will raise `KeyError` should an entry
            point strategy be duplicated. Otherwise, the first loaded entry point
            strategy will silently become the implementation of choice for the
            duplicated strategy and the duplicates will be ignored.

    """
    StrategyFactory.load_strategies(test_for_uniqueness)
Back to top