[med-svn] [Git][med-team/cwltest][master] 5 commits: New upstream version 2.5.20241122133319

Michael R. Crusoe (@crusoe) gitlab at salsa.debian.org
Sun Dec 15 23:06:31 GMT 2024



Michael R. Crusoe pushed to branch master at Debian Med / cwltest


Commits:
c834b6e7 by Michael R. Crusoe at 2024-12-15T23:59:52+01:00
New upstream version 2.5.20241122133319
- - - - -
be5880c4 by Michael R. Crusoe at 2024-12-15T23:59:52+01:00
New upstream version

- - - - -
abaa3ff0 by Michael R. Crusoe at 2024-12-15T23:59:53+01:00
Update upstream source from tag 'upstream/2.5.20241122133319'

Update to upstream version '2.5.20241122133319'
with Debian dir 635d2bec8052c4b8b8ca362294e3d93a4e3d1923
- - - - -
64de3597 by Michael R. Crusoe at 2024-12-15T23:59:53+01:00
Standards-Version: 4.7.0 (routine-update)

- - - - -
7cb71d8d by Michael R. Crusoe at 2024-12-16T00:05:09+01:00
routine-update: Ready to upload to unstable

- - - - -


15 changed files:

- .github/workflows/ci-tests.yml
- PKG-INFO
- README.rst
- cwltest.egg-info/PKG-INFO
- cwltest.egg-info/SOURCES.txt
- cwltest/_version.py
- cwltest/compare.py
- cwltest/main.py
- + cwltest/stdfsaccess.py
- cwltest/utils.py
- debian/changelog
- debian/control
- dev-requirements.txt
- docs/requirements.txt
- mypy-requirements.txt


Changes:

=====================================
.github/workflows/ci-tests.yml
=====================================
@@ -62,7 +62,7 @@ jobs:
 
       - name: Upload coverage to Codecov
         if: ${{ matrix.step == 'unit' }}
-        uses: codecov/codecov-action at v3
+        uses: codecov/codecov-action at v5
         with:
           fail_ci_if_error: true
           token: ${{ secrets.CODECOV_TOKEN }}


=====================================
PKG-INFO
=====================================
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: cwltest
-Version: 2.5.20240906231108
+Version: 2.5.20241122133319
 Summary: Common Workflow Language testing framework
 Author-email: Common workflow language working group <common-workflow-language at googlegroups.com>
 License: Apache 2.0
@@ -123,3 +123,57 @@ Once you upload JSON file to a server, you make a badge by using a link like htt
 Here is an example of markdown to add a badge::
 
   ![test result](https://flat.badgen.net/https/path/to/generated/json?icon=commonwl)
+
+*************************
+Custom file access module
+*************************
+
+If your CWL implementation does not write output files to a local file
+system location but instead to some other remote storage system, you
+can provide an alternate implementation of the *StdFsAccess* object
+that is able to access your storage system.
+
+Step 1:
+
+Implement your own class with the same public interface of the
+*StdFsAccess* object in *cwltest/stdfsaccess.py* (as of this writing,
+the methods are *open*, *size*, *isfile* and *isdir*).  These methods
+should expect to be called with URIs from the *location* field of the
+outputs of test cases.
+
+Define a function that, when called, returns a new instance of your object.
+
+Step 2:
+
+Create a Python package containing your class (or add it to an
+existing one).
+
+In the package metadata, add an entry point that declares the module
+(in this example, *my_cwl_runner.fsaccess*) containing the function
+(in this example, *get_fsaccess*) that *cwltest* will invoke to get an
+object implementing the *StdFsAccess* interface.
+
+In *setup.py* this looks like:
+
+.. code:: python
+
+  setup(
+    ...
+    entry_points={"cwltest.fsaccess": ["fsaccess=my_cwl_runner.fsaccess:get_fsaccess"]}},
+    ...
+  )
+
+In *pyproject.toml* it looks like:
+
+.. code::
+
+  [project.entry-points.'cwltest.fsaccess']
+  fsaccess = 'my_cwl_runner.fsaccess:get_fsaccess'
+
+
+Step 3:
+
+Install your package in the same Python environemnt as the
+installation of *cwltest*. When invoked, *cwltest* will query Python
+package metadata for a package with the *cwltest.fsaccess* entry point
+and call it to get back a custom filesystem access object.


=====================================
README.rst
=====================================
@@ -91,3 +91,57 @@ Once you upload JSON file to a server, you make a badge by using a link like htt
 Here is an example of markdown to add a badge::
 
   ![test result](https://flat.badgen.net/https/path/to/generated/json?icon=commonwl)
+
+*************************
+Custom file access module
+*************************
+
+If your CWL implementation does not write output files to a local file
+system location but instead to some other remote storage system, you
+can provide an alternate implementation of the *StdFsAccess* object
+that is able to access your storage system.
+
+Step 1:
+
+Implement your own class with the same public interface of the
+*StdFsAccess* object in *cwltest/stdfsaccess.py* (as of this writing,
+the methods are *open*, *size*, *isfile* and *isdir*).  These methods
+should expect to be called with URIs from the *location* field of the
+outputs of test cases.
+
+Define a function that, when called, returns a new instance of your object.
+
+Step 2:
+
+Create a Python package containing your class (or add it to an
+existing one).
+
+In the package metadata, add an entry point that declares the module
+(in this example, *my_cwl_runner.fsaccess*) containing the function
+(in this example, *get_fsaccess*) that *cwltest* will invoke to get an
+object implementing the *StdFsAccess* interface.
+
+In *setup.py* this looks like:
+
+.. code:: python
+
+  setup(
+    ...
+    entry_points={"cwltest.fsaccess": ["fsaccess=my_cwl_runner.fsaccess:get_fsaccess"]}},
+    ...
+  )
+
+In *pyproject.toml* it looks like:
+
+.. code::
+
+  [project.entry-points.'cwltest.fsaccess']
+  fsaccess = 'my_cwl_runner.fsaccess:get_fsaccess'
+
+
+Step 3:
+
+Install your package in the same Python environemnt as the
+installation of *cwltest*. When invoked, *cwltest* will query Python
+package metadata for a package with the *cwltest.fsaccess* entry point
+and call it to get back a custom filesystem access object.


=====================================
cwltest.egg-info/PKG-INFO
=====================================
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: cwltest
-Version: 2.5.20240906231108
+Version: 2.5.20241122133319
 Summary: Common Workflow Language testing framework
 Author-email: Common workflow language working group <common-workflow-language at googlegroups.com>
 License: Apache 2.0
@@ -123,3 +123,57 @@ Once you upload JSON file to a server, you make a badge by using a link like htt
 Here is an example of markdown to add a badge::
 
   ![test result](https://flat.badgen.net/https/path/to/generated/json?icon=commonwl)
+
+*************************
+Custom file access module
+*************************
+
+If your CWL implementation does not write output files to a local file
+system location but instead to some other remote storage system, you
+can provide an alternate implementation of the *StdFsAccess* object
+that is able to access your storage system.
+
+Step 1:
+
+Implement your own class with the same public interface of the
+*StdFsAccess* object in *cwltest/stdfsaccess.py* (as of this writing,
+the methods are *open*, *size*, *isfile* and *isdir*).  These methods
+should expect to be called with URIs from the *location* field of the
+outputs of test cases.
+
+Define a function that, when called, returns a new instance of your object.
+
+Step 2:
+
+Create a Python package containing your class (or add it to an
+existing one).
+
+In the package metadata, add an entry point that declares the module
+(in this example, *my_cwl_runner.fsaccess*) containing the function
+(in this example, *get_fsaccess*) that *cwltest* will invoke to get an
+object implementing the *StdFsAccess* interface.
+
+In *setup.py* this looks like:
+
+.. code:: python
+
+  setup(
+    ...
+    entry_points={"cwltest.fsaccess": ["fsaccess=my_cwl_runner.fsaccess:get_fsaccess"]}},
+    ...
+  )
+
+In *pyproject.toml* it looks like:
+
+.. code::
+
+  [project.entry-points.'cwltest.fsaccess']
+  fsaccess = 'my_cwl_runner.fsaccess:get_fsaccess'
+
+
+Step 3:
+
+Install your package in the same Python environemnt as the
+installation of *cwltest*. When invoked, *cwltest* will query Python
+package metadata for a package with the *cwltest.fsaccess* entry point
+and call it to get back a custom filesystem access object.


=====================================
cwltest.egg-info/SOURCES.txt
=====================================
@@ -28,6 +28,7 @@ cwltest/hooks.py
 cwltest/main.py
 cwltest/plugin.py
 cwltest/py.typed
+cwltest/stdfsaccess.py
 cwltest/utils.py
 cwltest.egg-info/PKG-INFO
 cwltest.egg-info/SOURCES.txt


=====================================
cwltest/_version.py
=====================================
@@ -12,5 +12,5 @@ __version__: str
 __version_tuple__: VERSION_TUPLE
 version_tuple: VERSION_TUPLE
 
-__version__ = version = '2.5.20240906231108'
-__version_tuple__ = version_tuple = (2, 5, 20240906231108)
+__version__ = version = '2.5.20241122133319'
+__version_tuple__ = version_tuple = (2, 5, 20241122133319)


=====================================
cwltest/compare.py
=====================================
@@ -2,9 +2,10 @@
 
 import hashlib
 import json
-import os.path
-import urllib.parse
 from typing import Any, Callable, Dict, Optional, Set
