Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion easybuild/base/generaloption.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

from easybuild.base.fancylogger import getLogger, setroot, setLogLevel, getDetailsLogLevels
from easybuild.base.optcomplete import autocomplete, CompleterOption
from easybuild.tools.asyncprocess import subprocess_popen_text
from easybuild.tools.run import subprocess_popen_text
from easybuild.tools.utilities import mk_md_table, mk_rst_table, nub, shell_quote

try:
Expand Down
18 changes: 0 additions & 18 deletions easybuild/tools/asyncprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,24 +152,6 @@ def _recv(self, which, maxsize):
message = "Other end disconnected!"


def subprocess_popen_text(cmd, **kwargs):
"""Call subprocess.Popen in text mode with specified named arguments."""
# open stdout/stderr in text mode in Popen when using Python 3
kwargs.setdefault('stderr', subprocess.PIPE)
return subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True, **kwargs)


def subprocess_terminate(proc, timeout):
"""Terminate the subprocess if it hasn't finished after the given timeout"""
try:
proc.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
for pipe in (proc.stdout, proc.stderr, proc.stdin):
if pipe:
pipe.close()
proc.terminate()


def recv_some(p, t=.2, e=1, tr=5, stderr=0):
if tr < 1:
tr = 1
Expand Down
3 changes: 1 addition & 2 deletions easybuild/tools/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,14 @@

from easybuild.base import fancylogger
from easybuild.tools import StrictVersion
from easybuild.tools.asyncprocess import subprocess_popen_text
from easybuild.tools.build_log import EasyBuildError, print_warning
from easybuild.tools.config import ERROR, IGNORE, PURGE, UNLOAD, UNSET
from easybuild.tools.config import EBROOT_ENV_VAR_ACTIONS, LOADED_MODULES_ACTIONS
from easybuild.tools.config import build_option, get_modules_tool, install_path
from easybuild.tools.environment import ORIG_OS_ENVIRON, restore_env, setvar, unset_env_vars
from easybuild.tools.filetools import convert_name, mkdir, normalize_path, path_matches, read_file, which, write_file
from easybuild.tools.module_naming_scheme.mns import DEVEL_MODULE_SUFFIX
from easybuild.tools.run import run_cmd
from easybuild.tools.run import run_cmd, subprocess_popen_text
from easybuild.tools.utilities import get_subclasses, nub

# software root/version environment variable name prefixes
Expand Down
29 changes: 24 additions & 5 deletions easybuild/tools/py2vs3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@
# You should have received a copy of the GNU General Public License
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
#
import sys

from easybuild.base import fancylogger

from easybuild.base.wrapper import create_base_metaclass # noqa

# all functionality provided by the py3 modules is made available via the easybuild.tools.py2vs3 namespace
from easybuild.tools.py2vs3.py3 import * # noqa

Expand All @@ -33,8 +36,24 @@
_log.deprecated("Using py2vs3 is deprecated, since EasyBuild no longer runs on Python 2.", '6.0')


# based on six's 'with_metaclass' function
# see also https://stackoverflow.com/questions/18513821/python-metaclass-understanding-the-with-metaclass
def create_base_metaclass(base_class_name, metaclass, *bases):
"""Create new class with specified metaclass based on specified base class(es)."""
return metaclass(base_class_name, bases, {})
def python2_is_deprecated():
"""
Print warning when using Python 2, since the support for running EasyBuild with it is deprecated.
"""
if sys.version_info[0] == 2:
full_py_ver = '.'.join(str(x) for x in sys.version_info[:3])
warning_lines = [
"Running EasyBuild with Python v2.x is deprecated, found Python v%s." % full_py_ver,
"Support for running EasyBuild with Python v2.x will be removed in EasyBuild v5.0.",
'',
"It is strongly recommended to start using Python v3.x for running EasyBuild,",
"see https://docs.easybuild.io/en/latest/Python-2-3-compatibility.html for more information.",
]
max_len = max(len(x) for x in warning_lines)
for i in range(len(warning_lines)):
line_len = len(warning_lines[i])
warning_lines[i] = '!!! ' + warning_lines[i] + ' ' * (max_len - line_len) + ' !!!'
max_len = max(len(x) for x in warning_lines)
warning_lines.insert(0, '!' * max_len)
warning_lines.append('!' * max_len)
sys.stderr.write('\n\n' + '\n'.join(warning_lines) + '\n\n\n')
33 changes: 3 additions & 30 deletions easybuild/tools/py2vs3/py3.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
# these are not used here, but imported from here in other places
import configparser # noqa
import json
import subprocess
import sys
import urllib.request as std_urllib # noqa
from collections import OrderedDict # noqa
Expand All @@ -59,6 +58,9 @@
except ImportError:
HAVE_DISTUTILS = False

