GTG

Merge lp:~gtg-user/gtg/improved_tools_dates.py into lp:~gtg/gtg/old-trunk

Proposed by Thibault Févry
Status: Rejected
Rejected by: Izidor Matušov
Proposed branch: lp:~gtg-user/gtg/improved_tools_dates.py
Merge into: lp:~gtg/gtg/old-trunk
Diff against target: 323 lines (+102/-92)
2 files modified
GTG/gtk/editor/editor.py (+1/-1)
GTG/tools/dates.py (+101/-91)
To merge this branch: bzr merge lp:~gtg-user/gtg/improved_tools_dates.py
Reviewer Review Type Date Requested Status
Izidor Matušov Needs Resubmitting
Gtg developers test in different locales perhaps. Pending
Review via email: mp+34697@code.launchpad.net

Commit message

Optimizations and improvements in tools-dates.py (This shouldn't change anything for developpers or users.

Description of the change

 This improves tool/dates.py, removing the fixme, adding an elegant way to get weekdays.

 This also removes the need for 7 strings translation per language, as this is now handled by the calendar module.

 Other nice thing is the pep8 fixing, should be only 4-5 errors left.

 This shouldn't break anything, if it does, I'll fix it. (It didn't break anything in mine GTG, but I also didn't tested it in a long time period.)

To post a comment you must log in.
Revision history for this message
Luca Invernizzi (invernizzi) wrote :

Great! thanks for this. You just gained the pep8-defender badge :P

Revision history for this message
Paul Natsuo Kishimoto (khaeru) wrote :

Using the calendar module's localized day names was one of the changes already made in https://code.edge.launchpad.net/~gtg-contributors/gtg/new-date-class/+merge/28009

Nobody has touched that one for a while, but it *is* still available to commit, without conflicts. Which of these two should be merged?

Thibault, if you like I can update my branch to incorporate your changes. That will probably be easier than vice-versa.

Revision history for this message
Luca Invernizzi (invernizzi) wrote :

Un-committing since it has problems with due dates not set (i.e., set to None). I'm trying to get a stable trunk, so I prefer that new bugs are fixed before merging. We have already enough :)

Traceback:

None
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.6/threading.py", line 532, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.6/threading.py", line 484, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/home/luca/Projects/gtg/TRUNK/GTG/core/datastore.py", line 401, in __start_get_tasks
    self.backend.start_get_tasks()
  File "/home/luca/Projects/gtg/TRUNK/GTG/backends/backend_localfile.py", line 129, in start_get_tasks
    task = taskxml.task_from_xml(task, node)
  File "/home/luca/Projects/gtg/TRUNK/GTG/tools/taskxml.py", line 58, in task_from_xml
    cur_task.set_due_date(dates.strtodate(cleanxml.readTextNode(xmlnode,"duedate")))
  File "/home/luca/Projects/gtg/TRUNK/GTG/core/task.py", line 193, in set_due_date
    assert(isinstance(fulldate, Date))
AssertionError

(fulldate is None).

About Paul branch, since you both have worked on this matter you can figure out how to merge the two the best. I'm still not convinced about the elimination of FuzzyDate, since it was useful to get the type of the date for syncing with the backends. There is the is_special() method, but that matches also NoDate.

Revision history for this message
Thibault Févry (thibaultfevry) wrote :

As I really don't know what in the changed code does the bug, (I'm not even sure this is a bug, this just prints an exception (That we raise), but does this change anything in the way GTG handle the task with no date attribute ?), I'll do other things for now and get back later to this.

Revision history for this message
Izidor Matušov (izidor) wrote :

Marking as rejected because nothing happend for quite long time and similar changes was already merged.

review: Needs Resubmitting

Unmerged revisions

873. By Thibault Févry

Further optimizations, commit with trunk.

872. By Thibault Févry

Fix evil...

871. By Thibault Févry

Commit

870. By Thibault Févry

l

869. By Thibault Févry

