[00:26:45] ** _Maniac_ has joined us [00:52:28] ** _Maniac_ has joined us [02:07:17] ** gpciceri has joined us [02:20:20] ** _Maniac_ has joined us [02:47:45] ** _Maniac_ has joined us [04:32:26] jack-e|away is now known as jack-e [04:32:32] morning [04:33:08] good morning [06:02:58] ** gpciceri has joined us [07:46:45] ** vlado_ has joined us [09:14:28] ** vlado_ has joined us [10:13:33] _Maniac_ is now known as Maniac [10:45:30] ** rdmurray has joined us [11:39:05] ** _Maniac_ has joined us [11:59:30] _Maniac_ is now known as Maniac [12:09:13] ** gpciceri has joined us [13:07:55] sqlite does support \describe to get a list of tables.... [13:11:30] ** jack-e has joined us [13:11:59] ** gpciceri has joined us [14:20:44] ** _Maniac_ has joined us [14:21:43] jack-e is now known as jack-e|away [14:35:21] ** vlado has joined us [14:48:53] * vlado is away, somewhere far beyond... (l!on)(p!off) [cRk/bx] [15:10:35] maniac: So it does. I think what happened was I tried it when I was having a problem, and it returned nothing, so I thought it didn't work. Later, having forgotten about having tried \describe, I figured out I'd made a typo in the database name. So that \describe I tried gave the correct output: there were no tables in the database I was accessing :) [15:30:15] There, the print references in helloworld are all fixed. [15:30:58] <_Maniac_> wow my client died [15:31:21] The Internet hasn't been a very stable place for you lately, has it? :) [15:31:25] <_Maniac_> grr [15:31:31] <_Maniac_> no, i keep getting disconnected [15:31:48] <_Maniac_> i've been chasing my ISP.. changed routers, generally complained alot. [15:32:02] <_Maniac_> to make a short story shorter. they have no idea what the problem is [15:32:23] <_Maniac_> anywho, what i typed into my client that never made it to the channel: [15:32:42] <_Maniac_> i checked the source on sqlite. postgresql does not have \describe yet [15:32:56] _Maniac_ is now known as Maniac [15:34:20] so helloworld is becoming "the evolution of a peak application STARTING with helloworld" [15:35:10] Something like that :) [15:35:41] We could subtitle it, "A Story of Feature Creep" [15:36:41] I just found out that two of the examples don't work yet, presumably because PJE hasn't checked in the code. [15:37:11] oo [15:38:06] * = commands.NoSuchSubCommand, and acceptURLs = False. [15:41:08] Hmm. Time to go shovel snow off my roof [15:41:10] recent cvs checkings [15:41:15] cvs up! [15:41:19] I just did [15:41:32] Just before I typed that. And I did a python setup.py install, too [15:41:33] i thought i saw commit messages that referenced those ones... [15:41:40] There should have been, certainly. [15:41:52] where do you live (that you have snow?) [15:41:59] New Hampshire [15:42:14] ah, we have very little here still... Winnipeg,Manitoba Canada [15:42:47] Yeah, this one came up from the south. Massechusettes actually got more. [15:43:00] Boy, I can't spell that state to save my ilfe. [15:43:03] life even. [15:43:18] Anyway, back in a few. [16:00:06] ** _jpl_ has joined us [16:00:34] hi _jpl_ [16:01:28] <_jpl_> [16:02:41] <_jpl_> [16:06:01] ** _jpl_ has left us [16:09:55] adapt(_jpl_,ILiveChatter).hello() [16:10:56] I decided to only do the (small) roof that was at the most risk from the coming rain. [16:16:16] NameError: name '_jpl_' is not defined [16:34:41] TypeError: Invalid keyword argument for advising classes: moduleProvides [16:34:44] yuk [16:37:47] you must call protocols.advise() with moduleProvides in module not in class [16:39:06] for classes use instancesProvide or classProvides [16:47:41] aha! [16:55:39] ** gpciceri has joined us [16:59:01] vlado is now known as vlado|zzzzzzzzzz [17:02:30] ** pje has joined us [17:02:43] rdmurray, I checked the code in for that stuff yesterday. [17:03:26] See e.g. http://cvs.eby-sarna.com/PEAK/src/peak/running/commands.py.diff?r1=1.44&r2=1.45 [17:03:57] It was in CVS before I saved the changes to the page. [17:07:28] Hmm. So why didn't I pick up the update :( [17:09:13] Hrmpf. [17:09:27] I re-did the cvs up and setup.py install, and now it works. [17:09:41] * rdmurray decides to turn up the radio on that one. [17:10:30] * Maniac can't get his plugins to work... [17:10:34] Dunno. [17:10:45] The anon CVS is updated every 5 minutes from the "real" CVS. [17:10:49] i did the code as we discussed yesterday [17:11:06] where in the class would i call binding.Make(plugins) [17:11:31] def plugins(self): [17:11:33] .... [17:11:39] plugins = binding.Make(plugins) [17:11:54] Think of it as being like classmethod or staticmethod or property. [17:12:13] It's a descriptor, just like them. [17:12:54] rdmurray, what did you mean by "turn up the radio"? [17:13:42] Oh, that's an expression one of my old coworkers used. It means something like "I'm going to pretend I didn't notice that anomolous behavior, in the hopes that it will never happen again" [17:14:01] what error do you get if it can't adapt()? [17:15:53] NotImplemented? [17:16:00] Maniac, yes. [17:16:06] NotImplementedError, to be precise. [17:16:14] like what we have works but when i have a module that does not conform to the interface i get a traceback [17:16:34] Well, there's a couple different ways to deal with that. [17:16:49] E.g. adapt(aModule,IWhatever,None), and if m is None: continue [17:17:07] Or.. adapt(aModule,IWhatever,NullPluginProvider) [17:17:22] ** Maniac has joined us [17:17:22] is there a way to advise() instances ? [17:17:36] vlado|zzzzzzzzzz: protocols.adviseObject() [17:17:47] pje: After reading your updates, I tried to implement acceptURLs = False. At first I tried to put that in the peak.commands.shortcuts section of the ini file, and it wasn't until that didn't work that I noticed that your text says to put it on the class. I'm not sure whether or not that means the text should emphasize that point :) [17:17:56] ah, thx [17:18:17] Maniac, did you get the two ways I mentioned? [17:18:42] There's also a third which is, "if people send you stuff that doesn't implement the interface, that *is* an error." [17:19:11] Better that they get an error message right away, then have their plugins silently not work. [17:19:16] yay! [17:19:18] def plugins(self): [17:19:18] plugins = [] [17:19:18] for m in self.modules: [17:19:18] try: [17:19:21] plugins.extend([factory() for factory in adapt(m,IBotPluginProvider).pluginFactories]) [17:19:23] except: [17:19:26] self.log.debug("%s does not appear to be a valid plugin" % m) [17:19:29] plugins.sort(self.pluginsCompare) [17:19:31] return plugins [17:19:35] rdmurray: Yeah, it should be clearer, I guess. [17:19:39] plugins = binding.Make(plugins) [17:19:39] Feel free to edit. :) [17:19:41] less lines or not isn't it more elegant? [17:20:11] bare excepts are evil. [17:20:27] You can catch errors that you don't intend to, like KeyboardInterrupt and such. [17:21:05] The only kind of code you want to trap errors in are framework-level things like reactors or other event loops, anyway. [17:21:16] Most everything else you want to break right away so that you know there's a problem. [17:21:25] IOW, if you don't look at the debug log, you're toast. [17:21:36] Heck, if you don't have debug logging enabled, you're toast. [17:21:44] At least use log.error or log.warning. :) [17:22:29] pje: meaning you aren't editing at the moment? [17:22:39] rdmurray, No... [17:22:49] pje, i think so (ie. get certainly the second) [17:22:50] I've been busy with tools.supervisor bugs and related issues all day. [17:23:39] Rolled out the new process manager to production today and all kinds of stuff broke. [17:23:52] (Despite the week-long beta test.) [17:23:54] you mean if it doesn't implement the interface is *should* traceback and die? [17:24:12] Maniac, that's what I'm saying. How will you know it's broken if it doesn't break? [17:24:32] PEAK follows that philosophy throughout. The sooner you get an error, the better. [17:24:34] well, i should change to except NotImplementedError ? [17:24:58] Maniac, how do you know the NotImplementedError wasn't raised in factory() [17:25:00] ? [17:25:06] not fair ! [17:25:32] What's not fair? [17:25:44] you are tricky [17:26:06] * Maniac is trying to think of any good reason to have modules in the modules directory that do not conform to the interface.... [17:26:07] What do you mean? [17:26:16] or plugins [17:26:29] I don't know how you get the modules. [17:26:35] I assumed they were passed in by somebody. [17:26:44] no, just globbing a directory [17:26:49] (currently) [17:27:33] Ah. Well, in that case you probably want to use the adapt(...,None) or adapt(...,NullPluginProvider) approach. [17:27:45] enlighten me sensei [17:27:50] The latter means you need an object called NullPluginProvider with an empty pluginFactories list. [17:28:29] e.g. class NullPluginProvider: pluginFactories=() [17:28:33] And that way your code just ignores modules that don't provide the interface. [17:28:41] If that's the behavior you want :) [17:28:44] Right, it treats them like they just provide no modules. [17:29:18] Er, no plugins. [17:29:28] I wish I had a faster gui browser than Mozilla. [17:31:15] adapt(...,NullPluginProvider) <---- what are the ....'s ? [17:32:07] adapt(component, protocol, [, default [, factory]]) so i'm just providing a default? [17:32:27] why not None? [17:32:47] Because None doesn't have a 'pluginFactories' attribute. [17:33:14] So you have to rewrite that nice list comprehension, or else use getattr. [17:34:01] If you use a null object (like NullPluginProvider), you can just access the attribute. [17:34:30] The best choice is highly context dependent. There are places in PEAK that don't use a default, places that use None, and places that use a null object. [17:35:06] Null object is most favorable when you have multiple methods or attributes on the interface. [17:35:07] ah [17:35:50] * Maniac doen't use list comprehensions unless they are handed to him on a platter [17:38:12] They aren't that hard, really :) [17:38:52] no, i've just recently discovered them :) [17:40:23] ah. [17:42:07] Hmm. Either I should have written these helloworld commands as IRerunnable's, or I've found a place to introduce pyprotocols, by writing a reverse adapter (ICmdLineApp -> IRerunnable). [17:42:12] works quite well now pje [17:42:37] and is more elegant and PEAKish at the same time [17:43:39] the idea is to write plugins that work for IRC 'bots' and jabber 'bots' [17:43:53] so adaptation lovin is good [17:45:08] You know, if you just use .ini or ZConfig files to specify plugins, you won't need to glob directories for modules. [17:46:17] Well, some people count being able to drop a plugin into a directory to "install" and active it as a feature :) [17:46:33] (I have mixed feelings, myself) [17:47:21] but i want to be able to drop plugins in and reload them dynamically without restarting the bot [17:47:25] * Maniac pokes rdmurray [17:48:38] Maniac: then modules are a really lousy way to do that. [17:48:51] teach me [17:49:01] You'd be better off with scripts that you run execfile() on. [17:49:07] If you use modules, reloading is a problem. [17:49:22] With scripts, there's no way for one script to depend on another. [17:49:29] But with modules, one module can import another. [17:49:41] When you reload, how will you be sure you've reloaded all the right modules? [17:49:53] you have to be carefull? [17:50:14] Say I have module A. Module A loads module B. [17:50:24] I notice that module B has changed on disk, so I reload it. [17:50:25] no, i understand the issue [17:50:33] But A is not reloaded. [17:50:38] A still has reference to B [17:50:53] Yep. It could e.g. subclass a class in B. [17:50:55] the modules must not reference each other [17:51:16] Right; if you use scripts instead of modules, there's no easy way for them to reference each other. [17:51:29] Except execfile, of course. [17:51:42] here's a sample plugin containing module: [17:51:44] http://randomthoughts.vandorp.ca/repos/projects/r [17:51:46] grr [17:51:48] OTOH, you could simply reload everything. [17:52:09] http://randomthoughts.vandorp.ca/repos/sandbox/jabberbot/modules/hello.py [17:52:49] i dont' think reloading everything is so simple is it? [17:55:13] Not necessarily, no. [17:55:35] Hence, my suggestion to execfile() them as scripts, instead. [17:56:03] You exec 'em in a dictionary, then pull pluginFactories out of the dictionary, and throw it (the dictionary) away. [17:56:28] If you want to restart the plugins, just throw away the old ones and re-exec the files. [17:56:35] Of course, that brings up a point... [17:56:55] If you were planning to reload them individually, how were you going to tell what module each plugin came from? [18:05:59] * pje is gonna head out [18:06:17] About to start a PC upgrade. [18:06:23] Laters, all. [18:06:30] bye [18:06:33] ** pje has left us [18:17:30] well i had'nt figured out how to reload them individually yet :) [18:21:46] mmm execfile could work i guess [18:22:40] but then i still dont' know how you would reload individul pluginss..... [18:23:01] you could re-execfile on 'modules' [18:23:18] that's what pje suggested, I believe. [18:23:39] Oh, individual [18:24:08] Well, you'd have to expand your plugins interface to support returning a source pointer, and record that somewhere, I suppose. [18:50:23] yeah [19:40:21] Hmm. Looks like there's a bug in my helloworld sql :( [19:58:16] Anyone know if peak's security system is only for the web stuff? [20:02:25] Hmm. This is a short chapter. [20:34:59] no, you can use peak.security for anything you please... [20:35:13] http://peak.telecommunity.com/DevCenter/ShortIntroPeakSecurity [20:37:10] That doesn't seem to be linked from the front page. [20:37:25] no, i wrote it and it hasn't been 'blessed' so i haven't linked it [20:37:39] Ah, I didn't realize things were supposed to get blessed. [20:37:55] no, it's also incomplete (lacking an explanation [20:37:56] ) [20:37:58] Nor did I know how to create a page without linking it :) [20:38:12] rdmurray, and they dont' have to be blessed :) [20:40:29] Do you know anything about the logging system? [20:41:17] not very much just how to use the basic logger [20:42:07] Well, what I'm wondering about is this 'logging.logger:' business. I don't get that at all. 'logfile:' I can understand, as well as the LogStream stuff. [20:44:23] Maybe I need to read PEP watzit. [20:55:48] lazy binding is cool [20:56:07] my 'bot' actually loads quicker now and doesn't load plugins until they try to get accessed [20:56:28] Heh. That's way cool :) [20:56:32] * Maniac cheers for lazy binding [20:56:44] i can imagine the difference this would make on 'real' applications [20:56:54] Yeah. [20:56:58] since i'm still just playing / learning :) [21:15:12] have the changes to binding (ie: the existence of binding.Obtain) occur after alpha2, or are they in alpha2? [21:22:53] this i do not know, check changes.txt [21:23:04] I am :) [21:23:05] i believe a3 [21:23:47] Yeah, looks like. [21:36:11] ** pje has joined us [21:36:24] rdmurray, we don't have syslog or logtee support ATM. [21:36:47] That's why they're listed in the TODO section of the logs module. :) [21:37:57] Btw, I'd like to start splitting the tutorial into separate pages. [21:38:36] I'm figuring I'll start a new page IntroToPeak, and give it sub-pages LessonOne, LessonTwo, etc. [21:51:01] wb pje [21:59:02] one big long page is intimidating [22:02:25] Yep. [22:02:47] I hope he isn't editing that page right now, since I'm busy carving it up into lessons... [22:16:01] rdmurray!!!!! [22:23:15] Okay, splitting is done... [22:23:21] The new page is IntroToPeak [22:23:50] Now if only I had time to keep working on the actual editing... [22:24:06] He's already two and a half lessons ahead of me. :) [22:24:13] Gotta run; see y'all later. [22:24:19] ** pje has left us [23:55:48] ** hazmat has joined us