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/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 59dfcc38..2eba3df0 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -39,6 +39,7 @@ jobs: path: tests/skill-object-test-results.xml unit_tests: strategy: + fail-fast: false matrix: python-version: [ 3.9, '3.10', '3.11', '3.12' ] runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 1544e5a9..3695b98e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,77 +1,20 @@ # Changelog -## [1.13.1a8](https://github.com/NeonGeckoCom/neon-utils/tree/1.13.1a8) (2025-09-12) +## [1.14.1a2](https://github.com/NeonGeckoCom/neon-utils/tree/1.14.1a2) (2026-06-08) -[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.13.1a7...1.13.1a8) +[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.14.1a1...1.14.1a2) **Merged pull requests:** -- Add function to get installed prerelease packages [\#517](https://github.com/NeonGeckoCom/neon-utils/pull/517) ([NeonDaniel](https://github.com/NeonDaniel)) +- Update `ovos-utils` compat. changes [\#563](https://github.com/NeonGeckoCom/neon-utils/pull/563) ([NeonDaniel](https://github.com/NeonDaniel)) -## [1.13.1a7](https://github.com/NeonGeckoCom/neon-utils/tree/1.13.1a7) (2025-09-12) +## [1.14.1a1](https://github.com/NeonGeckoCom/neon-utils/tree/1.14.1a1) (2026-03-13) -[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.13.1a6...1.13.1a7) - -**Implemented enhancements:** - -- \[FEAT\] Allow self-signed certificates in hana-utils [\#536](https://github.com/NeonGeckoCom/neon-utils/issues/536) -- \[FEAT\] Docker handling of status hooks [\#498](https://github.com/NeonGeckoCom/neon-utils/issues/498) - -**Merged pull requests:** - -- Refactor to remove use of deprecated `pkg_resources` module [\#555](https://github.com/NeonGeckoCom/neon-utils/pull/555) ([NeonDaniel](https://github.com/NeonDaniel)) - -## [1.13.1a6](https://github.com/NeonGeckoCom/neon-utils/tree/1.13.1a6) (2025-09-12) - -[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.13.1a5...1.13.1a6) - -**Merged pull requests:** - -- Add support for authenticated HANA [\#537](https://github.com/NeonGeckoCom/neon-utils/pull/537) ([NeonDaniel](https://github.com/NeonDaniel)) - -## [1.13.1a5](https://github.com/NeonGeckoCom/neon-utils/tree/1.13.1a5) (2025-09-12) - -[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.13.1a4...1.13.1a5) - -**Merged pull requests:** - -- Refactor log aggregators init [\#560](https://github.com/NeonGeckoCom/neon-utils/pull/560) ([NeonDaniel](https://github.com/NeonDaniel)) - -## [1.13.1a4](https://github.com/NeonGeckoCom/neon-utils/tree/1.13.1a4) (2025-09-11) - -[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.13.1a3...1.13.1a4) - -**Merged pull requests:** - -- Update pip package installation method [\#556](https://github.com/NeonGeckoCom/neon-utils/pull/556) ([NeonDaniel](https://github.com/NeonDaniel)) - -## [1.13.1a3](https://github.com/NeonGeckoCom/neon-utils/tree/1.13.1a3) (2025-09-10) - -[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.13.1a2...1.13.1a3) - -**Implemented enhancements:** - -- \[FEAT\] Deprecate ovos-core dependency [\#469](https://github.com/NeonGeckoCom/neon-utils/issues/469) - -**Merged pull requests:** - -- Remove ovos-core test dependency [\#557](https://github.com/NeonGeckoCom/neon-utils/pull/557) ([NeonDaniel](https://github.com/NeonDaniel)) - -## [1.13.1a2](https://github.com/NeonGeckoCom/neon-utils/tree/1.13.1a2) (2025-09-10) - -[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.13.1a1...1.13.1a2) - -**Merged pull requests:** - -- Improve Skill metadata parsing support and remove OSM dependency [\#558](https://github.com/NeonGeckoCom/neon-utils/pull/558) ([NeonDaniel](https://github.com/NeonDaniel)) - -## [1.13.1a1](https://github.com/NeonGeckoCom/neon-utils/tree/1.13.1a1) (2025-08-27) - -[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.13.0...1.13.1a1) +[Full Changelog](https://github.com/NeonGeckoCom/neon-utils/compare/1.14.0...1.14.1a1) **Merged pull requests:** -- Update Skill API to support outside applications [\#554](https://github.com/NeonGeckoCom/neon-utils/pull/554) ([NeonDaniel](https://github.com/NeonDaniel)) +- Fix compatibility with latest ovos-utils release [\#562](https://github.com/NeonGeckoCom/neon-utils/pull/562) ([NeonDaniel](https://github.com/NeonDaniel)) 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..1373024e 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,103 @@ def init_signal_handlers(): else: LOG.warning("FS signals are deprecated. Signal methods will have no effect.") if patch_imports: + import os + import tempfile + from ovos_utils.file_utils import ensure_directory_exists 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 + "configuration by setting `signal`.`patch_imports` " + "to `False`", "2.0.0") + + 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..6cd64011 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -5,7 +5,9 @@ timezonefinder~=5.2 nltk~=3.5 pyyaml>=5.4,<7.0 ovos-lingua-franca~=0.4 -ovos-utils~=0.0,>=0.0.35 +ovos-utils~=0.8,>=0.8.5 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") diff --git a/version.py b/version.py index f6ec4d9c..70af1dd9 100644 --- a/version.py +++ b/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__ = "1.14.0" +__version__ = "1.14.1"