Nothing, just updated to trunk.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'GTG/gtk/editor/editor.py'
--- GTG/gtk/editor/editor.py 2010-07-06 04:01:50 +0000
+++ GTG/gtk/editor/editor.py 2010-09-06 18:07:42 +0000
@@ -321,7 +321,7 @@
321 #If the task is marked as done, we display the delay between the 321 #If the task is marked as done, we display the delay between the
322 #due date and the actual closing date. If the task isn't marked 322 #due date and the actual closing date. If the task isn't marked
323 #as done, we display the number of days left.323 #as done, we display the number of days left.
324 if status in [Task.STA_DISMISSED, Task.STA_DONE]:324 if status in (Task.STA_DISMISSED, Task.STA_DONE):
325 delay = self.task.get_days_late()325 delay = self.task.get_days_late()
326 if delay is None:326 if delay is None:
327 txt = ""327 txt = ""
328328
=== modified file 'GTG/tools/dates.py'
--- GTG/tools/dates.py 2010-04-30 19:23:02 +0000
+++ GTG/tools/dates.py 2010-09-06 18:07:42 +0000
@@ -22,96 +22,109 @@
22import calendar22import calendar
23from GTG import _, ngettext23from GTG import _, ngettext
2424
25#setting the locale of gtg to the system locale 25#setting the locale of gtg to the system locale
26#locale.setlocale(locale.LC_TIME, '')26#locale.setlocale(locale.LC_TIME, '')
2727
28
28class Date(object):29class Date(object):
30
29 def __cmp__(self, other):31 def __cmp__(self, other):
30 if other is None: return 132 if other is None:
33 return 1
31 return cmp(self.to_py_date(), other.to_py_date())34 return cmp(self.to_py_date(), other.to_py_date())
32 35
33 def __sub__(self, other):36 def __sub__(self, other):
34 return self.to_py_date() - other.to_py_date()37 return self.to_py_date() - other.to_py_date()
3538
36 def __get_locale_string(self):39 def __get_locale_string(self):
37 return locale.nl_langinfo(locale.D_FMT)40 return locale.nl_langinfo(locale.D_FMT)
38 41
39 def xml_str(self): return str(self)42 def xml_str(self):
40 43 return str(self)
41 def day(self): return self.to_py_date().day44
42 def month(self): return self.to_py_date().month45 def day(self):
43 def year(self): return self.to_py_date().year46 return self.to_py_date().day
47
48 def month(self):
49 return self.to_py_date().month
50
51 def year(self):
52 return self.to_py_date().year
4453
45 def to_readable_string(self):54 def to_readable_string(self):
46 if self.to_py_date() == NoDate().to_py_date():55 if self.to_py_date() == NoDate().to_py_date():
47 return None56 return None
48 dleft = (self.to_py_date() - date.today()).days57 dleft = (self.to_py_date() - date.today()).days
49 if dleft == 0:58 if not dleft:
50 return _("Today")59 return _("Today")
51 elif dleft < 0:60 elif dleft < 0:
52 abs_days = abs(dleft)61 abs_days = abs(dleft)
53 return ngettext("Yesterday", "%(days)d days ago", abs_days) % \62 return ngettext("Yesterday", "%(days)d days ago", abs_days) % \
54 {"days": abs_days}63 {"days": abs_days}
55 elif dleft > 0 and dleft <= 15:64 elif 0 < dleft <= 15:
56 return ngettext("Tomorrow", "In %(days)d days", dleft) % \65 return ngettext("Tomorrow", "In %(days)d days", dleft) % \
57 {"days": dleft}66 {"days": dleft}
58 else:67 else:
59 locale_format = self.__get_locale_string()68 locale_format = self.__get_locale_string()
60 if calendar.isleap(date.today().year):69 year_len = 365 + int(calendar.isleap(date.today().year))
61 year_len = 366
62 else:
63 year_len = 365
64 if float(dleft) / year_len < 1.0:70 if float(dleft) / year_len < 1.0:
65 #if it's in less than a year, don't show the year field71 #if it's in less than a year, don't show the year field
66 locale_format = locale_format.replace('/%Y','')72 locale_format = locale_format.replace('/%Y', '')
67 return self.to_py_date().strftime(locale_format)73 return self.to_py_date().strftime(locale_format)
6874
6975
70class FuzzyDate(Date):76class FuzzyDate(Date):
77
71 def __init__(self, offset, name):78 def __init__(self, offset, name):
72 super(FuzzyDate, self).__init__()79 super(FuzzyDate, self).__init__()
73 self.name=name80 self.name = name
74 self.offset=offset81 self.offset = offset
75 82
76 def to_py_date(self):83 def to_py_date(self):
77 return date.today()+timedelta(self.offset)84 return date.today() + timedelta(self.offset)
78 85
79 def __str__(self):86 def __str__(self):
80 return _(self.name)87 return _(self.name)
81 88
82 def to_readable_string(self):89 def to_readable_string(self):
83 return _(self.name)90 return _(self.name)
84 91
85 def xml_str(self):92 def xml_str(self):
86 return self.name93 return self.name
87 94
88 def days_left(self):95 def days_left(self):
89 return None96 return None
90 97
98
91class FuzzyDateFixed(FuzzyDate):99class FuzzyDateFixed(FuzzyDate):
92 def to_py_date(self):100
93 return self.offset101 def to_py_date(self):
102 return self.offset
94103
95NOW = FuzzyDate(0, _('now'))104NOW = FuzzyDate(0, _('now'))
96SOON = FuzzyDate(15, _('soon'))105SOON = FuzzyDate(15, _('soon'))
97LATER = FuzzyDateFixed(date.max, _('later'))106LATER = FuzzyDateFixed(date.max, _('later'))
98107
108
99class RealDate(Date):109class RealDate(Date):
110
100 def __init__(self, dt):111 def __init__(self, dt):
101 super(RealDate, self).__init__()112 super(RealDate, self).__init__()
102 assert(dt is not None)113 assert(dt is not None)
103 self.proto = dt114 self.proto = dt
104 115
105 def to_py_date(self):116 def to_py_date(self):
106 return self.proto117 return self.proto
107 118
108 def __str__(self):119 def __str__(self):
109 return str(self.proto)120 return str(self.proto)
110121
111 def days_left(self):122 def days_left(self):
112 return (self.proto - date.today()).days123 return (self.proto - date.today()).days
113 124
114DATE_MAX_MINUS_ONE = date.max-timedelta(1) # sooner than 'later'125DATE_MAX_MINUS_ONE = date.max - timedelta(1) # sooner than 'later'
126
127
115class NoDate(Date):128class NoDate(Date):
116129
117 def __init__(self):130 def __init__(self):
@@ -119,54 +132,59 @@
119132
120 def to_py_date(self):133 def to_py_date(self):
121 return DATE_MAX_MINUS_ONE134 return DATE_MAX_MINUS_ONE
122 135
123 def __str__(self):136 def __str__(self):
124 return ''137 return ''
125 138
126 def days_left(self):139 def days_left(self):
127 return None140 return None
128 141
129 def __nonzero__(self):142 def __nonzero__(self):
130 return False 143 return False
144
131no_date = NoDate()145no_date = NoDate()
132146
133#function to convert a string of the form YYYY-MM-DD147def strtodate(stri):
134#to a date148 """Funct to convert a string of the form YYYY-MM-DD or "now", "soon" and
135#If the date is not correct, the function returns None149 "later" and localized versions to a date.
136def strtodate(stri) :150 If the date is not correct, funct returns None."""
137 if stri == _("now") or stri == "now":151 # Added this line to avoid unecessary calculations and indentation.
152 if not stri:
153 return None
154
155 if stri in (_("now"), "now"):
138 return NOW156 return NOW
139 elif stri == _("soon") or stri == "soon":157 elif stri in (_("soon"), "soon"):
140 return SOON158 return SOON
141 elif stri == _("later") or stri == "later":159 elif stri in (_("later"), "later"):
142 return LATER160 return LATER
143 161
144 toreturn = None162 toreturn = None
145 zedate = []163 zedate = []
146 if stri :164
147 if '-' in stri :165 if '-' in stri:
148 zedate = stri.split('-')166 zedate = stri.split('-')
149 elif '/' in stri :167 elif '/' in stri:
150 zedate = stri.split('/')168 zedate = stri.split('/')
151 169
152 if len(zedate) == 3 :170 if len(zedate) == 3:
153 y = zedate[0]171 y, m, d = zedate[:3]
154 m = zedate[1]172 if y.isdigit() and m.isdigit() and d.isdigit():
155 d = zedate[2]173 yy = int(y)
156 if y.isdigit() and m.isdigit() and d.isdigit() :174 mm = int(m)
157 yy = int(y)175 dd = int(d)
158 mm = int(m)176 # we catch exceptions here
159 dd = int(d)177 try:
160 # we catch exceptions here178 toreturn = date(yy, mm, dd)
161 try :179 except ValueError:
162 toreturn = date(yy,mm,dd)180 toreturn = None
163 except ValueError:181
164 toreturn = None182 if not toreturn:
165 183 return no_date
166 if not toreturn: return no_date184 else:
167 else: return RealDate(toreturn)185 return RealDate(toreturn)
168 186
169 187
170def date_today():188def date_today():
171 return RealDate(date.today())189 return RealDate(date.today())
172190
@@ -175,29 +193,22 @@
175 Transform "arg" in a valid yyyy-mm-dd date or return None.193 Transform "arg" in a valid yyyy-mm-dd date or return None.
176 "arg" can be a yyyy-mm-dd, yyyymmdd, mmdd, today, next week,194 "arg" can be a yyyy-mm-dd, yyyymmdd, mmdd, today, next week,
177 next month, next year, or a weekday name.195 next month, next year, or a weekday name.
178 Literals are accepted both in english and in the locale language.
179 When clashes occur the locale takes precedence.
180 """196 """
181 today = date.today()197 today = date.today()
182 #FIXME: there surely exist a way to get day names from the datetime198 # Next line was mostly taken from calendar module, it's the way they
183 # or time module.199 # get the full days name (Not localized.)
184 day_names = ["monday", "tuesday", "wednesday", \200 day_names = [date(2001, 1, i + 1).strftime('%A') for i in xrange(7)]
185 "thursday", "friday", "saturday", \201 # This line gets the localized name, so it avoids having +7 strings in
186 "sunday"]202 # each language.
187 day_names_localized = [_("monday"), _("tuesday"), _("wednesday"), \203 day_names_localized = [day for day in calendar.day_name]
188 _("thursday"), _("friday"), _("saturday"), \
189 _("sunday")]
190 delta_day_names = {"today": 0, \204 delta_day_names = {"today": 0, \
191 "tomorrow": 1, \205 "tomorrow": 1, \
192 "next week": 7, \206 "next week": 7, \
193 "next month": calendar.mdays[today.month], \207 "next month": calendar.mdays[today.month], \
194 "next year": 365 + int(calendar.isleap(today.year))}208 "next year": 365 + int(calendar.isleap(today.year))}
195 delta_day_names_localized = \209 # For next line there's a more elegant way to do it but it's 2.7
196 {_("today"): 0, \210 # only. Infact dict comprehensions doesn't exist before that.
197 _("tomorrow"): 1, \211 delta_day_names_localized = dict([(_(delta), i) for delta, i in delta_day_names.iteritems()])
198 _("next week"): 7, \
199 _("next month"): calendar.mdays[today.month], \
200 _("next year"): 365 + int(calendar.isleap(today.year))}
201 ### String sanitization212 ### String sanitization
202 arg = arg.lower()213 arg = arg.lower()
203 ### Conversion214 ### Conversion
@@ -208,23 +219,22 @@
208 assert(len(arg) == 8)219 assert(len(arg) == 8)
209 arg = "%s-%s-%s" % (arg[:4], arg[4:6], arg[6:])220 arg = "%s-%s-%s" % (arg[:4], arg[4:6], arg[6:])
210 #today, tomorrow, next {week, months, year}221 #today, tomorrow, next {week, months, year}
211 elif arg in delta_day_names.keys() or \222 elif arg in delta_day_names.keys() or \
212 arg in delta_day_names_localized.keys():223 arg in delta_day_names_localized.keys():
213 if arg in delta_day_names:224 if arg in delta_day_names:
214 delta = delta_day_names[arg]225 delta = delta_day_names[arg]
215 else:226 else:
216 delta = delta_day_names_localized[arg]227 delta = delta_day_names_localized[arg]
217 arg = (today + timedelta(days = delta)).isoformat()228 arg = (today + timedelta(days=delta)).isoformat()
218 elif arg in day_names or arg in day_names_localized:229 elif arg in day_names or arg in day_names_localized:
219 if arg in day_names:230 if arg in day_names:
220 arg_day = day_names.index(arg)231 arg_day = day_names.index(arg)
221 else:232 else:
222 arg_day = day_names_localized.index(arg)233 arg_day = day_names_localized.index(arg)
223 today_day = today.weekday()234 today_day = today.weekday()
224 next_date = timedelta(days = arg_day - today_day + \235 next_date = timedelta(days=arg_day - today_day + \
225 7 * int(arg_day <= today_day)) + today236 7 * int(arg_day <= today_day)) + today
226 arg = "%i-%i-%i" % (next_date.year, \237 arg = "%i-%i-%i" % (next_date.year, \
227 next_date.month, \238 next_date.month, \
228 next_date.day)239 next_date.day)
229 return strtodate(arg)240 return strtodate(arg)
230

Subscribers

People subscribed via source and target branches

to status/vote changes: