Discussion:
[Pyogp] Example High Level API
Christian Scholz
2008-07-14 21:31:34 UTC
Permalink
Hi!

I was playing around a bit while waiting for a video encoding to finish
and I came up with this example high level API which is more a set of
functions (no class needed here). It also includes doctests directly
which pass in my example sandbox.

I am not sure this works here regarding line breaks, so you can also see
it here:

http://pastebin.com/mffb73aa


(I also refactored the code a bit to use IPlaceAvatar on the AgentDomain
and not the Agent anymore and I implement an Avatar class which holds a
reference to the region it just is on which in turn stores the details
which it gets from place_avatar().

-- Christian


"""
High level API
"""

from pyogp.lib.base.credentials import PlainPasswordCredential
from pyogp.lib.base.agentdomain import AgentDomain
from pyogp.lib.base.regiondomain import Region

from pyogp.lib.base.interfaces import IPlaceAvatar

### login methods
def login_with_plainpassword(agentdomain_url, firstname, lastname,
password):
"""logs an agent into the agent domain and returns an agent handle

takes firstname, lastname and plain password and returns an agent
object
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")

Now this agent should contain an agentdomain object
agent.agentdomain
<pyogp.lib.base.agentdomain.AgentDomain object at ...>
agent.agentdomain.seed_cap
<SeedCapability for http://127.0.0.1:12345/seed_cap>

"""

credentials = PlainPasswordCredential(firstname, lastname, password)
agentdomain = AgentDomain(agentdomain_url)
agent = agentdomain.login(credentials)
return agent


### place avatar
def place_avatar(agent, region_url):
"""place an avatar on a region

Placing an avatar is simple. We just need an agent object and a
region url.
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
avatar = place_avatar(agent, "http://localhost:12345/region")
avatar.region
<pyogp.lib.base.regiondomain.Region object at ...>
avatar.region.details
{'sim_port': 12345, 'sim_ip': '127.0.0.1'}

"""
place = IPlaceAvatar(agent.agentdomain)
region = Region(region_url)
avatar = place(region)

return avatar

def run_loop(avatar):
"""run the UDP loop for the avatar
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
avatar = place_avatar(agent, "http://localhost:12345/region")
run_loop(avatar)
"""
--
Christian Scholz video blog: http://comlounge.tv
COM.lounge blog: http://mrtopf.de/blog
Luetticher Strasse 10 Skype: HerrTopf
52064 Aachen Homepage: http://comlounge.net
Tel: +49 241 400 730 0 E-Mail ***@comlounge.net
Fax: +49 241 979 00 850 IRC: MrTopf, Tao_T

neue Show: TOPFt?glich (http://mrtopf.de/blog/category/topf-taglich/)
Locklainn
2008-07-15 10:31:05 UTC
Permalink
Right,
So Christian and I were talking yesterday about what the client library
should look like. My initial thoughts were that we were going to have
high-level classes (encapsulated methods) in order to do certain things.
Christian has thought that we were going to do a more low-level library
which could be used to create a client, login, etc, but we wouldn't
necessarily implement things such as login or a client (just all the
components needed to do so). The question is, which are we doing? There
are a couple options:
1) Low-level components only - give them all the components they need to
write a lightweight client, without writing high-level functionality
that uses those components
2) High-level class structure - give them the components as well as some
high level functionality to make it easier for them to do things, such
as giving them a Login class that can be used to do all that is
necessary to login
3) High-level method structure - same as number 2, except it won't be
encapsulated into classes but kept in method form (such as the code he
sent out that I am replying to).

