From f1c19c31093626f17579f6e6eae38a19965ba676 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 15:02:11 +0200 Subject: [PATCH 01/19] Restore SPYTHON_SINGULARITY_VERSION after test Otherwise this affects all tests scheduled after this --- spython/tests/test_utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spython/tests/test_utils.py b/spython/tests/test_utils.py index 7294e033..a6970f10 100644 --- a/spython/tests/test_utils.py +++ b/spython/tests/test_utils.py @@ -77,8 +77,14 @@ def test_check_get_singularity_version(self): from spython.utils import get_singularity_version version = get_singularity_version() self.assertTrue(version != "") + oldValue = os.environ.get('SPYTHON_SINGULARITY_VERSION') os.environ['SPYTHON_SINGULARITY_VERSION'] = "3.0" version = get_singularity_version() + # Restore for other tests + if oldValue is None: + del os.environ['SPYTHON_SINGULARITY_VERSION'] + else: + os.environ['SPYTHON_SINGULARITY_VERSION'] = oldValue self.assertTrue(version == "3.0") From d96c1a65b6845d3f73778d79a8e8b9db5b18ca82 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 15:28:32 +0200 Subject: [PATCH 02/19] Cleanup unused imports --- spython/client/shell.py | 2 -- spython/client/test.py | 6 ------ spython/image/cmd/export.py | 1 - spython/image/cmd/importcmd.py | 2 -- spython/logger/spinner.py | 3 --- spython/main/apps.py | 2 -- spython/main/base/command.py | 6 +----- spython/main/execute.py | 2 -- spython/main/export.py | 1 - spython/main/inspect.py | 1 - spython/main/instances.py | 4 ++-- spython/main/parse/converters.py | 3 --- spython/main/parse/docker.py | 2 -- spython/main/parse/recipe.py | 2 -- spython/main/parse/singularity.py | 3 --- spython/main/pull.py | 3 --- spython/main/run.py | 1 - spython/oci/cmd/mounts.py | 5 ----- spython/oci/cmd/states.py | 1 - spython/tests/test_client.py | 2 -- spython/tests/test_instances.py | 3 --- spython/tests/test_oci.py | 2 -- spython/tests/test_utils.py | 2 -- spython/utils/fileio.py | 6 ------ spython/utils/terminal.py | 1 - 25 files changed, 3 insertions(+), 63 deletions(-) diff --git a/spython/client/shell.py b/spython/client/shell.py index ab60c090..3c41da78 100644 --- a/spython/client/shell.py +++ b/spython/client/shell.py @@ -6,8 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -import sys - def main(args, options, parser): from spython.main import Client as cli diff --git a/spython/client/test.py b/spython/client/test.py index b4e794fb..360215dc 100644 --- a/spython/client/test.py +++ b/spython/client/test.py @@ -6,12 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.logger import bot -from spython.utils import check_install -import sys -import os - - def main(args, options, parser): print('TBA, additional tests for Singularity containers.') print('What would you like to see? Let us know!') diff --git a/spython/image/cmd/export.py b/spython/image/cmd/export.py index b76fd09d..41c168d9 100644 --- a/spython/image/cmd/export.py +++ b/spython/image/cmd/export.py @@ -6,7 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.logger import bot import tempfile def export(self, image_path, tmptar=None): diff --git a/spython/image/cmd/importcmd.py b/spython/image/cmd/importcmd.py index eae8ddb3..15c2a9f4 100644 --- a/spython/image/cmd/importcmd.py +++ b/spython/image/cmd/importcmd.py @@ -6,8 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.logger import bot - def importcmd(self, image_path, input_source): '''import will import (stdin) to the image diff --git a/spython/logger/spinner.py b/spython/logger/spinner.py index df1fd1e9..e9221360 100644 --- a/spython/logger/spinner.py +++ b/spython/logger/spinner.py @@ -6,9 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -import os -import sys - import sys import time import threading diff --git a/spython/main/apps.py b/spython/main/apps.py index 3f2e26fb..4003a26c 100644 --- a/spython/main/apps.py +++ b/spython/main/apps.py @@ -6,8 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.logger import bot - def apps(self, image=None, full_path=False, root=''): ''' return list of SCIF apps in image. The Singularity software serves diff --git a/spython/main/base/command.py b/spython/main/base/command.py index 103cf408..0d51dc36 100644 --- a/spython/main/base/command.py +++ b/spython/main/base/command.py @@ -6,19 +6,15 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.main.base.logger import println from spython.utils import ( - run_command as run_cmd, - check_install + run_command as run_cmd ) from spython.logger import bot import subprocess -import json import sys import os -import re diff --git a/spython/main/execute.py b/spython/main/execute.py index 4df805a6..5da8ae3a 100644 --- a/spython/main/execute.py +++ b/spython/main/execute.py @@ -8,8 +8,6 @@ from spython.logger import bot from spython.utils import stream_command -import os -import sys def execute(self, diff --git a/spython/main/export.py b/spython/main/export.py index b3f8c0c6..156a5cf5 100644 --- a/spython/main/export.py +++ b/spython/main/export.py @@ -7,7 +7,6 @@ from spython.logger import bot -from spython.utils import stream_command import tempfile import shutil import os diff --git a/spython/main/inspect.py b/spython/main/inspect.py index 796df504..53c1e843 100644 --- a/spython/main/inspect.py +++ b/spython/main/inspect.py @@ -7,7 +7,6 @@ import json as jsonp -from spython.logger import bot from spython.utils import ( check_install, run_command diff --git a/spython/main/instances.py b/spython/main/instances.py index 987a3d54..44f2a7ba 100644 --- a/spython/main/instances.py +++ b/spython/main/instances.py @@ -7,7 +7,7 @@ from spython.logger import bot -from spython.utils import ( run_command, check_install ) +from spython.utils import ( run_command ) def instances(self, name=None, return_json=False, quiet=False): '''list instances. For Singularity, this is provided as a command sub @@ -106,7 +106,7 @@ def stopall(self, sudo=False, quiet=True): instances) ''' - from spython.utils import run_command, check_install + from spython.utils import check_install check_install() subgroup = 'instance.stop' diff --git a/spython/main/parse/converters.py b/spython/main/parse/converters.py index af77d276..f1e49887 100644 --- a/spython/main/parse/converters.py +++ b/spython/main/parse/converters.py @@ -6,10 +6,7 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -import json -import os import re -import sys from spython.logger import bot diff --git a/spython/main/parse/docker.py b/spython/main/parse/docker.py index c99be13a..262dbcb5 100644 --- a/spython/main/parse/docker.py +++ b/spython/main/parse/docker.py @@ -8,11 +8,9 @@ import os import re -import sys from .environment import parse_env from .recipe import Recipe -from spython.utils import read_file from spython.logger import bot class DockerRecipe(Recipe): diff --git a/spython/main/parse/recipe.py b/spython/main/parse/recipe.py index f0a3692e..7081d74d 100644 --- a/spython/main/parse/recipe.py +++ b/spython/main/parse/recipe.py @@ -5,10 +5,8 @@ # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -import json import tempfile import os -import re import sys from spython.logger import bot diff --git a/spython/main/parse/singularity.py b/spython/main/parse/singularity.py index c289c7ec..f1f98079 100644 --- a/spython/main/parse/singularity.py +++ b/spython/main/parse/singularity.py @@ -6,13 +6,10 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -import json -import os import re import sys from spython.logger import bot -from spython.utils import read_file from spython.main.parse.recipe import Recipe diff --git a/spython/main/pull.py b/spython/main/pull.py index 6673a3de..ac2adf6a 100644 --- a/spython/main/pull.py +++ b/spython/main/pull.py @@ -10,9 +10,6 @@ from spython.utils import stream_command import os import re -import shutil -import sys -import tempfile def pull(self, image=None, diff --git a/spython/main/run.py b/spython/main/run.py index 3ecf0404..8599db5e 100644 --- a/spython/main/run.py +++ b/spython/main/run.py @@ -6,7 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.logger import bot from spython.utils import stream_command import json diff --git a/spython/oci/cmd/mounts.py b/spython/oci/cmd/mounts.py index 61fcd73c..4baaf1b2 100644 --- a/spython/oci/cmd/mounts.py +++ b/spython/oci/cmd/mounts.py @@ -6,11 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.logger import bot -from .states import _state_command -import sys - - def mount(self, image, sudo=None): '''create an OCI bundle from SIF image diff --git a/spython/oci/cmd/states.py b/spython/oci/cmd/states.py index dfcd36c6..24798441 100644 --- a/spython/oci/cmd/states.py +++ b/spython/oci/cmd/states.py @@ -6,7 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.logger import bot import json diff --git a/spython/tests/test_client.py b/spython/tests/test_client.py index 8af26738..32118fec 100644 --- a/spython/tests/test_client.py +++ b/spython/tests/test_client.py @@ -7,12 +7,10 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. from spython.utils import get_installdir -from spython.logger import bot from spython.main import Client import unittest import tempfile import shutil -import json import os diff --git a/spython/tests/test_instances.py b/spython/tests/test_instances.py index 590d9acb..8cac6aa9 100644 --- a/spython/tests/test_instances.py +++ b/spython/tests/test_instances.py @@ -6,13 +6,10 @@ # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.utils import get_installdir -from spython.logger import bot from spython.main import Client import unittest import tempfile import shutil -import json import os diff --git a/spython/tests/test_oci.py b/spython/tests/test_oci.py index 0cb8844e..fde551db 100644 --- a/spython/tests/test_oci.py +++ b/spython/tests/test_oci.py @@ -8,12 +8,10 @@ from spython.utils import get_installdir from spython.main.base.generate import RobotNamer -from spython.logger import bot from spython.main import Client import unittest import tempfile import shutil -import json import os print("############################################################## test_oci") diff --git a/spython/tests/test_utils.py b/spython/tests/test_utils.py index a6970f10..347d992d 100644 --- a/spython/tests/test_utils.py +++ b/spython/tests/test_utils.py @@ -6,11 +6,9 @@ # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -from spython.utils import get_installdir import unittest import tempfile import shutil -import json import os print("############################################################ test_utils") diff --git a/spython/utils/fileio.py b/spython/utils/fileio.py index 3c4519a0..69a638e5 100644 --- a/spython/utils/fileio.py +++ b/spython/utils/fileio.py @@ -10,14 +10,8 @@ import errno import os -import re import json from spython.logger import bot -from subprocess import ( - Popen, - PIPE, - STDOUT -) import sys diff --git a/spython/utils/terminal.py b/spython/utils/terminal.py index af88747c..5a2caf8a 100644 --- a/spython/utils/terminal.py +++ b/spython/utils/terminal.py @@ -11,7 +11,6 @@ import os import re -import json from spython.logger import bot import subprocess import sys From 47d49d8be10b7275543904bf901812a16744576b Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 15:47:40 +0200 Subject: [PATCH 03/19] Fix missing imports and typos/C&P bugs --- spython/image/__init__.py | 2 +- spython/image/cmd/create.py | 1 + spython/image/cmd/utils.py | 1 + spython/instance/cmd/iutils.py | 4 +++- spython/logger/progress.py | 2 +- spython/main/parse/converters.py | 1 + spython/main/parse/recipe.py | 4 ++-- spython/oci/cmd/mounts.py | 4 ++-- 8 files changed, 12 insertions(+), 7 deletions(-) diff --git a/spython/image/__init__.py b/spython/image/__init__.py index e4c7302c..bdb32096 100644 --- a/spython/image/__init__.py +++ b/spython/image/__init__.py @@ -8,7 +8,7 @@ import hashlib import os import re - +from spython.logger import bot class ImageBase(object): diff --git a/spython/image/cmd/create.py b/spython/image/cmd/create.py index 7a9e1ed9..34f8eddf 100644 --- a/spython/image/cmd/create.py +++ b/spython/image/cmd/create.py @@ -6,6 +6,7 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +import os from spython.logger import bot def create(self,image_path, size=1024, sudo=False): diff --git a/spython/image/cmd/utils.py b/spython/image/cmd/utils.py index 3f800ab9..49818ae4 100644 --- a/spython/image/cmd/utils.py +++ b/spython/image/cmd/utils.py @@ -6,6 +6,7 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +import os from spython.logger import bot def compress(self, image_path): diff --git a/spython/instance/cmd/iutils.py b/spython/instance/cmd/iutils.py index 738acfb3..9af745e8 100644 --- a/spython/instance/cmd/iutils.py +++ b/spython/instance/cmd/iutils.py @@ -5,6 +5,8 @@ # Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +from spython.instance import Instance +from spython.logger import bot def parse_table(table_string, header, remove_rows=1): '''parse a table to json from a string, where a header is expected by default. @@ -49,7 +51,7 @@ def get(self, name, return_json=False, quiet=False): cmd = self._init_command(subgroup) cmd.append(name) - output = run_command(cmd, quiet=True) + output = self.run_command(cmd, quiet=True) # Success, we have instances diff --git a/spython/logger/progress.py b/spython/logger/progress.py index d21ce031..300fe8bb 100644 --- a/spython/logger/progress.py +++ b/spython/logger/progress.py @@ -104,7 +104,7 @@ def bar(it, label='', width=32, hide=None, empty_char=BAR_EMPTY_CHAR, count = len(it) if expected_size is None else expected_size - with Bar(label=label, width=width, hide=hide, empty_char=BAR_EMPTY_CHAR, + with ProgressBar(label=label, width=width, hide=hide, empty_char=BAR_EMPTY_CHAR, filled_char=BAR_FILLED_CHAR, expected_size=count, every=every) \ as bar: for i, item in enumerate(it): diff --git a/spython/main/parse/converters.py b/spython/main/parse/converters.py index f1e49887..24907d8f 100644 --- a/spython/main/parse/converters.py +++ b/spython/main/parse/converters.py @@ -7,6 +7,7 @@ import re +from spython.logger import bot from spython.logger import bot diff --git a/spython/main/parse/recipe.py b/spython/main/parse/recipe.py index 7081d74d..ffe7c883 100644 --- a/spython/main/parse/recipe.py +++ b/spython/main/parse/recipe.py @@ -282,7 +282,7 @@ def _clean_line(self, line): return line.split('#')[0].strip() - def _write_script(path, lines, chmod=True): + def _write_script(self, path, lines, chmod=True): '''write a script with some lines content to path in the image. This is done by way of adding echo statements to the install section. @@ -296,7 +296,7 @@ def _write_script(path, lines, chmod=True): if len(lines) > 0: lastline = lines.pop() for line in lines: - self.install.append('echo "%s" >> %s' %path) + self.install.append('echo "%s" >> %s' %line %path) self.install.append(lastline) if chmod is True: diff --git a/spython/oci/cmd/mounts.py b/spython/oci/cmd/mounts.py index 4baaf1b2..659524e7 100644 --- a/spython/oci/cmd/mounts.py +++ b/spython/oci/cmd/mounts.py @@ -16,8 +16,8 @@ def mount(self, image, sudo=None): return self._state_command(image, command="mount", sudo=sudo) -def umount(self, image): - '''delete an OCI bundle createdfrom SIF image +def umount(self, image, sudo=None): + '''delete an OCI bundle created from SIF image Parameters ========== From 9cfe7d16755526ff9267ba83851c60e16d30321e Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 15:50:44 +0200 Subject: [PATCH 04/19] Fix singleton comparisons (None, True) Checks should be done with "is None"/"is not None" --- setup.py | 4 ++-- spython/instance/__init__.py | 4 ++-- spython/instance/cmd/start.py | 4 ++-- spython/logger/spinner.py | 2 +- spython/main/base/command.py | 2 +- spython/main/export.py | 6 +++--- spython/main/help.py | 2 +- spython/main/instances.py | 4 ++-- spython/oci/__init__.py | 8 ++++---- spython/oci/cmd/actions.py | 10 +++++----- spython/oci/cmd/states.py | 6 +++--- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/setup.py b/setup.py index 1557e3b0..636d2e8a 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ def get_requirements(lookup=None): '''get_requirements reads in requirements and versions from the lookup obtained with get_lookup''' - if lookup == None: + if lookup is None: lookup = get_lookup() install_requires = [] @@ -43,7 +43,7 @@ def get_requirements(lookup=None): if "exact_version" in module_meta: dependency = "%s==%s" %(module_name,module_meta['exact_version']) elif "min_version" in module_meta: - if module_meta['min_version'] == None: + if module_meta['min_version'] is None: dependency = module_name else: dependency = "%s>=%s" %(module_name,module_meta['min_version']) diff --git a/spython/instance/__init__.py b/spython/instance/__init__.py index 6cca5dd4..c244e444 100644 --- a/spython/instance/__init__.py +++ b/spython/instance/__init__.py @@ -42,7 +42,7 @@ def generate_name(self, name=None): supply one. ''' # If no name provided, use robot name - if name == None: + if name is None: name = self.RobotNamer.generate() self.name = name.replace('-','_') @@ -74,7 +74,7 @@ def _update_metadata(self, kwargs=None): ''' # If not given metadata, use instance.list to get it for container - if kwargs == None and hasattr(self, 'name'): + if kwargs is None and hasattr(self, 'name'): kwargs = self._list(self.name, quiet=True, return_json=True) # Add acceptable arguments diff --git a/spython/instance/cmd/start.py b/spython/instance/cmd/start.py index 044e2a92..f2112706 100644 --- a/spython/instance/cmd/start.py +++ b/spython/instance/cmd/start.py @@ -30,7 +30,7 @@ def start(self, image=None, name=None, args=None, sudo=False, options=[], captur check_install() # If name provided, over write robot (default) - if name != None: + if name is not None: self.name = name # If an image isn't provided, we have an initialized instance @@ -57,7 +57,7 @@ def start(self, image=None, name=None, args=None, sudo=False, options=[], captur cmd = cmd + options + [image, self.name] # If arguments are provided - if args != None: + if args is not None: if not isinstance(args, list): args = [args] cmd = cmd + args diff --git a/spython/logger/spinner.py b/spython/logger/spinner.py index e9221360..22d40980 100644 --- a/spython/logger/spinner.py +++ b/spython/logger/spinner.py @@ -31,7 +31,7 @@ def changing_arrows(): for cursor in '<^>v': yield cursor def select_generator(self, generator): - if generator == None: + if generator is None: generator = choice(['cursor', 'arrow', 'balloons']) diff --git a/spython/main/base/command.py b/spython/main/base/command.py index 0d51dc36..ca3031e6 100644 --- a/spython/main/base/command.py +++ b/spython/main/base/command.py @@ -125,7 +125,7 @@ def run_command(self, cmd, ''' # First preference to function, then to client setting - if quiet == None: + if quiet is None: quiet = self.quiet result = run_cmd(cmd, sudo=sudo, capture=capture, quiet=quiet) diff --git a/spython/main/export.py b/spython/main/export.py index 156a5cf5..2f3a9dec 100644 --- a/spython/main/export.py +++ b/spython/main/export.py @@ -34,7 +34,7 @@ def export(self, # If not version 3, run deprecated command if 'version 3' in self.version() or '2.6' in self.version(): - if output_file == None: + if output_file is None: output_file = self._get_filename(image_path, 'sandbox') return self.build(recipe=image_path, @@ -79,7 +79,7 @@ def _export(self, cmd = self._init_command('export') # If the user has specified export to pipe, we don't need a file - if pipe == True: + if pipe: cmd.append(image_path) else: @@ -94,7 +94,7 @@ def _export(self, return None # if user has specified output file, move it there, return path - if output_file != None: + if output_file is not None: shutil.copyfile(tmptar, output_file) return output_file else: diff --git a/spython/main/help.py b/spython/main/help.py index 20a676fd..ebf6a1bf 100644 --- a/spython/main/help.py +++ b/spython/main/help.py @@ -18,7 +18,7 @@ def help(self, command=None): check_install() cmd = ['singularity','--help'] - if command != None: + if command is not None: cmd.append(command) help = self._run_command(cmd) return help diff --git a/spython/main/instances.py b/spython/main/instances.py index 44f2a7ba..a133f0e4 100644 --- a/spython/main/instances.py +++ b/spython/main/instances.py @@ -66,7 +66,7 @@ def instances(self, name=None, return_json=False, quiet=False): for i in instances: # If the user has provided a name, only add instance matches - if name != None: + if name is not None: if name != i['daemon_name']: continue @@ -89,7 +89,7 @@ def instances(self, name=None, return_json=False, quiet=False): bot.info('No instances found.') # If we are given a name, return just one - if name != None and instances not in [None,[]]: + if name is not None and instances not in [None,[]]: if len(instances) == 1: instances = instances[0] diff --git a/spython/oci/__init__.py b/spython/oci/__init__.py index 46452eab..4cb2cbcc 100644 --- a/spython/oci/__init__.py +++ b/spython/oci/__init__.py @@ -38,7 +38,7 @@ def __init__(self, self.sudo = sudo # If bundle is provided, create it - if bundle != None and container_id != None and create: + if bundle is not None and container_id is not None and create: self.bundle = bundle self.create(bundle, container_id, **kwargs) @@ -56,7 +56,7 @@ def get_container_id(self, container_id=None): ''' # The user must provide a container_id, or have one with the client - if container_id == None and self.container_id == None: + if container_id is None and self.container_id is None: bot.exit('You must provide a container_id.') # Choose whichever is not None, with preference for function provided @@ -72,7 +72,7 @@ def get_uri(self): # Naming def __str__(self): - if self.container_id != None: + if self.container_id is not None: return "[singularity-python-oci:%s]" % self.container_id return "[singularity-python-oci]" @@ -92,7 +92,7 @@ def _get_sudo(self, sudo=None): ========== sudo: if None, use self.sudo. Otherwise return sudo. ''' - if sudo == None: + if sudo is None: sudo = self.sudo return sudo diff --git a/spython/oci/cmd/actions.py b/spython/oci/cmd/actions.py index 09f2a0f4..324e90aa 100644 --- a/spython/oci/cmd/actions.py +++ b/spython/oci/cmd/actions.py @@ -119,11 +119,11 @@ def _run(self, bundle, # Additional Logging Files cmd = cmd + ['--log-format', log_format] - if log_path != None: + if log_path is not None: cmd = cmd + ['--log-path', log_path] - if pid_file != None: + if pid_file is not None: cmd = cmd + ['--pid-file', pid_file] - if sync_socket != None: + if sync_socket is not None: cmd = cmd + ['--sync-socket', sync_socket] if empty_process: cmd.append('--empty-process') @@ -225,7 +225,7 @@ def execute(self, command=None, container_id=None, sudo=False, stream=False): # Add the container_id cmd.append(container_id) - if command != None: + if command is not None: if not isinstance(command, list): command = [command] @@ -255,7 +255,7 @@ def update(self, container_id, from_file=None): # singularity oci delete cmd = self._init_command('update') - if from_file != None: + if from_file is not None: cmd = cmd + ['--from-file', from_file] # Add the container_id diff --git a/spython/oci/cmd/states.py b/spython/oci/cmd/states.py index 24798441..52a9ed34 100644 --- a/spython/oci/cmd/states.py +++ b/spython/oci/cmd/states.py @@ -35,7 +35,7 @@ def state(self, container_id=None, sudo=None, sync_socket=None): # singularity oci state cmd = self._init_command('state') - if sync_socket != None: + if sync_socket is not None: cmd = cmd + ['--sync-socket', sync_socket] # Finally, add the container_id @@ -44,7 +44,7 @@ def state(self, container_id=None, sudo=None, sync_socket=None): # Get the instance state result = self._run_command(cmd, sudo=sudo, quiet=True) - if result != None: + if result is not None: # If successful, a string is returned to parse if isinstance(result, str): @@ -133,7 +133,7 @@ def kill(self, container_id=None, sudo=None, signal=None): cmd.append(container_id) # Add the signal, if defined - if signal != None: + if signal is not None: cmd = cmd + ['--signal', signal] # Run the command, return return code From b906b4ed45f80ddefe7c939d12ecb9a34416d5f2 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 15:56:14 +0200 Subject: [PATCH 05/19] Fix wrong indents --- spython/image/__init__.py | 24 +++++++------- spython/instance/__init__.py | 52 +++++++++++++++---------------- spython/main/base/__init__.py | 8 ++--- spython/main/base/flags.py | 6 ++-- spython/main/parse/singularity.py | 18 +++++------ 5 files changed, 54 insertions(+), 54 deletions(-) diff --git a/spython/image/__init__.py b/spython/image/__init__.py index bdb32096..fe1ee324 100644 --- a/spython/image/__init__.py +++ b/spython/image/__init__.py @@ -65,18 +65,18 @@ def parse_image_name(self, image): class Image(ImageBase): def __init__(self, image=None): - '''An image here is an image file or a record. - The user can choose to load the image when starting the client, or - update the main client with an image. The image object is kept - with the main client to make running additional commands easier. - - Parameters - ========== - image: the image uri to parse (required) - - ''' - super(ImageBase, self).__init__() - self.parse_image_name(image) + '''An image here is an image file or a record. + The user can choose to load the image when starting the client, or + update the main client with an image. The image object is kept + with the main client to make running additional commands easier. + + Parameters + ========== + image: the image uri to parse (required) + + ''' + super(ImageBase, self).__init__() + self.parse_image_name(image) def get_hash(self, image=None): diff --git a/spython/instance/__init__.py b/spython/instance/__init__.py index c244e444..cc283145 100644 --- a/spython/instance/__init__.py +++ b/spython/instance/__init__.py @@ -11,29 +11,29 @@ class Instance(ImageBase): def __init__(self, image, start=True, name=None, **kwargs): - '''An instance is an image running as an instance with services. - This class has functions appended under cmd/__init__ and is - instantiated when the user calls Client. - - Parameters - ========== - image: the Singularity image uri to parse (required) - start: boolean to start the instance (default is True) - name: a name for the instance (will generate RobotName - if not provided) - ''' - super(ImageBase, self).__init__() - self.parse_image_name(image) - self.generate_name(name) - - # Update metadats from arguments - self._update_metadata(kwargs) - self.options = [] - self.cmd = [] - - # Start the instance - if start is True: - self.start(**kwargs) + '''An instance is an image running as an instance with services. + This class has functions appended under cmd/__init__ and is + instantiated when the user calls Client. + + Parameters + ========== + image: the Singularity image uri to parse (required) + start: boolean to start the instance (default is True) + name: a name for the instance (will generate RobotName + if not provided) + ''' + super(ImageBase, self).__init__() + self.parse_image_name(image) + self.generate_name(name) + + # Update metadats from arguments + self._update_metadata(kwargs) + self.options = [] + self.cmd = [] + + # Start the instance + if start is True: + self.start(**kwargs) # Unique resource identifier @@ -80,9 +80,9 @@ def _update_metadata(self, kwargs=None): # Add acceptable arguments for arg in ['pid', 'name']: - # Skip over non-iterables: - if arg in kwargs: - setattr(self, arg, kwargs[arg]) + # Skip over non-iterables: + if arg in kwargs: + setattr(self, arg, kwargs[arg]) if "image" in kwargs: self._image = kwargs['image'] diff --git a/spython/main/base/__init__.py b/spython/main/base/__init__.py index 978d8d6c..b4644c7e 100644 --- a/spython/main/base/__init__.py +++ b/spython/main/base/__init__.py @@ -37,10 +37,10 @@ def __repr__(self): return self.__str__() def __init__(self): - '''the base client for singularity, will have commands added to it. - upon init, store verbosity requested in environment MESSAGELEVEL. - ''' - self._init_level() + '''the base client for singularity, will have commands added to it. + upon init, store verbosity requested in environment MESSAGELEVEL. + ''' + self._init_level() def version(self): '''a wrapped to get_singularity_version, takes no arguments. diff --git a/spython/main/base/flags.py b/spython/main/base/flags.py index af420364..0f54a535 100644 --- a/spython/main/base/flags.py +++ b/spython/main/base/flags.py @@ -20,13 +20,13 @@ def parse_verbosity(self, args): flags = [] if args.silent is True: - flags.append('--silent') + flags.append('--silent') elif args.quiet is True: flags.append('--quiet') elif args.debug is True: - flags.append('--debug') + flags.append('--debug') elif args.verbose is True: - flags.append('-' + 'v' * args.verbose) + flags.append('-' + 'v' * args.verbose) return flags diff --git a/spython/main/parse/singularity.py b/spython/main/parse/singularity.py index f1f98079..ab69ca3d 100644 --- a/spython/main/parse/singularity.py +++ b/spython/main/parse/singularity.py @@ -122,17 +122,17 @@ def _files(self, lines): # Comments and Help def _comments(self, lines): - ''' comments is a wrapper for comment, intended to be given a list - of comments. + ''' comments is a wrapper for comment, intended to be given a list + of comments. - Parameters - ========== - lines: the list of lines to parse + Parameters + ========== + lines: the list of lines to parse - ''' - for line in lines: - comment = self._comment(line) - self.comments.append(comment) + ''' + for line in lines: + comment = self._comment(line) + self.comments.append(comment) def _comment(self, line): From 63a4becd73217a919e2a5e37b36928936c021c86 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 15:57:25 +0200 Subject: [PATCH 06/19] Fix super() calls --- spython/image/__init__.py | 2 +- spython/instance/__init__.py | 2 +- spython/oci/__init__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spython/image/__init__.py b/spython/image/__init__.py index fe1ee324..94678da3 100644 --- a/spython/image/__init__.py +++ b/spython/image/__init__.py @@ -75,7 +75,7 @@ def __init__(self, image=None): image: the image uri to parse (required) ''' - super(ImageBase, self).__init__() + super().__init__() self.parse_image_name(image) diff --git a/spython/instance/__init__.py b/spython/instance/__init__.py index cc283145..1175ff02 100644 --- a/spython/instance/__init__.py +++ b/spython/instance/__init__.py @@ -22,7 +22,7 @@ def __init__(self, image, start=True, name=None, **kwargs): name: a name for the instance (will generate RobotName if not provided) ''' - super(ImageBase, self).__init__() + super().__init__() self.parse_image_name(image) self.generate_name(name) diff --git a/spython/oci/__init__.py b/spython/oci/__init__.py index 4cb2cbcc..c8747a95 100644 --- a/spython/oci/__init__.py +++ b/spython/oci/__init__.py @@ -30,7 +30,7 @@ def __init__(self, sudo: if init is called with or without sudo, keep a record and use for following commands unless sudo is provided to function. ''' - super(ImageBase, self).__init__() + super().__init__() # Will typically be None, unless used outside of Client self.container_id = container_id From 9739e21279aa6cfb88d7b43e6ee5af41330a04ec Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 16:09:27 +0200 Subject: [PATCH 07/19] Fix conflict with overriden get_uri ImageBase defines get_uri(self, image) which is overriden in subclasses by get_uri(self) potentially causing trouble. Solution: Extract to free function Note: get_uri does actually return a protocol(-like), not a URI --- spython/image/__init__.py | 51 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/spython/image/__init__.py b/spython/image/__init__.py index 94678da3..02a704b5 100644 --- a/spython/image/__init__.py +++ b/spython/image/__init__.py @@ -10,6 +10,29 @@ import re from spython.logger import bot +def get_uri(image): + '''get the uri of an image, or the string (optional) that appears before + ://. Optional. If none found, returns '' + ''' + image = image or '' + uri = '' + + match = re.match("^(?P.+)://", image) + if match: + uri = match.group('uri') + + return uri + + +def remove_uri(image): + '''remove_image_uri will return just the image name. + this will also remove all spaces from the uri. + ''' + image = image or '' + uri = get_uri(image) or '' + image = image.replace('%s://' %uri,'', 1) + return image.strip('-').rstrip('/') + class ImageBase(object): def __str__(self): @@ -23,30 +46,6 @@ def __repr__(self): return self.__str__() - def get_uri(self, image): - '''get the uri of an image, or the string (optional) that appears before - ://. Optional. If none found, returns '' - ''' - image = image or '' - uri = '' - - match = re.match("^(?P.+)://", image) - if match: - uri = match.group('uri') - - return uri - - - def remove_uri(self, image): - '''remove_image_uri will return just the image name. - this will also remove all spaces from the uri. - ''' - image = image or '' - uri = self.get_uri(image) or '' - image = image.replace('%s://' %uri,'', 1) - return image.strip('-').rstrip('/') - - def parse_image_name(self, image): ''' simply split the uri from the image. Singularity handles @@ -58,8 +57,8 @@ def parse_image_name(self, image): ''' self._image = image - self.uri = self.get_uri(image) - self.image = self.remove_uri(image) + self.uri = get_uri(image) + self.image = remove_uri(image) class Image(ImageBase): From c09c60b4d60038cfeff9de355ce39f8e82198e4c Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 16:35:32 +0200 Subject: [PATCH 08/19] Use enumerate --- spython/instance/cmd/iutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spython/instance/cmd/iutils.py b/spython/instance/cmd/iutils.py index 9af745e8..f6a3cdd7 100644 --- a/spython/instance/cmd/iutils.py +++ b/spython/instance/cmd/iutils.py @@ -29,8 +29,8 @@ def parse_table(table_string, header, remove_rows=1): item = {} # This assumes no white spaces in each entry, which should be the case row = [x for x in row.split(' ') if x] - for e in range(len(row)): - item[header[e]] = row[e] + for i, r in enumerate(row): + item[header[i]] = r parsed.append(item) return parsed From e70783a9389edb9ccae95eef10d038903f71b40a Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 16:35:58 +0200 Subject: [PATCH 09/19] Add missing sudo param --- spython/oci/cmd/actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spython/oci/cmd/actions.py b/spython/oci/cmd/actions.py index 324e90aa..32bff381 100644 --- a/spython/oci/cmd/actions.py +++ b/spython/oci/cmd/actions.py @@ -236,7 +236,7 @@ def execute(self, command=None, container_id=None, sudo=False, stream=False): return stream_command(cmd, sudo=sudo) return self._run_command(cmd, sudo=sudo, quiet=True) -def update(self, container_id, from_file=None): +def update(self, container_id, from_file=None, sudo=False): '''update container cgroup resources for a specific container_id, The container must have state "running" or "created." From 8905507d5853a58f9a43f243cb489e29c1386fbe Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 16:36:21 +0200 Subject: [PATCH 10/19] Fix regexp --- spython/main/parse/singularity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spython/main/parse/singularity.py b/spython/main/parse/singularity.py index ab69ca3d..42ed054e 100644 --- a/spython/main/parse/singularity.py +++ b/spython/main/parse/singularity.py @@ -382,7 +382,7 @@ def _add_section(self, line, section=None): parts = line.split(' ') if len(parts) > 1: name = ' '.join(parts[1:]) - section = re.sub('[%]|(\s+)','',parts[0]).lower() + section = re.sub(r'[%]|(\s+)','',parts[0]).lower() if section not in self.config: self.config[section] = [] From fef4d289afdfd957cec46d769784253da31640c4 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 16:36:28 +0200 Subject: [PATCH 11/19] Cleanup --- spython/client/shell.py | 3 --- spython/image/cmd/importcmd.py | 1 - spython/logger/message.py | 2 +- spython/logger/progress.py | 2 +- spython/main/inspect.py | 3 ++- spython/tests/test_instances.py | 2 +- 6 files changed, 5 insertions(+), 8 deletions(-) diff --git a/spython/client/shell.py b/spython/client/shell.py index 3c41da78..b37a088f 100644 --- a/spython/client/shell.py +++ b/spython/client/shell.py @@ -7,9 +7,6 @@ def main(args, options, parser): - - from spython.main import Client as cli - # If we have options, first is image image = None if len(options) > 0: diff --git a/spython/image/cmd/importcmd.py b/spython/image/cmd/importcmd.py index 15c2a9f4..449526e6 100644 --- a/spython/image/cmd/importcmd.py +++ b/spython/image/cmd/importcmd.py @@ -23,4 +23,3 @@ def importcmd(self, image_path, input_source): output = self.run_command(cmd, sudo=False) self.println(output) return image_path - diff --git a/spython/logger/message.py b/spython/logger/message.py index 453bd729..dc7b7f93 100644 --- a/spython/logger/message.py +++ b/spython/logger/message.py @@ -206,7 +206,7 @@ def show_progress( percent = "%5s" % ("{0:.1f}").format(percent) output = '\r' + prefix + \ " |%s| %s%s %s" % (bar, percent, '%', suffix) - sys.stdout.write(output), + sys.stdout.write(output) if iteration == total and carriage_return: sys.stdout.write('\n') sys.stdout.flush() diff --git a/spython/logger/progress.py b/spython/logger/progress.py index 300fe8bb..666cfc6c 100644 --- a/spython/logger/progress.py +++ b/spython/logger/progress.py @@ -54,7 +54,7 @@ def __init__(self, label='', width=32, hide=None, empty_char=BAR_EMPTY_CHAR, self.etadelta = time.time() self.etadisp = self.format_time(self.eta) self.last_progress = 0 - if (self.expected_size): + if self.expected_size: self.show(0) def show(self, progress, count=None): diff --git a/spython/main/inspect.py b/spython/main/inspect.py index 53c1e843..2d3f2273 100644 --- a/spython/main/inspect.py +++ b/spython/main/inspect.py @@ -40,7 +40,8 @@ def inspect(self, image=None, json=True, app=None, quiet=True): if "version 3" in self.version(): options = ['e','d','l','r','H','t'] - [cmd.append('-%s' % x) for x in options] + for x in options: + cmd.append('-%s' % x) if json is True: cmd.append('--json') diff --git a/spython/tests/test_instances.py b/spython/tests/test_instances.py index 8cac6aa9..53388816 100644 --- a/spython/tests/test_instances.py +++ b/spython/tests/test_instances.py @@ -50,7 +50,7 @@ def test_instances(self): print("...Case 3: Commands to instances") result = self.cli.execute(myinstance, ['echo', 'hello']) - self.assertTrue('hello\n' == result) + self.assertEqual(result, 'hello\n') print('...Case 4: Return value from instance') result = self.cli.execute(myinstance,'ls /', return_result=True) From 40520d5ce7f6893761198512546b82a8bf0fd718 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 16:50:04 +0200 Subject: [PATCH 12/19] Remove or fix unused variables --- spython/client/__init__.py | 18 ------------------ spython/image/cmd/export.py | 2 +- spython/image/cmd/utils.py | 2 +- spython/main/build.py | 2 +- spython/main/inspect.py | 2 +- spython/main/parse/singularity.py | 6 +----- spython/oci/cmd/actions.py | 2 +- spython/tests/test_client.py | 4 +++- spython/tests/test_instances.py | 2 ++ spython/tests/test_utils.py | 2 +- 10 files changed, 12 insertions(+), 30 deletions(-) diff --git a/spython/client/__init__.py b/spython/client/__init__.py index 4da736bb..9ac8e3b7 100644 --- a/spython/client/__init__.py +++ b/spython/client/__init__.py @@ -63,23 +63,6 @@ def get_parser(): return parser - -def get_subparsers(parser): - '''get_subparser will get a dictionary of subparsers, to help with printing help - ''' - - actions = [action for action in parser._actions - if isinstance(action, argparse._SubParsersAction)] - - subparsers = dict() - for action in actions: - # get all subparsers and print help - for choice, subparser in action.choices.items(): - subparsers[choice] = subparser - - return subparsers - - def set_verbosity(args): '''determine the message level in the environment to set based on args. ''' @@ -113,7 +96,6 @@ def version(): def main(): parser = get_parser() - subparsers = get_subparsers(parser) def help(return_code=0): '''print help, including the software version and active client diff --git a/spython/image/cmd/export.py b/spython/image/cmd/export.py index 41c168d9..c8ace990 100644 --- a/spython/image/cmd/export.py +++ b/spython/image/cmd/export.py @@ -25,5 +25,5 @@ def export(self, image_path, tmptar=None): tmptar = "/%s/tmptar.tar" %(tempfile.mkdtemp()) cmd = ['singularity', 'image.export', '-f', tmptar, image_path] - output = self.run_command(cmd, sudo=False) + self.run_command(cmd, sudo=False) return tmptar diff --git a/spython/image/cmd/utils.py b/spython/image/cmd/utils.py index 49818ae4..a7ae8f41 100644 --- a/spython/image/cmd/utils.py +++ b/spython/image/cmd/utils.py @@ -27,5 +27,5 @@ def decompress(self, image_path, quiet=True): extracted_file = image_path.replace('.gz','') cmd = ['gzip','-d','-f', image_path] - result = self.run_command(cmd, quiet=quiet) # exits if return code != 0 + self.run_command(cmd, quiet=quiet) # exits if return code != 0 return extracted_file diff --git a/spython/main/build.py b/spython/main/build.py index 87a4f725..5cb74d54 100644 --- a/spython/main/build.py +++ b/spython/main/build.py @@ -89,7 +89,7 @@ def build(self, recipe=None, cmd = cmd + [image, recipe] if stream is False: - output = self._run_command(cmd, sudo=sudo, capture=False) + self._run_command(cmd, sudo=sudo, capture=False) else: # Here we return the expected image, and an iterator! # The caller must iterate over diff --git a/spython/main/inspect.py b/spython/main/inspect.py index 2d3f2273..6c475fa2 100644 --- a/spython/main/inspect.py +++ b/spython/main/inspect.py @@ -53,7 +53,7 @@ def inspect(self, image=None, json=True, app=None, quiet=True): result = jsonp.loads(result['message'][0]) # Fix up labels - labels = parse_labels(result) + result = parse_labels(result) if not quiet: print(jsonp.dumps(result, indent=4)) diff --git a/spython/main/parse/singularity.py b/spython/main/parse/singularity.py index 42ed054e..e001c3f3 100644 --- a/spython/main/parse/singularity.py +++ b/spython/main/parse/singularity.py @@ -85,7 +85,6 @@ def _test(self, lines): ''' self._write_script('/tests.sh', lines) - testrun = "/bin/bash /tests.sh" self.test = "/bin/bash /tests.sh" @@ -327,7 +326,6 @@ def load_recipe(self): self.config = dict() section = None - name = None while len(lines) > 0: @@ -379,9 +377,7 @@ def _add_section(self, line, section=None): line = line.split('#',1)[0].strip() # Is there a section name? - parts = line.split(' ') - if len(parts) > 1: - name = ' '.join(parts[1:]) + parts = line.split(' ') section = re.sub(r'[%]|(\s+)','',parts[0]).lower() if section not in self.config: diff --git a/spython/oci/cmd/actions.py b/spython/oci/cmd/actions.py index 32bff381..6425d495 100644 --- a/spython/oci/cmd/actions.py +++ b/spython/oci/cmd/actions.py @@ -132,7 +132,7 @@ def _run(self, bundle, cmd.append(container_id) # Generate the instance - result = self._send_command(cmd, sudo=True) + self._send_command(cmd, sudo=True) # Get the status to report to the user! # TODO: Singularity seems to create even with error, can we check and diff --git a/spython/tests/test_client.py b/spython/tests/test_client.py index 32118fec..050cd345 100644 --- a/spython/tests/test_client.py +++ b/spython/tests/test_client.py @@ -80,7 +80,9 @@ def test_commands(self): self.assertEqual(result['return_code'], 0) print("Testing client.inspect command") - labels = self.cli.inspect(container) + result = self.cli.inspect(container) + self.assertEqual(result['type'], 'container') + self.assertTrue('attributes' in result) os.remove(container) diff --git a/spython/tests/test_instances.py b/spython/tests/test_instances.py index 53388816..0fdad177 100644 --- a/spython/tests/test_instances.py +++ b/spython/tests/test_instances.py @@ -64,6 +64,8 @@ def test_instances(self): self.assertEqual(instances, []) myinstance1 = self.cli.instance(image) myinstance2 = self.cli.instance(image) + self.assertTrue(myinstance1 is not None) + self.assertTrue(myinstance2 is not None) instances = self.cli.instances() self.assertEqual(len(instances), 2) self.cli.instance_stopall() diff --git a/spython/tests/test_utils.py b/spython/tests/test_utils.py index 347d992d..679543af 100644 --- a/spython/tests/test_utils.py +++ b/spython/tests/test_utils.py @@ -44,7 +44,7 @@ def test_write_read_files(self): bad_json = {"Wakkawakkawakka'}":[{True},"2",3]} tmpfile = tempfile.mkstemp()[1] os.remove(tmpfile) - with self.assertRaises(TypeError) as cm: + with self.assertRaises(TypeError): write_json(bad_json,tmpfile) print("...Case 2: Providing good json") From 888f61da4dcf0eb00291cbe44b5d09b39ddce672 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 17:49:51 +0200 Subject: [PATCH 13/19] Add linter to CI --- .circleci/config.yml | 9 + .pylintrc | 511 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 520 insertions(+) create mode 100644 .pylintrc diff --git a/.circleci/config.yml b/.circleci/config.yml index 4e010b90..72ae21e7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -68,6 +68,13 @@ install_python_2: &install_python_2 echo "Miniconda 2 is already installed, continuing to build." fi +run_linter: &run_linter + name: run linter + command: | + $HOME/conda/bin/pip install --upgrade pylint + cd ~/repo + $HOME/conda/bin/pylint spython + test_spython: &test_spython name: Test Singularity Python (Singularity Version 2 and 3) command: | @@ -99,6 +106,7 @@ jobs: - singularity/debian-install-3: singularity-version: 3.1.0 - run: *install_spython + - run: *run_linter - save_cache: paths: - /home/circleci/conda @@ -121,6 +129,7 @@ jobs: - singularity/debian-install-3: singularity-version: 3.1.0 - run: *install_spython + - run: *run_linter - save_cache: paths: - /home/circleci/conda diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..68d70de2 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,511 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=0 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=attribute-defined-outside-init, + bad-continuation, + bad-whitespace, + bare-except, + blacklisted-name, + duplicate-code, + fixme, + import-error, + invalid-name, + len-as-condition, + line-too-long, + missing-docstring, + multiple-statements, + no-member, + protected-access, + R, + redefined-builtin, + redefined-outer-name, + trailing-whitespace, + unused-argument, + wrong-import-order + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable= + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. +#class-attribute-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. +#variable-rgx= + + +[STRING] + +# This flag controls whether the implicit-str-concat-in-sequence should +# generate a warning on implicit string concatenation in sequences defined over +# several lines. +check-str-concat-over-line-jumps=no + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package.. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[LOGGING] + +# Format style used to check logging format string. `old` means using % +# formatting, while `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma, + dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[DESIGN] + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement. +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules=optparse,tkinter.tix + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled). +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled). +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "BaseException, Exception". +overgeneral-exceptions=BaseException, + Exception From faa97d7d5fdc8f9aa5ddc6689ae2a9c0fad79263 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 18:03:36 +0200 Subject: [PATCH 14/19] Fix remaining lint issues --- spython/instance/cmd/start.py | 4 +-- spython/main/base/flags.py | 48 +++++++++++++++----------------- spython/main/parse/converters.py | 2 -- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/spython/instance/cmd/start.py b/spython/instance/cmd/start.py index f2112706..08e895cd 100644 --- a/spython/instance/cmd/start.py +++ b/spython/instance/cmd/start.py @@ -8,7 +8,7 @@ from spython.logger import bot -def start(self, image=None, name=None, args=None, sudo=False, options=[], capture=False): +def start(self, image=None, name=None, args=None, sudo=False, options=None, capture=False): '''start an instance. This is done by default when an instance is created. Parameters @@ -51,7 +51,7 @@ def start(self, image=None, name=None, args=None, sudo=False, options=[], captur # Add options, if they are provided if not isinstance(options, list): - options = options.split(' ') + options = [] if options is None else options.split(' ') # Assemble the command! cmd = cmd + options + [image, self.name] diff --git a/spython/main/base/flags.py b/spython/main/base/flags.py index 0f54a535..1a333781 100644 --- a/spython/main/base/flags.py +++ b/spython/main/base/flags.py @@ -6,31 +6,6 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. - -def parse_verbosity(self, args): - '''parse_verbosity will take an argument object, and return the args - passed (from a dictionary) to a list - - Parameters - ========== - args: the argparse argument objects - - ''' - - flags = [] - - if args.silent is True: - flags.append('--silent') - elif args.quiet is True: - flags.append('--quiet') - elif args.debug is True: - flags.append('--debug') - elif args.verbose is True: - flags.append('-' + 'v' * args.verbose) - - return flags - - ''' GLOBAL OPTIONS: -d|--debug Print debugging information @@ -69,3 +44,26 @@ def parse_verbosity(self, args): instance Persistent instance command group ''' + +def parse_verbosity(self, args): + '''parse_verbosity will take an argument object, and return the args + passed (from a dictionary) to a list + + Parameters + ========== + args: the argparse argument objects + + ''' + + flags = [] + + if args.silent is True: + flags.append('--silent') + elif args.quiet is True: + flags.append('--quiet') + elif args.debug is True: + flags.append('--debug') + elif args.verbose is True: + flags.append('-' + 'v' * args.verbose) + + return flags diff --git a/spython/main/parse/converters.py b/spython/main/parse/converters.py index 24907d8f..6a2fd191 100644 --- a/spython/main/parse/converters.py +++ b/spython/main/parse/converters.py @@ -9,8 +9,6 @@ import re from spython.logger import bot -from spython.logger import bot - # Singularity to Dockerfile # Easier, parsed line by line From 2a43fd1de150720259c63055e153272acb732288 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 27 May 2019 18:03:48 +0200 Subject: [PATCH 15/19] Bump version to 0.0.60 --- CHANGELOG.md | 2 ++ spython/version.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca4a13d5..03411ebf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ The client here will eventually be released as "spython" (and eventually to singularity on pypi), and the versions here will coincide with these releases. ## [master](https://github.com/singularityhub/singularity-cli/tree/master) + - fix crash in some error conditions (0.0.60) + - more OCI commands accept sudo parameter - fixing warning for files, only relevant for sources (0.0.59) - deprecating pulling by commit or hash, not supported for Singularity (0.0.58) - export command added back, points to build given Singularity 3.x+ diff --git a/spython/version.py b/spython/version.py index fa2b936a..291b69ac 100644 --- a/spython/version.py +++ b/spython/version.py @@ -6,7 +6,7 @@ # with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -__version__ = "0.0.59" +__version__ = "0.0.60" AUTHOR = 'Vanessa Sochat' AUTHOR_EMAIL = 'vsochat@stanford.edu' NAME = 'spython' From 9d18cd84261da680a1d2b1a0653ffaa29997d4c2 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Tue, 28 May 2019 10:36:53 +0200 Subject: [PATCH 16/19] Implement split_uri superseding get_uri/remove_uri --- spython/image/__init__.py | 27 ++------------------------- spython/tests/test_utils.py | 15 +++++++++++++++ spython/utils/__init__.py | 1 + spython/utils/terminal.py | 17 ++++++++++++++++- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/spython/image/__init__.py b/spython/image/__init__.py index 02a704b5..1fa9eae2 100644 --- a/spython/image/__init__.py +++ b/spython/image/__init__.py @@ -9,29 +9,7 @@ import os import re from spython.logger import bot - -def get_uri(image): - '''get the uri of an image, or the string (optional) that appears before - ://. Optional. If none found, returns '' - ''' - image = image or '' - uri = '' - - match = re.match("^(?P.+)://", image) - if match: - uri = match.group('uri') - - return uri - - -def remove_uri(image): - '''remove_image_uri will return just the image name. - this will also remove all spaces from the uri. - ''' - image = image or '' - uri = get_uri(image) or '' - image = image.replace('%s://' %uri,'', 1) - return image.strip('-').rstrip('/') +from spython.utils import split_uri class ImageBase(object): @@ -57,8 +35,7 @@ def parse_image_name(self, image): ''' self._image = image - self.uri = get_uri(image) - self.image = remove_uri(image) + self.uri, self.image = split_uri(image) class Image(ImageBase): diff --git a/spython/tests/test_utils.py b/spython/tests/test_utils.py index 679543af..4aba8502 100644 --- a/spython/tests/test_utils.py +++ b/spython/tests/test_utils.py @@ -97,11 +97,26 @@ def test_get_installdir(self): self.assertTrue(whereami.endswith('spython')) + def test_split_uri(self): + from spython.utils import split_uri + protocol, image = split_uri('docker://ubuntu') + self.assertEqual(protocol, 'docker') + self.assertEqual(image, 'ubuntu') + + protocol, image = split_uri('http://image/path/with/slash/') + self.assertEqual(protocol, 'http') + self.assertEqual(image, 'image/path/with/slash') + + protocol, image = split_uri('no/proto/') + self.assertEqual(protocol, '') + self.assertEqual(image, 'no/proto') + def test_remove_uri(self): print("Testing utils.remove_uri") from spython.utils import remove_uri self.assertEqual(remove_uri('docker://ubuntu'),'ubuntu') self.assertEqual(remove_uri('shub://vanessa/singularity-images'),'vanessa/singularity-images') + self.assertEqual(remove_uri('vanessa/singularity-images'),'vanessa/singularity-images') diff --git a/spython/utils/__init__.py b/spython/utils/__init__.py index 702fdb3a..46419f35 100644 --- a/spython/utils/__init__.py +++ b/spython/utils/__init__.py @@ -13,5 +13,6 @@ stream_command, run_command, format_container_name, + split_uri, remove_uri ) diff --git a/spython/utils/terminal.py b/spython/utils/terminal.py index 5a2caf8a..9fd14ee8 100644 --- a/spython/utils/terminal.py +++ b/spython/utils/terminal.py @@ -177,7 +177,22 @@ def format_container_name(name, special_characters=None): for e in name if e.isalnum() or e in special_characters) +def split_uri(container): + '''Split the uri of a container into the protocol and image part + + An empty protocol is returned if none found. + A trailing slash is removed from the image part. + ''' + parts = container.split('://', 1) + if len(parts) == 2: + protocol, image = parts + else: + protocol = '' + image=parts[0] + return protocol, image.rstrip('/') + + def remove_uri(container): '''remove_uri will remove docker:// or shub:// from the uri ''' - return container.replace('docker://', '').replace('shub://', '') + return split_uri(container)[1] From fae8cbb2bd650d9dbfb7ae5868c3a9acc23eb0df Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Tue, 28 May 2019 11:01:29 +0200 Subject: [PATCH 17/19] Add tests for get_uri --- spython/tests/test_instances.py | 10 ++++++++++ spython/tests/test_oci.py | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/spython/tests/test_instances.py b/spython/tests/test_instances.py index 0fdad177..6c3d398a 100644 --- a/spython/tests/test_instances.py +++ b/spython/tests/test_instances.py @@ -24,6 +24,16 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.tmpdir) + def test_instance_class(self): + instance = self.cli.instance('docker://ubuntu', start=False) + self.assertEqual(instance.get_uri(), 'instance://' + instance.name) + self.assertNotEqual(instance.name, '') + + name = 'coolName' + instance = self.cli.instance('docker://busybox:1.30.1', start=False, name=name) + self.assertEqual(instance.get_uri(), 'instance://' + instance.name) + self.assertEqual(instance.name, name) + def test_instances(self): print('Pulling testing container') diff --git a/spython/tests/test_oci.py b/spython/tests/test_oci.py index fde551db..355ab165 100644 --- a/spython/tests/test_oci.py +++ b/spython/tests/test_oci.py @@ -40,6 +40,10 @@ def _build_sandbox(self): shutil.copyfile(self.config, '%s/config.json' %image) return image + def test_oci_image(self): + image=self.cli.oci.OciImage('oci://imagename') + self.assertEqual(image.get_uri(), '[singularity-python-oci:oci://imagename]') + def test_oci(self): image = self._build_sandbox() From 915721b89fe3cb5d5c420953b0e247e36f90d5d3 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Tue, 28 May 2019 11:04:01 +0200 Subject: [PATCH 18/19] Rename member attribute uri to protocol It did contain the protocol not the uri --- spython/image/__init__.py | 8 ++++---- spython/instance/__init__.py | 6 +++--- spython/oci/__init__.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spython/image/__init__.py b/spython/image/__init__.py index 1fa9eae2..e0643ff5 100644 --- a/spython/image/__init__.py +++ b/spython/image/__init__.py @@ -14,9 +14,9 @@ class ImageBase(object): def __str__(self): - if hasattr(self, 'uri'): - if self.uri: - return "%s://%s" %(self.uri, self.image) + protocol = getattr(self, 'protocol', None) + if protocol: + return "%s://%s" %(protocol, self.image) return self.image @@ -35,7 +35,7 @@ def parse_image_name(self, image): ''' self._image = image - self.uri, self.image = split_uri(image) + self.protocol, self.image = split_uri(image) class Image(ImageBase): diff --git a/spython/instance/__init__.py b/spython/instance/__init__.py index 1175ff02..8f888fdd 100644 --- a/spython/instance/__init__.py +++ b/spython/instance/__init__.py @@ -58,7 +58,7 @@ def parse_image_name(self, image): ''' self._image = image - self.uri = 'instance://' + self.protocol = 'instance' def get_uri(self): @@ -92,8 +92,8 @@ def _update_metadata(self, kwargs=None): def __str__(self): if hasattr(self, 'name'): - if self.uri: - return "%s%s" %(self.uri, self.name) + if self.protocol: + return "%s://%s" %(self.protocol, self.name) return os.path.basename(self._image) def __repr__(self): diff --git a/spython/oci/__init__.py b/spython/oci/__init__.py index c8747a95..6ffbcfa9 100644 --- a/spython/oci/__init__.py +++ b/spython/oci/__init__.py @@ -34,7 +34,7 @@ def __init__(self, # Will typically be None, unless used outside of Client self.container_id = container_id - self.uri = 'oci://' + self.protocol = 'oci' self.sudo = sudo # If bundle is provided, create it From a5d7b0e044fc6ec5c42ae083c2c2b70240da22fc Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Tue, 28 May 2019 11:11:03 +0200 Subject: [PATCH 19/19] Unify inspect output --- spython/main/inspect.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/spython/main/inspect.py b/spython/main/inspect.py index 6c475fa2..7b995150 100644 --- a/spython/main/inspect.py +++ b/spython/main/inspect.py @@ -52,6 +52,10 @@ def inspect(self, image=None, json=True, app=None, quiet=True): if result['return_code'] == 0: result = jsonp.loads(result['message'][0]) + # Unify output to singularity 3 format + if "version 3" not in self.version(): + result = result['data'] + # Fix up labels result = parse_labels(result) @@ -70,22 +74,12 @@ def parse_labels(result): result: the json object to parse from inspect ''' - if "data" in result: - labels = result['data']['attributes'].get('labels') or {} - - elif 'attributes' in result: - labels = result['attributes'].get('labels') or {} - - # If labels included, try parsing to json - + labels = result['attributes'].get('labels') or {} try: labels = jsonp.loads(labels) except: pass - if "data" in result: - result['data']['attributes']['labels'] = labels - else: - result['attributes']['labels'] = labels + result['attributes']['labels'] = labels return result