Skip to content

Commit 5b3c000

Browse files
committed
issue2551126 - AttributeError: 'str' object has no attribute 'local'.
Fix traceback caused by DateHTMLProperty.pretty() called on a string value due to error in some other field.
1 parent 7e95548 commit 5b3c000

File tree

3 files changed

+54
-6
lines changed

3 files changed

+54
-6
lines changed

CHANGES.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ Fixed:
7676
- Call verifyPassword even if user does not exist. Address timing
7777
attack to discover valid account names. Useful where anonymous user
7878
is not allowed access. (John Rouillard)
79+
- issue2551126 - AttributeError: 'str' object has no attribute
80+
'local'. Fix traceback caused by DateHTMLProperty.pretty() called
81+
on a string value due to error in some other field. (Reported by
82+
reda, fix: John Rouillard)
7983

8084
Features:
8185
- issue2550522 - Add 'filter' command to command-line

roundup/cgi/templating.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2244,12 +2244,16 @@ def pretty(self, format=_marker):
22442244
else:
22452245
offset = self._offset
22462246

2247-
if not self._value:
2248-
return ''
2249-
elif format is not self._marker:
2250-
return self._value.local(offset).pretty(format)
2251-
else:
2252-
return self._value.local(offset).pretty()
2247+
try:
2248+
if not self._value:
2249+
return ''
2250+
elif format is not self._marker:
2251+
return self._value.local(offset).pretty(format)
2252+
else:
2253+
return self._value.local(offset).pretty()
2254+
except AttributeError:
2255+
# not a date value, e.g. from unsaved form data
2256+
return str(self._value)
22532257

22542258
def local(self, offset):
22552259
""" Return the date/time as a local (timezone offset) date/time.

test/test_templating.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,46 @@ def test_input_xhtml(self):
474474
input=input_xhtml(**attrs)
475475
self.assertEqual(input, '<input class="required" disabled="disabled" size="30" type="text"/>')
476476

477+
478+
class HTMLPropertyTestClass(unittest.TestCase):
479+
def setUp(self):
480+
self.form = FieldStorage()
481+
self.client = MockNull()
482+
self.client.db = db = MockDatabase()
483+
db.security.hasPermission = lambda *args, **kw: True
484+
self.client.form = self.form
485+
486+
self.client._props = MockNull()
487+
# add client props for testing anti_csrf_nonce
488+
self.client.session_api = MockNull(_sid="1234567890")
489+
self.client.db.getuid = lambda : 10
490+
491+
class DateHTMLPropertyTestCase(HTMLPropertyTestClass):
492+
493+
def test_DateHTMLWithText(self):
494+
"""Test methods when DateHTMLProperty._value is a string
495+
rather than a hyperdb.Date()
496+
"""
497+
test_datestring = "2021-01-01 11:22:10"
498+
test_date = hyperdb.Date("2")
499+
500+
self.form.list.append(MiniFieldStorage("test1@test", test_datestring))
501+
self.client._props=test_date
502+
503+
self.client.db.classes = dict \
504+
( test = MockNull(getprops = lambda : test_date)
505+
)
506+
507+
# client, classname, nodeid, prop, name, value,
508+
# anonymous=0, offset=None
509+
d = DateHTMLProperty(self.client, 'test', '1', self.client._props,
510+
'test', '')
511+
self.assertIs(type(d._value), str)
512+
self.assertEqual(d.pretty(), "2021-01-01 11:22:10")
513+
self.assertEqual(d.plain(), "2021-01-01 11:22:10")
514+
input = """<input name="test1@test" size="30" type="text" value="2021-01-01 11:22:10"><a class="classhelp" data-calurl="test?@template=calendar&amp;amp;property=test&amp;amp;form=itemSynopsis&amp;date=2021-01-01 11:22:10" data-height="200" data-width="300" href="javascript:help_window('test?@template=calendar&amp;property=test&amp;form=itemSynopsis&date=2021-01-01 11:22:10', 300, 200)">(cal)</a>"""
515+
self.assertEqual(d.field(), input)
516+
477517
# common markdown test cases
478518
class MarkdownTests:
479519
def mangleMarkdown2(self, s):

0 commit comments

Comments
 (0)