from easybuild.base.wrapper import mk_wrapper_baseclass # noqa
from easybuild.tools.run import subprocess_popen_text, subprocess_terminate # noqa

# string type that can be used in 'isinstance' calls
string_type = str

Expand All @@ -75,24 +77,6 @@ def json_loads(body):
return json.loads(body)


def subprocess_popen_text(cmd, **kwargs):
"""Call subprocess.Popen in text mode with specified named arguments."""
# open stdout/stderr in text mode in Popen when using Python 3
kwargs.setdefault('stderr', subprocess.PIPE)
return subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True, **kwargs)


def subprocess_terminate(proc, timeout):
"""Terminate the subprocess if it hasn't finished after the given timeout"""
try:
proc.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
for pipe in (proc.stdout, proc.stderr, proc.stdin):
if pipe:
pipe.close()
proc.terminate()


def raise_with_traceback(exception_class, message, traceback):
"""Raise exception of specified class with given message and traceback."""
raise exception_class(message).with_traceback(traceback)
Expand All @@ -103,17 +87,6 @@ def extract_method_name(method_func):
return '_'.join(method_func.__code__.co_names)


def mk_wrapper_baseclass(metaclass):

class WrapperBase(object, metaclass=metaclass):
"""
Wrapper class that provides proxy access to an instance of some internal instance.
"""
__wraps__ = None

return WrapperBase


def safe_cmp_looseversions(v1, v2):
"""Safe comparison function for two (values containing) LooseVersion instances."""

Expand Down
18 changes: 18 additions & 0 deletions easybuild/tools/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -769,3 +769,21 @@ def check_log_for_errors(log_txt, reg_exps):
if errors:
raise EasyBuildError("Found %s error(s) in command output (output: %s)",
len(errors), "\n\t".join(errors))


def subprocess_popen_text(cmd, **kwargs):
"""Call subprocess.Popen in text mode with specified named arguments."""
# open stdout/stderr in text mode in Popen when using Python 3
kwargs.setdefault('stderr', subprocess.PIPE)
return subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True, **kwargs)


def subprocess_terminate(proc, timeout):
"""Terminate the subprocess if it hasn't finished after the given timeout"""
try:
proc.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
for pipe in (proc.stdout, proc.stderr, proc.stdin):
if pipe:
pipe.close()
proc.terminate()
2 changes: 1 addition & 1 deletion easybuild/tools/systemtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
from collections import OrderedDict
from ctypes.util import find_library
from socket import gethostname
from easybuild.tools.asyncprocess import subprocess_popen_text
from easybuild.tools.run import subprocess_popen_text

# pkg_resources is provided by the setuptools Python package,
# which we really want to keep as an *optional* dependency
Expand Down
3 changes: 2 additions & 1 deletion test/framework/asyncprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
from unittest import TextTestRunner

import easybuild.tools.asyncprocess as p
from easybuild.tools.asyncprocess import Popen, subprocess_terminate
from easybuild.tools.asyncprocess import Popen
from easybuild.tools.run import subprocess_terminate


class AsyncProcessTest(EnhancedTestCase):
Expand Down
3 changes: 1 addition & 2 deletions test/framework/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@

import easybuild.tools.asyncprocess as asyncprocess
import easybuild.tools.utilities
from easybuild.tools.asyncprocess import subprocess_terminate
from easybuild.tools.build_log import EasyBuildError, init_logging, stop_logging
from easybuild.tools.filetools import adjust_permissions, read_file, write_file
from easybuild.tools.run import check_async_cmd, check_log_for_errors, complete_cmd, get_output_from_process
from easybuild.tools.run import parse_log_for_error, run_cmd, run_cmd_qa
from easybuild.tools.run import parse_log_for_error, run_cmd, run_cmd_qa, subprocess_terminate
from easybuild.tools.config import ERROR, IGNORE, WARN


Expand Down