diff --git a/.github/workflows/build_debos.yml b/.github/workflows/build_debos.yml deleted file mode 100644 index 2d169f5f1..000000000 --- a/.github/workflows/build_debos.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Build SquashFS Image -on: - workflow_dispatch: - inputs: - debos_branch: - type: string - description: neon_debos branch to use - push: - branches: - - dev - - master - paths-ignore: - - 'neon_core/version.py' - - 'CHANGELOG.md' - -jobs: - build_squashfs_image: - runs-on: 2222.us - steps: - - name: Get debos repo branch - id: branch - run: | - DEFAULT_REF=${{ github.ref }} - REQUEST_REF=${{ github.event.inputs.debos_branch }} - echo "::set-output name=debos::${REQUEST_REF:-${DEFAULT_REF}}" - - name: Checkout Debos Repository - uses: actions/checkout@v3 - with: - ref: ${{ steps.branch.outputs.debos }} - lfs: True - repository: NeonGeckoCom/neon_debos - path: action/neon_debos - - - name: Create LFS file list - run: | - cd action/neon_debos - git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id - cd ../.. - - name: Restore LFS cache - uses: actions/cache@v3 - id: lfs-cache - with: - path: action/neon_debos/.git/lfs - key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}-v1 - - name: Ensure LFS files are pulled - if: steps.lfs-cache.outputs.cache-hit != 'true' - run: | - cd action/neon_debos - git lfs pull - cd ../.. - - name: Save LFS Cache - if: steps.lfs-cache.outputs.cache-hit != 'true' - id: lfs-cache-save - uses: actions/cache/save@v3 - with: - path: action/neon_debos/.git/lfs - key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}-v1 - - - name: Export keys for image build - run: | - mkdir -p action/neon_debos/overlays/80-google-json-overlay/home/neon/.local/share/neon - echo ${GOOGLE_KEY}>action/neon_debos/overlays/80-google-json-overlay/home/neon/.local/share/neon/google.json - env: - GOOGLE_KEY: ${{secrets.google_api_key}} - - name: Build and Export Mk2 Image - run: | - bash action/neon_debos/run_automation.sh debian-neon-image.yml ${{ github.ref_name }} /var/www/html/app/files/neon_images/pi/mycroft_mark_2 rpi4 mark_2 - - name: Build and Export OPi5 Image - run: | - bash action/neon_debos/run_automation.sh debian-neon-image.yml ${{ github.ref_name }} /var/www/html/app/files/neon_images/orange_pi_5/ opi5 opi5 - - name: Stop Docker Build Containers - if: failure() || cancelled() - run: | - docker kill neon_debos_ghaction \ No newline at end of file diff --git a/.github/workflows/publish_test_build.yml b/.github/workflows/publish_test_build.yml index 8f6066047..f3ba2061e 100644 --- a/.github/workflows/publish_test_build.yml +++ b/.github/workflows/publish_test_build.yml @@ -21,6 +21,20 @@ jobs: publish_prerelease: true update_changelog: false # Changelog automation fails with this large repo + trigger_os_build: + runs-on: ubuntu-latest + steps: + - name: Call Release Action + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{secrets.NEON_OS_TOKEN}} + repository: neongeckocom/neon-os + event-type: Publish Release + client-payload: |- + { + "ref": "dev", + "repo": "neon-core" + } build_and_publish_docker: needs: publish_alpha_release uses: neongeckocom/.github/.github/workflows/publish_docker.yml@master diff --git a/.github/workflows/setup_tests.yml b/.github/workflows/setup_tests.yml index 0c8b0ad57..957b12d25 100644 --- a/.github/workflows/setup_tests.yml +++ b/.github/workflows/setup_tests.yml @@ -29,23 +29,6 @@ jobs: - name: Test Skills Installation run: | pip install .[skills_required,skills_essential,skills_default,skills_extended] -# pi_image_3_7: -# runs-on: ubuntu-latest -# timeout-minutes: 90 -# steps: -# - uses: actions/checkout@v2 -# - name: Test chroot installation -# uses: pguyot/arm-runner-action@v2 -# with: -# optimize_image: false -# base_image: https://2222.us/app/files/neon_images/pi/debian-base-image-rpi4_2023-02-13_09_05.img.xz -# cpu: cortex-a53 -# copy_repository_path: /core -# commands: | -# bash /core/test/pi_setup_3_7.sh || exit 2 -# . /core/venv/bin/activate || exit 2 -# neon-audio init-plugin -p coqui || exit 2 -# neon-speech init-plugin -p neon-stt-plugin-nemo || exit 2 pi_image_3_10: runs-on: ubuntu-latest timeout-minutes: 90 @@ -55,7 +38,7 @@ jobs: uses: pguyot/arm-runner-action@v2 with: optimize_image: false - base_image: https://2222.us/app/files/neon_images/pi/debian-base-image-rpi4_2023-07-12_16_30.img.xz + base_image: https://2222.us/app/files/neon_images/test_images/pi_image_3.img.xz cpu: cortex-a53 copy_repository_path: /core commands: | @@ -72,7 +55,7 @@ jobs: uses: pguyot/arm-runner-action@v2 with: optimize_image: false - base_image: https://2222.us/app/files/neon_images/pi/debian-base-image-rpi4_2023-07-12_16_30.img.xz + base_image: https://2222.us/app/files/neon_images/test_images/pi_image_3.img.xz cpu: cortex-a53 copy_repository_path: /core commands: | @@ -80,91 +63,3 @@ jobs: . /core/venv/bin/activate || exit 2 neon-audio init-plugin -p coqui || exit 2 neon-speech init-plugin -p neon-stt-plugin-nemo || exit 2 - legacy-remote: - strategy: - matrix: - python-version: [ 3.9 ] - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v2 - - name: Set up python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Setup Core - run: | - mkdir -p ~/.local/share/neon - echo ${GOOGLE_KEY}>~/.local/share/neon/google.json - echo ${AWS_CREDS}>~/.local/share/neon/aws.json - bash test/legacy_setup_remote.sh ${NEON_TOKEN} - env: - NEON_TOKEN: ${{secrets.neon_token}} - GOOGLE_KEY: ${{secrets.google_api_key}} - AWS_CREDS: ${{secrets.amazon_creds}} - - name: Test Core Setup - timeout-minutes: 10 - run: | - . test/.venv/bin/activate - pytest test/test_setup_remote.py --junitxml=tests/remote-setup-results.xml - pytest test/test_run_neon.py --junitxml=tests/remote-test-results.xml - - name: Upload Core Setup test results - uses: actions/upload-artifact@v2 - with: - name: pytest-results-remote-${{ matrix.python-version }} - path: tests/remote-test-results.xml - if: always() - - name: Upload Core Setup logs - uses: actions/upload-artifact@v2 - with: - name: core-logs-remote-${{ matrix.python-version }} - path: ~/.local/share/neon/logs/*.log - if: always() - - name: Upload Configuration - uses: actions/upload-artifact@v2 - with: - name: configuration-remote-${{ matrix.python-version }} - path: ~/.config/neon/neon.yaml - if: always() - legacy-dev_local: - strategy: - matrix: - python-version: [ 3.8 ] - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v2 - - name: Set up python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Setup Core - run: | - bash test/legacy_setup_dev_local.sh ${NEON_TOKEN} - env: - NEON_TOKEN: ${{secrets.neon_token}} - - name: Test Core Setup - timeout-minutes: 10 - run: | - . test/.venv/bin/activate - pip install pytest pytest-timeout - pytest test/test_setup_dev_local.py --junitxml=tests/dev_local-setup-results.xml - pytest test/test_run_neon.py --junitxml=tests/dev_local-test-results.xml - - name: Upload Core Setup test results - uses: actions/upload-artifact@v2 - with: - name: pytest-results-local-${{ matrix.python-version }} - path: tests/dev_local-test-results.xml - if: always() - - name: Upload Core Setup logs - uses: actions/upload-artifact@v2 - with: - name: core-logs-dev-local-${{ matrix.python-version }} - path: ~/test/logs/*.log - if: always() - - name: Upload Configuration - uses: actions/upload-artifact@v2 - with: - name: configuration-dev-local-${{ matrix.python-version }} - path: ~/.config/neon/neon.yaml - if: always() diff --git a/docker_overlay/root/run.sh b/docker_overlay/root/run.sh index c4e41f758..6ba2f3e57 100644 --- a/docker_overlay/root/run.sh +++ b/docker_overlay/root/run.sh @@ -29,5 +29,4 @@ # Python package installation must occur in a separate thread, before module load, for the entry point to be loaded. neon install-default-skills -#neon install-skill-requirements /skills neon run-skills \ No newline at end of file diff --git a/neon_core/cli.py b/neon_core/cli.py index a1a42720e..d526c2d90 100644 --- a/neon_core/cli.py +++ b/neon_core/cli.py @@ -89,17 +89,6 @@ def update_default_resources(): click.echo("Updating Default Resources") update_default_resources() -# @neon_core_cli.command(help= -# "Install skill requirements for a specified directory") -# @click.argument("skill_dir") -# def install_skill_requirements(skill_dir): -# from neon_core.util.skill_utils import install_local_skills -# try: -# installed = install_local_skills(skill_dir) -# click.echo(f"Installed {len(installed)} skills from {skill_dir}") -# except ValueError as e: -# click.echo(e) - @neon_core_cli.command(help="Start Neon Skills module") @click.option("--install-skills", "-i", default=None, diff --git a/neon_core/configuration/mark_2/neon.yaml b/neon_core/configuration/mark_2/neon.yaml index e7402bc89..2bc37e3aa 100644 --- a/neon_core/configuration/mark_2/neon.yaml +++ b/neon_core/configuration/mark_2/neon.yaml @@ -36,7 +36,7 @@ listener: instant_listen: true speech_begin: 0.5 silence_end: 0.9 - utterance_chunks_to_rewind: 1 + utterance_chunks_to_rewind: 0 hotwords: wake_up: active: false @@ -73,13 +73,6 @@ gui: run_gui_file_server: false generic: homescreen_supported: true -MQ: - server: mq.2023.us - port: 35672 - users: - mq_handler: - user: neon_api_utils - password: Klatchat2021 signal: use_signal_files: false skills: @@ -91,7 +84,7 @@ skills: - skill-audio_record.neongeckocom default_skills: [] PHAL: - ovos-PHAL-plugin-mk1: + ovos-phal-mk1: enabled: false ovos-PHAL-plugin-balena-wifi: enabled: false diff --git a/neon_core/configuration/neon.yaml b/neon_core/configuration/neon.yaml index 5b6e5bce6..8a0dd8e05 100644 --- a/neon_core/configuration/neon.yaml +++ b/neon_core/configuration/neon.yaml @@ -168,7 +168,6 @@ skills: appstore_sync_interval: 6 auto_update: false auto_update_interval: 24 - neon_token: '' install_essential: true essential_skills: [] install_default: false @@ -212,7 +211,7 @@ network_tests: ncsi_endpoint: http://www.msftncsi.com/ncsi.txt ncsi_expected_text: Microsoft NCSI MQ: - server: mq.2021.us + server: mq.neonaiservices.com port: 5672 users: mq_handler: diff --git a/neon_core/configuration/opi5/neon.yaml b/neon_core/configuration/opi5/neon.yaml index b3bfa5298..cb9618722 100644 --- a/neon_core/configuration/opi5/neon.yaml +++ b/neon_core/configuration/opi5/neon.yaml @@ -70,13 +70,6 @@ gui: run_gui_file_server: false generic: homescreen_supported: true -MQ: - server: mq.2023.us - port: 35672 - users: - mq_handler: - user: neon_api_utils - password: Klatchat2021 signal: use_signal_files: false skills: diff --git a/neon_core/configuration/rpi4/neon.yaml b/neon_core/configuration/rpi4/neon.yaml index 3600daeb7..fd289e26b 100644 --- a/neon_core/configuration/rpi4/neon.yaml +++ b/neon_core/configuration/rpi4/neon.yaml @@ -70,13 +70,6 @@ gui: run_gui_file_server: false generic: homescreen_supported: true -MQ: - server: mq.2023.us - port: 35672 - users: - mq_handler: - user: neon_api_utils - password: Klatchat2021 signal: use_signal_files: false skills: diff --git a/neon_core/run_neon.py b/neon_core/run_neon.py index f44ba9e4e..9ffae0fa4 100644 --- a/neon_core/run_neon.py +++ b/neon_core/run_neon.py @@ -35,7 +35,7 @@ from threading import Event from subprocess import Popen, STDOUT from ovos_bus_client import MessageBusClient, Message -from typing.io import IO +from typing import IO from neon_utils.configuration_utils import init_config_dir init_config_dir() diff --git a/neon_core/skills/__init__.py b/neon_core/skills/__init__.py index dc2a88a8a..d60c491a6 100644 --- a/neon_core/skills/__init__.py +++ b/neon_core/skills/__init__.py @@ -26,68 +26,15 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import importlib - -from ovos_utils.log import LOG -from neon_utils.skills.mycroft_skill import PatchedMycroftSkill from neon_core.skills.decorators import intent_handler, intent_file_handler, \ resting_screen_handler, conversational_intent -# Patch the base skill -import ovos_workshop.skills -ovos_workshop.skills.mycroft_skill.MycroftSkill = PatchedMycroftSkill - -workshop_modules = ("ovos_workshop.skills.ovos", - "ovos_workshop.skills.fallback", - "ovos_workshop.skills.common_query_skill", - "ovos_workshop.skills.common_play", - "ovos_workshop.skills") -neon_utils_modules = ("neon_utils.skills.neon_fallback_skill", - "neon_utils.skills") -mycroft_skills_modules = ("mycroft.skills.mycroft_skill.mycroft_skill", - "mycroft.skills.mycroft_skill", - "mycroft.skills.fallback_skill", - "mycroft.skills.common_play_skill", - "mycroft.skills.common_query_skill", - "mycroft.skills.common_iot_skill", - "mycroft.skills") - -# Reload ovos_workshop modules with Patched class -for module in workshop_modules: - try: - importlib.reload(importlib.import_module(module)) - except Exception as e: - LOG.exception(e) - -# Reload neon_utils modules with Patched class -for module in neon_utils_modules: - try: - importlib.reload(importlib.import_module(module)) - except Exception as e: - LOG.exception(e) - -# Reload mycroft modules with Patched class -for module in mycroft_skills_modules: - try: - importlib.reload(importlib.import_module(module)) - except Exception as e: - LOG.exception(e) - -# Manually patch top-level `mycroft` references -import mycroft -mycroft.MycroftSkill = PatchedMycroftSkill -mycroft.FallbackSkill = mycroft.skills.fallback_skill.FallbackSkill - -# Manually patch re-defined classes in `mycroft.skills.core` -import mycroft.skills.core -mycroft.skills.core.MycroftSkill = PatchedMycroftSkill -mycroft.skills.core.FallbackSkill = mycroft.skills.fallback_skill.FallbackSkill - # TODO: Remove below patches with ovos-core 0.0.8 refactor import neon_core.skills.patched_plugin_loader import neon_core.skills.patched_skill_settings import neon_core.skills.patched_common_query +import mycroft.skills from mycroft.skills import api from mycroft.skills import skill_manager from mycroft.skills.intent_services import padatious_service, converse_service diff --git a/neon_core/skills/intent_service.py b/neon_core/skills/intent_service.py index de99a6d0d..88ba42228 100644 --- a/neon_core/skills/intent_service.py +++ b/neon_core/skills/intent_service.py @@ -28,22 +28,26 @@ import time import wave +from threading import Event from typing import List +from ovos_bus_client.util import get_message_lang +from ovos_utils import flatten_list + from neon_transformers.text_transformers import UtteranceTransformersService -from ovos_bus_client import Message, MessageBusClient -from neon_utils.message_utils import get_message_user +from ovos_bus_client import Message, MessageBusClient, SessionManager, UtteranceState +from neon_utils.message_utils import get_message_user, dig_for_message from neon_utils.metrics_utils import Stopwatch from neon_utils.user_utils import apply_local_user_profile_updates from neon_utils.configuration_utils import get_neon_user_config from lingua_franca.parse import get_full_lang_code -from ovos_config.locale import set_default_lang +from ovos_config.locale import set_default_lang, setup_locale from ovos_utils.log import LOG from neon_core.configuration import Configuration from neon_core.language import get_lang_config from mycroft.skills.intent_service import IntentService -from mycroft.skills.intent_services import ConverseService +from mycroft.skills.intent_services import ConverseService, IntentMatch try: from neon_utterance_translator_plugin import UtteranceTranslator @@ -281,10 +285,261 @@ def handle_get_padatious(self, message): {"intent": intent})) +# TODO: Overrides below backporting 0.0.8 compat class NeonConverseService(ConverseService): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.bus.on('mycroft.speech.recognition.unknown', self.reset_converse) + self.bus.on('intent.service.skills.deactivate', self.handle_deactivate_skill_request) + self.bus.on('intent.service.skills.activate', self.handle_activate_skill_request) + self.bus.on('active_skill_request', self.handle_activate_skill_request) # TODO backwards compat, deprecate + self.bus.on('intent.service.active_skills.get', self.handle_get_active_skills) + self.bus.on("skill.converse.get_response.enable", self.handle_get_response_enable) + self.bus.on("skill.converse.get_response.disable", self.handle_get_response_disable) + + @property + def active_skills(self): + session = SessionManager.get() + return session.active_skills + + @active_skills.setter + def active_skills(self, val): + session = SessionManager.get() + session.active_skills = [] + for skill_id, ts in val: + session.activate_skill(skill_id) + + def get_active_skills(self, message=None): + """Active skill ids ordered by converse priority + this represents the order in which converse will be called + + Returns: + active_skills (list): ordered list of skill_ids + """ + session = SessionManager.get(message) + return [skill[0] for skill in session.active_skills] + + def deactivate_skill(self, skill_id, source_skill=None, message=None): + """Remove a skill from being targetable by converse. + + Args: + skill_id (str): skill to remove + source_skill (str): skill requesting the removal + """ + source_skill = source_skill or skill_id + if self._deactivate_allowed(skill_id, source_skill): + session = SessionManager.get(message) + if session.is_active(skill_id): + # update converse session + session.deactivate_skill(skill_id) + + # keep message.context + message = message or Message("") + message.context["session"] = session.serialize() # update session active skills + # send bus event + self.bus.emit( + message.forward("intent.service.skills.deactivated", + data={"skill_id": skill_id})) + if skill_id in self._consecutive_activations: + self._consecutive_activations[skill_id] = 0 + + def activate_skill(self, skill_id, source_skill=None, message=None): + """Add a skill or update the position of an active skill. + + The skill is added to the front of the list, if it's already in the + list it's removed so there is only a single entry of it. + + Args: + skill_id (str): identifier of skill to be added. + source_skill (str): skill requesting the removal + """ + source_skill = source_skill or skill_id + if self._activate_allowed(skill_id, source_skill): + # update converse session + session = SessionManager.get(message) + session.activate_skill(skill_id) + + # keep message.context + message = message or Message("") + message.context["session"] = session.serialize() # update session active skills + message = message.forward("intent.service.skills.activated", + {"skill_id": skill_id}) + # send bus event + self.bus.emit(message) + # update activation counter + self._consecutive_activations[skill_id] += 1 + + def _collect_converse_skills(self, message=None): + """use the messagebus api to determine which skills want to converse + This includes all skills and external applications""" + message = message or dig_for_message() + session = SessionManager.get(message) + + skill_ids = [] + # include all skills in get_response state + want_converse = [skill_id for skill_id, state in session.utterance_states.items() + if state == UtteranceState.RESPONSE] + skill_ids += want_converse # dont wait for these pong answers (optimization) + + active_skills = self.get_active_skills() + + if not active_skills: + return want_converse + + event = Event() + + def handle_ack(msg): + nonlocal event + skill_id = msg.data["skill_id"] + + # validate the converse pong + if all((skill_id not in want_converse, + msg.data.get("can_handle", True), + skill_id in active_skills)): + want_converse.append(skill_id) + + if skill_id not in skill_ids: # track which answer we got + skill_ids.append(skill_id) + + if all(s in skill_ids for s in active_skills): + # all skills answered the ping! + event.set() + + self.bus.on("skill.converse.pong", handle_ack) + + # ask skills if they want to converse + for skill_id in active_skills: + self.bus.emit(message.forward(f"{skill_id}.converse.ping", + {"skill_id": skill_id})) + + # wait for all skills to acknowledge they want to converse + event.wait(timeout=0.5) + + self.bus.remove("skill.converse.pong", handle_ack) + return want_converse + + def _check_converse_timeout(self, message=None): + """ filter active skill list based on timestamps """ + message = message or dig_for_message() + timeouts = self.config.get("skill_timeouts") or {} + def_timeout = self.config.get("timeout", 300) + session = SessionManager.get(message) + session.active_skills = [ + skill for skill in session.active_skills + if time.time() - skill[1] <= timeouts.get(skill[0], def_timeout)] + + def converse(self, utterances, skill_id, lang, message): + """Call skill and ask if they want to process the utterance. - def _collect_converse_skills(self): - # TODO: Patching bug in ovos-core 0.0.3 - return self.get_active_skills() + Args: + utterances (list of tuples): utterances paired with normalized + versions. + skill_id: skill to query. + lang (str): current language + message (Message): message containing interaction info. + + Returns: + handled (bool): True if handled otherwise False. + """ + session = SessionManager.get(message) + session.lang = lang + + state = session.utterance_states.get(skill_id, UtteranceState.INTENT) + if state == UtteranceState.RESPONSE: + converse_msg = message.reply(f"{skill_id}.converse.get_response", + {"utterances": utterances, + "lang": lang}) + self.bus.emit(converse_msg) + return True + + if self._converse_allowed(skill_id): + converse_msg = message.reply(f"{skill_id}.converse.request", + {"utterances": utterances, + "lang": lang}) + result = self.bus.wait_for_response(converse_msg, + 'skill.converse.response') + if result and 'error' in result.data: + error_msg = result.data['error'] + LOG.error(f"{skill_id}: {error_msg}") + return False + elif result is not None: + return result.data.get('result', False) + return False + + def converse_with_skills(self, utterances, lang, message): + """Give active skills a chance at the utterance + + Args: + utterances (list): list of utterances + lang (string): 4 letter ISO language code + message (Message): message to use to generate reply + + Returns: + IntentMatch if handled otherwise None. + """ + # we call flatten in case someone is sending the old style list of tuples + utterances = flatten_list(utterances) + # filter allowed skills + self._check_converse_timeout(message) + # check if any skill wants to handle utterance + for skill_id in self._collect_converse_skills(message): + if self.converse(utterances, skill_id, lang, message): + return IntentMatch('Converse', None, None, skill_id) + return None + + def handle_get_response_enable(self, message): + skill_id = message.data["skill_id"] + session = SessionManager.get(message) + session.enable_response_mode(skill_id) + if session.session_id == "default": + SessionManager.sync(message) + + def handle_get_response_disable(self, message): + skill_id = message.data["skill_id"] + session = SessionManager.get(message) + session.disable_response_mode(skill_id) + if session.session_id == "default": + SessionManager.sync(message) + + def handle_activate_skill_request(self, message): + # TODO imperfect solution - only a skill can activate itself + # someone can forge this message and emit it raw, but in OpenVoiceOS all + # skill messages should have skill_id in context, so let's make sure + # this doesnt happen accidentally at very least + skill_id = message.data['skill_id'] + source_skill = message.context.get("skill_id") + self.activate_skill(skill_id, source_skill, message) + sess = SessionManager.get(message) + if sess.session_id == "default": + SessionManager.sync(message) + + def handle_deactivate_skill_request(self, message): + # TODO imperfect solution - only a skill can deactivate itself + # someone can forge this message and emit it raw, but in ovos-core all + # skill message should have skill_id in context, so let's make sure + # this doesnt happen accidentally + skill_id = message.data['skill_id'] + source_skill = message.context.get("skill_id") or skill_id + self.deactivate_skill(skill_id, source_skill, message) + sess = SessionManager.get(message) + if sess.session_id == "default": + SessionManager.sync(message) + + def reset_converse(self, message): + """Let skills know there was a problem with speech recognition""" + lang = get_message_lang(message) + try: + setup_locale(lang) # restore default lang + except Exception as e: + LOG.exception(f"Failed to set lingua_franca default lang to {lang}") + + self.converse_with_skills([], lang, message) + + def handle_get_active_skills(self, message): + """Send active skills to caller. + + Argument: + message: query message to reply to. + """ + self.bus.emit(message.reply("intent.service.active_skills.reply", + {"skills": self.get_active_skills(message)})) diff --git a/neon_core/skills/patched_common_query.py b/neon_core/skills/patched_common_query.py index fd0c00f30..1a1c29538 100644 --- a/neon_core/skills/patched_common_query.py +++ b/neon_core/skills/patched_common_query.py @@ -35,9 +35,9 @@ from ovos_bus_client.session import SessionManager from ovos_bus_client.message import Message, dig_for_message from ovos_utils import flatten_list -from ovos_utils.enclosure.api import EnclosureAPI +from ovos_bus_client.apis.enclosure import EnclosureAPI +from ovos_bus_client.util import get_message_lang from ovos_utils.log import LOG -from ovos_utils.messagebus import get_message_lang from mycroft.skills.intent_services.base import IntentMatch from mycroft.skills.skill_data import CoreResources diff --git a/neon_core/skills/service.py b/neon_core/skills/service.py index 2270c0214..b9cc86d0f 100644 --- a/neon_core/skills/service.py +++ b/neon_core/skills/service.py @@ -35,7 +35,7 @@ from ovos_config.locale import set_default_lang, set_default_tz from ovos_config.config import Configuration from ovos_utils.log import LOG -from ovos_utils.skills.locations import get_plugin_skills, get_skill_directories +from ovos_plugin_manager.skills import get_plugin_skills, get_skill_directories from ovos_utils.process_utils import StatusCallbackMap from neon_utils.metrics_utils import announce_connection from neon_utils.signal_utils import init_signal_handlers, init_signal_bus diff --git a/neon_core/util/diagnostic_utils.py b/neon_core/util/diagnostic_utils.py index 0dec0ccfc..0c6eb9d21 100644 --- a/neon_core/util/diagnostic_utils.py +++ b/neon_core/util/diagnostic_utils.py @@ -118,21 +118,3 @@ def send_diagnostics(allow_logs=True, allow_transcripts=True, allow_config=True) "transcripts": transcripts} report_metric("diagnostics", **data) return data - - -def cli_send_diags(): - """ - CLI Entry Point to Send Diagnostics - """ - LOG.warning(f"This function is deprecated. Use `neon upload-diagnostics`") - import argparse - parser = argparse.ArgumentParser(description="Upload Neon Diagnostics Files", add_help=True) - parser.add_argument("--no-transcripts", dest="transcripts", default=True, action='store_false', - help="Disable upload of all transcribed input") - parser.add_argument("--no-logs", dest="logs", default=True, action='store_false', - help="Disable upload of Neon log files (NOTE: start_neon.log is always uploaded)") - parser.add_argument("--no-config", dest="config", default=True, action='store_false', - help="Disable upload of Neon config files") - - args = parser.parse_args() - send_diagnostics(args.logs, args.transcripts, args.config) diff --git a/neon_core/util/skill_utils.py b/neon_core/util/skill_utils.py index ca7432705..f8b249271 100644 --- a/neon_core/util/skill_utils.py +++ b/neon_core/util/skill_utils.py @@ -27,62 +27,28 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import json -import os.path import re from copy import copy -from os import listdir, makedirs, symlink -from tempfile import mkdtemp -from shutil import rmtree +from os import makedirs, symlink from os.path import expanduser, join, isdir, dirname, islink from typing import List from ovos_utils.xdg_utils import xdg_data_home -from ovos_utils.log import LOG, log_deprecation +from ovos_utils.log import LOG from ovos_config.config import Configuration -def get_neon_skills_data(skill_meta_repository: str = - "https://github.com/neongeckocom/neon_skills", - branch: str = "master", - repo_metadata_path: str = "skill_metadata") -> dict: - """ - Get skill data from configured neon_skills repository. - :param skill_meta_repository: URL of skills repository containing metadata - :param branch: branch of repository to check out - :param repo_metadata_path: Path to repo directory containing json metadata files - """ - log_deprecation("This skill repository format is deprecated; specify skills as packages") - from ovos_skills_manager.github import normalize_github_url, download_url_from_github_url - from ovos_skill_installer import download_extract_zip - skills_data = dict() - temp_download_dir = mkdtemp() - zip_url = download_url_from_github_url(skill_meta_repository, branch) - base_dir = join(temp_download_dir, "neon_skill_meta") - try: - download_extract_zip(zip_url, temp_download_dir, - "neon_skill_meta.zip", base_dir) - except PermissionError: - LOG.exception(f"Failed to download {zip_url} to {base_dir}") - return dict() - meta_dir = join(base_dir, repo_metadata_path) - for entry in listdir(meta_dir): - with open(join(meta_dir, entry)) as f: - skill_entry = json.load(f) - skills_data[normalize_github_url(skill_entry["url"])] = skill_entry - rmtree(temp_download_dir) - return skills_data - - -def _write_pip_constraints_to_file(output_file: str = None): +def _write_pip_constraints_to_file(output_file: str): """ Writes out a constraints file for OSM to use to prevent broken dependencies :param output_file: path to constraints file to write """ + if not output_file: + raise ValueError(f"Expected string path but got: {output_file}") + from neon_utils.packaging_utils import get_package_dependencies - # TODO: Backwards-compat to be deprecated - output_file = output_file or '/etc/mycroft/constraints.txt' if not isdir(dirname(output_file)): makedirs(dirname(output_file)) @@ -102,46 +68,6 @@ def _write_pip_constraints_to_file(output_file: str = None): LOG.info(f"Wrote core constraints to file: {output_file}") -def _install_skill_osm(skill_url: str, skill_dir: str, skills_catalog: dict): - """ - Install a skill from source using OVOS Skills Manager - :param skill_url: URL of skill to install - :param skill_dir: Directory to install skill to - :param skills_catalog: dict Neon skill information (url to dict data) - """ - from ovos_skills_manager.osm import OVOSSkillsManager - from ovos_skills_manager.skill_entry import SkillEntry - from ovos_skills_manager.github import normalize_github_url, get_branch_from_github_url - log_deprecation("Update all skills to `pip`-installable specs.") - osm = OVOSSkillsManager() - try: - normalized_url = normalize_github_url(skill_url) - # Check if this skill is in the Neon list - if normalized_url in skills_catalog: - branch = get_branch_from_github_url(skill_url) - # Set URL and branch to requested spec - skills_catalog[normalized_url]["url"] = normalized_url - skills_catalog[normalized_url]["branch"] = branch - entry = SkillEntry.from_json(skills_catalog.get(normalized_url), False) - else: - LOG.warning(f"Requested Skill not in Neon skill store ({skill_url})") - entry = osm.skill_entry_from_url(skill_url) - LOG.debug(entry.json) - - osm.install_skill(entry, skill_dir) - if not os.path.isdir(os.path.join(skill_dir, entry.uuid)): - LOG.error(f"Failed to install: " - f"{os.path.join(skill_dir, entry.uuid)}") - if entry.download(skill_dir): - LOG.info(f"Downloaded failed skill: {entry.uuid}") - else: - LOG.error(f"Failed to download: {entry.uuid}") - else: - LOG.info(f"Installed {skill_url} to {skill_dir}") - except Exception as e: - LOG.exception(e) - - def _install_skill_pip(skill_package: str, constraints_file: str) -> bool: """ Pip install the specified package @@ -159,53 +85,20 @@ def _install_skill_pip(skill_package: str, constraints_file: str) -> bool: def install_skills_from_list(skills_to_install: list, config: dict = None): """ - Installs the passed list of skill URLs and/or PyPI package names + Installs the passed list of skills (valid pip arguments). :param skills_to_install: list of skills to install :param config: optional dict configuration """ - config = config or Configuration()["skills"] - LOG.info(f"extra_directories={config.get('extra_directories')}") - LOG.info(f"directory={config.get('directory')}") - skill_dir = expanduser(config.get("extra_directories")[0] if - config.get("extra_directories") else - config.get("directory") if config.get("directory") - and config["directory"] != "skills" else - join(xdg_data_home(), "neon", "skills")) - LOG.info(f"skill_dir={skill_dir}") - skills_catalog = None - token_set = False - if config.get("neon_token"): - LOG.warning("Authenticated installation from git is deprecated. " - "Please remove `neon_token` from config") - from ovos_skills_manager.session import set_github_token - token_set = True - set_github_token(config["neon_token"]) - LOG.info(f"Added token to request headers: {config.get('neon_token')}") - - constraints_file = '/etc/mycroft/constraints.txt' - try: - _write_pip_constraints_to_file(constraints_file) - except PermissionError: - LOG.warning(f"Unable to write pip constraints file {constraints_file}") - from ovos_skills_manager.utils import set_osm_constraints_file - constraints_file = join(xdg_data_home(), "neon", "constraints.txt") - _write_pip_constraints_to_file(constraints_file) - set_osm_constraints_file(constraints_file) - - for url in skills_to_install: - if "://" in url and "git+" not in url: - skills_catalog = skills_catalog or get_neon_skills_data() - _install_skill_osm(url, skill_dir, skills_catalog) - else: - if not _install_skill_pip(url, constraints_file): - LOG.warning(f"Pip installation failed for: {url}") - skills_catalog = skills_catalog or get_neon_skills_data() - _install_skill_osm(url, skill_dir, skills_catalog) - - if token_set: - from ovos_skills_manager.session import clear_github_token - clear_github_token() - LOG.info(f"Installed {len(skills_to_install)} skills to: {skill_dir}") + constraints_file = join(xdg_data_home(), "neon", "constraints.txt") + _write_pip_constraints_to_file(constraints_file) + + for spec in skills_to_install: + if "://" in spec and "git+" not in spec: + LOG.error(f"Got an invalid package spec to install: {spec}") + elif not _install_skill_pip(spec, constraints_file): + LOG.error(f"Pip installation failed for: {spec}") + + LOG.info(f"Installed {len(skills_to_install)} skills") def install_skills_default(config: dict = None): diff --git a/neon_core/version.py b/neon_core/version.py index e7672dfc2..81fbab5d6 100644 --- a/neon_core/version.py +++ b/neon_core/version.py @@ -26,4 +26,4 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -__version__ = "24.2.29" +__version__ = "24.5.1" diff --git a/requirements/core_modules.txt b/requirements/core_modules.txt index 1c51ea491..b72c13cda 100644 --- a/requirements/core_modules.txt +++ b/requirements/core_modules.txt @@ -1,6 +1,6 @@ # neon core modules -neon_messagebus~=2.0,>=2.0.1 -neon_enclosure==1.6.2 # TODO: This is a yanked release because it depends on an alpha ovos-backend-client -neon_speech~=4.3 #,>=4.3.1a2 -neon_gui~=1.2,>=1.2.2 -neon_audio~=1.5,>=1.5.1 +neon-messagebus~=2.0,>=2.0.1 +neon-enclosure~=1.7 +neon-speech~=4.4,>=4.4.1 +neon-gui~=1.3 +neon-audio~=1.5,>=1.5.1 diff --git a/requirements/local_speech_processing.txt b/requirements/local_speech_processing.txt index 36a9b6cc3..aed0d3456 100644 --- a/requirements/local_speech_processing.txt +++ b/requirements/local_speech_processing.txt @@ -6,7 +6,3 @@ onnxruntime!=1.16.0 # TODO: Patching https://github.com/microsoft/onnxruntime/i # Fallback ovos-stt-plugin-vosk~=0.1,>=0.1.4 -ovos-tts-plugin-mimic~=0.2 - -# Backwards-compat. for tests -neon-tts-plugin-mimic diff --git a/requirements/pi.txt b/requirements/pi.txt index f7c85b146..f6654c379 100644 --- a/requirements/pi.txt +++ b/requirements/pi.txt @@ -16,6 +16,8 @@ onnxruntime!=1.16.0 # TODO: Patching https://github.com/microsoft/onnxruntime/i ovos-ww-plugin-precise~=0.1 ovos-ww-plugin-precise-lite[tflite]~=0.1,>=0.1.2 ovos-ww-plugin-vosk~=0.1,>=0.1.1 +# patching breaking change in openeakeword +openwakeword~=0.5,<0.6 ovos-ww-plugin-openwakeword~=0.2 neon-stt-plugin-google-cloud-streaming~=1.0,>=1.0.1 @@ -24,43 +26,46 @@ neon-stt-plugin-nemo~=0.0.4 ovos-tts-plugin-server==0.0.2a12 # Fallback plugins -neon-tts-plugin-coqui~=0.7,>=0.7.3a4 +neon-tts-plugin-coqui~=0.8 ovos-stt-plugin-vosk~=0.1,>=0.1.4 # PHAL Plugins -neon-phal-plugin-monitoring~=0.0.1 +neon-phal-plugin-monitoring~=0.0.2 neon-phal-plugin-audio-receiver~=0.0.4 -neon-phal-plugin-reset~=0.4 +neon-phal-plugin-reset~=0.4,>=0.4.1 neon-phal-plugin-core-updater~=1.3 -neon-phal-plugin-device-updater~=0.1 +neon-phal-plugin-device-updater~=0.2 neon-phal-plugin-fan~=0.1 -neon-phal-plugin-switches~=0.0.4 -neon-phal-plugin-linear_led~=0.2,>=0.2.2 +neon-phal-plugin-switches~=0.0.5 +neon-phal-plugin-linear_led~=0.2,>=0.2.3 +neon-phal-plugin-gui-network-client~=0.0.5 ovos-phal-plugin-balena-wifi~=1.0.0 -neon-phal-plugin-gui-network-client~=0.0.4 ovos-phal-plugin-network-manager~=1.1 +# TODO: wifi-setup pinned for stable release ovos-phal-plugin-wifi-setup==1.1.2a1 -ovos-phal-plugin-oauth==0.0.3a2 +# TODO: oauth pinned for stable release +ovos-phal-plugin-oauth==0.0.3a3 ovos-phal-plugin-alsa~=0.0.3 -ovos-phal-plugin-system~=0.0.4 #,>=0.0.5a1 +# TODO: system pinned for ovos-utils 0.0.x latest compat. +ovos-phal-plugin-system==0.0.5a1 ovos-phal-plugin-connectivity-events~=0.0.3 -ovos-phal-plugin-homeassistant~=0.0.3 #,>=0.0.4a5 +ovos-phal-plugin-homeassistant~=0.0.3 #,>=0.0.4a5 ovos-phal-plugin-wallpaper-manager~=0.0.1 ovos-phal-plugin-ipgeo~=0.0.2 -# ovos-phal-plugin-mk1 @ git+https://github.com/openvoiceos/ovos-phal-plugin-mk1@dev +#ovos-phal-plugin-mk1 @ git+https://github.com/openvoiceos/ovos-phal-plugin-mk1@dev # TODO: Stable spec for mk1 plugin # ovos-phal-plugin-gpsd @ git+https://github.com/OpenVoiceOS/ovos-PHAL-plugin-gpsd ovos-gui-plugin-shell-companion==0.0.1a5 # Pi-specific skills -neon-skill-core_ready~=0.0.1 #,>=0.0.2a1 -neon-skill-update~=2.1 #,>=2.1.3a1 -# ovos-skill-homescreen~=0.0.2,>=0.0.3a16 +neon-skill-core_ready~=0.1 +neon-skill-update~=3.0 +# TODO: Pinned for stable releases ovos-skill-homescreen==0.0.3a16 # ovos-skill-setup~=0.0.1 ovos-skill-volume~=0.0.1 skill-markII-audio-receiver~=0.1 -# Backwards-compat -ovos-skills-manager~=0.0.13 # TODO: Remove in 2024 +# TODO: Below fixing alpha version resolution +ovos-plugin-manager==0.0.25 diff --git a/requirements/remote_speech_processing.txt b/requirements/remote_speech_processing.txt index 22062b7e1..28de6bf2c 100644 --- a/requirements/remote_speech_processing.txt +++ b/requirements/remote_speech_processing.txt @@ -1,6 +1,3 @@ neon-stt-plugin-google-cloud-streaming~=1.0 neon-tts-plugin-polly~=0.2 neon-lang-plugin-amazon_translate~=0.1 - -# Fallback TTS -ovos-tts-plugin-mimic \ No newline at end of file diff --git a/requirements/requirements.txt b/requirements/requirements.txt index e97b50364..cc9aebe65 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -2,15 +2,14 @@ ovos-core==0.0.7 # padacioso==0.1.3a2 -neon-utils[network]~=1.9 - -ovos-utils~=0.0.38 +neon-utils[network]~=1.10,>=1.10.1 +ovos-utils~=0.0,>=0.0.38 ovos-bus-client~=0.0.8 neon-transformers~=0.2 ovos-config~=0.0.12 ovos-plugin-manager~=0.0.25 -# ovos-backend-client~=0.1,>=0.1.1a2 -ovos-backend-client==0.1.1a5 # TODO +# TODO: ovos-backend-client pinned for stable release +ovos-backend-client==0.1.1a5 psutil~=5.6 click~=8.0 @@ -26,12 +25,13 @@ neon-utterance-normalizer-plugin~=0.1 requests~=2.29 - # TODO: Patching dependencies ovos-core[skills,skills_lgpl] extra deps adapt-parser~=0.5 padacioso~=0.1 -ovos-lingua-franca==0.4.8a7 # TODO -ovos-classifiers==0.0.0a53 # TODO ovos-phal-plugin-connectivity-events~=0.0.1 padatious~=0.4.8 fann2==1.0.7 + +# TODO: Pinned for stable release +ovos-lingua-franca==0.4.8a7 +ovos-classifiers==0.0.0a53 \ No newline at end of file diff --git a/requirements/skills_default.txt b/requirements/skills_default.txt index 4087962fc..56e4712cf 100644 --- a/requirements/skills_default.txt +++ b/requirements/skills_default.txt @@ -1,18 +1,18 @@ -skill-ddg==0.0.2a3 -neon-skill-alerts~=2.0 #,>=2.0.1a4 -neon-skill-caffeinewiz~=1.0 #,>=1.0.1a4 -neon-skill-data_controls~=2.0 #,>=2.0.1a2 -neon-skill-fallback_wolfram_alpha~=1.0 #,>=1.0.1a1 -neon-skill-personal~=1.0 #,>=1.0.1a3 -neon-skill-speak~=2.0 #,>=2.0.1a1 -neon-skill-speed_test~=1.0,>=1.0.1 #,>=1.0.2a1 -neon-skill-spelling~=1.0 #,>=1.0.1a1 -neon-skill-stock~=1.0 #,>=1.0.1a1 -neon-skill-support_helper~=1.2,>=1.2.1 #,>=1.2.2a1 -neon-skill-user_settings~=1.0 #,>=1.0.5a2 -neon-skill-weather~=1.0,>=1.0.1 #,>=1.0.2a1 -neon-skill-wikipedia~=1.0,>=1.0.1 #,>=1.0.2a1 -neon-skill-free_music_archive~=1.0 #,>=1.0.1a1 -neon-skill-local_music~=2.0 #,>=2.0.1a1 +skill-ddg==0.0.2a5 +neon-skill-alerts~=3.0 +neon-skill-caffeinewiz~=1.0,>=1.0.1 +neon-skill-data_controls~=2.0,>=2.0.1 +neon-skill-fallback_wolfram_alpha~=2.0 +neon-skill-personal~=1.0,>=1.0.1 +neon-skill-speak~=2.0,>=2.0.1 +neon-skill-speed_test~=1.0,>=1.0.2 +neon-skill-spelling~=1.1 +neon-skill-stock~=1.0 #,>=1.0.1a3 +neon-skill-support_helper~=1.2,>=1.2.2 +neon-skill-user_settings~=1.0,>=1.0.5 +neon-skill-weather~=2.0 +neon-skill-wikipedia~=1.0,>=1.0.2 +neon-skill-free_music_archive~=1.0,>=1.0.1 +neon-skill-local_music~=3.0 # neon-skill-holidays~=0.0.0a1 -neon-skill-fallback_llm~=1.0,>=1.0.1 #,>=1.0.2a2 +neon-skill-fallback_llm~=1.0 #,>=1.0.2a3 diff --git a/requirements/skills_essential.txt b/requirements/skills_essential.txt index 8a9aa5a9c..0d7e127d4 100644 --- a/requirements/skills_essential.txt +++ b/requirements/skills_essential.txt @@ -1,5 +1,5 @@ -neon-skill-about~=1.0 #,>=1.0.1a1 -neon-skill-date_time~=1.0 #,>=1.0.1a6 +neon-skill-about~=1.0,>=1.0.1 +neon-skill-date_time~=1.1 neon-skill-demo~=1.0,>=1.0.2 -neon-skill-device_controls~=1.0 #,>=1.0.1a5 -neon-skill-ip_address~=1.1 #,>=1.1.1a3 \ No newline at end of file +neon-skill-device_controls~=1.1 +neon-skill-ip_address~=1.2 \ No newline at end of file diff --git a/requirements/skills_extended.txt b/requirements/skills_extended.txt index 9d6800703..edd46b43e 100644 --- a/requirements/skills_extended.txt +++ b/requirements/skills_extended.txt @@ -1,12 +1,12 @@ -neon-skill-audio_record~=1.0 #,>=1.0.1a1 +neon-skill-audio_record~=1.0,>=1.0.1 # neon-skill-custom_conversation>=0.0.1a8,<0.0.2 -neon-skill-instructions~=0.1 #,>=0.1.1a3 -neon-skill-launcher~=1.0 #,>=1.0.1a1 +# neon-skill-instructions~=0.1,>=0.1.1a4 +neon-skill-launcher~=1.0,>=1.0.1 skill-news~=0.0.3 # neon-skill-recipes>=0.0.1a8 -neon-skill-synonyms~=1.0, >=1.0.1 #,>=1.0.2a2 -neon-skill-translation~=1.0 #,>=1.0.1a2 -neon-skill-camera~=1.0 #,>=1.0.1a1 +neon-skill-synonyms~=1.0,>=1.0.2 +neon-skill-translation~=1.0,>=1.0.1 +neon-skill-camera~=1.0,>=1.0.1 ovos-skill-somafm~=0.0.1 -neon-homeassistant-skill==0.0.14 # TODO: Pinned for stable release -ovos-skill-jokes @ git+https://github.com/openvoiceos/skill-ovos-icanhazdadjokes@ad20ee400c7195cfdb43596f32b1c0a4293ce941 \ No newline at end of file +neon-homeassistant-skill~=0.0.14 +ovos-skill-icanhazdadjokes @ git+https://github.com/openvoiceos/skill-ovos-icanhazdadjokes@882f4bd1bab077a531b9f6979510b78f340a1886 \ No newline at end of file diff --git a/requirements/skills_required.txt b/requirements/skills_required.txt index 0ef94d056..fa94afcb6 100644 --- a/requirements/skills_required.txt +++ b/requirements/skills_required.txt @@ -1,3 +1,4 @@ -ovos-skill-stop==0.3.0a7 -neon-skill-fallback_unknown~=1.2 +# TODO: Stop skill deprecated with ovos-core 0.0.8; pinned last release (with stable dependencies) +ovos-skill-stop==0.3.0a9 +neon-skill-fallback_unknown~=2.0 neon-skill-communication~=0.1 \ No newline at end of file diff --git a/requirements/test.txt b/requirements/test.txt index 8a682c42e..5f070af6b 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,4 +1,3 @@ pytest pytest-cov -mock~=5.0 -ovos-skills-manager~=0.0.13 \ No newline at end of file +mock~=5.0 \ No newline at end of file diff --git a/setup.py b/setup.py index 776c5347a..80b7b8399 100644 --- a/setup.py +++ b/setup.py @@ -110,13 +110,7 @@ def get_requirements(requirements_filename: str): include_package_data=True, entry_points={ 'console_scripts': [ - 'neon=neon_core.cli:neon_core_cli', - # TODO: Deprecate below entrypoints - 'neon_skills_service=neon_core.skills.__main__:main', - 'neon-install-default-skills=neon_core.util.skill_utils:install_skills_default', - 'neon-upload-diagnostics=neon_core.util.diagnostic_utils:cli_send_diags', - 'neon-start=neon_core.run_neon:start_neon', - 'neon-stop=neon_core.run_neon:stop_neon' + 'neon=neon_core.cli:neon_core_cli' ] } ) diff --git a/setup.sh b/setup.sh index 692e580b8..e2977decf 100644 --- a/setup.sh +++ b/setup.sh @@ -28,6 +28,8 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +echo "WARNING: This script is no longer supported and will be removed with core version 24.05.x" + # Check if run as root if [ "${USER}" == "root" ]; then read -r -p "Installing as root may cause problems, would you like to continue? [y/N]" -n1 input diff --git a/test/legacy_setup_dev_local.sh b/test/legacy_setup_dev_local.sh deleted file mode 100644 index 8e2fa4e3c..000000000 --- a/test/legacy_setup_dev_local.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/bash - -# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework -# All trademark and other rights reserved by their respective owners -# Copyright 2008-2022 Neongecko.com Inc. -# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, -# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo -# BSD-3 License -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -export GITHUB_TOKEN="${1}" - -installerDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -export installerDir -sourceDir="$( cd "$( dirname "${installerDir}" )" && pwd )" -# Preferences -export devMode=true # false will enable fullscreen gui, isolated directories, and other device management -export autoStart=false # enables neonAI to run at login of installUser -export autoUpdate=false # enables neonAI to check for updates at runtime -export devName=${HOSTNAME} # device name used to identify uploads -export installServer=true # enables neonAI server module - -export sttModule="deepspeech_stream_local" -export ttsModule="neon_tts_mimic" - -localDeps="true" -installGui="false" -options=("core_modules") -options+=("test") -if [ "${localDeps}" == "true" ]; then - options+=("local") -else - options+=("remote") -fi - -if [ "${installServer}" == "true" ]; then - options+=("server") -else - options+=("client") -fi - -if [ "${devMode}" == "true" ]; then - options+=("dev") -fi -optStr=$(printf ",%s" "${options[@]}") -optStr="[${optStr:1}]" - -# Create install directory if specified and doesn't exist -if [ ! -d "${installerDir}" ]; then - echo "Creating Install Directory: ${installerDir}" - mkdir -p "${installerDir}" -fi - -# Make venv if not in one -if [ -z "${VIRTUAL_ENV}" ]; then - echo "Creating new Virtual Environment" - cd "${installerDir}" || exit 10 - python3 -m venv .venv - . .venv/bin/activate -fi - -## Actual Installation bits -# Add Mimic apt repository -sudo apt install -y curl -curl https://forslund.github.io/mycroft-desktop-repo/mycroft-desktop.gpg.key | sudo apt-key add - 2> /dev/null && echo "deb http://forslund.github.io/mycroft-desktop-repo bionic main" | sudo tee /etc/apt/sources.list.d/mycroft-desktop.list -sudo apt-get update - -# Install system dependencies -sudo apt install -y python3-dev python3-venv python3-pip swig libssl-dev libfann-dev portaudio19-dev git mpg123 ffmpeg mimic libpulse-dev - -# Do GUI install -if [ "${installGui}" == "true" ]; then - if [ -d mycroft-gui ]; then - rm -rf mycroft-gui - fi - git clone https://github.com/mycroftai/mycroft-gui - bash mycroft-gui/dev_setup.sh - rm -rf mycroft-gui -fi - -echo "${GITHUB_TOKEN}">~/token.txt -pip install --upgrade pip~=21.3 -pip install wheel - -cd "${sourceDir}" || exit 10 -pip install ".${optStr}" # --use-deprecated=legacy-resolver - -export NEON_CONFIG_PATH="${sourceDir}" -export logsDir="~/test/logs" -neon-config-import - -# Install Default Skills -neon-install-default-skills - -exit 0 diff --git a/test/legacy_setup_remote.sh b/test/legacy_setup_remote.sh deleted file mode 100644 index 5840d6a48..000000000 --- a/test/legacy_setup_remote.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/bin/bash - -# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework -# All trademark and other rights reserved by their respective owners -# Copyright 2008-2022 Neongecko.com Inc. -# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, -# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo -# BSD-3 License -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -export GITHUB_TOKEN="${1}" - -installerDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -export installerDir -sourceDir="$( cd "$( dirname "${installerDir}" )" && pwd )" - -# Preferences -export devMode=false # false will enable fullscreen gui, isolated directories, and other device management -export autoStart=false # enables neonAI to run at login of installUser -export autoUpdate=false # enables neonAI to check for updates at runtime -export devName=${HOSTNAME} # device name used to identify uploads -export installServer=true # enables neonAI server module - -export sttModule="google_cloud_streaming" -export ttsModule="amazon" - -localDeps="false" -installGui="false" -options=("core_modules") -options+=("test") -if [ "${localDeps}" == "true" ]; then - options+=("local") -else - options+=("remote") -fi - -if [ "${installServer}" == "true" ]; then - options+=("server") -else - options+=("client") -fi - -if [ "${devMode}" == "true" ]; then - options+=("dev") -fi -optStr=$(printf ",%s" "${options[@]}") -optStr="[${optStr:1}]" - -# Create install directory if specified and doesn't exist -if [ ! -d "${installerDir}" ]; then - echo "Creating Install Directory: ${installerDir}" - mkdir -p "${installerDir}" -fi - -# Make venv if not in one -if [ -z "${VIRTUAL_ENV}" ]; then - echo "Creating new Virtual Environment" - cd "${installerDir}" || exit 10 - python3 -m venv .venv - . .venv/bin/activate -fi - -## Actual Installation bits -# Add Mimic apt repository -sudo apt install -y curl -curl https://forslund.github.io/mycroft-desktop-repo/mycroft-desktop.gpg.key | sudo apt-key add - 2> /dev/null && echo "deb http://forslund.github.io/mycroft-desktop-repo bionic main" | sudo tee /etc/apt/sources.list.d/mycroft-desktop.list -sudo apt-get update - -# Install system dependencies -sudo apt install -y python3-dev python3-venv python3-pip swig libssl-dev libfann-dev portaudio19-dev git mpg123 ffmpeg mimic libpulse-dev - - -# Do GUI install -if [ "${installGui}" == "true" ]; then - if [ -d mycroft-gui ]; then - rm -rf mycroft-gui - fi - git clone https://github.com/mycroftai/mycroft-gui - bash mycroft-gui/dev_setup.sh - rm -rf mycroft-gui -fi - - -echo "${GITHUB_TOKEN}">~/token.txt -pip install --upgrade pip~=21.3 -pip install wheel - -cd "${sourceDir}" || exit 10 -pip install ".${optStr}" # --use-deprecated=legacy-resolver - -export NEON_CONFIG_PATH="${sourceDir}" -export logsDir="~/.local/share/neon/logs" -neon-config-import - -# Install Default Skills -neon-install-default-skills - -exit 0 diff --git a/test/license_tests.py b/test/license_tests.py deleted file mode 100644 index 651123caa..000000000 --- a/test/license_tests.py +++ /dev/null @@ -1,71 +0,0 @@ -import unittest -from pprint import pprint - -from lichecker import LicenseChecker - -# these packages dont define license in setup.py -# manually verified and injected -license_overrides = { - "kthread": "MIT", - 'yt-dlp': "Unlicense", - 'pyxdg': 'GPL-2.0', - 'ptyprocess': 'ISC license', - 'psutil': 'BSD3', - 'pyaudio': 'MIT', - 'petact': 'MIT', - "precise-runner": "Apache-2.0", - 'soupsieve': 'MIT', - 'setuptools': 'MIT', - 'sonopy': 'Apache-2.0', - "ovos-skill-installer": "MIT", - "python-dateutil": "Apache-2.0", - "pyparsing": "MIT", - "exceptiongroup": "MIT", - "idna": "BSD3" -} -# explicitly allow these packages that would fail otherwise -whitelist = ["neon-core", - "neon-audio", - "neon-speech", - "neon-gui", - "neon-messagebus", - "neon-api-proxy" - # "python-vlc" # This may be installed optionally - ] - -# validation flags -allow_nonfree = False -allow_viral = False -allow_unknown = False -allow_unlicense = True -allow_ambiguous = False - -pkg_name = "neon-core" - - -class TestLicensing(unittest.TestCase): - @classmethod - def setUpClass(self): - licheck = LicenseChecker(pkg_name, - license_overrides=license_overrides, - whitelisted_packages=whitelist, - allow_ambiguous=allow_ambiguous, - allow_unlicense=allow_unlicense, - allow_unknown=allow_unknown, - allow_viral=allow_viral, - allow_nonfree=allow_nonfree) - print("Package", pkg_name) - print("Version", licheck.version) - print("License", licheck.license) - print("Transient Requirements (dependencies of dependencies)") - pprint(licheck.transient_dependencies) - self.licheck = licheck - - def test_license_compliance(self): - print("Package Versions") - pprint(self.licheck.versions) - - print("Dependency Licenses") - pprint(self.licheck.licenses) - - self.licheck.validate() diff --git a/test/pi_setup_3_7.sh b/test/pi_setup_3_7.sh deleted file mode 100644 index 86dd4ad51..000000000 --- a/test/pi_setup_3_7.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework -# All trademark and other rights reserved by their respective owners -# Copyright 2008-2022 Neongecko.com Inc. -# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, -# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo -# BSD-3 License -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Override DNS resolver -rm /etc/resolv.conf -echo "nameserver 1.1.1.1" | tee /etc/resolv.conf - -# install system packages -apt update -apt install -y curl -curl https://forslund.github.io/mycroft-desktop-repo/mycroft-desktop.gpg.key | apt-key add - 2> /dev/null && \ -echo "deb http://forslund.github.io/mycroft-desktop-repo bionic main" | tee /etc/apt/sources.list.d/mycroft-desktop.list -apt update -apt install -y sox gcc libfann-dev swig libssl-dev portaudio19-dev git libpulse-dev mimic espeak-ng g++ libjpeg-dev make || exit 1 - -cd /core || exit 10 -python3.7 -m venv "/core/venv" || exit 11 -. /core/venv/bin/activate - -pip install --upgrade pip wheel "cython<3.0.0" # TODO: cython patching https://github.com/yaml/pyyaml/issues/724 -pip install --no-build-isolation pyyaml~=5.4 # TODO: patching https://github.com/yaml/pyyaml/issues/724 -pip install ".[core_modules,skills_required,skills_essential,skills_default,skills_extended,pi]" || exit 11 - -cp -rf /core/test/pi_image_overlay/* / \ No newline at end of file diff --git a/test/test_setup_dev_local.py b/test/test_setup_dev_local.py deleted file mode 100644 index ddf68e5ff..000000000 --- a/test/test_setup_dev_local.py +++ /dev/null @@ -1,61 +0,0 @@ -# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework -# All trademark and other rights reserved by their respective owners -# Copyright 2008-2022 Neongecko.com Inc. -# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, -# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo -# BSD-3 License -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import unittest - -from neon_core.util.runtime_utils import use_neon_core -from ovos_utils.xdg_utils import xdg_data_home - - -class TestSetupDevLocal(unittest.TestCase): - @use_neon_core - def test_config_from_setup(self): - from mycroft.configuration import Configuration - config = Configuration() - - self.assertTrue(config.get("debug")) - self.assertEqual(config["stt"]["module"], "deepspeech_stream_local") - self.assertEqual(config["tts"]["module"], "neon_tts_mimic") - self.assertIsInstance(config["skills"]["neon_token"], str) - - def test_installed_packages(self): - import neon_tts_plugin_mimic - import neon_stt_plugin_deepspeech_stream_local - import mycroft - import neon_cli - - def test_installed_skills(self): - self.assertEqual(str(xdg_data_home()), os.path.expanduser("~/.local/share")) - skill_dir = os.path.join(str(xdg_data_home()), "neon", "skills") - self.assertTrue(os.path.isdir(skill_dir)) - self.assertGreater(len(os.listdir(skill_dir)), 0) - - -if __name__ == '__main__': - unittest.main() diff --git a/test/test_setup_remote.py b/test/test_setup_remote.py deleted file mode 100644 index cd3e8c181..000000000 --- a/test/test_setup_remote.py +++ /dev/null @@ -1,62 +0,0 @@ -# NEON AI (TM) SOFTWARE, Software Development Kit & Application Framework -# All trademark and other rights reserved by their respective owners -# Copyright 2008-2022 Neongecko.com Inc. -# Contributors: Daniel McKnight, Guy Daniels, Elon Gasper, Richard Leeds, -# Regina Bloomstine, Casimiro Ferreira, Andrii Pernatii, Kirill Hrymailo -# BSD-3 License -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# 1. Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import os -import unittest - -from neon_core.util.runtime_utils import use_neon_core -from ovos_utils.xdg_utils import xdg_data_home - - -class TestSetupRemote(unittest.TestCase): - @use_neon_core - def test_config_from_setup(self): - from mycroft.configuration import Configuration - config = Configuration() - - self.assertFalse(config.get("debug")) - self.assertEqual(config["stt"]["module"], "google_cloud_streaming") - self.assertEqual(config["tts"]["module"], "amazon") - self.assertIsInstance(config["skills"]["neon_token"], str) - - def test_installed_packages(self): - import neon_tts_plugin_polly - import neon_stt_plugin_google_cloud_streaming - import mycroft - with self.assertRaises(ImportError): - import neon_test_utils - - def test_installed_skills(self): - self.assertEqual(str(xdg_data_home()), os.path.expanduser("~/.local/share")) - skill_dir = os.path.join(str(xdg_data_home()), "neon", "skills") - self.assertTrue(os.path.isdir(skill_dir)) - self.assertGreater(len(os.listdir(skill_dir)), 0) - - -if __name__ == '__main__': - unittest.main() diff --git a/test/test_skill_utils.py b/test/test_skill_utils.py index 9be227c52..00a590f74 100644 --- a/test/test_skill_utils.py +++ b/test/test_skill_utils.py @@ -32,6 +32,7 @@ import unittest from os.path import dirname, join, exists, isdir from unittest.mock import patch +from unittest import skip sys.path.append(os.path.dirname(os.path.dirname(__file__))) @@ -72,16 +73,15 @@ def tearDown(self) -> None: def test_get_skills_from_remote_list(self): from neon_core.util.skill_utils import _get_skills_from_remote_list - # from ovos_skills_manager.session import set_github_token,\ - # clear_github_token - # set_github_token(SKILL_CONFIG["neon_token"]) + skills_list = _get_skills_from_remote_list(SKILL_CONFIG["default_skills"]) - # clear_github_token() + self.assertIsInstance(skills_list, list) self.assertTrue(len(skills_list) > 0) self.assertTrue(all(skill.startswith("https://github.com") for skill in skills_list)) + @skip("Installation from Git is deprecated") def test_install_skills_from_list_no_auth(self): from neon_core.util.skill_utils import install_skills_from_list install_skills_from_list(TEST_SKILLS_NO_AUTH, SKILL_CONFIG) @@ -90,6 +90,7 @@ def test_install_skills_from_list_no_auth(self): self.assertEqual(len(skill_dirs), len(TEST_SKILLS_NO_AUTH)) self.assertIn("alerts.neon.neongeckocom", skill_dirs) + @skip("Installation from Git is deprecated") def test_install_skills_from_list_with_auth(self): from neon_core.util.skill_utils import install_skills_from_list install_skills_from_list(TEST_SKILLS_WITH_AUTH, SKILL_CONFIG) @@ -106,25 +107,19 @@ def test_install_skills_default(self, install_skills): expected = _get_skills_from_remote_list(SKILL_CONFIG["default_skills"]) install_skills.assert_called_once_with(expected, install_skills.call_args[0][1]) - # skill_dirs = [d for d in os.listdir(SKILL_DIR) if - # os.path.isdir(os.path.join(SKILL_DIR, d))] - # self.assertEqual( - # len(skill_dirs), - # len(_get_skills_from_remote_list(SKILL_CONFIG["default_skills"])), - # f"{skill_dirs}\n\n" - # f"{_get_skills_from_remote_list(SKILL_CONFIG['default_skills'])}") def test_install_skills_with_pip(self): from neon_core.util.skill_utils import install_skills_from_list install_skills_from_list(TEST_SKILLS_WITH_PIP, SKILL_CONFIG) skill_dirs = [d for d in os.listdir(SKILL_DIR) if os.path.isdir(os.path.join(SKILL_DIR, d))] - self.assertEqual(len(skill_dirs), 1) - self.assertIn("skill-date_time.neongeckocom", skill_dirs) + self.assertEqual(len(skill_dirs), 0) + # self.assertIn("skill-date_time.neongeckocom", skill_dirs) returned = os.system("pip show neon-skill-support-helper") self.assertEqual(returned, 0) + @skip("OSM skill installation deprecated") def test_get_neon_skills_data(self): from neon_core.util.skill_utils import get_neon_skills_data from ovos_skills_manager.github.utils import normalize_github_url @@ -135,29 +130,13 @@ def test_get_neon_skills_data(self): self.assertEqual(skill, normalize_github_url(neon_skills[skill]["url"])) - # def test_install_local_skills(self): - # import ovos_skills_manager.requirements - # import neon_core.util.skill_utils - # importlib.reload(neon_core.util.skill_utils) - # install_pip_deps = Mock() - # install_sys_deps = Mock() - # ovos_skills_manager.requirements.pip_install = install_pip_deps - # ovos_skills_manager.requirements.install_system_deps = install_sys_deps - # - # install_local_skills = neon_core.util.skill_utils.install_local_skills - # - # local_skills_dir = os.path.join(os.path.dirname(__file__), - # "local_skills") - # - # installed = install_local_skills(local_skills_dir) - # num_installed = len(installed) - # self.assertEqual(installed, os.listdir(local_skills_dir)) - # self.assertEqual(num_installed, install_pip_deps.call_count) - # self.assertEqual(num_installed, install_sys_deps.call_count) - def test_write_pip_constraints_to_file(self): from neon_core.util.skill_utils import _write_pip_constraints_to_file from neon_utils.packaging_utils import get_package_dependencies + + with self.assertRaises(ValueError): + _write_pip_constraints_to_file("") + real_deps = get_package_dependencies("neon-core") real_deps = [f'{c.split("[")[0]}{c.split("]")[1]}' if '[' in c else c for c in real_deps if '@' not in c] @@ -168,14 +147,6 @@ def test_write_pip_constraints_to_file(self): read_deps = f.read().split('\n') self.assertTrue(all((d in read_deps for d in real_deps))) - try: - _write_pip_constraints_to_file() - self.assertTrue(os.path.isfile("/etc/mycroft/constraints.txt")) - with open("/etc/mycroft/constraints.txt") as f: - deps = f.read().split('\n') - self.assertTrue(all((d in deps for d in real_deps))) - except Exception as e: - self.assertIsInstance(e, PermissionError) os.remove(test_outfile) # def test_set_osm_constraints_file(self): @@ -185,6 +156,7 @@ def test_write_pip_constraints_to_file(self): # self.assertEqual(ovos_skills_manager.requirements.DEFAULT_CONSTRAINTS, # __file__) + @skip("Skill class patching is deprecated") def test_skill_class_patches(self): import neon_core.skills # Import to do all the patching from neon_utils.skills.mycroft_skill import PatchedMycroftSkill diff --git a/test/test_skills_module.py b/test/test_skills_module.py index c61279528..883972ba1 100644 --- a/test/test_skills_module.py +++ b/test/test_skills_module.py @@ -131,8 +131,8 @@ def ready_hook(): stopping_hook.assert_called_once() service.join(10) - @patch("ovos_utils.skills.locations.get_plugin_skills") - @patch("ovos_utils.skills.locations.get_skill_directories") + @patch("ovos_plugin_manager.skills.get_plugin_skills") + @patch("ovos_plugin_manager.skills.get_skill_directories") def test_get_skill_dirs(self, skill_dirs, plugin_skills): from neon_core.skills.service import NeonSkillService