Merge lp:~stefanor/ibid/factoid-495700 into lp:~ibid-core/ibid/old-trunk-1.6
- factoid-495700
- Merge into old-trunk-1.6
Proposed by
Stefano Rivera
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Jonathan Hitchcock | ||||
Approved revision: | not available | ||||
Merged at revision: | 801 | ||||
Proposed branch: | lp:~stefanor/ibid/factoid-495700 | ||||
Merge into: | lp:~ibid-core/ibid/old-trunk-1.6 | ||||
Diff against target: |
317 lines (+117/-60) 3 files modified
ibid/plugins/factoid.py (+104/-54) ibid/plugins/log.py (+1/-1) scripts/ibid-factpack (+12/-5) |
||||
To merge this branch: | bzr merge lp:~stefanor/ibid/factoid-495700 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jonathan Hitchcock | Approve | ||
Michael Gorven | Approve | ||
Review via email: mp+16073@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
lp:~stefanor/ibid/factoid-495700
updated
- 797. By Stefano Rivera
-
Remove some redundant code
lp:~stefanor/ibid/factoid-495700
updated
- 798. By Stefano Rivera
-
gettatr doesn't work as expected on events
Revision history for this message
Jonathan Hitchcock (vhata) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'ibid/plugins/factoid.py' |
2 | --- ibid/plugins/factoid.py 2009-12-11 22:38:52 +0000 |
3 | +++ ibid/plugins/factoid.py 2009-12-14 13:43:11 +0000 |
4 | @@ -4,11 +4,13 @@ |
5 | import re |
6 | |
7 | from dateutil.tz import tzlocal, tzutc |
8 | -from sqlalchemy import Column, Integer, Unicode, DateTime, ForeignKey, UnicodeText, Table, or_ |
9 | -from sqlalchemy.orm import relation |
10 | +from sqlalchemy import Column, Table, ForeignKey, or_, Boolean, Integer, \ |
11 | + Unicode, UnicodeText, DateTime |
12 | +from sqlalchemy.orm import relation, synonym |
13 | from sqlalchemy.sql import func |
14 | |
15 | -from ibid.plugins import Processor, match, handler, authorise, auth_responses, RPC |
16 | +from ibid.plugins import Processor, match, handler, authorise, auth_responses, \ |
17 | + RPC |
18 | from ibid.config import Option, IntOption, ListOption |
19 | from ibid.plugins.identity import get_identities |
20 | from ibid.models import Base, VersionedSchema |
21 | @@ -24,17 +26,27 @@ |
22 | default_interrogatives = ('what', 'wtf', 'where', 'when', 'who', "what's", "who's") |
23 | |
24 | def strip_name(unstripped): |
25 | + "Apply to factoid names, as we use unstripped matches" |
26 | return re.match(r'^\s*(.*?)[?!.]*\s*$', unstripped, re.DOTALL).group(1) |
27 | |
28 | +def escape_name(name): |
29 | + "Turn a $arg factoid name to _%" |
30 | + return name.replace('%', '\\%').replace('_', '\\_').replace('$arg', '_%') |
31 | + |
32 | +def unescape_name(name): |
33 | + "Turn a _% factoid name to $arg" |
34 | + return name.replace('_%', '$arg').replace('\\%', '%').replace('\\_', '_') |
35 | + |
36 | class FactoidName(Base): |
37 | __table__ = Table('factoid_names', Base.metadata, |
38 | Column('id', Integer, primary_key=True), |
39 | - Column('name', UnicodeText, nullable=False, unique=True, index=True, |
40 | - info={'ibid_mysql_index_length': 32}), |
41 | + Column('name', UnicodeText, key='_name', nullable=False, unique=True, index=True, |
42 | + info={'ibid_mysql_index_length': 32}), |
43 | Column('factoid_id', Integer, ForeignKey('factoids.id'), nullable=False, index=True), |
44 | Column('identity_id', Integer, ForeignKey('identities.id'), index=True), |
45 | Column('time', DateTime, nullable=False), |
46 | Column('factpack', Integer, ForeignKey('factpacks.id'), index=True), |
47 | + Column('wild', Boolean, nullable=False, default=False, index=True), |
48 | useexisting=True) |
49 | |
50 | class FactoidNameSchema(VersionedSchema): |
51 | @@ -48,12 +60,25 @@ |
52 | self.add_index(self.table.c.identity_id) |
53 | self.add_index(self.table.c.factpack) |
54 | def upgrade_4_to_5(self): |
55 | - self.alter_column(Column('name', Unicode(64), nullable=False, unique=True, index=True)) |
56 | + self.alter_column(Column('name', Unicode(64), key='_name', nullable=False, |
57 | + unique=True, index=True)) |
58 | def upgrade_5_to_6(self): |
59 | - self.alter_column(Column('name', UnicodeText, nullable=False, |
60 | - unique=True, index=True, info={'ibid_mysql_index_length': 32})) |
61 | + self.alter_column(Column('name', UnicodeText, key='_name', nullable=False, |
62 | + unique=True, index=True, |
63 | + info={'ibid_mysql_index_length': 32})) |
64 | + def upgrade_6_to_7(self): |
65 | + self.add_column(Column('wild', Boolean, nullable=False, index=True, |
66 | + default=False, server_default='0')) |
67 | + # http://www.sqlalchemy.org/trac/ticket/1400: |
68 | + # We can't use .like() in MySQL |
69 | + for row in self.upgrade_session.query(FactoidName) \ |
70 | + .filter('name LIKE :pattern ESCAPE :escape') \ |
71 | + .params(pattern='%\\_\\%%', escape='\\') \ |
72 | + .all(): |
73 | + row.wild = True |
74 | + self.upgrade_session.save_or_update(row) |
75 | |
76 | - __table__.versioned_schema = FactoidNameSchema(__table__, 6) |
77 | + __table__.versioned_schema = FactoidNameSchema(__table__, 7) |
78 | |
79 | def __init__(self, name, identity_id, factoid_id=None, factpack=None): |
80 | self.name = name |
81 | @@ -65,6 +90,15 @@ |
82 | def __repr__(self): |
83 | return u'<FactoidName %s %s>' % (self.name, self.factoid_id) |
84 | |
85 | + def _get_name(self): |
86 | + return unescape_name(self._name) |
87 | + |
88 | + def _set_name(self, name): |
89 | + self.wild = u'$arg' in name |
90 | + self._name = escape_name(name) |
91 | + |
92 | + name = synonym('_name', descriptor=property(_get_name, _set_name)) |
93 | + |
94 | class FactoidValue(Base): |
95 | __table__ = Table('factoid_values', Base.metadata, |
96 | Column('id', Integer, primary_key=True), |
97 | @@ -142,13 +176,8 @@ |
98 | reply_re = re.compile(r'^\s*<reply>\s*') |
99 | escape_like_re = re.compile(r'([%_\\])') |
100 | |
101 | -def escape_name(name): |
102 | - return name.replace('%', '\\%').replace('_', '\\_').replace('$arg', '_%') |
103 | - |
104 | -def unescape_name(name): |
105 | - return name.replace('_%', '$arg').replace('\\%', '%').replace('\\_', '_') |
106 | - |
107 | -def get_factoid(session, name, number, pattern, is_regex, all=False, literal=False): |
108 | +def get_factoid(session, name, number, pattern, is_regex, all=False, |
109 | + literal=False): |
110 | """session: SQLAlchemy session |
111 | name: Factoid name (can contain arguments unless literal query) |
112 | number: Return factoid[number] (or factoid[number:] for literal queries) |
113 | @@ -157,34 +186,55 @@ |
114 | all: Return a random factoid from the set if False |
115 | literal: Match factoid name literally (implies all) |
116 | """ |
117 | - factoid = None |
118 | - # Reversed LIKE because factoid name contains SQL wildcards if factoid supports arguments |
119 | - query = session.query(Factoid)\ |
120 | - .add_entity(FactoidName).join(Factoid.names)\ |
121 | - .add_entity(FactoidValue).join(Factoid.values) |
122 | + # First pass for exact matches, if necessary again for wildcard matches |
123 | if literal: |
124 | - query = query.filter(func.lower(FactoidName.name)==escape_name(name).lower()) |
125 | - else: |
126 | - query = query.filter(":fact LIKE name ESCAPE :escape").params(fact=name, escape='\\') |
127 | - if pattern: |
128 | - if is_regex: |
129 | - query = query.filter(FactoidValue.value.op('REGEXP')(pattern)) |
130 | - else: |
131 | - pattern = "%%%s%%" % escape_like_re.sub(r'\\\1', pattern) |
132 | - # http://www.sqlalchemy.org/trac/ticket/1400: We can't use .like() in MySQL |
133 | - query = query.filter('value LIKE :pattern ESCAPE :escape').params(pattern=pattern, escape='\\') |
134 | - if number: |
135 | - try: |
136 | - if literal: |
137 | - return query.order_by(FactoidValue.id)[int(number) - 1:] |
138 | - else: |
139 | - factoid = query.order_by(FactoidValue.id)[int(number) - 1] |
140 | - except IndexError: |
141 | - return |
142 | - if all or literal: |
143 | - return factoid and [factoid] or query.all() |
144 | - else: |
145 | - return factoid or query.order_by(func.random()).first() |
146 | + passes = (False,) |
147 | + else: |
148 | + passes = (False, True) |
149 | + for wild in passes: |
150 | + factoid = None |
151 | + query = session.query(Factoid)\ |
152 | + .add_entity(FactoidName).join(Factoid.names)\ |
153 | + .add_entity(FactoidValue).join(Factoid.values) |
154 | + if wild: |
155 | + # Reversed LIKE because factoid name contains SQL wildcards if |
156 | + # factoid supports arguments |
157 | + query = query.filter(':fact LIKE name ESCAPE :escape') \ |
158 | + .params(fact=name, escape='\\') |
159 | + else: |
160 | + query = query.filter(func.lower(FactoidName.name) \ |
161 | + == escape_name(name).lower()) |
162 | + # For normal matches, restrict to the subset applicable |
163 | + if not literal: |
164 | + query = query.filter(FactoidName.wild == wild) |
165 | + |
166 | + if pattern: |
167 | + if is_regex: |
168 | + query = query.filter(FactoidValue.value.op('REGEXP')(pattern)) |
169 | + else: |
170 | + pattern = '%%%s%%' % escape_like_re.sub(r'\\\1', pattern) |
171 | + # http://www.sqlalchemy.org/trac/ticket/1400: |
172 | + # We can't use .like() in MySQL |
173 | + query = query.filter('value LIKE :pattern ESCAPE :escape') \ |
174 | + .params(pattern=pattern, escape='\\') |
175 | + |
176 | + if number: |
177 | + try: |
178 | + if literal: |
179 | + return query.order_by(FactoidValue.id)[int(number) - 1:] |
180 | + else: |
181 | + factoid = query.order_by(FactoidValue.id)[int(number) - 1] |
182 | + except IndexError: |
183 | + continue |
184 | + if all or literal: |
185 | + if factoid is not None: |
186 | + return [factoid] |
187 | + else: |
188 | + factoid = query.all() |
189 | + else: |
190 | + factoid = factoid or query.order_by(func.random()).first() |
191 | + if factoid: |
192 | + return factoid |
193 | |
194 | class Utils(Processor): |
195 | u"""literal <name> [( #<from number> | /<pattern>/[r] )]""" |
196 | @@ -286,7 +336,7 @@ |
197 | event.addresponse(u"I already know stuff about %s", target) |
198 | return |
199 | |
200 | - name = FactoidName(escape_name(unicode(target)), event.identity) |
201 | + name = FactoidName(unicode(target), event.identity) |
202 | factoid.names.append(name) |
203 | event.session.save_or_update(factoid) |
204 | event.session.commit() |
205 | @@ -347,7 +397,9 @@ |
206 | matches = [match for match in query[start:start+limit]] |
207 | |
208 | if matches: |
209 | - event.addresponse(u'; '.join(u'%s [%s]' % (unescape_name(fname.name), len(factoid.values)) for factoid, fname in matches)) |
210 | + event.addresponse(u'; '.join( |
211 | + u'%s [%s]' % (fname.name, len(factoid.values)) |
212 | + for factoid, fname in matches)) |
213 | else: |
214 | event.addresponse(u"I couldn't find anything that matched '%s'" % origpattern) |
215 | |
216 | @@ -401,14 +453,12 @@ |
217 | if factoid: |
218 | (factoid, fname, fvalue) = factoid |
219 | reply = fvalue.value |
220 | - pattern = re.escape(fname.name).replace(r'\_\%', '(.*)').replace('\\\\\\%', '%').replace('\\\\\\_', '_') |
221 | + oname = fname.name |
222 | + pattern = re.escape(fname.name).replace(r'\$arg', '(.*)') |
223 | |
224 | - position = 1 |
225 | - for capture in re.match(pattern, name, re.I).groups(): |
226 | - if capture.startswith('$arg'): |
227 | - return |
228 | - reply = reply.replace('$%s' % position, capture) |
229 | - position = position + 1 |
230 | + for i, capture in enumerate(re.match(pattern, name, re.I).groups()): |
231 | + reply = reply.replace('$%s' % (i + 1), capture) |
232 | + oname = oname.replace('$arg', capture, 1) |
233 | |
234 | reply = _interpolate(reply, event) |
235 | |
236 | @@ -420,7 +470,7 @@ |
237 | if count: |
238 | return {'address': False, 'reply': reply} |
239 | |
240 | - reply = u'%s %s' % (unescape_name(fname.name), reply) |
241 | + reply = u'%s %s' % (oname, reply) |
242 | return reply |
243 | |
244 | class Set(Processor): |
245 | @@ -473,7 +523,7 @@ |
246 | return |
247 | else: |
248 | factoid = Factoid() |
249 | - fname = FactoidName(escape_name(unicode(name)), event.identity) |
250 | + fname = FactoidName(unicode(name), event.identity) |
251 | factoid.names.append(fname) |
252 | event.session.save_or_update(factoid) |
253 | event.session.flush() |
254 | |
255 | === modified file 'ibid/plugins/log.py' |
256 | --- ibid/plugins/log.py 2009-12-11 14:26:39 +0000 |
257 | +++ ibid/plugins/log.py 2009-12-14 13:43:11 +0000 |
258 | @@ -64,7 +64,7 @@ |
259 | |
260 | file = open(filename, 'a') |
261 | self.logs[filename] = file |
262 | - if getattr(event, 'public', True): |
263 | + if event.get('public', True): |
264 | chmod(filename, int(self.public_mode, 8)) |
265 | else: |
266 | chmod(filename, int(self.private_mode, 8)) |
267 | |
268 | === modified file 'scripts/ibid-factpack' |
269 | --- scripts/ibid-factpack 2009-10-19 15:07:40 +0000 |
270 | +++ scripts/ibid-factpack 2009-12-14 13:43:11 +0000 |
271 | @@ -9,7 +9,8 @@ |
272 | import ibid |
273 | from ibid.compat import json |
274 | from ibid.config import FileConfig |
275 | -from ibid.plugins.factoid import Factoid, FactoidName, FactoidValue, Factpack, escape_name |
276 | +from ibid.plugins.factoid import Factoid, FactoidName, FactoidValue, Factpack, \ |
277 | + escape_name |
278 | |
279 | parser = OptionParser(usage=u'%prog <factpack>') |
280 | parser.add_option('-r', '--remove', action='store_true', help='Remove the named factpack from the database') |
281 | @@ -45,7 +46,8 @@ |
282 | session.delete(factoid) |
283 | |
284 | if extras and not options.force: |
285 | - print >> stderr, u'The following factoid entries have been added. Use -f to force removal.' |
286 | + print >> stderr, u'The following factoid entries have been added. ' \ |
287 | + u'Use -f to force removal.' |
288 | for extra in extras: |
289 | print extra |
290 | exit(6) |
291 | @@ -80,10 +82,13 @@ |
292 | for names, values in facts: |
293 | factoid = Factoid(factpack.id) |
294 | for name in names: |
295 | - if session.query(FactoidName).filter(func.lower(FactoidName.name)==escape_name(name).lower()).first(): |
296 | + if session.query(FactoidName) \ |
297 | + .filter(func.lower(FactoidName.name) |
298 | + == escape_name(name).lower()) \ |
299 | + .first(): |
300 | existing.append(name) |
301 | continue |
302 | - fname = FactoidName(escape_name(unicode(name)), None, factpack=factpack.id) |
303 | + fname = FactoidName(unicode(name), None, factpack=factpack.id) |
304 | factoid.names.append(fname) |
305 | for value in values: |
306 | fvalue = FactoidValue(unicode(value), None, factpack=factpack.id) |
307 | @@ -92,7 +97,9 @@ |
308 | session.save(factoid) |
309 | |
310 | if existing and not options.skip: |
311 | - print >> stderr, u'The following factoids already exist in the database. Please remove them before importing this factpack, or use -s to skip them' |
312 | + print >> stderr, u'The following factoids already exist in the database. ' \ |
313 | + u'Please remove them before importing this factpack, ' \ |
314 | + u'or use -s to skip them' |
315 | for name in existing: |
316 | print >> stderr, name |
317 | session.rollback() |
review approve