Repository: datalad/datalad-next

Issue:
Test failures on main
Core's extension test fails with datalad-next: https://github.com/datalad/datalad/actions/runs/3658950849/jobs/6184374333

Apparently the URL PATH pair given to `download` in https://github.com/datalad/datalad-next/blob/main/datalad_next/commands/tests/test_download.py#L73 ends up being interpreted as a single `Path`: https://github.com/datalad/datalad/actions/runs/3658950849/jobs/6184374333#step:13:2283


Furthermore, `test_cmd_with_validation` seems to compare a string and a `Path`: https://github.com/datalad/datalad/actions/runs/3658950849/jobs/6184374333#step:13:2336

Discussion:
mih: The patch that is dealt with here comes in #136 

Patch:
diff --git a/datalad_next/commands/__init__.py b/datalad_next/commands/__init__.py
index a069a99..4c660d3 100644
--- a/datalad_next/commands/__init__.py
+++ b/datalad_next/commands/__init__.py
@@ -6,10 +6,13 @@ from datalad.interface.base import (
     build_doc,
 )
 from datalad.interface.results import get_status_dict
-from datalad.interface.utils import (
-    eval_results,
-    generic_result_renderer,
-)
+from datalad.interface.utils import generic_result_renderer
+try:
+    # datalad 0.17.10+
+    from datalad.interface.base import eval_results
+except ImportError:
+    # older datalad
+    from datalad.interface.utils import eval_results
 from datalad.support.param import Parameter
 
 from datalad_next.constraints.parameter import EnsureCommandParameterization
diff --git a/datalad_next/patches/interface_utils.py b/datalad_next/patches/interface_utils.py
index 318996e..ab96abc 100644
--- a/datalad_next/patches/interface_utils.py
+++ b/datalad_next/patches/interface_utils.py
@@ -11,7 +11,6 @@ from datalad.core.local.resulthooks import (
     match_jsonhook2result,
     run_jsonhook,
 )
-from datalad.interface import utils as mod_interface_utils
 from datalad.interface.results import known_result_xfms
 from datalad.interface.utils import (
     anInterface,
@@ -249,5 +248,14 @@ def _execute_command_(
 
 
 # apply patch
-lgr.debug('Apply datalad-next patch to interface.utils.py:_execute_command_')
-mod_interface_utils._execute_command_ = _execute_command_
+from datalad.interface import utils as mod_interface_utils
+if hasattr(mod_interface_utils, '_execute_command_'):
+    lgr.debug(
+        'Apply datalad-next patch to interface.utils.py:_execute_command_')
+    mod_interface_utils._execute_command_ = _execute_command_
+else:
+    # we have datalad 0.17.10+ and the target has moved
+    from datalad.interface import base as mod_interface_base
+    lgr.debug(
+        'Apply datalad-next patch to interface.base.py:_execute_command_')
+    mod_interface_base._execute_command_ = _execute_command_
diff --git a/datalad_next/url_operations/any.py b/datalad_next/url_operations/any.py
index 7ab94ad..f24ea54 100644
--- a/datalad_next/url_operations/any.py
+++ b/datalad_next/url_operations/any.py
@@ -3,7 +3,6 @@
 # allow for |-type UnionType declarations
 from __future__ import annotations
 
-from importlib import import_module
 import logging
 from pathlib import Path
 import re
@@ -25,14 +24,12 @@ __all__ = ['AnyUrlOperations']
 
 # define handlers for each supported URL pattern
 # the key in this dict is a regex match expression.
-# the value is a tuple of containing module, and name of the
-# class providing the handler
 # extensions could patch their's in
 # TODO support proper entrypoint mechanism
 _url_handlers = dict(
-    http=('datalad_next.url_operations.http', 'HttpUrlOperations'),
-    file=('datalad_next.url_operations.file', 'FileUrlOperations'),
-    ssh=('datalad_next.url_operations.ssh', 'SshUrlOperations'),
+    http=HttpUrlOperations,
+    file=FileUrlOperations,
+    ssh=SshUrlOperations,
 )
 
 
@@ -78,20 +75,11 @@ class AnyUrlOperations(UrlOperations):
 
         # reuse existing handler, they might already have an idea on
         # authentication etc. from a previously processed URL
-        if best_match in self._url_handler_cache:
-            return self._url_handler_cache[best_match]
-
-        # we need to import the handler
-        try:
-            mod, cls = self._url_handlers[best_match]
-            module = import_module(mod, package='datalad')
-            handler_cls = getattr(module, cls)
-            url_handler = handler_cls(cfg=self.cfg)
-        except Exception as e:
-            raise ValueError(
-                'Cannot create URL handler instance for '
-                f'{best_match.pattern!r} from {self._url_handlers[best_match]}') from e
-
+        url_handler = (
+            self._url_handler_cache[best_match]
+            if best_match in self._url_handler_cache
+            else self._url_handlers[best_match](cfg=self.cfg)
+        )
         self._url_handler_cache[best_match] = url_handler
         return url_handler
 


Test patch:
diff --git a/datalad_next/url_operations/tests/test_any.py b/datalad_next/url_operations/tests/test_any.py
index 1ac5705..2317cc3 100644
--- a/datalad_next/url_operations/tests/test_any.py
+++ b/datalad_next/url_operations/tests/test_any.py
@@ -16,11 +16,7 @@ def test_get_best_url_handler(monkeypatch):
     # it will report the "longest-matching" Handler
     # we create a non-sensicle FileUrlOperations record to test that
     with monkeypatch.context() as m:
-        m.setitem(
-            _url_handlers,
-            'https://ex.*\.co',
-            ('datalad_next.url_operations.file', 'FileUrlOperations'),
-        )
+        m.setitem(_url_handlers, 'https://ex.*\.co', FileUrlOperations)
         # the handlers are sucked into the class, so we need a new instance
         ops = AnyUrlOperations()
         assert type(ops._get_handler('https://example.com')) == FileUrlOperations