Modify

#11131 closed defect (fixed)

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

Reported by: bill.chen Owned by: ChrisNelson
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 14 months ago by jun66j5

  • Component changed from SELECT A HACK to TracJsGanttPlugin
  • Owner set to ChrisNelson

comment:2 Changed 13 months 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 13 months 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

    old new  
    23552355        def affectedByOld(old_values): 
    23562356            affected = set() 
    23572357 
    2358             if 'parents' in old_values.keys() \ 
    2359                     and len(old_values['parents']) != 0: 
     2358            if 'parents' in old_values.keys() and old_values['parents'] != None and len(old_values['parents']) != 0: 
    23602359                affected.add(str(old_values['parents'])) 
    2361             if 'blockedby' in old_values.keys() \ 
    2362                     and len(old_values['blockedby']) != 0: 
     2360            if 'blockedby' in old_values.keys() and old_values['blockedby'] != None and len(old_values['blockedby']) != 0: 
    23632361                affected |= \ 
    23642362                    set([x.strip() 
    23652363                         for x in old_values['blockedby'].split(',')]) 
    2366             if 'blocking' in old_values.keys() \ 
    2367                     and len(old_values['blocking']) != 0: 
     2364            if 'blocking' in old_values.keys() and old_values['blocking'] != None and len(old_values['blocking']) != 0: 
    23682365                affected |= \ 
    23692366                    set([x.strip() 
    23702367                         for x in old_values['blocking'].split(',')]) 
     
    29012898                    values = [] 
    29022899                    for t in tickets: 
    29032900                        if t['id'] in toInsert: 
    2904                             values.append(t['id']) 
    2905                             values.append(to_utimestamp(self.pm.start(t))) 
    2906                             values.append(to_utimestamp(self.pm.finish(t))) 
    2907                     cursor.execute('INSERT INTO schedule' + \ 
    2908                                        ' (ticket, start, finish)' + \ 
    2909                                        ' VALUES %s' % valuesClause, 
    2910                                    values) 
     2901                            values.append((t['id'], to_utimestamp(self.pm.start(t)), to_utimestamp(self.pm.finish(t)))) 
     2902                    query = 'INSERT INTO schedule (ticket, start, finish) VALUES (%s,%s,%s)' 
     2903                    cursor.executemany(query, values) 
    29112904 
    29122905 
    29132906                    # Finally, add history records to schedule_change 
     
    29162909                    values = [] 
    29172910                    for t in tickets: 
    29182911                        if t['id'] in toInsert: 
    2919                             values.append(t['id']) 
    2920                             values.append(to_utimestamp(dbTime)) 
    2921                             # Old start and finish are null 
    2922                             values.append(to_utimestamp(self.pm.start(t))) 
    2923                             values.append(to_utimestamp(self.pm.finish(t))) 
    2924                     cursor.execute('INSERT INTO schedule_change' + \ 
    2925                                        ' (ticket, time,' + \ 
    2926                                        ' newstart, newfinish)' + \ 
    2927                                        ' VALUES %s' % valuesClause, 
    2928                                    values) 
     2912                            values.append((t['id'], to_utimestamp(dbTime), to_utimestamp(self.pm.start(t)), to_utimestamp(self.pm.finish(t)))) 
     2913                    query = 'INSERT INTO schedule_change (ticket, time, newstart, newfinish) VALUES (%s,%s,%s,%s)' 
     2914                    cursor.executemany(query, values) 
    29292915 
    29302916                end = datetime.now() 
    29312917                profile.append([ 'inserting', len(toInsert), end - start ]) 

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

Last edited 11 months ago by rjollos (previous) (diff)

comment:4 Changed 13 months ago by Yoheeb <yoheeb@…>

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 months ago by ChrisNelson

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

comment:6 follow-up: Changed 11 months ago by rjollos

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 months ago by ChrisNelson

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 months ago by ChrisNelson

  • Status changed from new to assigned

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 months ago by ChrisNelson

  • Resolution set to fixed
  • Status changed from assigned to closed

Add Comment

Modify Ticket

Action
as closed .
as The resolution will be set. Next status will be 'closed'.
to The owner will be changed from ChrisNelson. Next status will be 'closed'.
The resolution will be deleted. Next status will be 'reopened'.
Author


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

 
Note: See TracTickets for help on using tickets.