Modify

Opened 12 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 12 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

    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 years ago by Ryan J Ollos (previous) (diff)

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.