Thanks,
TJ
Post by Christian Scholz
Hi!
I was playing around a bit while waiting for a video encoding to
finish and I came up with this example high level API which is more a
set of functions (no class needed here). It also includes doctests
directly which pass in my example sandbox.
I am not sure this works here regarding line breaks, so you can also
http://pastebin.com/mffb73aa
(I also refactored the code a bit to use IPlaceAvatar on the
AgentDomain and not the Agent anymore and I implement an Avatar class
which holds a reference to the region it just is on which in turn
stores the details which it gets from place_avatar().
-- Christian
"""
High level API
"""
from pyogp.lib.base.credentials import PlainPasswordCredential
from pyogp.lib.base.agentdomain import AgentDomain
from pyogp.lib.base.regiondomain import Region
from pyogp.lib.base.interfaces import IPlaceAvatar
### login methods
def login_with_plainpassword(agentdomain_url, firstname, lastname,
"""logs an agent into the agent domain and returns an agent handle
takes firstname, lastname and plain password and returns an agent
object
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
Now this agent should contain an agentdomain object
agent.agentdomain
<pyogp.lib.base.agentdomain.AgentDomain object at ...>
agent.agentdomain.seed_cap
<SeedCapability for http://127.0.0.1:12345/seed_cap>
"""
credentials = PlainPasswordCredential(firstname, lastname, password)
agentdomain = AgentDomain(agentdomain_url)
agent = agentdomain.login(credentials)
return agent
### place avatar
"""place an avatar on a region
Placing an avatar is simple. We just need an agent object and a
region url.
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
avatar = place_avatar(agent, "http://localhost:12345/region")
avatar.region
<pyogp.lib.base.regiondomain.Region object at ...>
avatar.region.details
{'sim_port': 12345, 'sim_ip': '127.0.0.1'}
"""
place = IPlaceAvatar(agent.agentdomain)
region = Region(region_url)
avatar = place(region)
return avatar
"""run the UDP loop for the avatar
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
avatar = place_avatar(agent, "http://localhost:12345/region")
run_loop(avatar)
"""
Christian Scholz
2008-07-15 11:03:39 UTC
Permalink
Hi!
Post by Locklainn
So Christian and I were talking yesterday about what the client library
should look like. My initial thoughts were that we were going to have
high-level classes (encapsulated methods) in order to do certain things.
Christian has thought that we were going to do a more low-level library
which could be used to create a client, login, etc, but we wouldn't
necessarily implement things such as login or a client (just all the
components needed to do so). The question is, which are we doing? There
1) Low-level components only - give them all the components they need to
write a lightweight client, without writing high-level functionality
that uses those components
Actually I think the components we have are not that low level. We have
things like an Agent, an AgentDomain and so on. These encapsulate things
like capablilty handling, serialization and so on.

BTW, what about creating some pyogp.examples package where we can put
all sorts of example on how to use the library?
Post by Locklainn
2) High-level class structure - give them the components as well as some
high level functionality to make it easier for them to do things, such
as giving them a Login class that can be used to do all that is
necessary to login
3) High-level method structure - same as number 2, except it won't be
encapsulated into classes but kept in method form (such as the code he
sent out that I am replying to).
I personally don't like classes as a function library. It seems that the
login class now is "everything about login" but Login is not some entity
we really model. It's a process but not a "logical thing" IMHO. That's
why I converted this into simple functions as at least to me those seem
more appropriate. They take some input, process it and return something.

I try to use classes for things we want to model, such as Agent,
AgentDomain and so on. The problem I see here is that all the instance
variables in OGPLogin at some point need to be passed to the next class
which does the next bit, like handling inventory. Here I feel that it's
easier to use classes we already have for that, such as an avatar etc.

With the class structure we have right now we basically have 2 endpoints:

- Agent - has access to the agent domain
- Avatar - has access to the region domain and region (probably should
also contain a link to it's agent)

Right now at least I think this is all we need to pass around then. I
have no idea though right now about how the udp loop might look like but
we hopefully have soon some examples.

And of course we have the problem of defining where the scope of a
certain low or high level ends, which means how "high" it is I guess ;-)
Like do we pass firstname, lastname, plainpw into one function and
md5hash into another (and thus repeating most of the code except the
creation of the credential). Or do we pass in the credential and have to
create it manually before that?
The same applies to Regions and Region Domains. The more we let a high
level function or method do, the less flexible we are (of course unless
you use the low level functions) or the more code we have to duplicate
(or factor probably better factor out).
Another question is how much code it makes sense to collapse into a high
level function. Right now it's mostly 3 lines, 2 if you move out the
credential part.

