Repository: OpenVoiceOS/ovos-core (language: python)

Issue:
Update ovos-skill-homescreen requirement from <3.0.0,>=1.0.4 to >=1.0.4,<4.0.0 in /requirements
Updates the requirements on [ovos-skill-homescreen](https://github.com/OpenVoiceOS/skill-ovos-homescreen) to permit the latest version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/OpenVoiceOS/skill-ovos-homescreen/releases">ovos-skill-homescreen's releases</a>.</em></p>
<blockquote>
<h2>3.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: restore randomize examples setting by <a href="https://github.com/JarbasAl"><code>@​JarbasAl</code></a> in <a href="https://redirect.github.com/OpenVoiceOS/skill-ovos-homescreen/pull/140">OpenVoiceOS/skill-ovos-homescreen#140</a></li>
<li>Release 3.0.1a1 by <a href="https://github.com/github-actions"><code>@​github-actions</code></a> in <a href="https://redirect.github.com/OpenVoiceOS/skill-ovos-homescreen/pull/141">OpenVoiceOS/skill-ovos-homescreen#141</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/OpenVoiceOS/skill-ovos-homescreen/compare/3.0.0...3.0.1">https://github.com/OpenVoiceOS/skill-ovos-homescreen/compare/3.0.0...3.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/blob/dev/CHANGELOG.md">ovos-skill-homescreen's changelog</a>.</em></p>
<blockquote>
<h2><a href="https://github.com/OpenVoiceOS/skill-ovos-homescreen/tree/3.0.1a1">3.0.1a1</a> (2024-11-17)</h2>
<p><a href="https://github.com/OpenVoiceOS/skill-ovos-homescreen/compare/3.0.0...3.0.1a1">Full Changelog</a></p>
<p><strong>Merged pull requests:</strong></p>
<ul>
<li>fix: restore randomize examples setting <a href="https://redirect.github.com/OpenVoiceOS/skill-ovos-homescreen/pull/140">#140</a> (<a href="https://github.com/JarbasAl">JarbasAl</a>)</li>
</ul>
<p>* <em>This Changelog was automatically generated by <a href="https://github.com/github-changelog-generator/github-changelog-generator">github_changelog_generator</a></em></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/c169aac9d02520d2cbd3e7c8c49689506bc4d799"><code>c169aac</code></a> Increment Version to 3.0.1</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/433ced2ef81ae877c189e89ce250a2716409f1f2"><code>433ced2</code></a> Merge pull request <a href="https://redirect.github.com/OpenVoiceOS/skill-ovos-homescreen/issues/141">#141</a> from OpenVoiceOS/release-3.0.1a1</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/afbdb2e1b6fc822132ef33fad8eda53d3ca87989"><code>afbdb2e</code></a> Update Changelog</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/0dc119772be70defb7bcbab39463479036ec53c1"><code>0dc1197</code></a> Increment Version to 3.0.1a1</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/741250a0a5d227a36c1b94523a45b56f2d48e58d"><code>741250a</code></a> fix: restore randomize examples setting (<a href="https://redirect.github.com/OpenVoiceOS/skill-ovos-homescreen/issues/140">#140</a>)</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/466238459ef3991eb04b7cfb782770e14ffa179c"><code>4662384</code></a> Increment Version to 3.0.0</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/e0c20fc4feb29d5d070beb0f2d659cddf6dd393b"><code>e0c20fc</code></a> Merge pull request <a href="https://redirect.github.com/OpenVoiceOS/skill-ovos-homescreen/issues/139">#139</a> from OpenVoiceOS/release-3.0.0a1</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/cbe8adc75c55591928f165e11933a5cf7ffca49b"><code>cbe8adc</code></a> Update Changelog</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/a6a8a3b9daf37780f6a5131ecf0e0e417d214e98"><code>a6a8a3b</code></a> Increment Version to 3.0.0a1</li>
<li><a href="https://github.com/OpenVoiceOS/ovos-skill-homescreen/commit/1d1e5fcd1ed41ddde794439ae557b01a3494fd73"><code>1d1e5fc</code></a> fix!: remove screenshot intent (<a href="https://redirect.github.com/OpenVoiceOS/skill-ovos-homescreen/issues/138">#138</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/OpenVoiceOS/skill-ovos-homescreen/compare/1.0.4...3.0.1">compare view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ec0e5f9552..cd2f3b346ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,20 +1,20 @@
 # Changelog
 
-## [0.2.11a2](https://github.com/OpenVoiceOS/ovos-core/tree/0.2.11a2) (2024-11-15)
+## [0.2.13a1](https://github.com/OpenVoiceOS/ovos-core/tree/0.2.13a1) (2024-11-19)
 
-[Full Changelog](https://github.com/OpenVoiceOS/ovos-core/compare/0.2.11a1...0.2.11a2)
+[Full Changelog](https://github.com/OpenVoiceOS/ovos-core/compare/0.2.12a1...0.2.13a1)
 
 **Merged pull requests:**
 
-- fix: Update skills-gui.txt [\#597](https://github.com/OpenVoiceOS/ovos-core/pull/597) ([JarbasAl](https://github.com/JarbasAl))
+- deprecate!:backend client [\#604](https://github.com/OpenVoiceOS/ovos-core/pull/604) ([JarbasAl](https://github.com/JarbasAl))
 
-## [0.2.11a1](https://github.com/OpenVoiceOS/ovos-core/tree/0.2.11a1) (2024-11-12)
+## [0.2.12a1](https://github.com/OpenVoiceOS/ovos-core/tree/0.2.12a1) (2024-11-18)
 
-[Full Changelog](https://github.com/OpenVoiceOS/ovos-core/compare/0.2.10...0.2.11a1)
+[Full Changelog](https://github.com/OpenVoiceOS/ovos-core/compare/0.2.11...0.2.12a1)
 
 **Merged pull requests:**
 
-- Update combo-lock requirement from \<0.3,\>=0.2.2 to \>=0.2.2,\<0.4 in /requirements [\#585](https://github.com/OpenVoiceOS/ovos-core/pull/585) ([dependabot[bot]](https://github.com/apps/dependabot))
+- Update ovos-skill-homescreen requirement from \<3.0.0,\>=1.0.4 to \>=1.0.4,\<4.0.0 in /requirements [\#602](https://github.com/OpenVoiceOS/ovos-core/pull/602) ([dependabot[bot]](https://github.com/apps/dependabot))
 
 
 
diff --git a/mycroft/skills/settings.py b/mycroft/skills/settings.py
index b8d6fe218af..838486831de 100644
--- a/mycroft/skills/settings.py
+++ b/mycroft/skills/settings.py
@@ -57,17 +57,207 @@
 """
 import json
 from os.path import isfile
-import yaml
-
 from threading import Timer
+from typing import Optional
+
+import yaml
 from ovos_backend_client.api import DeviceApi
 from ovos_backend_client.pairing import is_paired, requires_backend
-from ovos_utils.log import LOG
 from ovos_backend_client.settings import RemoteSkillSettings, get_display_name
+
 from ovos_bus_client.message import Message, dig_for_message
+from ovos_utils.log import LOG
 
 # backwards compat imports
 from mycroft.deprecated.skills.settings import SkillSettingsDownloader, SettingsMetaUploader, load_remote_settings_cache, \
     save_remote_settings_cache, REMOTE_CACHE
 
-from ovos_workshop.settings import SkillSettingsManager
+
+class SkillSettingsManager:
+    def __init__(self, skill):
+        self.download_timer: Optional[Timer] = None
+        self.skill = skill
+        self.api = DeviceApi()
+        self.remote_settings = \
+            RemoteSkillSettings(self.skill_id,
+                                settings=dict(self.skill.settings),
+                                meta=self.load_meta(), remote_id=self.skill_gid)
+        self.register_bus_handlers()
+
+    def start(self):
+        self._download()
+
+    def _download(self):
+        # If this method is called outside of the timer loop, ensure the
+        # existing timer is canceled before starting a new one.
+        if self.download_timer:
+            self.download_timer.cancel()
+
+        self.download()
+
+        # prepare to download again in 60 seconds
+        self.download_timer = Timer(60, self._download)
+        self.download_timer.daemon = True
+        self.download_timer.start()
+
+    def stop(self):
+        # If this method is called outside of the timer loop, ensure the
+        # existing timer is canceled
+        if self.download_timer:
+            self.download_timer.cancel()
+
+    @property
+    def bus(self):
+        return self.skill.bus
+
+    @property
+    def skill_id(self) -> str:
+        return self.skill.skill_id
+
+    @property
+    def display_name(self) -> str:
+        return get_display_name(self.skill_id)
+
+    @property
+    def skill_gid(self) -> str:
+        return f"@{self.api.uuid}|{self.skill_id}"
+
+    @property
+    def skill_meta(self) -> dict:
+        return self.remote_settings.meta
+
+    def register_bus_handlers(self):
+        self.skill.add_event('mycroft.skills.settings.update',
+                             self.handle_download_remote)  # backwards compat
+        self.skill.add_event('mycroft.skills.settings.download',
+                             self.handle_download_remote)
+        self.skill.add_event('mycroft.skills.settings.upload',
+                             self.handle_upload_local)
+        self.skill.add_event('mycroft.skills.settings.upload.meta',
+                             self.handle_upload_meta)
+        self.skill.add_event('mycroft.paired',
+                             self.handle_upload_local)
+
+    def load_meta(self) -> dict:
+        json_path = f"{self.skill.root_dir}/settingsmeta.json"
+        yaml_path = f"{self.skill.root_dir}/settingsmeta.yaml"
+        if isfile(yaml_path):
+            with open(yaml_path) as meta_file:
+                return yaml.safe_load(meta_file)
+        elif isfile(json_path):
+            with open(json_path) as meta_file:
+                return json.load(meta_file)
+        return {}
+
+    def save_meta(self, generate: bool = False):
+        # unset reload flag to avoid a reload on settingmeta change
+        # TODO - support for settingsmeta XDG paths
+        reload = self.skill.reload_skill
+        self.skill.reload_skill = False
+
+        # generate meta for missing fields
+        if generate:
+            self.remote_settings.generate_meta()
+
+        # write to disk
+        json_path = f"{self.skill.root_dir}/settingsmeta.json"
+        yaml_path = f"{self.skill.root_dir}/settingsmeta.yaml"
+        if isfile(yaml_path):
+            with open(yaml_path) as meta_file:
+                yaml.dump(self.remote_settings.meta, meta_file)
+        else:
+            with open(json_path, "w") as meta_file:
+                json.dump(self.remote_settings.meta, meta_file)
+
+        # reset reloading flag
+        self.skill.reload_skill = reload
+
+    @requires_backend
+    def upload(self, generate: bool = False):
+        if not is_paired():
+            LOG.debug("Device needs to be paired to upload settings")
+            return
+        self.remote_settings.settings = dict(self.skill.settings)
+        if generate:
+            self.remote_settings.generate_meta()
+        self.remote_settings.upload()
+
+    @requires_backend
+    def upload_meta(self, generate: bool = False):
+        if not is_paired():
+            LOG.debug("Device needs to be paired to upload settingsmeta")
+            return
+        if generate:
+            self.remote_settings.settings = dict(self.skill.settings)
+            self.remote_settings.generate_meta()
+        self.remote_settings.upload_meta()
+
+    @requires_backend
+    def download(self):
+        if not is_paired():
+            LOG.debug("Device needs to be paired to download remote settings")
+            return
+        self.remote_settings.download()
+        # we do not update skill object settings directly
+        # skill will handle the event and trigger a callback
+        if self.skill.settings != self.remote_settings.settings:
+            # dig old message to keep context
+            msg = dig_for_message() or Message("")
+            msg = msg.forward('mycroft.skills.settings.changed')
+
+            msg.data[self.skill_id] = self.remote_settings.settings
+            self.bus.emit(msg)
+
+    def handle_upload_meta(self, message: Message):
+        skill_id = message.data.get("skill_id")
+        if skill_id == self.skill_id:
+            self.upload_meta()
+
+    def handle_upload_local(self, message: Message):
+        skill_id = message.data.get("skill_id")
+        if skill_id == self.skill_id:
+            self.upload()
+
+    def handle_download_remote(self, message: Message):
+        self.download()
+
+
+def settings2meta(settings, section_name="Skill Settings"):
+    """ generates basic settingsmeta """
+    fields = []
+
+    for k, v in settings.items():
+        if k.startswith("_"):
+            continue
+        label = k.replace("-", " ").replace("_", " ").title()
+        if isinstance(v, bool):
+            fields.append({
+                "name": k,
+                "type": "checkbox",
+                "label": label,
+                "value": str(v).lower()
+            })
+        if isinstance(v, str):
+            fields.append({
+                "name": k,
+                "type": "text",
+                "label": label,
+                "value": v
+            })
+        if isinstance(v, int):
+            fields.append({
+                "name": k,
+                "type": "number",
+                "label": label,
+                "value": str(v)
+            })
+    return {
+        "skillMetadata": {
+            "sections": [
+                {
+                    "name": section_name,
+                    "fields": fields
+                }
+            ]
+        }
+    }
diff --git a/ovos_core/version.py b/ovos_core/version.py
index b355c2ea009..7fe500eef3b 100644
--- a/ovos_core/version.py
+++ b/ovos_core/version.py
@@ -1,8 +1,8 @@
 # START_VERSION_BLOCK
 VERSION_MAJOR = 0
 VERSION_MINOR = 2
-VERSION_BUILD = 11
-VERSION_ALPHA = 0
+VERSION_BUILD = 13
+VERSION_ALPHA = 1
 # END_VERSION_BLOCK
 
 # for compat with old imports
diff --git a/requirements/extra-deprecated.txt b/requirements/extra-deprecated.txt
index daf18d98f76..3c7bdc0d448 100644
--- a/requirements/extra-deprecated.txt
+++ b/requirements/extra-deprecated.txt
@@ -9,6 +9,7 @@ pillow>=8.3
 pyaudio
 
 # mycroft-core imports / default plugins
+ovos-backend-client>=0.1.0,<2.0.0
 # for compat with mycroft namespace
 ovos-lingua-franca>=0.4.7,<1.0.0
 # NOTE: ovos-listener is causing conflicts in dependency resolution, blocks ovos-bus-client 1.0.0
diff --git a/requirements/lgpl.txt b/requirements/lgpl.txt
index cf36b2b4d27..51004877834 100644
--- a/requirements/lgpl.txt
+++ b/requirements/lgpl.txt
@@ -1,2 +1,2 @@
-ovos_padatious>=1.0.3, <2.0.0
+ovos_padatious>=1.0.4, <2.0.0
 fann2>=1.0.7, < 1.1.0
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index 406589c66d5..21591cb0cec 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -4,13 +4,12 @@ watchdog>=2.1, <3.0
 combo-lock>=0.2.2, <0.4
 
 padacioso>=1.0.0, <2.0.0
-ovos-adapt-parser>=1.0.4, <2.0.0
-ovos_ocp_pipeline_plugin>=1.0.5, <2.0.0
-ovos-common-query-pipeline-plugin>=1.0.4, <2.0.0
+ovos-adapt-parser>=1.0.5, <2.0.0
+ovos_ocp_pipeline_plugin>=1.0.7, <2.0.0
+ovos-common-query-pipeline-plugin>=1.0.5, <2.0.0
 
 ovos-utils>=0.3.5,<1.0.0
 ovos_bus_client>=0.1.4,<2.0.0
 ovos-plugin-manager>=0.5.6,<1.0.0
-ovos-config>=0.0.13,<1.0.0
-ovos-backend-client>=0.1.0,<2.0.0
-ovos-workshop>=2.2.2,<3.0.0
+ovos-config>=0.0.13,<2.0.0
+ovos-workshop>=3.0.1,<4.0.0
diff --git a/requirements/skills-audio.txt b/requirements/skills-audio.txt
index 123c65b9007..3ccf0f146f6 100644
--- a/requirements/skills-audio.txt
+++ b/requirements/skills-audio.txt
@@ -1,7 +1,7 @@
 # skills that run in audio enabled devices (require mic/speaker)
-ovos-skill-boot-finished>=0.4.4,<1.0.0
-ovos-skill-audio-recording>=0.2.2,<1.0.0
-ovos-skill-dictation>=0.2.1,<1.0.0
-ovos-skill-parrot>=0.1.5,<1.0.0
-ovos-skill-volume>=0.1.2,<1.0.0
-ovos-skill-naptime>=0.3.3,<1.0.0
+ovos-skill-boot-finished>=0.4.8,<1.0.0
+ovos-skill-audio-recording>=0.2.4,<1.0.0
+ovos-skill-dictation>=0.2.5,<1.0.0
+ovos-skill-parrot>=0.1.9,<1.0.0
+ovos-skill-volume>=0.1.7,<1.0.0
+ovos-skill-naptime>=0.3.8,<1.0.0
diff --git a/requirements/skills-desktop.txt b/requirements/skills-desktop.txt
index e626bc3e408..7a110cbffc8 100644
--- a/requirements/skills-desktop.txt
+++ b/requirements/skills-desktop.txt
@@ -1,2 +1,2 @@
 # skills that require a linux desktop environment
-ovos-skill-application-launcher>=0.5.4,<1.0.0
+ovos-skill-application-launcher>=0.5.6,<1.0.0
diff --git a/requirements/skills-essential.txt b/requirements/skills-essential.txt
index 34075dbf462..e87af0dc893 100644
--- a/requirements/skills-essential.txt
+++ b/requirements/skills-essential.txt
@@ -1,9 +1,9 @@
 # skills providing core functionality (offline)
-ovos-skill-fallback-unknown>=0.1.3,<1.0.0
-ovos-skill-alerts>=0.1.5,<1.0.0
-ovos-skill-personal>=0.1.5,<1.0.0
-ovos-skill-date-time>=0.3.4,<1.0.0
-ovos-skill-hello-world>=0.1.7,<1.0.0
-skill-wordnet>=0.0.6,<1.0.0
+ovos-skill-fallback-unknown>=0.1.5,<1.0.0
+ovos-skill-alerts>=0.1.10,<1.0.0
+ovos-skill-personal>=0.1.7,<1.0.0
+ovos-skill-date-time>=0.4.2,<1.0.0
+ovos-skill-hello-world>=0.1.10,<1.0.0
+skill-wordnet>=0.0.10,<1.0.0
 #skill-randomness>=0.0.1,<1.0.0
-ovos-skill-spelling>=0.2.3,<1.0.0
+ovos-skill-spelling>=0.2.5,<1.0.0
diff --git a/requirements/skills-gui.txt b/requirements/skills-gui.txt
index b85f14b0234..6c154fcfb0b 100644
--- a/requirements/skills-gui.txt
+++ b/requirements/skills-gui.txt
@@ -1,1 +1,1 @@
-ovos-skill-homescreen>=1.0.4,<3.0.0
+ovos-skill-homescreen>=3.0.2,<4.0.0
\ No newline at end of file
diff --git a/requirements/skills-internet.txt b/requirements/skills-internet.txt
index 2914e4ed18e..0f475dac37f 100644
--- a/requirements/skills-internet.txt
+++ b/requirements/skills-internet.txt
@@ -1,9 +1,9 @@
 # skills that require internet connectivity, should not be installed in offline devices
-ovos-skill-weather>=0.1.4,<1.0.0
-skill-ddg>=0.1.5,<1.0.0
-skill-wolfie>=0.2.7,<1.0.0
+ovos-skill-weather>=0.1.11,<1.0.0
+skill-ddg>=0.1.9,<1.0.0
+skill-wolfie>=0.2.9,<1.0.0
 ovos-skill-wikipedia>=0.5.3,<1.0.0
-skill-ovos-fallback-chatgpt>=0.1.4,<1.0.0
+skill-ovos-fallback-chatgpt>=0.1.7,<1.0.0
 ovos-skill-wikihow>=0.2.5,<1.0.0
-ovos-skill-speedtest>=0.2.3,<1.0.0
-ovos-skill-ip>=0.2.2,<1.0.0
+ovos-skill-speedtest>=0.3.2,<1.0.0
+ovos-skill-ip>=0.2.5,<1.0.0
\ No newline at end of file
diff --git a/requirements/skills-media.txt b/requirements/skills-media.txt
index e38496221f2..d62da9e811c 100644
--- a/requirements/skills-media.txt
+++ b/requirements/skills-media.txt
@@ -1,5 +1,5 @@
 # skills for OCP, require audio playback plugins (usually mpv)
-ovos-skill-somafm>=0.1.1,<1.0.0
-skill-news>=0.1.5,<1.0.0
-ovos-skill-pyradios>=0.1.3,<1.0.0
-ovos-skill-local-media>=0.2.1,<1.0.0
\ No newline at end of file
+ovos-skill-somafm>=0.1.3,<1.0.0
+skill-news>=0.1.8,<1.0.0
+ovos-skill-pyradios>=0.1.4,<1.0.0
+ovos-skill-local-media>=0.2.4,<1.0.0
\ No newline at end of file


Test patch:
diff --git a/.github/workflows/constraint_tests.yml b/.github/workflows/constraint_tests.yml
deleted file mode 100644
index 37e6898761d..00000000000
--- a/.github/workflows/constraint_tests.yml
+++ /dev/null
@@ -1,45 +0,0 @@
-name: Test Constraints
-
-on:
-  workflow_dispatch:
-  pull_request:
-    paths:
-      - 'requirements/requirements.txt'
-      - 'requirements/lgpl.txt'
-      - 'requirements/mycroft.txt'
-      - 'requirements/plugins.txt'
-      - 'requirements/skills-audio.txt'
-      - 'requirements/skills-desktop.txt'
-      - 'requirements/skills-essential.txt'
-      - 'requirements/skills-gui.txt'
-      - 'requirements/skills-internet.txt'
-      - 'requirements/skills-media.txt'
-
-jobs:
-  test-stable-and-testing-constraints:
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        constraints_file: ['testing']
-
-    steps:
-      - name: Checkout repository
-        uses: actions/checkout@v3
-
-      - name: Set up Python
-        uses: actions/setup-python@v4
-        with:
-          python-version: '3.8'
-
-      - name: Install System Dependencies
-        run: |
-          sudo apt-get update
-          sudo apt install python3-dev swig libssl-dev portaudio19-dev libpulse-dev libfann-dev
-
-      - name: Download constraints file
-        run: |
-          curl -o requirements/constraints-${{ matrix.constraints_file }}.txt https://raw.githubusercontent.com/OpenVoiceOS/ovos-releases/refs/heads/main/constraints-${{ matrix.constraints_file }}.txt
-
-      - name: Install core repo with constraints
-        run: |
-          pip install -e .[mycroft,lgpl,plugins,skills-essential,skills-audio,skills-gui,skills-internet,skills-media,skills-desktop] --pre -c requirements/constraints-${{ matrix.constraints_file }}.txt
diff --git a/requirements/tests.txt b/requirements/tests.txt
index 3978eae23f8..24ec8fa3ef0 100644
--- a/requirements/tests.txt
+++ b/requirements/tests.txt
@@ -1,5 +1,6 @@
-coveralls==1.8.2
-flake8==3.7.9
-pytest==5.2.4
-pytest-cov==2.8.1
-cov-core==1.15.0
\ No newline at end of file
+coveralls>=1.8.2
+flake8>=3.7.9
+pytest>=5.2.4
+pytest-cov>=2.8.1
+cov-core>=1.15.0
+ovos-backend-client>=0.1.0,<2.0.0
\ No newline at end of file