[00:00:23] nm, figured it as much as I needed to know by experiement. [03:37:37] ** jack-e has joined us [03:41:00] morning [03:41:16] Morning. Time for me to go to sleep :) [03:41:30] hey .. i just got up :) [03:44:10] I have a feeling PJE is going to have a *lot* of editing to do on this chapter. [03:50:24] ** vlado_ has joined us [03:50:32] morning [03:57:11] It's kind of amazing how far you can push Hello, World! I actually found myself needing to rewrite the domain model at the end of the last chapter, and that produced some useful new examples :) [03:58:07] Well, I need to go to bed before the sun comes up here. Maybe I'll catch you guys later on again. [05:00:10] ** vlado__ has joined us [09:04:29] ** vlado has joined us [09:37:50] ** vlado__ has joined us [10:38:31] ** gpciceri has joined us [10:49:06] ** kh has joined us [10:51:28] hello all ! [10:52:05] i just clued in gpciceri must be Gian Paolo Ciceri [10:56:22] Maniac: you are right [10:56:46] and you don't answer my jabber subscription request :-) [11:00:09] * Maniac just noticed it now that you mentioned it! [11:00:16] there ! [11:00:39] Maniac: done! [11:00:52] * Maniac is working... So i IRC during break :) [11:01:03] this is the place to learn about peak :) [11:01:31] did you get my message re:utf8? [11:01:55] Maniac: yes, but I didn't understand what to change in the code [11:02:08] me either :) [11:02:24] ok well, i'm not sure of the wisdom in logging all message contents [11:02:36] that's where the log is breaking [11:02:41] Maniac: o.k., I was starting feeling *very* stupid [11:03:29] the message starts as unicode, I suppose. I use italian letters like òàùùàò [11:03:50] and somewhere it's translated in a plain string, I suppose [11:04:18] well, i don't know if the twisted jabber code is doing something there too or not [11:04:24] so when the bot logs it takes the error [11:05:01] i don't know very much about unicode or utf8 [11:05:37] perhaps forcing the message to unicode before logging it should help [11:05:38] how easy did you find it to follow the peak stuff. like binding.Make and binding.Obtain etc.? [11:06:13] well, I discovered peak 3 days ago, indipendently from your bot [11:06:27] it seems reasonable [11:06:42] and rather powerful [11:07:54] yes, the 'bot' was an experiment in both peak and twisted.jabber [11:08:03] I've not studied the peak-dependent part of your bot deeply, but it's quite readable [11:08:30] (IMO it's most a python merit, of course) [11:08:35] yes [11:09:05] if you want to get 'up-to-speed' on some peak concepts there's some neat stuff going up on the wiki referenced in the topic title [11:09:35] * Maniac has to return to 'working' so i'll check in here occasionally [11:09:42] sure, I've lurked [11:10:10] and by way of introduction jack-e is also a peak user and a *much* better programmer than I and quite a 'peak' expert [11:10:21] :) [11:10:31] * Maniac pokes jack-e with a sharp stick [11:10:43] jack-e, how did your weekend go? [11:10:51] * Maniac goes to get cofee [11:17:30] * jack-e hides from Maniac being nasty [11:20:47] Maniac: ohh well .. our weekend .. it started out fairly slow .. and i nearly fell asleep at our meeting-place fr. night at 3h till a friend called and picked me up to go out. we raved on till 9h in the morning with DJ Hell playing .. then afterhour with "Weisswurst and Weissbier" ;-) .. then some sleep and again out for dancing at a friends place and afterwards we went out for DJ Sven Väth playing in munich as well .. so we were quite busy [11:22:17] you party too much [11:22:30] i had my work 'christmas' party. In bed by 12:00am [11:22:49] hehe [11:23:18] i'm kinda relaxed after such a weekend .. like others do sports i think [11:29:24] ** rdmurray has joined us [11:43:52] Maniac: I've solved the utf-8 issue [11:44:44] Maniac: it's a matter to decove the incoming XML stream from it's utf-8 format to unicode [11:46:13] Maniac: self.log.debug(obj.toXml().decode('utf-8','replace')) [11:47:28] Maniac: so when peak logs with its self.prefixedString.encode('utf8','replace') (so forcing an utf-8 encoding of an unicode string), it has *really* an unicode string to play with [11:56:15] cool [11:58:45] i'll check that in then :) [12:06:10] Maniac: my patch, too [12:11:44] sure ! [12:12:37] when i get a few minutes [12:48:11] gpciceri, both things should be checked in [12:57:46] Maniac: I don't see the obj.toXml().decode stuff [12:58:38] Maniac: and you can prune three comment lines (the old stuff) [12:58:58] #prefix = messageBody[0], #commandString = messageBody[1:] and #commandString = command[len(self.prefix):] [13:00:05] my bad, i changed it in the the jabberclient module not in the bot itself :) [13:00:15] yes, i'll prune out the commented lines [13:01:12] utf-8 in jabber protocol is standard, isn't it ? [13:02:35] i have no idea [13:03:56] yes, it appears so (from a quick google) [13:06:16] yes, it's standard... [13:06:35] 11.5 Character Encoding: Implementations MUST support the UTF-8 (RFC 2279 [UTF-8]) transformation of Universal Character Set [13:06:45] Implementations MUST NOT attempt to use any other encoding. [13:07:03] so this fix should be the right one. [13:07:46] what do you use jabber for? [13:07:57] (besides IM) [13:08:02] RPC stuff [13:08:16] i think i've seen your pyblosxom weblog [13:08:25] yes [13:37:11] jack-e is now known as jack-e|away [13:37:16] bye [13:39:42] bye [13:41:10] ** _jpl_ has joined us [13:42:21] <_jpl_> Hi all [13:43:05] hey junction man [13:56:43] ** _jpl_ has left us [14:50:40] ** gpciceri has joined us [15:07:53] ** _Maniac_ has joined us [15:09:22] * _Maniac_ wonders when maniac will take a hike [15:11:50] * _Maniac_ kicks Maniac [15:17:33] <_Maniac_> ok now we have to get serious [15:17:53] _Maniac_ is now known as Maniac [15:18:02] * Maniac thanks nickserv [16:05:12] ** _Maniac_ has joined us [16:22:30] _Maniac_ is now known as Maniac [16:40:25] * Maniac notices hello world getting changed again... [16:56:43] ** _Maniac_ has joined us [17:17:39] <_Maniac_> what's the advantage of doing: [17:17:50] <_Maniac_> something = binding.Make(lambda: None) [17:18:40] <_Maniac_> rather than something = None [17:21:10] i think, something = None == class attr, binding.Make(lambda s: None) == instance attr [17:22:26] <_Maniac_> lazy binding advantage here too i guess [17:33:25] ** gpciceri has joined us [17:46:58] ** pje has joined us [17:47:24] Maniac: the advantage is in being able to define offerAs. [17:48:08] If you don't need the offerAs (or adaptTo or suggestParent or uponAssembly), you probably don't need the Make. [17:49:03] rdmurray: I just edited through section 3.3. [17:49:20] It took a while, because I cheated and added code to PEAK to make it cleaner. :) [17:50:08] I'm also planning to redo 3.4 to not use EditableFile, at least at first. [17:50:17] ** Maniac has joined us [17:50:30] I want to show how you can use the DM.flush() method to accomplish the writing-out. [17:51:46] EntityDM.flush() is called during transaction voting when the DM has any dirty records. [17:51:51] pje, oh well the makes are in there now :) [17:52:12] So, you can override it to write to the file or update the EditableFile, after first calling the original flush() method. [17:52:39] Which means, it's not necessary to do away with the 'data' binding... you can keep it as an in-memory cache. [17:52:57] And '_save' can just update the 'data' dictionary. [17:54:07] I think it'll make the transition steps smaller. [17:55:09] Last, but not least, it'll let us get rid of the regular expression stuff. :) [17:57:45] That would be a good thing. [17:57:58] Yep. [18:00:56] It really is amazing just how far you can stretch "Hello world" as an example. :) [18:02:26] Indeed. [18:02:36] Just wait until I get to the point of adding the web interface :) [18:02:47] Not to mention logging... [18:02:55] Yeah, that comes first, actually. [18:02:58] And I guess the web interface will need security... [18:03:25] good point [18:03:47] Hm, maybe the example code as of the end of each chapter should get copied into PEAK CVS for people to look at/run. [18:04:05] I kind of liked the fact that I suddenly realized in chapter four that my domain model was out of date and needed fixing :) [18:04:19] I've got them in subdirectories right now. [18:04:31] I was going to suggest putting them in cvs. [18:04:33] ** _Maniac__ has joined us [18:05:02] On the way to peak.web, you can always pass through just a plain CGI, too. [18:05:13] Yeah. [18:05:19] <_Maniac__> darn intarweb [18:05:24] * _Maniac__ coughs [18:05:28] That way, we can show CGI/FastCGI setup considerations, without simultaneously being bogged down in peak.web stuff. [18:05:34] _Maniac__ is now known as Maniac [18:07:08] I'm thinking that in prep for the cgi stuff I need to go back and fix all the examples to use "print >>self.stdout" [18:07:44] I read about that in the docstrings but forgot to do it. [18:09:08] Ooh, good point. [18:09:15] I completely forgot about that. [18:10:24] Of course, for chapters 1 and 2 it's not so bad, since there's only one print statement. [18:10:53] Heck, actually, there's only one for chapter 3. [18:11:13] Right. The advantages of simple examples :) [18:11:18] And chapter 4, too. [18:11:31] There's still only one print statement in chapter four, for that matter. [18:11:41] Yeah... it does help that the whole example consists of printing only one line of text. :) [18:12:03] I still can't believe how beautiful this thing is. [18:12:13] I've found that keeping the example this trivial means I don't get distracted into program design issues. [18:12:41] As it is I have to keep resisting adding unecessary refinements, like a command to print the list of group names. [18:12:47] Well, there are still a few. And there are the "how to use PEAK" design questions. [18:13:09] (a few design issues) [18:14:01] right, the idea is to stay focused on the how to use peak questions, and have the application specific design questions drive those. So far it's working pretty well. [18:14:43] Definitely. [18:15:15] I'm thinking maybe if you play it right, it'll eventually evolve into the Bulletins example... :) [18:15:41] Hmm. [18:15:44] I mean, so far you've been collecting subcommands, a model, and storage... [18:15:53] And you're talking about web at some point. [18:16:04] Well, I've been learning from the bulletins example, so that makes sense. [18:16:41] And somebody following the tutorial will now have a much better chance of understanding how bulletins is put together. [18:17:00] pje, as i've said to rdmurray, i really wish i had 'hello world' when i first stumbled across peak :) [18:17:10] Because they'll have seen all the big picture parts, and they will just be seeing a few odds and ends that are new to them. [18:17:12] pje: Yeah, that's my hope. [18:17:54] This is *really* cool, because it means when this is done I can focus more on reference documentation. [18:18:34] I think there will still be room for some "advanced hackery" guides to certain aspects of PEAK [18:18:45] but I find it easier to *write* those, myself. :) [18:19:24] :) [18:19:33] Now, all I need to do is make sure that word doesn't get out about HelloWorld before we get to 0.5 beta. :) [18:19:45] And none of the rest of us will be comfortable doing so, I suspect :) [18:19:57] heh [18:20:03] Or else a horde of new users will swoop down and start using it before it's ready. :) [18:21:22] That sort of thing is like a plague of locusts... there's a noise and a cloud and you don't know what hit you, but there's nothing left. :) [18:21:42] Not that I have a problem with users. It's "flash crowds" that are the problem. [18:21:58] yeah. Don't anybody post anything to slashdot. [18:22:10] Absolutely not. [18:22:30] The word is already leaking out about PEAK, slowly. [18:22:48] New user traffic on the mailing list is much higher lately. [18:23:16] Well, you can always unlink HelloWorld from the front page if you get really worried :) [18:23:17] The problem is that if too many people show up while things aren't ready, there's this [18:23:39] sort of Zeitgeist wherein everybody concludes that it's not ready or worthless or whatever. [18:23:43] And then nobody comes back. [18:24:11] Ever. [18:24:42] Like the groups who picked over Zope 1.0, decided it was crap, and then built fifty other web frameworks... :) [18:24:56] Well, it *is* useful in its present form, just not complete. So if word does get out, as long as it's not overhyped we may be OK. [18:25:21] True. HelloWorld is actually the fix for the biggest problem: lack of a decent tutorial. [18:25:53] The remaining weak spots of any consequence are in model, storage, and web. [18:25:55] and peak has the advantage over zope that it is a toolkit, so one can pick it over and glom on to the useful parts without passing judgement on the rest.... [18:25:59] And really, they're not *that* bad. [18:26:12] Good point. [18:26:42] Really, PEAK is one of the most toolkit-ish toolkits out there, for Python. [18:26:52] It was really pyprotocols that drew me in this time, but I got snagged by the rest :) [18:27:06] (In terms of being decomposable and interoperable with other things) [18:27:28] Hm, yeah, that reminds me that HelloWorld doesn't deal in protocols any. [18:27:57] OTOH, you only need them if you're extending the framework in some sense, or creating a fresh implementation of something, without subclassing a PEAK base. [18:28:22] yeah, I know. I don't have a good grasp of how protocols plugs in yet. [18:28:44] Despite my attempt to explain it in chapter 4 :) [18:29:01] I'm not at all sure those couple of paragraphs belong there. [18:29:15] I thought that was an attempt to handwave past actually explaining it. :) [18:29:25] Woops, caught red handed :) [18:30:28] It wasn't *bad* handwaving, mind. [18:31:35] by the way, given your description of n2 as a namespace explorer, I'm surprised there wasn't an obvious way of getting a list of tables from an sql database connection. [18:31:50] There isn't a standard sql for that, is there? [18:31:58] There is an n2 command for it. It's \describe [18:32:09] Hmm [18:32:13] * Maniac still has not actually used pyprotocols [18:32:14] But I don't think the SQLite adapter supports it. [18:32:15] I thought I tried that. [18:32:24] Ah, that would explain it. [18:32:48] Maniac: you use it all the time in PEAK, you just don't have to worry about it :) [18:32:58] Neither does the PostgreSQL one, for that matter. [18:33:07] i know i *use* it in peak i just dont' *use* it intentionally [18:33:28] Sybase and Oracle are the only ones that support it right now, in fact. [18:33:29] sorry, that was a pretty feeble joke. [18:33:30] like what happens if you try to adapt(something) and it fails? [18:33:44] Maniac: you get an error, unless you supplied a default to adapt(). [18:34:00] so you can wrap it with try except [18:34:12] ** hazmat has joined us [18:34:20] rdmurray, if you know enough about Postgres or SQLite to get a list of tables from them, you can always add an adapter. :) [18:34:40] I could probably figure it out for postgres. But I'm not going to try right now :) [18:34:43] See storage.ISQLIntrospector [18:35:32] my understanding is i can use adapt(something,Isomething) instead of the hasattr calls i'm using now? [18:35:50] Yep. [18:36:11] There's a wee bit more to it than that, though. [18:36:20] yes, a wee bit more... [18:36:28] You define the interface you *wish* the object had. [18:36:36] Not the interface the objects *do* have. [18:37:02] That's the beginner mistake everybody makes (including me when I first started doing adaptation stuff). [18:37:35] is that just an order of implementation type of thing? [18:37:41] Not exactly. [18:37:54] It's a design thing :) [18:37:54] What are you hasattring for, so I can use an example in those terms? [18:38:35] for a list basically [18:38:44] plugins = [] [18:39:13] You mean, hasattr(ob,'plugins') or hasattr(plugins,'__getitem__'), or what? [18:39:20] so i'm hasattr(module,'plugins') [18:39:31] Ah. [18:39:39] And what do you want to *do* with the plugins? [18:39:46] plug them in [18:39:50] ... [18:39:57] * rdmurray slaps maniac with a wet fish. [18:39:58] i'm scared to show you the code :) [18:40:08] you will hurt me [18:40:19] def __loadPlugins(self): [18:40:19] self.plugins = [] [18:40:19] for m in self.modules: [18:40:19] if hasattr(m, 'plugins') and type(m.plugins) == types.ListType: [18:40:19] for x in m.plugins: [18:40:21] self.plugins.append(x(self)) [18:40:24] else: [18:40:26] self.log.debug("Module %s " % m.__name__ + \ [18:40:28] Hey, he'll probably just rewrite it in four lines and make your program twice as efficient. [18:40:29] "does not appear to contain a list named 'plugins'") [18:40:54] So, there's a couple ways to do this. [18:41:15] I might define an IPluginProvider interface, with a method, 'installPlugins()'. [18:41:20] it's almost supper so i'll be in and out so dont' be insulted if i dont' answer right away :) [18:41:44] * pje nods [18:42:08] So I might loop over the modules and say adapt(m,IPluginProvider).installPlugins(self) [18:42:10] on each one. [18:42:40] Or, I could say instead that IPluginProvider has a 'plugins' attribute, and do almost the same as you're doing. [18:42:52] Except using adapt() instead of the hasattr stuff. [18:43:02] In that case, I would add: [18:43:17] protocols.advise(moduleProvides=[IPluginProvider]) to each plugin module. [18:43:28] That declares that the module implements IPluginProvider. [18:43:55] So, if you accidentally import a module that *isn't* a plugin provider, even though it happens to have a 'plugins' list, you'll know something's wrong. :) [18:44:58] Of course, I might rename the attribute to 'pluginFactories' or some such to start with, to clarify what they're fore. [18:45:00] Er, for. [18:45:17] I notice that you are actually calling the "plugins", so it looks like they are really factories. [18:45:37] my thought was to go the protocols.advise route [18:45:52] Also, instead of __loadPlugins, I would use def plugins(self): and use binding.Make on it. [18:45:58] Just return plugins at the end of it. [18:46:24] Something like: [18:46:28] def plugins(self): [18:46:30] and you can do binding.Make each time you want to load them? [18:46:45] Huh? [18:46:49] :) [18:46:54] If you want to *reload* them, del self.plugins suffices. [18:46:57] * Maniac considers how to phrase them [18:47:08] The next access to self.plugins would recreate the plugin list. [18:47:08] er phrase the question [18:47:14] pje, aha! [18:47:23] plugins = [] [18:47:25] see now that is binding magic [18:47:31] for m in self.modules: [18:48:06] plugins.extend([factory() for factory in adapt(module,IPluginProvider).pluginFactories]) [18:48:14] return plugins [18:48:38] Here's the interesting part, btw... if it's a binding, the list will get suggestParentComponent called on it... [18:48:40] for every element. [18:48:51] So, I don't even need the factory(self) if I don't want. [18:49:03] What did I tell you, four lines :) :) [18:49:20] or, I can call factory(self,'plugins') and do 'suggestParent=False' on the Make. [18:49:38] Five if you count the 'def' line. Six at least with binding.Make() added. [18:49:46] And it also doesn't include the interface. [18:50:11] adapt() will also throw a NotImplementedError if one of the modules doesn't support the interface. [18:50:20] So, my way may actually end up being *more* code. [18:50:25] Ah, go ahead, spoil my fun with reality :) [18:50:31] And it's not more efficient in execution either. [18:50:53] And, if you will only ever use modules as plugins, then the added flexibility doesn't help much, either. [18:51:13] But the point was to illustrate PyProtocols, so the heck with it. :) [18:51:53] It doesn't really illustrate the "wishful thinking" principle of interfaces, though. [18:52:15] PEAK's IComponentKey is a much better example, really. [18:52:40] There, the "ideal" interface for binding.Obtain to use is something that does whatever's needed to "find" another component. [18:52:59] So, IComponentKey has a 'findComponent(ctx,default)' method. [18:53:45] And if you look at what binding.Obtain actually does, it just does: [18:53:46] return self.targetName.findComponent(obj, self.default) [18:54:18] All of the magic of being able to use strings or tuples or interfaces or property names and all that stuff, comes from adaptation to IComponentKey from those types. [18:54:57] Before PEAK used adaptation, the predecessor to Obtain had all this code to check whether something was a string or an interface, or... [18:55:10] It was a big hairy ball of code. [18:55:16] Now it's one line. [18:55:46] (Plus a bunch of single-purpose classes that "do the right thing" for one kind of input) [18:56:16] Anyway, that's the moral of the story. When you move to using adaptation, forget about the big hairy ball. [18:56:46] Wave a magic wand and say, "How would I write this in *one line* of code?" [18:57:12] As though the object already had the one or two methods you would need to get the job done. [18:57:52] Then, you decide *how* they would do it for different types of input objects, and write adapters that implement the method. [18:58:00] And you're done. [18:58:43] And speaking of being done, I gotta get going. [18:59:07] rdmurray, thanks again for your help. I probably won't get to editing the rest of chapter 3 till tomorrow. [18:59:24] I'll pop in here to make sure I don't collide with any of your edits; I almost did today. [18:59:28] (collide, that is.) [18:59:46] MoinMoin doesn't have a guard against that. :( [18:59:50] You did? [18:59:57] Did what? [19:00:00] Pop in? [19:00:01] No. [19:00:03] I don't remember changing anything today [19:00:11] You removed a comma. :) [19:00:24] Hmm. Must have been half asleep :) [19:00:35] It was a typo in code I'd edited. [19:00:39] And you fixed it. [19:00:43] Anyway... I gotta run. [19:00:51] * pje waves [19:00:52] k, see you [19:01:04] Maniac: hth; let me know if you've got questions [19:01:08] Bye [19:01:11] ** pje has left us [19:07:14] ** _jpl_ has joined us [19:29:39] ** _jpl_ has left us [19:29:43] ** _jpl_ has joined us [20:01:58] bye.. [20:02:29] ** _jpl_ has left us [20:11:07] so why would existing connections to my office network stay open, but all NEW connections fail? [20:11:14] my router? [20:22:31] ** _Maniac has joined us [20:26:36] ** _Maniac_ has joined us [21:59:47] ** _Maniac__ has joined us [22:33:18] _Maniac__ is now known as Maniac