Modify

Opened 11 years ago

Closed 11 years ago

#11131 closed defect (fixed)

TypeError: object of type 'NoneType' has no len()

Reported by: bill.chen Owned by: Chris Nelson
Priority: normal Component: TracJsGanttPlugin
Severity: normal Keywords:
Cc: Trac Release:

Description

How to Reproduce

While doing a POST operation on /ticket/21, Trac issued an internal error.

(please provide additional details here)

Request parameters:

{'__FORM_TOKEN': u'aec6cf6a0f6ab1bb16b6b8f5',
 'action': u'leave',
 'comment': u'',
 'field_blockedby': u'6',
 'field_blocking': u'',
 'field_cc': u'',
 'field_checkbox_billable': u'1',
 'field_complete': u'',
 'field_component': u'\u8bbe\u7f6e',
 'field_description': u'\u521b\u5efa\u8005\u53ef\u4fee\u6539\u5934\u50cf\u3001\u6635\u79f0\u3001\u8eab\u4efd\u3001\u751f\u65e5\u3001\u72b6\u6001\uff1b\u975e\u521b\u5efa\u8005\u8fd8\u53ef\u53d1\u9001\u9080\u8bf7\u3001\u9009\u62e9\u9000\u51fa\u8be5\u5c0f\u5bb6\u3002',
 'field_estimatedhours': u'',
 'field_hours': u'',
 'field_keywords': u'',
 'field_milestone': u'\u6700\u5c0f\u53ef\u4e0a\u7ebf\u7248',
 'field_parents': u'',
 'field_priority': u'major',
 'field_reporter': u'trac',
 'field_summary': u'\u7f16\u8f91\u4e2a\u4eba\u4fe1\u606f',
 'field_type': u'task',
 'field_userfinish': u'',
 'field_userstart': u'',
 'field_version': u'1.0',
 'id': u'21',
 'replyto': u'',
 'start_time': u'1369810004883288',
 'submit': u'Submit changes',
 'view_time': u'1369810004883288'}

User agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36

System Information

Trac 1.0
Docutils 0.10
Genshi 0.7 (without speedups)
MySQL server: "5.6.10", client: "5.6.10", thread-safe: 1
MySQLdb 1.2.4
Python 2.7.3 (default, Feb 16 2013, 14:25:34)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-46)]
setuptools 0.6c11
jQuery 1.7.2

Enabled Plugins

timingandestimationplugin 1.3.7
Trac-jsGantt 0.10-r12998
TracAccountManager 0.4.3
TracMasterTickets 3.0.5dev-r12950
TracSubTicketsPlugin 0.2.0.dev-20130601

Python Traceback

Traceback (most recent call last):
  File "build/bdist.linux-x86_64/egg/trac/web/main.py", line 497, in _dispatch_request
    dispatcher.dispatch(req)
  File "build/bdist.linux-x86_64/egg/trac/web/main.py", line 214, in dispatch
    resp = chosen_handler.process_request(req)
  File "build/bdist.linux-x86_64/egg/trac/ticket/web_ui.py", line 179, in process_request
    return self._process_ticket_request(req)
  File "build/bdist.linux-x86_64/egg/trac/ticket/web_ui.py", line 614, in _process_ticket_request
    self._do_save(req, ticket, action)
  File "build/bdist.linux-x86_64/egg/trac/ticket/web_ui.py", line 1328, in _do_save
    replyto=req.args.get('replyto'))
  File "build/bdist.linux-x86_64/egg/trac/ticket/model.py", line 363, in save_changes
    listener.ticket_changed(self, comment, author, old_values)
  File "build/bdist.linux-x86_64/egg/tracjsgantt/tracpm.py", line 2950, in ticket_changed
    self.rescheduleTickets(ticket, old_values)
  File "build/bdist.linux-x86_64/egg/tracjsgantt/tracpm.py", line 2738, in rescheduleTickets
    ids = self._findAffected(ticket, old_values)
  File "build/bdist.linux-x86_64/egg/tracjsgantt/tracpm.py", line 2426, in _findAffected
    affected |= affectedByOld(old_values)
  File "build/bdist.linux-x86_64/egg/tracjsgantt/tracpm.py", line 2359, in affectedByOld
    and len(old_values['parents']) != 0:
