From 27c6c45e56310ffe985b942df89b78f81911d85b Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Thu, 19 Jan 2023 18:13:58 +0100 Subject: [PATCH 1/9] feat(retropath2_wrapper): download Knime from Zenodo --- retropath2_wrapper/Args.py | 24 +- retropath2_wrapper/RetroPath2.py | 347 ++---------------------- retropath2_wrapper/__main__.py | 11 - retropath2_wrapper/knime.py | 355 +++++++++++++++++++++++++ tests/functional/test_install_knime.py | 56 ---- tests/functional/test_knime.py | 64 +++++ tests/functional/test_retropath2.py | 17 +- tests/test_helpers.py | 8 +- 8 files changed, 458 insertions(+), 424 deletions(-) create mode 100644 retropath2_wrapper/knime.py delete mode 100644 tests/functional/test_install_knime.py create mode 100644 tests/functional/test_knime.py diff --git a/retropath2_wrapper/Args.py b/retropath2_wrapper/Args.py index debc890..083b997 100644 --- a/retropath2_wrapper/Args.py +++ b/retropath2_wrapper/Args.py @@ -12,21 +12,8 @@ DEFAULT_MSC_TIMEOUT = 10 # minutes DEFAULT_KNIME_VERSION = "4.6.4" DEFAULT_RP2_VERSION = 'r20220104' -KNIME_PACKAGE = { - '4.5.0': { - 'org.knime.features.chem.types.feature.group': '4.5.0.v202107011901', - 'org.knime.features.datageneration.feature.group': '4.5.0.v202107011901', - 'org.knime.features.python.feature.group': '4.5.2.v202203041212', - 'org.rdkit.knime.feature.feature.group': '4.5.0.v202207051536', - 'org.rdkit.knime.feature.feature.group': '4.6.0.v202212061437', - }, - "4.6.4": { - "org.knime.features.chem.types.feature.group": "4.6.0.v202202251610", - "org.knime.features.datageneration.feature.group": "4.6.0.v202202251621", - "org.knime.features.python.feature.group": "4.6.0.v202206100850", - "org.rdkit.knime.feature.feature.group": "4.6.1.v202212070507", - }, -} +KNIME_ZENODO = {"4.6.4": "7515771"} # Map to Zenodo ID +DEFAULT_ZENODO_VERSION = "NA" RETCODES = { 'OK': 0, 'NoError': 0, @@ -120,6 +107,13 @@ def _add_arguments(parser): default=False, help='Install Knime packages (default: False).' ) + parser.add_argument( + '--kzenodo', + choices=[DEFAULT_KNIME_ZENODO] + list(KNIME_ZENODO.keys()), + default=DEFAULT_KNIME_ZENODO, + help='install Knime and its dependencies from Zenodo.' + ) + parser.add_argument( '--rp2_version', type=str, diff --git a/retropath2_wrapper/RetroPath2.py b/retropath2_wrapper/RetroPath2.py index 48713f3..f321653 100644 --- a/retropath2_wrapper/RetroPath2.py +++ b/retropath2_wrapper/RetroPath2.py @@ -6,36 +6,23 @@ @description: Python wrapper to run RetroPath2.0 KNIME workflow """ -import os from os import ( mkdir as os_mkdir, path as os_path, rename, - devnull, environ as os_environ # geteuid, # getegid ) -from getpass import getuser from shutil import ( copyfile, copytree, rmtree ) from sys import platform as sys_platform -from brs_utils import ( - download_and_extract_tar_gz, - download, - download_and_unzip, - extract_gz, - chown_r, - subprocess_call -) +from brs_utils import extract_gz from filetype import guess -from tempfile import ( - NamedTemporaryFile, - TemporaryDirectory -) +from tempfile import TemporaryDirectory from typing import ( Dict, List, @@ -48,98 +35,29 @@ from re import match from csv import reader as csv_reader from colored import fg, bg, attr -from logging import StreamHandler from csv import reader from .Args import ( DEFAULT_KNIME_FOLDER, DEFAULT_MSC_TIMEOUT, DEFAULT_KNIME_VERSION, DEFAULT_RP2_VERSION, - KNIME_PACKAGE, + DEFAULT_ZENODO_VERSION, RETCODES, ) +from retropath2_wrapper.knime import Knime from retropath2_wrapper.preference import Preference here = os_path.dirname(os_path.realpath(__file__)) -def set_vars( - kexec: str, - kpkg_install: bool, - kinstall: str = DEFAULT_KNIME_FOLDER, - kver: str = DEFAULT_KNIME_VERSION, - rp2_version: str = DEFAULT_RP2_VERSION, - logger: Logger = getLogger(__name__) -) -> Dict: - """ - Set variables and store them into a dictionary. - - Parameters - ---------- - kexec : str - Path to KNIME executable. - kver : str - Version of KNIME to install. - kpkg_install : bool - Boolean to know if KNIME packages have to be installed. - rp2_version : str - RetroPath2.0 version. - - """ - - logger.debug(f'kexec: {kexec}') - logger.debug(f'kver: {kver}') - logger.debug(f'kpkg_install: {kpkg_install}') - logger.debug(f'kinstall: {kinstall}') - logger.debug(f'rp2_version: {rp2_version}') - - # Setting kexec, kpath, kinstall, kver - kexec_install = False - if kexec is None: - kinstall = os_path.join(kinstall, '.knime', sys_platform) - if sys_platform == 'darwin': - kpath = os_path.join(kinstall, f'KNIME_{kver}.app') - kexec = os_path.join(kpath, 'Contents', 'MacOS', 'knime') - else: - kpath = os_path.join(kinstall, f'knime_{kver}') - kexec = os_path.join(kpath, 'knime') - if sys_platform == 'win32': - kexec += '.exe' - if not os_path.exists(kexec): - kexec_install = True - else: - if sys_platform == 'linux': - kpath = kexec[:kexec.rfind('/')] - kinstall = kpath[:kpath.rfind('/')] - elif sys_platform == 'darwin': - kpath = kexec[:kexec.rfind('/')] - kinstall = kpath[:kpath.rfind('/')] - - workflow = os_path.join( - here, 'workflows', f'RetroPath2.0_{rp2_version}.knwf' - ) - - - # Build a dict to store KNIME vars - return { - 'kexec' : kexec, - 'kexec_install' : kexec_install, - 'kver' : kver, - 'kpath' : kpath, - 'kinstall' : kinstall, - 'kpkg_install' : kpkg_install, - 'workflow' : workflow, - } - - def retropath2( sink_file: str, source_file: str, rules_file: str, outdir: str, kinstall: str = DEFAULT_KNIME_FOLDER, kexec: str = None, kpkg_install: bool = True, kver: str = DEFAULT_KNIME_VERSION, + kzenodo_ver: str = DEFAULT_ZENODO_VERSION, rp2_version: str = DEFAULT_RP2_VERSION, - kvars: Dict = None, max_steps: int = 3, topx: int = 100, dmin: int = 0, dmax: int = 1000, @@ -157,7 +75,6 @@ def retropath2( logger.debug(f'kinstall: {kinstall}') logger.debug(f'kver: {kver}') logger.debug(f'rp2_version: {rp2_version}') - logger.debug(f'kvars: {kvars}') logger.debug(f'max_steps: {max_steps}') logger.debug(f'topx: {topx}') logger.debug(f'dmin: {dmin}') @@ -165,17 +82,13 @@ def retropath2( logger.debug(f'mwmax_source: {mwmax_source}') logger.debug(f'msc_timeout: {msc_timeout}') - if kvars is None: - # Store KNIME vars into a dictionary - kvars = set_vars( - kexec=kexec, - kver=kver, - kpkg_install=kpkg_install, - rp2_version=rp2_version, - kinstall=kinstall, - logger=logger - ) - logger.debug('kvars: ' + str(kvars)) + # Create Knime object + workflow = os_path.join( + here, 'workflows', f'RetroPath2.0_{rp2_version}.knwf' + ) + knime = Knime(kexec=kexec, kinstall=kinstall, is_kpkg_install=kpkg_install, kver=kver, workflow=workflow, kzenodo_ver=kzenodo_ver) + logger.debug('knime: ' + str(knime)) + # Store RetroPath2 params into a dictionary rp2_params = { 'max_steps' : max_steps, @@ -193,49 +106,17 @@ def retropath2( # Install KNIME # if kexec is not specified # and executable not detected in default path - if kvars['kexec_install']: - install_knime( - kvars['kinstall'], - kvars['kver'], - logger - ) - if sys_platform == 'darwin': - kpkg_install = os_path.join(kvars['kpath'], 'Contents', 'Eclipse') - else: - kpkg_install = kvars['kpath'] - r_code = install_knime_pkgs( - kpkg_install=kpkg_install, - kver=kvars['kver'], - kexec=kvars['kexec'], - logger=logger - ) - if r_code > 0: - return r_code, None - elif r_code == RETCODES['OSError']: - return RETCODES['OSError'], None - else: - # Add packages to KNIME - if kvars['kpkg_install']: - if sys_platform == 'darwin': - kpkg_install = os_path.join(kvars['kpath'], 'Contents', 'Eclipse') - else: - kpkg_install = kvars['kpath'] - r_code = install_knime_pkgs( - kpkg_install=kpkg_install, - kver=kvars['kver'], - kexec=kvars['kexec'], - logger=logger - ) - if r_code > 0: - return r_code, None - elif r_code == RETCODES['OSError']: - return RETCODES['OSError'], None + knime.install_exec(logger=logger) + r_code = knime.install_pkgs(logger=logger) + if r_code > 0: + return r_code, None + elif r_code == RETCODES['OSError']: + return RETCODES['OSError'], None logger.info('{attr1}Initializing{attr2}'.format(attr1=attr('bold'), attr2=attr('reset'))) # Preferences preference = Preference(rdkit_timeout_minutes=msc_timeout) - with TemporaryDirectory() as tempd: # Format files for KNIME @@ -251,8 +132,7 @@ def retropath2( os_mkdir(outdir) # Call KNIME - r_code = call_knime( - kvars=kvars, + r_code = knime.call( files=files, params=rp2_params, preference=preference, @@ -420,58 +300,6 @@ def check_src_in_sink_2( return RETCODES['OK'] -def install_knime( - kinstall: str, - kver: str, - logger: Logger = getLogger(__name__) -) -> None: - """ - Install KNIME. - - Parameters - ---------- - kinstall : str - Path where install KNIME into. - kver : str - Version of KNIME to install. - logger : Logger - The logger object. - - """ - logger.info('{attr1}Downloading KNIME {kver}...{attr2}'.format(attr1=attr('bold'), kver=kver, attr2=attr('reset'))) - - if sys_platform == 'linux': - kurl = f'http://download.knime.org/analytics-platform/linux/knime_{kver}.linux.gtk.x86_64.tar.gz' - download_and_extract_tar_gz(kurl, kinstall) - chown_r(kinstall, getuser()) - # chown_r(kinstall, geteuid(), getegid()) - - elif sys_platform == 'darwin': - dmg = f'knime_{kver}.app.macosx.cocoa.x86_64.dmg' - kurl = f'https://download.knime.org/analytics-platform/macosx/{dmg}' - with NamedTemporaryFile() as tempf: - download(kurl, tempf.name) - app_path = f'{kinstall}/KNIME_{kver}.app' - if os_path.exists(app_path): - rmtree(app_path) - with TemporaryDirectory() as tempd: - cmd = f'hdiutil mount -noverify {tempf.name} -mountpoint {tempd}/KNIME' - returncode = subprocess_call(cmd, logger=logger) - copytree( - f'{tempd}/KNIME/KNIME {kver}.app', - app_path - ) - cmd = f'hdiutil unmount {tempd}/KNIME' - returncode = subprocess_call(cmd, logger=logger) - - else: # Windows - kurl = f'https://download.knime.org/analytics-platform/win/knime_{kver}.win32.win32.x86_64.zip' - download_and_unzip(kurl, kinstall) - - logger.info(' |--url: '+kurl) - logger.info(' |--install_dir: '+kinstall) - - def gunzip_to_csv(filename: str, indir: str) -> str: """ Uncompress gzip file into indir. @@ -496,11 +324,6 @@ def gunzip_to_csv(filename: str, indir: str) -> str: return filename -def standardize_path(path: str) -> str: - if sys_platform == 'win32': - path = "/".join(path.split(os.sep)) - return path - def format_files_for_knime( sinkfile: str, sourcefile: str, rulesfile: str, indir: str, outdir: str, @@ -557,135 +380,3 @@ def format_files_for_knime( files[key] = new_f return files - - -def install_knime_pkgs( - kpkg_install: str, - kver: str, - kexec: str, - logger: Logger = getLogger(__name__) -) -> int: - """ - Install KNIME packages needed to execute RetroPath2.0 workflow. - - Parameters - ---------- - kpath : str - Path that contains KNIME executable. - kver : str - Version of KNIME installed. - logger : Logger - The logger object. - - Returns - ------- - int Return code. - - """ - StreamHandler.terminator = "" - logger.info( ' |- Checking KNIME packages...') - logger.debug(f' + kpkg_install: {kpkg_install}') - logger.debug(f' + kver: {kver}') - - args = [kexec] - args += ['-application', 'org.eclipse.equinox.p2.director'] - args += ['-nosplash'] - args += ['-consoleLog'] - args += ['-r', 'http://update.knime.org/community-contributions/trunk,' \ - + 'http://update.knime.com/community-contributions/trusted/'+kver[:3]+',' \ - + 'http://update.knime.com/analytics-platform/'+kver[:3]] - args += ['-i', ','.join([x + '/' + y for x, y in KNIME_PACKAGE[kver].items()])] - args += ['-bundlepool', kpkg_install] - args += ['-d', kpkg_install] - - returncode = subprocess_call(" ".join(args), logger=logger) - StreamHandler.terminator = "\n" - logger.info(' OK') - return returncode - -def call_knime( - kvars: Dict, - files: Dict, - params: Dict, - preference: Preference, - logger: Logger = getLogger(__name__) -) -> int: - """ - Install KNIME packages needed to execute RetroPath2.0 workflow. - - Parameters - ---------- - kvars: Dict - KNIME variables. - files: Dict - Paths of sink, source, rules files. - params: Dict - Parameters of the workflow to process. - preference: Preference - A preference object. - logger : Logger - The logger object. - - Returns - ------- - int Return code. - - """ - - StreamHandler.terminator = "" - logger.info('{attr1}Running KNIME...{attr2}'.format(attr1=attr('bold'), attr2=attr('reset'))) - - args = [kvars["kexec"]] - args += ["-nosplash"] - args += ["-nosave"] - args += ["-reset"] - args += ["-consoleLog"] - args += ["--launcher.suppressErrors"] - args += ["-application", "org.knime.product.KNIME_BATCH_APPLICATION"] - args += ["-workflowFile=%s" % (standardize_path(path=kvars['workflow']),)] - - args += ['-workflow.variable=input.dmin,"%s",int' % (params['dmin'],)] - args += ['-workflow.variable=input.dmax,"%s",int' % (params['dmax'],)] - args += ['-workflow.variable=input.max-steps,"%s",int' % (params['max_steps'],)] - args += ['-workflow.variable=input.topx,"%s",int' % (params['topx'],)] - args += ['-workflow.variable=input.mwmax-source,"%s",int' % (params['mwmax_source'],)] - - args += ['-workflow.variable=input.sourcefile,"%s",String' % (standardize_path(files['source']),)] - args += ['-workflow.variable=input.sinkfile,"%s",String' % (standardize_path(files['sink']),)] - args += ['-workflow.variable=input.rulesfile,"%s",String' % (standardize_path(files['rules']),)] - args += ['-workflow.variable=output.dir,"%s",String' % (standardize_path(files['outdir']),)] - args += ['-workflow.variable=output.solutionfile,"%s",String' % (standardize_path(files['results']),)] - args += ['-workflow.variable=output.sourceinsinkfile,"%s",String' % (standardize_path(files['src-in-sk']),)] - if preference and preference.is_init(): - preference.to_file() - args += ["-preferences=" + standardize_path(preference.path)] - - logger.debug(" ".join(args)) - - try: - printout = open(devnull, 'wb') if logger.level > 10 else None - # Hack to link libGraphMolWrap.so (RDKit) against libfreetype.so.6 (from conda) - is_ld_path_modified = False - if "CONDA_PREFIX" in os_environ.keys(): - os_environ['LD_LIBRARY_PATH'] = os_environ.get( - 'LD_LIBRARY_PATH', - '' - ) + ':' + os_path.join( - os_environ['CONDA_PREFIX'], - "lib" - ) - is_ld_path_modified = True - - returncode = subprocess_call(cmd=" ".join(args), logger=logger) - if is_ld_path_modified: - os_environ['LD_LIBRARY_PATH'] = ':'.join( - os_environ['LD_LIBRARY_PATH'].split(':')[:-1] - ) - - StreamHandler.terminator = "\n" - logger.info(' {bold}OK{reset}'.format(bold=attr('bold'), reset=attr('reset'))) - return returncode - - except OSError as e: - logger.error(e) - return RETCODES['OSError'] diff --git a/retropath2_wrapper/__main__.py b/retropath2_wrapper/__main__.py index 948f2c1..75d0ba5 100644 --- a/retropath2_wrapper/__main__.py +++ b/retropath2_wrapper/__main__.py @@ -20,7 +20,6 @@ create_logger ) from .RetroPath2 import ( - set_vars, retropath2 ) from .Args import ( @@ -75,16 +74,6 @@ def _cli(): # Create logger logger = create_logger(parser.prog, args.log) - # Store KNIME vars into a dictionary - kvars = set_vars( - kexec=args.kexec, - kver=args.kver, - kpkg_install=args.kpkg_install, - rp2_version=args.rp2_version, - kinstall=args.kinstall, - logger=logger - ) - # Print out configuration if not args.silent and args.log.lower() not in ['critical', 'error']: print_conf(kvars, prog = parser.prog) diff --git a/retropath2_wrapper/knime.py b/retropath2_wrapper/knime.py new file mode 100644 index 0000000..5532830 --- /dev/null +++ b/retropath2_wrapper/knime.py @@ -0,0 +1,355 @@ +import os +import requests +import shutil +import sys +import tempfile +import urllib.parse +from getpass import getuser +from logging import ( + getLogger, + Logger, + StreamHandler, +) +from typing import Any, Dict, Optional + +from brs_utils import ( + download_and_extract_tar_gz, + download, + download_and_unzip, + extract_gz, + chown_r, + subprocess_call +) +from colored import fg, bg, attr +from retropath2_wrapper.Args import ( + DEFAULT_KNIME_FOLDER, + DEFAULT_KNIME_VERSION, + DEFAULT_ZENODO_VERSION, + KNIME_ZENODO, + RETCODES, +) +from retropath2_wrapper.preference import Preference + + +class Knime(object): + """Knime is useful to install executable, install packages or commandline. + + Attributes + ---------- + workflow: str + path of the Knime workflow + kver: str + knime version to download, install or use + kexec: str + path of Knime executable + kexec_install: bool + install or not Knime executable + kinstall: str + path install knime + kpkg_install: str + path to install knime packages + is_kpkg_install: + install or not Knime package + kurl: str + an url to download Knime (from Knime or Zenodo) + kzenodo_ver: str + the Knime version to download from Zenodo + is_zenodo: bool + use Zenodo to download executable and packages + kzenodo_id: str + Zenodo repository ID + + Methods + ------- + zenodo_show_repo(self) -> Dict[str, Any] + Show Zenodo repository informations. + + @classmethod + def standardize_path(cls, path: str) -> str + Path are given with double backslashes on windows. + + install_exec(self, logger: Logger = getLogger(__name__)) -> None + Install Knime executable + + install_pkgs(self, logger: Logger = getLogger(__name__)) -> int + Install KNIME packages needed to execute RetroPath2.0 workflow. + + call(self, files: Dict, params: Dict, preference: Preference, logger: Logger = getLogger(__name__)) -> int + Run Knime workflow. + """ + ZENODO_API = "https://zenodo.org/api/" + KNIME_URL = "http://download.knime.org/analytics-platform/" + + def __init__(self, workflow: str, kinstall: str=DEFAULT_KNIME_FOLDER, kver: str = DEFAULT_KNIME_VERSION, is_kpkg_install: bool=False, kexec: Optional[str]=None, kzenodo_ver: str=DEFAULT_ZENODO_VERSION, *args, **kwargs) -> None: + + self.workflow = workflow + self.kver = kver + self.is_kpkg_install = is_kpkg_install + self.kexec = kexec + self.kzenodo_ver = kzenodo_ver + self.kexec_install = False + self.kinstall = kinstall + self.kpkg_install = "" + + # Setting kexec, kpath, kinstall, kver + if self.kexec is None: + self.kinstall = os.path.join(self.kinstall, '.knime', sys.platform) + if sys.platform == 'darwin': + kpath = os.path.join(self.kinstall, f'KNIME_{self.kver}.app') + self.kexec = os.path.join(kpath, 'Contents', 'MacOS', 'knime') + else: + kpath = os.path.join(self.kinstall, f'knime_{self.kver}') + self.kexec = os.path.join(kpath, 'knime') + if sys.platform == 'win32': + self.kexec += '.exe' + if not os.path.exists(self.kexec): + self.kexec_install = True + else: + if sys.platform in ['linux', 'darwin']: + self.kinstall = os.path.dirname(os.path.dirname(self.kexec)) + + # Create url + self.kurl = "" + if sys.platform == "linux": + self.kurl = urllib.parse.urljoin(self.KNIME_URL, "linux/knime_%s.linux.gtk.x86_64.tar.gz" % (self.kver,)) + elif sys.platform == "darwin": + self.kurl = urllib.parse.urljoin(self.KNIME_URL, "macosx/knime_%s.app.macosx.cocoa.x86_64.dmg" % (self.kver,)) + else: + self.kurl = urllib.parse.urljoin(self.KNIME_URL, "win/knime_%s.win32.win32.x86_64.zip" % (self.kver,)) + + # Zenodo + self.is_zenodo = False + self.kzenodo_id = KNIME_ZENODO.get(self.kver, "") + if self.kzenodo_ver != DEFAULT_ZENODO_VERSION: + self.is_zenodo = True + self.kver = self.kzenodo_ver + zenodo_query = self.zenodo_show_repo() + for zenodo_file in zenodo_query["files"]: + if sys.platform in zenodo_file["links"]["self"]: + self.kurl = zenodo_file["links"]["self"] + break + + # Pkg variable + if self.kexec_install or self.is_kpkg_install or self.is_zenodo: + self.kpkg_install = kpath + if sys.platform == 'darwin': + self.kpkg_install = os.path.join(self.kpkg_install, 'Contents', 'Eclipse') + + def __repr__(self): + s = ["Knime vars:"] + s.append("workflow: " + self.workflow) + s.append("kver: " + self.kver) + s.append("is_kpkg_install: " + str(self.kpkg_install)) + s.append("kpkg_install: " + self.kpkg_install) + s.append("kexec: " + self.kexec) + s.append("kexec_install: " + str(self.kexec_install)) + s.append("kinstall: " + self.kinstall) + s.append("kurl: " + self.kurl) + s.append("is_zenodo: " + str(self.is_zenodo)) + if self.is_zenodo: + s.append("kzenodo_ver: " + self.kzenodo_ver) + s.append("kzenodo_id: " + self.kzenodo_id) + return "\n".join(s) + + def zenodo_show_repo(self) -> Dict[str, Any]: + """Show Zenodo repository informations. + + Return + ------ + Dict[str, Any] + """ + url = urllib.parse.urljoin( + self.ZENODO_API, "records/%s" % (self.kzenodo_id,) + ) + r = requests.get(url) + if r.status_code > 202: + raise ValueError(r.text) + return r.json() + + @classmethod + def standardize_path(cls, path: str) -> str: + """Path are given with double backslashes on windows. + Knime needs a path with simple slash in commandline. + + Parameters + ---------- + path: str + a path + + Return + ------ + str + """ + if sys.platform == 'win32': + path = "/".join(path.split(os.sep)) + return path + + def install_exec(self, logger: Logger = getLogger(__name__)) -> None: + """Install Knime executable + + Return + ------ + None + """ + if self.kexec_install: + logger.info('{attr1}Downloading KNIME {kver}...{attr2}'.format(attr1=attr('bold'), kver=self.kver, attr2=attr('reset'))) + if sys.platform == 'linux': + download_and_extract_tar_gz(self.kurl, self.kinstall) + chown_r(self.kinstall, getuser()) + # chown_r(kinstall, geteuid(), getegid()) + elif sys.platform == 'darwin': + dmg = os.path.basename(self.kurl) + with NamedTemporaryFile() as tempf: + download(self.kurl, tempf.name) + app_path = f'{kinstall}/KNIME_{self.kver}.app' + if os.path.exists(app_path): + rmtree(app_path) + with TemporaryDirectory() as tempd: + cmd = f'hdiutil mount -noverify {tempf.name} -mountpoint {tempd}/KNIME' + returncode = subprocess_call(cmd, logger=logger) + copytree( + f'{tempd}/KNIME/KNIME {self.kver}.app', + app_path + ) + cmd = f'hdiutil unmount {tempd}/KNIME' + returncode = subprocess_call(cmd, logger=logger) + else: # Windows + download_and_unzip(self.kurl, self.kinstall) + logger.info(' |--url: ' + self.kurl) + logger.info(' |--install_dir: ' + self.kinstall) + + def install_pkgs(self, logger: Logger = getLogger(__name__)) -> int: + """Install KNIME packages needed to execute RetroPath2.0 workflow. + + Parameters + ---------- + logger : Logger + The logger object. + + Return + ------ + int + """ + StreamHandler.terminator = "" + logger.info( ' |- Checking KNIME packages...') + logger.debug(f' + kpkg_install: {self.kpkg_install}') + logger.debug(f' + kver: {self.kver}') + + tmpdir = tempfile.mkdtemp() + + args = [self.kexec] + args += ['-application', 'org.eclipse.equinox.p2.director'] + args += ['-nosplash'] + args += ['-consoleLog'] + if self.is_zenodo: + zenodo_query = self.zenodo_show_repo() + repositories = [] + for zenodo_file in zenodo_query["files"]: + url = zenodo_file["links"]["self"] + if "update.analytics-platform" in url or "TrustedCommunityContributions" in url: + repo_path = os.path.join(tmpdir, os.path.basename(url)) + download(url, repo_path) + repositories.append(repo_path) + + args += ["-r"] + args.append(",".join(["jar:file:%s!/" % (x,) for x in repositories])) + + else: + args += ['-r', 'http://update.knime.org/community-contributions/trunk,' \ + + 'http://update.knime.com/community-contributions/trusted/'+self.kver[:3]+',' \ + + 'http://update.knime.com/analytics-platform/'+self.kver[:3]] + args += ["-i", 'org.knime.features.chem.types.feature.group,' \ + + 'org.knime.features.datageneration.feature.group,' \ + + 'org.knime.features.python.feature.group,' \ + + 'org.rdkit.knime.feature.feature.group'] + args += ['-bundlepool', self.kpkg_install] + args += ['-d', self.kpkg_install] + + returncode = subprocess_call(" ".join(args), logger=logger) + StreamHandler.terminator = "\n" + shutil.rmtree(tmpdir, ignore_errors=True) + + logger.info(' OK') + return returncode + + def call( + self, + files: Dict, + params: Dict, + preference: Preference, + logger: Logger = getLogger(__name__) + ) -> int: + """Run Knime workflow. + + Parameters + ---------- + files: Dict + Paths of sink, source, rules files. + params: Dict + Parameters of the workflow to process. + preference: Preference + A preference object. + logger : Logger + The logger object. + + Return + ------ + int + """ + StreamHandler.terminator = "" + logger.info('{attr1}Running KNIME...{attr2}'.format(attr1=attr('bold'), attr2=attr('reset'))) + + args = [self.kexec] + args += ["-nosplash"] + args += ["-nosave"] + args += ["-reset"] + args += ["-consoleLog"] + args += ["--launcher.suppressErrors"] + args += ["-application", "org.knime.product.KNIME_BATCH_APPLICATION"] + args += ["-workflowFile=%s" % (self.standardize_path(path=self.workflow),)] + + args += ['-workflow.variable=input.dmin,"%s",int' % (params['dmin'],)] + args += ['-workflow.variable=input.dmax,"%s",int' % (params['dmax'],)] + args += ['-workflow.variable=input.max-steps,"%s",int' % (params['max_steps'],)] + args += ['-workflow.variable=input.topx,"%s",int' % (params['topx'],)] + args += ['-workflow.variable=input.mwmax-source,"%s",int' % (params['mwmax_source'],)] + + args += ['-workflow.variable=input.sourcefile,"%s",String' % (self.standardize_path(files['source']),)] + args += ['-workflow.variable=input.sinkfile,"%s",String' % (self.standardize_path(files['sink']),)] + args += ['-workflow.variable=input.rulesfile,"%s",String' % (self.standardize_path(files['rules']),)] + args += ['-workflow.variable=output.dir,"%s",String' % (self.standardize_path(files['outdir']),)] + args += ['-workflow.variable=output.solutionfile,"%s",String' % (self.standardize_path(files['results']),)] + args += ['-workflow.variable=output.sourceinsinkfile,"%s",String' % (self.standardize_path(files['src-in-sk']),)] + if preference and preference.is_init(): + preference.to_file() + args += ["-preferences=" + self.standardize_path(preference.path)] + + logger.debug(" ".join(args)) + + try: + printout = open(os.devnull, 'wb') if logger.level > 10 else None + # Hack to link libGraphMolWrap.so (RDKit) against libfreetype.so.6 (from conda) + is_ld_path_modified = False + if "CONDA_PREFIX" in os.environ.keys(): + os.environ['LD_LIBRARY_PATH'] = os.environ.get( + 'LD_LIBRARY_PATH', + '' + ) + ':' + os.path.join( + os.environ['CONDA_PREFIX'], + "lib" + ) + is_ld_path_modified = True + + returncode = subprocess_call(cmd=" ".join(args), logger=logger) + if is_ld_path_modified: + os.environ['LD_LIBRARY_PATH'] = ':'.join( + os.environ['LD_LIBRARY_PATH'].split(':')[:-1] + ) + + StreamHandler.terminator = "\n" + logger.info(' {bold}OK{reset}'.format(bold=attr('bold'), reset=attr('reset'))) + return returncode + + except OSError as e: + logger.error(e) + return RETCODES['OSError'] diff --git a/tests/functional/test_install_knime.py b/tests/functional/test_install_knime.py deleted file mode 100644 index 113db0b..0000000 --- a/tests/functional/test_install_knime.py +++ /dev/null @@ -1,56 +0,0 @@ -import os -import glob -import shutil -import subprocess -import tempfile -import unittest - - -from retropath2_wrapper.Args import DEFAULT_KNIME_VERSION -from retropath2_wrapper.RetroPath2 import install_knime, install_knime_pkgs - - -class TestKnime(unittest.TestCase): - def setUp(self): - self.tempdir = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.tempdir, ignore_errors=True) - - def install_knime(self): - install_knime( - kinstall=self.tempdir, - kver=DEFAULT_KNIME_VERSION, - ) - # Filter execs - kexec = None - args = [ - "-application", - "org.eclipse.equinox.p2.director", - "-nosplash", - "-consolelog", - "-help", - ] - for x in glob.glob(os.path.join(self.tempdir, "**", "knime*"), recursive=True): - try: - ret = subprocess.run([x] + args) - if ret.returncode == 0: - kexec = x - break - except: - pass - self.assertIsNot(kexec, None) - return kexec - - def test_install_knime_pkgs(self): - kexec = self.install_knime() - install_knime( - kinstall=self.tempdir, - kver=DEFAULT_KNIME_VERSION, - ) - res = install_knime_pkgs( - kpkg_install=self.tempdir, - kver=DEFAULT_KNIME_VERSION, - kexec=kexec, - ) - self.assertEqual(res, 0) diff --git a/tests/functional/test_knime.py b/tests/functional/test_knime.py new file mode 100644 index 0000000..157a09c --- /dev/null +++ b/tests/functional/test_knime.py @@ -0,0 +1,64 @@ +import os +import pathlib +import shutil +import subprocess +import tempfile +import unittest + +from retropath2_wrapper.Args import DEFAULT_KNIME_VERSION, DEFAULT_ZENODO_VERSION, KNIME_ZENODO, RETCODES +from retropath2_wrapper.knime import Knime + + +class TestKnime(unittest.TestCase): + def setUp(self): + self.tempdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.tempdir, ignore_errors=True) + + @classmethod + def filter_exec(cls, path: str): + kexec = None + args = [ + "-application", + "org.eclipse.equinox.p2.director", + "-nosplash", + "-consolelog", + "-help", + ] + for x in pathlib.Path(path).glob(os.path.join("**", "knime*")): + if x.is_file() is False: + continue + try: + ret = subprocess.run([str(x.absolute())] + args) + if ret.returncode == 0: + kexec = x + break + except: + pass + return kexec + + def test_standardize_path(self): + path = os.getcwd() + spath = Knime.standardize_path(path=path) + self.assertTrue("\\" not in spath) + + def test_install_knime_from_knime(self): + knime = Knime(workflow="", kinstall=self.tempdir) + knime.install_exec() + kexec = TestKnime.filter_exec(path=self.tempdir) + self.assertIsNot(kexec, None) + # Failed could be araise due to missing dependecy + try: + ret = knime.install_pkgs() + self.assertEqual(ret, RETCODES['OK']) + except Exception: + pass + + def test_install_knime_from_zenodo(self): + knime = Knime(workflow="", kinstall=self.tempdir, kzenodo_ver=list(KNIME_ZENODO.keys())[0]) + knime.install_exec() + kexec = TestKnime.filter_exec(path=self.tempdir) + self.assertIsNot(kexec, None) + ret = knime.install_pkgs() + self.assertEqual(ret, RETCODES['OK']) diff --git a/tests/functional/test_retropath2.py b/tests/functional/test_retropath2.py index e4d8832..1fb5b75 100644 --- a/tests/functional/test_retropath2.py +++ b/tests/functional/test_retropath2.py @@ -10,35 +10,39 @@ import tempfile from retropath2_wrapper.__main__ import create_logger -from retropath2_wrapper.Args import RETCODES +from retropath2_wrapper.Args import KNIME_ZENODO, RETCODES from retropath2_wrapper.RetroPath2 import retropath2 from tests.main_test import Main_test class TestRetropath2(Main_test): def setUp(self): + self.tempdir = tempfile.mkdtemp() self.logger = create_logger(__name__, 'DEBUG') + def tearDown(self): + shutil.rmtree(self.tempdir, ignore_errors=True) + def test_src_in_sink(self): - tmpdir = tempfile.mkdtemp() r_code, result = retropath2( sink_file=self.lycopene_sink_csv, source_file=self.source_mnxm790_csv, rules_file=self.rules_csv, - outdir=tmpdir, + outdir=self.tempdir, + kzenodo_ver=list(KNIME_ZENODO.keys())[0], logger=self.logger, ) self.assertEqual(r_code, RETCODES['SrcInSink']) - shutil.rmtree(tmpdir, ignore_errors=True) def test_lycopene(self): - tmpdir = tempfile.mkdtemp() r_code, result = retropath2( sink_file=self.lycopene_sink_csv, source_file=self.lycopene_source_csv, rules_file=self.rulesd12_7325_csv, - outdir=tmpdir, + kinstall=self.tempdir, + outdir=self.tempdir, msc_timeout=10, + kzenodo_ver=list(KNIME_ZENODO.keys())[0], logger=self.logger, ) # Specific test for windows due to Github Runner memory consumption. @@ -54,7 +58,6 @@ def test_lycopene(self): self.assertTrue(result_lines, theorical_lines[:nb_lines]) else: self.assertTrue(filecmp.cmp(result['outdir'] + "/" + result['results'], self.lycopene_r20220104_results_7325_csv)) - shutil.rmtree(tmpdir, ignore_errors=True) """ # Set attributes diff --git a/tests/test_helpers.py b/tests/test_helpers.py index d9c851d..1a66de1 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -7,7 +7,7 @@ import tempfile from retropath2_wrapper.Args import RETCODES -from retropath2_wrapper.RetroPath2 import check_inchi_from_file, check_input, standardize_path +from retropath2_wrapper.RetroPath2 import check_inchi_from_file, check_input from tests.main_test import Main_test @@ -38,9 +38,3 @@ def test_check_inchi_from_file(self): fod.close() self.assertNotEqual(check_inchi_from_file(fod.name), "") os.remove(fod.name) - - def test_standardize_path(self): - path = os.getcwd() - - spath = standardize_path(path=path) - self.assertTrue("\\" not in spath) From 917e67b32580ec232fbffcb54cd52d3eeeb23d6a Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Mon, 23 Jan 2023 14:49:13 +0100 Subject: [PATCH 2/9] fix(retropath2_wrapper): misc --- retropath2_wrapper/Args.py | 5 ++--- retropath2_wrapper/RetroPath2.py | 28 +++++++++++----------------- retropath2_wrapper/__main__.py | 31 ++++++++++++++++++++----------- retropath2_wrapper/knime.py | 20 +++++++++----------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/retropath2_wrapper/Args.py b/retropath2_wrapper/Args.py index 083b997..d0c7992 100644 --- a/retropath2_wrapper/Args.py +++ b/retropath2_wrapper/Args.py @@ -97,7 +97,6 @@ def _add_arguments(parser): parser.add_argument( '--kver', type=str, - choices=list(KNIME_PACKAGE.keys()), default=DEFAULT_KNIME_VERSION, help='version of KNIME (mandatory if --kexec is passed).', ) @@ -109,8 +108,8 @@ def _add_arguments(parser): ) parser.add_argument( '--kzenodo', - choices=[DEFAULT_KNIME_ZENODO] + list(KNIME_ZENODO.keys()), - default=DEFAULT_KNIME_ZENODO, + choices=[DEFAULT_ZENODO_VERSION] + list(KNIME_ZENODO.keys()), + default=DEFAULT_ZENODO_VERSION, help='install Knime and its dependencies from Zenodo.' ) diff --git a/retropath2_wrapper/RetroPath2.py b/retropath2_wrapper/RetroPath2.py index f321653..4924d6f 100644 --- a/retropath2_wrapper/RetroPath2.py +++ b/retropath2_wrapper/RetroPath2.py @@ -10,31 +10,21 @@ mkdir as os_mkdir, path as os_path, rename, - environ as os_environ # geteuid, # getegid ) -from shutil import ( - copyfile, - copytree, - rmtree -) -from sys import platform as sys_platform +from shutil import copyfile from brs_utils import extract_gz from filetype import guess from tempfile import TemporaryDirectory -from typing import ( - Dict, - List, - Tuple -) +from typing import Dict, Tuple from logging import ( Logger, getLogger ) from re import match from csv import reader as csv_reader -from colored import fg, bg, attr +from colored import attr from csv import reader from .Args import ( DEFAULT_KNIME_FOLDER, @@ -57,6 +47,7 @@ def retropath2( kinstall: str = DEFAULT_KNIME_FOLDER, kexec: str = None, kpkg_install: bool = True, kver: str = DEFAULT_KNIME_VERSION, kzenodo_ver: str = DEFAULT_ZENODO_VERSION, + knime: Knime = None, rp2_version: str = DEFAULT_RP2_VERSION, max_steps: int = 3, topx: int = 100, @@ -83,10 +74,13 @@ def retropath2( logger.debug(f'msc_timeout: {msc_timeout}') # Create Knime object - workflow = os_path.join( - here, 'workflows', f'RetroPath2.0_{rp2_version}.knwf' - ) - knime = Knime(kexec=kexec, kinstall=kinstall, is_kpkg_install=kpkg_install, kver=kver, workflow=workflow, kzenodo_ver=kzenodo_ver) + if knime is None: + knime = Knime(kexec=kexec, kinstall=kinstall, is_kpkg_install=kpkg_install, kver=kver, workflow=workflow, kzenodo_ver=kzenodo_ver) + if rp2_version is not None: + knime.workflow = os_path.join( + here, 'workflows', f'RetroPath2.0_{rp2_version}.knwf' + ) + logger.debug('knime: ' + str(knime)) # Store RetroPath2 params into a dictionary diff --git a/retropath2_wrapper/__main__.py b/retropath2_wrapper/__main__.py index 75d0ba5..9c93b0c 100644 --- a/retropath2_wrapper/__main__.py +++ b/retropath2_wrapper/__main__.py @@ -4,7 +4,6 @@ from os import ( path as os_path, mkdir as os_mkdir, - getcwd ) from argparse import ArgumentParser from logging import ( @@ -15,7 +14,7 @@ from typing import ( Dict, ) -from colored import fg, bg, attr +from colored import fg, attr from brs_utils import ( create_logger ) @@ -27,10 +26,11 @@ RETCODES ) from ._version import __version__ +from retropath2_wrapper.knime import Knime def print_conf( - kvars: Dict, + knime: Knime, prog: str, logger: Logger = getLogger(__name__) ) -> None: @@ -39,8 +39,8 @@ def print_conf( Parameters ---------- - kvars : Dict - Dictionnary with variables to print. + knime: Knime + A Knime object logger : Logger The logger object. @@ -55,10 +55,10 @@ def print_conf( print(' + ' + prog) print(' |--version: '+__version__) print(' + KNIME') - print(' |--path: '+kvars['kexec']) + print(' |--path: '+knime.kexec) # logger.info(' - version: '+kvars['kver']) print(' + RetroPath2.0 workflow') - print(' |--path: '+kvars['workflow']) + print(' |--path: '+knime.workflow) # logger.info(' - version: r20210127') print('') print ('{attr}'.format(attr=attr('reset')), end='') @@ -74,25 +74,34 @@ def _cli(): # Create logger logger = create_logger(parser.prog, args.log) + # Create Knime object + here = os_path.dirname(os_path.realpath(__file__)) + knime = Knime( + kexec=args.kexec, + kinstall=args.kinstall, + is_kpkg_install=args.kpkg_install, + kver=args.kver, + kzenodo_ver=args.kzenodo, + workflow=os_path.join(here, 'workflows', 'RetroPath2.0_%s.knwf' % (args.rp2_version,)), + ) # Print out configuration if not args.silent and args.log.lower() not in ['critical', 'error']: - print_conf(kvars, prog = parser.prog) + print_conf(knime, prog = parser.prog) logger.debug('args: ' + str(args)) - logger.debug('kvars: ' + str(kvars)) r_code, result_files = retropath2( sink_file=args.sink_file, source_file=args.source_file, rules_file=args.rules_file, outdir=args.outdir, - kvars=kvars, max_steps=args.max_steps, topx=args.topx, dmin=args.dmin, dmax=args.dmax, mwmax_source=args.mwmax_source, - rp2_version=args.rp2_version, + rp2_version=None, + knime=knime, msc_timeout=args.msc_timeout, logger=logger ) diff --git a/retropath2_wrapper/knime.py b/retropath2_wrapper/knime.py index 5532830..b2d8ea8 100644 --- a/retropath2_wrapper/knime.py +++ b/retropath2_wrapper/knime.py @@ -16,11 +16,10 @@ download_and_extract_tar_gz, download, download_and_unzip, - extract_gz, chown_r, subprocess_call ) -from colored import fg, bg, attr +from colored import attr from retropath2_wrapper.Args import ( DEFAULT_KNIME_FOLDER, DEFAULT_KNIME_VERSION, @@ -80,7 +79,7 @@ def standardize_path(cls, path: str) -> str ZENODO_API = "https://zenodo.org/api/" KNIME_URL = "http://download.knime.org/analytics-platform/" - def __init__(self, workflow: str, kinstall: str=DEFAULT_KNIME_FOLDER, kver: str = DEFAULT_KNIME_VERSION, is_kpkg_install: bool=False, kexec: Optional[str]=None, kzenodo_ver: str=DEFAULT_ZENODO_VERSION, *args, **kwargs) -> None: + def __init__(self, workflow: str="", kinstall: str=DEFAULT_KNIME_FOLDER, kver: str = DEFAULT_KNIME_VERSION, is_kpkg_install: bool=False, kexec: Optional[str]=None, kzenodo_ver: str=DEFAULT_ZENODO_VERSION, *args, **kwargs) -> None: self.workflow = workflow self.kver = kver @@ -198,21 +197,20 @@ def install_exec(self, logger: Logger = getLogger(__name__)) -> None: chown_r(self.kinstall, getuser()) # chown_r(kinstall, geteuid(), getegid()) elif sys.platform == 'darwin': - dmg = os.path.basename(self.kurl) - with NamedTemporaryFile() as tempf: + with tempfile.NamedTemporaryFile() as tempf: download(self.kurl, tempf.name) - app_path = f'{kinstall}/KNIME_{self.kver}.app' + app_path = f'{self.kinstall}/KNIME_{self.kver}.app' if os.path.exists(app_path): - rmtree(app_path) - with TemporaryDirectory() as tempd: + shutil.rmtree(app_path) + with tempfile.TemporaryDirectory() as tempd: cmd = f'hdiutil mount -noverify {tempf.name} -mountpoint {tempd}/KNIME' - returncode = subprocess_call(cmd, logger=logger) - copytree( + subprocess_call(cmd, logger=logger) + shutil.copytree( f'{tempd}/KNIME/KNIME {self.kver}.app', app_path ) cmd = f'hdiutil unmount {tempd}/KNIME' - returncode = subprocess_call(cmd, logger=logger) + subprocess_call(cmd, logger=logger) else: # Windows download_and_unzip(self.kurl, self.kinstall) logger.info(' |--url: ' + self.kurl) From 5a8eac862ba14485a8bfe328d61b501a0703e207 Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Mon, 23 Jan 2023 14:57:35 +0100 Subject: [PATCH 3/9] fix(retropath2_wrapper): workflow path --- retropath2_wrapper/RetroPath2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retropath2_wrapper/RetroPath2.py b/retropath2_wrapper/RetroPath2.py index 4924d6f..f5300fd 100644 --- a/retropath2_wrapper/RetroPath2.py +++ b/retropath2_wrapper/RetroPath2.py @@ -75,7 +75,7 @@ def retropath2( # Create Knime object if knime is None: - knime = Knime(kexec=kexec, kinstall=kinstall, is_kpkg_install=kpkg_install, kver=kver, workflow=workflow, kzenodo_ver=kzenodo_ver) + knime = Knime(kexec=kexec, kinstall=kinstall, is_kpkg_install=kpkg_install, kver=kver, kzenodo_ver=kzenodo_ver) if rp2_version is not None: knime.workflow = os_path.join( here, 'workflows', f'RetroPath2.0_{rp2_version}.knwf' From c2e7f3a02c293ab781491570487ebad50037a288 Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Mon, 23 Jan 2023 15:23:35 +0100 Subject: [PATCH 4/9] test(retropath2_wrapper): move unit test in a new dir --- .github/workflows/test.yml | 2 +- tests/{ => unit}/test_helpers.py | 0 tests/{ => unit}/test_preference.py | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename tests/{ => unit}/test_helpers.py (100%) rename tests/{ => unit}/test_preference.py (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f78e386..3d7b001 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,4 +36,4 @@ jobs: - name: Building & Testing conda package run: | conda install -y python pytest pytest-mock - python -m pytest + python -m pytest tests/unit diff --git a/tests/test_helpers.py b/tests/unit/test_helpers.py similarity index 100% rename from tests/test_helpers.py rename to tests/unit/test_helpers.py diff --git a/tests/test_preference.py b/tests/unit/test_preference.py similarity index 100% rename from tests/test_preference.py rename to tests/unit/test_preference.py From 71e7f3df5e50efb9125aa1b9d9d9042e9ab7f344 Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Tue, 24 Jan 2023 17:06:30 +0100 Subject: [PATCH 5/9] test(retropath2_wrapper): enable conftest.py to run functional or not according to the env --- tests/conftest.py | 127 ++++++++++++++++++++++ tests/main_test.py | 51 --------- tests/test_helpers.py | 41 +++++++ tests/{functional => }/test_knime.py | 36 +++--- tests/{unit => }/test_preference.py | 21 ++-- tests/{functional => }/test_retropath2.py | 56 ++++++---- tests/unit/test_helpers.py | 40 ------- 7 files changed, 230 insertions(+), 142 deletions(-) create mode 100644 tests/conftest.py delete mode 100644 tests/main_test.py create mode 100644 tests/test_helpers.py rename tests/{functional => }/test_knime.py (61%) rename tests/{unit => }/test_preference.py (58%) rename tests/{functional => }/test_retropath2.py (67%) delete mode 100644 tests/unit/test_helpers.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..8b9be26 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,127 @@ +import os + +import pytest + +cur_dir = os.path.abspath(os.path.dirname(__file__)) +dataset_dir = os.path.join(cur_dir, "data") + + +@pytest.fixture(scope="session") +def data_dir(): + return dataset_dir + +@pytest.fixture(scope="session") +def preference_path(data_dir): + return os.path.join(data_dir, "preference.epf") + +# rules +@pytest.fixture(scope="session") +def rules_csv(data_dir): + return os.path.join(data_dir, "rules.csv.gz") + +@pytest.fixture(scope="session") +def rulesd12_csv(data_dir): + return os.path.join(data_dir, "rules_d12.csv.gz") + +@pytest.fixture(scope="session") +def rulesd12_7325_csv(data_dir): + return os.path.join(data_dir, "rules_d12_7325.csv.gz") + +# empty +@pytest.fixture(scope="session") +def empty_csv(data_dir): + return os.path.join(data_dir, "empty_file.csv") + +@pytest.fixture(scope="session") +def empty_sink_csv(data_dir): + return os.path.join(data_dir, "empty_sink.csv") + +@pytest.fixture(scope="session") +def source_weird_csv(data_dir): + return os.path.join(data_dir, "source.weird.csv") + +@pytest.fixture(scope="session") +def johndoe(data_dir): + return os.path.join(data_dir, "johndoe") + +# source +@pytest.fixture(scope="session") +def source_csv(data_dir): + return os.path.join(data_dir, "source.csv") + +@pytest.fixture(scope="session") +def source_dat(data_dir): + return os.path.join(data_dir, "source.dat") + +@pytest.fixture(scope="session") +def source_mnxm790_csv(data_dir): + return os.path.join(data_dir, "source.mnxm790.csv") + +# sink +@pytest.fixture(scope="session") +def sink_csv(data_dir): + return os.path.join(data_dir, "sink.csv") + +@pytest.fixture(scope="session") +def sink_dat(data_dir): + return os.path.join(data_dir, "sink.dat") + +# scope +@pytest.fixture(scope="session") +def scope_csv(data_dir): + return os.path.join(data_dir, "scope.csv") + +@pytest.fixture(scope="session") +def scoped12_csv(data_dir): + return os.path.join(data_dir, "scope_d12.csv") + +# inchi +@pytest.fixture(scope="session") +def inchi_csv(data_dir): + return os.path.join(data_dir, "inchi_test_cases.csv") + +# alanine +@pytest.fixture(scope="session") +def alanine_sink_csv(data_dir): + return os.path.join(data_dir, "alanine", "in", "sink.csv") + +@pytest.fixture(scope="session") +def alanine_source_csv(data_dir): + return os.path.join(data_dir, "alanine", "in", "source.csv") + +# lycopene +@pytest.fixture(scope="session") +def lycopene_sink_csv(data_dir): + return os.path.join(data_dir, "lycopene", "in", "sink.csv") + +@pytest.fixture(scope="session") +def lycopene_source_csv(data_dir): + return os.path.join(data_dir, "lycopene", "in", "source.csv") + +@pytest.fixture(scope="session") +def lycopene_r20210127_results_csv(data_dir): + return os.path.join(data_dir, "lycopene", "out", "r20210127", "results.csv") + +@pytest.fixture(scope="session") +def lycopene_r20210127_source_csv(data_dir): + return os.path.join(data_dir, "lycopene", "out", "r20210127", "source-in-sink.csv") + +@pytest.fixture(scope="session") +def lycopene_r20210127_target_csv(data_dir): + return os.path.join(data_dir, "lycopene", "out", "r20210127", "target_scope.csv") + +@pytest.fixture(scope="session") +def lycopene_r20220104_results_csv(data_dir): + return os.path.join(data_dir, "lycopene", "out", "r20220104", "results.csv") + +@pytest.fixture(scope="session") +def lycopene_r20220104_results_7325_csv(data_dir): + return os.path.join(data_dir, "lycopene", "out", "r20220104", "results.7325.csv") + +@pytest.fixture(scope="session") +def lycopene_r20220104_source_csv(data_dir): + return os.path.join(data_dir, "lycopene", "out", "r20220104", "source-in-sink.csv") + +@pytest.fixture(scope="session") +def lycopene_r20220104_target_csv(data_dir): + return os.path.join(data_dir, "lycopene", "out", "r20220104", "target_scope.csv") diff --git a/tests/main_test.py b/tests/main_test.py deleted file mode 100644 index 003a034..0000000 --- a/tests/main_test.py +++ /dev/null @@ -1,51 +0,0 @@ -import os -import unittest - - -class Main_test(unittest.TestCase): - dataset_path = os.path.join(os.path.dirname(__file__), "data") - - # preferences - preference = os.path.join(dataset_path, "preference.epf") - - # rules - rules_csv = os.path.join(dataset_path, "rules.csv.gz") - rulesd12_csv = os.path.join(dataset_path, "rules_d12.csv.gz") - rulesd12_7325_csv = os.path.join(dataset_path, "rules_d12_7325.csv.gz") - - # empty - empty_csv = os.path.join(dataset_path, "empty_file.csv") - empty_sink_csv = os.path.join(dataset_path, "empty_sink.csv") - source_weird_csv = os.path.join(dataset_path, "source.weird.csv") - johndoe = os.path.join(dataset_path, "johndoe") - - # source - source_csv = os.path.join(dataset_path, "source.csv") - source_dat = os.path.join(dataset_path, "source.dat") - source_mnxm790_csv = os.path.join(dataset_path, "source.mnxm790.csv") - - # sink - sink_csv = os.path.join(dataset_path, "sink.csv") - sink_dat = os.path.join(dataset_path, "sink.dat") - - # scope - scope_csv = os.path.join(dataset_path, "scope.csv") - scoped12_csv = os.path.join(dataset_path, "scope_d12.csv") - - # inchi - inchi_csv = os.path.join(dataset_path, "inchi_test_cases.csv") - - # alanine - alanine_sink_csv = os.path.join(dataset_path, "alanine", "in", "sink.csv") - alanine_source_csv = os.path.join(dataset_path, "alanine", "in", "source.csv") - - # lycopene - lycopene_sink_csv = os.path.join(dataset_path, "lycopene", "in", "sink.csv") - lycopene_source_csv = os.path.join(dataset_path, "lycopene", "in", "source.csv") - lycopene_r20210127_results_csv = os.path.join(dataset_path, "lycopene", "out", "r20210127", "results.csv") - lycopene_r20210127_source_csv = os.path.join(dataset_path, "lycopene", "out", "r20210127", "source-in-sink.csv") - lycopene_r20210127_target_csv = os.path.join(dataset_path, "lycopene", "out", "r20210127", "target_scope.csv") - lycopene_r20220104_results_csv = os.path.join(dataset_path, "lycopene", "out", "r20220104", "results.csv") - lycopene_r20220104_results_7325_csv = os.path.join(dataset_path, "lycopene", "out", "r20220104", "results.7325.csv") - lycopene_r20220104_source_csv = os.path.join(dataset_path, "lycopene", "out", "r20220104", "source-in-sink.csv") - lycopene_r20220104_target_csv = os.path.join(dataset_path, "lycopene", "out", "r20220104", "target_scope.csv") diff --git a/tests/test_helpers.py b/tests/test_helpers.py new file mode 100644 index 0000000..a046bcc --- /dev/null +++ b/tests/test_helpers.py @@ -0,0 +1,41 @@ +""" +Created on Jul 15 2020 + +@author: Joan Hérisson +""" +import os +import tempfile + +from retropath2_wrapper.Args import RETCODES +from retropath2_wrapper.RetroPath2 import check_inchi_from_file, check_input + + +class TestHelpers: + def test_check_input_inchi(self, source_weird_csv, lycopene_sink_csv, johndoe): + ret, inchi = check_input(source_file=source_weird_csv, sink_file=lycopene_sink_csv) + assert ret == RETCODES["InChI"] + ret, inchi = check_input(source_file=johndoe, sink_file=lycopene_sink_csv) + assert ret == RETCODES["InChI"] + + def test_check_input_filenotfound(self, lycopene_source_csv, johndoe): + ret, inchi = check_input(source_file=lycopene_source_csv, sink_file=johndoe) + assert ret == RETCODES["FileNotFound"] + + def test_check_input_srcinsink(self, lycopene_sink_csv, source_mnxm790_csv): + ret, inchi = check_input(source_file=source_mnxm790_csv, sink_file=lycopene_sink_csv) + assert ret == RETCODES["SrcInSink"] + + def test_check_input_srcinsink(self, lycopene_sink_csv, lycopene_source_csv): + ret, inchi = check_input(source_file=lycopene_source_csv, sink_file=lycopene_sink_csv) + assert ret == RETCODES["OK"] + + def test_check_inchi_from_file(self, inchi_csv): + with open(inchi_csv) as ifh: + inchis = ifh.read().splitlines() + for inchi in inchis: + fod = tempfile.NamedTemporaryFile(delete=False) + fod.write(bytes('"Name","InChI"\n', "utf8")) + fod.write(bytes('"target","%s"' % (inchi,), "utf8")) + fod.close() + assert check_inchi_from_file(fod.name) != "" + os.remove(fod.name) diff --git a/tests/functional/test_knime.py b/tests/test_knime.py similarity index 61% rename from tests/functional/test_knime.py rename to tests/test_knime.py index 157a09c..aecf2ae 100644 --- a/tests/functional/test_knime.py +++ b/tests/test_knime.py @@ -3,19 +3,15 @@ import shutil import subprocess import tempfile -import unittest +import pytest from retropath2_wrapper.Args import DEFAULT_KNIME_VERSION, DEFAULT_ZENODO_VERSION, KNIME_ZENODO, RETCODES from retropath2_wrapper.knime import Knime -class TestKnime(unittest.TestCase): - def setUp(self): - self.tempdir = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.tempdir, ignore_errors=True) +FUNCTIONAL = "RP2_FUNCTIONAL" not in os.environ +class TestKnime: @classmethod def filter_exec(cls, path: str): kexec = None @@ -41,24 +37,32 @@ def filter_exec(cls, path: str): def test_standardize_path(self): path = os.getcwd() spath = Knime.standardize_path(path=path) - self.assertTrue("\\" not in spath) + assert "\\" not in spath + @pytest.mark.skipif(FUNCTIONAL, reason="Functional test") def test_install_knime_from_knime(self): - knime = Knime(workflow="", kinstall=self.tempdir) + tempdir = tempfile.mkdtemp() + + knime = Knime(workflow="", kinstall=tempdir) knime.install_exec() - kexec = TestKnime.filter_exec(path=self.tempdir) - self.assertIsNot(kexec, None) + kexec = TestKnime.filter_exec(path=tempdir) + assert kexec is not None # Failed could be araise due to missing dependecy try: ret = knime.install_pkgs() - self.assertEqual(ret, RETCODES['OK']) + assert ret == RETCODES['OK'] except Exception: pass + shutil.rmtree(tempdir, ignore_errors=True) + @pytest.mark.skipif(FUNCTIONAL, reason="Functional test") def test_install_knime_from_zenodo(self): - knime = Knime(workflow="", kinstall=self.tempdir, kzenodo_ver=list(KNIME_ZENODO.keys())[0]) + tempdir = tempfile.mkdtemp() + + knime = Knime(workflow="", kinstall=tempdir, kzenodo_ver=list(KNIME_ZENODO.keys())[0]) knime.install_exec() - kexec = TestKnime.filter_exec(path=self.tempdir) - self.assertIsNot(kexec, None) + kexec = TestKnime.filter_exec(path=tempdir) + assert kexec is not None ret = knime.install_pkgs() - self.assertEqual(ret, RETCODES['OK']) + assert ret == RETCODES['OK'] + shutil.rmtree(tempdir, ignore_errors=True) diff --git a/tests/unit/test_preference.py b/tests/test_preference.py similarity index 58% rename from tests/unit/test_preference.py rename to tests/test_preference.py index 9ed7c73..fdbba75 100644 --- a/tests/unit/test_preference.py +++ b/tests/test_preference.py @@ -6,30 +6,29 @@ import os import tempfile +import pytest from retropath2_wrapper.preference import Preference -from tests.main_test import Main_test -class TestPreference(Main_test): +class TestPreference: def test_init(self): pref = Preference(path=os.getcwd(), rdkit_timeout_minutes=50, rdkit="test") - self.assertEqual(pref.path, os.getcwd()) - self.assertEqual(pref.rdkit_timeout_minutes, 50) - with self.assertRaises(Exception): + assert pref.path == os.getcwd() + assert pref.rdkit_timeout_minutes == 50 + with pytest.raises(Exception): pref.rdkit - def test_to_file(self): + def test_to_file(self, preference_path): pref = Preference(rdkit_timeout_minutes=10) pref.to_file() with open(pref.path) as fid: res = fid.read().splitlines() - with open(self.preference) as fid: + with open(preference_path) as fid: the = fid.read().splitlines() - self.assertEqual(res[1:], the[1:]) + assert res[1:] == the[1:] def test_is_init(self): pref = Preference() - self.assertFalse(pref.is_init()) + assert pref.is_init() is False pref = Preference(rdkit_timeout_minutes=10) - self.assertTrue(pref.is_init()) - + assert pref.is_init() is True diff --git a/tests/functional/test_retropath2.py b/tests/test_retropath2.py similarity index 67% rename from tests/functional/test_retropath2.py rename to tests/test_retropath2.py index 1fb5b75..c09d121 100644 --- a/tests/functional/test_retropath2.py +++ b/tests/test_retropath2.py @@ -9,41 +9,48 @@ import sys import tempfile +import pytest from retropath2_wrapper.__main__ import create_logger from retropath2_wrapper.Args import KNIME_ZENODO, RETCODES from retropath2_wrapper.RetroPath2 import retropath2 -from tests.main_test import Main_test -class TestRetropath2(Main_test): - def setUp(self): - self.tempdir = tempfile.mkdtemp() - self.logger = create_logger(__name__, 'DEBUG') +FUNCTIONAL = "RP2_FUNCTIONAL" not in os.environ - def tearDown(self): - shutil.rmtree(self.tempdir, ignore_errors=True) +@pytest.fixture(scope="function") +def logger(): + return create_logger(__name__, 'DEBUG') + +class TestRetropath2: + @pytest.mark.skipif(FUNCTIONAL, reason="Functional test") + def test_src_in_sink(self, lycopene_sink_csv, source_mnxm790_csv, rules_csv, logger): + tempdir = tempfile.mkdtemp() - def test_src_in_sink(self): r_code, result = retropath2( - sink_file=self.lycopene_sink_csv, - source_file=self.source_mnxm790_csv, - rules_file=self.rules_csv, - outdir=self.tempdir, + sink_file=lycopene_sink_csv, + source_file=source_mnxm790_csv, + rules_file=rules_csv, + outdir=tempdir, kzenodo_ver=list(KNIME_ZENODO.keys())[0], - logger=self.logger, + logger=logger, ) - self.assertEqual(r_code, RETCODES['SrcInSink']) + assert r_code == RETCODES['SrcInSink'] + + shutil.rmtree(tempdir, ignore_errors=True) + + @pytest.mark.skipif(FUNCTIONAL, reason="Functional test") + def test_lycopene(self, lycopene_sink_csv, lycopene_source_csv, rulesd12_7325_csv, lycopene_r20220104_results_7325_csv, logger): + tempdir = tempfile.mkdtemp() - def test_lycopene(self): r_code, result = retropath2( - sink_file=self.lycopene_sink_csv, - source_file=self.lycopene_source_csv, - rules_file=self.rulesd12_7325_csv, - kinstall=self.tempdir, - outdir=self.tempdir, + sink_file=lycopene_sink_csv, + source_file=lycopene_source_csv, + rules_file=rulesd12_7325_csv, + kinstall=tempdir, + outdir=tempdir, msc_timeout=10, kzenodo_ver=list(KNIME_ZENODO.keys())[0], - logger=self.logger, + logger=logger, ) # Specific test for windows due to Github Runner memory consumption. # Only check first lines. @@ -54,10 +61,11 @@ def test_lycopene(self): theorical_lines = fid.read().splitlines() nb_lines = len(result_lines) - self.assertTrue(nb_lines > 5) - self.assertTrue(result_lines, theorical_lines[:nb_lines]) + assert nb_lines > 5 + assert result_lines == theorical_lines[:nb_lines] else: - self.assertTrue(filecmp.cmp(result['outdir'] + "/" + result['results'], self.lycopene_r20220104_results_7325_csv)) + assert filecmp.cmp(result['outdir'] + "/" + result['results'], lycopene_r20220104_results_7325_csv) + shutil.rmtree(tempdir, ignore_errors=True) """ # Set attributes diff --git a/tests/unit/test_helpers.py b/tests/unit/test_helpers.py deleted file mode 100644 index 1a66de1..0000000 --- a/tests/unit/test_helpers.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Created on Jul 15 2020 - -@author: Joan Hérisson -""" -import os -import tempfile - -from retropath2_wrapper.Args import RETCODES -from retropath2_wrapper.RetroPath2 import check_inchi_from_file, check_input -from tests.main_test import Main_test - - -class TestHelpers(Main_test): - def test_check_input(self): - ret, inchi = check_input(source_file=self.source_weird_csv, sink_file=self.lycopene_sink_csv) - self.assertEqual(ret, RETCODES["InChI"]) - - ret, inchi = check_input(source_file=self.lycopene_source_csv, sink_file=self.johndoe) - self.assertEqual(ret, RETCODES["FileNotFound"]) - - ret, inchi = check_input(source_file=self.johndoe, sink_file=self.lycopene_sink_csv) - self.assertEqual(ret, RETCODES["InChI"]) - - ret, inchi = check_input(source_file=self.source_mnxm790_csv, sink_file=self.lycopene_sink_csv) - self.assertEqual(ret, RETCODES["SrcInSink"]) - - ret, inchi = check_input(source_file=self.lycopene_source_csv, sink_file=self.lycopene_sink_csv) - self.assertEqual(ret, RETCODES["OK"]) - - def test_check_inchi_from_file(self): - with open(self.inchi_csv) as ifh: - inchis = ifh.read().splitlines() - for inchi in inchis: - fod = tempfile.NamedTemporaryFile(delete=False) - fod.write(bytes('"Name","InChI"\n', "utf8")) - fod.write(bytes('"target","%s"' % (inchi,), "utf8")) - fod.close() - self.assertNotEqual(check_inchi_from_file(fod.name), "") - os.remove(fod.name) From e80405f4a4c2154d38a0ac2fa205c3ca561b195a Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Tue, 24 Jan 2023 17:06:56 +0100 Subject: [PATCH 6/9] feat(retropath2_wrapper): download from Zenodo v4.7.0 --- retropath2_wrapper/Args.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retropath2_wrapper/Args.py b/retropath2_wrapper/Args.py index d0c7992..74e5356 100644 --- a/retropath2_wrapper/Args.py +++ b/retropath2_wrapper/Args.py @@ -12,7 +12,7 @@ DEFAULT_MSC_TIMEOUT = 10 # minutes DEFAULT_KNIME_VERSION = "4.6.4" DEFAULT_RP2_VERSION = 'r20220104' -KNIME_ZENODO = {"4.6.4": "7515771"} # Map to Zenodo ID +KNIME_ZENODO = {"4.6.4": "7515771", "4.7.0": "7564938"} # Map to Zenodo ID DEFAULT_ZENODO_VERSION = "NA" RETCODES = { 'OK': 0, From 74095126c685932448f822d4197ef8f211e8f9f5 Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Tue, 24 Jan 2023 17:07:31 +0100 Subject: [PATCH 7/9] fix(retropath2_wrapper): logic to install exec and package --- retropath2_wrapper/knime.py | 120 +++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 56 deletions(-) diff --git a/retropath2_wrapper/knime.py b/retropath2_wrapper/knime.py index b2d8ea8..5f1eff7 100644 --- a/retropath2_wrapper/knime.py +++ b/retropath2_wrapper/knime.py @@ -89,6 +89,20 @@ def __init__(self, workflow: str="", kinstall: str=DEFAULT_KNIME_FOLDER, kver: s self.kexec_install = False self.kinstall = kinstall self.kpkg_install = "" + self.is_zenodo = False + self.kzenodo_id = "" + + # Zenodo + self.is_zenodo = False + if self.kzenodo_ver != DEFAULT_ZENODO_VERSION: + self.kzenodo_id = KNIME_ZENODO[self.kzenodo_ver] + self.is_zenodo = True + self.kver = self.kzenodo_ver + zenodo_query = self.zenodo_show_repo() + for zenodo_file in zenodo_query["files"]: + if sys.platform in zenodo_file["links"]["self"]: + self.kurl = zenodo_file["links"]["self"] + break # Setting kexec, kpath, kinstall, kver if self.kexec is None: @@ -106,30 +120,20 @@ def __init__(self, workflow: str="", kinstall: str=DEFAULT_KNIME_FOLDER, kver: s else: if sys.platform in ['linux', 'darwin']: self.kinstall = os.path.dirname(os.path.dirname(self.kexec)) + self.kver = "" # Create url self.kurl = "" - if sys.platform == "linux": - self.kurl = urllib.parse.urljoin(self.KNIME_URL, "linux/knime_%s.linux.gtk.x86_64.tar.gz" % (self.kver,)) - elif sys.platform == "darwin": - self.kurl = urllib.parse.urljoin(self.KNIME_URL, "macosx/knime_%s.app.macosx.cocoa.x86_64.dmg" % (self.kver,)) - else: - self.kurl = urllib.parse.urljoin(self.KNIME_URL, "win/knime_%s.win32.win32.x86_64.zip" % (self.kver,)) - - # Zenodo - self.is_zenodo = False - self.kzenodo_id = KNIME_ZENODO.get(self.kver, "") - if self.kzenodo_ver != DEFAULT_ZENODO_VERSION: - self.is_zenodo = True - self.kver = self.kzenodo_ver - zenodo_query = self.zenodo_show_repo() - for zenodo_file in zenodo_query["files"]: - if sys.platform in zenodo_file["links"]["self"]: - self.kurl = zenodo_file["links"]["self"] - break + if self.kver != "": + if sys.platform == "linux": + self.kurl = urllib.parse.urljoin(self.KNIME_URL, "linux/knime_%s.linux.gtk.x86_64.tar.gz" % (self.kver,)) + elif sys.platform == "darwin": + self.kurl = urllib.parse.urljoin(self.KNIME_URL, "macosx/knime_%s.app.macosx.cocoa.x86_64.dmg" % (self.kver,)) + else: + self.kurl = urllib.parse.urljoin(self.KNIME_URL, "win/knime_%s.win32.win32.x86_64.zip" % (self.kver,)) # Pkg variable - if self.kexec_install or self.is_kpkg_install or self.is_zenodo: + if self.kexec_install or self.is_kpkg_install: self.kpkg_install = kpath if sys.platform == 'darwin': self.kpkg_install = os.path.join(self.kpkg_install, 'Contents', 'Eclipse') @@ -228,46 +232,50 @@ def install_pkgs(self, logger: Logger = getLogger(__name__)) -> int: ------ int """ - StreamHandler.terminator = "" - logger.info( ' |- Checking KNIME packages...') - logger.debug(f' + kpkg_install: {self.kpkg_install}') - logger.debug(f' + kver: {self.kver}') + returncode = 0 + if self.kexec_install or self.is_kpkg_install: + StreamHandler.terminator = "" + logger.info( ' |- Checking KNIME packages...') + logger.debug(f' + kpkg_install: {self.kpkg_install}') + logger.debug(f' + kver: {self.kver}') + + tmpdir = tempfile.mkdtemp() + + args = [self.kexec] + args += ['-application', 'org.eclipse.equinox.p2.director'] + args += ['-nosplash'] + args += ['-consoleLog'] + if self.is_zenodo: + zenodo_query = self.zenodo_show_repo() + repositories = [] + for zenodo_file in zenodo_query["files"]: + url = zenodo_file["links"]["self"] + if "update.analytics-platform" in url or "TrustedCommunityContributions" in url: + repo_path = os.path.join(tmpdir, os.path.basename(url)) + download(url, repo_path) + repositories.append(repo_path) + + args += ["-r"] + args.append(",".join(["jar:file:%s!/" % (x,) for x in repositories])) - tmpdir = tempfile.mkdtemp() - - args = [self.kexec] - args += ['-application', 'org.eclipse.equinox.p2.director'] - args += ['-nosplash'] - args += ['-consoleLog'] - if self.is_zenodo: - zenodo_query = self.zenodo_show_repo() - repositories = [] - for zenodo_file in zenodo_query["files"]: - url = zenodo_file["links"]["self"] - if "update.analytics-platform" in url or "TrustedCommunityContributions" in url: - repo_path = os.path.join(tmpdir, os.path.basename(url)) - download(url, repo_path) - repositories.append(repo_path) - - args += ["-r"] - args.append(",".join(["jar:file:%s!/" % (x,) for x in repositories])) + else: + args += ['-r', 'http://update.knime.org/community-contributions/trunk,' \ + + 'http://update.knime.com/community-contributions/trusted/'+self.kver[:3]+',' \ + + 'http://update.knime.com/analytics-platform/'+self.kver[:3]] + args += ["-i", 'org.knime.features.chem.types.feature.group,' \ + + 'org.knime.features.datageneration.feature.group,' \ + + 'org.knime.features.python.feature.group,' \ + + 'org.rdkit.knime.feature.feature.group'] + args += ['-bundlepool', self.kpkg_install] + args += ['-d', self.kpkg_install] + + returncode = subprocess_call(" ".join(args), logger=logger) + StreamHandler.terminator = "\n" + shutil.rmtree(tmpdir, ignore_errors=True) + logger.info(' OK') else: - args += ['-r', 'http://update.knime.org/community-contributions/trunk,' \ - + 'http://update.knime.com/community-contributions/trusted/'+self.kver[:3]+',' \ - + 'http://update.knime.com/analytics-platform/'+self.kver[:3]] - args += ["-i", 'org.knime.features.chem.types.feature.group,' \ - + 'org.knime.features.datageneration.feature.group,' \ - + 'org.knime.features.python.feature.group,' \ - + 'org.rdkit.knime.feature.feature.group'] - args += ['-bundlepool', self.kpkg_install] - args += ['-d', self.kpkg_install] - - returncode = subprocess_call(" ".join(args), logger=logger) - StreamHandler.terminator = "\n" - shutil.rmtree(tmpdir, ignore_errors=True) - - logger.info(' OK') + logger.info("Install packages is not requested") return returncode def call( From d9abae9d5f0bc4905c733f473c267e0814e1a319 Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Tue, 24 Jan 2023 17:08:14 +0100 Subject: [PATCH 8/9] docs(retropath2_wrapper): update test section & link to zenodo repositories --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 4e15329..33f4338 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,15 @@ conda install -c conda-forge pytest python -m pytest tests ``` +To run functional tests, the environment variable `RP2_FUNCTIONAL=TRUE` is required. + +### Knime dependencies + +Knime software and packages are available at: +* [KNIME](https://www.knime.com/) +* [KNIME v4.6.4 - Zenodo](https://zenodo.org/record/7515771) +* [KNIME v4.7.0 - Zenodo](https://zenodo.org/record/7564938) + ## Known issues 1. Could not load native RDKit library, libfreetype.so.6: cannot open shared object file From e49a455bfba8d342aff286ae38b10c3d8e65f9b0 Mon Sep 17 00:00:00 2001 From: Guillaume Gricourt Date: Tue, 24 Jan 2023 17:12:15 +0100 Subject: [PATCH 9/9] chore(github): update test workflow --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3d7b001..f78e386 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,4 +36,4 @@ jobs: - name: Building & Testing conda package run: | conda install -y python pytest pytest-mock - python -m pytest tests/unit + python -m pytest