From dfbac903fbc2bde2c8665ea58266ce2c97c9a3a7 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:18:18 +0000 Subject: [PATCH 1/6] chore: add warnings (#291) * chore: add warnings make IDEs signal deprecated code instead of relying on runtime logs only * update python version --- .github/workflows/license_tests.yml | 2 +- .github/workflows/publish_stable.yml | 2 +- .github/workflows/release_workflow.yml | 2 +- ovos_plugin_manager/audio.py | 1 - ovos_plugin_manager/microphone.py | 7 +- ovos_plugin_manager/stt.py | 2 +- ovos_plugin_manager/templates/stt.py | 42 +++++++++- ovos_plugin_manager/templates/tts.py | 106 +++++++++++++++++++++++++ ovos_plugin_manager/tts.py | 2 +- ovos_plugin_manager/utils/__init__.py | 7 +- 10 files changed, 164 insertions(+), 9 deletions(-) diff --git a/.github/workflows/license_tests.yml b/.github/workflows/license_tests.yml index 29f4063e..aa37e2d3 100644 --- a/.github/workflows/license_tests.yml +++ b/.github/workflows/license_tests.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v1 with: - python-version: 3.8 + python-version: '3.11' - name: Install Build Tools run: | python -m pip install build wheel diff --git a/.github/workflows/publish_stable.yml b/.github/workflows/publish_stable.yml index 34b2bd3e..5fc60fe6 100644 --- a/.github/workflows/publish_stable.yml +++ b/.github/workflows/publish_stable.yml @@ -26,7 +26,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v1 with: - python-version: 3.8 + python-version: '3.11' - name: Install Build Tools run: | python -m pip install build wheel diff --git a/.github/workflows/release_workflow.yml b/.github/workflows/release_workflow.yml index 7dc553ac..02576f54 100644 --- a/.github/workflows/release_workflow.yml +++ b/.github/workflows/release_workflow.yml @@ -46,7 +46,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v1 with: - python-version: 3.8 + python-version: '3.11' - name: Install Build Tools run: | python -m pip install build wheel diff --git a/ovos_plugin_manager/audio.py b/ovos_plugin_manager/audio.py index 370952f5..c73464c0 100644 --- a/ovos_plugin_manager/audio.py +++ b/ovos_plugin_manager/audio.py @@ -2,7 +2,6 @@ from ovos_utils.log import LOG from ovos_bus_client.util import get_mycroft_bus from ovos_config import Configuration -from ovos_utils.log import log_deprecation # TODO - restore this log in next release with updated version string diff --git a/ovos_plugin_manager/microphone.py b/ovos_plugin_manager/microphone.py index d6bc2139..2fdd8b6e 100644 --- a/ovos_plugin_manager/microphone.py +++ b/ovos_plugin_manager/microphone.py @@ -1,6 +1,6 @@ from ovos_config import Configuration from ovos_utils.log import LOG, deprecated - +import warnings from ovos_plugin_manager.templates.microphone import Microphone from ovos_plugin_manager.utils import PluginTypes @@ -31,6 +31,11 @@ def get_microphone_config(config=None): @param config: global Configuration OR plugin class-specific configuration @return: plugin class-specific configuration """ + warnings.warn( + "get_microphone_config is deprecated, use Configuration() directly", + DeprecationWarning, + stacklevel=2, + ) from ovos_plugin_manager.utils.config import get_plugin_config return get_plugin_config(config, "microphone") diff --git a/ovos_plugin_manager/stt.py b/ovos_plugin_manager/stt.py index 4cd8592c..2194c20f 100644 --- a/ovos_plugin_manager/stt.py +++ b/ovos_plugin_manager/stt.py @@ -3,7 +3,7 @@ from ovos_config import Configuration from ovos_plugin_manager.utils.config import get_valid_plugin_configs, \ sort_plugin_configs, get_plugin_config -from ovos_utils.log import LOG, log_deprecation +from ovos_utils.log import LOG from ovos_plugin_manager.templates.stt import STT, StreamingSTT, StreamThread diff --git a/ovos_plugin_manager/templates/stt.py b/ovos_plugin_manager/templates/stt.py index 4fef5dc0..51a560b7 100644 --- a/ovos_plugin_manager/templates/stt.py +++ b/ovos_plugin_manager/templates/stt.py @@ -9,7 +9,7 @@ from queue import Queue from threading import Thread, Event from typing import List, Tuple, Optional, Set, Union - +import warnings from ovos_config import Configuration from ovos_utils import classproperty from ovos_utils.lang import standardize_lang_tag @@ -78,6 +78,11 @@ def runtime_requirements(self): @deprecated("self.recognizer has been deprecated! " "if you need it 'from speech_recognition import Recognizer' directly", "1.0.0") def recognizer(self): + warnings.warn( + "use 'from speech_recognition import Recognizer' directly", + DeprecationWarning, + stacklevel=2, + ) # only imported here to not drag dependency from speech_recognition import Recognizer if not self._recognizer: @@ -103,6 +108,11 @@ def lang(self, val): @deprecated("self.keys has been deprecated! " "implement config handling directly instead", "1.0.0") def keys(self): + warnings.warn( + "self.keys has been deprecated", + DeprecationWarning, + stacklevel=2, + ) return self._keys or self.config_core.get("keys", {}) @keys.setter @@ -114,6 +124,11 @@ def keys(self, val): @deprecated("self.credential has been deprecated! " "implement config handling directly instead", "1.0.0") def credential(self): + warnings.warn( + "self.credential has been deprecated", + DeprecationWarning, + stacklevel=2, + ) return self._credential or self.config.get("credential", {}) @credential.setter @@ -125,6 +140,11 @@ def credential(self, val): @deprecated("self.init_language has been deprecated! " "implement config handling directly instead", "1.0.0") def init_language(config_core): + warnings.warn( + "implement config handling directly instead", + DeprecationWarning, + stacklevel=2, + ) lang = config_core.get("lang", "en-US") return standardize_lang_tag(lang, macro=True) @@ -158,6 +178,11 @@ def available_languages(self) -> Set[str]: class TokenSTT(STT, metaclass=ABCMeta): @deprecated("TokenSTT is deprecated, please subclass from STT directly", "1.0.0") def __init__(self, config=None): + warnings.warn( + "please subclass from STT directly", + DeprecationWarning, + stacklevel=2, + ) super().__init__(config) self.token = self.credential.get("token") @@ -165,6 +190,11 @@ def __init__(self, config=None): class GoogleJsonSTT(STT, metaclass=ABCMeta): @deprecated("GoogleJsonSTT is deprecated, please subclass from STT directly", "1.0.0") def __init__(self, config=None): + warnings.warn( + "please subclass from STT directly", + DeprecationWarning, + stacklevel=2, + ) super().__init__(config) if not self.credential.get("json") or self.keys.get("google_cloud"): self.credential["json"] = self.keys["google_cloud"] @@ -174,6 +204,11 @@ def __init__(self, config=None): class BasicSTT(STT, metaclass=ABCMeta): @deprecated("BasicSTT is deprecated, please subclass from STT directly", "1.0.0") def __init__(self, config=None): + warnings.warn( + "please subclass from STT directly", + DeprecationWarning, + stacklevel=2, + ) super().__init__(config) self.username = str(self.credential.get("username")) self.password = str(self.credential.get("password")) @@ -183,6 +218,11 @@ class KeySTT(STT, metaclass=ABCMeta): @deprecated("KeySTT is deprecated, please subclass from STT directly", "1.0.0") def __init__(self, config=None): + warnings.warn( + "please subclass from STT directly", + DeprecationWarning, + stacklevel=2, + ) super().__init__(config) self.id = str(self.credential.get("client_id")) self.key = str(self.credential.get("client_key")) diff --git a/ovos_plugin_manager/templates/tts.py b/ovos_plugin_manager/templates/tts.py index 4dbc34d8..1f60fe1a 100644 --- a/ovos_plugin_manager/templates/tts.py +++ b/ovos_plugin_manager/templates/tts.py @@ -28,6 +28,7 @@ from ovos_utils.process_utils import RuntimeRequirements from ovos_plugin_manager.utils.config import get_plugin_config from ovos_plugin_manager.utils.tts_cache import TextToSpeechCache, hash_sentence +import warnings EMPTY_PLAYBACK_QUEUE_TUPLE = (None, None, None, None, None) SSML_TAGS = re.compile(r'<[^>]*>') @@ -133,16 +134,31 @@ def curate_caches(cls): # deprecated methods @deprecated("'get_message' has been deprecated without replacement", "1.0.0") def get_message(self, kwargs) -> Optional[Message]: + warnings.warn( + "deprecated without replacement", + DeprecationWarning, + stacklevel=2, + ) msg = kwargs.get("message") or dig_for_message() if msg and isinstance(msg, Message): return msg @deprecated("'self.get_lang' has been deprecated, access self.lang directly", "1.0.0") def get_lang(self, kwargs) -> str: + warnings.warn( + "access self.lang directly", + DeprecationWarning, + stacklevel=2, + ) return kwargs.get("lang") or self.lang @deprecated("'self.get_gender' has been deprecated, access self.voice and self.lang directly", "1.0.0") def get_gender(self, kwargs) -> Optional[str]: + warnings.warn( + "access self.lang and self.voice directly", + DeprecationWarning, + stacklevel=2, + ) gender = kwargs.get("gender") message = self.get_message(kwargs) if not gender and message: @@ -152,6 +168,11 @@ def get_gender(self, kwargs) -> Optional[str]: @deprecated("'self.get_voice' has been deprecated, access self.voice directly", "1.0.0") def get_voice(self, kwargs): + warnings.warn( + "access self.voice directly", + DeprecationWarning, + stacklevel=2, + ) voice = kwargs.get("voice") message = self.get_message(kwargs) if not voice and message: @@ -162,6 +183,11 @@ def get_voice(self, kwargs): @deprecated("'self.get' has been deprecated, access self.voice and self.lang directly", "1.0.0") def get(self, kwargs=None) -> Tuple[str, Optional[str]]: + warnings.warn( + "access self.lang and self.voice directly", + DeprecationWarning, + stacklevel=2, + ) kwargs = kwargs or {} return self.get_lang(kwargs), self.get_voice(kwargs) @@ -232,11 +258,21 @@ def __init__(self, lang=None, config=None, validator=None, @property def g2p(self) -> None: + warnings.warn( + "moved to PlaybackThread in ovos-audio", + DeprecationWarning, + stacklevel=2, + ) log_deprecation("G2P plugins moved to PlaybackThread in ovos-audio, self.g2p is deprecated!", "1.0.0") return None @g2p.setter def g2p(self, val): + warnings.warn( + "moved to PlaybackThread in ovos-audio", + DeprecationWarning, + stacklevel=2, + ) log_deprecation("G2P plugins moved to PlaybackThread in ovos-audio, self.g2p is deprecated!", "1.0.0") @property @@ -743,6 +779,11 @@ def enclosure(self): Returns: EnclosureAPI: The EnclosureAPI instance associated with the TTS playback. """ + warnings.warn( + "use EnclosureAPI directly", + DeprecationWarning, + stacklevel=2, + ) if not TTS.playback.enclosure: bus = TTS.playback.bus or self.bus TTS.playback.enclosure = EnclosureAPI(bus) @@ -757,6 +798,11 @@ def enclosure(self, val): Arguments: val (EnclosureAPI): The EnclosureAPI instance to set. """ + warnings.warn( + "use EnclosureAPI directly", + DeprecationWarning, + stacklevel=2, + ) TTS.playback.enclosure = val @property @@ -768,6 +814,11 @@ def filename(self): Returns: str: The filename for the TTS audio. """ + warnings.warn( + "deprecated without replacement", + DeprecationWarning, + stacklevel=2, + ) cache_dir = get_cache_directory(self.tts_name) return join(cache_dir, 'tts.' + self.audio_ext) @@ -780,6 +831,11 @@ def filename(self, val): Arguments: val (str): The filename to set. """ + warnings.warn( + "deprecated without replacement", + DeprecationWarning, + stacklevel=2, + ) @property @deprecated("self.tts_id has been deprecated, use TTSContext().tts_id", @@ -790,6 +846,11 @@ def tts_id(self): Returns: str: The ID associated with the TTS context. """ + warnings.warn( + "use TTSContext().tts_id", + DeprecationWarning, + stacklevel=2, + ) return self._get_ctxt().tts_id @property @@ -801,6 +862,11 @@ def cache(self): Returns: TextToSpeechCache: The cache associated with the TTS context. """ + warnings.warn( + "use TTSContext().get_cache", + DeprecationWarning, + stacklevel=2, + ) return TTSContext._caches.get(self.tts_id) or \ self.get_cache() @@ -813,6 +879,11 @@ def cache(self, val): Arguments: val (TextToSpeechCache): The cache to set. """ + warnings.warn( + "use TTSContext().get_cache", + DeprecationWarning, + stacklevel=2, + ) TTSContext._caches[self.tts_id] = val @deprecated("get_voice was never formally adopted and is unused, it will be removed", @@ -827,6 +898,11 @@ def get_voice(self, gender, lang=None): Returns: str: The selected voice. """ + warnings.warn( + "deprecated without replacement", + DeprecationWarning, + stacklevel=2, + ) return gender @deprecated("get_cache has been deprecated, use TTSContext().get_cache directly", @@ -841,12 +917,22 @@ def get_cache(self, voice=None, lang=None): Returns: TextToSpeechCache: The cache associated with the TTS context. """ + warnings.warn( + "use TTSContext().get_cache", + DeprecationWarning, + stacklevel=2, + ) return self._get_ctxt().get_cache(self.audio_ext, self.config) @deprecated("clear_cache has been deprecated, use TTSContext().get_cache directly", "1.0.0") def clear_cache(self): """Deprecated. Clear all cached files.""" + warnings.warn( + "use TTSContext().get_cache", + DeprecationWarning, + stacklevel=2, + ) cache = self._get_ctxt().get_cache(self.audio_ext, self.config) cache.clear() @@ -862,6 +948,11 @@ def save_phonemes(self, key, phonemes): Returns: PhonemeFile: The PhonemeFile instance. """ + warnings.warn( + "use TTSContext().get_cache", + DeprecationWarning, + stacklevel=2, + ) cache = self._get_ctxt().get_cache(self.audio_ext, self.config) phoneme_file = cache.define_phoneme_file(key) phoneme_file.save(phonemes) @@ -878,6 +969,11 @@ def load_phonemes(self, key): Returns: str: Phonemes loaded from the cache file. """ + warnings.warn( + "use TTSContext().get_cache", + DeprecationWarning, + stacklevel=2, + ) cache = self._get_ctxt().get_cache(self.audio_ext, self.config) phoneme_file = cache.define_phoneme_file(key) return phoneme_file.load() @@ -893,6 +989,11 @@ def get_from_cache(self, sentence): Returns: tuple: Tuple containing the audio and phonemes. """ + warnings.warn( + "use TTSContext().get_cache", + DeprecationWarning, + stacklevel=2, + ) return self._get_ctxt().get_from_cache(sentence, self.audio_ext, self.config) @property @@ -1191,6 +1292,11 @@ class RemoteTTS(TTS): @deprecated("RemoteTTS has been deprecated, please use the regular TTS class", "1.0.0") def __init__(self, lang, config, url, api_path, validator): + warnings.warn( + "please subclass from TTS directly", + DeprecationWarning, + stacklevel=2, + ) super(RemoteTTS, self).__init__(lang, config, validator) self.api_path = api_path self.auth = None diff --git a/ovos_plugin_manager/tts.py b/ovos_plugin_manager/tts.py index 31f2eb47..7d4d0671 100644 --- a/ovos_plugin_manager/tts.py +++ b/ovos_plugin_manager/tts.py @@ -6,7 +6,7 @@ PluginConfigTypes from ovos_plugin_manager.utils.config import get_valid_plugin_configs, \ sort_plugin_configs, get_plugin_config -from ovos_utils.log import LOG, log_deprecation +from ovos_utils.log import LOG from ovos_utils.xdg_utils import xdg_data_home from hashlib import md5 diff --git a/ovos_plugin_manager/utils/__init__.py b/ovos_plugin_manager/utils/__init__.py index f8219305..ceeeae20 100644 --- a/ovos_plugin_manager/utils/__init__.py +++ b/ovos_plugin_manager/utils/__init__.py @@ -16,7 +16,7 @@ from enum import Enum from threading import Event, Lock from typing import Optional - +import warnings import pkg_resources from ovos_utils.log import LOG, log_deprecation, deprecated @@ -178,6 +178,11 @@ def load_plugin(plug_name: str, plug_type: Optional[PluginTypes] = None): @deprecated("normalize_lang has been deprecated! update to 'from ovos_utils.lang import standardize_lang_tag'", "1.0.0") def normalize_lang(lang): + warnings.warn( + "update to 'from ovos_utils.lang import standardize_lang_tag'", + DeprecationWarning, + stacklevel=2, + ) from ovos_utils.lang import standardize_lang_tag return standardize_lang_tag(lang) From ac90132dc7ba3bac4db084720221bdb1da2e06d8 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 4 Jan 2025 17:18:32 +0000 Subject: [PATCH 2/6] Increment Version to 0.7.1a1 --- ovos_plugin_manager/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ovos_plugin_manager/version.py b/ovos_plugin_manager/version.py index 9806c342..24064967 100644 --- a/ovos_plugin_manager/version.py +++ b/ovos_plugin_manager/version.py @@ -1,6 +1,6 @@ # START_VERSION_BLOCK VERSION_MAJOR = 0 VERSION_MINOR = 7 -VERSION_BUILD = 0 -VERSION_ALPHA = 0 +VERSION_BUILD = 1 +VERSION_ALPHA = 1 # END_VERSION_BLOCK From e24281bdde4bbf379a3b71560b2ff1ac6d4c061d Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 4 Jan 2025 17:19:01 +0000 Subject: [PATCH 3/6] Update Changelog --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da95e149..3ca08332 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,12 @@ # Changelog -## [0.7.0a1](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/0.7.0a1) (2024-11-24) +## [0.7.1a1](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/0.7.1a1) (2025-01-04) -[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/0.6.0...0.7.0a1) +[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/0.7.0...0.7.1a1) **Merged pull requests:** -- feat: STT lang detector [\#289](https://github.com/OpenVoiceOS/ovos-plugin-manager/pull/289) ([JarbasAl](https://github.com/JarbasAl)) +- chore: add warnings [\#291](https://github.com/OpenVoiceOS/ovos-plugin-manager/pull/291) ([JarbasAl](https://github.com/JarbasAl)) From d49e0edce597ca3272dcfe5f9455bdf63285f247 Mon Sep 17 00:00:00 2001 From: JarbasAI <33701864+JarbasAl@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:56:42 +0000 Subject: [PATCH 4/6] fix log spam (#293) * rm scary warning * fix:logspam --- .github/workflows/build_tests.yml | 2 +- .github/workflows/pipaudit.yml | 2 +- .github/workflows/unit_tests.yml | 2 +- ovos_plugin_manager/templates/media.py | 2 +- ovos_plugin_manager/templates/solvers.py | 3 ++- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_tests.yml b/.github/workflows/build_tests.yml index 686d91da..378eec37 100644 --- a/.github/workflows/build_tests.yml +++ b/.github/workflows/build_tests.yml @@ -24,7 +24,7 @@ jobs: strategy: max-parallel: 2 matrix: - python-version: [ 3.7, 3.8, 3.9, "3.10" ] + python-version: [3.9, "3.10", "3.11"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/pipaudit.yml b/.github/workflows/pipaudit.yml index 9f2f3fbf..47a05e99 100644 --- a/.github/workflows/pipaudit.yml +++ b/.github/workflows/pipaudit.yml @@ -11,7 +11,7 @@ jobs: strategy: max-parallel: 2 matrix: - python-version: [ 3.7, 3.8, 3.9, "3.10" ] + python-version: [3.9, "3.10", "3.11"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 69a78d3a..2134dd2b 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -33,7 +33,7 @@ jobs: strategy: max-parallel: 2 matrix: - python-version: [ 3.8, 3.9, "3.10" ] + python-version: [3.9, "3.10", "3.11"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/ovos_plugin_manager/templates/media.py b/ovos_plugin_manager/templates/media.py index 85e25381..f769b613 100644 --- a/ovos_plugin_manager/templates/media.py +++ b/ovos_plugin_manager/templates/media.py @@ -2,7 +2,7 @@ from ovos_bus_client.message import Message from ovos_utils.log import LOG -from ovos_utils.messagebus import FakeBus +from ovos_utils.fakebus import FakeBus from ovos_utils.ocp import MediaState, PlayerState, TrackState diff --git a/ovos_plugin_manager/templates/solvers.py b/ovos_plugin_manager/templates/solvers.py index 3c04b5ed..bcf3a58e 100644 --- a/ovos_plugin_manager/templates/solvers.py +++ b/ovos_plugin_manager/templates/solvers.py @@ -494,7 +494,8 @@ def retrieve_from_corpus(self, query: str, k: int = 3, lang: Optional[str] = Non """return top_k matches from indexed corpus""" res = [] for doc, score in self.query(query, lang, k=k): - LOG.debug(f"Rank {len(res) + 1} (score: {score}): {doc}") + # this log can be very spammy, only enable for debug during dev + #LOG.debug(f"Rank {len(res) + 1} (score: {score}): {doc}") if self.config.get("min_conf"): if score >= self.config["min_conf"]: res.append((score, doc)) From 3dfd72ad9cee7770225c807e3413613e502eb431 Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 4 Jan 2025 23:56:56 +0000 Subject: [PATCH 5/6] Increment Version to 0.7.1a2 --- ovos_plugin_manager/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ovos_plugin_manager/version.py b/ovos_plugin_manager/version.py index 24064967..e19b31dd 100644 --- a/ovos_plugin_manager/version.py +++ b/ovos_plugin_manager/version.py @@ -2,5 +2,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 7 VERSION_BUILD = 1 -VERSION_ALPHA = 1 +VERSION_ALPHA = 2 # END_VERSION_BLOCK From a665bd1d90f1651a7a0856a10aa42acae41b5dab Mon Sep 17 00:00:00 2001 From: JarbasAl Date: Sat, 4 Jan 2025 23:57:25 +0000 Subject: [PATCH 6/6] Update Changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ca08332..2c29b356 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.7.1a2](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/0.7.1a2) (2025-01-04) + +[Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/0.7.1a1...0.7.1a2) + +**Merged pull requests:** + +- fix log spam [\#293](https://github.com/OpenVoiceOS/ovos-plugin-manager/pull/293) ([JarbasAl](https://github.com/JarbasAl)) + ## [0.7.1a1](https://github.com/OpenVoiceOS/ovos-plugin-manager/tree/0.7.1a1) (2025-01-04) [Full Changelog](https://github.com/OpenVoiceOS/ovos-plugin-manager/compare/0.7.0...0.7.1a1)