+import cwltest.stdfsaccess
+
+fs_access = cwltest.stdfsaccess.StdFsAccess("")
 
 
 class CompareFail(Exception):
@@ -130,13 +131,14 @@ def _compare_location(
         actual_comp = "path"
     else:
         actual_comp = "location"
-    path = urllib.parse.urlparse(actual[actual_comp]).path
+
     if actual.get("class") == "Directory":
         actual[actual_comp] = actual[actual_comp].rstrip("/")
-        exist_fun: Callable[[str], bool] = os.path.isdir
+        exist_fun: Callable[[str], bool] = fs_access.isdir
     else:
-        exist_fun = os.path.isfile
-    if not exist_fun(path) and not skip_details:
+        exist_fun = fs_access.isfile
+
+    if not exist_fun(actual[actual_comp]) and not skip_details:
         raise CompareFail.format(
             expected,
             actual,
@@ -160,15 +162,17 @@ def _compare_location(
 
 def _compare_checksum(expected: Dict[str, Any], actual: Dict[str, Any]) -> None:
     if "path" in actual:
-        path = urllib.parse.urlparse(actual["path"]).path
+        path = actual["path"]
     else:
-        path = urllib.parse.urlparse(actual["location"]).path
+        path = actual["location"]
     checksum = hashlib.sha1()  # nosec
-    with open(path, "rb") as f:
+
+    with fs_access.open(path, "rb") as f:
         contents = f.read(1024 * 1024)
         while contents != b"":
             checksum.update(contents)
             contents = f.read(1024 * 1024)
+
     actual_checksum_on_disk = f"sha1${checksum.hexdigest()}"
     if "checksum" in actual:
         actual_checksum_declared = actual["checksum"]
@@ -193,10 +197,12 @@ def _compare_checksum(expected: Dict[str, Any], actual: Dict[str, Any]) -> None:
 
 def _compare_size(expected: Dict[str, Any], actual: Dict[str, Any]) -> None:
     if "path" in actual:
-        path = urllib.parse.urlparse(actual["path"]).path
+        path = actual["path"]
     else:
-        path = urllib.parse.urlparse(actual["location"]).path
-    actual_size_on_disk = os.path.getsize(path)
+        path = actual["location"]
+
+    actual_size_on_disk = fs_access.size(path)
+
     if "size" in actual:
         actual_size_declared = actual["size"]
         if actual_size_on_disk != actual_size_declared:


=====================================
cwltest/main.py
=====================================
@@ -13,7 +13,12 @@ import schema_salad.avro
 import schema_salad.ref_resolver
 import schema_salad.schema
 from cwltest.argparser import arg_parser
-from cwltest.utils import CWLTestConfig, CWLTestReport, TestResult
+from cwltest.utils import (
+    CWLTestConfig,
+    CWLTestReport,
+    TestResult,
+    load_optional_fsaccess_plugin,
+)
 from schema_salad.exceptions import ValidationException
 
 from cwltest import logger, utils
@@ -116,6 +121,8 @@ def main() -> int:
     suite_name, _ = os.path.splitext(os.path.basename(args.test))
     report: Optional[junit_xml.TestSuite] = junit_xml.TestSuite(suite_name, [])
 
+    load_optional_fsaccess_plugin()
+
     ntotal: Dict[str, int] = Counter()
     npassed: Dict[str, List[CWLTestReport]] = defaultdict(list)
 


=====================================
cwltest/stdfsaccess.py
=====================================
@@ -0,0 +1,48 @@
+"""Abstracted IO access."""
+
+import os
+import urllib
+from typing import IO, Any
+
+from schema_salad.ref_resolver import uri_file_path
+
+
+def abspath(src: str, basedir: str) -> str:
+    """Determine local filesystem absolute path given a basedir, handling both plain paths and URIs."""
+    if src.startswith("file://"):
+        abpath = uri_file_path(src)
+    elif urllib.parse.urlsplit(src).scheme in ["http", "https"]:
+        return src
+    else:
+        if basedir.startswith("file://"):
+            abpath = src if os.path.isabs(src) else basedir + "/" + src
+        else:
+            abpath = src if os.path.isabs(src) else os.path.join(basedir, src)
+    return abpath
+
+
+class StdFsAccess:
+    """Local filesystem implementation."""
+
+    def __init__(self, basedir: str) -> None:
+        """Perform operations with respect to a base directory."""
+        self.basedir = basedir
+
+    def _abs(self, p: str) -> str:
+        return abspath(p, self.basedir)
+
+    def open(self, fn: str, mode: str) -> IO[Any]:
+        """Open a file from a file: URI."""
+        return open(self._abs(fn), mode)
+
+    def size(self, fn: str) -> int:
+        """Get the size of the file resource pointed to by a URI."""
+        return os.stat(self._abs(fn)).st_size
+
+    def isfile(self, fn: str) -> bool:
+        """Determine if a resource pointed to by a URI represents a file."""
+        return os.path.isfile(self._abs(fn))
+
+    def isdir(self, fn: str) -> bool:
+        """Determine if a resource pointed to by a URI represents a directory."""
+        return os.path.isdir(self._abs(fn))


=====================================
cwltest/utils.py
=====================================
@@ -27,6 +27,8 @@ import ruamel.yaml.scanner
 import schema_salad.avro
 import schema_salad.ref_resolver
 import schema_salad.schema
+import cwltest.compare
+import cwltest.stdfsaccess
 from cwltest.compare import CompareFail, compare
 from rdflib import Graph
 from ruamel.yaml.scalarstring import ScalarString
@@ -37,6 +39,10 @@ if sys.version_info >= (3, 9):
 else:
     from importlib_resources import as_file, files
 
+# available since Python 3.8 (minimum version supports as of this
+# writing) so we don't need to fuss with backports
+from importlib.metadata import entry_points, EntryPoint
+
 from cwltest import REQUIRED, UNSUPPORTED_FEATURE, logger, templock
 
 __all__ = ["files", "as_file"]
@@ -659,3 +665,35 @@ def absuri(path: str) -> str:
     if "://" in path:
         return path
     return "file://" + os.path.abspath(path)
+
+
+def load_optional_fsaccess_plugin() -> None:
+    """
+    Load optional fsaccess plugin.
+
+    Looks for a package with cwltest.fsaccess entry point and if so,
+    use that to get a filesystem access object that will be used for
+    checking test output.
+    """
+    fsaccess_eps: List[EntryPoint]
+
+    try:
+        # The interface to importlib.metadata.entry_points() changed
+        # several times between Python 3.8 and 3.13; the code below
+        # actually works fine on all of them but there's no single
+        # mypy annotation that works across of them.  Explicitly cast
+        # it to a consistent type to make mypy shut up.
+        fsaccess_eps = cast(List[EntryPoint], entry_points()["cwltest.fsaccess"])  # type: ignore [redundant-cast, unused-ignore]
+    except KeyError:
+        return
+
+    if len(fsaccess_eps) == 0:
+        return
+
+    if len(fsaccess_eps) > 1:
+        logger.warn(
+            "More than one cwltest.fsaccess entry point found, selected %s",
+            fsaccess_eps[0],
+        )
+
+    cwltest.compare.fs_access = fsaccess_eps[0].load()()


=====================================
debian/changelog
=====================================
@@ -1,3 +1,10 @@
+cwltest (2.5.20241122133319-1) unstable; urgency=medium
+
+  * New upstream version
+  * Standards-Version: 4.7.0 (routine-update)
+
+ -- Michael R. Crusoe <crusoe at debian.org>  Mon, 16 Dec 2024 00:00:25 +0100
+
 cwltest (2.5.20240906231108-1) unstable; urgency=medium
 
   * New upstream version


=====================================
debian/control
=====================================
@@ -23,7 +23,7 @@ Build-Depends: debhelper-compat (= 13),
                cwltool <!nocheck>,
                python3-typing-extensions <!nocheck> <!nodoc>,
                help2man <!nodoc>
-Standards-Version: 4.6.2
+Standards-Version: 4.7.0
 Vcs-Browser: https://salsa.debian.org/med-team/cwltest
 Vcs-Git: https://salsa.debian.org/med-team/cwltest.git
 Homepage: https://www.commonwl.org


=====================================
dev-requirements.txt
=====================================
@@ -1,5 +1,5 @@
 diff_cover
-black ~= 24.8
+black ~= 24.10
 pylint
 pep257
 pydocstyle


=====================================
docs/requirements.txt
=====================================
@@ -1,5 +1,5 @@
 sphinx >= 2.2
-sphinx-rtd-theme==2.0.0
+sphinx-rtd-theme==3.0.2
 sphinx-autoapi
 sphinx-autodoc-typehints
 typed_ast;python_version<'3.8'


=====================================
mypy-requirements.txt
=====================================
@@ -1,4 +1,4 @@
-mypy==1.11.2
+mypy==1.13.0
 pytest >= 8.3, < 9
 types-setuptools
 types-requests



View it on GitLab: https://salsa.debian.org/med-team/cwltest/-/compare/90192dc98c8410efc919a59e02bcc9b3d77f7e1c...7cb71d8d5c2136b411f160cb6624293dc259f355

-- 
View it on GitLab: https://salsa.debian.org/med-team/cwltest/-/compare/90192dc98c8410efc919a59e02bcc9b3d77f7e1c...7cb71d8d5c2136b411f160cb6624293dc259f355
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20241215/2d3a4e7d/attachment-0001.htm>


More information about the debian-med-commit mailing list