TypeError: object of type 'NoneType' has no len()

Attachments (0)

Change History (9)

comment:1 Changed 11 years ago by Jun Omae

Component: SELECT A HACKTracJsGanttPlugin
Owner: changed from anonymous to Chris Nelson

comment:2 Changed 11 years ago by floriansiggel@…

I had the same problem and wrote a quick fix for it. (Working on Solaris10, 64bit Python 2.6) Additionally there was a syntax problem with some SQL queries which I also corrected.

I cannot attach a patch file, thus copy the following part into a file tracpm.patch and run the a command like "patch < tracpm.patch" in the directory containing the tracpm.py file


tracpm.patch:

2358,2359c2358
<             if 'parents' in old_values.keys() \
<                     and len(old_values['parents']) != 0:
---
>             if 'parents' in old_values.keys() and old_values['parents'] != None and len(old_values['parents']) != 0:
2361,2362c2360
<             if 'blockedby' in old_values.keys() \
<                     and len(old_values['blockedby']) != 0:
---
>             if 'blockedby' in old_values.keys() and old_values['blockedby'] != None and len(old_values['blockedby']) != 0:
2366,2367c2364
<             if 'blocking' in old_values.keys() \
<                     and len(old_values['blocking']) != 0:
---
>             if 'blocking' in old_values.keys() and old_values['blocking'] != None and len(old_values['blocking']) != 0:
2900d2896
<                     valuesClause = ','.join(('(%s,%s,%s)',) * len(toInsert))
2904,2911c2900,2902
<                             values.append(t['id']) 
<                             values.append(to_utimestamp(self.pm.start(t)))
<                             values.append(to_utimestamp(self.pm.finish(t)))
<                     cursor.execute('INSERT INTO schedule' + \
<                                        ' (ticket, start, finish)' + \
<                                        ' VALUES %s' % valuesClause,
<                                    values)
< 
---
>                             values.append((t['id'], to_utimestamp(self.pm.start(t)), to_utimestamp(self.pm.finish(t)))) 
>                     query = 'INSERT INTO schedule (ticket, start, finish) VALUES (%s,%s,%s)'
>                     cursor.executemany(query, values)
2919,2928c2910,2912
<                             values.append(t['id'])
<                             values.append(to_utimestamp(dbTime))
<                             # Old start and finish are null
<                             values.append(to_utimestamp(self.pm.start(t)))
<                             values.append(to_utimestamp(self.pm.finish(t)))
<                     cursor.execute('INSERT INTO schedule_change' + \
<                                        ' (ticket, time,' + \
<                                        ' newstart, newfinish)' + \
<                                        ' VALUES %s' % valuesClause,
<                                    values)
---
>                             values.append((t['id'], to_utimestamp(dbTime), to_utimestamp(self.pm.start(t)), to_utimestamp(self.pm.finish(t))))
>                     query = 'INSERT INTO schedule_change (ticket, time, newstart, newfinish) VALUES (%s,%s,%s,%s)'
>                     cursor.executemany(query, values)

comment:3 Changed 11 years ago by trenb@…

I've had the same issue as the original reporter. However his patch must be Solaris specific. I've attached a patch I made on Linux.

--- tracpm.py.orig	2013-07-18 11:54:24.586803161 -0700
+++ tracpm.py	2013-07-18 12:05:49.658801814 -0700
@@ -2355,16 +2355,13 @@
         def affectedByOld(old_values):
             affected = set()

-            if 'parents' in old_values.keys() \
-                    and len(old_values['parents']) != 0:
+            if 'parents' in old_values.keys() and old_values['parents'] != None and len(old_values['parents']) != 0:
                 affected.add(str(old_values['parents']))
-            if 'blockedby' in old_values.keys() \
-                    and len(old_values['blockedby']) != 0:
+            if 'blockedby' in old_values.keys() and old_values['blockedby'] != None and len(old_values['blockedby']) != 0:
                 affected |= \
                     set([x.strip()
                          for x in old_values['blockedby'].split(',')])
