GTG

Merge lp:~jml/gtg/better-lint-checking into lp:~gtg/gtg/old-trunk

Proposed by Jonathan Lange
Status: Merged
Merged at revision: not available
Proposed branch: lp:~jml/gtg/better-lint-checking
Merge into: lp:~gtg/gtg/old-trunk
Diff against target: None lines
To merge this branch: bzr merge lp:~jml/gtg/better-lint-checking
Reviewer Review Type Date Requested Status
Gtg developers Pending
Review via email: mp+8680@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

This branch tries to improve both the way that lint checking is done and also how well we do at those lint checks.

Most of the size of the branch is made up from adding pep8.py to scripts. It's an MIT licensed script, and should be OK to distribute with this GPLv3 app.

The next biggest change is making dbuswrapper use 4 space indentation, like every other Python module in the known universe :)

Another interesting change is removing the '_' hack to __builtins__ and instead requiring scripts to import _ from GTG. This change, together with removal of '*' imports and a few other tweaks means that pyflakes returns a clean bill of health. Note that * imports make pyflakes less useful, since with them it can't detect unrecognized names.

I've also got rid of some tabs and replaced them with spaces.

The most interesting change is that 'make lint' now runs pyflakes and pep8 checks on the code base. Although I've updated codecheck.sh so that the sillier warnings are now disabled, I think that 'make lint' should become the standard way of doing a lint check.

lp:~jml/gtg/better-lint-checking updated
278. By Jonathan Lange

Remove codecheck.sh -- let's use 'make lint' instead.

279. By Jonathan Lange

Later version of PEP 8. Drop the warning filters

280. By Jonathan Lange

