diff --git a/.github/workflows/license_tests.yml b/.github/workflows/license_tests.yml index 7adc134e..cc773f98 100644 --- a/.github/workflows/license_tests.yml +++ b/.github/workflows/license_tests.yml @@ -11,4 +11,3 @@ jobs: uses: neongeckocom/.github/.github/workflows/license_tests.yml@master with: package-extras: audio,configuration,networking - packages-exclude: '^(precise-runner|fann2|tqdm|bs4|ovos-phal-plugin|ovos-skill|neon-core|nvidia|neon-phal-plugin|bitstruct|audioread|RapidFuzz|click|setuptools|typing_extensions|urllib|marisa-trie).*' diff --git a/neon_utils/file_utils.py b/neon_utils/file_utils.py index a23eb181..ca333405 100644 --- a/neon_utils/file_utils.py +++ b/neon_utils/file_utils.py @@ -34,8 +34,7 @@ from tempfile import mkstemp from typing import Optional, List -from ovos_utils.signal import ensure_directory_exists - +from ovos_utils.file_utils import ensure_directory_exists from neon_utils.logger import LOG diff --git a/neon_utils/signal_utils.py b/neon_utils/signal_utils.py index 93f45fea..b0d563ac 100644 --- a/neon_utils/signal_utils.py +++ b/neon_utils/signal_utils.py @@ -124,14 +124,11 @@ def init_signal_handlers(): log_deprecation("Import patching will be deprecated. Disable in " "configuration by setting `signal`.`patch_imports` " "to `False`", "2.0.0") - import ovos_utils.signal - ovos_utils.signal.check_for_signal = _check_for_signal - ovos_utils.signal.create_signal = _create_signal try: import mycroft.util.signal mycroft.util.signal.create_signal = _create_signal mycroft.util.signal.check_for_signal = _check_for_signal - LOG.info(f"Overrode mycroft.util.signal methods") + LOG.info("Overrode mycroft.util.signal methods") except (ImportError, AttributeError) as e: LOG.debug(e) except TypeError as e: @@ -141,12 +138,100 @@ def init_signal_handlers(): else: LOG.warning("FS signals are deprecated. Signal methods will have no effect.") if patch_imports: - log_deprecation("Import patching will be deprecated. Disable in " - "configuration by setting `signal`.`patch_imports` " - "to `False`", "2.0.0") - import ovos_utils.signal - _create_signal = ovos_utils.signal.create_signal - _check_for_signal = ovos_utils.signal.check_for_signal + import os + import tempfile + from ovos_utils.file_utils import ensure_directory_exists + + def get_ipc_directory(domain=None, config=None): + """Get the directory used for Inter Process Communication + + Files in this folder can be accessed by different processes on the + machine. Useful for communication. This is often a small RAM disk. + + Args: + domain (str): The IPC domain. Basically a subdirectory to prevent + overlapping signal filenames. + config (dict): mycroft.conf, to read ipc directory from + + Returns: + str: a path to the IPC directory + """ + if config is None: + try: + from ovos_config.config import Configuration + config = Configuration() + except ImportError: + LOG.warning("Config not provided and ovos_config not available") + config = dict() + path = config.get("ipc_path") + if not path: + # If not defined, use /tmp/mycroft/ipc + path = os.path.join(tempfile.gettempdir(), "mycroft", "ipc") + return ensure_directory_exists(path, domain) + + def create_file(filename): + """ Create the file filename and create any directories needed + + Args: + filename: Path to the file to be created + """ + try: + os.makedirs(os.path.dirname(filename)) + except OSError: + pass + with open(filename, 'w') as f: + f.write('') + + def create_signal(signal_name, config=None): + """Create a named signal + + Args: + signal_name (str): The signal's name. Must only contain characters + valid in filenames. + config (dict): mycroft.conf, to read ipc directory from + """ + try: + path = os.path.join(get_ipc_directory(config=config), + "signal", signal_name) + create_file(path) + return os.path.isfile(path) + except IOError: + return False + + + def check_for_signal(signal_name, sec_lifetime=0, config=None): + """See if a named signal exists + + Args: + signal_name (str): The signal's name. Must only contain characters + valid in filenames. + sec_lifetime (int, optional): How many seconds the signal should + remain valid. If 0 or not specified, it is a single-use signal. + If -1, it never expires. + config (dict): mycroft.conf, to read ipc directory from + + Returns: + bool: True if the signal is defined, False otherwise + """ + path = os.path.join(get_ipc_directory(config=config), + "signal", signal_name) + if os.path.isfile(path): + if sec_lifetime == 0: + # consume this single-use signal + os.remove(path) + elif sec_lifetime == -1: + return True + elif int(os.path.getctime(path) + sec_lifetime) < int(time.time()): + # remove once expired + os.remove(path) + return False + return True + + # No such signal exists + return False + + _create_signal = create_signal + _check_for_signal = check_for_signal _wait_for_signal_clear = _fs_wait_for_signal_clear _wait_for_signal_create = _fs_wait_for_signal_create else: diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 71314602..bbba9677 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -7,5 +7,7 @@ pyyaml>=5.4,<7.0 ovos-lingua-franca~=0.4 ovos-utils~=0.0,>=0.0.35 geopy~=2.1 -ovos-config~=0.0,>=0.0.9 -ovos-workshop~=0.0,>=0.0.15 \ No newline at end of file +ovos-config~=0.1 +ovos-workshop~=0.0,>=0.0.15 +# TODO: Refactor to remove `pkg_resources` imports +setuptools<82.0.0 diff --git a/tests/location_util_tests.py b/tests/location_util_tests.py index b269f32e..2033476d 100644 --- a/tests/location_util_tests.py +++ b/tests/location_util_tests.py @@ -126,9 +126,9 @@ def test_get_full_location(self): location_es = get_full_location("Seattle, Washington", "es") self.assertAlmostEqual(float(location_es['lat']), - float(location_en['lat']), places=6) + float(location_en['lat']), places=3) self.assertAlmostEqual(float(location_es['lon']), - float(location_en['lon']), places=6) + float(location_en['lon']), places=3) self.assertEqual(location_es['address']['country'], "Estados Unidos de América") self.assertEqual(location_en['address']['country_code'], "us") diff --git a/tests/signal_util_tests.py b/tests/signal_util_tests.py index 528dc71e..bdc256dd 100644 --- a/tests/signal_util_tests.py +++ b/tests/signal_util_tests.py @@ -33,7 +33,6 @@ from threading import Event from os.path import join, dirname -import ovos_utils.signal from ovos_bus_client import Message from ovos_utils.messagebus import FakeBus @@ -132,7 +131,7 @@ def on_create(message): self.assertEqual(msg.data, {'signal_name': 'test_signal'}) self.assertEqual(msg.context['origin_module'], 'tests.signal_util_tests') - self.assertEqual(msg.context['origin_line'], 130) + self.assertEqual(msg.context['origin_line'], 129) def test_signal_utils_manager_available(self): TestSignalManager(self.test_bus) @@ -151,40 +150,21 @@ def test_signal_utils_manager_available(self): self.assertEqual(neon_utils.signal_utils._wait_for_signal_create, neon_utils.signal_utils._manager_wait_for_signal_create) - # Check ovos_utils references - self.assertEqual(ovos_utils.signal.check_for_signal, - neon_utils.signal_utils._manager_check_for_signal) - self.assertEqual(ovos_utils.signal.create_signal, - neon_utils.signal_utils._manager_create_signal) - def test_signal_utils_manager_unavailable(self): - import ovos_utils.signal neon_utils.signal_utils.init_signal_handlers() self.assertFalse(neon_utils.signal_utils.check_signal_manager_available()) self.assertIsInstance(neon_utils.signal_utils._MAX_TIMEOUT, int) - self.assertEqual(neon_utils.signal_utils._check_for_signal, - ovos_utils.signal.check_for_signal) - self.assertEqual(neon_utils.signal_utils._create_signal, - ovos_utils.signal.create_signal) self.assertEqual(neon_utils.signal_utils._wait_for_signal_clear, neon_utils.signal_utils._fs_wait_for_signal_clear) self.assertEqual(neon_utils.signal_utils._wait_for_signal_create, neon_utils.signal_utils._fs_wait_for_signal_create) def test_signal_utils_reload(self): - import ovos_utils.signal - from neon_utils.signal_utils import _check_for_signal self.assertFalse(neon_utils.signal_utils.check_signal_manager_available()) - self.assertEqual(neon_utils.signal_utils._check_for_signal, - ovos_utils.signal.check_for_signal) - self.assertEqual(neon_utils.signal_utils._create_signal, - ovos_utils.signal.create_signal) self.assertEqual(neon_utils.signal_utils._wait_for_signal_clear, neon_utils.signal_utils._fs_wait_for_signal_clear) self.assertEqual(neon_utils.signal_utils._wait_for_signal_create, neon_utils.signal_utils._fs_wait_for_signal_create) - self.assertEqual(_check_for_signal, - ovos_utils.signal.check_for_signal) TestSignalManager(self.test_bus) neon_utils.signal_utils.init_signal_handlers() @@ -197,13 +177,8 @@ def test_signal_utils_reload(self): self.assertEqual(neon_utils.signal_utils._wait_for_signal_create, neon_utils.signal_utils._manager_wait_for_signal_create) - # Previously imported method is not updated - self.assertEqual(_check_for_signal, - ovos_utils.signal.check_for_signal) - def test_check_signal_manager_available_lazy_load_bus(self): from ovos_bus_client import MessageBusClient - from neon_utils.signal_utils import check_signal_manager_available neon_utils.signal_utils._BUS = None neon_utils.signal_utils.check_signal_manager_available() self.assertIsInstance(neon_utils.signal_utils._BUS, MessageBusClient) diff --git a/tests/web_util_tests.py b/tests/web_util_tests.py index 52ed6b4c..f470cd5f 100644 --- a/tests/web_util_tests.py +++ b/tests/web_util_tests.py @@ -37,14 +37,14 @@ class WebUtilTests(unittest.TestCase): def test_scrape_page_for_links(self): try: - links = scrape_page_for_links("neon.ai") + links = scrape_page_for_links("2025.neon.ai") self.assertIsInstance(links, dict) self.assertIn("company", links.keys()) # TODO: Update test to validate absolute and relative URL paths # Relative href self.assertIn(links["company"], - ("https://neon.ai/company", - "https://neon.ai/company/")) + ("https://2025.neon.ai/company", + "https://2025.neon.ai/company/")) except ConnectTimeout: LOG.error("Github testing breaks here")