User:Enus Linden/Office Hours/2008 July 18
Jump to navigation
Jump to search
- [9:29] Saijanai Kuhn: Ah as a way of introducing Tao's topic later: https://wiki.secondlife.com/wiki/Pyogp/Client_Lib/Development/Zope
- [9:29] Enus Linden: thanks sai, was grabbing that link myself
- [9:29] Asterion Coen: hehe yes, i was about to ask what Pyogp is :)
- [9:30] Saijanai Kuhn: And generically https://wiki.secondlife.com/wiki/Pyogp/
- [9:30] Enus Linden: and more generally, and to your question
- [9:30] Enus Linden: [1]
- [9:30] Locklainn Linden: hahah
- [9:30] Enus Linden: sigh
- [9:30] Locklainn Linden: wow
- [9:30] Enus Linden: sai is my secretary now, hired on the spot
- [9:30] Saijanai Kuhn: can't type well, but the spam just flies off the fingertips
- [9:30] Locklainn Linden: haha
- [9:30] Tao Takashi: heh :)
- [9:31] Infinity Linden: hmm... reads your mind... knows how to rile the populous... purports to be a secret smalltalk agent...
- [9:31] Enus Linden: So i reckon we might as well get rolling
- [9:32] Bartholomew Kleiber: Hi all
- [9:32] Enus Linden: thanks for coming to the first of my office hours. We're gonna talk pyogp today
- [9:32] Enus Linden: and for the forseeable future
- [9:32] Infinity Linden: yay
- [9:32] Saijanai Kuhn: pyogp => https://wiki.secondlife.com/wiki/Pyogp/
- [9:32] Enus Linden: as other topics need to pop up, they will i'm sure
- [9:33] Enus Linden: The intent today isn't so much to introduce pyogp, the wiki can serve that function
- [9:33] Enus Linden: we are gonna have Tao give us some words on pyogp's use of zca thoguh
- [9:34] Enus Linden: tao, you ready to chat?
- [9:34] Tao Takashi: Mostly answering question of those who have read the tutorial but might not get the concept or are confused in general
- [9:34] Tao Takashi: yes
- [9:34] Saijanai Kuhn: ZCA intro => https://wiki.secondlife.com/wiki/Pyogp/Client_Lib/Development/Zope
- [9:34] Tao Takashi: right. So who here has read it?
- [9:34] Enus Linden: raises hand
- [9:34] Locklainn Linden: raises hand
- [9:35] Tao Takashi: well, I didn't ;-)
- [9:35] Locklainn Linden: oh boy
- [9:35] Saijanai Kuhn: I read an earlier version I think
- [9:35] Tao Takashi: but I should and clean up typos ;-)
- [9:35] Tao Takashi: and who here has questions about it? I think Saijanai has
- [9:36] Infinity Linden: is there sample code that uses it (in the PyOGP context?)
- [9:36] Locklainn Linden: yea
- [9:36] Tao Takashi: I need to understand what you guys don't understand so I can explain these parts :)
- [9:36] Locklainn Linden: Credentials
- [9:36] Saijanai Kuhn: welll, I understand the concepts. I'l need to actually go step by step through typing a simple example in before I "get it" is all
- [9:36] Tao Takashi: yes, or PlaceAvatarAdapter in agent.py
- [9:36] Tao Takashi: ok, so let's take credentials
- [9:37] Tao Takashi: grr, cannot find the URL
- [9:37] RacerX Gullwing: [2] ?
- [9:37] Asterion Coen: things happens
- [9:38] Saijanai Kuhn: [3]
- [9:38] Saijanai Kuhn: ?
- [9:38] Tao Takashi: [4]
- [9:38] Tao Takashi: This is the source file
- [9:38] Saijanai Kuhn: ah, never in a millions years ...;-)
- [9:38] Tao Takashi: glad, trac has line numbers :)
- [9:38] Tao Takashi: does everybody see this file?
- [9:39] Tao Takashi: Enus could put this on a parcel media url ;-)
- [9:39] Bartholomew Kleiber: I do
- [9:39] Elric Anthony: nods
- [9:39] Locklainn Linden: yep
- [9:39] Tao Takashi: but it's probably too long
- [9:39] Tao Takashi: but as long as you see it in a browser that's ok
- [9:39] Enus Linden: i'll trust browsers for now (and will put up a screen for next time)
- [9:39] Tao Takashi: so what you see there is a simple class called PlainPasswordCredential
- [9:39] Tao Takashi: is just stores firstname, lastname and a password
- [9:40] Sea Urchin: beanbag: Going to next texture.
- [9:40] Tao Takashi: what we need to do for logging into an agent domain is to convert this data to LLSD
- [9:40] Dahlia Trimble: plain text, not a hash?
- [9:40] Tao Takashi: this is plain text but there will be other credentials which have a hash
- [9:40] Infinity Linden: "go with him here.. that's later
- [9:41] Tao Takashi: so normally you would implement a method like get_llsd() which returns the data as LLSD XML
- [9:41] Sea Urchin: beanbag: Going to next texture.
- [9:41] Tao Takashi: but the problem here is that later you might want to replace this by using JSON
- [9:42] Tao Takashi: so you would need a different method get_json()
- [9:42] Tao Takashi: now imagine you want to replace this in your application
- [9:42] Tao Takashi: you can subclass from this class of course and implement it or even exchange the existing method to return json
- [9:43] Tao Takashi: but other packages would then still use the class defined in pyogp.lib.base
- [9:43] Tao Takashi: not yours
- [9:43] Tao Takashi: what you want is to be flexible in how it is serialized into whatever format you want
- [9:43] Tao Takashi: as a default we want to provide LLSD
- [9:43] Tao Takashi: so what we do instead is using an adapter
- [9:44] Tao Takashi: an adapter is mainly a new object which is a wrapper around the original object (in our case the PlainPasswordCredential instance)
- [9:44] Tao Takashi: can you follow me so far? :)
- [9:44] Tao Takashi: if you have questions inbetween please ask
- [9:44] Tao Takashi: so this PlainPasswordLLSDSerializer class is such a wrapper class
- [9:45] Tao Takashi: as you can see in it's __init__() on line 31, it simply takes another object and stores it as self.context
- [9:45] Tao Takashi: so self.context will store an instance of PlainPasswordCredential
- [9:45] Enus Linden: line 31?
- [9:45] Tao Takashi: in my trac view it says 31 where it says self.context = context
- [9:46] Latha Serevi: I was late; could someone please re-paste the relevent one or two URLs for us latecomers? Thx.
- [9:46] Enus Linden: i see, tx
- [9:46] Tao Takashi: it starts at 29
- [9:46] Tao Takashi: This is the source code we are talking about: [5]
- [9:46] Enus Linden: high level doc: [6] using the svn trac as an example to step through
- [9:46] Tao Takashi: now having this in self.context we can obtain e.g. the firstname by using self.context.firstname
- [9:47] Tao Takashi: Hey Vektor, you are on the wrong grid! ;-)
- [9:47] Tao Takashi: but good to see you anyway :)
- [9:47] Tao Takashi: so what we now implement in PlainPasswordLLSDSerializer is a serialize() method which simply uses this information from self.context to construct an LLSD string
- [9:47] Tao Takashi: see line 33-43
- [9:48] Saijanai Kuhn: For ka leteecomers, we're looking at: [7]
- [9:48] Tao Takashi: so what we now could do is the following:
- [9:48] Infinity Linden: hey Tao... are you using context to have any particular behavor, or is it just a holder of slots?
- [9:48] Tao Takashi: credentials = PlainPasswordCredential("some","name",pw")
- [9:48] Tao Takashi: it is just a convention for naming where the wrapped object is stored
- [9:49] Infinity Linden: oh.. okay
- [9:49] Tao Takashi: and we can instantiate the wrapper around it:
- [9:49] Tao Takashi: wrapper = PlainPasswordLLSDSerializer(credentials)
- [9:49] Saijanai Kuhn: its like "self" in a non-oop language
- [9:49] Tao Takashi: and we could call this wrapper now: wrapper.serialize()
- [9:49] Tao Takashi: and we would get an LLSD string
- [9:49] Infinity Linden: were you thinking of doing a Factory pattern so all the contexts respond to the same protocol?
- [9:50] Tao Takashi: unfortunately I am not so good at patterns as I tend to forget the specifics ;-)
- [9:50] Infinity Linden: that might help with refactoring if/when we move to authentication++
- [9:50] Tao Takashi: but the pattern here is bascially passing in an object and store it in self.context to add additional functionality to it
- [9:50] Tao Takashi: like serialize() in our case
- [9:51] Tao Takashi: so instead of implementing serialize directly in the main class we write a layer on top basically
- [9:51] Infinity Linden: basically it means that you have a superclass upon which you call a class method and it decides which of it's subclasses to implement
- [9:51] Tao Takashi: well, this has nothing to do with actual subclassing
- [9:51] Infinity Linden: i'll just update yer code and post it somewhere
- [9:51] Infinity Linden: right.. it's about interface
- [9:51] Tao Takashi: yes, I am coming to that now
- [9:51] Elric Anthony: So registration allows you to access your extender class without without including a package?
- [9:52] Infinity Linden: classic Factory pattern uses subclasses just for naming convenience
- [9:52] Infinity Linden: and to encapsulate common behavior
- [9:52] Tao Takashi: Elric: I will explain registration now
- [9:52] Tao Takashi: so the problem we have now is that we need to rely on the fact that self.context really has firstname, lastname and password
- [9:52] Tao Takashi: if we pass in something else it will apparently break
- [9:53] Tao Takashi: so in order to do that we define interfaces. An interface basically is a collection of methods and attributes which has a name
- [9:53] Tao Takashi: in our case we define an interface called IPlainPasswordCredential
- [9:53] Tao Takashi: you can find this in [8]
- [9:53] Tao Takashi: in line 6
- [9:53] Tao Takashi: so it really just lists those attributes
- [9:54] Tao Takashi: with some documentation what they mean
- [9:54] Tao Takashi: and what the interface is about
- [9:54] Tao Takashi: it also derives from a more general interface which is not used right now but maybe is of some use later (ICredential)
- [9:54] Tao Takashi: now we only need to mark the class that it implements this interface
- [9:55] Tao Takashi: this is done by the implements(IPlainPasswordCredential) call in [9] in line 12
- [9:55] Tao Takashi: now the system knows that PlainPasswordCredential implements this interface
- [9:55] Infinity Linden: hmm... why would we want an interface for plain password credential?
- [9:55] Tao Takashi: because we need to define what attributes it has
- [9:55] Infinity Linden: I understand why we might want an interface for Credential
- [9:56] Elric Anthony: So the extender class doesn't have to imort it?
- [9:56] Infinity Linden: why do we need to define what attributes it has?
- [9:56] Tao Takashi: because the adapter relies on this interface and accesses the attributes which are defined in it
- [9:56] Tao Takashi: see line 37-39 in credentials.py
- [9:57] Tao Takashi: the actual adapter does not need to know about our actual implementation of PlainPasswordCredential
- [9:57] Tao Takashi: it just needs to know that this context we pass in has those 3 attributes
- [9:57] Tao Takashi: and another form of credential might have different attributes
- [9:57] Tao Takashi: so we need a different serialization method for this and thus a different adapter
- [9:57] Infinity Linden: right... but what's the advantage to building a ZCA interface around it
- [9:58] Tao Takashi: I will come to that in a bit
- [9:58] Tao Takashi: also note line 27 of credentials.py
- [9:58] Enus Linden: but any implementation can work so long as it uses the same parameter api...
- [9:58] Tao Takashi: there it says adapts(IPlainPasswordCredential)
- [9:58] Tao Takashi: Enus: As long as your credential has those attributes and thus implements this interface it will work
- [9:59] Infinity Linden: but we're going to have different attributes for different implementations of the IPlainPasswordCredential...
- [9:59] Tao Takashi: the adapts() directive tells the ZCA that this wrapper which we call an adapter needs a context object which implements this interface
- [9:59] Tao Takashi: Infinity: why's that?
- [9:59] Saijanai Kuhn: you don't even need specific parameters for the adapter, do you?
- [9:59] Infinity Linden: so we have a different client protocol for each thing that uses IPlainPasswordCredential
- [9:59] Tao Takashi: well, as you see, the adapter expects firstname, lastname and password
- [10:00] Tao Takashi: so the adapter wants to make sure the context object also has those
- [10:00] Tao Takashi: so it says that it adapts to any object which implements IPlainPasswordCredential which in turn means that it has those 3 attributes
- [10:01] Tao Takashi: and as you can see it also has an implements(ICredentialSerializer) line in line 26
- [10:01] Infinity Linden: okay... i gotta run. Thanks Tao.. good intro... ZCA looks useful, but I still need convincing about this specific example. and with that I'll just shut up and write some code to demonstrate my concerns...
- [10:01] Saijanai Kuhn: so its checking the context for the parameter-names, rather than checking for specific names passed in a function?
- [10:01] Infinity Linden: cheers
- [10:01] Tao Takashi: this way it says that it implements this interface. And if you look in interfaces.py again you see this interface there and that it has a serialize() and a header() method we need to implement
- [10:02] Enus Linden: infinity, raise those concerns asap. i'm surious what they are
- [10:02] Tao Takashi: Sai: well, it's not checking the context
- [10:02] Tao Takashi: it's expecting the context to have those
- [10:03] Tao Takashi: as it says by having adapts(IPlainPasswordCredential) that it's only supposed to work if the context is implementing this interface
- [10:03] Tao Takashi: which is defined as having those attributes. So in the end context needs to have those attributes
- [10:03] Enus Linden: haven't tried: what happens if an attribute is missing, or if extras exist?
- [10:03] Tao Takashi: let me search for an example of where it's used
- [10:04] Tao Takashi: well, then it breaks in line 37-39 somewhere
- [10:04] Tao Takashi: and you have a bug in your code
- [10:04] Tao Takashi: because then you haven't implemented the interface correctly you were saying you do
- [10:04] Saijanai Kuhn: OK almost seeing it
- [10:04] Tao Takashi: the interface btw is not checked on runtime but you can check for the existance of methods in a class at least in a unit test
- [10:04] Tao Takashi: so what is checked is only the name
- [10:05] jashua Alter: gave you SR-720h Skymaster 1.0.
- [10:05] Tao Takashi: so let me search for a usage example
- [10:05] Tao Takashi: ah, one thing before that
- [10:05] Tao Takashi: we need to tell the ZCA that this adapter is available
- [10:05] Tao Takashi: just writing it there does not tell it
- [10:05] Tao Takashi: this is what the last 2 lines in credentials.py are for
- [10:05] Tao Takashi: this just stores it in some global configuration also called the registry
- [10:06] Tao Takashi: now for usage
- [10:06] Tao Takashi: look at [10]
- [10:06] Tao Takashi: and you see line 31 there
- [10:06] Tao Takashi: it says:
- [10:06] Tao Takashi: serializer = ICredentialSerializer(credentials)
- [10:07] Tao Takashi: what we have is an object credentials which is an instance of the PlainPasswordCredential class
- [10:07] Tao Takashi: so it implements the interface IPlainPasswordCredential
- [10:07] Tao Takashi: (there are actually functions in the ZCA to test which interfaces an object implements, it can also be more than one interface)
- [10:08] Tao Takashi: what we now need though is to serialize this credential
- [10:08] Tao Takashi: so we need LLSD, not an object
- [10:08] Tao Takashi: before that I explained how you can invoke the wrapper manually
- [10:08] Tao Takashi: simply by saying PlainPasswordLLSDSerializer(credential)
- [10:08] Tao Takashi: but then we would have this wrapper class hard coded in our code
- [10:09] Tao Takashi: we couldn't replace it later on easily in our own application without changing agentdomain.py
- [10:09] Tao Takashi: so instead we call it by it's interface:
- [10:09] Tao Takashi: serializer = ICredentialSerializer(credentials)
- [10:09] Tao Takashi: what happens now is the following:
- [10:09] Tao Takashi: 1. The ZCA looks up which interfaces credentials implements and finds IPlainPasswordCredential
- [10:10] Tao Takashi: 2. The ZCA looks up in it's registry if there is some adapter which implements the interface ICredentialSerializer and adapts to IPlainPasswordCredential
- [10:10] Tao Takashi: 3. Happily it finds our adapter PlainPasswordLLSDSerializer
- [10:10] Tao Takashi: 4. It does the same thing I wrote above: PlainPasswordLLSDSerializer(credential)
- [10:10] Tao Takashi: and returns it
- [10:11] Tao Takashi: now we have an object which wraps our original object but it has a different interface: ICredentialSerializer
- [10:11] Tao Takashi: we now know that this interface has a serialize() method which we can call now
- [10:11] Tao Takashi: So all in all it's an indirection here over the interface name
- [10:12] Tao Takashi: which means: If we simply override the registration somewhere and do not provide PlainPasswordLLSDSerializer but our own PlainPasswordJSONSerializer instead
- [10:12] Tao Takashi: we would not need to change the login code but we can simply do the additional registration on startup time in our own application which uses this library
- [10:12] Tao Takashi: and this is basically everything about adapters
- [10:13] Tao Takashi: questions? :)
- [10:13] Tao Takashi: I guess now you have more questions than before
- [10:13] Tao Takashi: I might also put an example up which has all the code in one file
- [10:14] Enus Linden: so i think it's important to point out that using zca in this way in pyogp makes it feasible to have a core codebase that does what we collectively want pyogp to do, which is enable testing of OGP
- [10:14] Enus Linden: plus
- [10:14] Enus Linden: make it so that it's extendable and bits are swappable
- [10:14] Tao Takashi: that's the LL goal ;-) I also would like to use it for implementing agent domains, region domains and clients
- [10:14] Tao Takashi: someday
- [10:15] Enus Linden: so the intial goal, LL's and AWGsa, is a codebase that supports testing OGP
- [10:15] Enus Linden: where it goes from there is up to those who carry it forward : )
- [10:15] Tao Takashi: so one advantage of doing things like this is that you can easily exchange parts like the serialization without changing the library itself
- [10:16] Tao Takashi: it's of course also doable in different ways like using some other means of configuration but this is somewhat a proven way and a well tested framework for doing this
- [10:16] Tao Takashi: an additional advantage IMHO is that you have to think about your interfaces
- [10:16] Tao Takashi: this makes IMHO sense as it helps to get a cleaner architecture
- [10:16] Enus Linden: tao, we've been churning a bit on things. I feel like we're settling down on structure, do you agree? what big changes remain?
- [10:16] Tao Takashi: and they can also serve as documentation. The first thing you should read in a new component should be it's interfaces.py
- [10:17] Enus Linden: granted, this is a very young project...
- [10:17] Tao Takashi: well, I don't think there are many changes as there is not yet so much there to change ;-)
- [10:17] Tao Takashi: so we first need more additions on which e.g. Locklainn is working on (Message Parsing)
- [10:18] Locklainn Linden: yep, and building and reading :)
- [10:18] Saijanai Kuhn: and more reading :-/
- [10:18] Enus Linden: how about networking? and it's a given that many components remain to be built (like 99% of it), but architecture wise.....
- [10:18] Tao Takashi: Sai: is this adapter stuff now clearer to you?
- [10:19] Tao Takashi: right, I was planning to continue work on a network layer
- [10:19] Tao Takashi: so we can easily exchange e.g. urllib2 with eventlet or some mockup network layer for testing
- [10:20] Saijanai Kuhn: not really. I had that level of understanding alrady, I think. What I need to do is just write two different "hello world" implementations and play with making them interfaces/adapters/whateverss
- [10:20] Tao Takashi: maybe try to implement something like the document example I gave in the tutorial
- [10:20] Tao Takashi: so you have some simple class which has some attributes and you want to add functionality to it by using adapters
- [10:20] Tao Takashi: like get_size()
- [10:21] Tao Takashi: and another advantage of adapters is I think that they are small and easy to test
- [10:22] Tao Takashi: just give them a mockup object which implements the needed interface and you can test the outcome
- [10:22] Enus Linden: tess, whump, anyone else: questions at this point?
- [10:22] Tao Takashi: I also wanted to write down some best practives for developing
- [10:22] Tao Takashi: like how it's best to start with some example (like in a doctest), then try to define interfaces and then implement everything until the doctest passes
- [10:23] Tao Takashi: or unit test if you prefer
- [10:23] Locklainn Linden: called Test-Driven-Development
- [10:23] Enus Linden: shudder to think it's possible
- [10:23] Whump Linden: Tao, I had a question, but I'll take it off line. Schedule stuff for OGPB.
- [10:24] Tao Takashi: Enus: I did the base library stuff like this
- [10:24] Tao Takashi: I started with login.txt
- [10:24] Tao Takashi: helps to understand how components might look like
- [10:24] Tao Takashi: because you start with using them
- [10:24] Tao Takashi: Whump: ok, I will also be on #pyogp and #gridnauts
- [10:24] Whump Linden: cool, thanks
- [10:25] Tao Takashi: whump: and another question: Would it be ok to put the gridnauts mailing list on gmane.org?
- [10:25] Tao Takashi: (like we did with pyogp)
- [10:25] Saijanai Kuhn: Think I found my helloworld example: [11]
- [10:26] Tao Takashi: yes, Lennart is good at explaining things, maybe also link this from the wiki
- [10:26] Bartholomew Kleiber: Saijanai: thx, just what I needed, too
- [10:26] Enus Linden: more to read, sweet
- [10:27] Enus Linden: Tao thanks for the overview...
- [10:27] Tao Takashi: please email to the pyogp list if you have questions
- [10:27] Enus Linden: and for updates watch [12] and it's family of pages
- [10:27] Bartholomew Kleiber: tao: Only speaking for me I missed reading the page Zope Wiki page and do so ASAP because this seems very important to understand. Other than that I think I got the point from your explanations.
- [10:28] Tao Takashi: Bartholomew: Great :) And we should maybe do this sprint someday soon :)
- [10:28] Bartholomew Kleiber: 'tis true :-).
- [10:28] Enus Linden: so we're about out of time. pyogp will eat a lot of this meetings time in the short term. eventually general QA related issues will pop up as well.
- [10:29] Enus Linden: feel free to hollar at #pyogp as needed all
- [10:29] Enus Linden: i gotta run
- [10:29] Saijanai Kuhn: great first meeting
- [10:29] Tao Takashi: thanks for hosting, Enus :)
- [10:29] Tess Linden: thanks!
- [10:29] Kitty Tandino: <3 hugs e
- [10:29] Tiffany Sicling: yes, thanks :)
- [10:29] Enus Linden: agreed. secretary sai, you got a transcript, or shall i?
- [10:29] Vektor Linden: Thanks Enus!
- [10:30] Saijanai Kuhn: probably you should so I see howyou want to mark it up on your user page
- [10:30] Dahlia Trimble: gotta run too, Thanks Tao and everyone :)
- [10:30] Enus Linden: sure thing sai. catch y'all later on!
- [10:30] Saijanai Kuhn: laters Enus
- [10:30] Bartholomew Kleiber: bye
- [10:30] Asterion Coen: have dhaliaste transcript here