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
1 change: 0 additions & 1 deletion reframe/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import tempfile

import reframe
import reframe.core.debug as debug
import reframe.core.fields as fields
import reframe.core.settings as settings
import reframe.utility as util
Expand Down
62 changes: 0 additions & 62 deletions reframe/core/debug.py

This file was deleted.

7 changes: 0 additions & 7 deletions reframe/core/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import reframe
import reframe.utility.color as color
import reframe.core.debug as debug
import reframe.utility.os_ext as os_ext
from reframe.core.exceptions import ConfigError, LoggingError

Expand Down Expand Up @@ -333,9 +332,6 @@ def __init__(self, name, level=logging.NOTSET):
super().__init__(name, logging.NOTSET)
self.level = _check_level(level)

def __repr__(self):
return debug.repr(self)

def setLevel(self, level):
self.level = _check_level(level)

Expand Down Expand Up @@ -405,9 +401,6 @@ def __init__(self, logger=None, check=None):
self.check = check
self.colorize = False

def __repr__(self):
return debug.repr(self)

def setLevel(self, level):
if self.logger:
super().setLevel(level)
Expand Down
7 changes: 0 additions & 7 deletions reframe/frontend/executors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import time
import weakref

import reframe.core.debug as debug
import reframe.core.environments as env
import reframe.core.logging as logging
import reframe.core.runtime as runtime
Expand Down Expand Up @@ -350,9 +349,6 @@ def __init__(self, policy, printer=None, max_retries=0):
self._policy.printer = self._printer
signal.signal(signal.SIGTERM, _handle_sigterm)

def __repr__(self):
return debug.repr(self)

@property
def max_retries(self):
return self._max_retries
Expand Down Expand Up @@ -465,9 +461,6 @@ def __init__(self):
self.task_listeners = []
self.stats = None

def __repr__(self):
return debug.repr(self)

def enter(self):
pass

Expand Down
4 changes: 0 additions & 4 deletions reframe/frontend/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import collections
import os

import reframe.core.debug as debug
import reframe.utility as util
import reframe.utility.os_ext as os_ext
from reframe.core.exceptions import NameConflictError, RegressionTestLoadError
Expand Down Expand Up @@ -48,9 +47,6 @@ def __init__(self, load_path, recurse=False, ignore_conflicts=False):
# Loaded tests by name; maps test names to the file that were defined
self._loaded = {}

def __repr__(self):
return debug.repr(self)

def _module_name(self, filename):
'''Figure out a module name from filename.

Expand Down
4 changes: 0 additions & 4 deletions reframe/frontend/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#
# SPDX-License-Identifier: BSD-3-Clause

import reframe.core.debug as debug
import reframe.core.runtime as rt
from reframe.core.exceptions import StatisticsError

Expand All @@ -15,9 +14,6 @@ def __init__(self):
# Tasks per run stored as follows: [[run0_tasks], [run1_tasks], ...]
self._tasks = [[]]

def __repr__(self):
return debug.repr(self)

def add_task(self, task):
current_run = rt.runtime().current_run
if current_run == len(self._tasks):
Expand Down
65 changes: 51 additions & 14 deletions reframe/utility/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#
# SPDX-License-Identifier: BSD-3-Clause

import builtins
import collections
import functools
import importlib
Expand Down Expand Up @@ -126,7 +127,8 @@ def toalphanum(s):
return re.sub(r'\W', '_', s)


def ppretty(value, htchar=' ', lfchar='\n', indent=4, basic_offset=0):
def ppretty(value, htchar=' ', lfchar='\n', indent=4, basic_offset=0,
repr=builtins.repr):
'''Format string of dictionaries, lists and tuples

:arg value: The value to be formatted.
Expand All @@ -135,26 +137,30 @@ def ppretty(value, htchar=' ', lfchar='\n', indent=4, basic_offset=0):
:arg indent: Number of htchar characters for every indentation level.
:arg basic_offset: Basic offset for the representation, any additional
indentation space is added to the ``basic_offset``.
:arg repr: The :func:`repr` to use for printing values. This function may
accept also all the arguments of :func:`ppretty` except the ``repr``.

:returns: a formatted string of the ``value``.
'''

ppretty2 = functools.partial(
ppretty, htchar=htchar, lfchar=lfchar, indent=indent,
basic_offset=basic_offset+1, repr=repr
)
nlch = lfchar + htchar * indent * (basic_offset + 1)
if isinstance(value, tuple):
if value == ():
return '()'

items = [
nlch + ppretty(item, htchar, lfchar, indent, basic_offset + 1)
for item in value
]
items = [nlch + ppretty2(item) for item in value]
return '(%s)' % (','.join(items) + lfchar +
htchar * indent * basic_offset)
elif isinstance(value, list):
if value == []:
return '[]'

items = [
nlch + ppretty(item, htchar, lfchar, indent, basic_offset + 1)
nlch + ppretty2(item)
for item in value
]
return '[%s]' % (','.join(items) + lfchar +
Expand All @@ -164,24 +170,55 @@ def ppretty(value, htchar=' ', lfchar='\n', indent=4, basic_offset=0):
return '{}'

items = [
nlch + repr(key) + ': ' +
ppretty(value[key], htchar, lfchar, indent, basic_offset + 1)
for key in value
nlch + repr(key) + ': ' + ppretty2(value[key]) for key in value
]
return '{%s}' % (','.join(items) + lfchar +
htchar * indent * basic_offset)
elif isinstance(value, set):
if value == set():
return 'set()'

items = [
nlch + ppretty(item, htchar, lfchar, indent, basic_offset + 1)
for item in value
]
items = [nlch + ppretty2(item) for item in value]
return '{%s}' % (','.join(items) + lfchar +
htchar * indent * basic_offset)
else:
return repr(value)
try:
return repr(value, htchar, lfchar, indent, basic_offset)
except TypeError:
# Not our custom repr()
return repr(value)


def _tracked_repr(func):
objects = set()

@functools.wraps(func)
def _repr(obj, *args, **kwargs):
addr = id(obj)
if addr in objects:
return f'{type(obj).__name__}(...)@{hex(addr)}'

# Do not track builtin objects
if hasattr(obj, '__dict__'):
objects.add(addr)

return func(obj, *args, **kwargs)

return _repr


@_tracked_repr
def repr(obj, htchar=' ', lfchar='\n', indent=4, basic_offset=0):
'''A debug repr() function printing all object attributes recursively'''
if (isinstance(obj, list) or isinstance(obj, tuple) or
isinstance(obj, set) or isinstance(obj, dict)):
return ppretty(obj, basic_offset=basic_offset, repr=repr)

if not hasattr(obj, '__dict__'):
return builtins.repr(obj)

r = ppretty(obj.__dict__, htchar, lfchar, indent, basic_offset, repr)
return f'{type(obj).__name__}({r})@{hex(id(obj))}'


class ScopedDict(UserDict):
Expand Down
5 changes: 5 additions & 0 deletions unittests/test_policies.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import reframe.frontend.dependency as dependency
import reframe.frontend.executors as executors
import reframe.frontend.executors.policies as policies
import reframe.utility as util
import reframe.utility.os_ext as os_ext
from reframe.core.exceptions import (JobNotStartedError,
ReframeForceExitError,
Expand Down Expand Up @@ -524,6 +525,10 @@ def test_kbd_interrupt_in_wait_with_limited_concurrency(
KeyboardInterruptCheck(), SleepCheck(10),
SleepCheck(10), SleepCheck(10)
]))
# FIXME: Dump everything in case Github #1369 appears
print(util.repr(runner))
print(runner.stats.failure_report())
print(util.repr(rt.runtime().site_config))

assert_interrupted_run(runner)

Expand Down
69 changes: 34 additions & 35 deletions unittests/test_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import unittest

import reframe
import reframe.core.debug as debug
import reframe.core.fields as fields
import reframe.utility as util
import reframe.utility.os_ext as os_ext
Expand Down Expand Up @@ -420,40 +419,6 @@ def test_load_namespace_package(self):
assert 'unittests.resources' in sys.modules


class TestDebugRepr(unittest.TestCase):
def test_builtin_types(self):
# builtin types must use the default repr()
assert repr(1) == debug.repr(1)
assert repr(1.2) == debug.repr(1.2)
assert repr([1, 2, 3]) == debug.repr([1, 2, 3])
assert repr({1, 2, 3}) == debug.repr({1, 2, 3})
assert repr({1, 2, 3}) == debug.repr({1, 2, 3})
assert repr({'a': 1, 'b': {2, 3}}) == debug.repr({'a': 1, 'b': {2, 3}})

def test_obj_repr(self):
class C:
def __repr__(self):
return debug.repr(self)

class D:
def __repr__(self):
return debug.repr(self)

c = C()
c._a = -1
c.a = 1
c.b = {1, 2, 3}
c.d = D()
c.d.a = 2
c.d.b = 3

rep = repr(c)
assert 'unittests.test_utility' in rep
assert '_a=%r' % c._a in rep
assert 'b=%r' % c.b in rep
assert 'D(...)' in rep


class TestPpretty:
def test_simple_types(self):
assert util.ppretty(1) == repr(1)
Expand Down Expand Up @@ -542,6 +507,40 @@ def __repr__(self):
"]")


class _X:
def __init__(self):
self._a = False


class _Y:
def __init__(self, x, a=None):
self.x = x
self.y = 'foo'
self.z = self
self.a = a


def test_repr_default():
c0, c1 = _Y(1), _Y(2, _X())
s = util.repr([c0, c1])
assert s == f'''[
_Y({{
'x': 1,
'y': 'foo',
'z': _Y(...)@{hex(id(c0))},
'a': None
}})@{hex(id(c0))},
_Y({{
'x': 2,
'y': 'foo',
'z': _Y(...)@{hex(id(c1))},
'a': _X({{
'_a': False
}})@{hex(id(c1.a))}
}})@{hex(id(c1))}
]'''


class TestChangeDirCtxManager(unittest.TestCase):
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
Expand Down