That being said I am not against high level functions, I guess we just
differ in what we see as high level ;-)
And I guess it also does not hurt to provide high level functions as
long as they are tested. We probably mostly need to make sure everything
is documented (and have examples, hence pyogp.examples).

So my proposal here would be:

- go with functions unless there really is a logical entity we might
want to model (it's not said that some high level function won't have
this, like a UDP Loop Handler)
- test everything
- document everything (might be similar if we use doctests)
- create examples
- think about a clever filesystem structure so that maybe high level
methods have their own directory.

As a sidenote I would like to propose that we only use lower case
filenames, as it's defined in PEP 08 (python coding style). We probably
should follow PEP 8, as it's usually a good convention. You can read
about it here:

http://www.python.org/dev/peps/pep-0008/

(and I actually also have to do that ;-) ).

Thanks as well! :-)

Christian
Post by Locklainn
Thanks,
TJ
Post by Christian Scholz
Hi!
I was playing around a bit while waiting for a video encoding to
finish and I came up with this example high level API which is more a
set of functions (no class needed here). It also includes doctests
directly which pass in my example sandbox.
I am not sure this works here regarding line breaks, so you can also
http://pastebin.com/mffb73aa
(I also refactored the code a bit to use IPlaceAvatar on the
AgentDomain and not the Agent anymore and I implement an Avatar class
which holds a reference to the region it just is on which in turn
stores the details which it gets from place_avatar().
-- Christian
"""
High level API
"""
from pyogp.lib.base.credentials import PlainPasswordCredential
from pyogp.lib.base.agentdomain import AgentDomain
from pyogp.lib.base.regiondomain import Region
from pyogp.lib.base.interfaces import IPlaceAvatar
### login methods
def login_with_plainpassword(agentdomain_url, firstname, lastname,
"""logs an agent into the agent domain and returns an agent handle
takes firstname, lastname and plain password and returns an agent
object
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
Now this agent should contain an agentdomain object
agent.agentdomain
<pyogp.lib.base.agentdomain.AgentDomain object at ...>
agent.agentdomain.seed_cap
<SeedCapability for http://127.0.0.1:12345/seed_cap>
"""
credentials = PlainPasswordCredential(firstname, lastname, password)
agentdomain = AgentDomain(agentdomain_url)
agent = agentdomain.login(credentials)
return agent
### place avatar
"""place an avatar on a region
Placing an avatar is simple. We just need an agent object and a
region url.
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
avatar = place_avatar(agent, "http://localhost:12345/region")
avatar.region
<pyogp.lib.base.regiondomain.Region object at ...>
avatar.region.details
{'sim_port': 12345, 'sim_ip': '127.0.0.1'}
"""
place = IPlaceAvatar(agent.agentdomain)
region = Region(region_url)
avatar = place(region)
return avatar
"""run the UDP loop for the avatar
agent =
login_with_plainpassword("http://localhost:12345","Firstname","Lastname","secret")
avatar = place_avatar(agent, "http://localhost:12345/region")
run_loop(avatar)
"""
_______________________________________________
https://lists.secondlife.com/cgi-bin/mailman/listinfo/pyogp
--
Christian Scholz video blog: http://comlounge.tv
COM.lounge blog: http://mrtopf.de/blog
Luetticher Strasse 10 Skype: HerrTopf
52064 Aachen Homepage: http://comlounge.net
Tel: +49 241 400 730 0 E-Mail ***@comlounge.net
Fax: +49 241 979 00 850 IRC: MrTopf, Tao_T

neue Show: TOPFt?glich (http://mrtopf.de/blog/category/topf-taglich/)
Loading...