Extract `Job.get_call_string` logic to `utils.get_call_string` (#1499)

* Extract `Job.get_call_string` logic to `utils.get_call_string`

* Remove an outdaded comment

* Move `truncate_long_string` to `utils`

* Remove `truncate` parameter in `get_call_string`

* Add a test for `get_call_string`

* Move `truncate_long_string` to module's top level

* Add a test case for `truncate_long_string` suite
main
Adrian Sadłocha 4 years ago committed by GitHub
parent 5590aab458
commit caa4efc35b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -22,7 +22,7 @@ from .exceptions import DeserializationError, NoSuchJobError
from .local import LocalStack from .local import LocalStack
from .serializers import resolve_serializer from .serializers import resolve_serializer
from .utils import (get_version, import_attribute, parse_timeout, str_to_date, from .utils import (get_version, import_attribute, parse_timeout, str_to_date,
utcformat, utcnow, ensure_list) utcformat, utcnow, ensure_list, get_call_string)
# Serialize pickle dumps using the highest pickle protocol (binary, default # Serialize pickle dumps using the highest pickle protocol (binary, default
# uses ascii) # uses ascii)
@ -45,12 +45,6 @@ class JobStatus(str, Enum):
UNEVALUATED = object() UNEVALUATED = object()
def truncate_long_string(data, maxlen=75):
""" Truncates strings longer than maxlen
"""
return (data[:maxlen] + '...') if len(data) > maxlen else data
def cancel_job(job_id, connection=None): def cancel_job(job_id, connection=None):
"""Cancels the job with the given job ID, preventing execution. Discards """Cancels the job with the given job ID, preventing execution. Discards
any job info (i.e. it can't be requeued later). any job info (i.e. it can't be requeued later).
@ -801,17 +795,7 @@ class Job:
"""Returns a string representation of the call, formatted as a regular """Returns a string representation of the call, formatted as a regular
Python function invocation statement. Python function invocation statement.
""" """
if self.func_name is None: return get_call_string(self.func_name, self.args, self.kwargs, max_length=75)
return None
arg_list = [as_text(truncate_long_string(repr(arg))) for arg in self.args]
kwargs = ['{0}={1}'.format(k, as_text(truncate_long_string(repr(v)))) for k, v in self.kwargs.items()]
# Sort here because python 3.3 & 3.4 makes different call_string
arg_list += sorted(kwargs)
args = ', '.join(arg_list)
return '{0}({1})'.format(self.func_name, args)
def cleanup(self, ttl=None, pipeline=None, remove_from_queue=True): def cleanup(self, ttl=None, pipeline=None, remove_from_queue=True):
"""Prepare job for eventual deletion (if needed). This method is usually """Prepare job for eventual deletion (if needed). This method is usually

@ -297,3 +297,27 @@ def split_list(a_list, segment_size):
""" """
for i in range(0, len(a_list), segment_size): for i in range(0, len(a_list), segment_size):
yield a_list[i:i + segment_size] yield a_list[i:i + segment_size]
def truncate_long_string(data, max_length=None):
"""Truncate arguments with representation longer than max_length"""
if max_length is None:
return data
return (data[:max_length] + '...') if len(data) > max_length else data
def get_call_string(func_name, args, kwargs, max_length=None):
"""Returns a string representation of the call, formatted as a regular
Python function invocation statement. If max_length is not None, truncate
arguments with representation longer than max_length.
"""
if func_name is None:
return None
arg_list = [as_text(truncate_long_string(repr(arg), max_length)) for arg in args]
kwargs = ['{0}={1}'.format(k, as_text(truncate_long_string(repr(v), max_length))) for k, v in kwargs.items()]
arg_list += sorted(kwargs)
args = ', '.join(arg_list)
return '{0}({1})'.format(func_name, args)

@ -11,7 +11,7 @@ from redis import Redis
from tests import RQTestCase, fixtures from tests import RQTestCase, fixtures
from rq.utils import backend_class, ensure_list, first, get_version, is_nonstring_iterable, parse_timeout, utcparse, \ from rq.utils import backend_class, ensure_list, first, get_version, is_nonstring_iterable, parse_timeout, utcparse, \
split_list, ceildiv split_list, ceildiv, get_call_string, truncate_long_string
from rq.exceptions import TimeoutFormatError from rq.exceptions import TimeoutFormatError
@ -113,3 +113,26 @@ class TestUtils(RQTestCase):
expected_small_list_count = ceildiv(BIG_LIST_SIZE, SEGMENT_SIZE) expected_small_list_count = ceildiv(BIG_LIST_SIZE, SEGMENT_SIZE)
self.assertEqual(len(small_lists), expected_small_list_count) self.assertEqual(len(small_lists), expected_small_list_count)
def test_truncate_long_string(self):
"""Ensure truncate_long_string works properly"""
assert truncate_long_string("12", max_length=3) == "12"
assert truncate_long_string("123", max_length=3) == "123"
assert truncate_long_string("1234", max_length=3) == "123..."
assert truncate_long_string("12345", max_length=3) == "123..."
s = "long string but no max_length provided so no truncating should occur" * 10
assert truncate_long_string(s) == s
def test_get_call_string(self):
"""Ensure a case, when func_name, args and kwargs are not None, works properly"""
cs = get_call_string("f", ('some', 'args', 42), {"key1": "value1", "key2": True})
assert cs == "f('some', 'args', 42, key1='value1', key2=True)"
def test_get_call_string_with_max_length(self):
"""Ensure get_call_string works properly when max_length is provided"""
func_name = "f"
args = (1234, 12345, 123456)
kwargs = {"len4": 1234, "len5": 12345, "len6": 123456}
cs = get_call_string(func_name, args, kwargs, max_length=5)
assert cs == "f(1234, 12345, 12345..., len4=1234, len5=12345, len6=12345...)"

Loading…
Cancel
Save