Update comments in Makefile.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'GTG/__init__.py'
--- GTG/__init__.py 2009-07-12 22:05:07 +0000
+++ GTG/__init__.py 2009-07-13 10:22:44 +0000
@@ -96,8 +96,8 @@
96translation = gettext.translation(GETTEXT_DOMAIN, LOCALE_PATH,96translation = gettext.translation(GETTEXT_DOMAIN, LOCALE_PATH,
97 languages=languages_used,97 languages=languages_used,
98 fallback=True)98 fallback=True)
99import __builtin__99
100__builtin__._ = translation.gettext100_ = translation.gettext
101101
102#GTG directories setup102#GTG directories setup
103if not os.path.isdir( os.path.join(LOCAL_ROOTDIR,'data') ) :103if not os.path.isdir( os.path.join(LOCAL_ROOTDIR,'data') ) :
104104
=== modified file 'GTG/backends/localfile.py'
--- GTG/backends/localfile.py 2009-04-02 22:03:26 +0000
+++ GTG/backends/localfile.py 2009-07-13 09:20:43 +0000
@@ -21,7 +21,7 @@
21#Localfile is a read/write backend that will store your tasks in an XML file21#Localfile is a read/write backend that will store your tasks in an XML file
22#This file will be in your $XDG_DATA_DIR/gtg folder.22#This file will be in your $XDG_DATA_DIR/gtg folder.
2323
24import os,shutil24import os
25import uuid25import uuid
2626
27from GTG.core import CoreConfig27from GTG.core import CoreConfig
2828
=== modified file 'GTG/core/__init__.py'
--- GTG/core/__init__.py 2009-06-18 08:56:33 +0000
+++ GTG/core/__init__.py 2009-07-13 10:26:28 +0000
@@ -45,11 +45,10 @@
4545
46#=== IMPORT ====================================================================46#=== IMPORT ====================================================================
47import os47import os
48from xdg.BaseDirectory import *48from xdg.BaseDirectory import xdg_data_home, xdg_config_home
49from GTG.tools import cleanxml49from GTG.tools import cleanxml
50from configobj import ConfigObj50from configobj import ConfigObj
5151
52import GTG
53from GTG.core import firstrun_tasks52from GTG.core import firstrun_tasks
5453
55class CoreConfig:54class CoreConfig:
5655
=== modified file 'GTG/core/dbuswrapper.py'
--- GTG/core/dbuswrapper.py 2009-07-09 20:03:12 +0000
+++ GTG/core/dbuswrapper.py 2009-07-13 09:13:22 +0000
@@ -1,120 +1,133 @@
1import gobject, dbus.glib, dbus, dbus.service1import dbus
2import dbus.glib
3import dbus.service
4
25
3BUSNAME = "org.GTG"6BUSNAME = "org.GTG"
47
5def dsanitize(data):8def dsanitize(data):
6 # Clean up a dict so that it can be transmitted through D-Bus9 # Clean up a dict so that it can be transmitted through D-Bus
7 for k, v in data.items():10 for k, v in data.items():
8 # Manually specify an arbitrary content type for empty Python arrays11 # Manually specify an arbitrary content type for empty Python arrays
9 # because D-Bus can't handle the type conversion for empty arrays12 # because D-Bus can't handle the type conversion for empty arrays
10 if not v and isinstance(v, list):13 if not v and isinstance(v, list):
11 data[k] = dbus.Array([], "s")14 data[k] = dbus.Array([], "s")
12 # D-Bus has no concept of a null or empty value so we have to convert None15 # D-Bus has no concept of a null or empty value so we have to convert
13 # types to something else. I use an empty string because it has the same16 # None types to something else. I use an empty string because it has
14 # behavior as None in a Python conditional expression17 # the same behavior as None in a Python conditional expression
15 elif v == None:18 elif v == None:
16 data[k] = ""19 data[k] = ""
1720
18 return data21 return data
22
1923
20def task_to_dict(task):24def task_to_dict(task):
21 # Translate a task object into a D-Bus dictionary25 # Translate a task object into a D-Bus dictionary
22 return dbus.Dictionary(dsanitize({26 return dbus.Dictionary(dsanitize({
23 "id": task.get_id(),27 "id": task.get_id(),
24 "status": task.get_status(),28 "status": task.get_status(),
25 "title": task.get_title(),29 "title": task.get_title(),
26 "duedate": task.get_due_date(),30 "duedate": task.get_due_date(),
27 "startdate": task.get_start_date(),31 "startdate": task.get_start_date(),
28 "donedate": task.get_closed_date(),32 "donedate": task.get_closed_date(),
29 "tags": task.get_tags_name(),33 "tags": task.get_tags_name(),
30 "text": task.get_text(),34 "text": task.get_text(),
31 "subtask": task.get_subtasks_tid(),35 "subtask": task.get_subtasks_tid(),
32 }), signature="sv")36 }), signature="sv")
37
3338
34class DBusTaskWrapper(dbus.service.Object):39class DBusTaskWrapper(dbus.service.Object):
35 # D-Bus service object that exposes GTG's task store to third-party apps40
36 def __init__(self, req, ui):41 # D-Bus service object that exposes GTG's task store to third-party apps
37 # Attach the object to D-Bus42 def __init__(self, req, ui):
38 self.bus = dbus.SessionBus()43 # Attach the object to D-Bus
39 bus_name = dbus.service.BusName(BUSNAME, bus=self.bus)44 self.bus = dbus.SessionBus()
40 dbus.service.Object.__init__(self, bus_name, "/org/GTG")45 bus_name = dbus.service.BusName(BUSNAME, bus=self.bus)
41 self.req = req46 dbus.service.Object.__init__(self, bus_name, "/org/GTG")
42 self.ui = ui47 self.req = req
4348 self.ui = ui
44 @dbus.service.method(BUSNAME)49
45 def get_task_ids(self):50 @dbus.service.method(BUSNAME)
46 # Retrieve a list of task ID values51 def get_task_ids(self):
47 return self.req.get_tasks_list(status=["Active", "Done"], started_only=False)52 # Retrieve a list of task ID values
4853 return self.req.get_tasks_list(
49 @dbus.service.method(BUSNAME)54 status=["Active", "Done"], started_only=False)
50 def get_task(self, tid):55
51 # Retrieve a specific task by ID and return the data56 @dbus.service.method(BUSNAME)
52 return task_to_dict(self.req.get_task(tid))57 def get_task(self, tid):
5358 # Retrieve a specific task by ID and return the data
54 @dbus.service.method(BUSNAME)59 return task_to_dict(self.req.get_task(tid))
55 def get_tasks(self):60
56 # Retrieve a list of task data dicts61 @dbus.service.method(BUSNAME)
57 return [self.get_task(id) for id in self.get_task_ids()]62 def get_tasks(self):
5863 # Retrieve a list of task data dicts
59 @dbus.service.method(BUSNAME, in_signature="asasbb")64 return [self.get_task(id) for id in self.get_task_ids()]
60 def get_task_ids_filtered(self, tags, status, started_only, is_root):65
61 # Retrieve a list of task IDs filtered by specified parameters66 @dbus.service.method(BUSNAME, in_signature="asasbb")
62 ids = self.req.get_tasks_list(tags, status, False, started_only, is_root)67 def get_task_ids_filtered(self, tags, status, started_only, is_root):
63 # If there are no matching tasks, return an empty D-Bus array68 # Retrieve a list of task IDs filtered by specified parameters
64 return ids if ids else dbus.Array([], "s")69 ids = self.req.get_tasks_list(
6570 tags, status, False, started_only, is_root)
66 @dbus.service.method(BUSNAME, in_signature="asasbb")71 # If there are no matching tasks, return an empty D-Bus array
67 def get_tasks_filtered(self, tags, status, started_only, is_root):72 return ids if ids else dbus.Array([], "s")
68 # Retrieve a list of task data discts filtered by specificed parameters73
69 tasks = self.get_task_ids_filtered(tags, status, started_only, is_root)74 @dbus.service.method(BUSNAME, in_signature="asasbb")
70 # If no tasks match the filter, return an empty D-Bus array75 def get_tasks_filtered(self, tags, status, started_only, is_root):
71 return [self.get_task(id) for id in tasks] if tasks else dbus.Array([], "s")76 # Retrieve a list of task data discts filtered by specificed parameters
7277 tasks = self.get_task_ids_filtered(
73 @dbus.service.method(BUSNAME)78 tags, status, started_only, is_root)
74 def has_task(self, tid):79 # If no tasks match the filter, return an empty D-Bus array
75 return self.req.has_task(tid)80 if tasks:
7681 return [self.get_task(id) for id in tasks]
77 @dbus.service.method(BUSNAME)82 else:
78 def delete_task(self, tid):83 return dbus.Array([], "s")
79 self.req.delete_task(tid)84
8085 @dbus.service.method(BUSNAME)
81 @dbus.service.method(BUSNAME, in_signature="sssssassas")86 def has_task(self, tid):
82 def new_task(self, status, title, duedate, startdate, donedate, tags, text, subtasks):87 return self.req.has_task(tid)
83 # Generate a new task object and return the task data as a dict88
84 nt = self.req.new_task()89 @dbus.service.method(BUSNAME)
85 for sub in subtasks: nt.add_subtask(sub)90 def delete_task(self, tid):
86 for tag in tags: nt.add_tag(tag)91 self.req.delete_task(tid)
87 nt.set_status(status, donedate=donedate)92
88 nt.set_title(title)93 @dbus.service.method(BUSNAME, in_signature="sssssassas")
89 nt.set_due_date(duedate)94 def new_task(self, status, title, duedate, startdate, donedate, tags,
90 nt.set_start_date(startdate)95 text, subtasks):
91 nt.set_text(text)96 # Generate a new task object and return the task data as a dict
92 return task_to_dict(nt)97 nt = self.req.new_task()
9398 for sub in subtasks: nt.add_subtask(sub)
94 @dbus.service.method(BUSNAME)99 for tag in tags: nt.add_tag(tag)
95 def modify_task(self, tid, task_data):100 nt.set_status(status, donedate=donedate)
96 # Apply supplied task data to the task object with the specified ID101 nt.set_title(title)
97 task = self.req.get_task(tid)102 nt.set_due_date(duedate)
98 task.set_status(task_data["status"], donedate=task_data["donedate"])103 nt.set_start_date(startdate)
99 task.set_title(task_data["title"])104 nt.set_text(text)
100 task.set_due_date(task_data["duedate"])105 return task_to_dict(nt)
101 task.set_start_date(task_data["startdate"])106
102 task.set_text(task_data["text"])107 @dbus.service.method(BUSNAME)
103108 def modify_task(self, tid, task_data):
104 for tag in task_data["tags"]: task.add_tag(tag)109 # Apply supplied task data to the task object with the specified ID
105 for sub in task_data["subtask"]: task.add_subtask(sub)110 task = self.req.get_task(tid)
106 return task_to_dict(task)111 task.set_status(task_data["status"], donedate=task_data["donedate"])
107112 task.set_title(task_data["title"])
108 @dbus.service.method(BUSNAME)113 task.set_due_date(task_data["duedate"])
109 def open_task_editor(self, tid):114 task.set_start_date(task_data["startdate"])
110 self.ui.open_task(tid)115 task.set_text(task_data["text"])
111116
112 @dbus.service.method(BUSNAME)117 for tag in task_data["tags"]: task.add_tag(tag)
113 def hide_task_browser(self):118 for sub in task_data["subtask"]: task.add_subtask(sub)
114 self.ui.window.hide()119 return task_to_dict(task)
115 120
116 @dbus.service.method(BUSNAME)121 @dbus.service.method(BUSNAME)
117 def show_task_browser(self):122 def open_task_editor(self, tid):
118 self.ui.window.present()123 self.ui.open_task(tid)
119 self.ui.window.move(self.ui.priv["window_xpos"], self.ui.priv["window_ypos"])124
120125 @dbus.service.method(BUSNAME)
126 def hide_task_browser(self):
127 self.ui.window.hide()
128
129 @dbus.service.method(BUSNAME)
130 def show_task_browser(self):
131 self.ui.window.present()
132 self.ui.window.move(
133 self.ui.priv["window_xpos"], self.ui.priv["window_ypos"])
121134
=== modified file 'GTG/core/firstrun_tasks.py'
--- GTG/core/firstrun_tasks.py 2009-06-18 08:37:25 +0000
+++ GTG/core/firstrun_tasks.py 2009-07-13 10:22:44 +0000
@@ -1,3 +1,4 @@
1from GTG import _
1from GTG.tools import cleanxml2from GTG.tools import cleanxml
23
3def populate():4def populate():
45
=== modified file 'GTG/core/requester.py'
--- GTG/core/requester.py 2009-07-13 08:57:44 +0000
+++ GTG/core/requester.py 2009-07-13 10:26:28 +0000
@@ -18,7 +18,7 @@
18# -----------------------------------------------------------------------------18# -----------------------------------------------------------------------------
1919
2020
21from GTG.tools.listes import *21from GTG.tools.listes import returnlist
2222
23#Requester is a pure View object. It will not do anything but it will23#Requester is a pure View object. It will not do anything but it will
24#be used by any Interface to handle the requests to the datastore24#be used by any Interface to handle the requests to the datastore
2525
=== modified file 'GTG/core/task.py'
--- GTG/core/task.py 2009-07-13 08:57:44 +0000
+++ GTG/core/task.py 2009-07-13 10:26:28 +0000
@@ -20,8 +20,10 @@
20from datetime import date20from datetime import date
21import xml.dom.minidom21import xml.dom.minidom
2222
23from GTG.tools.dates import *23from GTG import _
24from GTG.tools.listes import *24from GTG.tools.dates import strtodate
25from GTG.tools.listes import returnlist
26
2527
26#This class represent a task in GTG.28#This class represent a task in GTG.
27#You should never create a Task directly. Use the datastore.new_task() function.29#You should never create a Task directly. Use the datastore.new_task() function.
2830
=== modified file 'GTG/gtg.py'
--- GTG/gtg.py 2009-07-09 08:31:53 +0000
+++ GTG/gtg.py 2009-07-13 10:22:44 +0000
@@ -46,6 +46,7 @@
46import sys, os46import sys, os
4747
48#our own imports48#our own imports
49from GTG import _
49from GTG.taskbrowser.browser import TaskBrowser50from GTG.taskbrowser.browser import TaskBrowser
50from GTG.core.datastore import DataStore51from GTG.core.datastore import DataStore
51from GTG.core.dbuswrapper import DBusTaskWrapper52from GTG.core.dbuswrapper import DBusTaskWrapper
5253
=== modified file 'GTG/taskbrowser/__init__.py'
--- GTG/taskbrowser/__init__.py 2009-04-03 15:00:18 +0000
+++ GTG/taskbrowser/__init__.py 2009-07-13 10:22:44 +0000
@@ -22,6 +22,8 @@
22#simple, HIG compliant and well integrated with Gnome.22#simple, HIG compliant and well integrated with Gnome.
23import os23import os
2424
25from GTG import _
26
25class GnomeConfig :27class GnomeConfig :
26 current_rep = os.path.dirname(os.path.abspath(__file__))28 current_rep = os.path.dirname(os.path.abspath(__file__))
27 GLADE_FILE = os.path.join(current_rep,"taskbrowser.glade")29 GLADE_FILE = os.path.join(current_rep,"taskbrowser.glade")
2830
=== modified file 'GTG/taskbrowser/browser.py'
--- GTG/taskbrowser/browser.py 2009-07-13 02:40:17 +0000
+++ GTG/taskbrowser/browser.py 2009-07-13 10:41:18 +0000
@@ -1,4 +1,5 @@
1# -*- coding: utf-8 -*-1# -*- coding: utf-8 -*-
2# pylint: disable-msg=W0201
2# -----------------------------------------------------------------------------3# -----------------------------------------------------------------------------
3# Gettings Things Gnome! - a personnal organizer for the GNOME desktop4# Gettings Things Gnome! - a personnal organizer for the GNOME desktop
4# Copyright (c) 2008-2009 - Lionel Dricot & Bertrand Rousseau5# Copyright (c) 2008-2009 - Lionel Dricot & Bertrand Rousseau
@@ -33,6 +34,7 @@
3334
34#our own imports35#our own imports
35import GTG36import GTG
37from GTG import _
36from GTG.taskeditor.editor import TaskEditor38from GTG.taskeditor.editor import TaskEditor
37from GTG.taskbrowser.CellRendererTags import CellRendererTags39from GTG.taskbrowser.CellRendererTags import CellRendererTags
38from GTG.taskbrowser import GnomeConfig40from GTG.taskbrowser import GnomeConfig
@@ -507,15 +509,15 @@
507 }509 }
508 wTree.signal_autoconnect(dic)510 wTree.signal_autoconnect(dic)
509 window = wTree.get_widget("ColorChooser")511 window = wTree.get_widget("ColorChooser")
510 # Get previous color512 # Get previous color
511 tags,notag_only = self.get_selected_tags() #pylint: disable-msg=W0612513 tags,notag_only = self.get_selected_tags() #pylint: disable-msg=W0612
512 if len(tags) == 1:514 if len(tags) == 1:
513 color = tags[0].get_attribute("color")515 color = tags[0].get_attribute("color")
514 if color != None:516 if color != None:
515 colorspec = gtk.gdk.Color(color)517 colorspec = gtk.gdk.Color(color)
516 colorsel = window.colorsel518 colorsel = window.colorsel
517 colorsel.set_previous_color(colorspec)519 colorsel.set_previous_color(colorspec)
518 colorsel.set_current_color(colorspec)520 colorsel.set_current_color(colorspec)
519 window.show()521 window.show()
520522
521 def on_color_response(self,widget,response) :523 def on_color_response(self,widget,response) :
@@ -653,7 +655,7 @@
653 return False655 return False
654 year,month,day = splited_date656 year,month,day = splited_date
655 try :657 try :
656 date = datetime.date(int(year),int(month),int(day))658 datetime.date(int(year),int(month),int(day))
657 except ValueError :659 except ValueError :
658 return False660 return False
659 else :661 else :
660662
=== modified file 'GTG/taskeditor/__init__.py'
--- GTG/taskeditor/__init__.py 2009-06-10 13:17:47 +0000
+++ GTG/taskeditor/__init__.py 2009-07-13 10:22:44 +0000
@@ -20,6 +20,8 @@
2020
21import os21import os
2222
23from GTG import _
24
23class GnomeConfig :25class GnomeConfig :
24 current_rep = os.path.dirname(os.path.abspath(__file__))26 current_rep = os.path.dirname(os.path.abspath(__file__))
25 GLADE_FILE = os.path.join(current_rep,"taskeditor.glade")27 GLADE_FILE = os.path.join(current_rep,"taskeditor.glade")
2628
=== modified file 'GTG/taskeditor/editor.py'
--- GTG/taskeditor/editor.py 2009-06-10 13:17:47 +0000
+++ GTG/taskeditor/editor.py 2009-07-13 10:41:18 +0000
@@ -26,18 +26,19 @@
26import time26import time
27from datetime import date27from datetime import date
2828
29from GTG import _
29from GTG.taskeditor import GnomeConfig30from GTG.taskeditor import GnomeConfig
30from GTG.tools import dates31from GTG.tools import dates
31from GTG.taskeditor.taskview import TaskView32from GTG.taskeditor.taskview import TaskView
32try:33try:
33 import pygtk34 import pygtk
34 pygtk.require("2.0")35 pygtk.require("2.0")
35except:36except: # pylint: disable-msg=W0702
36 sys.exit(1)37 sys.exit(1)
37try:38try:
38 import gtk39 import gtk
39 from gtk import gdk40 from gtk import gdk
40except:41except: # pylint: disable-msg=W0702
41 sys.exit(1)42 sys.exit(1)
42 43
43date_separator = "/"44date_separator = "/"
4445
=== modified file 'GTG/taskeditor/taskview.py'
--- GTG/taskeditor/taskview.py 2009-06-04 19:59:15 +0000
+++ GTG/taskeditor/taskview.py 2009-07-13 09:20:43 +0000
@@ -909,11 +909,11 @@
909 for ta in itera.get_toggled_tags(False) :909 for ta in itera.get_toggled_tags(False) :
910 if ta.get_data('is_subtask') :910 if ta.get_data('is_subtask') :
911 subtask_nbr = ta.get_data('child')911 subtask_nbr = ta.get_data('child')
912 912
913 #New line : the user pressed enter !913 #New line : the user pressed enter !
914 #If the line begins with "-", it's a new subtask !914 #If the line begins with "-", it's a new subtask !
915 if tex == '\n' :915 if tex == '\n' :
916 insert_point = self.buff.create_mark("insert_point",itera,True)916 self.buff.create_mark("insert_point", itera, True)
917 #First, we close tag tags.917 #First, we close tag tags.
918 #If we are at the end of a tag, we look for closed tags918 #If we are at the end of a tag, we look for closed tags
919 closed_tag = None919 closed_tag = None
@@ -923,7 +923,6 @@
923 #Or maybe we are in the middle of a tag923 #Or maybe we are in the middle of a tag
924 else :924 else :
925 list_stag = itera.get_tags()925 list_stag = itera.get_tags()
926 stag = None
927 for t in list_stag :926 for t in list_stag :
928 if t.get_data('is_tag') :927 if t.get_data('is_tag') :
929 closed_tag = t.get_data('tagname')928 closed_tag = t.get_data('tagname')
@@ -984,17 +983,15 @@
984 self.buff.create_mark(anchor,itera,True)983 self.buff.create_mark(anchor,itera,True)
985 self.buff.create_mark("/%s"%anchor,itera,False)984 self.buff.create_mark("/%s"%anchor,itera,False)
986 self.insert_sigid = self.buff.connect('insert-text', self._insert_at_cursor)985 self.insert_sigid = self.buff.connect('insert-text', self._insert_at_cursor)
987 self.keypress_sigid = self.connect('key_press_event', self._keypress)986 self.connect('key_press_event', self._keypress)
988 self.modified_sigid = self.buff.connect("changed" , self.modified)987 self.modified_sigid = self.buff.connect("changed" , self.modified)
989 988
990 def _keypress(self, widget, event):989 def _keypress(self, widget, event):
991 # Check for Ctrl-Return/Enter990 # Check for Ctrl-Return/Enter
992 if event.state & gtk.gdk.CONTROL_MASK and event.keyval in (gtk.keysyms.Return, gtk.keysyms.KP_Enter):991 if event.state & gtk.gdk.CONTROL_MASK and event.keyval in (gtk.keysyms.Return, gtk.keysyms.KP_Enter):
993 buff = self.buff 992 buff = self.buff
994 cursor_mark = buff.get_insert()993 cursor_mark = buff.get_insert()
995 cursor_iter = buff.get_iter_at_mark(cursor_mark)994 cursor_iter = buff.get_iter_at_mark(cursor_mark)
996 table = buff.get_tag_table()
997
998 local_start = cursor_iter.copy()995 local_start = cursor_iter.copy()
999996
1000 for tag in local_start.get_tags():997 for tag in local_start.get_tags():
@@ -1005,7 +1002,7 @@
1005 self.open_task(anchor)1002 self.open_task(anchor)
1006 elif typ == "http" :1003 elif typ == "http" :
1007 openurl.openurl(anchor)1004 openurl.openurl(anchor)
1008 1005
1009 return True1006 return True
10101007
1011 #Deindent the current line of one level1008 #Deindent the current line of one level
10121009
=== added file 'Makefile'
--- Makefile 1970-01-01 00:00:00 +0000
+++ Makefile 2009-07-13 10:59:58 +0000
@@ -0,0 +1,13 @@
1
2pyflakes:
3 pyflakes GTG
4
5# Ignoring E301 "One blank line between things within a class", since it
6# triggers false positives for normal decorator syntax.
7pep8:
8 find . -name '*.py' -print0 | xargs -0 ./scripts/pep8.py --ignore=E301
9 find . -name '*.py' -print0 | xargs -0 ./scripts/pep8.py --ignore=E301 --repeat | wc -l
10
11lint: pyflakes pep8
12
13.PHONY: lint pyflakes pep8
014
=== modified file 'scripts/codecheck.sh'
--- scripts/codecheck.sh 2009-03-31 11:04:14 +0000
+++ scripts/codecheck.sh 2009-07-13 10:41:18 +0000
@@ -37,7 +37,7 @@
37#I0011 : Locally disabling. We don't care if we disabled locally37#I0011 : Locally disabling. We don't care if we disabled locally
3838
39#pylint argument :39#pylint argument :
40disabled="C0324,C0103,C0301,C0111,R0914,R0903,R0915,R0904,R0912,R0201,R0913,C0323,R0902,W0102,W0232,W0105,C0321,W0401,W0142,I0011"40disabled="C0324,C0103,C0301,C0111,R0914,R0903,R0915,R0904,R0912,R0201,R0913,C0323,R0902,W0102,W0232,W0105,C0321,W0401,W0142,I0011,C0302,W0613,W0511,W0622,R0911"
41args="--rcfile=/dev/null --include-ids=y --reports=n"41args="--rcfile=/dev/null --include-ids=y --reports=n"
42#grepped_out="Locally disabling"42#grepped_out="Locally disabling"
43#pylint doesn't recognize gettext _()43#pylint doesn't recognize gettext _()
@@ -49,8 +49,7 @@
4949
50echo "Running pyflakes"50echo "Running pyflakes"
51echo "#################"51echo "#################"
52#pyflakes triggers a false positive with import * and with gettext _()52pyflakes GTG
53pyflakes GTG|grep -v "import \*"|grep -v "undefined name '_'"
5453
55echo "Running pylint"54echo "Running pylint"
56echo "#################"55echo "#################"
@@ -61,3 +60,8 @@
61 pylint --rcfile=/dev/null --include-ids=y --reports=n --disable-msg=$disabled $i |grep -v "$grepped_out"60 pylint --rcfile=/dev/null --include-ids=y --reports=n --disable-msg=$disabled $i |grep -v "$grepped_out"
62 fi61 fi
63done62done
63
64
65echo "Running pep8"
66echo "############"
67find . -name '*.py' -print0 | xargs -0 ./scripts/pep8.py
6468
=== added file 'scripts/pep8.py'
--- scripts/pep8.py 1970-01-01 00:00:00 +0000
+++ scripts/pep8.py 2009-07-13 10:12:30 +0000
@@ -0,0 +1,773 @@
1#!/usr/bin/python
2# pep8.py - Check Python source code formatting, according to PEP 8
3# Copyright (C) 2006 Johann C. Rocholl <johann@browsershots.org>
4#
5# Permission is hereby granted, free of charge, to any person
6# obtaining a copy of this software and associated documentation files
7# (the "Software"), to deal in the Software without restriction,
8# including without limitation the rights to use, copy, modify, merge,
9# publish, distribute, sublicense, and/or sell copies of the Software,
10# and to permit persons to whom the Software is furnished to do so,
11# subject to the following conditions:
12#
13# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23# SOFTWARE.
24
25"""
26Check Python source code formatting, according to PEP 8:
27http://www.python.org/dev/peps/pep-0008/
28
29For usage and a list of options, try this:
30$ python pep8.py -h
31
32This program and its regression test suite live here:
33http://svn.browsershots.org/trunk/devtools/pep8/
34http://trac.browsershots.org/browser/trunk/devtools/pep8/
35
36Groups of errors and warnings:
37E errors
38W warnings
39100 indentation
40200 whitespace
41300 blank lines
42400 imports
43500 line length
44600 deprecation
45
46You can add checks to this program by writing plugins. Each plugin is
47a simple function that is called for each line of source code, either
48physical or logical.
49
50Physical line:
51- Raw line of text from the input file.
52
53Logical line:
54- Multi-line statements converted to a single line.
55- Stripped left and right.
56- Contents of strings replaced with 'xxx' of same length.
57- Comments removed.
58
59The check function requests physical or logical lines by the name of
60the first argument:
61
62def maximum_line_length(physical_line)
63def extraneous_whitespace(logical_line)
64def indentation(logical_line, indent_level, state)
65
66The last example above demonstrates how check plugins can request
67additional information with extra arguments. All attributes of the
68Checker object are available. Some examples:
69
70lines: a list of the raw lines from the input file
71tokens: the tokens that contribute to this logical line
72state: dictionary for passing information across lines
73indent_level: indentation (with tabs expanded to multiples of 8)
74
75The docstring of each check function shall be the relevant part of
76text from PEP 8. It is printed if the user enables --show-pep8.
77
78"""
79
80import os
81import sys
82import re
83import time
84import inspect
85import tokenize
86from optparse import OptionParser
87from keyword import iskeyword
88from fnmatch import fnmatch
89
90__version__ = '0.2.0'
91__revision__ = '$Rev: 930 $'
92
93default_exclude = '.svn,CVS,*.pyc,*.pyo'
94
95indent_match = re.compile(r'([ \t]*)').match
96raise_comma_match = re.compile(r'raise\s+\w+\s*(,)').match
97
98operators = """
99+ - * / % ^ & | = < > >> <<
100+= -= *= /= %= ^= &= |= == <= >= >>= <<=
101!= <> :
102in is or not and
103""".split()
104
105options = None
106args = None
107
108
109##############################################################################
110# Plugins (check functions) for physical lines
111##############################################################################
112
113
114def tabs_or_spaces(physical_line, state):
115 """
116 Never mix tabs and spaces.
117
118 The most popular way of indenting Python is with spaces only. The
119 second-most popular way is with tabs only. Code indented with a mixture
120 of tabs and spaces should be converted to using spaces exclusively. When
121 invoking the Python command line interpreter with the -t option, it issues
122 warnings about code that illegally mixes tabs and spaces. When using -tt
123 these warnings become errors. These options are highly recommended!
124 """
125 indent = indent_match(physical_line).group(1)
126 if not indent:
127 return
128 if 'indent_char' in state:
129 indent_char = state['indent_char']
130 else:
131 indent_char = indent[0]
132 state['indent_char'] = indent_char
133 for offset, char in enumerate(indent):
134 if char != indent_char:
135 return offset, "E101 indentation contains mixed spaces and tabs"
136
137
138def tabs_obsolete(physical_line):
139 """
140 For new projects, spaces-only are strongly recommended over tabs. Most
141 editors have features that make this easy to do.
142 """
143 indent = indent_match(physical_line).group(1)
144 if indent.count('\t'):
145 return indent.index('\t'), "W191 indentation contains tabs"
146
147
148def trailing_whitespace(physical_line):
149 """
150 JCR: Trailing whitespace is superfluous.
151 """
152 physical_line = physical_line.rstrip('\n') # chr(10), newline
153 physical_line = physical_line.rstrip('\r') # chr(13), carriage return
154 physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L
155 stripped = physical_line.rstrip()
156 if physical_line != stripped:
157 return len(stripped), "W291 trailing whitespace"
158
159
160def maximum_line_length(physical_line):
161 """
162 Limit all lines to a maximum of 79 characters.
163
164 There are still many devices around that are limited to 80 character
165 lines; plus, limiting windows to 80 characters makes it possible to have
166 several windows side-by-side. The default wrapping on such devices looks
167 ugly. Therefore, please limit all lines to a maximum of 79 characters.
168 For flowing long blocks of text (docstrings or comments), limiting the
169 length to 72 characters is recommended.
170 """
171 length = len(physical_line.rstrip())
172 if length > 79:
173 return 79, "E501 line too long (%d characters)" % length
174
175
176##############################################################################
177# Plugins (check functions) for logical lines
178##############################################################################
179
180
181def blank_lines(logical_line, state, indent_level):
182 """
183 Separate top-level function and class definitions with two blank lines.
184
185 Method definitions inside a class are separated by a single blank line.
186
187 Extra blank lines may be used (sparingly) to separate groups of related
188 functions. Blank lines may be omitted between a bunch of related
189 one-liners (e.g. a set of dummy implementations).
190
191 Use blank lines in functions, sparingly, to indicate logical sections.
192 """
193 line = logical_line
194 blank_lines = state.get('blank_lines', 0)
195 if line.startswith('def '):
196 if indent_level > 0 and blank_lines != 1:
197 return 0, "E301 expected 1 blank line, found %d" % blank_lines
198 if indent_level == 0 and blank_lines != 2:
199 return 0, "E302 expected 2 blank lines, found %d" % blank_lines
200 if blank_lines > 2:
201 return 0, "E303 too many blank lines (%d)" % blank_lines
202
203
204def extraneous_whitespace(logical_line):
205 """
206 Avoid extraneous whitespace in the following situations:
207
208 - Immediately inside parentheses, brackets or braces.
209
210 - Immediately before a comma, semicolon, or colon.
211 """
212 line = logical_line
213 for char in '([{':
214 found = line.find(char + ' ')
215 if found > -1:
216 return found + 1, "E201 whitespace after '%s'" % char
217 for char in '}])':
218 found = line.find(' ' + char)
219 if found > -1 and line[found - 1] != ',':
220 return found, "E202 whitespace before '%s'" % char
221 for char in ',;:':
222 found = line.find(' ' + char)
223 if found > -1:
224 return found, "E203 whitespace before '%s'" % char
225
226
227def indentation(logical_line, indent_level, state):
228 """
229 Use 4 spaces per indentation level.
230
231 For really old code that you don't want to mess up, you can continue to
232 use 8-space tabs.
233 """
234 line = logical_line
235 previous_level = state.get('indent_level', 0)
236 indent_expect = state.get('indent_expect', False)
237 state['indent_expect'] = line.rstrip('#').rstrip().endswith(':')
238 indent_char = state.get('indent_char', ' ')
239 state['indent_level'] = indent_level
240 if indent_char == ' ' and indent_level % 4:
241 return 0, "E111 indentation is not a multiple of four"
242 if indent_expect and indent_level <= previous_level:
243 return 0, "E112 expected an indented block"
244 if not indent_expect and indent_level > previous_level:
245 return 0, "E113 unexpected indentation"
246
247
248def whitespace_before_parameters(logical_line, tokens):
249 """
250 Avoid extraneous whitespace in the following situations:
251
252 - Immediately before the open parenthesis that starts the argument
253 list of a function call.
254
255 - Immediately before the open parenthesis that starts an indexing or
256 slicing.
257 """
258 prev_type = tokens[0][0]
259 prev_text = tokens[0][1]
260 prev_end = tokens[0][3]
261 for index in range(1, len(tokens)):
262 token_type, text, start, end, line = tokens[index]
263 if (token_type == tokenize.OP and
264 text in '([' and
265 start != prev_end and
266 prev_type == tokenize.NAME and
267 (index < 2 or tokens[index - 2][1] != 'class') and
268 (not iskeyword(prev_text))):
269 return prev_end, "E211 whitespace before '%s'" % text
270 prev_type = token_type
271 prev_text = text
272 prev_end = end
273
274
275def whitespace_around_operator(logical_line):
276 """
277 Avoid extraneous whitespace in the following situations:
278
279 - More than one space around an assignment (or other) operator to
280 align it with another.
281 """
282 line = logical_line
283 for operator in operators:
284 found = line.find(' ' + operator)
285 if found > -1:
286 return found, "E221 multiple spaces before operator"
287 found = line.find('\t' + operator)
288 if found > -1:
289 return found, "E222 tab before operator"
290
291
292def imports_on_separate_lines(logical_line):
293 """
294 Imports should usually be on separate lines.
295 """
296 line = logical_line
297 if line.startswith('import '):
298 found = line.find(',')
299 if found > -1:
300 return found, "E401 multiple imports on one line"
301
302
303def python_3000_has_key(logical_line):
304 """
305 The {}.has_key() method will be removed in the future version of
306 Python. Use the 'in' operation instead, like:
307 d = {"a": 1, "b": 2}
308 if "b" in d:
309 print d["b"]
310 """
311 pos = logical_line.find('.has_key(')
312 if pos > -1:
313 return pos, "W601 .has_key() is deprecated, use 'in'"
314
315
316def python_3000_raise_comma(logical_line):
317 """
318 When raising an exception, use "raise ValueError('message')"
319 instead of the older form "raise ValueError, 'message'".
320
321 The paren-using form is preferred because when the exception arguments
322 are long or include string formatting, you don't need to use line
323 continuation characters thanks to the containing parentheses. The older
324 form will be removed in Python 3000.
325 """
326 match = raise_comma_match(logical_line)
327 if match:
328 return match.start(1), "W602 deprecated form of raising exception"
329
330
331##############################################################################
332# Helper functions
333##############################################################################
334
335
336def expand_indent(line):
337 """
338 Return the amount of indentation.
339 Tabs are expanded to the next multiple of 8.
340
341 >>> expand_indent(' ')
342 4
343 >>> expand_indent('\\t')
344 8
345 >>> expand_indent(' \\t')
346 8
347 >>> expand_indent(' \\t')
348 8
349 >>> expand_indent(' \\t')
350 16
351 """
352 result = 0
353 for char in line:
354 if char == '\t':
355 result = result / 8 * 8 + 8
356 elif char == ' ':
357 result += 1
358 else:
359 break
360 return result
361
362
363##############################################################################
364# Framework to run all checks
365##############################################################################
366
367
368def message(text):
369 """Print a message."""
370 # print >> sys.stderr, options.prog + ': ' + text
371 # print >> sys.stderr, text
372 print text
373
374
375def find_checks(argument_name):
376 """
377 Find all globally visible functions where the first argument name
378 starts with argument_name.
379 """
380 checks = []
381 function_type = type(find_checks)
382 for name, function in globals().iteritems():
383 if type(function) is function_type:
384 args = inspect.getargspec(function)[0]
385 if len(args) >= 1 and args[0].startswith(argument_name):
386 checks.append((name, function, args))
387 checks.sort()
388 return checks
389
390
391def mute_string(text):
392 """
393 Replace contents with 'xxx' to prevent syntax matching.
394
395 >>> mute_string('"abc"')
396 '"xxx"'
397 >>> mute_string("'''abc'''")
398 "'''xxx'''"
399 >>> mute_string("r'abc'")
400 "r'xxx'"
401 """
402 start = 1
403 end = len(text) - 1
404 # String modifiers (e.g. u or r)
405 if text.endswith('"'):
406 start += text.index('"')
407 elif text.endswith("'"):
408 start += text.index("'")
409 # Triple quotes
410 if text.endswith('"""') or text.endswith("'''"):
411 start += 2
412 end -= 2
413 return text[:start] + 'x' * (end - start) + text[end:]
414
415
416class Checker:
417 """
418 Load a Python source file, tokenize it, check coding style.
419 """
420
421 def __init__(self, filename):
422 self.filename = filename
423 self.lines = file(filename).readlines()
424 self.physical_checks = find_checks('physical_line')
425 self.logical_checks = find_checks('logical_line')
426 options.counters['physical lines'] = \
427 options.counters.get('physical lines', 0) + len(self.lines)
428
429 def readline(self):
430 """
431 Get the next line from the input buffer.
432 """
433 self.line_number += 1
434 if self.line_number > len(self.lines):
435 return ''
436 return self.lines[self.line_number - 1]
437
438 def readline_check_physical(self):
439 """
440 Check and return the next physical line. This method can be
441 used to feed tokenize.generate_tokens.
442 """
443 line = self.readline()
444 self.check_physical(line)
445 return line
446
447 def run_check(self, check, argument_names):
448 """
449 Run a check plugin.
450 """
451 arguments = []
452 for name in argument_names:
453 arguments.append(getattr(self, name))
454 return check(*arguments)
455
456 def check_physical(self, line):
457 """
458 Run all physical checks on a raw input line.
459 """
460 self.physical_line = line
461 for name, check, argument_names in self.physical_checks:
462 result = self.run_check(check, argument_names)
463 if result is not None:
464 offset, text = result
465 self.report_error(self.line_number, offset, text, check)
466
467 def build_tokens_line(self):
468 """
469 Build a logical line from tokens.
470 """
471 self.mapping = []
472 logical = []
473 length = 0
474 previous = None
475 for token in self.tokens:
476 token_type, text = token[0:2]
477 if token_type in (tokenize.COMMENT, tokenize.NL,
478 tokenize.INDENT, tokenize.DEDENT,
479 tokenize.NEWLINE):
480 continue
481 if token_type == tokenize.STRING:
482 text = mute_string(text)
483 if previous:
484 end_line, end = previous[3]
485 start_line, start = token[2]
486 if end_line != start_line: # different row
487 if self.lines[end_line - 1][end - 1] not in '{[(':
488 logical.append(' ')
489 length += 1
490 elif end != start: # different column
491 fill = self.lines[end_line - 1][end:start]
492 logical.append(fill)
493 length += len(fill)
494 self.mapping.append((length, token))
495 logical.append(text)
496 length += len(text)
497 previous = token
498 self.logical_line = ''.join(logical)
499
500 def check_logical(self):
501 """
502 Build a line from tokens and run all logical checks on it.
503 """
504 options.counters['logical lines'] = \
505 options.counters.get('logical lines', 0) + 1
506 self.build_tokens_line()
507 first_line = self.lines[self.mapping[0][1][2][0] - 1]
508 indent = first_line[:self.mapping[0][1][2][1]]
509 self.indent_level = expand_indent(indent)
510 if options.verbose >= 2:
511 print self.logical_line[:80].rstrip()
512 for name, check, argument_names in self.logical_checks:
513 if options.verbose >= 3:
514 print ' ', name
515 result = self.run_check(check, argument_names)
516 if result is not None:
517 offset, text = result
518 if type(offset) is tuple:
519 original_number, original_offset = offset
520 else:
521 for token_offset, token in self.mapping:
522 if offset >= token_offset:
523 original_number = token[2][0]
524 original_offset = (token[2][1]
525 + offset - token_offset)
526 self.report_error(original_number, original_offset,
527 text, check)
528
529 def check_all(self):
530 """
531 Run all checks on the input file.
532 """
533 self.file_errors = 0
534 self.line_number = 0
535 self.state = {'blank_lines': 0}
536 self.tokens = []
537 parens = 0
538 for token in tokenize.generate_tokens(self.readline_check_physical):
539 # print tokenize.tok_name[token[0]], repr(token)
540 self.tokens.append(token)
541 token_type, text = token[0:2]
542 if token_type == tokenize.OP and text in '([{':
543 parens += 1
544 if token_type == tokenize.OP and text in '}])':
545 parens -= 1
546 if token_type == tokenize.NEWLINE and not parens:
547 self.check_logical()
548 self.state['blank_lines'] = 0
549 self.tokens = []
550 if token_type == tokenize.NL and len(self.tokens) == 1:
551 self.state['blank_lines'] += 1
552 self.tokens = []
553 return self.file_errors
554
555 def report_error(self, line_number, offset, text, check):
556 """
557 Report an error, according to options.
558 """
559 if options.quiet == 1 and not self.file_errors:
560 message(self.filename)
561 self.file_errors += 1
562 code = text[:4]
563 options.counters[code] = options.counters.get(code, 0) + 1
564 options.messages[code] = text[5:]
565 if options.quiet:
566 return
567 if options.testsuite:
568 base = os.path.basename(self.filename)[:4]
569 if base == code:
570 return
571 if base[0] == 'E' and code[0] == 'W':
572 return
573 if ignore_code(code):
574 return
575 if options.counters[code] == 1 or options.repeat:
576 message("%s:%s:%d: %s" %
577 (self.filename, line_number, offset + 1, text))
578 if options.show_source:
579 line = self.lines[line_number - 1]
580 message(line.rstrip())
581 message(' ' * offset + '^')
582 if options.show_pep8:
583 message(check.__doc__.lstrip('\n').rstrip())
584
585
586def input_file(filename):
587 """
588 Run all checks on a Python source file.
589 """
590 if excluded(filename) or not filename_match(filename):
591 return {}
592 if options.verbose:
593 message('checking ' + filename)
594 options.counters['files'] = options.counters.get('files', 0) + 1
595 errors = Checker(filename).check_all()
596 if options.testsuite and not errors:
597 message("%s: %s" % (filename, "no errors found"))
598
599
600def input_dir(dirname):
601 """
602 Check all Python source files in this directory and all subdirectories.
603 """
604 dirname = dirname.rstrip('/')
605 if excluded(dirname):
606 return
607 for root, dirs, files in os.walk(dirname):
608 if options.verbose:
609 message('directory ' + root)
610 options.counters['directories'] = \
611 options.counters.get('directories', 0) + 1
612 dirs.sort()
613 for subdir in dirs:
614 if excluded(subdir):
615 dirs.remove(subdir)
616 files.sort()
617 for filename in files:
618 input_file(os.path.join(root, filename))
619
620
621def excluded(filename):
622 """
623 Check if options.exclude contains a pattern that matches filename.
624 """
625 for pattern in options.exclude:
626 if fnmatch(filename, pattern):
627 return True
628
629
630def filename_match(filename):
631 """
632 Check if options.filename contains a pattern that matches filename.
633 If options.filename is unspecified, this always returns True.
634 """
635 if not options.filename:
636 return True
637 for pattern in options.filename:
638 if fnmatch(filename, pattern):
639 return True
640
641
642def ignore_code(code):
643 """
644 Check if options.ignore contains a prefix of the error code.
645 """
646 for ignore in options.ignore:
647 if code.startswith(ignore):
648 return True
649
650
651def get_error_statistics():
652 """Get error statistics."""
653 return get_statistics("E")
654
655
656def get_warning_statistics():
657 """Get warning statistics."""
658 return get_statistics("W")
659
660
661def get_statistics(prefix=''):
662 """
663 Get statistics for message codes that start with the prefix.
664
665 prefix='' matches all errors and warnings
666 prefix='E' matches all errors
667 prefix='W' matches all warnings
668 prefix='E4' matches all errors that have to do with imports
669 """
670 stats = []
671 keys = options.messages.keys()
672 keys.sort()
673 for key in keys:
674 if key.startswith(prefix):
675 stats.append('%-7s %s %s' %
676 (options.counters[key], key, options.messages[key]))
677 return stats
678
679
680def print_statistics(prefix=''):
681 """Print overall statistics (number of errors and warnings)."""
682 for line in get_statistics(prefix):
683 print line
684
685
686def print_benchmark(elapsed):
687 """
688 Print benchmark numbers.
689 """
690 print '%-7.2f %s' % (elapsed, 'seconds elapsed')
691 keys = ['directories', 'files',
692 'logical lines', 'physical lines']
693 for key in keys:
694 if key in options.counters:
695 print '%-7d %s per second (%d total)' % (
696 options.counters[key] / elapsed, key,
697 options.counters[key])
698
699
700def process_options(arglist=None):
701 """
702 Process options passed either via arglist or via command line args.
703 """
704 global options, args
705 usage = "%prog [options] input ..."
706 parser = OptionParser(usage)
707 parser.add_option('-v', '--verbose', default=0, action='count',
708 help="print status messages, or debug with -vv")
709 parser.add_option('-q', '--quiet', default=0, action='count',
710 help="report only file names, or nothing with -qq")
711 parser.add_option('--exclude', metavar='patterns', default=default_exclude,
712 help="skip matches (default %s)" % default_exclude)
713 parser.add_option('--filename', metavar='patterns',
714 help="only check matching files (e.g. *.py)")
715 parser.add_option('--ignore', metavar='errors', default='',
716 help="skip errors and warnings (e.g. E4,W)")
717 parser.add_option('--repeat', action='store_true',
718 help="show all occurrences of the same error")
719 parser.add_option('--show-source', action='store_true',
720 help="show source code for each error")
721 parser.add_option('--show-pep8', action='store_true',
722 help="show text of PEP 8 for each error")
723 parser.add_option('--statistics', action='store_true',
724 help="count errors and warnings")
725 parser.add_option('--benchmark', action='store_true',
726 help="measure processing speed")
727 parser.add_option('--testsuite', metavar='dir',
728 help="run regression tests from dir")
729 parser.add_option('--doctest', action='store_true',
730 help="run doctest on myself")
731 options, args = parser.parse_args(arglist)
732 if options.testsuite:
733 args.append(options.testsuite)
734 if len(args) == 0:
735 parser.error('input not specified')
736 options.prog = os.path.basename(sys.argv[0])
737 options.exclude = options.exclude.split(',')
738 for index in range(len(options.exclude)):
739 options.exclude[index] = options.exclude[index].rstrip('/')
740 if options.filename:
741 options.filename = options.filename.split(',')
742 if options.ignore:
743 options.ignore = options.ignore.split(',')
744 else:
745 options.ignore = []
746 options.counters = {}
747 options.messages = {}
748
749 return options, args
750
751def _main():
752 """
753 Parse options and run checks on Python source.
754 """
755 options, args = process_options()
756 if options.doctest:
757 import doctest
758 return doctest.testmod()
759 start_time = time.time()
760 for path in args:
761 if os.path.isdir(path):
762 input_dir(path)
763 else:
764 input_file(path)
765 elapsed = time.time() - start_time
766 if options.statistics:
767 print_statistics()
768 if options.benchmark:
769 print_benchmark(elapsed)
770
771
772if __name__ == '__main__':
773 _main()
0774
=== modified file 'setup.py'
--- setup.py 2009-07-04 13:31:04 +0000
+++ setup.py 2009-07-13 09:13:22 +0000
@@ -43,7 +43,7 @@
43 if file.endswith(".png") or file.endswith(".svg"):43 if file.endswith(".png") or file.endswith(".svg"):
44 dirList.append(os.path.join(root,file))44 dirList.append(os.path.join(root,file))
45 if len(dirList)!=0:45 if len(dirList)!=0:
46 newroot = root.replace("data/","")46 newroot = root.replace("data/","")
47 fileList.append( (os.path.join(DATA_DIR,newroot),dirList) )47 fileList.append( (os.path.join(DATA_DIR,newroot),dirList) )
48 return fileList48 return fileList
4949

Subscribers

People subscribed via source and target branches

to status/vote changes: