Skip to content

medcat.plugins.catalog

Management of the curated plugin catalog.

Classes:

Functions:

  • get_catalog

    Get the global plugin catalog instance.

Attributes:

LOCAL_CATALOG_PATH module-attribute

LOCAL_CATALOG_PATH = files('medcat.plugins.data') / 'plugin_catalog.json'

logger module-attribute

logger = getLogger(__name__)

CatalogModel

Bases: BaseModel

Pydantic model for the top-level catalog JSON.

Methods:

  • merge

    Merge another catalog into this one.

Attributes:

last_updated instance-attribute

last_updated: str

plugins class-attribute instance-attribute

plugins: dict[str, PluginInfo] = Field(default_factory=dict)

version instance-attribute

version: str

merge

merge(other: CatalogModel, prefer_other: bool = True) -> None

Merge another catalog into this one.

Parameters:

  • other

    (CatalogModel) –

    The other catalog to merge.

  • prefer_other

    (bool, default: True ) –

    Whether to prefer other. Defaults to True.

Source code in medcat-v2/medcat/plugins/catalog.py
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def merge(self, other: 'CatalogModel', prefer_other: bool = True) -> None:
    """Merge another catalog into this one.

    Args:
        other (CatalogModel): The other catalog to merge.
        prefer_other (bool): Whether to prefer other. Defaults to True.
    """
    if prefer_other:
        self.version = other.version
        self.last_updated = other.last_updated
    for plugin_name, info in other.plugins.items():
        if plugin_name not in self.plugins:
            self.plugins[plugin_name] = info
        elif prefer_other:
            self.plugins[plugin_name].merge(info, prefer_other=prefer_other)

NoCompatibleSpecException

NoCompatibleSpecException(plugin: PluginInfo, medcat_ver: Version)

Bases: ValueError

Source code in medcat-v2/medcat/plugins/catalog.py
229
230
231
232
233
def __init__(self, plugin: PluginInfo, medcat_ver: Version) -> None:
    super().__init__(
        f"Was unable to find a version of the plugin {plugin.name} "
        f"that was compatible with MedCAT version {medcat_ver}. "
        f"Plugin details: {plugin}")

NoSuchPluginException

NoSuchPluginException(plugin_name: str)

Bases: ValueError

Source code in medcat-v2/medcat/plugins/catalog.py
222
223
224
def __init__(self, plugin_name: str) -> None:
    super().__init__(
        f"No plugin by the name '{plugin_name}' is known to MedCAT")

PluginCatalog

PluginCatalog(use_remote: bool = True)

Manages the catalog of curated plugins.

Initialize the plugin catalog.

Parameters:

  • use_remote

    (bool, default: True ) –

    Whether to attempt fetching the remote catalog

Methods:

Attributes:

Source code in medcat-v2/medcat/plugins/catalog.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def __init__(self, use_remote: bool = True):
    """
    Initialize the plugin catalog.

    Args:
        use_remote: Whether to attempt fetching the remote catalog
    """
    self._catalog: CatalogModel = CatalogModel(
        version="N/A", last_updated='N/A', plugins={})
    self._load_local_catalog()
    if use_remote:
        try:
            self._update_from_remote()
        except Exception as e:
            logger.debug(f"Could not fetch remote catalog: {e}")

REMOTE_CATALOG_URL class-attribute instance-attribute

REMOTE_CATALOG_URL = 'https://raw.githubusercontent.com/CogStack/cogstack-nlp/main/medcat-v2/medcat/plugins/data/plugin_catalog.json'

get_compatible_version

get_compatible_version(plugin_name: str, medcat_version: str) -> str

Get compatible plugin version for given MedCAT version.

Parameters:

  • plugin_name

    (str) –

    Name of the plugin

  • medcat_version

    (str) –

    MedCAT version string

Raises:

Returns:

  • str

    Compatible version specifier

Source code in medcat-v2/medcat/plugins/catalog.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
def get_compatible_version(
    self, 
    plugin_name: str, 
    medcat_version: str
) -> str:
    """
    Get compatible plugin version for given MedCAT version.

    Args:
        plugin_name: Name of the plugin
        medcat_version: MedCAT version string

    Raises:
        NoSuchPluginException: If the plugin wasn't found / known.
        NoCompatibleSpecException: If compatibility spec was unable to be met.

    Returns:
        Compatible version specifier
    """
    plugin = self.get_plugin(plugin_name)
    if not plugin:
        raise NoSuchPluginException(plugin_name)

    medcat_ver = Version(medcat_version)

    for compat in plugin.compatibility:
        spec = SpecifierSet(compat.medcat_version)
        if medcat_ver in spec:
            return compat.plugin_version

    raise NoCompatibleSpecException(plugin, medcat_ver)

get_plugin

get_plugin(name: str) -> Optional[PluginInfo]

Get plugin info by name.

Source code in medcat-v2/medcat/plugins/catalog.py
158
159
160
161
162
163
164
def get_plugin(self, name: str) -> Optional[PluginInfo]:
    """Get plugin info by name."""
    plugin = self._catalog.plugins.get(name)
    if plugin:
        return plugin
    # try lower case and with "-" instead of "_"
    return self._catalog.plugins.get(name.lower().replace("_", "-"))

is_curated

is_curated(name: str) -> bool

Check if a plugin is in the curated catalog.

Source code in medcat-v2/medcat/plugins/catalog.py
171
172
173
def is_curated(self, name: str) -> bool:
    """Check if a plugin is in the curated catalog."""
    return name in self._catalog.plugins

list_plugins

list_plugins() -> list[PluginInfo]

List all available plugins.

Source code in medcat-v2/medcat/plugins/catalog.py
167
168
169
def list_plugins(self) -> list[PluginInfo]:
    """List all available plugins."""
    return list(self._catalog.plugins.values())

PluginCompatibility

Bases: BaseModel

Attributes:

medcat_version instance-attribute

medcat_version: str

plugin_version instance-attribute

plugin_version: str

PluginInfo

Bases: BaseModel

Methods:

  • can_merge

    Checks if 2 plugin infos can be merged.

  • merge

    Merge other plugin info into this one.

Attributes:

compatibility instance-attribute

compatibility: list[PluginCompatibility]

description instance-attribute

description: str

display_name instance-attribute

display_name: str

homepage instance-attribute

homepage: str

name instance-attribute

name: str

requires_auth class-attribute instance-attribute

requires_auth: bool = False

source_spec instance-attribute

source_spec: PluginSourceSpec

can_merge

can_merge(other: PluginInfo) -> bool

Checks if 2 plugin infos can be merged.

This checks to make sure the name and the source spec is the same. In that case the two objects likely refer to the same plugin. But one might have updated information.

Parameters:

Returns:

  • bool ( bool ) –

    Whether they can be merged.

Source code in medcat-v2/medcat/plugins/catalog.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def can_merge(self, other: 'PluginInfo') -> bool:
    """Checks if 2 plugin infos can be merged.

    This checks to make sure the name and the source spec is the same.
    In that case the two objects likely refer to the same plugin. But
    one might have updated information.

    Args:
        other (PluginInfo): The other plugin info.

    Returns:
        bool: Whether they can be merged.
    """
    return (
        self.name == other.name and
        self.source_spec == other.source_spec)

merge

merge(other: PluginInfo, prefer_other: bool = True) -> None

Merge other plugin info into this one.

Normally it is likely the "other" plugin info is newer so we want to prefer its data if/when possible.

Parameters:

  • other

    (PluginInfo) –

    The other plugin info.

  • prefer_other

    (bool, default: True ) –

    Whether to prefer other. Defaults to True.

Raises:

Source code in medcat-v2/medcat/plugins/catalog.py
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
def merge(self, other: 'PluginInfo', prefer_other: bool = True) -> None:
    """Merge other plugin info into this one.

    Normally it is likely the "other" plugin info is newer so we want to
    prefer its data if/when possible.

    Args:
        other (PluginInfo): The other plugin info.
        prefer_other (bool): Whether to prefer other. Defaults to True.

    Raises:
        UnmergablePluginInfo: If the infos cannot be merged.
    """
    if not self.can_merge(other):
        raise UnmergablePluginInfo(self, other)
    if prefer_other:
        self.display_name = other.display_name
        self.description = other.description
        self.homepage = other.homepage
        self.requires_auth = other.requires_auth
    existing_plugin_versions = {cur.plugin_version for cur in self.compatibility}
    for other_comp in other.compatibility:
        if other_comp.plugin_version not in existing_plugin_versions:
            self.compatibility.append(other_comp)
        elif prefer_other:
            prev_index = [idx for idx, cur in enumerate(self.compatibility)
                          if cur.plugin_version == other_comp.plugin_version][0]
            self.compatibility[prev_index] = other_comp

UnmergablePluginInfo

UnmergablePluginInfo(info1: PluginInfo, info2: PluginInfo)

Bases: ValueError

Source code in medcat-v2/medcat/plugins/catalog.py
238
239
240
241
242
def __init__(self, info1: PluginInfo, info2: PluginInfo) -> None:
    super().__init__(
        "The two plugin infos cannot be merged:\n"
        f"One:\n{info1}\nand two:\n{info2}"
    )

get_catalog

get_catalog() -> PluginCatalog

Get the global plugin catalog instance.

Source code in medcat-v2/medcat/plugins/catalog.py
212
213
214
215
216
217
def get_catalog() -> PluginCatalog:
    """Get the global plugin catalog instance."""
    global _catalog
    if _catalog is None:
        _catalog = PluginCatalog()
    return _catalog