From 8de87e04fec511c32dc2baa76117ce37b490fab6 Mon Sep 17 00:00:00 2001 From: Friday Date: Wed, 18 Feb 2026 05:59:53 +0000 Subject: [PATCH] Fix TypeError in repr when unit is None and interval is 1 Job.__repr__ crashes with `TypeError: 'NoneType' object is not subscriptable` when called on a partially-composed Job with interval=1, because `self.unit[:-1]` is attempted on None. Guard self.unit against None before slicing. Fixes #646. Co-Authored-By: Claude Opus 4.6 --- schedule/__init__.py | 9 +++++++-- test_schedule.py | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/schedule/__init__.py b/schedule/__init__.py index 8e12eeb7..2e3ddd5c 100644 --- a/schedule/__init__.py +++ b/schedule/__init__.py @@ -299,10 +299,15 @@ def is_repr(j): else: call_repr = "[None]" + if self.unit is not None: + unit = self.unit[:-1] if self.interval == 1 else self.unit + else: + unit = "[None]" + if self.at_time is not None: return "Every %s %s at %s do %s %s" % ( self.interval, - self.unit[:-1] if self.interval == 1 else self.unit, + unit, self.at_time, call_repr, timestats, @@ -317,7 +322,7 @@ def is_repr(j): return fmt % dict( interval=self.interval, latest=self.latest, - unit=(self.unit[:-1] if self.interval == 1 else self.unit), + unit=unit, call_repr=call_repr, timestats=timestats, ) diff --git a/test_schedule.py b/test_schedule.py index f497826d..0a742a39 100644 --- a/test_schedule.py +++ b/test_schedule.py @@ -1358,7 +1358,11 @@ def job_fun(): # Ensure Job.__repr__ does not throw exception on a partially-composed Job s3 = repr(schedule.every(10)) - assert s3 == "Every 10 None do [None] (last run: [never], next run: [never])" + assert s3 == "Every 10 [None] do [None] (last run: [never], next run: [never])" + + # Ensure repr does not crash when interval is 1 and unit is None + s4 = repr(schedule.every(1)) + assert s4 == "Every 1 [None] do [None] (last run: [never], next run: [never])" def test_to_string_lambda_job_func(self): assert len(str(every().minute.do(lambda: 1))) > 1