-            if 'blocking' in old_values.keys() \
-                    and len(old_values['blocking']) != 0:
+            if 'blocking' in old_values.keys() and old_values['blocking'] != None and len(old_values['blocking']) != 0:
                 affected |= \
                     set([x.strip()
                          for x in old_values['blocking'].split(',')])
@@ -2901,13 +2898,9 @@
                     values = []
                     for t in tickets:
                         if t['id'] in toInsert:
-                            values.append(t['id'])
-                            values.append(to_utimestamp(self.pm.start(t)))
-                            values.append(to_utimestamp(self.pm.finish(t)))
-                    cursor.execute('INSERT INTO schedule' + \
-                                       ' (ticket, start, finish)' + \
-                                       ' VALUES %s' % valuesClause,
-                                   values)
+                            values.append((t['id'], to_utimestamp(self.pm.start(t)), to_utimestamp(self.pm.finish(t))))
+                    query = 'INSERT INTO schedule (ticket, start, finish) VALUES (%s,%s,%s)'
+                    cursor.executemany(query, values)


                     # Finally, add history records to schedule_change
@@ -2916,16 +2909,9 @@
                     values = []
                     for t in tickets:
                         if t['id'] in toInsert:
-                            values.append(t['id'])
-                            values.append(to_utimestamp(dbTime))
-                            # Old start and finish are null
-                            values.append(to_utimestamp(self.pm.start(t)))
-                            values.append(to_utimestamp(self.pm.finish(t)))
-                    cursor.execute('INSERT INTO schedule_change' + \
-                                       ' (ticket, time,' + \
-                                       ' newstart, newfinish)' + \
-                                       ' VALUES %s' % valuesClause,
-                                   values)
+                            values.append((t['id'], to_utimestamp(dbTime), to_utimestamp(self.pm.start(t)), to_utimestamp(self.pm.finish(t))))
+                    query = 'INSERT INTO schedule_change (ticket, time, newstart, newfinish) VALUES (%s,%s,%s,%s)'
+                    cursor.executemany(query, values)

                 end = datetime.now()
                 profile.append([ 'inserting', len(toInsert), end - start ])

Thank you to the original poster for the fix to this issue!

Version 0, edited 11 years ago by trenb@… (next)

comment:4 Changed 11 years ago by Jay

I also just recently started having this. Adding the scenario to potentially help the author understand the issue. I was orginally using the plugin with SubticketsPlugin and TimingAndEstimationPlugin plugins. At a later point, I added MasterTicketsPlugin for dependecy support, and this started happening. I assume the plugin sees dependency checking is enabled, and assumes every ticket has an entry, in my case, old tickets do not.

Related, dependent tickets seem to inherit the priority of the "blockedby" ticket in the resource balancing, regardless of the ticket priority, or that of its parent ticket, if it has !one, but I suspect that is a different quirk.

comment:5 Changed 11 years ago by Chris Nelson

I'm not familiar with executemany(). Can someone explain the point of that change?

comment:6 Changed 11 years ago by Ryan J Ollos

Not sure I can help much, but using executemany was also suggested in comment:9:ticket:11027.

comment:7 in reply to:  6 Changed 11 years ago by Chris Nelson

Replying to rjollos:

Not sure I can help much, but using executemany was also suggested in comment:9:ticket:11027.

http://www.python.org/dev/peps/pep-0249/ seems to be relevant. I tend to agree that this is clearer. I have to look to see how much trouble it is to convert (i.e., how many places I do this).

comment:8 Changed 11 years ago by Chris Nelson

Status: newassigned

The len() issue was addressed in r13360 (not sure why that didn't link here, maybe I forgot the Refs).

The executemany() idiom is addressed in #11287.

comment:9 Changed 11 years ago by Chris Nelson

Resolution: fixed
Status: assignedclosed

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Chris Nelson.
The resolution will be deleted. Next status will be 'reopened'.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.